Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 01:28:00 +0000 (18:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 01:28:00 +0000 (18:28 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (108 commits)
  ehea: Fixing statistics
  bonding: Fix lockdep warning after bond_vlan_rx_register()
  tunnels: Fix tunnels change rcu protection
  caif-u5500: Build config for CAIF shared mem driver
  caif-u5500: CAIF shared memory mailbox interface
  caif-u5500: CAIF shared memory transport protocol
  caif-u5500: Adding shared memory include
  drivers/isdn: delete double assignment
  drivers/net/typhoon.c: delete double assignment
  drivers/net/sb1000.c: delete double assignment
  qlcnic: define valid vlan id range
  qlcnic: reduce rx ring size
  qlcnic: fix mac learning
  ehea: fix use after free
  inetpeer: __rcu annotations
  fib_rules: __rcu annotates ctarget
  tunnels: add __rcu annotations
  net: add __rcu annotations to protocol
  ipv4: add __rcu annotations to routes.c
  qlge: bugfix: Restoring the vlan setting.
  ...

2292 files changed:
Documentation/ABI/obsolete/dv1394 [deleted file]
Documentation/ABI/removed/dv1394 [new file with mode: 0644]
Documentation/ABI/removed/raw1394 [new file with mode: 0644]
Documentation/ABI/removed/raw1394_legacy_isochronous [deleted file]
Documentation/ABI/removed/video1394 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-system-ibm-rtl [new file with mode: 0644]
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/kernel-api.tmpl
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/nfs/00-INDEX
Documentation/filesystems/nfs/idmapper.txt [new file with mode: 0644]
Documentation/filesystems/nfs/nfsroot.txt
Documentation/filesystems/nfs/pnfs.txt [new file with mode: 0644]
Documentation/filesystems/proc.txt
Documentation/filesystems/sharedsubtree.txt
Documentation/hwmon/ltc4261 [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/misc-devices/apds990x.txt [new file with mode: 0644]
Documentation/misc-devices/bh1770glc.txt [new file with mode: 0644]
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sysrq.txt
Documentation/timers/hpet_example.c
Documentation/trace/postprocess/trace-vmscan-postprocess.pl
Documentation/vm/highmem.txt [new file with mode: 0644]
MAINTAINERS
arch/alpha/Kconfig
arch/alpha/include/asm/core_mcpcia.h
arch/alpha/include/asm/core_t2.h
arch/alpha/include/asm/pgtable.h
arch/alpha/kernel/core_t2.c
arch/alpha/kernel/machvec_impl.h
arch/arm/Kconfig
arch/arm/configs/da8xx_omapl_defconfig
arch/arm/configs/n8x0_defconfig [deleted file]
arch/arm/configs/omap2plus_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_defconfig [deleted file]
arch/arm/configs/omap_4430sdp_defconfig [deleted file]
arch/arm/configs/omap_generic_2420_defconfig [deleted file]
arch/arm/configs/pcontrol_g20_defconfig [new file with mode: 0644]
arch/arm/include/asm/highmem.h
arch/arm/include/asm/pgtable.h
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9_alt_reset.S [new file with mode: 0644]
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/board-pcontrol-g20.c [new file with mode: 0644]
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_slowclock.S
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/aemif.c [new file with mode: 0644]
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/board-mityomapl138.c [new file with mode: 0644]
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-davinci/board-omapl138-hawk.c [new file with mode: 0644]
arch/arm/mach-davinci/board-sffsdr.c
arch/arm/mach-davinci/board-tnetv107x-evm.c
arch/arm/mach-davinci/clock.c
arch/arm/mach-davinci/clock.h
arch/arm/mach-davinci/cpufreq.c
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/devices-tnetv107x.c
arch/arm/mach-davinci/devices.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/dm646x.c
arch/arm/mach-davinci/dma.c
arch/arm/mach-davinci/include/mach/aemif.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/da8xx.h
arch/arm/mach-davinci/include/mach/dm365.h
arch/arm/mach-davinci/include/mach/dm644x.h
arch/arm/mach-davinci/include/mach/dm646x.h
arch/arm/mach-davinci/include/mach/nand.h
arch/arm/mach-davinci/include/mach/psc.h
arch/arm/mach-davinci/include/mach/tnetv107x.h
arch/arm/mach-davinci/include/mach/uncompress.h
arch/arm/mach-davinci/tnetv107x.c
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/netspace_v2-setup.c
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-h2-mmc.c
arch/arm/mach-omap1/board-h3-mmc.c
arch/arm/mach-omap1/board-htcherald.c
arch/arm/mach-omap1/board-sx1-mmc.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/include/mach/camera.h [new file with mode: 0644]
arch/arm/mach-omap1/pm_bus.c [new file with mode: 0644]
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-cm-t3517.c [new file with mode: 0644]
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-flash.c
arch/arm/mach-omap2/board-flash.h [new file with mode: 0644]
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-igep0030.c [new file with mode: 0644]
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3logic.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-rx51-sdram.c
arch/arm/mach-omap2/board-rx51-video.c
arch/arm/mach-omap2/board-zoom-debugboard.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/board-zoom3.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/cm-regbits-34xx.h
arch/arm/mach-omap2/cm-regbits-44xx.h
arch/arm/mach-omap2/cm44xx.h
arch/arm/mach-omap2/cm4xxx.c
arch/arm/mach-omap2/common.c [new file with mode: 0644]
arch/arm/mach-omap2/control.c
arch/arm/mach-omap2/control.h [new file with mode: 0644]
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc-smsc911x.c [new file with mode: 0644]
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/hsmmc.h
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/include/mach/board-flash.h [deleted file]
arch/arm/mach-omap2/include/mach/board-rx51.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h [new file with mode: 0644]
arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h [new file with mode: 0644]
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/io.h [new file with mode: 0644]
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/mux2420.c
arch/arm/mach-omap2/mux2430.c
arch/arm/mach-omap2/mux34xx.c
arch/arm/mach-omap2/omap4-common.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c [new file with mode: 0644]
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/pm_bus.c [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains44xx.h
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prcm.c
arch/arm/mach-omap2/prm-regbits-34xx.h
arch/arm/mach-omap2/prm-regbits-44xx.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/prm2xxx_3xxx.c [new file with mode: 0644]
arch/arm/mach-omap2/prm44xx.c [new file with mode: 0644]
arch/arm/mach-omap2/prm44xx.h
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/sram34xx.S
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/timer-gp.h [new file with mode: 0644]
arch/arm/mach-omap2/usb-fs.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-harmony-pcie.c [new file with mode: 0644]
arch/arm/mach-tegra/board.h
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/cpu-tegra.c [new file with mode: 0644]
arch/arm/mach-tegra/dma.c [new file with mode: 0644]
arch/arm/mach-tegra/fuse.c [new file with mode: 0644]
arch/arm/mach-tegra/fuse.h [new file with mode: 0644]
arch/arm/mach-tegra/gpio.c
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/gpio.h
arch/arm/mach-tegra/include/mach/hardware.h
arch/arm/mach-tegra/include/mach/io.h
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/include/mach/irqs.h
arch/arm/mach-tegra/include/mach/legacy_irq.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/pinmux-t2.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/pinmux.h
arch/arm/mach-tegra/io.c
arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/legacy_irq.c [new file with mode: 0644]
arch/arm/mach-tegra/pcie.c [new file with mode: 0644]
arch/arm/mach-tegra/pinmux-t2-tables.c [new file with mode: 0644]
arch/arm/mach-tegra/pinmux.c
arch/arm/mach-tegra/tegra2_clocks.c
arch/arm/mach-tegra/tegra2_dvfs.c [new file with mode: 0644]
arch/arm/mach-tegra/tegra2_dvfs.h [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/include/mach/devices.h
arch/arm/mach-ux500/pins-db8500.h
arch/arm/mm/fault-armv.c
arch/arm/mm/highmem.c
arch/arm/mm/pgd.c
arch/arm/plat-nomadik/include/plat/ske.h [new file with mode: 0644]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/counter_32k.c [new file with mode: 0644]
arch/arm/plat-omap/cpu-omap.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/fb.h [new file with mode: 0644]
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/plat/common.h
arch/arm/plat-omap/include/plat/control.h [deleted file]
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/display.h
arch/arm/plat-omap/include/plat/dma.h
arch/arm/plat-omap/include/plat/dmtimer.h
arch/arm/plat-omap/include/plat/gpmc-smsc911x.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/i2c.h
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/plat-omap/include/plat/mcbsp.h
arch/arm/plat-omap/include/plat/mmc.h
arch/arm/plat-omap/include/plat/omap-serial.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/omap24xx.h
arch/arm/plat-omap/include/plat/omap4-keypad.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/omap_device.h
arch/arm/plat-omap/include/plat/omap_hwmod.h
arch/arm/plat-omap/include/plat/powerdomain.h
arch/arm/plat-omap/include/plat/prcm.h
arch/arm/plat-omap/include/plat/sdrc.h
arch/arm/plat-omap/include/plat/sram.h
arch/arm/plat-omap/include/plat/timer-gp.h [deleted file]
arch/arm/plat-omap/include/plat/uncompress.h
arch/arm/plat-omap/include/plat/usb.h
arch/arm/plat-omap/include/plat/vrfb.h
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/sram.c
arch/arm/plat-omap/sram.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-samsung/include/plat/devs.h
arch/avr32/include/asm/pgtable.h
arch/blackfin/Kconfig.debug
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF527-TLL6527M_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-ACVILON_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/configs/BlackStamp_defconfig
arch/blackfin/configs/CM-BF527_defconfig
arch/blackfin/configs/CM-BF533_defconfig
arch/blackfin/configs/CM-BF537E_defconfig
arch/blackfin/configs/CM-BF537U_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/configs/CM-BF561_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/IP0X_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/SRV1_defconfig
arch/blackfin/configs/TCM-BF518_defconfig
arch/blackfin/configs/TCM-BF537_defconfig
arch/blackfin/include/asm/bfin5xx_spi.h
arch/blackfin/include/asm/bfin_ppi.h
arch/blackfin/include/asm/bfin_twi.h [new file with mode: 0644]
arch/blackfin/include/asm/cdef_LPBlackfin.h
arch/blackfin/include/asm/entry.h
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/boards/tcm-bf518.c
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/boards/tll6527m.c
arch/blackfin/mach-bf537/boards/cm_bf537e.c
arch/blackfin/mach-bf537/boards/cm_bf537u.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-common/Makefile
arch/blackfin/mach-common/irqpanic.c [deleted file]
arch/cris/include/asm/pgtable.h
arch/frv/include/asm/highmem.h
arch/frv/include/asm/pgtable.h
arch/frv/mb93090-mb00/pci-dma.c
arch/frv/mm/cache-page.c
arch/frv/mm/highmem.c
arch/ia64/include/asm/pgtable.h
arch/ia64/include/asm/siginfo.h
arch/m32r/include/asm/pgtable.h
arch/m68k/include/asm/cacheflush_no.h
arch/m68k/include/asm/coldfire.h
arch/m68k/include/asm/entry_mm.h
arch/m68k/include/asm/entry_no.h
arch/m68k/include/asm/gpio.h
arch/m68k/include/asm/m548xgpt.h [new file with mode: 0644]
arch/m68k/include/asm/m548xsim.h [new file with mode: 0644]
arch/m68k/include/asm/mcfcache.h
arch/m68k/include/asm/mcfsim.h
arch/m68k/include/asm/mcfslt.h [new file with mode: 0644]
arch/m68k/include/asm/mcfuart.h
arch/m68k/include/asm/motorola_pgtable.h
arch/m68k/include/asm/sun3_pgtable.h
arch/m68k/kernel/asm-offsets.c
arch/m68knommu/Kconfig
arch/m68knommu/Makefile
arch/m68knommu/kernel/.gitignore [new file with mode: 0644]
arch/m68knommu/kernel/asm-offsets.c
arch/m68knommu/kernel/ptrace.c
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/time.c
arch/m68knommu/kernel/traps.c
arch/m68knommu/platform/5206/Makefile
arch/m68knommu/platform/5206e/Makefile
arch/m68knommu/platform/520x/Makefile
arch/m68knommu/platform/523x/Makefile
arch/m68knommu/platform/5249/Makefile
arch/m68knommu/platform/5272/Makefile
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/5272/intc.c
arch/m68knommu/platform/527x/Makefile
arch/m68knommu/platform/528x/Makefile
arch/m68knommu/platform/5307/Makefile
arch/m68knommu/platform/532x/Makefile
arch/m68knommu/platform/5407/Makefile
arch/m68knommu/platform/548x/Makefile [new file with mode: 0644]
arch/m68knommu/platform/548x/config.c [new file with mode: 0644]
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68328/head-de2.S
arch/m68knommu/platform/68328/head-ram.S
arch/m68knommu/platform/68328/ints.c
arch/m68knommu/platform/68360/entry.S
arch/m68knommu/platform/68360/ints.c
arch/m68knommu/platform/68VZ328/config.c
arch/m68knommu/platform/coldfire/Makefile
arch/m68knommu/platform/coldfire/entry.S
arch/m68knommu/platform/coldfire/intc-2.c
arch/m68knommu/platform/coldfire/intc-simr.c
arch/m68knommu/platform/coldfire/intc.c
arch/m68knommu/platform/coldfire/sltimers.c [new file with mode: 0644]
arch/microblaze/Kconfig
arch/microblaze/Kconfig.debug
arch/microblaze/Makefile
arch/microblaze/include/asm/byteorder.h
arch/microblaze/include/asm/checksum.h
arch/microblaze/include/asm/cpuinfo.h
arch/microblaze/include/asm/elf.h
arch/microblaze/include/asm/gpio.h
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/prom.h
arch/microblaze/include/asm/pvr.h
arch/microblaze/include/asm/seccomp.h [new file with mode: 0644]
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/include/asm/unaligned.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/cpuinfo-static.c
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/cpu/mb.c
arch/microblaze/kernel/cpu/pvr.c
arch/microblaze/kernel/early_printk.c
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/exceptions.c
arch/microblaze/kernel/heartbeat.c
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/kgdb.c
arch/microblaze/kernel/microblaze_ksyms.c
arch/microblaze/kernel/prom.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/timer.c
arch/microblaze/kernel/vmlinux.lds.S
arch/microblaze/lib/Makefile
arch/microblaze/lib/ashldi3.c [new file with mode: 0644]
arch/microblaze/lib/ashrdi3.c [new file with mode: 0644]
arch/microblaze/lib/divsi3.S [new file with mode: 0644]
arch/microblaze/lib/libgcc.h [new file with mode: 0644]
arch/microblaze/lib/lshrdi3.c [new file with mode: 0644]
arch/microblaze/lib/memcpy.c
arch/microblaze/lib/memmove.c
arch/microblaze/lib/memset.c
arch/microblaze/lib/modsi3.S [new file with mode: 0644]
arch/microblaze/lib/muldi3.S [new file with mode: 0644]
arch/microblaze/lib/mulsi3.S [new file with mode: 0644]
arch/microblaze/lib/udivsi3.S [new file with mode: 0644]
arch/microblaze/lib/umodsi3.S [new file with mode: 0644]
arch/microblaze/pci/pci-common.c
arch/microblaze/platform/generic/system.dts
arch/microblaze/platform/platform.c
arch/mips/Kconfig
arch/mips/alchemy/devboards/db1200/platform.c
arch/mips/include/asm/highmem.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/pgtable-32.h
arch/mips/include/asm/pgtable-64.h
arch/mips/include/asm/prom.h [new file with mode: 0644]
arch/mips/kernel/Makefile
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/prom.c [new file with mode: 0644]
arch/mips/kernel/setup.c
arch/mips/mm/highmem.c
arch/mn10300/include/asm/highmem.h
arch/mn10300/include/asm/pgtable.h
arch/mn10300/kernel/vmlinux.lds.S
arch/parisc/include/asm/pgtable.h
arch/powerpc/boot/dts/mpc8610_hpcd.dts
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/include/asm/fsl_guts.h [new file with mode: 0644]
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/immap_86xx.h [deleted file]
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/vio.c
arch/powerpc/mm/highmem.c
arch/powerpc/platforms/85xx/p1022_ds.c
arch/s390/Kbuild [new file with mode: 0644]
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/crypto/crypt_s390.h
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/cpu.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/s390_ext.h
arch/s390/include/asm/scatterlist.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/syscall.h
arch/s390/include/asm/sysinfo.h
arch/s390/include/asm/system.h
arch/s390/include/asm/tlb.h
arch/s390/include/asm/topology.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_ptrace.h
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/head.S
arch/s390/kernel/process.c
arch/s390/kernel/processor.c
arch/s390/kernel/s390_ext.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/sysinfo.c
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/traps.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vtime.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/mm/Makefile
arch/s390/mm/cmm.c
arch/s390/mm/fault.c
arch/s390/mm/gup.c [new file with mode: 0644]
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/mm/pgtable.c
arch/score/include/asm/pgtable.h
arch/sh/Kconfig
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-sh2007.c [new file with mode: 0644]
arch/sh/boards/board-sh7757lcr.c [new file with mode: 0644]
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-sdk7786/Makefile
arch/sh/boards/mach-sdk7786/gpio.c [new file with mode: 0644]
arch/sh/boards/mach-sdk7786/setup.c
arch/sh/boards/mach-sdk7786/sram.c [new file with mode: 0644]
arch/sh/boards/mach-x3proto/Makefile
arch/sh/boards/mach-x3proto/gpio.c [new file with mode: 0644]
arch/sh/boards/mach-x3proto/ilsel.c
arch/sh/boards/mach-x3proto/setup.c
arch/sh/boot/compressed/head_32.S
arch/sh/cchips/hd6446x/Makefile
arch/sh/configs/ap325rxa_defconfig
arch/sh/configs/cayman_defconfig
arch/sh/configs/dreamcast_defconfig
arch/sh/configs/ecovec24-romimage_defconfig
arch/sh/configs/edosk7760_defconfig
arch/sh/configs/espt_defconfig
arch/sh/configs/hp6xx_defconfig
arch/sh/configs/kfr2r09-romimage_defconfig
arch/sh/configs/kfr2r09_defconfig
arch/sh/configs/landisk_defconfig
arch/sh/configs/lboxre2_defconfig
arch/sh/configs/magicpanelr2_defconfig
arch/sh/configs/microdev_defconfig
arch/sh/configs/migor_defconfig
arch/sh/configs/polaris_defconfig
arch/sh/configs/r7780mp_defconfig
arch/sh/configs/r7785rp_defconfig
arch/sh/configs/rts7751r2d1_defconfig
arch/sh/configs/rts7751r2dplus_defconfig
arch/sh/configs/sdk7780_defconfig
arch/sh/configs/se7343_defconfig
arch/sh/configs/se7712_defconfig
arch/sh/configs/se7721_defconfig
arch/sh/configs/se7722_defconfig
arch/sh/configs/se7724_defconfig
arch/sh/configs/se7750_defconfig
arch/sh/configs/se7751_defconfig
arch/sh/configs/se7780_defconfig
arch/sh/configs/sh03_defconfig
arch/sh/configs/sh2007_defconfig [new file with mode: 0644]
arch/sh/configs/sh7710voipgw_defconfig
arch/sh/configs/sh7757lcr_defconfig [new file with mode: 0644]
arch/sh/configs/sh7763rdp_defconfig
arch/sh/configs/sh7785lcr_defconfig
arch/sh/configs/shx3_defconfig
arch/sh/configs/snapgear_defconfig
arch/sh/configs/systemh_defconfig
arch/sh/configs/titan_defconfig
arch/sh/configs/ul2_defconfig
arch/sh/drivers/dma/dma-api.c
arch/sh/drivers/pci/Makefile
arch/sh/drivers/pci/fixups-sdk7786.c [new file with mode: 0644]
arch/sh/drivers/pci/ops-sh4.c
arch/sh/drivers/pci/ops-sh7786.c
arch/sh/drivers/pci/pci-sh7751.c
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/drivers/pci/pci-sh7780.h
arch/sh/drivers/pci/pci.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/drivers/pci/pcie-sh7786.h
arch/sh/include/asm/Kbuild
arch/sh/include/asm/elf.h
arch/sh/include/asm/fixmap.h
arch/sh/include/asm/gpio.h
arch/sh/include/asm/ilsel.h [deleted file]
arch/sh/include/asm/irq.h
arch/sh/include/asm/kprobes.h
arch/sh/include/asm/pci.h
arch/sh/include/asm/pgtable_32.h
arch/sh/include/asm/pgtable_64.h
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/ptrace_32.h [new file with mode: 0644]
arch/sh/include/asm/ptrace_64.h [new file with mode: 0644]
arch/sh/include/asm/sizes.h
arch/sh/include/asm/sram.h [new file with mode: 0644]
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/tlbflush.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/include/cpu-sh3/cpu/mmu_context.h
arch/sh/include/cpu-sh4/cpu/freq.h
arch/sh/include/cpu-sh4/cpu/sh7757.h
arch/sh/include/cpu-sh4/cpu/shx3.h [new file with mode: 0644]
arch/sh/include/mach-common/mach/sh2007.h [new file with mode: 0644]
arch/sh/include/mach-sdk7786/mach/fpga.h
arch/sh/include/mach-x3proto/mach/hardware.h [new file with mode: 0644]
arch/sh/include/mach-x3proto/mach/ilsel.h [new file with mode: 0644]
arch/sh/kernel/Makefile
arch/sh/kernel/clkdev.c
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh4a/intc-shx3.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/perf_event.c
arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
arch/sh/kernel/cpu/sh4a/pinmux-shx3.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/head_32.S
arch/sh/kernel/io_trapped.c
arch/sh/kernel/irq.c
arch/sh/kernel/kdebugfs.c [new file with mode: 0644]
arch/sh/kernel/kprobes.c
arch/sh/kernel/ptrace.c [new file with mode: 0644]
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/ptrace_64.c
arch/sh/kernel/reboot.c
arch/sh/kernel/setup.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/traps_32.c
arch/sh/kernel/traps_64.c
arch/sh/lib/Makefile
arch/sh/math-emu/math.c
arch/sh/mm/Kconfig
arch/sh/mm/Makefile
arch/sh/mm/asids-debugfs.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/consistent.c
arch/sh/mm/init.c
arch/sh/mm/nommu.c
arch/sh/mm/pmb.c
arch/sh/mm/sram.c [new file with mode: 0644]
arch/sh/mm/tlb-debugfs.c
arch/sh/mm/tlbflush_32.c
arch/sh/mm/tlbflush_64.c
arch/sh/tools/mach-types
arch/sparc/Kconfig
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/floppy_32.h
arch/sparc/include/asm/highmem.h
arch/sparc/include/asm/openprom.h
arch/sparc/include/asm/oplib_32.h
arch/sparc/include/asm/oplib_64.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/prom.h
arch/sparc/kernel/auxio_32.c
arch/sparc/kernel/btext.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/prom.h
arch/sparc/kernel/prom_common.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/starfire.c
arch/sparc/kernel/tadpole.c
arch/sparc/mm/highmem.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/prom/init_32.c
arch/sparc/prom/init_64.c
arch/sparc/prom/memory.c
arch/sparc/prom/misc_64.c
arch/sparc/prom/ranges.c
arch/sparc/prom/tree_32.c
arch/sparc/prom/tree_64.c
arch/tile/Kconfig
arch/tile/Makefile
arch/tile/include/arch/sim.h [new file with mode: 0644]
arch/tile/include/arch/sim_def.h
arch/tile/include/arch/spr_def.h
arch/tile/include/arch/spr_def_32.h
arch/tile/include/asm/backtrace.h
arch/tile/include/asm/compat.h
arch/tile/include/asm/highmem.h
arch/tile/include/asm/irqflags.h
arch/tile/include/asm/mman.h
arch/tile/include/asm/page.h
arch/tile/include/asm/pgtable.h
arch/tile/include/asm/processor.h
arch/tile/include/asm/ptrace.h
arch/tile/include/asm/syscalls.h
arch/tile/include/asm/system.h
arch/tile/include/asm/traps.h
arch/tile/include/hv/hypervisor.h
arch/tile/kernel/backtrace.c
arch/tile/kernel/compat.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/entry.S
arch/tile/kernel/head_32.S
arch/tile/kernel/intvec_32.S
arch/tile/kernel/irq.c
arch/tile/kernel/messaging.c
arch/tile/kernel/process.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/regs_32.S
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/single_step.c
arch/tile/kernel/smp.c
arch/tile/kernel/stack.c
arch/tile/kernel/sys.c
arch/tile/kernel/traps.c
arch/tile/kvm/Kconfig [new file with mode: 0644]
arch/tile/lib/Makefile
arch/tile/lib/atomic_32.c
arch/tile/lib/exports.c
arch/tile/lib/memcpy_32.S
arch/tile/lib/memmove.c [new file with mode: 0644]
arch/tile/lib/memmove_32.c [deleted file]
arch/tile/lib/memset_32.c
arch/tile/lib/strlen_32.c
arch/tile/mm/fault.c
arch/tile/mm/highmem.c
arch/tile/mm/homecache.c
arch/tile/mm/init.c
arch/um/Kconfig.um
arch/um/defconfig
arch/um/include/asm/dma-mapping.h [deleted file]
arch/um/include/asm/pgtable.h
arch/um/include/asm/system.h
arch/um/kernel/dyn.lds.S
arch/um/kernel/irq.c
arch/um/kernel/uml.lds.S
arch/um/os-Linux/time.c
arch/x86/include/asm/highmem.h
arch/x86/include/asm/iomap.h
arch/x86/include/asm/olpc.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/include/asm/xen/page.h
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
arch/x86/kernel/cpu/cpufreq/longrun.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/crash_dump_32.c
arch/x86/kernel/hpet.c
arch/x86/kernel/smpboot.c
arch/x86/mm/fault.c
arch/x86/mm/highmem_32.c
arch/x86/mm/iomap_32.c
arch/x86/xen/Kconfig
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/setup.c
arch/x86/xen/xen-ops.h
arch/xtensa/include/asm/pgtable.h
block/blk-core.c
block/blk-merge.c
block/blk.h
block/genhd.c
crypto/async_tx/async_memcpy.c
crypto/blkcipher.c
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/ac.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/hwpci.c [new file with mode: 0644]
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utosi.c [new file with mode: 0644]
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxferror.c [new file with mode: 0644]
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/acpi/pci_root.c
drivers/acpi/power.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_thermal.c
drivers/acpi/processor_throttling.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sleep.h
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/base/node.c
drivers/base/platform.c
drivers/base/power/runtime.c
drivers/block/loop.c
drivers/block/xsysace.c
drivers/char/agp/Makefile
drivers/char/agp/agp.h
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/backend.c
drivers/char/agp/generic.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/hpet.c
drivers/char/hvc_iucv.c
drivers/char/hvc_tile.c
drivers/char/hvc_xen.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/sysrq.c
drivers/clocksource/sh_cmt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/crypto/hifn_795x.c
drivers/edac/edac_core.h
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/i7core_edac.c
drivers/firewire/Kconfig
drivers/firewire/Makefile
drivers/firewire/init_ohci1394_dma.c [new file with mode: 0644]
drivers/gpio/pca953x.c
drivers/gpio/xilinx_gpio.c
drivers/gpu/Makefile
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_agpsupport.c
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_drawable.c [deleted file]
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_scatter.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/i810/i810_drv.c
drivers/gpu/drm/i830/i830_drv.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_debugfs.c
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_debug.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_opregion.c [deleted file]
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_acpi.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_opregion.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/mga/mga_drv.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_calc.c
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_debugfs.c
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_dma.h
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_grctx.h
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_i2c.h
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_perf.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_pm.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_pm.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_ramht.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_ramht.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_temp.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_volt.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_fbcon.c
drivers/gpu/drm/nouveau/nv04_fifo.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv04_pm.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/nouveau/nv10_fifo.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv17_tv.h
drivers/gpu/drm/nouveau/nv17_tv_modes.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_grctx.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_cursor.c
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fb.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nv50_fifo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_pm.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/nouveau/nva3_pm.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_fifo.c
drivers/gpu/drm/nouveau/nvc0_instmem.c
drivers/gpu/drm/nouveau/nvreg.h
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_blit_kms.c [new file with mode: 0644]
drivers/gpu/drm/radeon/evergreen_blit_shaders.c [new file with mode: 0644]
drivers/gpu/drm/radeon/evergreen_blit_shaders.h [new file with mode: 0644]
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/reg_srcs/evergreen
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/savage/savage_drv.c
drivers/gpu/drm/sis/sis_drv.c
drivers/gpu/drm/tdfx/tdfx_drv.c
drivers/gpu/drm/ttm/Makefile
drivers/gpu/drm/ttm/ttm_agp_backend.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_manager.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/vmwgfx/Makefile
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/stub/Kconfig [new file with mode: 0644]
drivers/gpu/stub/Makefile [new file with mode: 0644]
drivers/gpu/stub/poulsbo.c [new file with mode: 0644]
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/coretemp.c
drivers/hwmon/gpio-fan.c [new file with mode: 0644]
drivers/hwmon/hdaps.c [deleted file]
drivers/hwmon/hp_accel.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/lis3lv02d_i2c.c
drivers/hwmon/lis3lv02d_spi.c
drivers/hwmon/ltc4261.c [new file with mode: 0644]
drivers/hwmon/pkgtemp.c
drivers/hwmon/via-cputemp.c
drivers/i2c/busses/i2c-sh7760.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/idle/intel_idle.c
drivers/ieee1394/Kconfig [deleted file]
drivers/ieee1394/Makefile [deleted file]
drivers/ieee1394/config_roms.c [deleted file]
drivers/ieee1394/config_roms.h [deleted file]
drivers/ieee1394/csr.c [deleted file]
drivers/ieee1394/csr.h [deleted file]
drivers/ieee1394/csr1212.c [deleted file]
drivers/ieee1394/csr1212.h [deleted file]
drivers/ieee1394/dma.c [deleted file]
drivers/ieee1394/dma.h [deleted file]
drivers/ieee1394/dv1394-private.h [deleted file]
drivers/ieee1394/dv1394.c [deleted file]
drivers/ieee1394/dv1394.h [deleted file]
drivers/ieee1394/eth1394.c [deleted file]
drivers/ieee1394/eth1394.h [deleted file]
drivers/ieee1394/highlevel.c [deleted file]
drivers/ieee1394/highlevel.h [deleted file]
drivers/ieee1394/hosts.c [deleted file]
drivers/ieee1394/hosts.h [deleted file]
drivers/ieee1394/ieee1394-ioctl.h [deleted file]
drivers/ieee1394/ieee1394.h [deleted file]
drivers/ieee1394/ieee1394_core.c [deleted file]
drivers/ieee1394/ieee1394_core.h [deleted file]
drivers/ieee1394/ieee1394_hotplug.h [deleted file]
drivers/ieee1394/ieee1394_transactions.c [deleted file]
drivers/ieee1394/ieee1394_transactions.h [deleted file]
drivers/ieee1394/ieee1394_types.h [deleted file]
drivers/ieee1394/init_ohci1394_dma.c [deleted file]
drivers/ieee1394/iso.c [deleted file]
drivers/ieee1394/iso.h [deleted file]
drivers/ieee1394/nodemgr.c [deleted file]
drivers/ieee1394/nodemgr.h [deleted file]
drivers/ieee1394/ohci1394.c [deleted file]
drivers/ieee1394/ohci1394.h [deleted file]
drivers/ieee1394/pcilynx.c [deleted file]
drivers/ieee1394/pcilynx.h [deleted file]
drivers/ieee1394/raw1394-private.h [deleted file]
drivers/ieee1394/raw1394.c [deleted file]
drivers/ieee1394/raw1394.h [deleted file]
drivers/ieee1394/sbp2.c [deleted file]
drivers/ieee1394/sbp2.h [deleted file]
drivers/ieee1394/video1394.c [deleted file]
drivers/ieee1394/video1394.h [deleted file]
drivers/infiniband/core/agent.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/iwcm.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/multicast.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/ud_header.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/amso1100/Kbuild
drivers/infiniband/hw/amso1100/c2_intr.c
drivers/infiniband/hw/cxgb3/Makefile
drivers/infiniband/hw/cxgb3/cxio_hal.c
drivers/infiniband/hw/cxgb3/cxio_wr.h
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/cxgb3/iwch_ev.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/cxgb3/iwch_user.h
drivers/infiniband/hw/cxgb4/Makefile
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/ev.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/resource.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/cxgb4/user.h
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ipath/Makefile
drivers/infiniband/hw/ipath/ipath_fs.c
drivers/infiniband/hw/mlx4/ah.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/mr.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/qib/qib.h
drivers/infiniband/hw/qib/qib_fs.c
drivers/infiniband/hw/qib/qib_init.c
drivers/infiniband/hw/qib/qib_pcie.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/hw/qib/qib_uc.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/evdev.c
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/fm801-gp.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/hil_kbd.c
drivers/input/keyboard/nomadik-ske-keypad.c [new file with mode: 0644]
drivers/input/keyboard/omap4-keypad.c [new file with mode: 0644]
drivers/input/keyboard/tnetv107x-keypad.c [new file with mode: 0644]
drivers/input/keyboard/twl4030_keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ab8500-ponkey.c [new file with mode: 0644]
drivers/input/misc/ati_remote2.c
drivers/input/misc/powermate.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/elantech.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/mouse/trackpoint.c
drivers/input/mousedev.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/i8042.c
drivers/input/serio/ps2mult.c [new file with mode: 0644]
drivers/input/serio/serio.c
drivers/input/sparse-keymap.c
drivers/input/tablet/Kconfig
drivers/input/tablet/Makefile
drivers/input/tablet/hanwang.c [new file with mode: 0644]
drivers/input/tablet/wacom.h
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/bu21013_ts.c [new file with mode: 0644]
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/hp680_ts_input.c
drivers/input/touchscreen/intel-mid-touch.c [new file with mode: 0644]
drivers/input/touchscreen/lpc32xx_ts.c [new file with mode: 0644]
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/stmpe-ts.c
drivers/input/touchscreen/tnetv107x-ts.c [new file with mode: 0644]
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/wacom_w8001.c
drivers/input/touchscreen/wm97xx-core.c
drivers/macintosh/windfarm_pm121.c
drivers/md/dm-snap-persistent.c
drivers/media/IR/ir-keytable.c
drivers/mfd/ab8500-core.c
drivers/mfd/sh_mobile_sdhi.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-codec.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ad525x_dpot-i2c.c
drivers/misc/ad525x_dpot-spi.c
drivers/misc/ad525x_dpot.c
drivers/misc/ad525x_dpot.h
drivers/misc/apds9802als.c [new file with mode: 0644]
drivers/misc/apds990x.c [new file with mode: 0644]
drivers/misc/bh1770glc.c [new file with mode: 0644]
drivers/misc/ibmasm/ibmasmfs.c
drivers/misc/isl29020.c [new file with mode: 0644]
drivers/misc/lkdtm.c
drivers/misc/phantom.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/host/Kconfig
drivers/mmc/host/omap_hsmmc.c
drivers/mtd/devices/m25p80.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/ofpart.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/bfin_mac.c
drivers/net/bfin_mac.h
drivers/net/davinci_cpdma.c [new file with mode: 0644]
drivers/net/davinci_cpdma.h [new file with mode: 0644]
drivers/net/davinci_emac.c
drivers/net/davinci_mdio.c [new file with mode: 0644]
drivers/net/mlx4/en_main.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_port.c
drivers/net/mlx4/en_port.h
drivers/net/mlx4/fw.c
drivers/net/mlx4/intf.c
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4_en.h
drivers/net/mlx4/port.c
drivers/net/xilinx_emaclite.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/address.c
drivers/of/base.c
drivers/of/device.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/of_i2c.c
drivers/of/pdt.c [new file with mode: 0644]
drivers/of/platform.c
drivers/oprofile/oprofilefs.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/hdaps.c [new file with mode: 0644]
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/ibm_rtl.c [new file with mode: 0644]
drivers/platform/x86/ideapad-laptop.c [new file with mode: 0644]
drivers/platform/x86/ideapad_acpi.c [deleted file]
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/topstar-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/wmi.c
drivers/platform/x86/xo1-rfkill.c [new file with mode: 0644]
drivers/pnp/base.h
drivers/pnp/core.c
drivers/pnp/driver.c
drivers/pnp/pnpacpi/core.c
drivers/pnp/resource.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/bq20z75.c [new file with mode: 0644]
drivers/power/bq27x00_battery.c
drivers/power/ds2760_battery.c
drivers/power/ds2782_battery.c
drivers/power/isp1704_charger.c [new file with mode: 0644]
drivers/power/jz4740-battery.c
drivers/power/olpc_battery.c
drivers/power/pcf50633-charger.c
drivers/power/power_supply_sysfs.c
drivers/power/twl4030_charger.c [new file with mode: 0644]
drivers/power/wm831x_power.c
drivers/rtc/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_proc.c
drivers/s390/char/sclp.c
drivers/s390/char/vmlogrdr.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/chp.c
drivers/s390/cio/chp.h
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/io_sch.h
drivers/s390/crypto/ap_bus.c
drivers/s390/kvm/kvm_virtio.c
drivers/sbus/char/jsflash.c
drivers/serial/68328serial.h
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/of_serial.c
drivers/serial/omap-serial.c [new file with mode: 0644]
drivers/serial/sh-sci.h
drivers/sh/Kconfig
drivers/sh/Makefile
drivers/sh/clk-cpg.c [deleted file]
drivers/sh/clk.c [deleted file]
drivers/sh/clk/Makefile [new file with mode: 0644]
drivers/sh/clk/core.c [new file with mode: 0644]
drivers/sh/clk/cpg.c [new file with mode: 0644]
drivers/sh/intc.c [deleted file]
drivers/sh/intc/Kconfig [new file with mode: 0644]
drivers/sh/intc/Makefile [new file with mode: 0644]
drivers/sh/intc/access.c [new file with mode: 0644]
drivers/sh/intc/balancing.c [new file with mode: 0644]
drivers/sh/intc/chip.c [new file with mode: 0644]
drivers/sh/intc/core.c [new file with mode: 0644]
drivers/sh/intc/dynamic.c [new file with mode: 0644]
drivers/sh/intc/handle.c [new file with mode: 0644]
drivers/sh/intc/internals.h [new file with mode: 0644]
drivers/sh/intc/userimask.c [new file with mode: 0644]
drivers/sh/intc/virq-debugfs.c [new file with mode: 0644]
drivers/sh/intc/virq.c [new file with mode: 0644]
drivers/sh/pfc.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi_tegra.c [new file with mode: 0644]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/mrst-touchscreen/Kconfig [deleted file]
drivers/staging/mrst-touchscreen/Makefile [deleted file]
drivers/staging/mrst-touchscreen/TODO [deleted file]
drivers/staging/mrst-touchscreen/intel-mid-touch.c [deleted file]
drivers/staging/pohmelfs/inode.c
drivers/staging/xgifb/TODO
drivers/usb/core/inode.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/omap_udc.c
drivers/usb/host/r8a66597-hcd.c
drivers/uwb/Kconfig
drivers/uwb/Makefile
drivers/uwb/i1480/Makefile
drivers/uwb/i1480/i1480-wlp.h [deleted file]
drivers/uwb/i1480/i1480u-wlp/Makefile [deleted file]
drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h [deleted file]
drivers/uwb/i1480/i1480u-wlp/lc.c [deleted file]
drivers/uwb/i1480/i1480u-wlp/netdev.c [deleted file]
drivers/uwb/i1480/i1480u-wlp/rx.c [deleted file]
drivers/uwb/i1480/i1480u-wlp/sysfs.c [deleted file]
drivers/uwb/i1480/i1480u-wlp/tx.c [deleted file]
drivers/uwb/wlp/Makefile [deleted file]
drivers/uwb/wlp/driver.c [deleted file]
drivers/uwb/wlp/eda.c [deleted file]
drivers/uwb/wlp/messages.c [deleted file]
drivers/uwb/wlp/sysfs.c [deleted file]
drivers/uwb/wlp/txrx.c [deleted file]
drivers/uwb/wlp/wlp-internal.h [deleted file]
drivers/uwb/wlp/wlp-lc.c [deleted file]
drivers/uwb/wlp/wss-lc.c [deleted file]
drivers/video/Kconfig
drivers/video/aty/atyfb_base.c
drivers/video/au1200fb.c
drivers/video/omap/lcd_omap3beagle.c
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic.c
drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
drivers/video/omap2/displays/panel-toppoly-tdo35s.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/Makefile
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss_features.c [new file with mode: 0644]
drivers/video/omap2/dss/dss_features.h [new file with mode: 0644]
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/omapfb/Kconfig
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/xilinxfb.c
drivers/watchdog/omap_wdt.c
drivers/xen/events.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenfs/Makefile
drivers/xen/xenfs/privcmd.c [new file with mode: 0644]
drivers/xen/xenfs/super.c
drivers/xen/xenfs/xenfs.h
drivers/xen/xenfs/xenstored.c [new file with mode: 0644]
firmware/ihex2fw.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/Makefile
fs/affs/file.c
fs/affs/inode.c
fs/afs/dir.c
fs/afs/write.c
fs/aio.c
fs/anon_inodes.c
fs/autofs4/inode.c
fs/bfs/dir.c
fs/binfmt_misc.c
fs/block_dev.c
fs/btrfs/inode.c
fs/buffer.c
fs/ceph/addr.c
fs/cifs/file.c
fs/coda/cache.c
fs/coda/cnode.c
fs/coda/dir.c
fs/coda/file.c
fs/coda/inode.c
fs/coda/pioctl.c
fs/coda/psdev.c
fs/coda/symlink.c
fs/coda/upcall.c
fs/compat.c
fs/configfs/inode.c
fs/dcache.c
fs/debugfs/inode.c
fs/direct-io.c
fs/exec.c
fs/exofs/dir.c
fs/exofs/file.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/exportfs/expfs.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext2/xattr.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/fcntl.c
fs/file_table.c
fs/freevxfs/vxfs_inode.c
fs/fs-writeback.c
fs/fuse/control.c
fs/fuse/dev.c
fs/gfs2/aops.c
fs/gfs2/meta_io.c
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/super.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfs/mdb.c
fs/hfs/super.c
fs/hfsplus/dir.c
fs/hfsplus/inode.c
fs/hostfs/hostfs.h
fs/hostfs/hostfs_kern.c
fs/hostfs/hostfs_user.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/jffs2/dir.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_txnmgr.c
fs/jfs/namei.c
fs/libfs.c
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/locks.c
fs/logfs/dir.c
fs/minix/namei.c
fs/namei.c
fs/namespace.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/callback.c
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/dns_resolve.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c [new file with mode: 0644]
fs/nfs/nfs4filelayout.h [new file with mode: 0644]
fs/nfs/nfs4filelayoutdev.c [new file with mode: 0644]
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/pnfs.c [new file with mode: 0644]
fs/nfs/pnfs.h [new file with mode: 0644]
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/sysctl.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/Kconfig
fs/nfsd/export.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/namei.c
fs/nilfs2/segment.c
fs/notify/fsnotify.c
fs/notify/inode_mark.c
fs/ntfs/super.c
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/file.c
fs/ocfs2/namei.c
fs/partitions/check.c
fs/pipe.c
fs/proc/Kconfig
fs/proc/base.c
fs/proc/proc_sysctl.c
fs/ramfs/inode.c
fs/read_write.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/namei.c
fs/reiserfs/xattr.c
fs/seq_file.c
fs/signalfd.c
fs/smbfs/dir.c
fs/smbfs/inode.c
fs/smbfs/proc.c
fs/super.c
fs/sysv/namei.c
fs/ubifs/dir.c
fs/udf/namei.c
fs/ufs/namei.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/xfs_inode.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/actypes.h
include/acpi/platform/acenv.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/pgtable.h
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_helper.h
include/drm/i915_drm.h
include/drm/intel-gtt.h [new file with mode: 0644]
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/vmwgfx_drm.h
include/linux/acpi.h
include/linux/backing-dev.h
include/linux/bfin_mac.h [new file with mode: 0644]
include/linux/blkdev.h
include/linux/buffer_head.h
include/linux/coda_fs_i.h
include/linux/coda_linux.h
include/linux/coda_psdev.h
include/linux/completion.h
include/linux/davinci_emac.h
include/linux/elevator.h
include/linux/fs.h
include/linux/gameport.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/gpio-fan.h [new file with mode: 0644]
include/linux/highmem.h
include/linux/hugetlb.h
include/linux/i2c/apds990x.h [new file with mode: 0644]
include/linux/i2c/bh1770glc.h [new file with mode: 0644]
include/linux/i2c/twl.h
include/linux/idr.h
include/linux/input.h
include/linux/input/bu21013.h [new file with mode: 0644]
include/linux/io-mapping.h
include/linux/kernel.h
include/linux/kfifo.h
include/linux/lis3lv02d.h
include/linux/list.h
include/linux/math64.h
include/linux/memory_hotplug.h
include/linux/migrate.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/mlx4/driver.h
include/linux/mlx4/qp.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/moduleparam.h
include/linux/net.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_idmap.h
include/linux/nfs_mount.h
include/linux/nfs_xdr.h
include/linux/of_device.h
include/linux/of_fdt.h
include/linux/of_irq.h
include/linux/of_pdt.h [new file with mode: 0644]
include/linux/page-flags.h
include/linux/pageblock-flags.h
include/linux/pagemap.h
include/linux/pci_ids.h
include/linux/power_supply.h
include/linux/ratelimit.h
include/linux/reiserfs_fs.h
include/linux/rmap.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/serio.h
include/linux/sfi.h
include/linux/sh_clk.h
include/linux/sh_intc.h
include/linux/sh_pfc.h
include/linux/signalfd.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/gss_spkm3.h [deleted file]
include/linux/sunrpc/stats.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/svcauth.h
include/linux/sunrpc/xdr.h
include/linux/sunrpc/xprt.h
include/linux/swap.h
include/linux/types.h
include/linux/vmalloc.h
include/linux/wlp.h [deleted file]
include/linux/workqueue.h
include/linux/writeback.h
include/media/rc-map.h
include/rdma/ib_addr.h
include/rdma/ib_pack.h
include/rdma/ib_user_verbs.h
include/rdma/ib_verbs.h
include/scsi/srp.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/jack.h
include/sound/max98088.h [new file with mode: 0644]
include/sound/pcm.h
include/sound/sh_fsi.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc-of-simple.h [deleted file]
include/sound/soc.h
include/sound/tlv.h
include/sound/tlv320aic3x.h
include/sound/wm8962.h [new file with mode: 0644]
include/trace/events/ext4.h
include/trace/events/vmscan.h
include/trace/events/writeback.h
include/video/sh_mobile_hdmi.h
include/xen/Kbuild
include/xen/interface/memory.h
include/xen/privcmd.h [new file with mode: 0644]
include/xen/xen-ops.h
init/do_mounts.c
init/do_mounts_md.c
init/do_mounts_rd.c
init/initramfs.c
init/noinitramfs.c
ipc/mqueue.c
kernel/cgroup.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/kexec.c
kernel/power/snapshot.c
kernel/power/swap.c
kernel/printk.c
kernel/stop_machine.c
kernel/sysctl.c
kernel/user.c
kernel/wait.c
kernel/workqueue.c
lib/Kconfig.debug
lib/bitmap.c
lib/div64.c
lib/idr.c
lib/list_sort.c
lib/parser.c
lib/percpu_counter.c
lib/vsprintf.c
mm/backing-dev.c
mm/dmapool.c
mm/filemap.c
mm/highmem.c
mm/hugetlb.c
mm/internal.h
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mremap.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/iucv/iucv.c
net/socket.c
net/sunrpc/Kconfig
net/sunrpc/auth.c
net/sunrpc/auth_generic.c
net/sunrpc/auth_gss/Makefile
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_spkm3_mech.c [deleted file]
net/sunrpc/auth_gss/gss_spkm3_seal.c [deleted file]
net/sunrpc/auth_gss/gss_spkm3_token.c [deleted file]
net/sunrpc/auth_gss/gss_spkm3_unseal.c [deleted file]
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/netns.h [new file with mode: 0644]
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/svc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtsock.c
net/unix/af_unix.c
scripts/checkpatch.pl
scripts/get_maintainer.pl
security/apparmor/path.c
security/inode.c
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_iint.c
security/integrity/ima/ima_main.c
security/security.c
security/selinux/selinuxfs.c
security/tomoyo/realpath.c
sound/core/init.c
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/drivers/Kconfig
sound/drivers/Makefile
sound/drivers/aloop.c [new file with mode: 0644]
sound/drivers/virmidi.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/ad1816a/ad1816a.c
sound/isa/azt2320.c
sound/isa/galaxy/Makefile [new file with mode: 0644]
sound/isa/galaxy/azt1605.c [new file with mode: 0644]
sound/isa/galaxy/azt2316.c [new file with mode: 0644]
sound/isa/galaxy/galaxy.c [new file with mode: 0644]
sound/isa/gus/gusmax.c
sound/isa/sb/sb8.c
sound/isa/sgalaxy.c [deleted file]
sound/oss/Kconfig
sound/oss/Makefile
sound/oss/au1550_ac97.c
sound/oss/dmasound/dmasound_core.c
sound/oss/msnd_pinnacle.c
sound/oss/sh_dac_audio.c [deleted file]
sound/oss/soundcard.c
sound/oss/swarm_cs4297a.c
sound/oss/vwsnd.c
sound/pci/Kconfig
sound/pci/au88x0/au88x0_mixer.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/emu10k1/emumpu401.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c [deleted file]
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_intelhdmi.c [deleted file]
sound/pci/hda/patch_nvhdmi.c [deleted file]
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/delta.c
sound/pci/ice1712/delta.h
sound/pci/ice1712/pontis.c
sound/pci/ice1712/prodigy192.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/oxygen_regs.h
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_pcm179x.c
sound/pci/oxygen/xonar_wm87x6.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/ppc/tumbler.c
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/atmel/playpaq_wm8510.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/atmel/snd-soc-afeb9260.c
sound/soc/au1x/db1200.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/au1x/psc.h
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97-pcm.h
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.h
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-i2s.h [deleted file]
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm-pcm.h
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bf5xx-tdm.h
sound/soc/codecs/88pm860x-codec.c [new file with mode: 0644]
sound/soc/codecs/88pm860x-codec.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ac97.h [deleted file]
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1836.h
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad1980.h
sound/soc/codecs/ad73311.c
sound/soc/codecs/ad73311.h
sound/soc/codecs/ads117x.c
sound/soc/codecs/ads117x.h
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4104.h [deleted file]
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4535.h
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4642.h [deleted file]
sound/soc/codecs/ak4671.c
sound/soc/codecs/ak4671.h
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cq93vc.h [deleted file]
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4270.h [deleted file]
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l51.h
sound/soc/codecs/cx20442.c
sound/soc/codecs/cx20442.h
sound/soc/codecs/da7210.c
sound/soc/codecs/da7210.h [deleted file]
sound/soc/codecs/jz4740.c
sound/soc/codecs/jz4740.h [deleted file]
sound/soc/codecs/max98088.c [new file with mode: 0644]
sound/soc/codecs/max98088.h [new file with mode: 0644]
sound/soc/codecs/pcm3008.c
sound/soc/codecs/pcm3008.h
sound/soc/codecs/spdif_transciever.c
sound/soc/codecs/spdif_transciever.h [deleted file]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm2602.h
sound/soc/codecs/stac9766.c
sound/soc/codecs/stac9766.h
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic23.h
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic26.h
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tlv320dac33.h
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h [deleted file]
sound/soc/codecs/twl6040.c
sound/soc/codecs/twl6040.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda134x.h
sound/soc/codecs/uda1380.c
sound/soc/codecs/uda1380.h
sound/soc/codecs/wl1273.c [new file with mode: 0644]
sound/soc/codecs/wl1273.h [new file with mode: 0644]
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8350.h
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8400.h
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8510.h
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8523.h
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8580.h
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8711.h
sound/soc/codecs/wm8727.c
sound/soc/codecs/wm8727.h [deleted file]
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8728.h
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8741.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8750.h
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8776.h
sound/soc/codecs/wm8804.c [new file with mode: 0644]
sound/soc/codecs/wm8804.h [new file with mode: 0644]
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8900.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8903.h
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8904.h
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8940.h
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8955.h
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8960.h
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8961.h
sound/soc/codecs/wm8962.c [new file with mode: 0644]
sound/soc/codecs/wm8962.h [new file with mode: 0644]
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8971.h
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8974.h
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8978.h
sound/soc/codecs/wm8985.c [new file with mode: 0644]
sound/soc/codecs/wm8985.h [new file with mode: 0644]
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8988.h
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8990.h
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8993.h
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9081.h
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9090.h
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9705.h
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9712.h
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm9713.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-i2s.h
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-sffsdr.c
sound/soc/davinci/davinci-vcif.c
sound/soc/davinci/davinci-vcif.h [deleted file]
sound/soc/ep93xx/Kconfig
sound/soc/ep93xx/Makefile
sound/soc/ep93xx/ep93xx-ac97.c [new file with mode: 0644]
sound/soc/ep93xx/ep93xx-i2s.c
sound/soc/ep93xx/ep93xx-i2s.h [deleted file]
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/ep93xx/ep93xx-pcm.h
sound/soc/ep93xx/simone.c [new file with mode: 0644]
sound/soc/ep93xx/snappercl15.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/efika-audio-fabric.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_dma.h
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_ssi.h
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_ac97.h
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/p1022_ds.c [new file with mode: 0644]
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/fsl/soc-of-simple.c [deleted file]
sound/soc/imx/Kconfig
sound/soc/imx/Makefile
sound/soc/imx/eukrea-tlv320.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-pcm-fiq.c
sound/soc/imx/imx-ssi.c
sound/soc/imx/imx-ssi.h
sound/soc/imx/phycore-ac97.c
sound/soc/imx/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/jz4740-i2s.h
sound/soc/jz4740/jz4740-pcm.c
sound/soc/jz4740/jz4740-pcm.h
sound/soc/jz4740/qi_lb60.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-dma.h [deleted file]
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-i2s.h [deleted file]
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/nuc900/nuc900-audio.c
sound/soc/nuc900/nuc900-audio.h
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/igep0020.c
sound/soc/omap/mcpdm.c
sound/soc/omap/mcpdm.h
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-mcpdm.h [deleted file]
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/omap2evm.c
sound/soc/omap/omap3beagle.c
sound/soc/omap/omap3evm.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/overo.c
sound/soc/omap/rx51.c
sound/soc/omap/sdp3430.c
sound/soc/omap/sdp4430.c
sound/soc/omap/zoom2.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/imote2.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa-ssp.h
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-ac97.h
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-i2s.h
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/pxa2xx-pcm.h [deleted file]
sound/soc/pxa/raumfeld.c
sound/soc/pxa/saarb.c [new file with mode: 0644]
sound/soc/pxa/spitz.c
sound/soc/pxa/tavorevb3.c [new file with mode: 0644]
sound/soc/pxa/tosa.c
sound/soc/pxa/z2.c
sound/soc/pxa/zylonite.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/aquila_wm8994.c [new file with mode: 0644]
sound/soc/s3c24xx/goni_wm8994.c [new file with mode: 0644]
sound/soc/s3c24xx/jive_wm8750.c
sound/soc/s3c24xx/ln2440sbc_alc650.c
sound/soc/s3c24xx/neo1973_gta02_wm8753.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/rx1950_uda1380.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c-ac97.c
sound/soc/s3c24xx/s3c-ac97.h
sound/soc/s3c24xx/s3c-dma.c
sound/soc/s3c24xx/s3c-dma.h
sound/soc/s3c24xx/s3c-i2s-v2.c
sound/soc/s3c24xx/s3c-i2s-v2.h
sound/soc/s3c24xx/s3c-pcm.c
sound/soc/s3c24xx/s3c-pcm.h
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2412-i2s.h
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-i2s.h
sound/soc/s3c24xx/s3c24xx_simtec.c
sound/soc/s3c24xx/s3c24xx_simtec.h
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
sound/soc/s3c24xx/s3c24xx_uda134x.c
sound/soc/s3c24xx/s3c64xx-i2s-v4.c
sound/soc/s3c24xx/s3c64xx-i2s.c
sound/soc/s3c24xx/s3c64xx-i2s.h
sound/soc/s3c24xx/smartq_wm8987.c
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/s3c24xx/smdk64xx_wm8580.c
sound/soc/s3c24xx/smdk_spdif.c [new file with mode: 0644]
sound/soc/s3c24xx/smdk_wm9713.c
sound/soc/s3c24xx/spdif.c [new file with mode: 0644]
sound/soc/s3c24xx/spdif.h [new file with mode: 0644]
sound/soc/s6000/s6000-i2s.c
sound/soc/s6000/s6000-i2s.h
sound/soc/s6000/s6000-pcm.c
sound/soc/s6000/s6000-pcm.h
sound/soc/s6000/s6105-ipcam.c
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi-ak4642.c
sound/soc/sh/fsi-da7210.c
sound/soc/sh/fsi-hdmi.c [new file with mode: 0644]
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/migor.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/siu.h
sound/soc/sh/siu_dai.c
sound/soc/sh/siu_pcm.c
sound/soc/sh/ssi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/txx9/txx9aclc-generic.c
sound/soc/txx9/txx9aclc.c
sound/soc/txx9/txx9aclc.h
sound/synth/emux/emux_hwdep.c
sound/usb/Kconfig
sound/usb/caiaq/audio.c
sound/usb/caiaq/control.c
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/caiaq/input.c
sound/usb/card.c
sound/usb/endpoint.c
sound/usb/helper.c
sound/usb/midi.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/proc.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/urb.c
sound/usb/usbaudio.h
sound/usb/usx2y/usx2yhwdeppcm.c

diff --git a/Documentation/ABI/obsolete/dv1394 b/Documentation/ABI/obsolete/dv1394
deleted file mode 100644 (file)
index 2ee3686..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-What:          dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
-Contact:       linux1394-devel@lists.sourceforge.net
-Description:
-       New application development should use raw1394 + userspace libraries
-       instead, notably libiec61883 which is functionally equivalent.
-
-Users:
-       ffmpeg/libavformat (used by a variety of media players)
-       dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
diff --git a/Documentation/ABI/removed/dv1394 b/Documentation/ABI/removed/dv1394
new file mode 100644 (file)
index 0000000..c2310b6
--- /dev/null
@@ -0,0 +1,14 @@
+What:          dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
+Date:          May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:       linux1394-devel@lists.sourceforge.net
+Description:
+       /dev/dv1394/* were character device files, one for each FireWire
+       controller and for NTSC and PAL respectively, from which DV data
+       could be received by read() or transmitted by write().  A few
+       ioctl()s allowed limited control.
+       This special-purpose interface has been superseded by libraw1394 +
+       libiec61883 which are functionally equivalent, support HDV, and
+       transparently work on top of the newer firewire kernel drivers.
+
+Users:
+       ffmpeg/libavformat (if configured for DV1394)
diff --git a/Documentation/ABI/removed/raw1394 b/Documentation/ABI/removed/raw1394
new file mode 100644 (file)
index 0000000..490aa1e
--- /dev/null
@@ -0,0 +1,15 @@
+What:          raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
+Date:          May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:       linux1394-devel@lists.sourceforge.net
+Description:
+       /dev/raw1394 was a character device file that allowed low-level
+       access to FireWire buses.  Its major drawbacks were its inability
+       to implement sensible device security policies, and its low level
+       of abstraction that required userspace clients do duplicate much
+       of the kernel's ieee1394 core functionality.
+       Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+       firewire-core.
+
+Users:
+       libraw1394 (works with firewire-cdev too, transparent to library ABI
+       users)
diff --git a/Documentation/ABI/removed/raw1394_legacy_isochronous b/Documentation/ABI/removed/raw1394_legacy_isochronous
deleted file mode 100644 (file)
index 1b62962..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-What:          legacy isochronous ABI of raw1394 (1st generation iso ABI)
-Date:          June 2007 (scheduled), removed in kernel v2.6.23
-Contact:       linux1394-devel@lists.sourceforge.net
-Description:
-       The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
-       been deprecated for quite some time.  They are very inefficient as they
-       come with high interrupt load and several layers of callbacks for each
-       packet.  Because of these deficiencies, the video1394 and dv1394 drivers
-       and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
-
-Users:
-       libraw1394 users via the long deprecated API raw1394_iso_write,
-       raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
-
-       libdc1394, which optionally uses these old libraw1394 calls
-       alternatively to the more efficient video1394 ABI
diff --git a/Documentation/ABI/removed/video1394 b/Documentation/ABI/removed/video1394
new file mode 100644 (file)
index 0000000..c39c25a
--- /dev/null
@@ -0,0 +1,16 @@
+What:          video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
+Date:          May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:       linux1394-devel@lists.sourceforge.net
+Description:
+       /dev/video1394/* were character device files, one for each FireWire
+       controller, which were used for isochronous I/O.  It was added as an
+       alternative to raw1394's isochronous I/O functionality which had
+       performance issues in its first generation.  Any video1394 user had
+       to use raw1394 + libraw1394 too because video1394 did not provide
+       asynchronous I/O for device discovery and configuration.
+       Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+       firewire-core.
+
+Users:
+       libdc1394 (works with firewire-cdev too, transparent to library ABI
+       users)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644 (file)
index 0000000..b82deea
--- /dev/null
@@ -0,0 +1,22 @@
+What:           state
+Date:           Sep 2010
+KernelVersion:  2.6.37
+Contact:        Vernon Mauery <vernux@us.ibm.com>
+Description:    The state file allows a means by which to change in and
+                out of Premium Real-Time Mode (PRTM), as well as the
+                ability to query the current state.
+                    0 => PRTM off
+                    1 => PRTM enabled
+Users:          The ibm-prtm userspace daemon uses this interface.
+
+
+What:           version
+Date:           Sep 2010
+KernelVersion:  2.6.37
+Contact:        Vernon Mauery <vernux@us.ibm.com>
+Description:    The version file provides a means by which to query
+                the RTL table version that lives in the Extended
+                BIOS Data Area (EBDA).
+Users:          The ibm-prtm userspace daemon uses this interface.
+
+
index feca0758391e145a8fb76e5a7059ce7f057e79ab..22edcbb9ddaf7602d8599c89e8d0a643edc4d439 100644 (file)
      <sect1><title>Delaying, scheduling, and timer routines</title>
 !Iinclude/linux/sched.h
 !Ekernel/sched.c
+!Iinclude/linux/completion.h
 !Ekernel/timer.c
+     </sect1>
+     <sect1><title>Wait queues and Wake events</title>
+!Iinclude/linux/wait.h
+!Ekernel/wait.c
      </sect1>
      <sect1><title>High-resolution timers</title>
 !Iinclude/linux/ktime.h
index 6b4e07f28b695893f2a48924cffbb06994b9750b..7160652a8736fc5f2978f720206ec3221570fd51 100644 (file)
@@ -93,6 +93,12 @@ X!Ilib/string.c
 !Elib/crc32.c
 !Elib/crc-ccitt.c
      </sect1>
+
+     <sect1 id="idr"><title>idr/ida Functions</title>
+!Pinclude/linux/idr.h idr sync
+!Plib/idr.c IDA description
+!Elib/idr.c
+     </sect1>
   </chapter>
 
   <chapter id="mm">
index 9961f1564d22d8d546ec80ca592705573a40233e..d2af87ba96e11ed5edc7ac4a81e081cff23ee00c 100644 (file)
@@ -502,16 +502,6 @@ Who:       Thomas Gleixner <tglx@linutronix.de>
 
 ----------------------------
 
-What:  old ieee1394 subsystem (CONFIG_IEEE1394)
-When:  2.6.37
-Files: drivers/ieee1394/ except init_ohci1394_dma.c
-Why:   superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
-       features, better performance, and better security, all with smaller
-       and more modern code base
-Who:   Stefan Richter <stefanr@s5r6.in-berlin.de>
-
-----------------------------
-
 What:  The acpi_sleep=s4_nonvs command line option
 When:  2.6.37
 Files: arch/x86/kernel/acpi/sleep.c
@@ -545,3 +535,13 @@ Why:       Hareware scan is the prefer method for iwlwifi devices for
 Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
 
 ----------------------------
+
+What:   access to nfsd auth cache through sys_nfsservctl or '.' files
+        in the 'nfsd' filesystem.
+When:   2.6.40
+Why:    This is a legacy interface which have been replaced by a more
+        dynamic cache.  Continuing to maintain this interface is an
+        unnecessary burden.
+Who:    NeilBrown <neilb@suse.de>
+
+----------------------------
index 2db4283efa8dbf99e0e6576edc8d0a054d3b299d..8a817f656f0a808dffb344c6a46bab960cb8a0ae 100644 (file)
@@ -349,21 +349,36 @@ call this method upon the IO completion.
 
 --------------------------- block_device_operations -----------------------
 prototypes:
-       int (*open) (struct inode *, struct file *);
-       int (*release) (struct inode *, struct file *);
-       int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+       int (*open) (struct block_device *, fmode_t);
+       int (*release) (struct gendisk *, fmode_t);
+       int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+       int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+       int (*direct_access) (struct block_device *, sector_t, void **, unsigned long *);
        int (*media_changed) (struct gendisk *);
+       void (*unlock_native_capacity) (struct gendisk *);
        int (*revalidate_disk) (struct gendisk *);
+       int (*getgeo)(struct block_device *, struct hd_geometry *);
+       void (*swap_slot_free_notify) (struct block_device *, unsigned long);
 
 locking rules:
-                       BKL     bd_sem
-open:                  yes     yes
-release:               yes     yes
-ioctl:                 yes     no
+                       BKL     bd_mutex
+open:                  no      yes
+release:               no      yes
+ioctl:                 no      no
+compat_ioctl:          no      no
+direct_access:         no      no
 media_changed:         no      no
+unlock_native_capacity:        no      no
 revalidate_disk:       no      no
+getgeo:                        no      no
+swap_slot_free_notify: no      no      (see below)
+
+media_changed, unlock_native_capacity and revalidate_disk are called only from
+check_disk_change().
+
+swap_slot_free_notify is called with swap_lock and sometimes the page lock
+held.
 
-The last two are called only from check_disk_change().
 
 --------------------------- file_operations -------------------------------
 prototypes:
index 2f68cd68876957530b6b7fbbcb23be9f85a623df..a57e12411d2a2570511df65500989110121e476e 100644 (file)
@@ -12,5 +12,9 @@ nfs-rdma.txt
        - how to install and setup the Linux NFS/RDMA client and server software
 nfsroot.txt
        - short guide on setting up a diskless box with NFS root filesystem.
+pnfs.txt
+       - short explanation of some of the internals of the pnfs client code
 rpc-cache.txt
        - introduction to the caching mechanisms in the sunrpc layer.
+idmapper.txt
+       - information for configuring request-keys to be used by idmapper
diff --git a/Documentation/filesystems/nfs/idmapper.txt b/Documentation/filesystems/nfs/idmapper.txt
new file mode 100644 (file)
index 0000000..b9b4192
--- /dev/null
@@ -0,0 +1,67 @@
+
+=========
+ID Mapper
+=========
+Id mapper is used by NFS to translate user and group ids into names, and to
+translate user and group names into ids.  Part of this translation involves
+performing an upcall to userspace to request the information.  Id mapper will
+user request-key to perform this upcall and cache the result.  The program
+/usr/sbin/nfs.idmap should be called by request-key, and will perform the
+translation and initialize a key with the resulting information.
+
+ NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
+ feature.
+
+===========
+Configuring
+===========
+The file /etc/request-key.conf will need to be modified so /sbin/request-key can
+direct the upcall.  The following line should be added:
+
+#OP    TYPE    DESCRIPTION     CALLOUT INFO    PROGRAM ARG1 ARG2 ARG3 ...
+#======        ======= =============== =============== ===============================
+create id_resolver     *       *               /usr/sbin/nfs.idmap %k %d 600
+
+This will direct all id_resolver requests to the program /usr/sbin/nfs.idmap.
+The last parameter, 600, defines how many seconds into the future the key will
+expire.  This parameter is optional for /usr/sbin/nfs.idmap.  When the timeout
+is not specified, nfs.idmap will default to 600 seconds.
+
+id mapper uses for key descriptions:
+         uid:  Find the UID for the given user
+         gid:  Find the GID for the given group
+        user:  Find the user  name for the given UID
+       group:  Find the group name for the given GID
+
+You can handle any of these individually, rather than using the generic upcall
+program.  If you would like to use your own program for a uid lookup then you
+would edit your request-key.conf so it look similar to this:
+
+#OP    TYPE    DESCRIPTION     CALLOUT INFO    PROGRAM ARG1 ARG2 ARG3 ...
+#======        ======= =============== =============== ===============================
+create id_resolver     uid:*   *               /some/other/program %k %d 600
+create id_resolver     *       *               /usr/sbin/nfs.idmap %k %d 600
+
+Notice that the new line was added above the line for the generic program.
+request-key will find the first matching line and corresponding program.  In
+this case, /some/other/program will handle all uid lookups and
+/usr/sbin/nfs.idmap will handle gid, user, and group lookups.
+
+See <file:Documentation/keys-request-keys.txt> for more information about the
+request-key function.
+
+
+=========
+nfs.idmap
+=========
+nfs.idmap is designed to be called by request-key, and should not be run "by
+hand".  This program takes two arguments, a serialized key and a key
+description.  The serialized key is first converted into a key_serial_t, and
+then passed as an argument to keyctl_instantiate (both are part of keyutils.h).
+
+The actual lookups are performed by functions found in nfsidmap.h.  nfs.idmap
+determines the correct function to call by looking at the first part of the
+description string.  For example, a uid lookup description will appear as
+"uid:user@domain".
+
+nfs.idmap will return 0 if the key was instantiated, and non-zero otherwise.
index f2430a7974e1655b3cdbb27b79eb801597ac6059..90c71c6f0d005f6066a6c7932ad55f36f12667d5 100644 (file)
@@ -159,6 +159,28 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
                 Default: any
 
 
+nfsrootdebug
+
+  This parameter enables debugging messages to appear in the kernel
+  log at boot time so that administrators can verify that the correct
+  NFS mount options, server address, and root path are passed to the
+  NFS client.
+
+
+rdinit=<executable file>
+
+  To specify which file contains the program that starts system
+  initialization, administrators can use this command line parameter.
+  The default value of this parameter is "/init".  If the specified
+  file exists and the kernel can execute it, root filesystem related
+  kernel command line parameters, including `nfsroot=', are ignored.
+
+  A description of the process of mounting the root file system can be
+  found in:
+
+    Documentation/early-userspace/README
+
+
 
 
 3.) Boot Loader
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
new file mode 100644 (file)
index 0000000..bc0b9cf
--- /dev/null
@@ -0,0 +1,48 @@
+Reference counting in pnfs:
+==========================
+
+The are several inter-related caches.  We have layouts which can
+reference multiple devices, each of which can reference multiple data servers.
+Each data server can be referenced by multiple devices.  Each device
+can be referenced by multiple layouts.  To keep all of this straight,
+we need to reference count.
+
+
+struct pnfs_layout_hdr
+----------------------
+The on-the-wire command LAYOUTGET corresponds to struct
+pnfs_layout_segment, usually referred to by the variable name lseg.
+Each nfs_inode may hold a pointer to a cache of of these layout
+segments in nfsi->layout, of type struct pnfs_layout_hdr.
+
+We reference the header for the inode pointing to it, across each
+outstanding RPC call that references it (LAYOUTGET, LAYOUTRETURN,
+LAYOUTCOMMIT), and for each lseg held within.
+
+Each header is also (when non-empty) put on a list associated with
+struct nfs_client (cl_layouts).  Being put on this list does not bump
+the reference count, as the layout is kept around by the lseg that
+keeps it in the list.
+
+deviceid_cache
+--------------
+lsegs reference device ids, which are resolved per nfs_client and
+layout driver type.  The device ids are held in a RCU cache (struct
+nfs4_deviceid_cache).  The cache itself is referenced across each
+mount.  The entries (struct nfs4_deviceid) themselves are held across
+the lifetime of each lseg referencing them.
+
+RCU is used because the deviceid is basically a write once, read many
+data structure.  The hlist size of 32 buckets needs better
+justification, but seems reasonable given that we can have multiple
+deviceid's per filesystem, and multiple filesystems per nfs_client.
+
+The hash code is copied from the nfsd code base.  A discussion of
+hashing and variations of this algorithm can be found at:
+http://groups.google.com/group/comp.lang.c/browse_thread/thread/9522965e2b8d3809
+
+data server cache
+-----------------
+file driver devices refer to data servers, which are kept in a module
+level cache.  Its reference is held over the lifetime of the deviceid
+pointing to it.
index a6aca87408830b12aa0302dad05da5fa79244617..a563b74c7aef400ccfcd8e5e0a10cd03b94523f1 100644 (file)
@@ -374,13 +374,13 @@ Swap:                  0 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB
 
-The first  of these lines shows  the same information  as is displayed for the
-mapping in /proc/PID/maps.  The remaining lines show  the size of the mapping,
-the amount of the mapping that is currently resident in RAM, the "proportional
-set size” (divide each shared page by the number of processes sharing it), the
-number of clean and dirty shared pages in the mapping, and the number of clean
-and dirty private pages in the mapping.  The "Referenced" indicates the amount
-of memory currently marked as referenced or accessed.
+The first of these lines shows the same information as is displayed for the
+mapping in /proc/PID/maps.  The remaining lines show the size of the mapping
+(size), the amount of the mapping that is currently resident in RAM (RSS), the
+process' proportional share of this mapping (PSS), the number of clean and
+dirty shared pages in the mapping, and the number of clean and dirty private
+pages in the mapping.  The "Referenced" indicates the amount of memory
+currently marked as referenced or accessed.
 
 This file is only present if the CONFIG_MMU kernel configuration option is
 enabled.
index fc0e39af43c32a42343f97daed5a5d285f844863..4ede421c9687a71d33027b95118c90dc743da0fe 100644 (file)
@@ -62,10 +62,10 @@ replicas continue to be exactly same.
        # mount /dev/sd0  /tmp/a
 
        #ls /tmp/a
-       t1 t2 t2
+       t1 t2 t3
 
        #ls /mnt/a
-       t1 t2 t2
+       t1 t2 t3
 
        Note that the mount has propagated to the mount at /mnt as well.
 
diff --git a/Documentation/hwmon/ltc4261 b/Documentation/hwmon/ltc4261
new file mode 100644 (file)
index 0000000..eba2e2c
--- /dev/null
@@ -0,0 +1,63 @@
+Kernel driver ltc4261
+=====================
+
+Supported chips:
+  * Linear Technology LTC4261
+    Prefix: 'ltc4261'
+    Addresses scanned: -
+    Datasheet:
+        http://cds.linear.com/docs/Datasheet/42612fb.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+The LTC4261/LTC4261-2 negative voltage Hot Swap controllers allow a board
+to be safely inserted and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4261 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4261 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4261
+$ echo ltc4261 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+The chip has two voltage sensors, but only one set of voltage alarm status bits.
+In many many designs, those alarms are associated with the ADIN2 sensor, due to
+the proximity of the ADIN2 pin to the OV pin. ADIN2 is, however, not available
+on all chip variants. To ensure that the alarm condition is reported to the user,
+report it with both voltage sensors.
+
+in1_input              ADIN2 voltage (mV)
+in1_min_alarm          ADIN/ADIN2 Undervoltage alarm
+in1_max_alarm          ADIN/ADIN2 Overvoltage alarm
+
+in2_input              ADIN voltage (mV)
+in2_min_alarm          ADIN/ADIN2 Undervoltage alarm
+in2_max_alarm          ADIN/ADIN2 Overvoltage alarm
+
+curr1_input            SENSE current (mA)
+curr1_alarm            SENSE overcurrent alarm
index 0b6815504e6de780f84b8aef3daa0acec47957ac..4bc2f3c3da5b1a6772eda0eaa712575fea3bf9c9 100644 (file)
@@ -1541,12 +1541,15 @@ and is between 256 and 4096 characters. It is defined in the file
                        1 to enable accounting
                        Default value is 0.
 
-       nfsaddrs=       [NFS]
+       nfsaddrs=       [NFS] Deprecated.  Use ip= instead.
                        See Documentation/filesystems/nfs/nfsroot.txt.
 
        nfsroot=        [NFS] nfs root filesystem for disk-less boxes.
                        See Documentation/filesystems/nfs/nfsroot.txt.
 
+       nfsrootdebug    [NFS] enable nfsroot debugging messages.
+                       See Documentation/filesystems/nfs/nfsroot.txt.
+
        nfs.callback_tcpport=
                        [NFS] set the TCP port on which the NFSv4 callback
                        channel should listen.
@@ -2438,7 +2441,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        topology informations if the hardware supports these.
                        The scheduler will make use of these informations and
                        e.g. base its process migration decisions on it.
-                       Default is off.
+                       Default is on.
 
        tp720=          [HW,PS2]
 
diff --git a/Documentation/misc-devices/apds990x.txt b/Documentation/misc-devices/apds990x.txt
new file mode 100644 (file)
index 0000000..d5408ca
--- /dev/null
@@ -0,0 +1,111 @@
+Kernel driver apds990x
+======================
+
+Supported chips:
+Avago APDS990X
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+
+APDS990x is a combined ambient light and proximity sensor. ALS and proximity
+functionality are highly connected. ALS measurement path must be running
+while the proximity functionality is enabled.
+
+ALS produces raw measurement values for two channels: Clear channel
+(infrared + visible light) and IR only. However, threshold comparisons happen
+using clear channel only. Lux value and the threshold level on the HW
+might vary quite much depending the spectrum of the light source.
+
+Driver makes necessary conversions to both directions so that user handles
+only lux values. Lux value is calculated using information from the both
+channels. HW threshold level is calculated from the given lux value to match
+with current type of the lightning. Sometimes inaccuracy of the estimations
+lead to false interrupt, but that doesn't harm.
+
+ALS contains 4 different gain steps. Driver automatically
+selects suitable gain step. After each measurement, reliability of the results
+is estimated and new measurement is trigged if necessary.
+
+Platform data can provide tuned values to the conversion formulas if
+values are known. Otherwise plain sensor default values are used.
+
+Proximity side is little bit simpler. There is no need for complex conversions.
+It produces directly usable values.
+
+Driver controls chip operational state using pm_runtime framework.
+Voltage regulators are controlled based on chip operational state.
+
+SYSFS
+-----
+
+
+chip_id
+       RO - shows detected chip type and version
+
+power_state
+       RW - enable / disable chip. Uses counting logic
+            1 enables the chip
+            0 disables the chip
+lux0_input
+       RO - measured lux value
+            sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+       RO - lux0_input max value. Actually never reaches since sensor tends
+            to saturate much before that. Real max value varies depending
+            on the light spectrum etc.
+
+lux0_rate
+       RW - measurement rate in Hz
+
+lux0_rate_avail
+       RO - supported measurement rates
+
+lux0_calibscale
+       RW - calibration value. Set to neutral value by default.
+            Output results are multiplied with calibscale / calibscale_default
+            value.
+
+lux0_calibscale_default
+       RO - neutral calibration value
+
+lux0_thresh_above_value
+       RW - HI level threshold value. All results above the value
+            trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+            interrupt.
+
+lux0_thresh_below_value
+       RW - LO level threshold value. All results below the value
+            trigs an interrupt. 0 disables the below interrupt.
+
+prox0_raw
+       RO - measured proximity value
+            sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+       RO - prox0_raw max value (1023)
+
+prox0_raw_en
+       RW - enable / disable proximity - uses counting logic
+            1 enables the proximity
+            0 disables the proximity
+
+prox0_reporting_mode
+       RW - trigger / periodic. In "trigger" mode the driver tells two possible
+            values: 0 or prox0_sensor_range value. 0 means no proximity,
+            1023 means proximity. This causes minimal number of interrupts.
+            In "periodic" mode the driver reports all values above
+            prox0_thresh_above. This causes more interrupts, but it can give
+            _rough_ estimate about the distance.
+
+prox0_reporting_mode_avail
+       RO - accepted values to prox0_reporting_mode (trigger, periodic)
+
+prox0_thresh_above_value
+       RW - threshold level which trigs proximity events.
diff --git a/Documentation/misc-devices/bh1770glc.txt b/Documentation/misc-devices/bh1770glc.txt
new file mode 100644 (file)
index 0000000..7d64c01
--- /dev/null
@@ -0,0 +1,116 @@
+Kernel driver bh1770glc
+=======================
+
+Supported chips:
+ROHM BH1770GLC
+OSRAM SFH7770
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+BH1770GLC and SFH7770 are combined ambient light and proximity sensors.
+ALS and proximity parts operates on their own, but they shares common I2C
+interface and interrupt logic. In principle they can run on their own,
+but ALS side results are used to estimate reliability of the proximity sensor.
+
+ALS produces 16 bit lux values. The chip contains interrupt logic to produce
+low and high threshold interrupts.
+
+Proximity part contains IR-led driver up to 3 IR leds. The chip measures
+amount of reflected IR light and produces proximity result. Resolution is
+8 bit. Driver supports only one channel. Driver uses ALS results to estimate
+reliability of the proximity results. Thus ALS is always running while
+proximity detection is needed.
+
+Driver uses threshold interrupts to avoid need for polling the values.
+Proximity low interrupt doesn't exists in the chip. This is simulated
+by using a delayed work. As long as there is proximity threshold above
+interrupts the delayed work is pushed forward. So, when proximity level goes
+below the threshold value, there is no interrupt and the delayed work will
+finally run. This is handled as no proximity indication.
+
+Chip state is controlled via runtime pm framework when enabled in config.
+
+Calibscale factor is used to hide differences between the chips. By default
+value set to neutral state meaning factor of 1.00. To get proper values,
+calibrated source of light is needed as a reference. Calibscale factor is set
+so that measurement produces about the expected lux value.
+
+SYSFS
+-----
+
+chip_id
+       RO - shows detected chip type and version
+
+power_state
+       RW - enable / disable chip. Uses counting logic
+            1 enables the chip
+            0 disables the chip
+
+lux0_input
+       RO - measured lux value
+            sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+       RO - lux0_input max value
+
+lux0_rate
+       RW - measurement rate in Hz
+
+lux0_rate_avail
+       RO - supported measurement rates
+
+lux0_thresh_above_value
+       RW - HI level threshold value. All results above the value
+            trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+            interrupt.
+
+lux0_thresh_below_value
+       RW - LO level threshold value. All results below the value
+            trigs an interrupt. 0 disables the below interrupt.
+
+lux0_calibscale
+       RW - calibration value. Set to neutral value by default.
+            Output results are multiplied with calibscale / calibscale_default
+            value.
+
+lux0_calibscale_default
+       RO - neutral calibration value
+
+prox0_raw
+       RO - measured proximity value
+            sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+       RO - prox0_raw max value
+
+prox0_raw_en
+       RW - enable / disable proximity - uses counting logic
+            1 enables the proximity
+            0 disables the proximity
+
+prox0_thresh_above_count
+       RW - number of proximity interrupts needed before triggering the event
+
+prox0_rate_above
+       RW - Measurement rate (in Hz) when the level is above threshold
+            i.e. when proximity on has been reported.
+
+prox0_rate_below
+       RW - Measurement rate (in Hz) when the level is below threshold
+            i.e. when proximity off has been reported.
+
+prox0_rate_avail
+       RO - Supported proximity measurement rates in Hz
+
+prox0_thresh_above0_value
+       RW - threshold level which trigs proximity events.
+            Filtered by persistence filter (prox0_thresh_above_count)
+
+prox0_thresh_above1_value
+       RW - threshold level which trigs event immediately
index 7f4dcebda9c62d75fa7a3d23709fc77dbb42cf77..d0eb696d32e8ade011a695a401fdfc51e42d7be5 100644 (file)
@@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
 
+  Module snd-azt1605
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+    chipset.
+
+    port       - port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port   - port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq                - IRQ # for WSS (7,9,10,11)
+    dma1       - DMA # for WSS playback (0,1,3)
+    dma2       - DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port   - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq    - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+    fm_port    - port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
+  Module snd-azt2316
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+    chipset.
+
+    port       - port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port   - port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq                - IRQ # for WSS (7,9,10,11)
+    dma1       - DMA # for WSS playback (0,1,3)
+    dma2       - DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port   - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq    - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+    fm_port    - port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
   Module snd-aw2
   --------------
 
@@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
 
-  Module snd-sgalaxy
-  ------------------
-
-    Module for Aztech Sound Galaxy sound card.
-
-    sbport     - Port # for SB16 interface (0x220,0x240)
-    wssport    - Port # for WSS interface (0x530,0xe80,0xf40,0x604)
-    irq                - IRQ # (7,9,10,11)
-    dma1       - DMA #
-
-    This module supports multiple cards.
-
-    The power-management is supported.
-
   Module snd-sscape
   -----------------
 
index 278cc2122ea056797aa3c6ae04c77b4052f5f5f9..c82beb0076341856ca13b1e1dd125cc440ed439c 100644 (file)
@@ -57,9 +57,11 @@ dead.  However, this detection isn't perfect on some devices.  In such
 a case, you can change the default method via `position_fix` option.
 
 `position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer.  0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above.  If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers.  0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above.  If you get a problem of repeated sounds, this option might
 help.
 
 In addition to that, every controller is known to be broken regarding
index 5c17196c8fe9172f5c2ae7364c1b9d7966d6cb73..312e3754e8c5599b00c644d64be5b9907bb64ada 100644 (file)
@@ -75,7 +75,7 @@ On all -  write a character to /proc/sysrq-trigger.  e.g.:
 
 'f'    - Will call oom_kill to kill a memory hog process.
 
-'g'    - Used by kgdb on ppc and sh platforms.
+'g'    - Used by kgdb (kernel debugger)
 
 'h'     - Will display help (actually any other key than those listed
           here will display help. but 'h' is easy to remember :-)
@@ -110,12 +110,15 @@ On all -  write a character to /proc/sysrq-trigger.  e.g.:
 
 'u'     - Will attempt to remount all mounted filesystems read-only.
 
-'v'    - Dumps Voyager SMP processor info to your console.
+'v'    - Forcefully restores framebuffer console
+'v'    - Causes ETM buffer dump [ARM-specific]
 
 'w'    - Dumps tasks that are in uninterruptable (blocked) state.
 
 'x'    - Used by xmon interface on ppc/powerpc platforms.
 
+'y'    - Show global CPU Registers [SPARC-64 specific]
+
 'z'    - Dump the ftrace buffer
 
 '0'-'9' - Sets the console log level, controlling which kernel messages
index 4bfafb7bc4c5852b2796fa15572a753bcb717a6e..9a3e7012c1900be12f2967c3a71dffb9a71c772d 100644 (file)
@@ -97,6 +97,33 @@ hpet_open_close(int argc, const char **argv)
 void
 hpet_info(int argc, const char **argv)
 {
+       struct hpet_info        info;
+       int                     fd;
+
+       if (argc != 1) {
+               fprintf(stderr, "hpet_info: device-name\n");
+               return;
+       }
+
+       fd = open(argv[0], O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]);
+               return;
+       }
+
+       if (ioctl(fd, HPET_INFO, &info) < 0) {
+               fprintf(stderr, "hpet_info: failed to get info\n");
+               goto out;
+       }
+
+       fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ",
+               info.hi_ireqfreq, info.hi_flags);
+       fprintf(stderr, "hi_hpet %d hi_timer %d\n",
+               info.hi_hpet, info.hi_timer);
+
+out:
+       close(fd);
+       return;
 }
 
 void
index 1b55146d1c8d9b5ef8eee34028c6af11ff41a24c..b3e73ddb1567902fdeb9d65e1a661db9bca7780d 100644 (file)
@@ -46,7 +46,7 @@ use constant HIGH_KSWAPD_LATENCY              => 20;
 use constant HIGH_KSWAPD_REWAKEUP              => 21;
 use constant HIGH_NR_SCANNED                   => 22;
 use constant HIGH_NR_TAKEN                     => 23;
-use constant HIGH_NR_RECLAIM                   => 24;
+use constant HIGH_NR_RECLAIMED                 => 24;
 use constant HIGH_NR_CONTIG_DIRTY              => 25;
 
 my %perprocesspid;
@@ -58,11 +58,13 @@ my $opt_read_procstat;
 my $total_wakeup_kswapd;
 my ($total_direct_reclaim, $total_direct_nr_scanned);
 my ($total_direct_latency, $total_kswapd_latency);
+my ($total_direct_nr_reclaimed);
 my ($total_direct_writepage_file_sync, $total_direct_writepage_file_async);
 my ($total_direct_writepage_anon_sync, $total_direct_writepage_anon_async);
 my ($total_kswapd_nr_scanned, $total_kswapd_wake);
 my ($total_kswapd_writepage_file_sync, $total_kswapd_writepage_file_async);
 my ($total_kswapd_writepage_anon_sync, $total_kswapd_writepage_anon_async);
+my ($total_kswapd_nr_reclaimed);
 
 # Catch sigint and exit on request
 my $sigint_report = 0;
@@ -104,7 +106,7 @@ my $regex_kswapd_wake_default = 'nid=([0-9]*) order=([0-9]*)';
 my $regex_kswapd_sleep_default = 'nid=([0-9]*)';
 my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*)';
 my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_taken=([0-9]*) contig_taken=([0-9]*) contig_dirty=([0-9]*) contig_failed=([0-9]*)';
-my $regex_lru_shrink_inactive_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*)';
+my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) zid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)';
 my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)';
 my $regex_writepage_default = 'page=([0-9a-f]*) pfn=([0-9]*) flags=([A-Z_|]*)';
 
@@ -203,8 +205,8 @@ $regex_lru_shrink_inactive = generate_traceevent_regex(
                        "vmscan/mm_vmscan_lru_shrink_inactive",
                        $regex_lru_shrink_inactive_default,
                        "nid", "zid",
-                       "lru",
-                       "nr_scanned", "nr_reclaimed", "priority");
+                       "nr_scanned", "nr_reclaimed", "priority",
+                       "flags");
 $regex_lru_shrink_active = generate_traceevent_regex(
                        "vmscan/mm_vmscan_lru_shrink_active",
                        $regex_lru_shrink_active_default,
@@ -375,6 +377,16 @@ EVENT_PROCESS:
                        my $nr_contig_dirty = $7;
                        $perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
                        $perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
+               } elsif ($tracepoint eq "mm_vmscan_lru_shrink_inactive") {
+                       $details = $5;
+                       if ($details !~ /$regex_lru_shrink_inactive/o) {
+                               print "WARNING: Failed to parse mm_vmscan_lru_shrink_inactive as expected\n";
+                               print "         $details\n";
+                               print "         $regex_lru_shrink_inactive/o\n";
+                               next;
+                       }
+                       my $nr_reclaimed = $4;
+                       $perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED} += $nr_reclaimed;
                } elsif ($tracepoint eq "mm_vmscan_writepage") {
                        $details = $5;
                        if ($details !~ /$regex_writepage/o) {
@@ -464,8 +476,8 @@ sub dump_stats {
 
        # Print out process activity
        printf("\n");
-       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s %8s\n", "Process", "Direct",  "Wokeup", "Pages",   "Pages",   "Pages",     "Time");
-       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s %8s\n", "details", "Rclms",   "Kswapd", "Scanned", "Sync-IO", "ASync-IO",  "Stalled");
+       printf("%-" . $max_strlen . "s %8s %10s   %8s %8s  %8s %8s %8s %8s\n", "Process", "Direct",  "Wokeup", "Pages",   "Pages",   "Pages",   "Pages",     "Time");
+       printf("%-" . $max_strlen . "s %8s %10s   %8s %8s  %8s %8s %8s %8s\n", "details", "Rclms",   "Kswapd", "Scanned", "Rclmed",  "Sync-IO", "ASync-IO",  "Stalled");
        foreach $process_pid (keys %stats) {
 
                if (!$stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN}) {
@@ -475,6 +487,7 @@ sub dump_stats {
                $total_direct_reclaim += $stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN};
                $total_wakeup_kswapd += $stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
                $total_direct_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+               $total_direct_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
                $total_direct_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
                $total_direct_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
                $total_direct_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
@@ -489,11 +502,12 @@ sub dump_stats {
                        $index++;
                }
 
-               printf("%-" . $max_strlen . "s %8d %10d   %8u   %8u %8u %8.3f",
+               printf("%-" . $max_strlen . "s %8d %10d   %8u %8u  %8u %8u %8.3f",
                        $process_pid,
                        $stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN},
                        $stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD},
                        $stats{$process_pid}->{HIGH_NR_SCANNED},
+                       $stats{$process_pid}->{HIGH_NR_RECLAIMED},
                        $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
                        $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC},
                        $this_reclaim_delay / 1000);
@@ -529,8 +543,8 @@ sub dump_stats {
 
        # Print out kswapd activity
        printf("\n");
-       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Kswapd",   "Kswapd",  "Order",     "Pages",   "Pages",  "Pages");
-       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Sync-IO", "ASync-IO");
+       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Kswapd",   "Kswapd",  "Order",     "Pages",   "Pages",   "Pages",  "Pages");
+       printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Rclmed",  "Sync-IO", "ASync-IO");
        foreach $process_pid (keys %stats) {
 
                if (!$stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE}) {
@@ -539,16 +553,18 @@ sub dump_stats {
 
                $total_kswapd_wake += $stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE};
                $total_kswapd_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+               $total_kswapd_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
                $total_kswapd_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
                $total_kswapd_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
                $total_kswapd_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
                $total_kswapd_writepage_anon_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC};
 
-               printf("%-" . $max_strlen . "s %8d %10d   %8u   %8i %8u",
+               printf("%-" . $max_strlen . "s %8d %10d   %8u %8u  %8i %8u",
                        $process_pid,
                        $stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE},
                        $stats{$process_pid}->{HIGH_KSWAPD_REWAKEUP},
                        $stats{$process_pid}->{HIGH_NR_SCANNED},
+                       $stats{$process_pid}->{HIGH_NR_RECLAIMED},
                        $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
                        $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC});
 
@@ -579,6 +595,7 @@ sub dump_stats {
        print "\nSummary\n";
        print "Direct reclaims:                         $total_direct_reclaim\n";
        print "Direct reclaim pages scanned:            $total_direct_nr_scanned\n";
+       print "Direct reclaim pages reclaimed:          $total_direct_nr_reclaimed\n";
        print "Direct reclaim write file sync I/O:      $total_direct_writepage_file_sync\n";
        print "Direct reclaim write anon sync I/O:      $total_direct_writepage_anon_sync\n";
        print "Direct reclaim write file async I/O:     $total_direct_writepage_file_async\n";
@@ -588,6 +605,7 @@ sub dump_stats {
        print "\n";
        print "Kswapd wakeups:                          $total_kswapd_wake\n";
        print "Kswapd pages scanned:                    $total_kswapd_nr_scanned\n";
+       print "Kswapd pages reclaimed:                  $total_kswapd_nr_reclaimed\n";
        print "Kswapd reclaim write file sync I/O:      $total_kswapd_writepage_file_sync\n";
        print "Kswapd reclaim write anon sync I/O:      $total_kswapd_writepage_anon_sync\n";
        print "Kswapd reclaim write file async I/O:     $total_kswapd_writepage_file_async\n";
@@ -612,6 +630,7 @@ sub aggregate_perprocesspid() {
                $perprocess{$process}->{MM_VMSCAN_WAKEUP_KSWAPD} += $perprocesspid{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
                $perprocess{$process}->{HIGH_KSWAPD_REWAKEUP} += $perprocesspid{$process_pid}->{HIGH_KSWAPD_REWAKEUP};
                $perprocess{$process}->{HIGH_NR_SCANNED} += $perprocesspid{$process_pid}->{HIGH_NR_SCANNED};
+               $perprocess{$process}->{HIGH_NR_RECLAIMED} += $perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED};
                $perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
                $perprocess{$process}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
                $perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
diff --git a/Documentation/vm/highmem.txt b/Documentation/vm/highmem.txt
new file mode 100644 (file)
index 0000000..4324d24
--- /dev/null
@@ -0,0 +1,162 @@
+
+                            ====================
+                            HIGH MEMORY HANDLING
+                            ====================
+
+By: Peter Zijlstra <a.p.zijlstra@chello.nl>
+
+Contents:
+
+ (*) What is high memory?
+
+ (*) Temporary virtual mappings.
+
+ (*) Using kmap_atomic.
+
+ (*) Cost of temporary mappings.
+
+ (*) i386 PAE.
+
+
+====================
+WHAT IS HIGH MEMORY?
+====================
+
+High memory (highmem) is used when the size of physical memory approaches or
+exceeds the maximum size of virtual memory.  At that point it becomes
+impossible for the kernel to keep all of the available physical memory mapped
+at all times.  This means the kernel needs to start using temporary mappings of
+the pieces of physical memory that it wants to access.
+
+The part of (physical) memory not covered by a permanent mapping is what we
+refer to as 'highmem'.  There are various architecture dependent constraints on
+where exactly that border lies.
+
+In the i386 arch, for example, we choose to map the kernel into every process's
+VM space so that we don't have to pay the full TLB invalidation costs for
+kernel entry/exit.  This means the available virtual memory space (4GiB on
+i386) has to be divided between user and kernel space.
+
+The traditional split for architectures using this approach is 3:1, 3GiB for
+userspace and the top 1GiB for kernel space:
+
+               +--------+ 0xffffffff
+               | Kernel |
+               +--------+ 0xc0000000
+               |        |
+               | User   |
+               |        |
+               +--------+ 0x00000000
+
+This means that the kernel can at most map 1GiB of physical memory at any one
+time, but because we need virtual address space for other things - including
+temporary maps to access the rest of the physical memory - the actual direct
+map will typically be less (usually around ~896MiB).
+
+Other architectures that have mm context tagged TLBs can have separate kernel
+and user maps.  Some hardware (like some ARMs), however, have limited virtual
+space when they use mm context tags.
+
+
+==========================
+TEMPORARY VIRTUAL MAPPINGS
+==========================
+
+The kernel contains several ways of creating temporary mappings:
+
+ (*) vmap().  This can be used to make a long duration mapping of multiple
+     physical pages into a contiguous virtual space.  It needs global
+     synchronization to unmap.
+
+ (*) kmap().  This permits a short duration mapping of a single page.  It needs
+     global synchronization, but is amortized somewhat.  It is also prone to
+     deadlocks when using in a nested fashion, and so it is not recommended for
+     new code.
+
+ (*) kmap_atomic().  This permits a very short duration mapping of a single
+     page.  Since the mapping is restricted to the CPU that issued it, it
+     performs well, but the issuing task is therefore required to stay on that
+     CPU until it has finished, lest some other task displace its mappings.
+
+     kmap_atomic() may also be used by interrupt contexts, since it is does not
+     sleep and the caller may not sleep until after kunmap_atomic() is called.
+
+     It may be assumed that k[un]map_atomic() won't fail.
+
+
+=================
+USING KMAP_ATOMIC
+=================
+
+When and where to use kmap_atomic() is straightforward.  It is used when code
+wants to access the contents of a page that might be allocated from high memory
+(see __GFP_HIGHMEM), for example a page in the pagecache.  The API has two
+functions, and they can be used in a manner similar to the following:
+
+       /* Find the page of interest. */
+       struct page *page = find_get_page(mapping, offset);
+
+       /* Gain access to the contents of that page. */
+       void *vaddr = kmap_atomic(page);
+
+       /* Do something to the contents of that page. */
+       memset(vaddr, 0, PAGE_SIZE);
+
+       /* Unmap that page. */
+       kunmap_atomic(vaddr);
+
+Note that the kunmap_atomic() call takes the result of the kmap_atomic() call
+not the argument.
+
+If you need to map two pages because you want to copy from one page to
+another you need to keep the kmap_atomic calls strictly nested, like:
+
+       vaddr1 = kmap_atomic(page1);
+       vaddr2 = kmap_atomic(page2);
+
+       memcpy(vaddr1, vaddr2, PAGE_SIZE);
+
+       kunmap_atomic(vaddr2);
+       kunmap_atomic(vaddr1);
+
+
+==========================
+COST OF TEMPORARY MAPPINGS
+==========================
+
+The cost of creating temporary mappings can be quite high.  The arch has to
+manipulate the kernel's page tables, the data TLB and/or the MMU's registers.
+
+If CONFIG_HIGHMEM is not set, then the kernel will try and create a mapping
+simply with a bit of arithmetic that will convert the page struct address into
+a pointer to the page contents rather than juggling mappings about.  In such a
+case, the unmap operation may be a null operation.
+
+If CONFIG_MMU is not set, then there can be no temporary mappings and no
+highmem.  In such a case, the arithmetic approach will also be used.
+
+
+========
+i386 PAE
+========
+
+The i386 arch, under some circumstances, will permit you to stick up to 64GiB
+of RAM into your 32-bit machine.  This has a number of consequences:
+
+ (*) Linux needs a page-frame structure for each page in the system and the
+     pageframes need to live in the permanent mapping, which means:
+
+ (*) you can have 896M/sizeof(struct page) page-frames at most; with struct
+     page being 32-bytes that would end up being something in the order of 112G
+     worth of pages; the kernel, however, needs to store more than just
+     page-frames in that memory...
+
+ (*) PAE makes your page tables larger - which slows the system down as more
+     data has to be accessed to traverse in TLB fills and the like.  One
+     advantage is that PAE has more PTE bits and can provide advanced features
+     like NX and PAT.
+
+The general recommendation is that you don't use more than 8GiB on a 32-bit
+machine - although more might work for you and your workload, you're pretty
+much on your own - don't expect kernel developers to really care much if things
+come apart.
index 69aa8fe060b30ad65db57b49bb3d3bfa89ada910..debde0128cd0f661937d759923d2dd0790cc2fac 100644 (file)
@@ -243,21 +243,6 @@ F: drivers/pnp/pnpacpi/
 F:     include/linux/acpi.h
 F:     include/acpi/
 
-ACPI BATTERY DRIVERS
-M:     Alexey Starikovskiy <astarikovskiy@suse.de>
-L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
-S:     Supported
-F:     drivers/acpi/battery.c
-F:     drivers/acpi/*sbs*
-
-ACPI EC DRIVER
-M:     Alexey Starikovskiy <astarikovskiy@suse.de>
-L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
-S:     Supported
-F:     drivers/acpi/ec.c
-
 ACPI FAN DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
@@ -657,7 +642,7 @@ ARM/FARADAY FA526 PORT
 M:     Hans Ulli Kroll <ulli.kroll@googlemail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git://git.berlios.de/gemini-board
+T:     git git://git.berlios.de/gemini-board
 F:     arch/arm/mm/*-fa*
 
 ARM/FOOTBRIDGE ARCHITECTURE
@@ -672,7 +657,7 @@ ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
 M:     Sascha Hauer <kernel@pengutronix.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git://git.pengutronix.de/git/imx/linux-2.6.git
+T:     git git://git.pengutronix.de/git/imx/linux-2.6.git
 F:     arch/arm/mach-mx*/
 F:     arch/arm/plat-mxc/
 
@@ -710,8 +695,7 @@ ARM/INCOME PXA270 SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-pxa/income.c
-F:     arch/arm/mach-pxa/include/mach-pxa/income.h
+F:     arch/arm/mach-pxa/colibri-pxa270-income.c
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
@@ -758,13 +742,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-ixp4xx/
 
-ARM/INTEL RESEARCH IMOTE 2 MACHINE SUPPORT
-M:     Jonathan Cameron <jic23@cam.ac.uk>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/mach-pxa/imote2.c
-
-ARM/INTEL RESEARCH STARGATE 2 MACHINE SUPPORT
+ARM/INTEL RESEARCH IMOTE/STARGATE 2 MACHINE SUPPORT
 M:     Jonathan Cameron <jic23@cam.ac.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -929,40 +907,20 @@ W:        http://www.fluff.org/ben/linux/
 S:     Maintained
 F:     arch/arm/mach-s3c2410/
 
-ARM/S3C2440 ARM ARCHITECTURE
+ARM/S3C244x ARM ARCHITECTURE
 M:     Ben Dooks <ben-linux@fluff.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
 F:     arch/arm/mach-s3c2440/
-
-ARM/S3C2442 ARM ARCHITECTURE
-M:     Ben Dooks <ben-linux@fluff.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.fluff.org/ben/linux/
-S:     Maintained
-F:     arch/arm/mach-s3c2442/
-
-ARM/S3C2443 ARM ARCHITECTURE
-M:     Ben Dooks <ben-linux@fluff.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.fluff.org/ben/linux/
-S:     Maintained
 F:     arch/arm/mach-s3c2443/
 
-ARM/S3C6400 ARM ARCHITECTURE
+ARM/S3C64xx ARM ARCHITECTURE
 M:     Ben Dooks <ben-linux@fluff.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
-F:     arch/arm/mach-s3c6400/
-
-ARM/S3C6410 ARM ARCHITECTURE
-M:     Ben Dooks <ben-linux@fluff.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.fluff.org/ben/linux/
-S:     Maintained
-F:     arch/arm/mach-s3c6410/
+F:     arch/arm/mach-s3c64xx/
 
 ARM/S5P ARM ARCHITECTURES
 M:     Kukjin Kim <kgene.kim@samsung.com>
@@ -1562,9 +1520,8 @@ F:        net/ceph
 F:     include/linux/ceph
 
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
-M:     David Vrabel <david.vrabel@csr.com>
 L:     linux-usb@vger.kernel.org
-S:     Supported
+S:     Orphan
 F:     Documentation/usb/WUSB-Design-overview.txt
 F:     Documentation/usb/wusb-cbaf
 F:     drivers/usb/host/hwa-hc.c
@@ -2103,6 +2060,15 @@ S:       Maintained
 F:     drivers/gpu/drm/
 F:     include/drm/
 
+INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
+M:     Chris Wilson <chris@chris-wilson.co.uk>
+L:     intel-gfx@lists.freedesktop.org
+L:     dri-devel@lists.freedesktop.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+S:     Supported
+F:     drivers/gpu/drm/i915
+F:     include/drm/i915*
+
 DSCC4 DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
@@ -2646,10 +2612,10 @@ F:      drivers/net/greth*
 
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 M:     Frank Seidel <frank@f-seidel.de>
-L:     lm-sensors@lm-sensors.org
+L:     platform-driver-x86@vger.kernel.org
 W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 S:     Maintained
-F:     drivers/hwmon/hdaps.c
+F:     drivers/platform/x86/hdaps.c
 
 HWPOISON MEMORY FAILURE HANDLING
 M:     Andi Kleen <andi@firstfloor.org>
@@ -3016,7 +2982,7 @@ M:        Roland Dreier <rolandd@cisco.com>
 M:     Sean Hefty <sean.hefty@intel.com>
 M:     Hal Rosenstock <hal.rosenstock@gmail.com>
 L:     linux-rdma@vger.kernel.org
-W:     http://www.openib.org/
+W:     http://www.openfabrics.org/
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
 S:     Supported
@@ -3766,6 +3732,13 @@ L:       linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/sym53c8xx_2/
 
+LTC4261 HARDWARE MONITOR DRIVER
+M:     Guenter Roeck <linux@roeck-us.net>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/ltc4261
+F:     drivers/hwmon/ltc4261.c
+
 LTP (Linux Test Project)
 M:     Rishikesh K Rajak <risrajak@linux.vnet.ibm.com>
 M:     Garrett Cooper <yanegomi@gmail.com>
@@ -3861,7 +3834,7 @@ F:        drivers/net/wireless/mwl8k.c
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Odd Fixes
-F: drivers/mmc/host/mvsdio.*
+F:     drivers/mmc/host/mvsdio.*
 
 MARVELL YUKON / SYSKONNECT DRIVER
 M:     Mirko Lindner <mlindner@syskonnect.de>
@@ -4952,7 +4925,7 @@ RCUTORTURE MODULE
 M:     Josh Triplett <josh@freedesktop.org>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 S:     Supported
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
 F:     Documentation/RCU/torture.txt
 F:     kernel/rcutorture.c
 
@@ -4977,7 +4950,7 @@ M:        Dipankar Sarma <dipankar@in.ibm.com>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 W:     http://www.rdrop.com/users/paulmck/rclock/
 S:     Supported
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
 F:     Documentation/RCU/
 F:     include/linux/rcu*
 F:     include/linux/srcu*
@@ -5167,6 +5140,16 @@ W:       http://www.kernel.dk
 S:     Maintained
 F:     drivers/scsi/sr*
 
+SCSI RDMA PROTOCOL (SRP) INITIATOR
+M:     David Dillow <dillowda@ornl.gov>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+W:     http://www.openfabrics.org
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dad/srp-initiator.git
+F:     drivers/infiniband/ulp/srp/
+F:     include/scsi/srp.h
+
 SCSI SG DRIVER
 M:     Doug Gilbert <dgilbert@interlog.com>
 L:     linux-scsi@vger.kernel.org
@@ -5389,8 +5372,8 @@ F:        drivers/*/*s3c2410*
 F:     drivers/*/*/*s3c2410*
 
 TI DAVINCI MACHINE SUPPORT
-P:     Kevin Hilman
-M:     davinci-linux-open-source@linux.davincidsp.com
+M:     Kevin Hilman <khilman@deeprootsystems.com>
+L:     davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
 S:     Supported
 F:     arch/arm/mach-davinci
@@ -5991,13 +5974,9 @@ F:       Documentation/filesystems/ufs.txt
 F:     fs/ufs/
 
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
-M:     David Vrabel <david.vrabel@csr.com>
 L:     linux-usb@vger.kernel.org
-S:     Supported
+S:     Orphan
 F:     drivers/uwb/
-X:     drivers/uwb/wlp/
-X:     drivers/uwb/i1480/i1480u-wlp/
-X:     drivers/uwb/i1480/i1480-wlp.h
 F:     include/linux/uwb.h
 F:     include/linux/uwb/
 
@@ -6139,13 +6118,6 @@ L:       linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/serial/option.c
 
-USB OV511 DRIVER
-M:     Mark McClelland <mmcclell@bigfoot.com>
-L:     linux-usb@vger.kernel.org
-W:     http://alpha.dyndns.org/ov511/
-S:     Maintained
-F:     drivers/media/video/ov511.*
-
 USB PEGASUS DRIVER
 M:     Petko Manolov <petkan@users.sourceforge.net>
 L:     linux-usb@vger.kernel.org
@@ -6306,16 +6278,6 @@ S:       Supported
 F:     drivers/usb/host/xhci*
 F:     drivers/usb/host/pci-quirks*
 
-USB ZC0301 DRIVER
-M:     Luca Risolia <luca.risolia@studio.unibo.it>
-L:     linux-usb@vger.kernel.org
-L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
-W:     http://www.linux-projects.org
-S:     Maintained
-F:     Documentation/video4linux/zc0301.txt
-F:     drivers/media/video/zc0301/
-
 USB ZD1201 DRIVER
 L:     linux-wireless@vger.kernel.org
 W:     http://linux-lc100020.sourceforge.net
@@ -6533,15 +6495,6 @@ F:       include/linux/wimax/debug.h
 F:     include/net/wimax.h
 F:     net/wimax/
 
-WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM
-M:     David Vrabel <david.vrabel@csr.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     include/linux/wlp.h
-F:     drivers/uwb/wlp/
-F:     drivers/uwb/i1480/i1480u-wlp/
-F:     drivers/uwb/i1480/i1480-wlp.h
-
 WISTRON LAPTOP BUTTON DRIVER
 M:     Miloslav Trmac <mitr@volny.cz>
 S:     Maintained
index d04ccd73af45f6487f442a0dba26921db884e218..28f93a6c0fde9169b451abc1837d7661bd95152b 100644 (file)
@@ -55,6 +55,9 @@ config ZONE_DMA
        bool
        default y
 
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
index 21ac53383b37eca3cea4e4ff3ac9b0c6d7989d67..9f67a056b46181e36753575698ea40d6944e6fd2 100644 (file)
@@ -247,7 +247,7 @@ struct el_MCPCIA_uncorrected_frame_mcheck {
 #define vip    volatile int __force *
 #define vuip   volatile unsigned int __force *
 
-#ifdef MCPCIA_ONE_HAE_WINDOW
+#ifndef MCPCIA_ONE_HAE_WINDOW
 #define MCPCIA_FROB_MMIO                                               \
        if (__mcpcia_is_mmio(hose)) {                                   \
                set_hae(hose & 0xffffffff);                             \
index 471c07292e0b88f881393036b46ea3594f106b50..91b46801b290420b067966382d1cd0be19d1d11b 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __ALPHA_T2__H__
 #define __ALPHA_T2__H__
 
+/* Fit everything into one 128MB HAE window. */
+#define T2_ONE_HAE_WINDOW 1
+
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <asm/compiler.h>
@@ -19,7 +22,7 @@
  *
  */
 
-#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 26 bits */
+#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 27 bits */
 
 /* GAMMA-SABLE is a SABLE with EV5-based CPUs */
 /* All LYNX machines, EV4 or EV5, use the GAMMA bias also */
@@ -85,7 +88,9 @@
 #define T2_DIR                 (IDENT_ADDR + GAMMA_BIAS + 0x38e0004a0UL)
 #define T2_ICE                 (IDENT_ADDR + GAMMA_BIAS + 0x38e0004c0UL)
 
+#ifndef T2_ONE_HAE_WINDOW
 #define T2_HAE_ADDRESS         T2_HAE_1
+#endif
 
 /*  T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
  3.8fff.ffff
@@ -429,13 +434,15 @@ extern inline void t2_outl(u32 b, unsigned long addr)
  *
  */
 
+#ifdef T2_ONE_HAE_WINDOW
+#define t2_set_hae
+#else
 #define t2_set_hae { \
-       msb = addr  >> 27; \
+       unsigned long msb = addr >> 27; \
        addr &= T2_MEM_R1_MASK; \
        set_hae(msb); \
 }
-
-extern raw_spinlock_t t2_hae_lock;
+#endif
 
 /*
  * NOTE: take T2_DENSE_MEM off in each readX/writeX routine, since
@@ -446,28 +453,22 @@ extern raw_spinlock_t t2_hae_lock;
 __EXTERN_INLINE u8 t2_readb(const volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long result, msb;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long result;
 
        t2_set_hae;
 
        result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
        return __kernel_extbl(result, addr & 3);
 }
 
 __EXTERN_INLINE u16 t2_readw(const volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long result, msb;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long result;
 
        t2_set_hae;
 
        result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
        return __kernel_extwl(result, addr & 3);
 }
 
@@ -478,59 +479,47 @@ __EXTERN_INLINE u16 t2_readw(const volatile void __iomem *xaddr)
 __EXTERN_INLINE u32 t2_readl(const volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long result, msb;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long result;
 
        t2_set_hae;
 
        result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
        return result & 0xffffffffUL;
 }
 
 __EXTERN_INLINE u64 t2_readq(const volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long r0, r1, work, msb;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long r0, r1, work;
 
        t2_set_hae;
 
        work = (addr << 5) + T2_SPARSE_MEM + 0x18;
        r0 = *(vuip)(work);
        r1 = *(vuip)(work + (4 << 5));
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
        return r1 << 32 | r0;
 }
 
 __EXTERN_INLINE void t2_writeb(u8 b, volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long msb, w;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long w;
 
        t2_set_hae;
 
        w = __kernel_insbl(b, addr & 3);
        *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void t2_writew(u16 b, volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long msb, w;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long w;
 
        t2_set_hae;
 
        w = __kernel_inswl(b, addr & 3);
        *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 /*
@@ -540,29 +529,22 @@ __EXTERN_INLINE void t2_writew(u16 b, volatile void __iomem *xaddr)
 __EXTERN_INLINE void t2_writel(u32 b, volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long msb;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
 
        t2_set_hae;
 
        *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void t2_writeq(u64 b, volatile void __iomem *xaddr)
 {
        unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-       unsigned long msb, work;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&t2_hae_lock, flags);
+       unsigned long work;
 
        t2_set_hae;
 
        work = (addr << 5) + T2_SPARSE_MEM + 0x18;
        *(vuip)work = b;
        *(vuip)(work + (4 << 5)) = b >> 32;
-       raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void __iomem *t2_ioportmap(unsigned long addr)
index 71a243294142a41f6a80c0a4dc1e7149aa338dcf..de98a732683d868b29a3175a5cccd6e22c23f1c8 100644 (file)
@@ -318,9 +318,7 @@ extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)
 }
 
 #define pte_offset_map(dir,addr)       pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir),(addr))
 #define pte_unmap(pte)                 do { } while (0)
-#define pte_unmap_nested(pte)          do { } while (0)
 
 extern pgd_t swapper_pg_dir[1024];
 
index e6d90568b65d62a378525dfaf0af8fe3366d160f..2f770e99428961f6233c8d7742f705180455bdb2 100644 (file)
@@ -74,8 +74,6 @@
 # define DBG(args)
 #endif
 
-DEFINE_RAW_SPINLOCK(t2_hae_lock);
-
 static volatile unsigned int t2_mcheck_any_expected;
 static volatile unsigned int t2_mcheck_last_taken;
 
@@ -406,6 +404,7 @@ void __init
 t2_init_arch(void)
 {
        struct pci_controller *hose;
+       struct resource *hae_mem;
        unsigned long temp;
        unsigned int i;
 
@@ -433,7 +432,13 @@ t2_init_arch(void)
         */
        pci_isa_hose = hose = alloc_pci_controller();
        hose->io_space = &ioport_resource;
-       hose->mem_space = &iomem_resource;
+       hae_mem = alloc_resource();
+       hae_mem->start = 0;
+       hae_mem->end = T2_MEM_R1_MASK;
+       hae_mem->name = pci_hae0_name;
+       if (request_resource(&iomem_resource, hae_mem) < 0)
+               printk(KERN_ERR "Failed to request HAE_MEM\n");
+       hose->mem_space = hae_mem;
        hose->index = 0;
 
        hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
index 512685f78097a0ed5406e1e2226641cc007545c8..7fa62488bd16791f77b0218451629d749c2e5351 100644 (file)
@@ -25,6 +25,9 @@
 #ifdef MCPCIA_ONE_HAE_WINDOW
 #define MCPCIA_HAE_ADDRESS     (&alpha_mv.hae_cache)
 #endif
+#ifdef T2_ONE_HAE_WINDOW
+#define T2_HAE_ADDRESS         (&alpha_mv.hae_cache)
+#endif
 
 /* Only a few systems don't define IACK_SC, handling all interrupts through
    the SRM console.  But splitting out that one case from IO() below
index b64e465ac49ce4748fb2707206fcdbfe0d075de0..bf7273f3dc64efa359ece26eed3a7e19192e7bf2 100644 (file)
@@ -573,6 +573,7 @@ config ARCH_TEGRA
        select HAVE_CLK
        select COMMON_CLKDEV
        select ARCH_HAS_BARRIERS if CACHE_L2X0
+       select ARCH_HAS_CPUFREQ
        help
          This enables support for NVIDIA Tegra based systems (Tegra APX,
          Tegra 6xx and Tegra 2 series).
@@ -831,7 +832,7 @@ config ARCH_OMAP
        select GENERIC_CLOCKEVENTS
        select ARCH_HAS_HOLES_MEMORYMODEL
        help
-         Support for TI's OMAP platform (OMAP1 and OMAP2).
+         Support for TI's OMAP platform (OMAP1/2/3/4).
 
 config PLAT_SPEAR
        bool "ST SPEAr"
index ba6670556f78f9e9410d1a59cb64cd7181cc3bd1..cdc40c4b8c48f6ff9a36b05033d31c28f6339b73 100644 (file)
@@ -17,6 +17,8 @@ CONFIG_MODVERSIONS=y
 CONFIG_ARCH_DAVINCI=y
 CONFIG_ARCH_DAVINCI_DA830=y
 CONFIG_ARCH_DAVINCI_DA850=y
+CONFIG_MACH_MITYOMAPL138=y
+CONFIG_MACH_OMAPL138_HAWKBOARD=y
 CONFIG_DAVINCI_RESET_CLOCKS=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -79,6 +81,7 @@ CONFIG_I2C_DAVINCI=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DUMMY=y
 CONFIG_REGULATOR_TPS6507X=y
 CONFIG_FB=y
 CONFIG_FB_DA8XX=y
diff --git a/arch/arm/configs/n8x0_defconfig b/arch/arm/configs/n8x0_defconfig
deleted file mode 100644 (file)
index 56aebb6..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_OMAP_RESET_CLOCKS=y
-# CONFIG_OMAP_MUX is not set
-# CONFIG_OMAP_MCBSP is not set
-CONFIG_OMAP_MBOX_FWK=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 console=ttyS2,115200n8 debug earlyprintk rootwait"
-CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_PM=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# 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_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_ONENAND=y
-CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_ONENAND_OTP=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-# CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_HELPER_AUTO is not set
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_MENELAUS=y
-CONFIG_REGULATOR=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
-# CONFIG_MUSB_PIO_ONLY is not set
-CONFIG_USB_MUSB_DEBUG=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_ETH=m
-CONFIG_USB_ETH_EEM=y
-CONFIG_MMC=y
-CONFIG_MMC_OMAP=y
-CONFIG_EXT3_FS=y
-CONFIG_INOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
new file mode 100644 (file)
index 0000000..ccedde1
--- /dev/null
@@ -0,0 +1,293 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP2=y
+CONFIG_ARCH_OMAP3=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_MACH_OMAP_GENERIC=y
+CONFIG_ARCH_OMAP2420=y
+CONFIG_ARCH_OMAP2430=y
+CONFIG_ARCH_OMAP3430=y
+CONFIG_MACH_OMAP_H4=y
+CONFIG_MACH_OMAP_APOLLON=y
+CONFIG_MACH_OMAP_2430SDP=y
+CONFIG_MACH_OMAP3_BEAGLE=y
+CONFIG_MACH_DEVKIT8000=y
+CONFIG_MACH_OMAP_LDP=y
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+CONFIG_MACH_OMAP3517EVM=y
+CONFIG_MACH_OMAP3_PANDORA=y
+CONFIG_MACH_OMAP3_TOUCHBOOK=y
+CONFIG_MACH_OMAP_3430SDP=y
+CONFIG_MACH_NOKIA_N8X0=y
+CONFIG_MACH_NOKIA_RX51=y
+CONFIG_MACH_OMAP_ZOOM2=y
+CONFIG_MACH_OMAP_ZOOM3=y
+CONFIG_MACH_CM_T35=y
+CONFIG_MACH_IGEP0020=y
+CONFIG_MACH_SBC3530=y
+CONFIG_MACH_OMAP_3630SDP=y
+CONFIG_MACH_OMAP_4430SDP=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_ERRATA_411920=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_LOCAL_TIMERS is not set
+CONFIG_AEABI=y
+CONFIG_LEDS=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
+CONFIG_KEXEC=y
+CONFIG_FPE_NWFPE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_LEDS=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_EEPROM_LEGACY=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_DEBUG=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_TWL4030=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+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
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_OMAP=y
+CONFIG_SPI=y
+CONFIG_SPI_OMAP24XX=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_W1=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_WATCHDOG=y
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MENELAUS=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_TPS65023=y
+CONFIG_REGULATOR_TPS6507X=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_OMAP_LCD_VGA=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_DISPLAY_SUPPORT=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_DEBUG=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_ZERO=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TWL92330=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_PROVE_LOCKING=y
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SECURITY=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/omap3_defconfig b/arch/arm/configs/omap3_defconfig
deleted file mode 100644 (file)
index 5db9a6b..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_ARCH_OMAP3=y
-CONFIG_ARCH_OMAP4=y
-CONFIG_OMAP_RESET_CLOCKS=y
-CONFIG_OMAP_MUX_DEBUG=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_ARCH_OMAP2430=y
-CONFIG_ARCH_OMAP3430=y
-CONFIG_MACH_OMAP_H4=y
-CONFIG_MACH_OMAP_APOLLON=y
-CONFIG_MACH_OMAP_2430SDP=y
-CONFIG_MACH_OMAP3_BEAGLE=y
-CONFIG_MACH_DEVKIT8000=y
-CONFIG_MACH_OMAP_LDP=y
-CONFIG_MACH_OVERO=y
-CONFIG_MACH_OMAP3EVM=y
-CONFIG_MACH_OMAP3517EVM=y
-CONFIG_MACH_OMAP3_PANDORA=y
-CONFIG_MACH_OMAP3_TOUCHBOOK=y
-CONFIG_MACH_OMAP_3430SDP=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_MACH_NOKIA_RX51=y
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_MACH_OMAP_ZOOM3=y
-CONFIG_MACH_CM_T35=y
-CONFIG_MACH_IGEP0020=y
-CONFIG_MACH_SBC3530=y
-CONFIG_MACH_OMAP_3630SDP=y
-CONFIG_MACH_OMAP_4430SDP=y
-CONFIG_ARM_THUMBEE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyS2,115200"
-CONFIG_KEXEC=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
-CONFIG_PM_DEBUG=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=y
-CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_LL=y
-CONFIG_BT_HCIBCM203X=y
-CONFIG_BT_HCIBPA10X=y
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
-CONFIG_MAC80211_RC_PID=y
-CONFIG_MAC80211_RC_DEFAULT_PID=y
-CONFIG_MAC80211_LEDS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_CONNECTOR=y
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_OOPS=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_ONENAND=y
-CONFIG_MTD_ONENAND_VERIFY_WRITE=y
-CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_UBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_EEPROM_LEGACY=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_LIBERTAS=y
-CONFIG_LIBERTAS_USB=y
-CONFIG_LIBERTAS_SDIO=y
-CONFIG_LIBERTAS_DEBUG=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_INPUT_JOYDEV=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_KEYBOARD_GPIO=y
-CONFIG_KEYBOARD_TWL4030=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-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
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_TWL4030=y
-CONFIG_W1=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_WATCHDOG=y
-CONFIG_MENELAUS=y
-CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_TWL4030=y
-CONFIG_REGULATOR_TPS65023=y
-CONFIG_REGULATOR_TPS6507X=y
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_OMAP_LCD_VGA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_LCD_PLATFORM=y
-CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_VERBOSE_PRINTK=y
-CONFIG_SND_DEBUG=y
-CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
-CONFIG_USB_MON=y
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
-CONFIG_USB_MUSB_DEBUG=y
-CONFIG_USB_WDM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
-CONFIG_USB_TEST=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
-CONFIG_USB_ZERO=m
-CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_SDIO_UART=y
-CONFIG_MMC_OMAP=y
-CONFIG_MMC_OMAP_HS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_TWL92330=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_UBIFS_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_LL=y
-CONFIG_SECURITY=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC7=y
-CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig
deleted file mode 100644 (file)
index 14c1e18..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_ELF_CORE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP4=y
-# CONFIG_ARCH_OMAP2PLUS_TYPICAL is not set
-# CONFIG_ARCH_OMAP2 is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_OMAP_MUX is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_DM_TIMER=y
-CONFIG_MACH_OMAP_4430SDP=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PL310_ERRATA_588369=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
-# CONFIG_LOCAL_TIMERS is not set
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS2,115200n8 initrd=0x81600000,20M ramdisk_size=20480"
-CONFIG_VFP=y
-CONFIG_NEON=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_FW_LOADER is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_KS8851=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-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
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_CORE=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_TWL4030=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_OMAP_HS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_FTRACE is not set
-# CONFIG_ARM_UNWIND is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/omap_generic_2420_defconfig b/arch/arm/configs/omap_generic_2420_defconfig
deleted file mode 100644 (file)
index ac08e51..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-# CONFIG_OMAP_MUX is not set
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_FPE_NWFPE=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_INOTIFY=y
-CONFIG_ROMFS_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/pcontrol_g20_defconfig b/arch/arm/configs/pcontrol_g20_defconfig
new file mode 100644 (file)
index 0000000..b42ee62
--- /dev/null
@@ -0,0 +1,175 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="/opt/arm-2010q1/bin/arm-none-linux-gnueabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91SAM9G20=y
+CONFIG_MACH_PCONTROL_G20=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 mem=128M mtdparts=atmel_nand:128k(bootstrap)ro,256k(uboot)ro,128k(env1)ro,128k(env2)ro,2M(linux),-(root) root=/dev/mmcblk0p1 rootwait rw"
+CONFIG_VFP=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# 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_IPV6 is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_AT24=m
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MACVLAN=m
+CONFIG_TUN=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+CONFIG_SMSC911X=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_INPUT_POLLDEV=y
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+# CONFIG_SERIO is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_MAX3100=m
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_R3964=m
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_GPIO=m
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_W1=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_DS2431=m
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=m
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_HID=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_ATMELMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AT91SAM9=y
+CONFIG_AUXDISPLAY=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
index 5aff581266024831e359ce30658dd191403714cd..1fc684e70ab6a6c9915ad5fbd302066ccb050a29 100644 (file)
@@ -35,9 +35,9 @@ extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
 #ifdef CONFIG_HIGHMEM
 extern void *kmap(struct page *page);
 extern void kunmap(struct page *page);
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
 extern struct page *kmap_atomic_to_page(const void *ptr);
 #endif
 
index a9672e8406a3cdb5efd45f69b0cbe10e47196ec2..b155414192daea110acf0f890a6f3d139ceef182 100644 (file)
@@ -263,17 +263,15 @@ extern struct page *empty_zero_page;
 #define pte_page(pte)          (pfn_to_page(pte_pfn(pte)))
 #define pte_offset_kernel(dir,addr)    (pmd_page_vaddr(*(dir)) + __pte_index(addr))
 
-#define pte_offset_map(dir,addr)       (__pte_map(dir, KM_PTE0) + __pte_index(addr))
-#define pte_offset_map_nested(dir,addr)        (__pte_map(dir, KM_PTE1) + __pte_index(addr))
-#define pte_unmap(pte)                 __pte_unmap(pte, KM_PTE0)
-#define pte_unmap_nested(pte)          __pte_unmap(pte, KM_PTE1)
+#define pte_offset_map(dir,addr)       (__pte_map(dir) + __pte_index(addr))
+#define pte_unmap(pte)                 __pte_unmap(pte)
 
 #ifndef CONFIG_HIGHPTE
-#define __pte_map(dir,km)      pmd_page_vaddr(*(dir))
-#define __pte_unmap(pte,km)    do { } while (0)
+#define __pte_map(dir)         pmd_page_vaddr(*(dir))
+#define __pte_unmap(pte)       do { } while (0)
 #else
-#define __pte_map(dir,km)      ((pte_t *)kmap_atomic(pmd_page(*(dir)), km) + PTRS_PER_PTE)
-#define __pte_unmap(pte,km)    kunmap_atomic((pte - PTRS_PER_PTE), km)
+#define __pte_map(dir)         ((pte_t *)kmap_atomic(pmd_page(*(dir))) + PTRS_PER_PTE)
+#define __pte_unmap(pte)       kunmap_atomic((pte - PTRS_PER_PTE))
 #endif
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
index abed4d15a7fdfee9b8616c14e8d3da0d1ab6e6c8..c015b684b4fe5c311d7e5bbecb20fd3c9aae7b91 100644 (file)
@@ -375,6 +375,12 @@ config MACH_STAMP9G20
          evaluation board.
          <http://www.taskit.de/en/>
 
+config MACH_PCONTROL_G20
+       bool "PControl G20 CPU module"
+       help
+         Select this if you are using taskit's Stamp9G20 CPU module on this
+         carrier board, beeing the decentralized unit of a building automation
+         system; featuring nvram, eth-switch, iso-rs485, display, io
 endif
 
 if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
index 412b3a471a4b43e4a6053c5f57deb822a0e14633..821eb842795f137d94a2904ffe5d1db827dca4bf 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 sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G10) += 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_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9RL)  += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT572D940HF)  += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
@@ -65,6 +65,7 @@ obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
 obj-$(CONFIG_MACH_CPU9G20)     += board-cpu9krea.o
 obj-$(CONFIG_MACH_STAMP9G20)   += board-stamp9g20.o
 obj-$(CONFIG_MACH_PORTUXG20)   += board-stamp9g20.o
+obj-$(CONFIG_MACH_PCONTROL_G20)        += board-pcontrol-g20.o
 
 # AT91SAM9260/AT91SAM9G20 board-specific support
 obj-$(CONFIG_MACH_SNAPPER_9260)        += board-snapper9260.o
index 0894f1077be7db5368568fefd64b9831280d447c..195208b30024cff807656304c1aef3bf833d8f83 100644 (file)
@@ -279,11 +279,6 @@ static struct at91_gpio_bank at91sam9260_gpio[] = {
        }
 };
 
-static void at91sam9260_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9260_poweroff(void)
 {
        at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -327,7 +322,7 @@ void __init at91sam9260_initialize(unsigned long main_clock)
        else
                iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
 
-       at91_arch_reset = at91sam9260_reset;
+       at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9260_poweroff;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
                        | (1 << AT91SAM9260_ID_IRQ2);
index 4ecf37996c770faf83e48d93cf707ef4dd90fc45..fcad88668504bde5331b764419b0676fa89edc68 100644 (file)
@@ -257,11 +257,6 @@ static struct at91_gpio_bank at91sam9261_gpio[] = {
        }
 };
 
-static void at91sam9261_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9261_poweroff(void)
 {
        at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -283,7 +278,7 @@ void __init at91sam9261_initialize(unsigned long main_clock)
                iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
 
 
-       at91_arch_reset = at91sam9261_reset;
+       at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9261_poweroff;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
                        | (1 << AT91SAM9261_ID_IRQ2);
index 942792d630d8c457ed6bf0051babba6dea36a83c..249f900954d8b08c05078c5a7ed0cf57d53255d6 100644 (file)
@@ -269,11 +269,6 @@ static struct at91_gpio_bank at91sam9263_gpio[] = {
        }
 };
 
-static void at91sam9263_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9263_poweroff(void)
 {
        at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -289,7 +284,7 @@ void __init at91sam9263_initialize(unsigned long main_clock)
        /* Map peripherals */
        iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
 
-       at91_arch_reset = at91sam9263_reset;
+       at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9263_poweroff;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
diff --git a/arch/arm/mach-at91/at91sam9_alt_reset.S b/arch/arm/mach-at91/at91sam9_alt_reset.S
new file mode 100644 (file)
index 0000000..e0256de
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * reset AT91SAM9G20 as per errata
+ *
+ * (C) BitBox Ltd 2010
+ *
+ * unless the SDRAM is cleanly shutdown before we hit the
+ * reset register it can be left driving the data bus and
+ * killing the chance of a subsequent boot from NAND
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/linkage.h>
+#include <asm/system.h>
+#include <mach/hardware.h>
+#include <mach/at91sam9_sdramc.h>
+#include <mach/at91_rstc.h>
+
+                       .arm
+
+                       .globl  at91sam9_alt_reset
+
+at91sam9_alt_reset:    mrc     p15, 0, r0, c1, c0, 0
+                       orr     r0, r0, #CR_I
+                       mcr     p15, 0, r0, c1, c0, 0           @ enable I-cache
+
+                       ldr     r0, .at91_va_base_sdramc        @ preload constants
+                       ldr     r1, .at91_va_base_rstc_cr
+
+                       mov     r2, #1
+                       mov     r3, #AT91_SDRAMC_LPCB_POWER_DOWN
+                       ldr     r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST
+
+                       .balign 32                              @ align to cache line
+
+                       str     r2, [r0, #AT91_SDRAMC_TR]       @ disable SDRAM access
+                       str     r3, [r0, #AT91_SDRAMC_LPR]      @ power down SDRAM
+                       str     r4, [r1]                        @ reset processor
+
+                       b       .
+
+.at91_va_base_sdramc:
+       .word AT91_VA_BASE_SYS + AT91_SDRAMC0
+.at91_va_base_rstc_cr:
+       .word AT91_VA_BASE_SYS + AT91_RSTC_CR
index 1276babf84d540ad253d06eb089f29d57beab1a7..1e8f275c17f602349540461bceb989ae34b21ca2 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
+#include <linux/atmel-mci.h>
 
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
@@ -25,6 +26,7 @@
 #include <mach/at91sam9g45_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
+#include <mach/atmel-mci.h>
 
 #include "generic.h"
 
@@ -349,6 +351,169 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {}
 #endif
 
 
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_MCI0,
+               .end    = AT91SAM9G45_BASE_MCI0 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_MCI0,
+               .end    = AT91SAM9G45_ID_MCI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91sam9g45_mmc0_device = {
+       .name           = "atmel_mci",
+       .id             = 0,
+       .dev            = {
+                               .dma_mask               = &mmc_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &mmc0_data,
+       },
+       .resource       = mmc0_resources,
+       .num_resources  = ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_MCI1,
+               .end    = AT91SAM9G45_BASE_MCI1 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_MCI1,
+               .end    = AT91SAM9G45_ID_MCI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91sam9g45_mmc1_device = {
+       .name           = "atmel_mci",
+       .id             = 1,
+       .dev            = {
+                               .dma_mask               = &mmc_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &mmc1_data,
+       },
+       .resource       = mmc1_resources,
+       .num_resources  = ARRAY_SIZE(mmc1_resources),
+};
+
+/* Consider only one slot : slot 0 */
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+{
+
+       if (!data)
+               return;
+
+       /* Must have at least one usable slot */
+       if (!data->slot[0].bus_width)
+               return;
+
+#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
+       {
+       struct at_dma_slave     *atslave;
+       struct mci_dma_data     *alt_atslave;
+
+       alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
+       atslave = &alt_atslave->sdata;
+
+       /* DMA slave channel configuration */
+       atslave->dma_dev = &at_hdmac_device.dev;
+       atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
+       atslave->cfg = ATC_FIFOCFG_HALFFIFO
+                       | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
+       atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
+       if (mmc_id == 0)        /* MCI0 */
+               atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
+                             | ATC_DST_PER(AT_DMA_ID_MCI0);
+
+       else                    /* MCI1 */
+               atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
+                             | ATC_DST_PER(AT_DMA_ID_MCI1);
+
+       data->dma_slave = alt_atslave;
+       }
+#endif
+
+
+       /* input/irq */
+       if (data->slot[0].detect_pin) {
+               at91_set_gpio_input(data->slot[0].detect_pin, 1);
+               at91_set_deglitch(data->slot[0].detect_pin, 1);
+       }
+       if (data->slot[0].wp_pin)
+               at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+       if (mmc_id == 0) {              /* MCI0 */
+
+               /* CLK */
+               at91_set_A_periph(AT91_PIN_PA0, 0);
+
+               /* CMD */
+               at91_set_A_periph(AT91_PIN_PA1, 1);
+
+               /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+               at91_set_A_periph(AT91_PIN_PA2, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_A_periph(AT91_PIN_PA3, 1);
+                       at91_set_A_periph(AT91_PIN_PA4, 1);
+                       at91_set_A_periph(AT91_PIN_PA5, 1);
+                       if (data->slot[0].bus_width == 8) {
+                               at91_set_A_periph(AT91_PIN_PA6, 1);
+                               at91_set_A_periph(AT91_PIN_PA7, 1);
+                               at91_set_A_periph(AT91_PIN_PA8, 1);
+                               at91_set_A_periph(AT91_PIN_PA9, 1);
+                       }
+               }
+
+               mmc0_data = *data;
+               at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
+               platform_device_register(&at91sam9g45_mmc0_device);
+
+       } else {                        /* MCI1 */
+
+               /* CLK */
+               at91_set_A_periph(AT91_PIN_PA31, 0);
+
+               /* CMD */
+               at91_set_A_periph(AT91_PIN_PA22, 1);
+
+               /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+               at91_set_A_periph(AT91_PIN_PA23, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_A_periph(AT91_PIN_PA24, 1);
+                       at91_set_A_periph(AT91_PIN_PA25, 1);
+                       at91_set_A_periph(AT91_PIN_PA26, 1);
+                       if (data->slot[0].bus_width == 8) {
+                               at91_set_A_periph(AT91_PIN_PA27, 1);
+                               at91_set_A_periph(AT91_PIN_PA28, 1);
+                               at91_set_A_periph(AT91_PIN_PA29, 1);
+                               at91_set_A_periph(AT91_PIN_PA30, 1);
+                       }
+               }
+
+               mmc1_data = *data;
+               at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
+               platform_device_register(&at91sam9g45_mmc1_device);
+
+       }
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  NAND / SmartMedia
  * -------------------------------------------------------------------- */
index 211c5c14a1e605d6d4835203c798b9bc47419c9f..6a9d24e5ed8e412680c2364208c46b820959f236 100644 (file)
@@ -242,11 +242,6 @@ static struct at91_gpio_bank at91sam9rl_gpio[] = {
        }
 };
 
-static void at91sam9rl_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9rl_poweroff(void)
 {
        at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -281,7 +276,7 @@ void __init at91sam9rl_initialize(unsigned long main_clock)
        /* Map SRAM */
        iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
 
-       at91_arch_reset = at91sam9rl_reset;
+       at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9rl_poweroff;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
new file mode 100644 (file)
index 0000000..bba5a56
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ *  Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
+ *                     taskit GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+/*
+ * copied and adjusted from board-stamp9g20.c
+ * by Peter Gsellmann <pgsellmann@portner-elektronik.at>
+ */
+
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/w1-gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init pcontrol_g20_map_io(void)
+{
+       /* Initialize processor: 18.432 MHz crystal */
+       at91sam9260_initialize(18432000);
+
+       /* DGBU on ttyS0. (Rx, Tx) only TTL -> JTAG connector X7 17,19 ) */
+       at91_register_uart(0, 0, 0);
+
+       /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
+       at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+                                               | ATMEL_UART_RTS);
+
+       /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485  X5 */
+       at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+                                               | ATMEL_UART_RTS);
+
+       /* USART2 on ttyS3. (Rx, Tx)  9bit-Bus  Multidrop-mode  X4 */
+       at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+
+static void __init init_irq(void)
+{
+       at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * NAND flash 512MiB 1,8V 8-bit, sector size 128 KiB
+ */
+static struct atmel_nand_data __initdata nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+       .rdy_pin        = AT91_PIN_PC13,
+       .enable_pin     = AT91_PIN_PC14,
+};
+
+/*
+ * Bus timings; unit = 7.57ns
+ */
+static struct sam9_smc_config __initdata 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 | AT91_SMC_DBW_8,
+       .tdf_cycles             = 3,
+};
+
+static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
+       .ncs_read_setup         = 16,
+       .nrd_setup              = 18,
+       .ncs_write_setup        = 16,
+       .nwe_setup              = 18,
+
+       .ncs_read_pulse         = 63,
+       .nrd_pulse              = 55,
+       .ncs_write_pulse        = 63,
+       .nwe_pulse              = 55,
+
+       .read_cycle             = 127,
+       .write_cycle            = 127,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+                       | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+                       | AT91_SMC_DBW_8 | AT91_SMC_PS_4
+                       | AT91_SMC_TDFMODE,
+       .tdf_cycles             = 3,
+}, {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 0,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 8,
+       .nrd_pulse              = 8,
+       .ncs_write_pulse        = 5,
+       .nwe_pulse              = 4,
+
+       .read_cycle             = 8,
+       .write_cycle            = 7,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+                       | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+                       | AT91_SMC_DBW_16 | AT91_SMC_PS_8
+                       | AT91_SMC_TDFMODE,
+       .tdf_cycles             = 1,
+} };
+
+static void __init add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &nand_smc_config);
+       at91_add_device_nand(&nand_data);
+}
+
+
+static void __init add_device_pcontrol(void)
+{
+       /* configure chip-select 4 (IO compatible to 8051  X4 ) */
+       sam9_smc_configure(4, &pcontrol_smc_config[0]);
+       /* configure chip-select 7 (FerroRAM 256KiBx16bit MR2A16A  D4 ) */
+       sam9_smc_configure(7, &pcontrol_smc_config[1]);
+}
+
+
+/*
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata mmc_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+       },
+};
+#else
+static struct at91_mmc_data __initdata mmc_data = {
+       .wire4          = 1,
+};
+#endif
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata usbh_data = {
+       .ports          = 2,
+};
+
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata pcontrol_g20_udc_data = {
+       .vbus_pin       = AT91_PIN_PA22,        /* Detect +5V bus voltage */
+       .pullup_pin     = AT91_PIN_PA4,         /* K-state, active low */
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata macb_data = {
+       .phy_irq_pin    = AT91_PIN_PA28,
+       .is_rmii        = 1,
+};
+
+
+/*
+ * I2C devices: eeprom and phy/switch
+ */
+static struct i2c_board_info __initdata pcontrol_g20_i2c_devices[] = {
+{              /* D7  address width=2, 8KiB */
+       I2C_BOARD_INFO("24c64", 0x50)
+}, {           /* D8  address width=1, 1 byte has 32 bits! */
+       I2C_BOARD_INFO("lan9303", 0x0a)
+}, };
+
+
+/*
+ * LEDs
+ */
+static struct gpio_led pcontrol_g20_leds[] = {
+       {
+               .name                   = "LED1",       /* red  H5 */
+               .gpio                   = AT91_PIN_PB18,
+               .active_low             = 1,
+               .default_trigger        = "none",       /* supervisor */
+       }, {
+               .name                   = "LED2",       /* yellow  H7 */
+               .gpio                   = AT91_PIN_PB19,
+               .active_low             = 1,
+               .default_trigger        = "mmc0",       /* SD-card activity */
+       }, {
+               .name                   = "LED3",       /* green  H2 */
+               .gpio                   = AT91_PIN_PB20,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",  /* blinky */
+       }, {
+               .name                   = "LED4",       /* red  H3 */
+               .gpio                   = AT91_PIN_PC6,
+               .active_low             = 1,
+               .default_trigger        = "none",       /* connection lost */
+       }, {
+               .name                   = "LED5",       /* yellow  H6 */
+               .gpio                   = AT91_PIN_PC7,
+               .active_low             = 1,
+               .default_trigger        = "none",       /* unsent data */
+       }, {
+               .name                   = "LED6",       /* green  H1 */
+               .gpio                   = AT91_PIN_PC9,
+               .active_low             = 1,
+               .default_trigger        = "none",       /* snafu */
+       }
+};
+
+
+/*
+ * SPI devices
+ */
+static struct spi_board_info pcontrol_g20_spi_devices[] = {
+       {
+               .modalias       = "spidev",     /* HMI port  X4 */
+               .chip_select    = 1,
+               .max_speed_hz   = 50 * 1000 * 1000,
+               .bus_num        = 0,
+       }, {
+               .modalias       = "spidev",     /* piggyback  A2 */
+               .chip_select    = 0,
+               .max_speed_hz   = 50 * 1000 * 1000,
+               .bus_num        = 1,
+       },
+};
+
+
+/*
+ * Dallas 1-Wire  DS2431
+ */
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+       .pin            = AT91_PIN_PA29,
+       .is_open_drain  = 1,
+};
+
+static struct platform_device w1_device = {
+       .name                   = "w1-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &w1_gpio_pdata,
+};
+
+static void add_wire1(void)
+{
+       at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
+       at91_set_multi_drive(w1_gpio_pdata.pin, 1);
+       platform_device_register(&w1_device);
+}
+
+
+static void __init pcontrol_g20_board_init(void)
+{
+       at91_add_device_serial();
+       add_device_nand();
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+       at91_add_device_mci(0, &mmc_data);
+#else
+       at91_add_device_mmc(0, &mmc_data);
+#endif
+       at91_add_device_usbh(&usbh_data);
+       at91_add_device_eth(&macb_data);
+       at91_add_device_i2c(pcontrol_g20_i2c_devices,
+               ARRAY_SIZE(pcontrol_g20_i2c_devices));
+       add_wire1();
+       add_device_pcontrol();
+       at91_add_device_spi(pcontrol_g20_spi_devices,
+               ARRAY_SIZE(pcontrol_g20_spi_devices));
+       at91_add_device_udc(&pcontrol_g20_udc_data);
+       at91_gpio_leds(pcontrol_g20_leds,
+               ARRAY_SIZE(pcontrol_g20_leds));
+       /* piggyback  A2 */
+       at91_set_gpio_output(AT91_PIN_PB31, 1);
+}
+
+
+MACHINE_START(PCONTROL_G20, "PControl G20")
+       /* Maintainer: pgsellmann@portner-elektronik.at */
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = pcontrol_g20_map_io,
+       .init_irq       = init_irq,
+       .init_machine   = pcontrol_g20_board_init,
+MACHINE_END
index 7913984f6de9bbc1163c987b654afb9d955e0e87..86ff4b52db32bfc64c75b822cf8edf57547e4650 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/clk.h>
+#include <linux/atmel-mci.h>
 
+#include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
@@ -97,6 +99,25 @@ static struct spi_board_info ek_spi_devices[] = {
 };
 
 
+/*
+ * MCI (SD/MMC)
+ */
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PD10,
+       },
+};
+
+static struct mci_platform_data __initdata mci1_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PD11,
+               .wp_pin         = AT91_PIN_PD29,
+       },
+};
+
+
 /*
  * MACB Ethernet device
  */
@@ -380,6 +401,9 @@ static void __init ek_board_init(void)
        at91_add_device_usba(&ek_usba_udc_data);
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+       /* MMC */
+       at91_add_device_mci(0, &mci0_data);
+       at91_add_device_mci(1, &mci1_data);
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* NAND */
index 65c3dc5ba0d0c608e649565121ac59e3ce4d1159..0c66deb2db39a990646d833da4c751e7fc28e81c 100644 (file)
@@ -46,6 +46,9 @@ extern void __init at91_clock_associate(const char *id, struct device *dev, cons
 extern void at91_irq_suspend(void);
 extern void at91_irq_resume(void);
 
+/* reset */
+extern void at91sam9_alt_reset(void);
+
  /* GPIO */
 #define AT91RM9200_PQFP                3       /* AT91RM9200 PQFP package has 3 banks */
 #define AT91RM9200_BGA         4       /* AT91RM9200 BGA package has 4 banks */
index 61566898648004ebb4856ecf3550dc3e046c2204..dafbacc25eb11ddbf5977f6e9fda7253d421c155 100644 (file)
@@ -258,16 +258,23 @@ static int at91_pm_enter(suspend_state_t state)
                         * NOTE: the Wait-for-Interrupt instruction needs to be
                         * in icache so no SDRAM accesses are needed until the
                         * wakeup IRQ occurs and self-refresh is terminated.
+                        * For ARM 926 based chips, this requirement is weaker
+                        * as at91sam9 can access a RAM in self-refresh mode.
                         */
-                       asm("b 1f; .align 5; 1:");
-                       asm("mcr p15, 0, r0, c7, c10, 4");      /* drain write buffer */
+                       asm volatile (  "mov r0, #0\n\t"
+                                       "b 1f\n\t"
+                                       ".align 5\n\t"
+                                       "1: mcr p15, 0, r0, c7, c10, 4\n\t"
+                                       : /* no output */
+                                       : /* no input */
+                                       : "r0");
                        saved_lpr = sdram_selfrefresh_enable();
-                       asm("mcr p15, 0, r0, c7, c0, 4");       /* wait for interrupt */
+                       wait_for_interrupt_enable();
                        sdram_selfrefresh_disable(saved_lpr);
                        break;
 
                case PM_SUSPEND_ON:
-                       asm("mcr p15, 0, r0, c7, c0, 4");       /* wait for interrupt */
+                       cpu_do_idle();
                        break;
 
                default:
index 8c87d0c1b8f8b9b9dc0383bff155798454a6460f..ce9a206991111672d6d1a0a235855c8849adf842 100644 (file)
@@ -21,6 +21,8 @@ static inline u32 sdram_selfrefresh_enable(void)
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()            asm volatile ("mcr p15, 0, %0, c7, c0, 4" \
+                                                               : : "r" (0))
 
 #elif defined(CONFIG_ARCH_AT91CAP9)
 #include <mach/at91cap9_ddrsdr.h>
@@ -38,6 +40,7 @@ static inline u32 sdram_selfrefresh_enable(void)
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()            cpu_do_idle()
 
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
 #include <mach/at91sam9_ddrsdr.h>
@@ -74,6 +77,7 @@ static inline u32 sdram_selfrefresh_enable(void)
                at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
                at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
        } while (0)
+#define wait_for_interrupt_enable()            cpu_do_idle()
 
 #else
 #include <mach/at91sam9_sdramc.h>
@@ -98,5 +102,6 @@ static inline u32 sdram_selfrefresh_enable(void)
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()            cpu_do_idle()
 
 #endif
index b6b00a1f612546eb463036214455336381560e37..f7922a436172a063bf188af5fc2b24cad4ab148e 100644 (file)
@@ -124,6 +124,7 @@ ENTRY(at91_slow_clock)
        ldr     r5, .at91_va_base_ramc1
 
        /* Drain write buffer */
+       mov     r0, #0
        mcr     p15, 0, r0, c7, c10, 4
 
 #ifdef CONFIG_ARCH_AT91RM9200
index 71f90f864748154f573856f23e75cc83c82f8aea..b77b860b36d77a74d267e83d77e40427bbe4badf 100644 (file)
@@ -20,23 +20,23 @@ config ARCH_DAVINCI_DM644x
        select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DM355
-        bool "DaVinci 355 based system"
+       bool "DaVinci 355 based system"
        select AINTC
        select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DM646x
-        bool "DaVinci 646x based system"
+       bool "DaVinci 646x based system"
        select AINTC
        select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DA830
-        bool "DA830/OMAP-L137 based system"
+       bool "DA830/OMAP-L137/AM17x based system"
        select CP_INTC
        select ARCH_DAVINCI_DA8XX
        select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
 
 config ARCH_DAVINCI_DA850
-       bool "DA850/OMAP-L138 based system"
+       bool "DA850/OMAP-L138/AM18x based system"
        select CP_INTC
        select ARCH_DAVINCI_DA8XX
        select ARCH_HAS_CPUFREQ
@@ -115,21 +115,21 @@ config MACH_DAVINCI_DM365_EVM
          for development is a DM365 EVM
 
 config MACH_DAVINCI_DA830_EVM
-       bool "TI DA830/OMAP-L137 Reference Platform"
+       bool "TI DA830/OMAP-L137/AM17x Reference Platform"
        default ARCH_DAVINCI_DA830
        depends on ARCH_DAVINCI_DA830
        select GPIO_PCF857X
        help
-         Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+         Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module.
 
 choice
-       prompt "Select DA830/OMAP-L137 UI board peripheral"
+       prompt "Select DA830/OMAP-L137/AM17x UI board peripheral"
        depends on MACH_DAVINCI_DA830_EVM
        help
-         The presence of UI card on the DA830/OMAP-L137 EVM is detected
-         automatically based on successful probe of the I2C based GPIO
-         expander on that board. This option selected in this menu has
-         an effect only in case of a successful UI card detection.
+         The presence of UI card on the DA830/OMAP-L137/AM17x EVM is
+         detected automatically based on successful probe of the I2C
+         based GPIO expander on that board. This option selected in this
+         menu has an effect only in case of a successful UI card detection.
 
 config DA830_UI_LCD
        bool "LCD"
@@ -140,23 +140,23 @@ config DA830_UI_LCD
 config DA830_UI_NAND
        bool "NAND flash"
        help
-         Say Y here to use the NAND flash.  Do not forget to setup
+         Say Y here to use the NAND flash. Do not forget to setup
          the switch correctly.
 endchoice
 
 config MACH_DAVINCI_DA850_EVM
-       bool "TI DA850/OMAP-L138 Reference Platform"
+       bool "TI DA850/OMAP-L138/AM18x Reference Platform"
        default ARCH_DAVINCI_DA850
        depends on ARCH_DAVINCI_DA850
        select GPIO_PCA953X
        help
-         Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
+         Say Y here to select the TI DA850/OMAP-L138/AM18x Evaluation Module.
 
 choice
        prompt "Select peripherals connected to expander on UI board"
        depends on MACH_DAVINCI_DA850_EVM
        help
-         The presence of User Interface (UI) card on the DA850/OMAP-L138
+         The presence of User Interface (UI) card on the DA850/OMAP-L138/AM18x
          EVM is detected automatically based on successful probe of the I2C
          based GPIO expander on that card. This option selected in this
          menu has an effect only in case of a successful UI card detection.
@@ -165,13 +165,13 @@ config DA850_UI_NONE
        bool "No peripheral is enabled"
        help
          Say Y if you do not want to enable any of the peripherals connected
-         to TCA6416 expander on DA850/OMAP-L138 EVM UI card
+         to TCA6416 expander on DA850/OMAP-L138/AM18x EVM UI card
 
 config DA850_UI_RMII
        bool "RMII Ethernet PHY"
        help
-         Say Y if you want to use the RMII PHY on the DA850/OMAP-L138 EVM.
-         This PHY is found on the UI daughter card that is supplied with
+         Say Y if you want to use the RMII PHY on the DA850/OMAP-L138/AM18x
+         EVM. This PHY is found on the UI daughter card that is supplied with
          the EVM.
          NOTE: Please take care while choosing this option, MII PHY will
          not be functional if RMII mode is selected.
@@ -185,6 +185,22 @@ config MACH_TNETV107X
        help
          Say Y here to select the TI TNETV107X Evaluation Module.
 
+config MACH_MITYOMAPL138
+       bool "Critical Link MityDSP-L138/MityARM-1808 SoM"
+       depends on ARCH_DAVINCI_DA850
+       help
+         Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
+         System on Module.  Information on this SoM may be found at
+         http://www.mitydsp.com
+
+config MACH_OMAPL138_HAWKBOARD
+       bool "TI AM1808 / OMAPL-138 Hawkboard platform"
+       depends on ARCH_DAVINCI_DA850
+       help
+         Say Y here to select the TI AM1808 / OMAPL-138 Hawkboard platform .
+         Information of this board may be found at
+         http://www.hawkboard.org/
+
 config DAVINCI_MUX
        bool "DAVINCI multiplexing support"
        depends on ARCH_DAVINCI
@@ -195,20 +211,20 @@ config DAVINCI_MUX
          say Y.
 
 config DAVINCI_MUX_DEBUG
-        bool "Multiplexing debug output"
-        depends on DAVINCI_MUX
-        help
-          Makes the multiplexing functions print out a lot of debug info.
-          This is useful if you want to find out the correct values of the
-          multiplexing registers.
+       bool "Multiplexing debug output"
+       depends on DAVINCI_MUX
+       help
+         Makes the multiplexing functions print out a lot of debug info.
+         This is useful if you want to find out the correct values of the
+         multiplexing registers.
 
 config DAVINCI_MUX_WARNINGS
-        bool "Warn about pins the bootloader didn't set up"
-        depends on DAVINCI_MUX
-        help
-          Choose Y here to warn whenever driver initialization logic needs
-          to change the pin multiplexing setup.  When there are no warnings
-          printed, it's safe to deselect DAVINCI_MUX for your product.
+       bool "Warn about pins the bootloader didn't set up"
+       depends on DAVINCI_MUX
+       help
+         Choose Y here to warn whenever driver initialization logic needs
+         to change the pin multiplexing setup. When there are no warnings
+         printed, it's safe to deselect DAVINCI_MUX for your product.
 
 config DAVINCI_RESET_CLOCKS
        bool "Reset unused clocks during boot"
index eab4c0fd667a3fe523ab71651a3686183378bbe2..0b87a1ca2bb3a187c78a6b20b68f7c8bb66c2288 100644 (file)
@@ -5,7 +5,7 @@
 
 # Common objects
 obj-y                  := time.o clock.o serial.o io.o psc.o \
-                          gpio.o dma.o usb.o common.o sram.o
+                          gpio.o dma.o usb.o common.o sram.o aemif.o
 
 obj-$(CONFIG_DAVINCI_MUX)              += mux.o
 
@@ -33,6 +33,8 @@ obj-$(CONFIG_MACH_DAVINCI_DM365_EVM)  += board-dm365-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA830_EVM)   += board-da830-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA850_EVM)   += board-da850-evm.o
 obj-$(CONFIG_MACH_TNETV107X)           += board-tnetv107x-evm.o
+obj-$(CONFIG_MACH_MITYOMAPL138)                += board-mityomapl138.o
+obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD)  += board-omapl138-hawk.o
 
 # Power Management
 obj-$(CONFIG_CPU_FREQ)                 += cpufreq.o
diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c
new file mode 100644 (file)
index 0000000..9c3f500
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * AEMIF support for DaVinci SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/time.h>
+
+#include <mach/aemif.h>
+
+/* Timing value configuration */
+
+#define TA(x)          ((x) << 2)
+#define RHOLD(x)       ((x) << 4)
+#define RSTROBE(x)     ((x) << 7)
+#define RSETUP(x)      ((x) << 13)
+#define WHOLD(x)       ((x) << 17)
+#define WSTROBE(x)     ((x) << 20)
+#define WSETUP(x)      ((x) << 26)
+
+#define TA_MAX         0x3
+#define RHOLD_MAX      0x7
+#define RSTROBE_MAX    0x3f
+#define RSETUP_MAX     0xf
+#define WHOLD_MAX      0x7
+#define WSTROBE_MAX    0x3f
+#define WSETUP_MAX     0xf
+
+#define TIMING_MASK    (TA(TA_MAX) | \
+                               RHOLD(RHOLD_MAX) | \
+                               RSTROBE(RSTROBE_MAX) |  \
+                               RSETUP(RSETUP_MAX) | \
+                               WHOLD(WHOLD_MAX) | \
+                               WSTROBE(WSTROBE_MAX) | \
+                               WSETUP(WSETUP_MAX))
+
+/*
+ * aemif_calc_rate - calculate timing data.
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(int wanted, unsigned long clk, int max)
+{
+       int result;
+
+       result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+       pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
+
+       /* It is generally OK to have a more relaxed timing than requested... */
+       if (result < 0)
+               result = 0;
+
+       /* ... But configuring tighter timings is not an option. */
+       else if (result > max)
+               result = -EINVAL;
+
+       return result;
+}
+
+/**
+ * davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
+ * @t: timing values to be progammed
+ * @base: The virtual base address of the AEMIF interface
+ * @cs: chip-select to program the timing values for
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+                                       void __iomem *base, unsigned cs)
+{
+       unsigned set, val;
+       unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+       unsigned offset = A1CR_OFFSET + cs * 4;
+       struct clk *aemif_clk;
+       unsigned long clkrate;
+
+       if (!t)
+               return 0;       /* Nothing to do */
+
+       aemif_clk = clk_get(NULL, "aemif");
+       if (IS_ERR(aemif_clk))
+               return PTR_ERR(aemif_clk);
+
+       clkrate = clk_get_rate(aemif_clk);
+
+       clkrate /= 1000;        /* turn clock into kHz for ease of use */
+
+       ta      = aemif_calc_rate(t->ta, clkrate, TA_MAX);
+       rhold   = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
+       rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
+       rsetup  = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
+       whold   = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
+       wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
+       wsetup  = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
+
+       if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+                       whold < 0 || wstrobe < 0 || wsetup < 0) {
+               pr_err("%s: cannot get suitable timings\n", __func__);
+               return -EINVAL;
+       }
+
+       set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+               WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+       val = __raw_readl(base + offset);
+       val &= ~TIMING_MASK;
+       val |= set;
+       __raw_writel(val, base + offset);
+
+       return 0;
+}
+EXPORT_SYMBOL(davinci_aemif_setup_timing);
index 7f3cdbfc0fbb5229f25b360f4477f28968991cf3..b52a3a1abd945745bf7e251062f7d4b6447f99ab 100644 (file)
 #include <mach/nand.h>
 #include <mach/da8xx.h>
 #include <mach/usb.h>
+#include <mach/aemif.h>
 
-#define DA830_EVM_PHY_MASK             0x0
-#define DA830_EVM_MDIO_FREQUENCY       2200000 /* PHY bus frequency */
-
+#define DA830_EVM_PHY_ID               ""
 /*
  * USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
  */
@@ -360,6 +359,16 @@ static struct nand_bbt_descr da830_evm_nand_bbt_mirror_descr = {
        .pattern        = da830_evm_nand_mirror_pattern
 };
 
+static struct davinci_aemif_timing da830_evm_nandflash_timing = {
+       .wsetup         = 24,
+       .wstrobe        = 21,
+       .whold          = 14,
+       .rsetup         = 19,
+       .rstrobe        = 50,
+       .rhold          = 0,
+       .ta             = 20,
+};
+
 static struct davinci_nand_pdata da830_evm_nand_pdata = {
        .parts          = da830_evm_nand_partitions,
        .nr_parts       = ARRAY_SIZE(da830_evm_nand_partitions),
@@ -368,6 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = {
        .options        = NAND_USE_FLASH_BBT,
        .bbt_td         = &da830_evm_nand_bbt_main_descr,
        .bbt_md         = &da830_evm_nand_bbt_mirror_descr,
+       .timing         = &da830_evm_nandflash_timing,
 };
 
 static struct resource da830_evm_nand_resources[] = {
@@ -546,9 +556,8 @@ static __init void da830_evm_init(void)
 
        da830_evm_usb_init();
 
-       soc_info->emac_pdata->phy_mask = DA830_EVM_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = DA830_EVM_MDIO_FREQUENCY;
        soc_info->emac_pdata->rmii_en = 1;
+       soc_info->emac_pdata->phy_id = DA830_EVM_PHY_ID;
 
        ret = davinci_cfg_reg_list(da830_cpgmac_pins);
        if (ret)
@@ -586,6 +595,9 @@ static __init void da830_evm_init(void)
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static int __init da830_evm_console_init(void)
 {
+       if (!machine_is_davinci_da830_evm())
+               return 0;
+
        return add_preferred_console("ttyS", 2, "115200");
 }
 console_initcall(da830_evm_console_init);
@@ -596,7 +608,7 @@ static void __init da830_evm_map_io(void)
        da830_init();
 }
 
-MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
+MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
        .boot_params    = (DA8XX_DDR_BASE + 0x100),
        .map_io         = da830_evm_map_io,
        .init_irq       = cp_intc_init,
index b26f5cbfce3e2f5f1d8b4e8ee47a5e138e1a2999..c6e11c682e4c31261abb6a0a6c1cb5141b3f60d8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6507x.h>
-#include <linux/mfd/tps6507x.h>
 #include <linux/input/tps6507x-ts.h>
 
 #include <asm/mach-types.h>
 #include <mach/da8xx.h>
 #include <mach/nand.h>
 #include <mach/mux.h>
+#include <mach/aemif.h>
 
-#define DA850_EVM_PHY_MASK             0x1
-#define DA850_EVM_MDIO_FREQUENCY       2200000 /* PHY bus frequency */
-
+#define DA850_EVM_PHY_ID               "0:00"
 #define DA850_LCD_PWR_PIN              GPIO_TO_PIN(2, 8)
 #define DA850_LCD_BL_PIN               GPIO_TO_PIN(2, 15)
 
@@ -110,7 +108,7 @@ static struct platform_device da850_pm_device = {
  * to boot, using TI's tools to install the secondary boot loader
  * (UBL) and U-Boot.
  */
-struct mtd_partition da850_evm_nandflash_partition[] = {
+static struct mtd_partition da850_evm_nandflash_partition[] = {
        {
                .name           = "u-boot env",
                .offset         = 0,
@@ -143,12 +141,23 @@ struct mtd_partition da850_evm_nandflash_partition[] = {
        },
 };
 
+static struct davinci_aemif_timing da850_evm_nandflash_timing = {
+       .wsetup         = 24,
+       .wstrobe        = 21,
+       .whold          = 14,
+       .rsetup         = 19,
+       .rstrobe        = 50,
+       .rhold          = 0,
+       .ta             = 20,
+};
+
 static struct davinci_nand_pdata da850_evm_nandflash_data = {
        .parts          = da850_evm_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(da850_evm_nandflash_partition),
        .ecc_mode       = NAND_ECC_HW,
        .ecc_bits       = 4,
        .options        = NAND_USE_FLASH_BBT,
+       .timing         = &da850_evm_nandflash_timing,
 };
 
 static struct resource da850_evm_nandflash_resource[] = {
@@ -196,6 +205,30 @@ static void __init da850_evm_init_nor(void)
        iounmap(aemif_addr);
 }
 
+static const short da850_evm_nand_pins[] = {
+       DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+       DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+       DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
+       DA850_NEMA_WE, DA850_NEMA_OE,
+       -1
+};
+
+static const short da850_evm_nor_pins[] = {
+       DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
+       DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
+       DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
+       DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
+       DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
+       DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
+       DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
+       DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
+       DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
+       DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
+       DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
+       DA850_EMA_A_22, DA850_EMA_A_23,
+       -1
+};
+
 static u32 ui_card_detected;
 
 #if defined(CONFIG_MMC_DAVINCI) || \
@@ -205,17 +238,17 @@ static u32 ui_card_detected;
 #define HAS_MMC 0
 #endif
 
-static __init void da850_evm_setup_nor_nand(void)
+static inline void da850_evm_setup_nor_nand(void)
 {
        int ret = 0;
 
        if (ui_card_detected & !HAS_MMC) {
-               ret = davinci_cfg_reg_list(da850_nand_pins);
+               ret = davinci_cfg_reg_list(da850_evm_nand_pins);
                if (ret)
                        pr_warning("da850_evm_init: nand mux setup failed: "
                                        "%d\n", ret);
 
-               ret = davinci_cfg_reg_list(da850_nor_pins);
+               ret = davinci_cfg_reg_list(da850_evm_nor_pins);
                if (ret)
                        pr_warning("da850_evm_init: nor mux setup failed: %d\n",
                                ret);
@@ -406,7 +439,7 @@ static int da850_lcd_hw_init(void)
 /* TPS65070 voltage regulator support */
 
 /* 3.3V */
-struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
        {
                .supply = "usb0_vdda33",
        },
@@ -416,7 +449,7 @@ struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
 };
 
 /* 3.3V or 1.8V */
-struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
        {
                .supply = "dvdd3318_a",
        },
@@ -429,14 +462,14 @@ struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
 };
 
 /* 1.2V */
-struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
        {
                .supply = "cvdd",
        },
 };
 
 /* 1.8V LDO */
-struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
        {
                .supply = "sata_vddr",
        },
@@ -452,7 +485,7 @@ struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
 };
 
 /* 1.2V LDO */
-struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
        {
                .supply = "sata_vdd",
        },
@@ -475,7 +508,7 @@ static struct tps6507x_reg_platform_data tps6507x_platform_data = {
        .defdcdc_default = true,
 };
 
-struct regulator_init_data tps65070_regulator_data[] = {
+static struct regulator_init_data tps65070_regulator_data[] = {
        /* dcdc1 */
        {
                .constraints = {
@@ -576,6 +609,23 @@ static const short da850_evm_lcdc_pins[] = {
        -1
 };
 
+static const short da850_evm_mii_pins[] = {
+       DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+       DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+       DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+       DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+       DA850_MDIO_D,
+       -1
+};
+
+static const short da850_evm_rmii_pins[] = {
+       DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+       DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+       DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+       DA850_MDIO_D,
+       -1
+};
+
 static int __init da850_evm_config_emac(void)
 {
        void __iomem *cfg_chip3_base;
@@ -593,12 +643,12 @@ static int __init da850_evm_config_emac(void)
 
        if (rmii_en) {
                val |= BIT(8);
-               ret = davinci_cfg_reg_list(da850_rmii_pins);
+               ret = davinci_cfg_reg_list(da850_evm_rmii_pins);
                pr_info("EMAC: RMII PHY configured, MII PHY will not be"
                                                        " functional\n");
        } else {
                val &= ~BIT(8);
-               ret = davinci_cfg_reg_list(da850_cpgmac_pins);
+               ret = davinci_cfg_reg_list(da850_evm_mii_pins);
                pr_info("EMAC: MII PHY configured, RMII PHY will not be"
                                                        " functional\n");
        }
@@ -625,8 +675,7 @@ static int __init da850_evm_config_emac(void)
        /* Enable/Disable MII MDIO clock */
        gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, rmii_en);
 
-       soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+       soc_info->emac_pdata->phy_id = DA850_EVM_PHY_ID;
 
        ret = da8xx_register_emac();
        if (ret)
@@ -787,7 +836,7 @@ static __init void da850_evm_init(void)
        if (ret)
                pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
 
-       ret = da850_register_cpufreq();
+       ret = da850_register_cpufreq("pll0_sysclk3");
        if (ret)
                pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
                                ret);
@@ -806,6 +855,9 @@ static __init void da850_evm_init(void)
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static int __init da850_evm_console_init(void)
 {
+       if (!machine_is_davinci_da850_evm())
+               return 0;
+
        return add_preferred_console("ttyS", 2, "115200");
 }
 console_initcall(da850_evm_console_init);
@@ -816,7 +868,7 @@ static void __init da850_evm_map_io(void)
        da850_init();
 }
 
-MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
+MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
        .boot_params    = (DA8XX_DDR_BASE + 0x100),
        .map_io         = da850_evm_map_io,
        .init_irq       = cp_intc_init,
index 944a0cbaf5cb7cdbaf2fe3f29fbdead6b0174850..c67f684ee3e58e219a182c55624e902e069e666b 100644 (file)
@@ -54,9 +54,7 @@ static inline int have_tvp7002(void)
        return 0;
 }
 
-#define DM365_EVM_PHY_MASK             (0x2)
-#define DM365_EVM_MDIO_FREQUENCY       (2200000) /* PHY bus frequency */
-
+#define DM365_EVM_PHY_ID               "0:01"
 /*
  * A MAX-II CPLD is used for various board control functions.
  */
@@ -175,7 +173,9 @@ static struct at24_platform_data eeprom_info = {
        .context        = (void *)0x7f00,
 };
 
-static struct snd_platform_data dm365_evm_snd_data;
+static struct snd_platform_data dm365_evm_snd_data = {
+       .asp_chan_q = EVENTQ_3,
+};
 
 static struct i2c_board_info i2c_info[] = {
        {
@@ -533,8 +533,7 @@ fail:
 
                /* ... and ENET ... */
                dm365evm_emac_configure();
-               soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
-               soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
+               soc_info->emac_pdata->phy_id = DM365_EVM_PHY_ID;
                resets &= ~BIT(3);
 
                /* ... and AIC33 */
index d59fba15ba8de949e6ae1142cada534219d6c4a3..0ca90b834586d8b2fa551279be442d07283b943b 100644 (file)
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
+#include <mach/aemif.h>
 
-#define DM644X_EVM_PHY_MASK            (0x2)
-#define DM644X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
-
+#define DM644X_EVM_PHY_ID              "0:01"
 #define LXT971_PHY_ID  (0x001378e2)
 #define LXT971_PHY_MASK        (0xfffffff0)
 
@@ -137,11 +136,22 @@ static struct mtd_partition davinci_evm_nandflash_partition[] = {
         */
 };
 
+static struct davinci_aemif_timing davinci_evm_nandflash_timing = {
+       .wsetup         = 20,
+       .wstrobe        = 40,
+       .whold          = 20,
+       .rsetup         = 10,
+       .rstrobe        = 40,
+       .rhold          = 10,
+       .ta             = 40,
+};
+
 static struct davinci_nand_pdata davinci_evm_nandflash_data = {
        .parts          = davinci_evm_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(davinci_evm_nandflash_partition),
        .ecc_mode       = NAND_ECC_HW,
        .options        = NAND_USE_FLASH_BBT,
+       .timing         = &davinci_evm_nandflash_timing,
 };
 
 static struct resource davinci_evm_nandflash_resource[] = {
@@ -695,9 +705,7 @@ static __init void davinci_evm_init(void)
        davinci_serial_init(&uart_config);
        dm644x_init_asp(&dm644x_evm_snd_data);
 
-       soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
-
+       soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
        /* Register the fixup for PHY on DaVinci */
        phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
                                        davinci_phy_fixup);
index 6890488fb92b4eb9e67af4138767e2f6efd3a60f..f6ac9ba74878066afdfcde05e3630108ff86f6c1 100644 (file)
@@ -42,6 +42,7 @@
 #include <mach/nand.h>
 #include <mach/clock.h>
 #include <mach/cdce949.h>
+#include <mach/aemif.h>
 
 #include "clock.h"
 
@@ -71,6 +72,16 @@ static struct mtd_partition davinci_nand_partitions[] = {
        }
 };
 
+static struct davinci_aemif_timing dm6467tevm_nandflash_timing = {
+       .wsetup         = 29,
+       .wstrobe        = 24,
+       .whold          = 14,
+       .rsetup         = 19,
+       .rstrobe        = 33,
+       .rhold          = 0,
+       .ta             = 29,
+};
+
 static struct davinci_nand_pdata davinci_nand_data = {
        .mask_cle               = 0x80000,
        .mask_ale               = 0x40000,
@@ -718,9 +729,7 @@ static struct davinci_uart_config uart_config __initdata = {
        .enabled_uarts = (1 << 0),
 };
 
-#define DM646X_EVM_PHY_MASK            (0x2)
-#define DM646X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
-
+#define DM646X_EVM_PHY_ID              "0:01"
 /*
  * The following EDMA channels/slots are not being used by drivers (for
  * example: Timer, GPIO, UART events etc) on dm646x, hence they are being
@@ -763,6 +772,9 @@ static __init void evm_init(void)
        dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
        dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
 
+       if (machine_is_davinci_dm6467tevm())
+               davinci_nand_data.timing = &dm6467tevm_nandflash_timing;
+
        platform_device_register(&davinci_nand_device);
 
        dm646x_init_edma(dm646x_edma_rsv);
@@ -770,8 +782,7 @@ static __init void evm_init(void)
        if (HAS_ATA)
                davinci_init_ide();
 
-       soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+       soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID;
 }
 
 #define DM646X_EVM_REF_FREQ            27000000
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
new file mode 100644 (file)
index 0000000..0bb5f0c
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Critical Link MityOMAP-L138 SoM
+ *
+ * Copyright (C) 2010 Critical Link LLC - http://www.criticallink.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/console.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/etherdevice.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/common.h>
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+#include <mach/nand.h>
+#include <mach/mux.h>
+
+#define MITYOMAPL138_PHY_ID            "0:03"
+
+#define FACTORY_CONFIG_MAGIC   0x012C0138
+#define FACTORY_CONFIG_VERSION 0x00010001
+
+/* Data Held in On-Board I2C device */
+struct factory_config {
+       u32     magic;
+       u32     version;
+       u8      mac[6];
+       u32     fpga_type;
+       u32     spare;
+       u32     serialnumber;
+       char    partnum[32];
+};
+
+static struct factory_config factory_config;
+
+static void read_factory_config(struct memory_accessor *a, void *context)
+{
+       int ret;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
+       if (ret != sizeof(struct factory_config)) {
+               pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
+                               ret);
+               return;
+       }
+
+       if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
+               pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
+                               factory_config.magic);
+               return;
+       }
+
+       if (factory_config.version != FACTORY_CONFIG_VERSION) {
+               pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
+                               factory_config.version);
+               return;
+       }
+
+       pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
+       pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum);
+       if (is_valid_ether_addr(factory_config.mac))
+               memcpy(soc_info->emac_pdata->mac_addr,
+                       factory_config.mac, ETH_ALEN);
+       else
+               pr_warning("MityOMAPL138: Invalid MAC found "
+                               "in factory config block\n");
+}
+
+static struct at24_platform_data mityomapl138_fd_chip = {
+       .byte_len       = 256,
+       .page_size      = 8,
+       .flags          = AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
+       .setup          = read_factory_config,
+       .context        = NULL,
+};
+
+static struct davinci_i2c_platform_data mityomap_i2c_0_pdata = {
+       .bus_freq       = 100,  /* kHz */
+       .bus_delay      = 0,    /* usec */
+};
+
+/* TPS65023 voltage regulator support */
+/* 1.2V Core */
+static struct regulator_consumer_supply tps65023_dcdc1_consumers[] = {
+       {
+               .supply = "cvdd",
+       },
+};
+
+/* 1.8V */
+static struct regulator_consumer_supply tps65023_dcdc2_consumers[] = {
+       {
+               .supply = "usb0_vdda18",
+       },
+       {
+               .supply = "usb1_vdda18",
+       },
+       {
+               .supply = "ddr_dvdd18",
+       },
+       {
+               .supply = "sata_vddr",
+       },
+};
+
+/* 1.2V */
+static struct regulator_consumer_supply tps65023_dcdc3_consumers[] = {
+       {
+               .supply = "sata_vdd",
+       },
+       {
+               .supply = "usb_cvdd",
+       },
+       {
+               .supply = "pll0_vdda",
+       },
+       {
+               .supply = "pll1_vdda",
+       },
+};
+
+/* 1.8V Aux LDO, not used */
+static struct regulator_consumer_supply tps65023_ldo1_consumers[] = {
+       {
+               .supply = "1.8v_aux",
+       },
+};
+
+/* FPGA VCC Aux (2.5 or 3.3) LDO */
+static struct regulator_consumer_supply tps65023_ldo2_consumers[] = {
+       {
+               .supply = "vccaux",
+       },
+};
+
+static struct regulator_init_data tps65023_regulator_data[] = {
+       /* dcdc1 */
+       {
+               .constraints = {
+                       .min_uV = 1150000,
+                       .max_uV = 1350000,
+                       .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                                         REGULATOR_CHANGE_STATUS,
+                       .boot_on = 1,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1_consumers),
+               .consumer_supplies = tps65023_dcdc1_consumers,
+       },
+       /* dcdc2 */
+       {
+               .constraints = {
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                       .boot_on = 1,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc2_consumers),
+               .consumer_supplies = tps65023_dcdc2_consumers,
+       },
+       /* dcdc3 */
+       {
+               .constraints = {
+                       .min_uV = 1200000,
+                       .max_uV = 1200000,
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                       .boot_on = 1,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc3_consumers),
+               .consumer_supplies = tps65023_dcdc3_consumers,
+       },
+       /* ldo1 */
+       {
+               .constraints = {
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                       .boot_on = 1,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo1_consumers),
+               .consumer_supplies = tps65023_ldo1_consumers,
+       },
+       /* ldo2 */
+       {
+               .constraints = {
+                       .min_uV = 2500000,
+                       .max_uV = 3300000,
+                       .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                                         REGULATOR_CHANGE_STATUS,
+                       .boot_on = 1,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo2_consumers),
+               .consumer_supplies = tps65023_ldo2_consumers,
+       },
+};
+
+static struct i2c_board_info __initdata mityomap_tps65023_info[] = {
+       {
+               I2C_BOARD_INFO("tps65023", 0x48),
+               .platform_data = &tps65023_regulator_data[0],
+       },
+       {
+               I2C_BOARD_INFO("24c02", 0x50),
+               .platform_data = &mityomapl138_fd_chip,
+       },
+};
+
+static int __init pmic_tps65023_init(void)
+{
+       return i2c_register_board_info(1, mityomap_tps65023_info,
+                                       ARRAY_SIZE(mityomap_tps65023_info));
+}
+
+/*
+ * MityDSP-L138 includes a 256 MByte large-page NAND flash
+ * (128K blocks).
+ */
+static struct mtd_partition mityomapl138_nandflash_partition[] = {
+       {
+               .name           = "rootfs",
+               .offset         = 0,
+               .size           = SZ_128M,
+               .mask_flags     = 0, /* MTD_WRITEABLE, */
+       },
+       {
+               .name           = "homefs",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0,
+       },
+};
+
+static struct davinci_nand_pdata mityomapl138_nandflash_data = {
+       .parts          = mityomapl138_nandflash_partition,
+       .nr_parts       = ARRAY_SIZE(mityomapl138_nandflash_partition),
+       .ecc_mode       = NAND_ECC_HW,
+       .options        = NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16,
+       .ecc_bits       = 1, /* 4 bit mode is not supported with 16 bit NAND */
+};
+
+static struct resource mityomapl138_nandflash_resource[] = {
+       {
+               .start  = DA8XX_AEMIF_CS3_BASE,
+               .end    = DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = DA8XX_AEMIF_CTL_BASE,
+               .end    = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device mityomapl138_nandflash_device = {
+       .name           = "davinci_nand",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &mityomapl138_nandflash_data,
+       },
+       .num_resources  = ARRAY_SIZE(mityomapl138_nandflash_resource),
+       .resource       = mityomapl138_nandflash_resource,
+};
+
+static struct platform_device *mityomapl138_devices[] __initdata = {
+       &mityomapl138_nandflash_device,
+};
+
+static void __init mityomapl138_setup_nand(void)
+{
+       platform_add_devices(mityomapl138_devices,
+                                ARRAY_SIZE(mityomapl138_devices));
+}
+
+static struct davinci_uart_config mityomapl138_uart_config __initdata = {
+       .enabled_uarts = 0x7,
+};
+
+static const short mityomap_mii_pins[] = {
+       DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+       DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+       DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+       DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+       DA850_MDIO_D,
+       -1
+};
+
+static const short mityomap_rmii_pins[] = {
+       DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+       DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+       DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+       DA850_MDIO_D,
+       -1
+};
+
+static void __init mityomapl138_config_emac(void)
+{
+       void __iomem *cfg_chip3_base;
+       int ret;
+       u32 val;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       soc_info->emac_pdata->rmii_en = 0; /* hardcoded for now */
+
+       cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+       val = __raw_readl(cfg_chip3_base);
+
+       if (soc_info->emac_pdata->rmii_en) {
+               val |= BIT(8);
+               ret = davinci_cfg_reg_list(mityomap_rmii_pins);
+               pr_info("RMII PHY configured\n");
+       } else {
+               val &= ~BIT(8);
+               ret = davinci_cfg_reg_list(mityomap_mii_pins);
+               pr_info("MII PHY configured\n");
+       }
+
+       if (ret) {
+               pr_warning("mii/rmii mux setup failed: %d\n", ret);
+               return;
+       }
+
+       /* configure the CFGCHIP3 register for RMII or MII */
+       __raw_writel(val, cfg_chip3_base);
+
+       soc_info->emac_pdata->phy_id = MITYOMAPL138_PHY_ID;
+
+       ret = da8xx_register_emac();
+       if (ret)
+               pr_warning("emac registration failed: %d\n", ret);
+}
+
+static struct davinci_pm_config da850_pm_pdata = {
+       .sleepcount = 128,
+};
+
+static struct platform_device da850_pm_device = {
+       .name   = "pm-davinci",
+       .dev = {
+               .platform_data  = &da850_pm_pdata,
+       },
+       .id     = -1,
+};
+
+static void __init mityomapl138_init(void)
+{
+       int ret;
+
+       /* for now, no special EDMA channels are reserved */
+       ret = da850_register_edma(NULL);
+       if (ret)
+               pr_warning("edma registration failed: %d\n", ret);
+
+       ret = da8xx_register_watchdog();
+       if (ret)
+               pr_warning("watchdog registration failed: %d\n", ret);
+
+       davinci_serial_init(&mityomapl138_uart_config);
+
+       ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata);
+       if (ret)
+               pr_warning("i2c0 registration failed: %d\n", ret);
+
+       ret = pmic_tps65023_init();
+       if (ret)
+               pr_warning("TPS65023 PMIC init failed: %d\n", ret);
+
+       mityomapl138_setup_nand();
+
+       mityomapl138_config_emac();
+
+       ret = da8xx_register_rtc();
+       if (ret)
+               pr_warning("rtc setup failed: %d\n", ret);
+
+       ret = da850_register_cpufreq("pll0_sysclk3");
+       if (ret)
+               pr_warning("cpufreq registration failed: %d\n", ret);
+
+       ret = da8xx_register_cpuidle();
+       if (ret)
+               pr_warning("cpuidle registration failed: %d\n", ret);
+
+       ret = da850_register_pm(&da850_pm_device);
+       if (ret)
+               pr_warning("da850_evm_init: suspend registration failed: %d\n",
+                               ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init mityomapl138_console_init(void)
+{
+       if (!machine_is_mityomapl138())
+               return 0;
+
+       return add_preferred_console("ttyS", 1, "115200");
+}
+console_initcall(mityomapl138_console_init);
+#endif
+
+static void __init mityomapl138_map_io(void)
+{
+       da850_init();
+}
+
+MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
+       .boot_params    = (DA8XX_DDR_BASE + 0x100),
+       .map_io         = mityomapl138_map_io,
+       .init_irq       = cp_intc_init,
+       .timer          = &davinci_timer,
+       .init_machine   = mityomapl138_init,
+MACHINE_END
index a4def889275ccbea6e7064377c2dc8e474a67c1d..6c389ff1020ef30d0434309a05b626ce565d0496 100644 (file)
@@ -39,9 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
-#define NEUROS_OSD2_PHY_MASK           0x2
-#define NEUROS_OSD2_MDIO_FREQUENCY     2200000 /* PHY bus frequency */
-
+#define NEUROS_OSD2_PHY_ID             "0:01"
 #define LXT971_PHY_ID                  0x001378e2
 #define LXT971_PHY_MASK                        0xfffffff0
 
@@ -252,8 +250,7 @@ static __init void davinci_ntosd2_init(void)
        davinci_serial_init(&uart_config);
        dm644x_init_asp(&dm644x_ntosd2_snd_data);
 
-       soc_info->emac_pdata->phy_mask = NEUROS_OSD2_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = NEUROS_OSD2_MDIO_FREQUENCY;
+       soc_info->emac_pdata->phy_id = NEUROS_OSD2_PHY_ID;
 
        davinci_setup_usb(1000, 8);
        /*
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
new file mode 100644 (file)
index 0000000..0b8dbdb
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Hawkboard.org based on TI's OMAP-L138 Platform
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+
+static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
+       .enabled_uarts = 0x7,
+};
+
+static __init void omapl138_hawk_init(void)
+{
+       int ret;
+
+       davinci_serial_init(&omapl138_hawk_uart_config);
+
+       ret = da8xx_register_watchdog();
+       if (ret)
+               pr_warning("omapl138_hawk_init: "
+                       "watchdog registration failed: %d\n",
+                       ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init omapl138_hawk_console_init(void)
+{
+       if (!machine_is_omapl138_hawkboard())
+               return 0;
+
+       return add_preferred_console("ttyS", 2, "115200");
+}
+console_initcall(omapl138_hawk_console_init);
+#endif
+
+static void __init omapl138_hawk_map_io(void)
+{
+       da850_init();
+}
+
+MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
+       .boot_params    = (DA8XX_DDR_BASE + 0x100),
+       .map_io         = omapl138_hawk_map_io,
+       .init_irq       = cp_intc_init,
+       .timer          = &davinci_timer,
+       .init_machine   = omapl138_hawk_init,
+MACHINE_END
index 9bdf8aafcc840f8fc4f15e9e70a9f153db1ba9d2..61ac96d8f00da3f1ce9ead940725a88827331ac6 100644 (file)
@@ -42,9 +42,7 @@
 #include <mach/mux.h>
 #include <mach/usb.h>
 
-#define SFFSDR_PHY_MASK                (0x2)
-#define SFFSDR_MDIO_FREQUENCY  (2200000) /* PHY bus frequency */
-
+#define SFFSDR_PHY_ID          "0:01"
 static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
        /* U-Boot Environment: Block 0
         * UBL:                Block 1
@@ -143,8 +141,7 @@ static __init void davinci_sffsdr_init(void)
                             ARRAY_SIZE(davinci_sffsdr_devices));
        sffsdr_init_i2c();
        davinci_serial_init(&uart_config);
-       soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
-       soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
+       soc_info->emac_pdata->phy_id = SFFSDR_PHY_ID;
        davinci_setup_usb(0, 0); /* We support only peripheral mode. */
 
        /* mux VLYNQ pins */
index b4de35b78904a0fda72e13a2c702211c998cd3ac..a6db854602277a3e334c1a50585798847cc1c6ea 100644 (file)
@@ -23,6 +23,9 @@
 #include <linux/ratelimit.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
@@ -141,10 +144,63 @@ static struct davinci_uart_config serial_config __initconst = {
        .enabled_uarts  = BIT(1),
 };
 
+static const uint32_t keymap[] = {
+       KEY(0, 0, KEY_NUMERIC_1),
+       KEY(0, 1, KEY_NUMERIC_2),
+       KEY(0, 2, KEY_NUMERIC_3),
+       KEY(0, 3, KEY_FN_F1),
+       KEY(0, 4, KEY_MENU),
+
+       KEY(1, 0, KEY_NUMERIC_4),
+       KEY(1, 1, KEY_NUMERIC_5),
+       KEY(1, 2, KEY_NUMERIC_6),
+       KEY(1, 3, KEY_UP),
+       KEY(1, 4, KEY_FN_F2),
+
+       KEY(2, 0, KEY_NUMERIC_7),
+       KEY(2, 1, KEY_NUMERIC_8),
+       KEY(2, 2, KEY_NUMERIC_9),
+       KEY(2, 3, KEY_LEFT),
+       KEY(2, 4, KEY_ENTER),
+
+       KEY(3, 0, KEY_NUMERIC_STAR),
+       KEY(3, 1, KEY_NUMERIC_0),
+       KEY(3, 2, KEY_NUMERIC_POUND),
+       KEY(3, 3, KEY_DOWN),
+       KEY(3, 4, KEY_RIGHT),
+
+       KEY(4, 0, KEY_FN_F3),
+       KEY(4, 1, KEY_FN_F4),
+       KEY(4, 2, KEY_MUTE),
+       KEY(4, 3, KEY_HOME),
+       KEY(4, 4, KEY_BACK),
+
+       KEY(5, 0, KEY_VOLUMEDOWN),
+       KEY(5, 1, KEY_VOLUMEUP),
+       KEY(5, 2, KEY_F1),
+       KEY(5, 3, KEY_F2),
+       KEY(5, 4, KEY_F3),
+};
+
+static const struct matrix_keymap_data keymap_data = {
+       .keymap         = keymap,
+       .keymap_size    = ARRAY_SIZE(keymap),
+};
+
+static struct matrix_keypad_platform_data keypad_config = {
+       .keymap_data    = &keymap_data,
+       .num_row_gpios  = 6,
+       .num_col_gpios  = 5,
+       .debounce_ms    = 0, /* minimum */
+       .active_low     = 0, /* pull up realization */
+       .no_autorepeat  = 0,
+};
+
 static struct tnetv107x_device_info evm_device_info __initconst = {
        .serial_config          = &serial_config,
        .mmc_config[1]          = &mmc_config,  /* controller 1 */
        .nand_config[0]         = &nand_config, /* chip select 0 */
+       .keypad_config          = &keypad_config,
 };
 
 static __init void tnetv107x_evm_board_init(void)
index 054c303caeadd106673bf4b0fa5afbc93088a0ad..01ba080433db556d0364cadb791303d2433b69a3 100644 (file)
@@ -236,7 +236,7 @@ static int __init clk_disable_unused(void)
                if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
                        continue;
 
-               pr_info("Clocks: disable unused %s\n", ck->name);
+               pr_debug("Clocks: disable unused %s\n", ck->name);
 
                davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc,
                                (ck->flags & PSC_SWRSTDISABLE) ?
@@ -287,6 +287,79 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
        return rate;
 }
 
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned v;
+       struct pll_data *pll;
+       unsigned long input;
+       unsigned ratio = 0;
+
+       /* If this is the PLL base clock, wrong function to call */
+       if (clk->pll_data)
+               return -EINVAL;
+
+       /* There must be a parent... */
+       if (WARN_ON(!clk->parent))
+               return -EINVAL;
+
+       /* ... the parent must be a PLL... */
+       if (WARN_ON(!clk->parent->pll_data))
+               return -EINVAL;
+
+       /* ... and this clock must have a divider. */
+       if (WARN_ON(!clk->div_reg))
+               return -EINVAL;
+
+       pll = clk->parent->pll_data;
+
+       input = clk->parent->rate;
+
+       /* If pre-PLL, source clock is before the multiplier and divider(s) */
+       if (clk->flags & PRE_PLL)
+               input = pll->input_rate;
+
+       if (input > rate) {
+               /*
+                * Can afford to provide an output little higher than requested
+                * only if maximum rate supported by hardware on this sysclk
+                * is known.
+                */
+               if (clk->maxrate) {
+                       ratio = DIV_ROUND_CLOSEST(input, rate);
+                       if (input / ratio > clk->maxrate)
+                               ratio = 0;
+               }
+
+               if (ratio == 0)
+                       ratio = DIV_ROUND_UP(input, rate);
+
+               ratio--;
+       }
+
+       if (ratio > PLLDIV_RATIO_MASK)
+               return -EINVAL;
+
+       do {
+               v = __raw_readl(pll->base + PLLSTAT);
+       } while (v & PLLSTAT_GOSTAT);
+
+       v = __raw_readl(pll->base + clk->div_reg);
+       v &= ~PLLDIV_RATIO_MASK;
+       v |= ratio | PLLDIV_EN;
+       __raw_writel(v, pll->base + clk->div_reg);
+
+       v = __raw_readl(pll->base + PLLCMD);
+       v |= PLLCMD_GOSET;
+       __raw_writel(v, pll->base + PLLCMD);
+
+       do {
+               v = __raw_readl(pll->base + PLLSTAT);
+       } while (v & PLLSTAT_GOSTAT);
+
+       return 0;
+}
+EXPORT_SYMBOL(davinci_set_sysclk_rate);
+
 static unsigned long clk_leafclk_recalc(struct clk *clk)
 {
        if (WARN_ON(!clk->parent))
index 01e36483ac3d0b4e5e32b768f556982ec20dd713..11099980b58bdfc2342ba67a8ccd373f07fb4fdf 100644 (file)
@@ -70,6 +70,9 @@
 #include <linux/list.h>
 #include <asm/clkdev.h>
 
+#define PLLSTAT_GOSTAT BIT(0)
+#define PLLCMD_GOSET   BIT(0)
+
 struct pll_data {
        u32 phys_base;
        void __iomem *base;
@@ -86,6 +89,7 @@ struct clk {
        struct module           *owner;
        const char              *name;
        unsigned long           rate;
+       unsigned long           maxrate;        /* H/W supported max rate */
        u8                      usecount;
        u8                      lpsc;
        u8                      gpsc;
@@ -118,6 +122,7 @@ struct clk {
 int davinci_clk_init(struct clk_lookup *clocks);
 int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
                                unsigned int mult, unsigned int postdiv);
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
 
 extern struct platform_device davinci_wdt_device;
 extern void davinci_watchdog_reset(struct platform_device *);
index d3fa6de1e20f6d5cb85d4e8424e26a6c9d5889b4..343de73161fad0a72aca262717e07494b26cf461 100644 (file)
@@ -34,6 +34,8 @@
 struct davinci_cpufreq {
        struct device *dev;
        struct clk *armclk;
+       struct clk *asyncclk;
+       unsigned long asyncrate;
 };
 static struct davinci_cpufreq cpufreq;
 
@@ -104,15 +106,27 @@ static int davinci_target(struct cpufreq_policy *policy,
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
        /* if moving to higher frequency, up the voltage beforehand */
-       if (pdata->set_voltage && freqs.new > freqs.old)
-               pdata->set_voltage(idx);
+       if (pdata->set_voltage && freqs.new > freqs.old) {
+               ret = pdata->set_voltage(idx);
+               if (ret)
+                       goto out;
+       }
 
        ret = clk_set_rate(armclk, idx);
+       if (ret)
+               goto out;
+
+       if (cpufreq.asyncclk) {
+               ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
+               if (ret)
+                       goto out;
+       }
 
        /* if moving to lower freq, lower the voltage after lowering freq */
        if (pdata->set_voltage && freqs.new < freqs.old)
                pdata->set_voltage(idx);
 
+out:
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
        return ret;
@@ -185,6 +199,7 @@ static struct cpufreq_driver davinci_driver = {
 static int __init davinci_cpufreq_probe(struct platform_device *pdev)
 {
        struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
+       struct clk *asyncclk;
 
        if (!pdata)
                return -EINVAL;
@@ -199,6 +214,12 @@ static int __init davinci_cpufreq_probe(struct platform_device *pdev)
                return PTR_ERR(cpufreq.armclk);
        }
 
+       asyncclk = clk_get(cpufreq.dev, "async");
+       if (!IS_ERR(asyncclk)) {
+               cpufreq.asyncclk = asyncclk;
+               cpufreq.asyncrate = clk_get_rate(asyncclk);
+       }
+
        return cpufreq_register_driver(&davinci_driver);
 }
 
@@ -206,6 +227,9 @@ static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
 {
        clk_put(cpufreq.armclk);
 
+       if (cpufreq.asyncclk)
+               clk_put(cpufreq.asyncclk);
+
        return cpufreq_unregister_driver(&davinci_driver);
 }
 
index 68ed58a48252948ee756c544a97d002d0ded8082..63916b90276042f01750bf5a41f79d7b64c2fd3a 100644 (file)
@@ -86,6 +86,8 @@ static struct clk pll0_sysclk3 = {
        .parent         = &pll0_clk,
        .flags          = CLK_PLL,
        .div_reg        = PLLDIV3,
+       .set_rate       = davinci_set_sysclk_rate,
+       .maxrate        = 100000000,
 };
 
 static struct clk pll0_sysclk4 = {
@@ -323,12 +325,19 @@ static struct clk lcdc_clk = {
        .gpsc           = 1,
 };
 
-static struct clk mmcsd_clk = {
-       .name           = "mmcsd",
+static struct clk mmcsd0_clk = {
+       .name           = "mmcsd0",
        .parent         = &pll0_sysclk2,
        .lpsc           = DA8XX_LPSC0_MMC_SD,
 };
 
+static struct clk mmcsd1_clk = {
+       .name           = "mmcsd1",
+       .parent         = &pll0_sysclk2,
+       .lpsc           = DA850_LPSC1_MMC_SD1,
+       .gpsc           = 1,
+};
+
 static struct clk aemif_clk = {
        .name           = "aemif",
        .parent         = &pll0_sysclk3,
@@ -375,7 +384,8 @@ static struct clk_lookup da850_clks[] = {
        CLK("davinci_emac.1",   NULL,           &emac_clk),
        CLK("davinci-mcasp.0",  NULL,           &mcasp_clk),
        CLK("da8xx_lcdc.0",     NULL,           &lcdc_clk),
-       CLK("davinci_mmc.0",    NULL,           &mmcsd_clk),
+       CLK("davinci_mmc.0",    NULL,           &mmcsd0_clk),
+       CLK("davinci_mmc.1",    NULL,           &mmcsd1_clk),
        CLK(NULL,               "aemif",        &aemif_clk),
        CLK(NULL,               NULL,           NULL),
 };
@@ -572,15 +582,9 @@ const short da850_cpgmac_pins[] __initdata = {
        DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
        DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
        DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
-       DA850_MDIO_D,
-       -1
-};
-
-const short da850_rmii_pins[] __initdata = {
-       DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
-       DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
-       DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
-       DA850_MDIO_D,
+       DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+       DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER,
+       DA850_RMII_MHZ_50_CLK,
        -1
 };
 
@@ -607,27 +611,19 @@ const short da850_mmcsd0_pins[] __initdata = {
        -1
 };
 
-const short da850_nand_pins[] __initdata = {
-       DA850_EMA_D_7, DA850_EMA_D_6, DA850_EMA_D_5, DA850_EMA_D_4,
-       DA850_EMA_D_3, DA850_EMA_D_2, DA850_EMA_D_1, DA850_EMA_D_0,
-       DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
-       DA850_NEMA_WE, DA850_NEMA_OE,
-       -1
-};
-
-const short da850_nor_pins[] __initdata = {
+const short da850_emif25_pins[] __initdata = {
        DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
-       DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
-       DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
-       DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
-       DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
-       DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
-       DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
-       DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
-       DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
-       DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
-       DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
-       DA850_EMA_A_22, DA850_EMA_A_23,
+       DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE,
+       DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+       DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+       DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
+       DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
+       DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3,
+       DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7,
+       DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11,
+       DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15,
+       DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19,
+       DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23,
        -1
 };
 
@@ -851,7 +847,7 @@ static const struct da850_opp da850_opp_300 = {
        .prediv         = 1,
        .mult           = 25,
        .postdiv        = 2,
-       .cvdd_min       = 1140000,
+       .cvdd_min       = 1200000,
        .cvdd_max       = 1320000,
 };
 
@@ -860,7 +856,7 @@ static const struct da850_opp da850_opp_200 = {
        .prediv         = 1,
        .mult           = 25,
        .postdiv        = 3,
-       .cvdd_min       = 1050000,
+       .cvdd_min       = 1100000,
        .cvdd_max       = 1160000,
 };
 
@@ -869,7 +865,7 @@ static const struct da850_opp da850_opp_96 = {
        .prediv         = 1,
        .mult           = 20,
        .postdiv        = 5,
-       .cvdd_min       = 950000,
+       .cvdd_min       = 1000000,
        .cvdd_max       = 1050000,
 };
 
@@ -929,10 +925,16 @@ static struct platform_device da850_cpufreq_device = {
        .dev = {
                .platform_data  = &cpufreq_info,
        },
+       .id = -1,
 };
 
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
 {
+       /* cpufreq driver can help keep an "async" clock constant */
+       if (async_clk)
+               clk_add_alias("async", da850_cpufreq_device.name,
+                                                       async_clk, NULL);
+
        return platform_device_register(&da850_cpufreq_device);
 }
 
@@ -983,7 +985,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
        return 0;
 }
 #else
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
 {
        return 0;
 }
index 52bc7b1c6ca3365309bd407254163f3811469031..9eec63070e0c35b42c2fc55a6f7282635d99b737 100644 (file)
@@ -24,6 +24,7 @@
 #include "clock.h"
 
 #define DA8XX_TPCC_BASE                        0x01c00000
+#define DA850_MMCSD1_BASE              0x01e1b000
 #define DA850_TPCC1_BASE               0x01e30000
 #define DA8XX_TPTC0_BASE               0x01c08000
 #define DA8XX_TPTC1_BASE               0x01c08400
@@ -41,7 +42,6 @@
 #define DA8XX_EMAC_CTRL_REG_OFFSET     0x3000
 #define DA8XX_EMAC_MOD_REG_OFFSET      0x2000
 #define DA8XX_EMAC_RAM_OFFSET          0x0000
-#define DA8XX_MDIO_REG_OFFSET          0x4000
 #define DA8XX_EMAC_CTRL_RAM_SIZE       SZ_8K
 
 void __iomem *da8xx_syscfg0_base;
@@ -351,7 +351,7 @@ int __init da8xx_register_watchdog(void)
 static struct resource da8xx_emac_resources[] = {
        {
                .start  = DA8XX_EMAC_CPPI_PORT_BASE,
-               .end    = DA8XX_EMAC_CPPI_PORT_BASE + 0x5000 - 1,
+               .end    = DA8XX_EMAC_CPPI_PORT_BASE + SZ_16K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -380,7 +380,6 @@ struct emac_platform_data da8xx_emac_pdata = {
        .ctrl_reg_offset        = DA8XX_EMAC_CTRL_REG_OFFSET,
        .ctrl_mod_reg_offset    = DA8XX_EMAC_MOD_REG_OFFSET,
        .ctrl_ram_offset        = DA8XX_EMAC_RAM_OFFSET,
-       .mdio_reg_offset        = DA8XX_MDIO_REG_OFFSET,
        .ctrl_ram_size          = DA8XX_EMAC_CTRL_RAM_SIZE,
        .version                = EMAC_VERSION_2,
 };
@@ -395,9 +394,34 @@ static struct platform_device da8xx_emac_device = {
        .resource       = da8xx_emac_resources,
 };
 
+static struct resource da8xx_mdio_resources[] = {
+       {
+               .start  = DA8XX_EMAC_MDIO_BASE,
+               .end    = DA8XX_EMAC_MDIO_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device da8xx_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(da8xx_mdio_resources),
+       .resource       = da8xx_mdio_resources,
+};
+
 int __init da8xx_register_emac(void)
 {
-       return platform_device_register(&da8xx_emac_device);
+       int ret;
+
+       ret = platform_device_register(&da8xx_mdio_device);
+       if (ret < 0)
+               return ret;
+       ret = platform_device_register(&da8xx_emac_device);
+       if (ret < 0)
+               return ret;
+       ret = clk_add_alias(NULL, dev_name(&da8xx_mdio_device.dev),
+                           NULL, &da8xx_emac_device.dev);
+       return ret;
 }
 
 static struct resource da830_mcasp1_resources[] = {
@@ -566,6 +590,44 @@ int __init da8xx_register_mmcsd0(struct davinci_mmc_config *config)
        return platform_device_register(&da8xx_mmcsd0_device);
 }
 
+#ifdef CONFIG_ARCH_DAVINCI_DA850
+static struct resource da850_mmcsd1_resources[] = {
+       {               /* registers */
+               .start  = DA850_MMCSD1_BASE,
+               .end    = DA850_MMCSD1_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {               /* interrupt */
+               .start  = IRQ_DA850_MMCSDINT0_1,
+               .end    = IRQ_DA850_MMCSDINT0_1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {               /* DMA RX */
+               .start  = EDMA_CTLR_CHAN(1, 28),
+               .end    = EDMA_CTLR_CHAN(1, 28),
+               .flags  = IORESOURCE_DMA,
+       },
+       {               /* DMA TX */
+               .start  = EDMA_CTLR_CHAN(1, 29),
+               .end    = EDMA_CTLR_CHAN(1, 29),
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device da850_mmcsd1_device = {
+       .name           = "davinci_mmc",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(da850_mmcsd1_resources),
+       .resource       = da850_mmcsd1_resources,
+};
+
+int __init da850_register_mmcsd1(struct davinci_mmc_config *config)
+{
+       da850_mmcsd1_device.dev.platform_data = config;
+       return platform_device_register(&da850_mmcsd1_device);
+}
+#endif
+
 static struct resource da8xx_rtc_resources[] = {
        {
                .start          = DA8XX_RTC_BASE,
index 2718a3a90dff7931c038f9e625aec69a83956f18..c9a86d8130d151795433d7833b2fb85911a2bec5 100644 (file)
 #define TNETV107X_TPTC0_BASE                   0x01c10000
 #define TNETV107X_TPTC1_BASE                   0x01c10400
 #define TNETV107X_WDOG_BASE                    0x08086700
+#define TNETV107X_TSC_BASE                     0x08088500
 #define TNETV107X_SDIO0_BASE                   0x08088700
 #define TNETV107X_SDIO1_BASE                   0x08088800
+#define TNETV107X_KEYPAD_BASE                  0x08088a00
 #define TNETV107X_ASYNC_EMIF_CNTRL_BASE                0x08200000
 #define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE     0x30000000
 #define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE     0x40000000
@@ -298,12 +300,55 @@ static int __init nand_init(int chipsel, struct davinci_nand_pdata *data)
        return platform_device_register(pdev);
 }
 
+static struct resource keypad_resources[] = {
+       {
+               .start  = TNETV107X_KEYPAD_BASE,
+               .end    = TNETV107X_KEYPAD_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_TNETV107X_KEYPAD,
+               .flags  = IORESOURCE_IRQ,
+               .name   = "press",
+       },
+       {
+               .start  = IRQ_TNETV107X_KEYPAD_FREE,
+               .flags  = IORESOURCE_IRQ,
+               .name   = "release",
+       },
+};
+
+static struct platform_device keypad_device = {
+       .name           = "tnetv107x-keypad",
+       .num_resources  = ARRAY_SIZE(keypad_resources),
+       .resource       = keypad_resources,
+};
+
+static struct resource tsc_resources[] = {
+       {
+               .start  = TNETV107X_TSC_BASE,
+               .end    = TNETV107X_TSC_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_TNETV107X_TSC,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tsc_device = {
+       .name           = "tnetv107x-ts",
+       .num_resources  = ARRAY_SIZE(tsc_resources),
+       .resource       = tsc_resources,
+};
+
 void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
 {
        int i;
 
        platform_device_register(&edma_device);
        platform_device_register(&tnetv107x_wdt_device);
+       platform_device_register(&tsc_device);
 
        if (info->serial_config)
                davinci_serial_init(info->serial_config);
@@ -317,4 +362,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
        for (i = 0; i < 4; i++)
                if (info->nand_config[i])
                        nand_init(i, info->nand_config[i]);
+
+       if (info->keypad_config) {
+               keypad_device.dev.platform_data = info->keypad_config;
+               platform_device_register(&keypad_device);
+       }
 }
index 8b7201e4c79c6aabd616a11a696bf183357a911b..22ebc64bc9d99a5bd71a52f801f3903a6f5b04d9 100644 (file)
@@ -213,7 +213,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
                                IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
 
                        /* Configure pull down control */
-                       __raw_writel((__raw_readl(pupdctl1) & ~0x400),
+                       __raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
                                        pupdctl1);
 
                        mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
@@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
 
 /*-------------------------------------------------------------------------*/
 
+struct platform_device davinci_pcm_device = {
+       .name           = "davinci-pcm-audio",
+       .id             = -1,
+};
+
+static void davinci_init_pcm(void)
+{
+       platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
 struct davinci_timer_instance davinci_timer_instance[2] = {
        {
                .base           = DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
+       davinci_init_pcm();
        davinci_init_wdt();
 
        return 0;
index 7781e35daec3d0a7cf9e956aceb7e717f48c7c44..a12065e87266669a9d66f72bb21a9b4207aca4d2 100644 (file)
@@ -691,7 +691,6 @@ static struct emac_platform_data dm365_emac_pdata = {
        .ctrl_reg_offset        = DM365_EMAC_CNTRL_OFFSET,
        .ctrl_mod_reg_offset    = DM365_EMAC_CNTRL_MOD_OFFSET,
        .ctrl_ram_offset        = DM365_EMAC_CNTRL_RAM_OFFSET,
-       .mdio_reg_offset        = DM365_EMAC_MDIO_OFFSET,
        .ctrl_ram_size          = DM365_EMAC_CNTRL_RAM_SIZE,
        .version                = EMAC_VERSION_2,
 };
@@ -699,7 +698,7 @@ static struct emac_platform_data dm365_emac_pdata = {
 static struct resource dm365_emac_resources[] = {
        {
                .start  = DM365_EMAC_BASE,
-               .end    = DM365_EMAC_BASE + 0x47ff,
+               .end    = DM365_EMAC_BASE + SZ_16K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -734,6 +733,21 @@ static struct platform_device dm365_emac_device = {
        .resource       = dm365_emac_resources,
 };
 
+static struct resource dm365_mdio_resources[] = {
+       {
+               .start  = DM365_EMAC_MDIO_BASE,
+               .end    = DM365_EMAC_MDIO_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dm365_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(dm365_mdio_resources),
+       .resource       = dm365_mdio_resources,
+};
+
 static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
        [IRQ_VDINT0]                    = 2,
        [IRQ_VDINT1]                    = 6,
@@ -1219,7 +1233,12 @@ static int __init dm365_init_devices(void)
 
        davinci_cfg_reg(DM365_INT_EDMA_CC);
        platform_device_register(&dm365_edma_device);
+
+       platform_device_register(&dm365_mdio_device);
        platform_device_register(&dm365_emac_device);
+       clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
+                     NULL, &dm365_emac_device.dev);
+
        /* Add isif clock alias */
        clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
        platform_device_register(&dm365_vpss_device);
index 5e5b0a7831fbf2b7af156ba76bf4af0b6be26489..0608dd776a16ca3fd966e02b22f93804f812e618 100644 (file)
@@ -322,7 +322,6 @@ static struct emac_platform_data dm644x_emac_pdata = {
        .ctrl_reg_offset        = DM644X_EMAC_CNTRL_OFFSET,
        .ctrl_mod_reg_offset    = DM644X_EMAC_CNTRL_MOD_OFFSET,
        .ctrl_ram_offset        = DM644X_EMAC_CNTRL_RAM_OFFSET,
-       .mdio_reg_offset        = DM644X_EMAC_MDIO_OFFSET,
        .ctrl_ram_size          = DM644X_EMAC_CNTRL_RAM_SIZE,
        .version                = EMAC_VERSION_1,
 };
@@ -330,7 +329,7 @@ static struct emac_platform_data dm644x_emac_pdata = {
 static struct resource dm644x_emac_resources[] = {
        {
                .start  = DM644X_EMAC_BASE,
-               .end    = DM644X_EMAC_BASE + 0x47ff,
+               .end    = DM644X_EMAC_BASE + SZ_16K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -350,6 +349,21 @@ static struct platform_device dm644x_emac_device = {
        .resource       = dm644x_emac_resources,
 };
 
+static struct resource dm644x_mdio_resources[] = {
+       {
+               .start  = DM644X_EMAC_MDIO_BASE,
+               .end    = DM644X_EMAC_MDIO_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dm644x_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(dm644x_mdio_resources),
+       .resource       = dm644x_mdio_resources,
+};
+
 /*
  * Device specific mux setup
  *
@@ -776,7 +790,12 @@ static int __init dm644x_init_devices(void)
        clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
        clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
        platform_device_register(&dm644x_edma_device);
+
+       platform_device_register(&dm644x_mdio_device);
        platform_device_register(&dm644x_emac_device);
+       clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
+                     NULL, &dm644x_emac_device.dev);
+
        platform_device_register(&dm644x_vpss_device);
        platform_device_register(&dm644x_ccdc_dev);
        platform_device_register(&vpfe_capture_dev);
index 26e8a9c7f50b4393f1e716575950fff967658b9a..1e0f809644bbfd1df1dcda646ea968e6f5e71a29 100644 (file)
@@ -358,7 +358,6 @@ static struct emac_platform_data dm646x_emac_pdata = {
        .ctrl_reg_offset        = DM646X_EMAC_CNTRL_OFFSET,
        .ctrl_mod_reg_offset    = DM646X_EMAC_CNTRL_MOD_OFFSET,
        .ctrl_ram_offset        = DM646X_EMAC_CNTRL_RAM_OFFSET,
-       .mdio_reg_offset        = DM646X_EMAC_MDIO_OFFSET,
        .ctrl_ram_size          = DM646X_EMAC_CNTRL_RAM_SIZE,
        .version                = EMAC_VERSION_2,
 };
@@ -366,7 +365,7 @@ static struct emac_platform_data dm646x_emac_pdata = {
 static struct resource dm646x_emac_resources[] = {
        {
                .start  = DM646X_EMAC_BASE,
-               .end    = DM646X_EMAC_BASE + 0x47ff,
+               .end    = DM646X_EMAC_BASE + SZ_16K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -401,6 +400,21 @@ static struct platform_device dm646x_emac_device = {
        .resource       = dm646x_emac_resources,
 };
 
+static struct resource dm646x_mdio_resources[] = {
+       {
+               .start  = DM646X_EMAC_MDIO_BASE,
+               .end    = DM646X_EMAC_MDIO_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device dm646x_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(dm646x_mdio_resources),
+       .resource       = dm646x_mdio_resources,
+};
+
 /*
  * Device specific mux setup
  *
@@ -896,7 +910,11 @@ static int __init dm646x_init_devices(void)
        if (!cpu_is_davinci_dm646x())
                return 0;
 
+       platform_device_register(&dm646x_mdio_device);
        platform_device_register(&dm646x_emac_device);
+       clk_add_alias(NULL, dev_name(&dm646x_mdio_device.dev),
+                     NULL, &dm646x_emac_device.dev);
+
        return 0;
 }
 postcore_initcall(dm646x_init_devices);
index 2ede598b77dd71274bd5a9fd7034a1cbcaeb602f..6b9669869c4680d7eedc992ec98078c01b5f5131 100644 (file)
@@ -354,10 +354,12 @@ static int irq2ctlr(int irq)
 static irqreturn_t dma_irq_handler(int irq, void *data)
 {
        int i;
-       unsigned ctlr;
+       int ctlr;
        unsigned int cnt = 0;
 
        ctlr = irq2ctlr(irq);
+       if (ctlr < 0)
+               return IRQ_NONE;
 
        dev_dbg(data, "dma_irq_handler\n");
 
@@ -408,10 +410,12 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
 static irqreturn_t dma_ccerr_handler(int irq, void *data)
 {
        int i;
-       unsigned ctlr;
+       int ctlr;
        unsigned int cnt = 0;
 
        ctlr = irq2ctlr(irq);
+       if (ctlr < 0)
+               return IRQ_NONE;
 
        dev_dbg(data, "dma_ccerr_handler\n");
 
diff --git a/arch/arm/mach-davinci/include/mach/aemif.h b/arch/arm/mach-davinci/include/mach/aemif.h
new file mode 100644 (file)
index 0000000..05b2934
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * TI DaVinci AEMIF support
+ *
+ * Copyright 2010 (C) Texas Instruments, Inc. http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+#ifndef _MACH_DAVINCI_AEMIF_H
+#define _MACH_DAVINCI_AEMIF_H
+
+#define NRCSR_OFFSET           0x00
+#define AWCCR_OFFSET           0x04
+#define A1CR_OFFSET            0x10
+
+#define ACR_ASIZE_MASK         0x3
+#define ACR_EW_MASK            BIT(30)
+#define ACR_SS_MASK            BIT(31)
+
+/* All timings in nanoseconds */
+struct davinci_aemif_timing {
+       u8      wsetup;
+       u8      wstrobe;
+       u8      whold;
+
+       u8      rsetup;
+       u8      rstrobe;
+       u8      rhold;
+
+       u8      ta;
+};
+
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+                                       void __iomem *base, unsigned cs);
+#endif
index 3c07059f526e9605feddb0d8c5ef06f0b355977f..4247b3f53b338f596b37fc1664becc3c82df727e 100644 (file)
@@ -76,9 +76,10 @@ int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
 int da8xx_register_emac(void);
 int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
 int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
+int da850_register_mmcsd1(struct davinci_mmc_config *config);
 void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
 int da8xx_register_rtc(void);
-int da850_register_cpufreq(void);
+int da850_register_cpufreq(char *async_clk);
 int da8xx_register_cpuidle(void);
 void __iomem * __init da8xx_get_mem_ctlr(void);
 int da850_register_pm(struct platform_device *pdev);
@@ -121,11 +122,9 @@ extern const short da850_uart2_pins[];
 extern const short da850_i2c0_pins[];
 extern const short da850_i2c1_pins[];
 extern const short da850_cpgmac_pins[];
-extern const short da850_rmii_pins[];
 extern const short da850_mcasp_pins[];
 extern const short da850_lcdcntl_pins[];
 extern const short da850_mmcsd0_pins[];
-extern const short da850_nand_pins[];
-extern const short da850_nor_pins[];
+extern const short da850_emif25_pins[];
 
 #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
index ea5df3b49ec4ec1f936ee2acd9be6c0776dd494d..2563bf4e93a10e1cc655f0cff4ca7b04f188a5b7 100644 (file)
 #include <media/davinci/vpfe_capture.h>
 
 #define DM365_EMAC_BASE                        (0x01D07000)
+#define DM365_EMAC_MDIO_BASE           (DM365_EMAC_BASE + 0x4000)
 #define DM365_EMAC_CNTRL_OFFSET                (0x0000)
 #define DM365_EMAC_CNTRL_MOD_OFFSET    (0x3000)
 #define DM365_EMAC_CNTRL_RAM_OFFSET    (0x1000)
-#define DM365_EMAC_MDIO_OFFSET         (0x4000)
 #define DM365_EMAC_CNTRL_RAM_SIZE      (0x2000)
 
 /* Base of key scan register bank */
index 6fca568a0fd25c2e01a86f9416b337f3e1ac1f6c..5a1b26d4e68b41936ac16ee574d34d7be8342e6c 100644 (file)
 #include <media/davinci/vpfe_capture.h>
 
 #define DM644X_EMAC_BASE               (0x01C80000)
+#define DM644X_EMAC_MDIO_BASE          (DM644X_EMAC_BASE + 0x4000)
 #define DM644X_EMAC_CNTRL_OFFSET       (0x0000)
 #define DM644X_EMAC_CNTRL_MOD_OFFSET   (0x1000)
 #define DM644X_EMAC_CNTRL_RAM_OFFSET   (0x2000)
-#define DM644X_EMAC_MDIO_OFFSET                (0x4000)
 #define DM644X_EMAC_CNTRL_RAM_SIZE     (0x2000)
 
 #define DM644X_ASYNC_EMIF_CONTROL_BASE 0x01E00000
index 0a27ee9a70e1de39448898da62090eb981096e11..7a27f3f139137258b517d589606041e275f5cf13 100644 (file)
 #include <linux/davinci_emac.h>
 
 #define DM646X_EMAC_BASE               (0x01C80000)
+#define DM646X_EMAC_MDIO_BASE          (DM646X_EMAC_BASE + 0x4000)
 #define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
 #define DM646X_EMAC_CNTRL_MOD_OFFSET   (0x1000)
 #define DM646X_EMAC_CNTRL_RAM_OFFSET   (0x2000)
-#define DM646X_EMAC_MDIO_OFFSET                (0x4000)
 #define DM646X_EMAC_CNTRL_RAM_SIZE     (0x2000)
 
 #define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000
index b2ad8090bd1058b86367c19456a3a0ef42d57efb..025151049f0517a103c4efb96ee86d465c3fff19 100644 (file)
@@ -30,9 +30,6 @@
 
 #include <linux/mtd/nand.h>
 
-#define NRCSR_OFFSET           0x00
-#define AWCCR_OFFSET           0x04
-#define A1CR_OFFSET            0x10
 #define NANDFCR_OFFSET         0x60
 #define NANDFSR_OFFSET         0x64
 #define NANDF1ECC_OFFSET       0x70
@@ -83,6 +80,9 @@ struct davinci_nand_pdata {           /* platform_data */
        /* Main and mirror bbt descriptor overrides */
        struct nand_bbt_descr   *bbt_td;
        struct nand_bbt_descr   *bbt_md;
+
+       /* Access timings */
+       struct davinci_aemif_timing     *timing;
 };
 
 #endif /* __ARCH_ARM_DAVINCI_NAND_H */
index 983da6e4554cd01cddd2150f5042bfb4caf66049..62b0858f68cacbf8560f090cc02c6e0eb5f1a491 100644 (file)
 #define DA8XX_LPSC1_UART2              13
 #define DA8XX_LPSC1_LCDC               16
 #define DA8XX_LPSC1_PWM                        17
+#define DA850_LPSC1_MMC_SD1            18
 #define DA8XX_LPSC1_ECAP               20
 #define DA830_LPSC1_EQEP               21
 #define DA850_LPSC1_TPTC2              21
index c720647331235455a002196b9e70fa7391577439..5a681d880dcb800e54f6f4de86010363c5d3ec66 100644 (file)
@@ -33,6 +33,8 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/serial_8250.h>
+#include <linux/input/matrix_keypad.h>
+
 #include <mach/mmc.h>
 #include <mach/nand.h>
 #include <mach/serial.h>
@@ -41,6 +43,7 @@ struct tnetv107x_device_info {
        struct davinci_uart_config      *serial_config;
        struct davinci_mmc_config       *mmc_config[2];  /* 2 controllers */
        struct davinci_nand_pdata       *nand_config[4]; /* 4 chipsels */
+       struct matrix_keypad_platform_data *keypad_config;
 };
 
 extern struct platform_device tnetv107x_wdt_device;
index 15a6192ad6eb8953fa9f306b431e0adc46d45cc4..47723e8d75a449b7495a8453c5acc66111265507 100644 (file)
@@ -88,6 +88,8 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
                /* DA8xx boards */
                DEBUG_LL_DA8XX(davinci_da830_evm,       2);
                DEBUG_LL_DA8XX(davinci_da850_evm,       2);
+               DEBUG_LL_DA8XX(mityomapl138,            1);
+               DEBUG_LL_DA8XX(omapl138_hawkboard,      2);
 
                /* TNETV107x boards */
                DEBUG_LL_TNETV107X(tnetv107x,           1);
index 864e60482c536f8e1cb3b05cbf5aedc426bb6305..daeae06430b9093417011fc9f3ece612adcf8ee4 100644 (file)
@@ -104,7 +104,7 @@ static u32 pll_ext_freq[] = {
 };
 
 /* PSC control registers */
-static u32 psc_regs[] __initconst = { TNETV107X_PSC_BASE };
+static u32 psc_regs[] = { TNETV107X_PSC_BASE };
 
 /* Host map for interrupt controller */
 static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 };
@@ -581,7 +581,14 @@ static struct davinci_id ids[] = {
                .part_no        = 0xb8a1,
                .manufacturer   = 0x017,
                .cpu_id         = DAVINCI_CPU_ID_TNETV107X,
-               .name           = "tnetv107x rev1.0",
+               .name           = "tnetv107x rev 1.0",
+       },
+       {
+               .variant        = 0x1,
+               .part_no        = 0xb8a1,
+               .manufacturer   = 0x017,
+               .cpu_id         = DAVINCI_CPU_ID_TNETV107X,
+               .name           = "tnetv107x rev 1.1/1.2",
        },
 };
 
index 4566bd1c8660b3fe7ac0cff28473746fd3d34c82..ef06c66a6f1630cbab1ec79487382dc8704f4049 100644 (file)
@@ -358,8 +358,7 @@ static int calc_clk_div(struct clk *clk, unsigned long rate,
        int i, found = 0, __div = 0, __pdiv = 0;
 
        /* Don't exceed the maximum rate */
-       max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4),
-                      clk_xtali.rate / 4);
+       max_rate = max3(clk_pll1.rate / 4, clk_pll2.rate / 4, clk_xtali.rate / 4);
        rate = min(rate, max_rate);
 
        /*
index 4cb55d3902ff675e4fb5e3ed59d6244eb20f181d..ffdf87be295855e93a5e74734c86d060e28b4022 100644 (file)
@@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
        .resource       = ep93xx_i2s_resource,
 };
 
+static struct platform_device ep93xx_pcm_device = {
+       .name           = "ep93xx-pcm-audio",
+       .id             = -1,
+};
+
 void __init ep93xx_register_i2s(void)
 {
        platform_device_register(&ep93xx_i2s_device);
+       platform_device_register(&ep93xx_pcm_device);
 }
 
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK  (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
 }
 EXPORT_SYMBOL(ep93xx_i2s_release);
 
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+       {
+               .start  = EP93XX_AAC_PHYS_BASE,
+               .end    = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_EP93XX_AACINTR,
+               .end    = IRQ_EP93XX_AACINTR,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ep93xx_ac97_device = {
+       .name           = "ep93xx-ac97",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ep93xx_ac97_resources),
+       .resource       = ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+       /*
+        * Make sure that the AC97 pins are not used by I2S.
+        */
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+       platform_device_register(&ep93xx_ac97_device);
+       platform_device_register(&ep93xx_pcm_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
index c54b3e56ba635a6c3edfc599dcf9154f27c5d43c..9ac4d105509727ef7968fedd488a9f121f73a6b0 100644 (file)
 #define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
 
+#define EP93XX_AAC_PHYS_BASE           EP93XX_APB_PHYS(0x00080000)
 #define EP93XX_AAC_BASE                        EP93XX_APB_IOMEM(0x00080000)
 
 #define EP93XX_SPI_PHYS_BASE           EP93XX_APB_PHYS(0x000a0000)
index 3330b36d79e6a0838a88b0960db3ee436e0edc33..50660455b1d8bbaca6f221e8a8f7aa1710816057 100644 (file)
@@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
index f22ce8db7947b616f7f45cf7fe6cf7eeebec62f2..d96dc1c5da20a26c0f3b4017d2411d16ceacadd7 100644 (file)
@@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
        ep93xx_register_fb(&simone_fb_info);
        ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
                            ARRAY_SIZE(simone_i2c_board_info));
+       ep93xx_register_ac97();
 }
 
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
index 1c82d4290dad6f6e593022fb318e4f67b5694fb6..51ff23b72d3a3e8d6982b031dd36df0c3c1cc711 100644 (file)
@@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
        },
 };
 
+static struct platform_device kirkwood_pcm_device = {
+       .name           = "kirkwood-pcm-audio",
+       .id             = -1,
+};
+
 void __init kirkwood_audio_init(void)
 {
        kirkwood_clk_ctrl |= CGC_AUDIO;
        platform_device_register(&kirkwood_i2s_device);
+       platform_device_register(&kirkwood_pcm_device);
 }
 
 /*****************************************************************************
index 5e286441b8f45f5f571e001b48d16fe7685362ac..5ea66f1f4178b0b846cfb42e6e600ddb2d3a1f87 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
+#include <linux/gpio-fan.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
@@ -136,6 +137,46 @@ static struct platform_device netspace_v2_leds = {
        },
 };
 
+/*****************************************************************************
+ * GPIO fan
+ ****************************************************************************/
+
+/* Designed for fan 40x40x16: ADDA AD0412LB-D50 6000rpm@12v */
+static struct gpio_fan_speed netspace_max_v2_fan_speed[] = {
+       {    0,  0 },
+       { 1500, 15 },
+       { 1700, 14 },
+       { 1800, 13 },
+       { 2100, 12 },
+       { 3100, 11 },
+       { 3300, 10 },
+       { 4300,  9 },
+       { 5500,  8 },
+};
+
+static unsigned netspace_max_v2_fan_ctrl[] = { 22, 7, 33, 23 };
+
+static struct gpio_fan_alarm netspace_max_v2_fan_alarm = {
+       .gpio           = 25,
+       .active_low     = 1,
+};
+
+static struct gpio_fan_platform_data netspace_max_v2_fan_data = {
+       .num_ctrl       = ARRAY_SIZE(netspace_max_v2_fan_ctrl),
+       .ctrl           = netspace_max_v2_fan_ctrl,
+       .alarm          = &netspace_max_v2_fan_alarm,
+       .num_speed      = ARRAY_SIZE(netspace_max_v2_fan_speed),
+       .speed          = netspace_max_v2_fan_speed,
+};
+
+static struct platform_device netspace_max_v2_gpio_fan = {
+       .name   = "gpio-fan",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &netspace_max_v2_fan_data,
+       },
+};
+
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
@@ -205,6 +246,8 @@ static void __init netspace_v2_init(void)
        platform_device_register(&netspace_v2_leds);
        platform_device_register(&netspace_v2_gpio_leds);
        platform_device_register(&netspace_v2_gpio_buttons);
+       if (machine_is_netspace_max_v2())
+               platform_device_register(&netspace_max_v2_gpio_fan);
 
        if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
            gpio_direction_output(NETSPACE_V2_GPIO_POWER_OFF, 0) == 0)
index facfaeb1ae5cb2837ff71903f793b9453e1b769c..9a304d854e3343486d4410ce6696d80a67aebffe 100644 (file)
@@ -12,7 +12,7 @@ obj-$(CONFIG_OMAP_MPU_TIMER)  += time.o
 obj-$(CONFIG_OMAP_32K_TIMER)   += timer32k.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o
 
 # DSP
 obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
index 73c86392fcd3ac1e147bcc7e25d64eb5f91daedf..1d4163b9f0b71f36881841350f66c2eedc73f566 100644 (file)
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 
+#include <media/soc_camera.h>
+
 #include <asm/serial.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -32,6 +35,7 @@
 #include <plat/usb.h>
 #include <plat/board.h>
 #include <plat/common.h>
+#include <mach/camera.h>
 
 #include <mach/ams-delta-fiq.h>
 
@@ -213,10 +217,56 @@ static struct platform_device ams_delta_led_device = {
        .id     = -1
 };
 
+static struct i2c_board_info ams_delta_camera_board_info[] = {
+       {
+               I2C_BOARD_INFO("ov6650", 0x60),
+       },
+};
+
+#ifdef CONFIG_LEDS_TRIGGERS
+DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger);
+
+static int ams_delta_camera_power(struct device *dev, int power)
+{
+       /*
+        * turn on camera LED
+        */
+       if (power)
+               led_trigger_event(ams_delta_camera_led_trigger, LED_FULL);
+       else
+               led_trigger_event(ams_delta_camera_led_trigger, LED_OFF);
+       return 0;
+}
+#else
+#define ams_delta_camera_power NULL
+#endif
+
+static struct soc_camera_link __initdata ams_delta_iclink = {
+       .bus_id         = 0,    /* OMAP1 SoC camera bus */
+       .i2c_adapter_id = 1,
+       .board_info     = &ams_delta_camera_board_info[0],
+       .module_name    = "ov6650",
+       .power          = ams_delta_camera_power,
+};
+
+static struct platform_device ams_delta_camera_device = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ams_delta_iclink,
+       },
+};
+
+static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
+       .camexclk_khz   = 12000,        /* default 12MHz clock, no extra DPLL */
+       .lclk_khz_max   = 1334,         /* results in 5fps CIF, 10fps QCIF */
+};
+
 static struct platform_device *ams_delta_devices[] __initdata = {
        &ams_delta_kp_device,
        &ams_delta_lcd_device,
        &ams_delta_led_device,
+       &ams_delta_camera_device,
 };
 
 static void __init ams_delta_init(void)
@@ -225,6 +275,20 @@ static void __init ams_delta_init(void)
        omap_cfg_reg(UART1_TX);
        omap_cfg_reg(UART1_RTS);
 
+       /* parallel camera interface */
+       omap_cfg_reg(H19_1610_CAM_EXCLK);
+       omap_cfg_reg(J15_1610_CAM_LCLK);
+       omap_cfg_reg(L18_1610_CAM_VS);
+       omap_cfg_reg(L15_1610_CAM_HS);
+       omap_cfg_reg(L19_1610_CAM_D0);
+       omap_cfg_reg(K14_1610_CAM_D1);
+       omap_cfg_reg(K15_1610_CAM_D2);
+       omap_cfg_reg(K19_1610_CAM_D3);
+       omap_cfg_reg(K18_1610_CAM_D4);
+       omap_cfg_reg(J14_1610_CAM_D5);
+       omap_cfg_reg(J19_1610_CAM_D6);
+       omap_cfg_reg(J18_1610_CAM_D7);
+
        iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
 
        omap_board_config = ams_delta_config;
@@ -236,6 +300,11 @@ static void __init ams_delta_init(void)
        ams_delta_latch2_write(~0, 0);
 
        omap1_usb_init(&ams_delta_usb_config);
+       omap1_set_camera_info(&ams_delta_camera_platform_data);
+#ifdef CONFIG_LEDS_TRIGGERS
+       led_trigger_register_simple("ams_delta_camera",
+                       &ams_delta_camera_led_trigger);
+#endif
        platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
 
 #ifdef CONFIG_AMS_DELTA_FIQ
index b30c4990744d075bf7d540e110684634ea6d9de6..f2fc43d8382b36c5e19e18e371abfce8e9595a74 100644 (file)
@@ -58,8 +58,7 @@ static struct omap_mmc_platform_data mmc1_data = {
        .dma_mask                       = 0xffffffff,
        .slots[0]       = {
                .set_power              = mmc_set_power,
-               .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-                                         MMC_VDD_32_33 | MMC_VDD_33_34,
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
index 54b0f063e2639d6d179ea8d786492acaa62b8323..2098525e7cc5dcd1de834fd8dd0a642077ee9ddf 100644 (file)
@@ -40,8 +40,7 @@ static struct omap_mmc_platform_data mmc1_data = {
        .dma_mask                       = 0xffffffff,
        .slots[0]       = {
                .set_power              = mmc_set_power,
-               .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-                                         MMC_VDD_32_33 | MMC_VDD_33_34,
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
index 86afb29522259e63efecc5d1758ee4ce007d55c9..071af3e4778914400eed44218b4c423071ec8c3f 100644 (file)
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/htcpld.h>
+#include <linux/leds.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -39,6 +46,7 @@
 #include <plat/board.h>
 #include <plat/keypad.h>
 #include <plat/usb.h>
+#include <plat/mmc.h>
 
 #include <mach/irqs.h>
 
 #define       OMAP_LCDC_CTRL_LCD_EN           (1 << 0)
 #define       OMAP_LCDC_STAT_DONE             (1 << 0)
 
-static struct omap_lcd_config htcherald_lcd_config __initdata = {
-       .ctrl_name      = "internal",
-};
+/* GPIO definitions for the power button and keyboard slide switch */
+#define HTCHERALD_GPIO_POWER 139
+#define HTCHERALD_GPIO_SLIDE 174
+#define HTCHERALD_GIRQ_BTNS 141
 
-static struct omap_board_config_kernel htcherald_config[] __initdata = {
-       { OMAP_TAG_LCD, &htcherald_lcd_config },
-};
+/* GPIO definitions for the touchscreen */
+#define HTCHERALD_GPIO_TS 76
+
+/* HTCPLD definitions */
+
+/*
+ * CPLD Logic
+ *
+ * Chip 3 - 0x03
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * DPAD light          x x x x  x x x 1
+ * SoundDev            x x x x  1 x x x
+ * Screen white        1 x x x  x x x x
+ * MMC power on        x x x x  x 1 x x
+ * Happy times (n)     0 x x x  x 1 x x
+ *
+ * Chip 4 - 0x04
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Keyboard light      x x x x  x x x 1
+ * LCD Bright (4)      x x x x  x 1 1 x
+ * LCD Bright (3)      x x x x  x 0 1 x
+ * LCD Bright (2)      x x x x  x 1 0 x
+ * LCD Bright (1)      x x x x  x 0 0 x
+ * LCD Off             x x x x  0 x x x
+ * LCD image (fb)      1 x x x  x x x x
+ * LCD image (white)   0 x x x  x x x x
+ * Caps lock LED       x x 1 x  x x x x
+ *
+ * Chip 5 - 0x05
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Red (solid)         x x x x  x 1 x x
+ * Red (flash)         x x x x  x x 1 x
+ * Green (GSM flash)   x x x x  1 x x x
+ * Green (GSM solid)   x x x 1  x x x x
+ * Green (wifi flash)  x x 1 x  x x x x
+ * Blue (bt flash)     x 1 x x  x x x x
+ * DPAD Int Enable     1 x x x  x x x 0
+ *
+ * (Combinations of the above can be made for different colors.)
+ * The direction pad interrupt enable must be set each time the
+ * interrupt is handled.
+ *
+ * Chip 6 - 0x06
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Vibrator            x x x x  1 x x x
+ * Alt LED             x x x 1  x x x x
+ * Screen white        1 x x x  x x x x
+ * Screen white        x x 1 x  x x x x
+ * Screen white        x 0 x x  x x x x
+ * Enable kbd dpad     x x x x  x x 0 x
+ * Happy Times         0 1 0 x  x x 0 x
+ */
+
+/*
+ * HTCPLD GPIO lines start 16 after OMAP_MAX_GPIO_LINES to account
+ * for the 16 MPUIO lines.
+ */
+#define HTCPLD_GPIO_START_OFFSET       (OMAP_MAX_GPIO_LINES + 16)
+#define HTCPLD_IRQ(chip, offset)       (OMAP_IRQ_END + 8 * (chip) + (offset))
+#define HTCPLD_BASE(chip, offset)      \
+       (HTCPLD_GPIO_START_OFFSET + 8 * (chip) + (offset))
+
+#define HTCPLD_GPIO_LED_DPAD           HTCPLD_BASE(0, 0)
+#define HTCPLD_GPIO_LED_KBD            HTCPLD_BASE(1, 0)
+#define HTCPLD_GPIO_LED_CAPS           HTCPLD_BASE(1, 5)
+#define HTCPLD_GPIO_LED_RED_FLASH      HTCPLD_BASE(2, 1)
+#define HTCPLD_GPIO_LED_RED_SOLID      HTCPLD_BASE(2, 2)
+#define HTCPLD_GPIO_LED_GREEN_FLASH    HTCPLD_BASE(2, 3)
+#define HTCPLD_GPIO_LED_GREEN_SOLID    HTCPLD_BASE(2, 4)
+#define HTCPLD_GPIO_LED_WIFI           HTCPLD_BASE(2, 5)
+#define HTCPLD_GPIO_LED_BT             HTCPLD_BASE(2, 6)
+#define HTCPLD_GPIO_LED_VIBRATE                HTCPLD_BASE(3, 3)
+#define HTCPLD_GPIO_LED_ALT            HTCPLD_BASE(3, 4)
+
+#define HTCPLD_GPIO_RIGHT_KBD          HTCPLD_BASE(6, 7)
+#define HTCPLD_GPIO_UP_KBD             HTCPLD_BASE(6, 6)
+#define HTCPLD_GPIO_LEFT_KBD           HTCPLD_BASE(6, 5)
+#define HTCPLD_GPIO_DOWN_KBD           HTCPLD_BASE(6, 4)
+
+#define HTCPLD_GPIO_RIGHT_DPAD         HTCPLD_BASE(7, 7)
+#define HTCPLD_GPIO_UP_DPAD            HTCPLD_BASE(7, 6)
+#define HTCPLD_GPIO_LEFT_DPAD          HTCPLD_BASE(7, 5)
+#define HTCPLD_GPIO_DOWN_DPAD          HTCPLD_BASE(7, 4)
+#define HTCPLD_GPIO_ENTER_DPAD         HTCPLD_BASE(7, 3)
+
+/*
+ * The htcpld chip requires a gpio write to a specific line
+ * to re-enable interrupts after one has occurred.
+ */
+#define HTCPLD_GPIO_INT_RESET_HI       HTCPLD_BASE(2, 7)
+#define HTCPLD_GPIO_INT_RESET_LO       HTCPLD_BASE(2, 0)
+
+/* Chip 5 */
+#define HTCPLD_IRQ_RIGHT_KBD           HTCPLD_IRQ(0, 7)
+#define HTCPLD_IRQ_UP_KBD              HTCPLD_IRQ(0, 6)
+#define HTCPLD_IRQ_LEFT_KBD            HTCPLD_IRQ(0, 5)
+#define HTCPLD_IRQ_DOWN_KBD            HTCPLD_IRQ(0, 4)
+
+/* Chip 6 */
+#define HTCPLD_IRQ_RIGHT_DPAD          HTCPLD_IRQ(1, 7)
+#define HTCPLD_IRQ_UP_DPAD             HTCPLD_IRQ(1, 6)
+#define HTCPLD_IRQ_LEFT_DPAD           HTCPLD_IRQ(1, 5)
+#define HTCPLD_IRQ_DOWN_DPAD           HTCPLD_IRQ(1, 4)
+#define HTCPLD_IRQ_ENTER_DPAD          HTCPLD_IRQ(1, 3)
 
 /* Keyboard definition */
 
@@ -140,6 +258,129 @@ static struct platform_device kp_device = {
        .resource       = kp_resources,
 };
 
+/* GPIO buttons for keyboard slide and power button */
+static struct gpio_keys_button herald_gpio_keys_table[] = {
+       {BTN_0,  HTCHERALD_GPIO_POWER, 1, "POWER", EV_KEY, 1, 20},
+       {SW_LID, HTCHERALD_GPIO_SLIDE, 0, "SLIDE", EV_SW,  1, 20},
+
+       {KEY_LEFT,  HTCPLD_GPIO_LEFT_KBD,  1, "LEFT",  EV_KEY, 1, 20},
+       {KEY_RIGHT, HTCPLD_GPIO_RIGHT_KBD, 1, "RIGHT", EV_KEY, 1, 20},
+       {KEY_UP,    HTCPLD_GPIO_UP_KBD,    1, "UP",    EV_KEY, 1, 20},
+       {KEY_DOWN,  HTCPLD_GPIO_DOWN_KBD,  1, "DOWN",  EV_KEY, 1, 20},
+
+       {KEY_LEFT,  HTCPLD_GPIO_LEFT_DPAD,   1, "DLEFT",  EV_KEY, 1, 20},
+       {KEY_RIGHT, HTCPLD_GPIO_RIGHT_DPAD,  1, "DRIGHT", EV_KEY, 1, 20},
+       {KEY_UP,    HTCPLD_GPIO_UP_DPAD,     1, "DUP",    EV_KEY, 1, 20},
+       {KEY_DOWN,  HTCPLD_GPIO_DOWN_DPAD,   1, "DDOWN",  EV_KEY, 1, 20},
+       {KEY_ENTER, HTCPLD_GPIO_ENTER_DPAD,  1, "DENTER", EV_KEY, 1, 20},
+};
+
+static struct gpio_keys_platform_data herald_gpio_keys_data = {
+       .buttons        = herald_gpio_keys_table,
+       .nbuttons       = ARRAY_SIZE(herald_gpio_keys_table),
+       .rep            = 1,
+};
+
+static struct platform_device herald_gpiokeys_device = {
+       .name      = "gpio-keys",
+       .id             = -1,
+       .dev = {
+               .platform_data = &herald_gpio_keys_data,
+       },
+};
+
+/* LEDs for the Herald.  These connect to the HTCPLD GPIO device. */
+static struct gpio_led gpio_leds[] = {
+       {"dpad",        NULL, HTCPLD_GPIO_LED_DPAD,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"kbd",         NULL, HTCPLD_GPIO_LED_KBD,         0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"vibrate",     NULL, HTCPLD_GPIO_LED_VIBRATE,     0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"green_solid", NULL, HTCPLD_GPIO_LED_GREEN_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"green_flash", NULL, HTCPLD_GPIO_LED_GREEN_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"red_solid",   "mmc0", HTCPLD_GPIO_LED_RED_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"red_flash",   NULL, HTCPLD_GPIO_LED_RED_FLASH,   0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"wifi",        NULL, HTCPLD_GPIO_LED_WIFI,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"bt",          NULL, HTCPLD_GPIO_LED_BT,          0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"caps",        NULL, HTCPLD_GPIO_LED_CAPS,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+       {"alt",         NULL, HTCPLD_GPIO_LED_ALT,         0, 0, LEDS_GPIO_DEFSTATE_OFF},
+};
+
+static struct gpio_led_platform_data gpio_leds_data = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device gpio_leds_device = {
+       .name           = "leds-gpio",
+       .id             = 0,
+       .dev    = {
+               .platform_data  = &gpio_leds_data,
+       },
+};
+
+/* HTC PLD chips */
+
+static struct resource htcpld_resources[] = {
+       [0] = {
+               .start  = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+               .end    = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct htcpld_chip_platform_data htcpld_chips[] = {
+       [0] = {
+               .addr           = 0x03,
+               .reset          = 0x04,
+               .num_gpios      = 8,
+               .gpio_out_base  = HTCPLD_BASE(0, 0),
+               .gpio_in_base   = HTCPLD_BASE(4, 0),
+       },
+       [1] = {
+               .addr           = 0x04,
+               .reset          = 0x8e,
+               .num_gpios      = 8,
+               .gpio_out_base  = HTCPLD_BASE(1, 0),
+               .gpio_in_base   = HTCPLD_BASE(5, 0),
+       },
+       [2] = {
+               .addr           = 0x05,
+               .reset          = 0x80,
+               .num_gpios      = 8,
+               .gpio_out_base  = HTCPLD_BASE(2, 0),
+               .gpio_in_base   = HTCPLD_BASE(6, 0),
+               .irq_base       = HTCPLD_IRQ(0, 0),
+               .num_irqs       = 8,
+       },
+       [3] = {
+               .addr           = 0x06,
+               .reset          = 0x40,
+               .num_gpios      = 8,
+               .gpio_out_base  = HTCPLD_BASE(3, 0),
+               .gpio_in_base   = HTCPLD_BASE(7, 0),
+               .irq_base       = HTCPLD_IRQ(1, 0),
+               .num_irqs       = 8,
+       },
+};
+
+struct htcpld_core_platform_data htcpld_pfdata = {
+       .int_reset_gpio_hi = HTCPLD_GPIO_INT_RESET_HI,
+       .int_reset_gpio_lo = HTCPLD_GPIO_INT_RESET_LO,
+       .i2c_adapter_id    = 1,
+
+       .chip              = htcpld_chips,
+       .num_chip          = ARRAY_SIZE(htcpld_chips),
+};
+
+static struct platform_device htcpld_device = {
+       .name           = "i2c-htcpld",
+       .id             = -1,
+       .resource       = htcpld_resources,
+       .num_resources  = ARRAY_SIZE(htcpld_resources),
+       .dev    = {
+               .platform_data  = &htcpld_pfdata,
+       },
+};
+
 /* USB Device */
 static struct omap_usb_config htcherald_usb_config __initdata = {
        .otg = 0,
@@ -150,14 +391,71 @@ static struct omap_usb_config htcherald_usb_config __initdata = {
 };
 
 /* LCD Device resources */
+static struct omap_lcd_config htcherald_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel htcherald_config[] __initdata = {
+       { OMAP_TAG_LCD, &htcherald_lcd_config },
+};
+
 static struct platform_device lcd_device = {
        .name           = "lcd_htcherald",
        .id             = -1,
 };
 
+/* MMC Card */
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+static struct omap_mmc_platform_data htc_mmc1_data = {
+       .nr_slots                       = 1,
+       .switch_slot                    = NULL,
+       .slots[0]       = {
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
+               .name                   = "mmcblk",
+               .nomux                  = 1,
+               .wires                  = 4,
+               .switch_pin             = -1,
+       },
+};
+
+static struct omap_mmc_platform_data *htc_mmc_data[1];
+#endif
+
+
+/* Platform devices for the Herald */
 static struct platform_device *devices[] __initdata = {
        &kp_device,
        &lcd_device,
+       &htcpld_device,
+       &gpio_leds_device,
+       &herald_gpiokeys_device,
+};
+
+/*
+ * Touchscreen
+ */
+static const struct ads7846_platform_data htcherald_ts_platform_data = {
+       .model                  = 7846,
+       .keep_vref_on           = 1,
+       .x_plate_ohms           = 496,
+       .gpio_pendown           = HTCHERALD_GPIO_TS,
+       .pressure_max           = 100000,
+       .pressure_min           = 5000,
+       .x_min                  = 528,
+       .x_max                  = 3760,
+       .y_min                  = 624,
+       .y_max                  = 3760,
+};
+
+static struct spi_board_info __initdata htcherald_spi_board_info[] = {
+       {
+               .modalias               = "ads7846",
+               .platform_data          = &htcherald_ts_platform_data,
+               .irq                    = OMAP_GPIO_IRQ(HTCHERALD_GPIO_TS),
+               .max_speed_hz           = 2500000,
+               .bus_num                = 2,
+               .chip_select            = 1,
+       }
 };
 
 /*
@@ -278,6 +576,7 @@ static void __init htcherald_init(void)
 {
        printk(KERN_INFO "HTC Herald init.\n");
 
+       /* Do board initialization before we register all the devices */
        omap_gpio_init();
 
        omap_board_config = htcherald_config;
@@ -288,6 +587,16 @@ static void __init htcherald_init(void)
 
        htcherald_usb_enable();
        omap1_usb_init(&htcherald_usb_config);
+
+       spi_register_board_info(htcherald_spi_board_info,
+               ARRAY_SIZE(htcherald_spi_board_info));
+
+       omap_register_i2c_bus(1, 100, NULL, 0);
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+       htc_mmc_data[0] = &htc_mmc1_data;
+       omap1_init_mmc(htc_mmc_data, 1);
+#endif
 }
 
 static void __init htcherald_init_irq(void)
index 5b33ae8141bc9844536a2edecbc5ab93b9c63c84..e8ddd86e3fda698f2227a86f78774f0603d89dd9 100644 (file)
@@ -44,8 +44,7 @@ static struct omap_mmc_platform_data mmc1_data = {
        .nr_slots                       = 1,
        .slots[0]       = {
                .set_power              = mmc_set_power,
-               .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-                                         MMC_VDD_32_33 | MMC_VDD_33_34,
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
index aa0725608fb17ec51e15cc077f0f3198a19018ab..ea0d80a89da7560ac0a6a9d5b0d5d3a52a89c258 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -25,6 +26,7 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -191,10 +193,76 @@ static inline void omap_init_spi100k(void)
 }
 #endif
 
+
+#define OMAP1_CAMERA_BASE      0xfffb6800
+#define OMAP1_CAMERA_IOSIZE    0x1c
+
+static struct resource omap1_camera_resources[] = {
+       [0] = {
+               .start  = OMAP1_CAMERA_BASE,
+               .end    = OMAP1_CAMERA_BASE + OMAP1_CAMERA_IOSIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = INT_CAMERA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 omap1_camera_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device omap1_camera_device = {
+       .name           = "omap1-camera",
+       .id             = 0, /* This is used to put cameras on this interface */
+       .dev            = {
+               .dma_mask               = &omap1_camera_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(omap1_camera_resources),
+       .resource       = omap1_camera_resources,
+};
+
+void __init omap1_camera_init(void *info)
+{
+       struct platform_device *dev = &omap1_camera_device;
+       int ret;
+
+       dev->dev.platform_data = info;
+
+       ret = platform_device_register(dev);
+       if (ret)
+               dev_err(&dev->dev, "unable to register device: %d\n", ret);
+}
+
+
 /*-------------------------------------------------------------------------*/
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+       .name   = "omap-pcm-audio",
+       .id     = -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+       platform_device_register(&omap_mcbsp1);
+       platform_device_register(&omap_mcbsp2);
+       if (!cpu_is_omap7xx())
+               platform_device_register(&omap_mcbsp3);
+       platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -227,8 +295,36 @@ static int __init omap1_init_devices(void)
        omap_init_rtc();
        omap_init_spi100k();
        omap_init_sti();
+       omap_init_audio();
 
        return 0;
 }
 arch_initcall(omap1_init_devices);
 
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+
+static struct resource wdt_resources[] = {
+       {
+               .start          = 0xfffeb000,
+               .end            = 0xfffeb07F,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap_wdt_device = {
+       .name      = "omap_wdt",
+       .id          = -1,
+       .num_resources  = ARRAY_SIZE(wdt_resources),
+       .resource       = wdt_resources,
+};
+
+static int __init omap_init_wdt(void)
+{
+       if (!cpu_is_omap16xx())
+               return;
+
+       platform_device_register(&omap_wdt_device);
+       return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap1/include/mach/camera.h b/arch/arm/mach-omap1/include/mach/camera.h
new file mode 100644 (file)
index 0000000..fd54b45
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+void omap1_camera_init(void *);
+
+static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info)
+{
+       omap1_camera_init(info);
+}
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
new file mode 100644 (file)
index 0000000..8b66392
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Runtime PM support code for OMAP1
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+static int omap1_pm_runtime_suspend(struct device *dev)
+{
+       struct clk *iclk, *fclk;
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       ret = pm_generic_runtime_suspend(dev);
+
+       fclk = clk_get(dev, "fck");
+       if (!IS_ERR(fclk)) {
+               clk_disable(fclk);
+               clk_put(fclk);
+       }
+
+       iclk = clk_get(dev, "ick");
+       if (!IS_ERR(iclk)) {
+               clk_disable(iclk);
+               clk_put(iclk);
+       }
+
+       return 0;
+};
+
+static int omap1_pm_runtime_resume(struct device *dev)
+{
+       int ret = 0;
+       struct clk *iclk, *fclk;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       iclk = clk_get(dev, "ick");
+       if (!IS_ERR(iclk)) {
+               clk_enable(iclk);
+               clk_put(iclk);
+       }
+
+       fclk = clk_get(dev, "fck");
+       if (!IS_ERR(fclk)) {
+               clk_enable(fclk);
+               clk_put(fclk);
+       }
+
+       return pm_generic_runtime_resume(dev);
+};
+
+static int __init omap1_pm_runtime_init(void)
+{
+       const struct dev_pm_ops *pm;
+       struct dev_pm_ops *omap_pm;
+
+       pm = platform_bus_get_pm_ops();
+       if (!pm) {
+               pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+       if (!omap_pm) {
+               pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       omap_pm->runtime_suspend = omap1_pm_runtime_suspend;
+       omap_pm->runtime_resume = omap1_pm_runtime_resume;
+
+       platform_bus_set_pm_ops(omap_pm);
+
+       return 0;
+}
+core_initcall(omap1_pm_runtime_init);
+#endif /* CONFIG_PM_RUNTIME */
index b48bacf0a7aa96c9b6892c80efb94183019efe53..ab784bfde908c77b55dc1b4833988a2c7afaef6f 100644 (file)
@@ -11,9 +11,8 @@ config ARCH_OMAP2PLUS_TYPICAL
        select PM_RUNTIME
        select VFP
        select NEON if ARCH_OMAP3 || ARCH_OMAP4
-       select SERIAL_8250
-       select SERIAL_CORE_CONSOLE
-       select SERIAL_8250_CONSOLE
+       select SERIAL_OMAP
+       select SERIAL_OMAP_CONSOLE
        select I2C
        select I2C_OMAP
        select MFD
@@ -35,7 +34,7 @@ config ARCH_OMAP3
        default y
        select CPU_V7
        select USB_ARCH_HAS_EHCI
-       select ARM_L1_CACHE_SHIFT_6
+       select ARM_L1_CACHE_SHIFT_6 if !ARCH_OMAP4
 
 config ARCH_OMAP4
        bool "TI OMAP4"
@@ -43,6 +42,8 @@ config ARCH_OMAP4
        depends on ARCH_OMAP2PLUS
        select CPU_V7
        select ARM_GIC
+       select PL310_ERRATA_588369
+       select ARM_ERRATA_720789
 
 comment "OMAP Core Type"
        depends on ARCH_OMAP2
@@ -99,20 +100,20 @@ config MACH_OMAP2_TUSB6010
 
 config MACH_OMAP_H4
        bool "OMAP 2420 H4 board"
-       depends on ARCH_OMAP2
+       depends on ARCH_OMAP2420
        default y
        select OMAP_PACKAGE_ZAF
        select OMAP_DEBUG_DEVICES
 
 config MACH_OMAP_APOLLON
        bool "OMAP 2420 Apollon board"
-       depends on ARCH_OMAP2
+       depends on ARCH_OMAP2420
        default y
        select OMAP_PACKAGE_ZAC
 
 config MACH_OMAP_2430SDP
        bool "OMAP 2430 SDP board"
-       depends on ARCH_OMAP2
+       depends on ARCH_OMAP2430
        default y
        select OMAP_PACKAGE_ZAC
 
@@ -135,6 +136,26 @@ config MACH_OMAP_LDP
        default y
        select OMAP_PACKAGE_CBB
 
+config MACH_OMAP3530_LV_SOM
+       bool "OMAP3 Logic 3530 LV SOM board"
+       depends on ARCH_OMAP3
+       select OMAP_PACKAGE_CBB
+       default y
+       help
+        Support for the LogicPD OMAP3530 SOM Development kit
+        for full description please see the products webpage at
+        http://www.logicpd.com/products/development-kits/texas-instruments-zoom%E2%84%A2-omap35x-development-kit
+
+config MACH_OMAP3_TORPEDO
+       bool "OMAP3 Logic 35x Torpedo board"
+       depends on ARCH_OMAP3
+       select OMAP_PACKAGE_CBB
+       default y
+       help
+        Support for the LogicPD OMAP35x Torpedo Development kit
+        for full description please see the products webpage at
+        http://www.logicpd.com/products/development-kits/zoom-omap35x-torpedo-development-kit
+
 config MACH_OVERO
        bool "Gumstix Overo board"
        depends on ARCH_OMAP3
@@ -200,12 +221,18 @@ config MACH_OMAP_ZOOM2
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBB
+       select SERIAL_8250
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_8250_CONSOLE
 
 config MACH_OMAP_ZOOM3
        bool "OMAP3630 Zoom3 board"
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBP
+       select SERIAL_8250
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_8250_CONSOLE
 
 config MACH_CM_T35
        bool "CompuLab CM-T35 module"
@@ -214,12 +241,25 @@ config MACH_CM_T35
        select OMAP_PACKAGE_CUS
        select OMAP_MUX
 
+config MACH_CM_T3517
+       bool "CompuLab CM-T3517 module"
+       depends on ARCH_OMAP3
+       default y
+       select OMAP_PACKAGE_CBB
+       select OMAP_MUX
+
 config MACH_IGEP0020
        bool "IGEP v2 board"
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBB
 
+config MACH_IGEP0030
+       bool "IGEP OMAP3 module"
+       depends on ARCH_OMAP3
+       default y
+       select OMAP_PACKAGE_CBB
+
 config MACH_SBC3530
        bool "OMAP3 SBC STALKER board"
        depends on ARCH_OMAP3
index 88d3a1e920f583110a88aa8c90bbe7903b098f8f..7352412e49170e5b98b56c69bbd1e2679ff42ace 100644 (file)
@@ -3,9 +3,10 @@
 #
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o
+obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o \
+        common.o
 
-omap-2-3-common                                = irq.o sdrc.o
+omap-2-3-common                                = irq.o sdrc.o prm2xxx_3xxx.o
 hwmod-common                           = omap_hwmod.o \
                                          omap_hwmod_common_data.o
 prcm-common                            = prcm.o powerdomain.o
@@ -15,7 +16,7 @@ clock-common                          = clock.o clock_common_data.o \
 
 obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) prm44xx.o $(hwmod-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
@@ -49,14 +50,18 @@ obj-$(CONFIG_ARCH_OMAP2)            += sdrc2xxx.o
 # Power Management
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2)               += sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o cpuidle34xx.o
-obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o
+obj-$(CONFIG_ARCH_OMAP2)               += sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 
 AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
 AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a
 
+ifeq ($(CONFIG_PM_VERBOSE),y)
+CFLAGS_pm_bus.o                                += -DDEBUG
+endif
+
 endif
 
 # PRCM
@@ -87,6 +92,7 @@ obj-$(CONFIG_ARCH_OMAP2430)           += opp2430_data.o
 obj-$(CONFIG_ARCH_OMAP2420)            += omap_hwmod_2420_data.o
 obj-$(CONFIG_ARCH_OMAP2430)            += omap_hwmod_2430_data.o
 obj-$(CONFIG_ARCH_OMAP3)               += omap_hwmod_3xxx_data.o
+obj-$(CONFIG_ARCH_OMAP4)               += omap_hwmod_44xx_data.o
 
 # EMU peripherals
 obj-$(CONFIG_OMAP3_EMU)                        += emu.o
@@ -115,6 +121,10 @@ obj-$(CONFIG_MACH_DEVKIT8000)      += board-devkit8000.o \
 obj-$(CONFIG_MACH_OMAP_LDP)            += board-ldp.o \
                                           board-flash.o \
                                           hsmmc.o
+obj-$(CONFIG_MACH_OMAP3530_LV_SOM)      += board-omap3logic.o \
+                                          hsmmc.o
+obj-$(CONFIG_MACH_OMAP3_TORPEDO)        += board-omap3logic.o \
+                                          hsmmc.o
 obj-$(CONFIG_MACH_OVERO)               += board-overo.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_OMAP3EVM)            += board-omap3evm.o \
@@ -146,8 +156,11 @@ obj-$(CONFIG_MACH_OMAP_3630SDP)            += board-3630sdp.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_CM_T35)              += board-cm-t35.o \
                                           hsmmc.o
+obj-$(CONFIG_MACH_CM_T3517)            += board-cm-t3517.o
 obj-$(CONFIG_MACH_IGEP0020)            += board-igep0020.o \
                                           hsmmc.o
+obj-$(CONFIG_MACH_IGEP0030)            += board-igep0030.o \
+                                          hsmmc.o
 obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK)     += board-omap3touchbook.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_OMAP_4430SDP)                += board-4430sdp.o \
@@ -174,3 +187,6 @@ obj-y                                       += $(nand-m) $(nand-y)
 
 smc91x-$(CONFIG_SMC91X)                        := gpmc-smc91x.o
 obj-y                                  += $(smc91x-m) $(smc91x-y)
+
+smsc911x-$(CONFIG_SMSC911X)            := gpmc-smsc911x.o
+obj-y                                  += $(smsc911x-m) $(smsc911x-y)
index b857ce48451068cd24e4e5ae8125d7680ec73621..b527f8d187ad571f3d3ee7e04514393f1891f2b7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mmc/host.h>
 #include <linux/delay.h>
 #include <linux/i2c/twl.h>
 #include <linux/err.h>
@@ -190,7 +191,7 @@ static int __init omap2430_i2c_init(void)
 static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .ext_clock      = 1,
index a5b095cf2adcdd67a14690e7eb0c8d99244f6167..4e3742c512b81f3da619c7cb9895bad8fe61b39e 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
 #include <plat/display.h>
 
-#include <plat/control.h>
 #include <plat/gpmc-smc91x.h>
 
-#include <mach/board-flash.h>
-
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-qimonda-hyb18m512160af-6.h"
 #include "hsmmc.h"
 #include "pm.h"
+#include "control.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
@@ -76,7 +76,7 @@ static struct cpuidle_params omap3_cpuidle_params_table[] = {
        {1, 10000, 30000, 300000},
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_LEFT),
        KEY(0, 1, KEY_RIGHT),
        KEY(0, 2, KEY_A),
@@ -353,12 +353,12 @@ static struct omap2_hsmmc_info mmc[] = {
                /* 8 bits (default) requires S6.3 == ON,
                 * so the SIM card isn't used; else 4 bits.
                 */
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 4,
        },
        {
                .mmc            = 2,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 7,
        },
        {}      /* Terminator */
index fd27ac0860b0c6b6d217f0d46b61c65a4574c36b..bbcf580fa097101056b1fc98545fd5cae9c1fdf8 100644 (file)
@@ -21,8 +21,8 @@
 #include <plat/usb.h>
 
 #include <mach/board-zoom.h>
-#include <mach/board-flash.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
 
@@ -208,7 +208,6 @@ static struct flash_partitions sdp_flash_partitions[] = {
 static void __init omap_sdp_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
-       omap_serial_init();
        zoom_peripherals_init();
        board_smc91x_init();
        board_flash_init(sdp_flash_partitions, chip_sel_sdp);
index 0b6a65f3a10a2adf508d209c7daeccfc51fea68c..69a4ae971e411a35f7c8be8b496e67f586b3092c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/usb/otg.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c/twl.h>
+#include <linux/gpio_keys.h>
 #include <linux/regulator/machine.h>
 #include <linux/leds.h>
 
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+
 #include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
 
 #define ETH_KS8851_IRQ                 34
 #define ETH_KS8851_POWER_ON            48
 #define ETH_KS8851_QUART               138
+#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO       184
+#define OMAP4_SFH7741_ENABLE_GPIO              188
 
 static struct gpio_led sdp4430_gpio_leds[] = {
        {
@@ -77,11 +81,47 @@ static struct gpio_led sdp4430_gpio_leds[] = {
 
 };
 
+static struct gpio_keys_button sdp4430_gpio_keys[] = {
+       {
+               .desc                   = "Proximity Sensor",
+               .type                   = EV_SW,
+               .code                   = SW_FRONT_PROXIMITY,
+               .gpio                   = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO,
+               .active_low             = 0,
+       }
+};
+
 static struct gpio_led_platform_data sdp4430_led_data = {
        .leds   = sdp4430_gpio_leds,
        .num_leds       = ARRAY_SIZE(sdp4430_gpio_leds),
 };
 
+static int omap_prox_activate(struct device *dev)
+{
+       gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1);
+       return 0;
+}
+
+static void omap_prox_deactivate(struct device *dev)
+{
+       gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0);
+}
+
+static struct gpio_keys_platform_data sdp4430_gpio_keys_data = {
+       .buttons        = sdp4430_gpio_keys,
+       .nbuttons       = ARRAY_SIZE(sdp4430_gpio_keys),
+       .enable         = omap_prox_activate,
+       .disable        = omap_prox_deactivate,
+};
+
+static struct platform_device sdp4430_gpio_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &sdp4430_gpio_keys_data,
+       },
+};
+
 static struct platform_device sdp4430_leds_gpio = {
        .name   = "leds-gpio",
        .id     = -1,
@@ -161,6 +201,7 @@ static struct platform_device sdp4430_lcd_device = {
 
 static struct platform_device *sdp4430_devices[] __initdata = {
        &sdp4430_lcd_device,
+       &sdp4430_gpio_keys_device,
        &sdp4430_leds_gpio,
 };
 
@@ -193,15 +234,16 @@ static struct omap_musb_board_data musb_board_data = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = -EINVAL,
        },
        {
                .mmc            = 2,
-               .wires          = 8,
+               .caps           =  MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .nonremovable   = true,
+               .ocr_mask       = MMC_VDD_29_30,
        },
        {}      /* Terminator */
 };
@@ -235,8 +277,14 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 {
-       struct omap_mmc_platform_data *pdata = dev->platform_data;
+       struct omap_mmc_platform_data *pdata;
 
+       /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+       if (!dev) {
+               pr_err("Failed %s\n", __func__);
+               return;
+       }
+       pdata = dev->platform_data;
        pdata->init =   omap4_twl6030_hsmmc_late_init;
 }
 
@@ -412,6 +460,11 @@ static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = {
                I2C_BOARD_INFO("tmp105", 0x48),
        },
 };
+static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("hmc5843", 0x1e),
+       },
+};
 static int __init omap4_i2c_init(void)
 {
        /*
@@ -423,14 +476,36 @@ static int __init omap4_i2c_init(void)
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
                                ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
-       omap_register_i2c_bus(4, 400, NULL, 0);
+       omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo,
+                               ARRAY_SIZE(sdp4430_i2c_4_boardinfo));
        return 0;
 }
+
+static void __init omap_sfh7741prox_init(void)
+{
+       int  error;
+
+       error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741");
+       if (error < 0) {
+               pr_err("%s:failed to request GPIO %d, error %d\n",
+                       __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+               return;
+       }
+
+       error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0);
+       if (error < 0) {
+               pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",
+                        __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+               gpio_free(OMAP4_SFH7741_ENABLE_GPIO);
+       }
+}
+
 static void __init omap_4430sdp_init(void)
 {
        int status;
 
        omap4_i2c_init();
+       omap_sfh7741prox_init();
        platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
        omap_serial_init();
        omap4_twl6030_hsmmc_init(mmc);
index d547036aff3f2cb640da7905cf75ec8f22f6aff7..07399505312b19fac8331d1d0b5367e85418a422 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/i2c/pca953x.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/usb.h>
 #include <plat/display.h>
 
 #include "mux.h"
+#include "control.h"
 
-#define AM35XX_EVM_PHY_MASK            (0xF)
 #define AM35XX_EVM_MDIO_FREQUENCY      (1000000)
 
+static struct mdio_platform_data am3517_evm_mdio_pdata = {
+       .bus_freq       = AM35XX_EVM_MDIO_FREQUENCY,
+};
+
+static struct resource am3517_mdio_resources[] = {
+       {
+               .start  = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
+               .end    = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
+                         SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device am3517_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(am3517_mdio_resources),
+       .resource       = am3517_mdio_resources,
+       .dev.platform_data = &am3517_evm_mdio_pdata,
+};
+
 static struct emac_platform_data am3517_evm_emac_pdata = {
-       .phy_mask       = AM35XX_EVM_PHY_MASK,
-       .mdio_max_freq  = AM35XX_EVM_MDIO_FREQUENCY,
        .rmii_en        = 1,
 };
 
 static struct resource am3517_emac_resources[] = {
        {
                .start  = AM35XX_IPSS_EMAC_BASE,
-               .end    = AM35XX_IPSS_EMAC_BASE + 0x3FFFF,
+               .end    = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -106,14 +125,13 @@ static void am3517_disable_ethernet_int(void)
        regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
 }
 
-void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
+static void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
 {
        unsigned int regval;
 
        pdata->ctrl_reg_offset          = AM35XX_EMAC_CNTRL_OFFSET;
        pdata->ctrl_mod_reg_offset      = AM35XX_EMAC_CNTRL_MOD_OFFSET;
        pdata->ctrl_ram_offset          = AM35XX_EMAC_CNTRL_RAM_OFFSET;
-       pdata->mdio_reg_offset          = AM35XX_EMAC_MDIO_OFFSET;
        pdata->ctrl_ram_size            = AM35XX_EMAC_CNTRL_RAM_SIZE;
        pdata->version                  = EMAC_VERSION_2;
        pdata->hw_ram_addr              = AM35XX_EMAC_HW_RAM_ADDR;
@@ -121,6 +139,9 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
        pdata->interrupt_disable        = am3517_disable_ethernet_int;
        am3517_emac_device.dev.platform_data    = pdata;
        platform_device_register(&am3517_emac_device);
+       platform_device_register(&am3517_mdio_device);
+       clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
+                     NULL, &am3517_emac_device.dev);
 
        regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
        regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
@@ -139,7 +160,6 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
 static struct i2c_board_info __initdata am3517evm_i2c1_boardinfo[] = {
        {
                I2C_BOARD_INFO("s35390a", 0x30),
-               .type           = "s35390a",
        },
 };
 
@@ -347,7 +367,7 @@ static struct omap_dss_board_info am3517_evm_dss_data = {
        .default_device = &am3517_evm_lcd_device,
 };
 
-struct platform_device am3517_evm_dss_device = {
+static struct platform_device am3517_evm_dss_device = {
        .name           = "omapdss",
        .id             = -1,
        .dev            = {
index 68f07f5f441a65887e9d7783173b30916ccb0461..2c6db1aaeb2965406d82457bb8fe0fb81ebc0498 100644 (file)
@@ -39,9 +39,9 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/gpmc.h>
-#include <plat/control.h>
 
 #include "mux.h"
+#include "control.h"
 
 /* LED & Switch macros */
 #define LED0_GPIO13            13
index 934d9380c372e5ec31710fb47f6f4aa58714c60e..63f764e2af3ff31c9b5edceb6da2e9dcc307cd90 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c/at24.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/tdo24m.h>
@@ -237,8 +238,6 @@ static inline void cm_t35_init_nand(void) {}
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 #include <linux/spi/ads7846.h>
 
-#include <plat/mcspi.h>
-
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
        .turbo_mode     = 0,
        .single_channel = 1,    /* 0: slave, 1: master */
@@ -558,7 +557,7 @@ static struct twl4030_usb_data cm_t35_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
-static int cm_t35_keymap[] = {
+static uint32_t cm_t35_keymap[] = {
        KEY(0, 0, KEY_A),       KEY(0, 1, KEY_B),       KEY(0, 2, KEY_LEFT),
        KEY(1, 0, KEY_UP),      KEY(1, 1, KEY_ENTER),   KEY(1, 2, KEY_DOWN),
        KEY(2, 0, KEY_RIGHT),   KEY(2, 1, KEY_C),       KEY(2, 2, KEY_D),
@@ -579,14 +578,14 @@ static struct twl4030_keypad_data cm_t35_kp_data = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
 
        },
        {
                .mmc            = 2,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .transceiver    = 1,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
new file mode 100644 (file)
index 0000000..1dd303e
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * linux/arch/arm/mach-omap2/board-cm-t3517.c
+ *
+ * Support for the CompuLab CM-T3517 modules
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Author: Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/rtc-v3020.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/can/platform/ti_hecc.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+#include <plat/nand.h>
+#include <plat/gpmc.h>
+
+#include <mach/am35xx.h>
+
+#include "mux.h"
+#include "control.h"
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static struct gpio_led cm_t3517_leds[] = {
+       [0] = {
+               .gpio                   = 186,
+               .name                   = "cm-t3517:green",
+               .default_trigger        = "heartbeat",
+               .active_low             = 0,
+       },
+};
+
+static struct gpio_led_platform_data cm_t3517_led_pdata = {
+       .num_leds       = ARRAY_SIZE(cm_t3517_leds),
+       .leds           = cm_t3517_leds,
+};
+
+static struct platform_device cm_t3517_led_device = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &cm_t3517_led_pdata,
+       },
+};
+
+static void __init cm_t3517_init_leds(void)
+{
+       platform_device_register(&cm_t3517_led_device);
+}
+#else
+static inline void cm_t3517_init_leds(void) {}
+#endif
+
+#if defined(CONFIG_CAN_TI_HECC) || defined(CONFIG_CAN_TI_HECC_MODULE)
+static struct resource cm_t3517_hecc_resources[] = {
+       {
+               .start  = AM35XX_IPSS_HECC_BASE,
+               .end    = AM35XX_IPSS_HECC_BASE + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = INT_35XX_HECC0_IRQ,
+               .end    = INT_35XX_HECC0_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct ti_hecc_platform_data cm_t3517_hecc_pdata = {
+       .scc_hecc_offset        = AM35XX_HECC_SCC_HECC_OFFSET,
+       .scc_ram_offset         = AM35XX_HECC_SCC_RAM_OFFSET,
+       .hecc_ram_offset        = AM35XX_HECC_RAM_OFFSET,
+       .mbx_offset             = AM35XX_HECC_MBOX_OFFSET,
+       .int_line               = AM35XX_HECC_INT_LINE,
+       .version                = AM35XX_HECC_VERSION,
+};
+
+static struct platform_device cm_t3517_hecc_device = {
+       .name           = "ti_hecc",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(cm_t3517_hecc_resources),
+       .resource       = cm_t3517_hecc_resources,
+       .dev            = {
+               .platform_data  = &cm_t3517_hecc_pdata,
+       },
+};
+
+static void cm_t3517_init_hecc(void)
+{
+       platform_device_register(&cm_t3517_hecc_device);
+}
+#else
+static inline void cm_t3517_init_hecc(void) {}
+#endif
+
+#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
+#define RTC_IO_GPIO            (153)
+#define RTC_WR_GPIO            (154)
+#define RTC_RD_GPIO            (160)
+#define RTC_CS_GPIO            (163)
+
+struct v3020_platform_data cm_t3517_v3020_pdata = {
+       .use_gpio       = 1,
+       .gpio_cs        = RTC_CS_GPIO,
+       .gpio_wr        = RTC_WR_GPIO,
+       .gpio_rd        = RTC_RD_GPIO,
+       .gpio_io        = RTC_IO_GPIO,
+};
+
+static struct platform_device cm_t3517_rtc_device = {
+       .name           = "v3020",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &cm_t3517_v3020_pdata,
+       }
+};
+
+static void __init cm_t3517_init_rtc(void)
+{
+       platform_device_register(&cm_t3517_rtc_device);
+}
+#else
+static inline void cm_t3517_init_rtc(void) {}
+#endif
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+#define HSUSB1_RESET_GPIO      (146)
+#define HSUSB2_RESET_GPIO      (147)
+#define USB_HUB_RESET_GPIO     (152)
+
+static struct ehci_hcd_omap_platform_data cm_t3517_ehci_pdata __initdata = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset  = true,
+       .reset_gpio_port[0]  = HSUSB1_RESET_GPIO,
+       .reset_gpio_port[1]  = HSUSB2_RESET_GPIO,
+       .reset_gpio_port[2]  = -EINVAL,
+};
+
+static int cm_t3517_init_usbh(void)
+{
+       int err;
+
+       err = gpio_request(USB_HUB_RESET_GPIO, "usb hub rst");
+       if (err) {
+               pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
+       } else {
+               gpio_direction_output(USB_HUB_RESET_GPIO, 0);
+               udelay(10);
+               gpio_set_value(USB_HUB_RESET_GPIO, 1);
+               msleep(1);
+       }
+
+       usb_ehci_init(&cm_t3517_ehci_pdata);
+
+       return 0;
+}
+#else
+static inline int cm_t3517_init_usbh(void)
+{
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#define NAND_BLOCK_SIZE                SZ_128K
+
+static struct mtd_partition cm_t3517_nand_partitions[] = {
+       {
+               .name           = "xloader",
+               .offset         = 0,                    /* Offset = 0x00000 */
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "uboot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 15 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "uboot environment",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x260000 */
+               .size           = 2 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "linux",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data cm_t3517_nand_data = {
+       .parts                  = cm_t3517_nand_partitions,
+       .nr_parts               = ARRAY_SIZE(cm_t3517_nand_partitions),
+       .dma_channel            = -1,   /* disable DMA in OMAP NAND driver */
+       .cs                     = 0,
+};
+
+static void __init cm_t3517_init_nand(void)
+{
+       if (gpmc_nand_init(&cm_t3517_nand_data) < 0)
+               pr_err("CM-T3517: NAND initialization failed\n");
+}
+#else
+static inline void cm_t3517_init_nand(void) {}
+#endif
+
+static struct omap_board_config_kernel cm_t3517_config[] __initdata = {
+};
+
+static void __init cm_t3517_init_irq(void)
+{
+       omap_board_config = cm_t3517_config;
+       omap_board_config_size = ARRAY_SIZE(cm_t3517_config);
+
+       omap2_init_common_hw(NULL, NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct omap_board_mux board_mux[] __initdata = {
+       /* GPIO186 - Green LED */
+       OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+       /* RTC GPIOs: IO, WR#, RD#, CS# */
+       OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       /* HSUSB1 RESET */
+       OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+       /* HSUSB2 RESET */
+       OMAP3_MUX(UART2_RX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+       /* CM-T3517 USB HUB nRESET */
+       OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+       { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static void __init cm_t3517_init(void)
+{
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap_serial_init();
+       cm_t3517_init_leds();
+       cm_t3517_init_nand();
+       cm_t3517_init_rtc();
+       cm_t3517_init_usbh();
+       cm_t3517_init_hecc();
+}
+
+MACHINE_START(CM_T3517, "Compulab CM-T3517")
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_map_io,
+       .reserve        = omap_reserve,
+       .init_irq       = cm_t3517_init_irq,
+       .init_machine   = cm_t3517_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 2205c20a4cdb61cf17ea11dd199b752baacafc65..067f4379c87fc5d927d201df192883b5bd914820 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
@@ -44,7 +45,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 #include <plat/display.h>
 
 #include <plat/mcspi.h>
@@ -58,6 +58,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #define NAND_BLOCK_SIZE                SZ_128K
 
@@ -105,7 +106,7 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 29,
        },
        {}      /* Terminator */
@@ -198,7 +199,7 @@ static struct platform_device devkit8000_dss_device = {
 static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
        REGULATOR_SUPPLY("vdda_dac", "omapdss");
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_1),
        KEY(1, 0, KEY_2),
        KEY(2, 0, KEY_3),
index ac834aa7abf61f0713957c9f98061e8045a99767..fd38c05bb47fdff9f718b0d960c7c06ec78c3db3 100644 (file)
@@ -21,7 +21,8 @@
 #include <plat/nand.h>
 #include <plat/onenand.h>
 #include <plat/tc.h>
-#include <mach/board-flash.h>
+
+#include "board-flash.h"
 
 #define REG_FPGA_REV                   0x10
 #define REG_FPGA_DIP_SWITCH_INPUT2     0x60
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
new file mode 100644 (file)
index 0000000..69befe0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  board-sdp.h
+ *
+ *  Information structures for SDP-specific board config data
+ *
+ *  Copyright (C) 2009 Nokia Corporation
+ *  Copyright (C) 2009 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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <plat/gpmc.h>
+
+#define PDC_NOR                1
+#define PDC_NAND       2
+#define PDC_ONENAND    3
+#define DBG_MPDB       4
+
+struct flash_partitions {
+       struct mtd_partition *parts;
+       int nr_parts;
+};
+
+extern void board_flash_init(struct flash_partitions [],
+                               char chip_sel[][GPMC_CS_NUM]);
+extern void board_nand_init(struct mtd_partition *nand_parts,
+                                       u8 nr_parts, u8 cs);
index 69064b1c6a75da991e7a229296be750eb68c4649..b1c2c9a11c389f44e4e870f39ed8236f2b4ae649 100644 (file)
@@ -48,10 +48,22 @@ static void __init omap_generic_init(void)
 
 static void __init omap_generic_map_io(void)
 {
-       omap2_set_globals_242x(); /* should be 242x, 243x, or 343x */
-       omap242x_map_common_io();
+       if (cpu_is_omap242x()) {
+               omap2_set_globals_242x();
+               omap242x_map_common_io();
+       } else if (cpu_is_omap243x()) {
+               omap2_set_globals_243x();
+               omap243x_map_common_io();
+       } else if (cpu_is_omap34xx()) {
+               omap2_set_globals_3xxx();
+               omap34xx_map_common_io();
+       } else if (cpu_is_omap44xx()) {
+               omap2_set_globals_443x();
+               omap44xx_map_common_io();
+       }
 }
 
+/* XXX This machine entry name should be updated */
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
        .boot_params    = 0x80000100,
index cc39fc866524bfa1def1a0e7ec727a346f592196..929993b4bf26bbb77cbcb385a570d15adc50f231 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/control.h>
 #include <mach/gpio.h>
 #include <plat/usb.h>
 #include <plat/board.h>
@@ -42,6 +41,7 @@
 #include <plat/gpmc.h>
 
 #include "mux.h"
+#include "control.h"
 
 #define H4_FLASH_CS    0
 #define H4_SMC91X_CS   1
index b62a68ba069bae2e198af22e76b7cf1500ae9ec9..5e035a58b80923e13b0de0aee669dd132729a764 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #define IGEP2_SMSC911X_CS       5
 #define IGEP2_SMSC911X_GPIO     176
 #define IGEP2_GPIO_USBH_NRESET  24
-#define IGEP2_GPIO_LED0_GREEN  26
-#define IGEP2_GPIO_LED0_RED    27
-#define IGEP2_GPIO_LED1_RED    28
-#define IGEP2_GPIO_DVI_PUP     170
-#define IGEP2_GPIO_WIFI_NPD    94
-#define IGEP2_GPIO_WIFI_NRESET         95
+#define IGEP2_GPIO_LED0_GREEN   26
+#define IGEP2_GPIO_LED0_RED     27
+#define IGEP2_GPIO_LED1_RED     28
+#define IGEP2_GPIO_DVI_PUP      170
+
+#define IGEP2_RB_GPIO_WIFI_NPD     94
+#define IGEP2_RB_GPIO_WIFI_NRESET  95
+#define IGEP2_RB_GPIO_BT_NRESET    137
+#define IGEP2_RC_GPIO_WIFI_NPD     138
+#define IGEP2_RC_GPIO_WIFI_NRESET  139
+#define IGEP2_RC_GPIO_BT_NRESET    137
+
+/*
+ * IGEP2 Hardware Revision Table
+ *
+ *  --------------------------------------------------------------------------
+ * | Id. | Hw Rev.            | HW0 (28) | WIFI_NPD | WIFI_NRESET | BT_NRESET |
+ *  --------------------------------------------------------------------------
+ * |  0  | B                  |   high   |  gpio94  |   gpio95    |     -     |
+ * |  0  | B/C (B-compatible) |   high   |  gpio94  |   gpio95    |  gpio137  |
+ * |  1  | C                  |   low    |  gpio138 |   gpio139   |  gpio137  |
+ *  --------------------------------------------------------------------------
+ */
+
+#define IGEP2_BOARD_HWREV_B    0
+#define IGEP2_BOARD_HWREV_C    1
+
+static u8 hwrev;
+
+static void __init igep2_get_revision(void)
+{
+       u8 ret;
+
+       omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT);
+
+       if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_HW0_REV") == 0) &&
+           (gpio_direction_input(IGEP2_GPIO_LED1_RED) == 0)) {
+               ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
+               if (ret == 0) {
+                       pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
+                       hwrev = IGEP2_BOARD_HWREV_C;
+               } else if (ret ==  1) {
+                       pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
+                       hwrev = IGEP2_BOARD_HWREV_B;
+               } else {
+                       pr_err("IGEP2: Unknown Hardware Revision\n");
+                       hwrev = -1;
+               }
+       } else {
+               pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n");
+               pr_err("IGEP2: Unknown Hardware Revision\n");
+       }
+
+       gpio_free(IGEP2_GPIO_LED1_RED);
+}
 
 #if defined(CONFIG_MTD_ONENAND_OMAP2) || \
        defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
@@ -107,7 +157,7 @@ static struct platform_device igep2_onenand_device = {
        },
 };
 
-void __init igep2_flash_init(void)
+static void __init igep2_flash_init(void)
 {
        u8              cs = 0;
        u8              onenandcs = GPMC_CS_NUM + 1;
@@ -141,7 +191,7 @@ void __init igep2_flash_init(void)
 }
 
 #else
-void __init igep2_flash_init(void) {}
+static void __init igep2_flash_init(void) {}
 #endif
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
@@ -211,10 +261,6 @@ static struct regulator_consumer_supply igep2_vmmc1_supply = {
        .supply         = "vmmc",
 };
 
-static struct regulator_consumer_supply igep2_vmmc2_supply = {
-       .supply         = "vmmc",
-};
-
 /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
 static struct regulator_init_data igep2_vmmc1 = {
        .constraints = {
@@ -230,37 +276,95 @@ static struct regulator_init_data igep2_vmmc1 = {
        .consumer_supplies      = &igep2_vmmc1_supply,
 };
 
-/* VMMC2 for OMAP VDD_MMC2 (i/o) and MMC2 WIFI */
-static struct regulator_init_data igep2_vmmc2 = {
-       .constraints = {
-               .min_uV                 = 1850000,
-               .max_uV                 = 3150000,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
-                                       | REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep2_vmmc2_supply,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
        },
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
        {
                .mmc            = 2,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
        },
+#endif
        {}      /* Terminator */
 };
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep2_gpio_leds[] = {
+       [0] = {
+               .name                   = "gpio-led:red:d0",
+               .gpio                   = IGEP2_GPIO_LED0_RED,
+               .default_trigger        = "default-off"
+       },
+       [1] = {
+               .name                   = "gpio-led:green:d0",
+               .gpio                   = IGEP2_GPIO_LED0_GREEN,
+               .default_trigger        = "default-off",
+       },
+       [2] = {
+               .name                   = "gpio-led:red:d1",
+               .gpio                   = IGEP2_GPIO_LED1_RED,
+               .default_trigger        = "default-off",
+       },
+       [3] = {
+               .name                   = "gpio-led:green:d1",
+               .default_trigger        = "heartbeat",
+               .gpio                   = -EINVAL, /* gets replaced */
+       },
+};
+
+static struct gpio_led_platform_data igep2_led_pdata = {
+       .leds           = igep2_gpio_leds,
+       .num_leds       = ARRAY_SIZE(igep2_gpio_leds),
+};
+
+static struct platform_device igep2_led_device = {
+        .name   = "leds-gpio",
+        .id     = -1,
+        .dev    = {
+                .platform_data  =  &igep2_led_pdata,
+       },
+};
+
+static void __init igep2_leds_init(void)
+{
+       platform_device_register(&igep2_led_device);
+}
+
+#else
+static inline void igep2_leds_init(void)
+{
+       if ((gpio_request(IGEP2_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED0_RED, 0);
+               gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+
+       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
+               gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+       if ((gpio_request(IGEP2_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+           (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
+               gpio_export(IGEP2_GPIO_LED1_RED, 0);
+               gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+
+}
+#endif
+
 static int igep2_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
@@ -268,20 +372,48 @@ static int igep2_twl_gpio_setup(struct device *dev,
        mmc[0].gpio_cd = gpio + 0;
        omap2_hsmmc_init(mmc);
 
-       /* link regulators to MMC adapters ... we "know" the
+       /*
+        * link regulators to MMC adapters ... we "know" the
         * regulators will be set up only *after* we return.
-       */
+        */
        igep2_vmmc1_supply.dev = mmc[0].dev;
-       igep2_vmmc2_supply.dev = mmc[1].dev;
+
+       /*
+        * REVISIT: need ehci-omap hooks for external VBUS
+        * power switch and overcurrent detect
+        */
+       if ((gpio_request(gpio + 1, "GPIO_EHCI_NOC") < 0) ||
+           (gpio_direction_input(gpio + 1) < 0))
+               pr_err("IGEP2: Could not obtain gpio for EHCI NOC");
+
+       /*
+        * TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN
+        * (out, active low)
+        */
+       if ((gpio_request(gpio + TWL4030_GPIO_MAX, "GPIO_USBH_CPEN") < 0) ||
+           (gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0) < 0))
+               pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
+
+       /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+       if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+           && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+               gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+               gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+       } else
+               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+       igep2_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
 
        return 0;
 };
 
-static struct twl4030_gpio_platform_data igep2_gpio_data = {
+static struct twl4030_gpio_platform_data igep2_twl4030_gpio_pdata = {
        .gpio_base      = OMAP_MAX_GPIO_LINES,
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
-       .use_leds       = false,
+       .use_leds       = true,
        .setup          = igep2_twl_gpio_setup,
 };
 
@@ -355,47 +487,6 @@ static void __init igep2_display_init(void)
                pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
 }
 
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led igep2_gpio_leds[] = {
-       {
-               .name = "led0:red",
-               .gpio = IGEP2_GPIO_LED0_RED,
-       },
-       {
-               .name = "led0:green",
-               .default_trigger = "heartbeat",
-               .gpio = IGEP2_GPIO_LED0_GREEN,
-       },
-       {
-               .name = "led1:red",
-               .gpio = IGEP2_GPIO_LED1_RED,
-       },
-};
-
-static struct gpio_led_platform_data igep2_led_pdata = {
-       .leds           = igep2_gpio_leds,
-       .num_leds       = ARRAY_SIZE(igep2_gpio_leds),
-};
-
-static struct platform_device igep2_led_device = {
-        .name   = "leds-gpio",
-        .id     = -1,
-        .dev    = {
-                .platform_data  =  &igep2_led_pdata,
-       },
-};
-
-static void __init igep2_init_led(void)
-{
-       platform_device_register(&igep2_led_device);
-}
-
-#else
-static inline void igep2_init_led(void) {}
-#endif
-
 static struct platform_device *igep2_devices[] __initdata = {
        &igep2_dss_device,
 };
@@ -425,14 +516,13 @@ static struct twl4030_platform_data igep2_twldata = {
        /* platform_data for children goes here */
        .usb            = &igep2_usb_data,
        .codec          = &igep2_codec_data,
-       .gpio           = &igep2_gpio_data,
+       .gpio           = &igep2_twl4030_gpio_pdata,
        .vmmc1          = &igep2_vmmc1,
-       .vmmc2          = &igep2_vmmc2,
        .vpll2          = &igep2_vpll2,
 
 };
 
-static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata igep2_i2c1_boardinfo[] = {
        {
                I2C_BOARD_INFO("twl4030", 0x48),
                .flags          = I2C_CLIENT_WAKE,
@@ -441,14 +531,29 @@ static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
        },
 };
 
-static int __init igep2_i2c_init(void)
+static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("eeprom", 0x50),
+       },
+};
+
+static void __init igep2_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, igep2_i2c_boardinfo,
-                       ARRAY_SIZE(igep2_i2c_boardinfo));
-       /* Bus 3 is attached to the DVI port where devices like the pico DLP
-        * projector don't work reliably with 400kHz */
-       omap_register_i2c_bus(3, 100, NULL, 0);
-       return 0;
+       int ret;
+
+       ret = omap_register_i2c_bus(1, 2600, igep2_i2c1_boardinfo,
+               ARRAY_SIZE(igep2_i2c1_boardinfo));
+       if (ret)
+               pr_warning("IGEP2: Could not register I2C1 bus (%d)\n", ret);
+
+       /*
+        * Bus 3 is attached to the DVI port where devices like the pico DLP
+        * projector don't work reliably with 400kHz
+        */
+       ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
+               ARRAY_SIZE(igep2_i2c3_boardinfo));
+       if (ret)
+               pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
 }
 
 static struct omap_musb_board_data musb_board_data = {
@@ -476,9 +581,57 @@ static struct omap_board_mux board_mux[] __initdata = {
 #define board_mux      NULL
 #endif
 
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep2_wlan_bt_init(void)
+{
+       unsigned npd, wreset, btreset;
+
+       /* GPIO's for WLAN-BT combo depends on hardware revision */
+       if (hwrev == IGEP2_BOARD_HWREV_B) {
+               npd = IGEP2_RB_GPIO_WIFI_NPD;
+               wreset = IGEP2_RB_GPIO_WIFI_NRESET;
+               btreset = IGEP2_RB_GPIO_BT_NRESET;
+       } else if (hwrev == IGEP2_BOARD_HWREV_C) {
+               npd = IGEP2_RC_GPIO_WIFI_NPD;
+               wreset = IGEP2_RC_GPIO_WIFI_NRESET;
+               btreset = IGEP2_RC_GPIO_BT_NRESET;
+       } else
+               return;
+
+       /* Set GPIO's for  WLAN-BT combo module */
+       if ((gpio_request(npd, "GPIO_WIFI_NPD") == 0) &&
+           (gpio_direction_output(npd, 1) == 0)) {
+               gpio_export(npd, 0);
+       } else
+               pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+       if ((gpio_request(wreset, "GPIO_WIFI_NRESET") == 0) &&
+           (gpio_direction_output(wreset, 1) == 0)) {
+               gpio_export(wreset, 0);
+               gpio_set_value(wreset, 0);
+               udelay(10);
+               gpio_set_value(wreset, 1);
+       } else
+               pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+       if ((gpio_request(btreset, "GPIO_BT_NRESET") == 0) &&
+           (gpio_direction_output(btreset, 1) == 0)) {
+               gpio_export(btreset, 0);
+       } else
+               pr_warning("IGEP2: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+static inline void __init igep2_wlan_bt_init(void) { }
+#endif
+
 static void __init igep2_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+       /* Get IGEP2 hardware revision */
+       igep2_get_revision();
+       /* Register I2C busses and drivers */
        igep2_i2c_init();
        platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
        omap_serial_init();
@@ -486,50 +639,16 @@ static void __init igep2_init(void)
        usb_ehci_init(&ehci_pdata);
 
        igep2_flash_init();
-       igep2_init_led();
+       igep2_leds_init();
        igep2_display_init();
        igep2_init_smsc911x();
 
-       /* GPIO userspace leds */
-#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
-       if ((gpio_request(IGEP2_GPIO_LED0_RED, "led0:red") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
-               gpio_export(IGEP2_GPIO_LED0_RED, 0);
-               gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
-       } else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
-
-       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "led0:green") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
-               gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
-               gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
-       } else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
-
-       if ((gpio_request(IGEP2_GPIO_LED1_RED, "led1:red") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
-               gpio_export(IGEP2_GPIO_LED1_RED, 0);
-               gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
-       } else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
-#endif
-
-       /* GPIO W-LAN + Bluetooth combo module */
-       if ((gpio_request(IGEP2_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_WIFI_NPD, 1) == 0)) {
-               gpio_export(IGEP2_GPIO_WIFI_NPD, 0);
-/*             gpio_set_value(IGEP2_GPIO_WIFI_NPD, 0); */
-       } else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NPD\n");
+       /*
+        * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+        * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+        */
+       igep2_wlan_bt_init();
 
-       if ((gpio_request(IGEP2_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_WIFI_NRESET, 1) == 0)) {
-               gpio_export(IGEP2_GPIO_WIFI_NRESET, 0);
-               gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 0);
-               udelay(10);
-               gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 1);
-       } else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NRESET\n");
 }
 
 MACHINE_START(IGEP0020, "IGEP v2 board")
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
new file mode 100644 (file)
index 0000000..22b0b25
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2010 - ISEE 2007 SL
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+#include <plat/onenand.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "sdram-numonyx-m65kxxxxam.h"
+
+#define IGEP3_GPIO_LED0_GREEN  54
+#define IGEP3_GPIO_LED0_RED    53
+#define IGEP3_GPIO_LED1_RED    16
+
+#define IGEP3_GPIO_WIFI_NPD    138
+#define IGEP3_GPIO_WIFI_NRESET 139
+#define IGEP3_GPIO_BT_NRESET   137
+
+#define IGEP3_GPIO_USBH_NRESET  115
+
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+       defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+#define ONENAND_MAP             0x20000000
+
+/*
+ * x2 Flash built-in COMBO POP MEMORY
+ * Since the device is equipped with two DataRAMs, and two-plane NAND
+ * Flash memory array, these two component enables simultaneous program
+ * of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+ * while Plane2 has only odd blocks such as block1, block3, block5.
+ * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
+ */
+
+static struct mtd_partition igep3_onenand_partitions[] = {
+       {
+               .name           = "X-Loader",
+               .offset         = 0,
+               .size           = 2 * (64*(2*2048))
+       },
+       {
+               .name           = "U-Boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 6 * (64*(2*2048)),
+       },
+       {
+               .name           = "Environment",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 2 * (64*(2*2048)),
+       },
+       {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 12 * (64*(2*2048)),
+       },
+       {
+               .name           = "File System",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data igep3_onenand_pdata = {
+       .parts = igep3_onenand_partitions,
+       .nr_parts = ARRAY_SIZE(igep3_onenand_partitions),
+       .onenand_setup = NULL,
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device igep3_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &igep3_onenand_pdata,
+       },
+};
+
+void __init igep3_flash_init(void)
+{
+       u8 cs = 0;
+       u8 onenandcs = GPMC_CS_NUM + 1;
+
+       for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+               u32 ret;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               /* Check if NAND/oneNAND is configured */
+               if ((ret & 0xC00) == 0x800)
+                       /* NAND found */
+                       pr_err("IGEP3: Unsupported NAND found\n");
+               else {
+                       ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+                       if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+                               /* OneNAND found */
+                               onenandcs = cs;
+               }
+       }
+
+       if (onenandcs > GPMC_CS_NUM) {
+               pr_err("IGEP3: Unable to find configuration in GPMC\n");
+               return;
+       }
+
+       igep3_onenand_pdata.cs = onenandcs;
+
+       if (platform_device_register(&igep3_onenand_device) < 0)
+               pr_err("IGEP3: Unable to register OneNAND device\n");
+}
+
+#else
+void __init igep3_flash_init(void) {}
+#endif
+
+static struct regulator_consumer_supply igep3_vmmc1_supply = {
+       .supply         = "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data igep3_vmmc1 = {
+       .constraints = {
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &igep3_vmmc1_supply,
+};
+
+static struct omap2_hsmmc_info mmc[] = {
+       [0] = {
+               .mmc            = 1,
+               .caps           = MMC_CAP_4_BIT_DATA,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+       [1] = {
+               .mmc            = 2,
+               .caps           = MMC_CAP_4_BIT_DATA,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+#endif
+       {}      /* Terminator */
+};
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep3_gpio_leds[] = {
+       [0] = {
+               .name                   = "gpio-led:red:d0",
+               .gpio                   = IGEP3_GPIO_LED0_RED,
+               .default_trigger        = "default-off"
+       },
+       [1] = {
+               .name                   = "gpio-led:green:d0",
+               .gpio                   = IGEP3_GPIO_LED0_GREEN,
+               .default_trigger        = "default-off",
+       },
+       [2] = {
+               .name                   = "gpio-led:red:d1",
+               .gpio                   = IGEP3_GPIO_LED1_RED,
+               .default_trigger        = "default-off",
+       },
+       [3] = {
+               .name                   = "gpio-led:green:d1",
+               .default_trigger        = "heartbeat",
+               .gpio                   = -EINVAL, /* gets replaced */
+       },
+};
+
+static struct gpio_led_platform_data igep3_led_pdata = {
+       .leds           = igep3_gpio_leds,
+       .num_leds       = ARRAY_SIZE(igep3_gpio_leds),
+};
+
+static struct platform_device igep3_led_device = {
+        .name   = "leds-gpio",
+        .id     = -1,
+        .dev    = {
+                .platform_data = &igep3_led_pdata,
+       },
+};
+
+static void __init igep3_leds_init(void)
+{
+       platform_device_register(&igep3_led_device);
+}
+
+#else
+static inline void igep3_leds_init(void)
+{
+       if ((gpio_request(IGEP3_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+           (gpio_direction_output(IGEP3_GPIO_LED0_RED, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_LED0_RED, 0);
+               gpio_set_value(IGEP3_GPIO_LED0_RED, 1);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_RED\n");
+
+       if ((gpio_request(IGEP3_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+           (gpio_direction_output(IGEP3_GPIO_LED0_GREEN, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_LED0_GREEN, 0);
+               gpio_set_value(IGEP3_GPIO_LED0_GREEN, 1);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+       if ((gpio_request(IGEP3_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+               (gpio_direction_output(IGEP3_GPIO_LED1_RED, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_LED1_RED, 0);
+               gpio_set_value(IGEP3_GPIO_LED1_RED, 1);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_RED\n");
+}
+#endif
+
+static int igep3_twl4030_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+       mmc[0].gpio_cd = gpio + 0;
+       omap2_hsmmc_init(mmc);
+
+       /*
+        * link regulators to MMC adapters ... we "know" the
+        * regulators will be set up only *after* we return.
+        */
+       igep3_vmmc1_supply.dev = mmc[0].dev;
+
+       /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+       if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+           && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+               gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+               gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+       igep3_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
+
+       return 0;
+};
+
+static struct twl4030_gpio_platform_data igep3_twl4030_gpio_pdata = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .use_leds       = true,
+       .setup          = igep3_twl4030_gpio_setup,
+};
+
+static struct twl4030_usb_data igep3_twl4030_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static void __init igep3_init_irq(void)
+{
+       omap2_init_common_hw(m65kxxxxam_sdrc_params, m65kxxxxam_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct twl4030_platform_data igep3_twl4030_pdata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .usb            = &igep3_twl4030_usb_data,
+       .gpio           = &igep3_twl4030_gpio_pdata,
+       .vmmc1          = &igep3_vmmc1,
+};
+
+static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags          = I2C_CLIENT_WAKE,
+               .irq            = INT_34XX_SYS_NIRQ,
+               .platform_data  = &igep3_twl4030_pdata,
+       },
+};
+
+static int __init igep3_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, igep3_i2c_boardinfo,
+                       ARRAY_SIZE(igep3_i2c_boardinfo));
+
+       return 0;
+}
+
+static struct omap_musb_board_data musb_board_data = {
+       .interface_type = MUSB_INTERFACE_ULPI,
+       .mode           = MUSB_OTG,
+       .power          = 100,
+};
+
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep3_wifi_bt_init(void)
+{
+       /* Configure MUX values for W-LAN + Bluetooth GPIO's */
+       omap_mux_init_gpio(IGEP3_GPIO_WIFI_NPD, OMAP_PIN_OUTPUT);
+       omap_mux_init_gpio(IGEP3_GPIO_WIFI_NRESET, OMAP_PIN_OUTPUT);
+       omap_mux_init_gpio(IGEP3_GPIO_BT_NRESET, OMAP_PIN_OUTPUT);
+
+       /* Set GPIO's for  W-LAN + Bluetooth combo module */
+       if ((gpio_request(IGEP3_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
+           (gpio_direction_output(IGEP3_GPIO_WIFI_NPD, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_WIFI_NPD, 0);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+       if ((gpio_request(IGEP3_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
+           (gpio_direction_output(IGEP3_GPIO_WIFI_NRESET, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_WIFI_NRESET, 0);
+               gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 0);
+               udelay(10);
+               gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 1);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+       if ((gpio_request(IGEP3_GPIO_BT_NRESET, "GPIO_BT_NRESET") == 0) &&
+           (gpio_direction_output(IGEP3_GPIO_BT_NRESET, 1) == 0)) {
+               gpio_export(IGEP3_GPIO_BT_NRESET, 0);
+       } else
+               pr_warning("IGEP3: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+void __init igep3_wifi_bt_init(void) {}
+#endif
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+       { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux      NULL
+#endif
+
+static void __init igep3_init(void)
+{
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+       /* Register I2C busses and drivers */
+       igep3_i2c_init();
+
+       omap_serial_init();
+       usb_musb_init(&musb_board_data);
+
+       igep3_flash_init();
+       igep3_leds_init();
+
+       /*
+        * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+        * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+        */
+       igep3_wifi_bt_init();
+
+}
+
+MACHINE_START(IGEP0030, "IGEP OMAP3 module")
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_map_io,
+       .init_irq       = igep3_init_irq,
+       .init_machine   = igep3_init,
+       .timer          = &omap_timer,
+MACHINE_END
index f28fd77bceb322f476b142f5cb5496b6a9dcf2db..001fd9713f391df3517f333dc1c6d55d65b8a9ba 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/board-zoom.h>
 
 #include <asm/delay.h>
-#include <plat/control.h>
 #include <plat/usb.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "hsmmc.h"
+#include "control.h"
 
 #define LDP_SMSC911X_CS                1
 #define LDP_SMSC911X_GPIO      152
@@ -82,7 +84,7 @@ static struct platform_device ldp_smsc911x_device = {
        },
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_1),
        KEY(1, 0, KEY_2),
        KEY(2, 0, KEY_3),
@@ -362,7 +364,7 @@ static int __init omap_i2c_init(void)
 static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
        },
index 3f796687350771fe4334fc8ee0646f0405079e98..e823c7042ab31271145959530454b05dfb7830eb 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/usb/musb.h>
+#include <sound/tlv320aic3x.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -383,15 +384,6 @@ static void n8x0_mmc_callback(void *data, u8 card_mask)
        omap_mmc_notify_cover_event(mmc_device, index, *openp);
 }
 
-void n8x0_mmc_slot1_cover_handler(void *arg, int closed_state)
-{
-       if (mmc_device == NULL)
-               return;
-
-       slot1_cover_open = !closed_state;
-       omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
-}
-
 static int n8x0_mmc_late_init(struct device *dev)
 {
        int r, bit, *openp;
@@ -511,7 +503,7 @@ static struct omap_mmc_platform_data mmc1_data = {
 
 static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
 
-void __init n8x0_mmc_init(void)
+static void __init n8x0_mmc_init(void)
 
 {
        int err;
@@ -560,11 +552,6 @@ void __init n8x0_mmc_init(void)
 void __init n8x0_mmc_init(void)
 {
 }
-
-void n8x0_mmc_slot1_cover_handler(void *arg, int state)
-{
-}
-
 #endif /* CONFIG_MMC_OMAP */
 
 #ifdef CONFIG_MENELAUS
@@ -614,29 +601,35 @@ static int n8x0_menelaus_late_init(struct device *dev)
        return 0;
 }
 
-static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] = {
+#else
+static int n8x0_menelaus_late_init(struct device *dev)
+{
+       return 0;
+}
+#endif
+
+static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+       .late_init = n8x0_menelaus_late_init,
+};
+
+static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = {
        {
                I2C_BOARD_INFO("menelaus", 0x72),
                .irq = INT_24XX_SYS_NIRQ,
+               .platform_data = &n8x0_menelaus_platform_data,
        },
 };
 
-static struct menelaus_platform_data n8x0_menelaus_platform_data = {
-       .late_init = n8x0_menelaus_late_init,
+static struct aic3x_pdata n810_aic33_data __initdata = {
+       .gpio_reset = 118,
 };
 
-static void __init n8x0_menelaus_init(void)
-{
-       n8x0_i2c_board_info_1[0].platform_data = &n8x0_menelaus_platform_data;
-       omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
-                             ARRAY_SIZE(n8x0_i2c_board_info_1));
-}
-
-#else
-static inline void __init n8x0_menelaus_init(void)
-{
-}
-#endif
+static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {
+       {
+               I2C_BOARD_INFO("tlv320aic3x", 0x18),
+               .platform_data = &n810_aic33_data,
+       },
+};
 
 static void __init n8x0_map_io(void)
 {
@@ -653,6 +646,11 @@ static void __init n8x0_init_irq(void)
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       /* I2S codec port pins for McBSP block */
+       OMAP2420_MUX(EAC_AC_SCLK, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+       OMAP2420_MUX(EAC_AC_FS, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+       OMAP2420_MUX(EAC_AC_DIN, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+       OMAP2420_MUX(EAC_AC_DOUT, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -665,9 +663,14 @@ static void __init n8x0_init_machine(void)
        /* FIXME: add n810 spi devices */
        spi_register_board_info(n800_spi_board_info,
                                ARRAY_SIZE(n800_spi_board_info));
+       omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
+                             ARRAY_SIZE(n8x0_i2c_board_info_1));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       if (machine_is_nokia_n810())
+               i2c_register_board_info(2, n810_i2c_board_info_2,
+                                       ARRAY_SIZE(n810_i2c_board_info_2));
 
        omap_serial_init();
-       n8x0_menelaus_init();
        n8x0_onenand_init();
        n8x0_mmc_init();
        n8x0_usb_init();
index 9d9f5b881ee872137407901b3e5300921bc0cf0c..14f42240ae792bf01fcd289d60d441d9d55eb328 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #define NAND_BLOCK_SIZE                SZ_128K
 
+/*
+ * OMAP3 Beagle revision
+ * Run time detection of Beagle revision is done by reading GPIO.
+ * GPIO ID -
+ *     AXBX    = GPIO173, GPIO172, GPIO171: 1 1 1
+ *     C1_3    = GPIO173, GPIO172, GPIO171: 1 1 0
+ *     C4      = GPIO173, GPIO172, GPIO171: 1 0 1
+ *     XM      = GPIO173, GPIO172, GPIO171: 0 0 0
+ */
+enum {
+       OMAP3BEAGLE_BOARD_UNKN = 0,
+       OMAP3BEAGLE_BOARD_AXBX,
+       OMAP3BEAGLE_BOARD_C1_3,
+       OMAP3BEAGLE_BOARD_C4,
+       OMAP3BEAGLE_BOARD_XM,
+};
+
+static u8 omap3_beagle_version;
+
+static u8 omap3_beagle_get_rev(void)
+{
+       return omap3_beagle_version;
+}
+
+static void __init omap3_beagle_init_rev(void)
+{
+       int ret;
+       u16 beagle_rev = 0;
+
+       omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
+
+       ret = gpio_request(171, "rev_id_0");
+       if (ret < 0)
+               goto fail0;
+
+       ret = gpio_request(172, "rev_id_1");
+       if (ret < 0)
+               goto fail1;
+
+       ret = gpio_request(173, "rev_id_2");
+       if (ret < 0)
+               goto fail2;
+
+       gpio_direction_input(171);
+       gpio_direction_input(172);
+       gpio_direction_input(173);
+
+       beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
+                       | (gpio_get_value(173) << 2);
+
+       switch (beagle_rev) {
+       case 7:
+               printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX;
+               break;
+       case 6:
+               printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3;
+               break;
+       case 5:
+               printk(KERN_INFO "OMAP3 Beagle Rev: C4\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
+               break;
+       case 0:
+               printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+               break;
+       default:
+               printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+       }
+
+       return;
+
+fail2:
+       gpio_free(172);
+fail1:
+       gpio_free(171);
+fail0:
+       printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+       omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+
+       return;
+}
+
 static struct mtd_partition omap3beagle_nand_partitions[] = {
        /* All the partition sizes are listed in terms of NAND block size */
        {
@@ -166,7 +254,7 @@ static void __init beagle_display_init(void)
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 29,
        },
        {}      /* Terminator */
@@ -185,7 +273,10 @@ static struct gpio_led gpio_leds[];
 static int beagle_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
-       if (system_rev >= 0x20 && system_rev <= 0x34301000) {
+       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+               mmc[0].gpio_wp = -EINVAL;
+       } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+               (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
                omap_mux_init_gpio(23, OMAP_PIN_INPUT);
                mmc[0].gpio_wp = 23;
        } else {
@@ -322,13 +413,19 @@ static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
        },
 };
 
+static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+       {
+               I2C_BOARD_INFO("eeprom", 0x50),
+       },
+};
+
 static int __init omap3_beagle_i2c_init(void)
 {
        omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
                        ARRAY_SIZE(beagle_i2c_boardinfo));
        /* Bus 3 is attached to the DVI port where devices like the pico DLP
         * projector don't work reliably with 400kHz */
-       omap_register_i2c_bus(3, 100, NULL, 0);
+       omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
        return 0;
 }
 
@@ -464,6 +561,7 @@ static struct omap_musb_board_data musb_board_data = {
 static void __init omap3_beagle_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap3_beagle_init_rev();
        omap3_beagle_i2c_init();
        platform_add_devices(omap3_beagle_devices,
                        ARRAY_SIZE(omap3_beagle_devices));
index 8936e4fba334796c2de6a68a96efe1330a0e2b15..b04365c6bb10895e4ebdf45fd5fa8465c722e518 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smsc911x.h>
 
 #include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -370,7 +371,7 @@ static struct regulator_init_data omap3evm_vsim = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = 63,
        },
@@ -446,7 +447,7 @@ static struct twl4030_usb_data omap3evm_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_LEFT),
        KEY(0, 1, KEY_DOWN),
        KEY(0, 2, KEY_ENTER),
@@ -584,7 +585,7 @@ static int ads7846_get_pendown_state(void)
        return !gpio_get_value(OMAP3_EVM_TS_GPIO);
 }
 
-struct ads7846_platform_data ads7846_config = {
+static struct ads7846_platform_data ads7846_config = {
        .x_max                  = 0x0fff,
        .y_max                  = 0x0fff,
        .x_plate_ohms           = 180,
@@ -603,7 +604,7 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
        .single_channel = 1,    /* 0: slave, 1: master */
 };
 
-struct spi_board_info omap3evm_spi_board_info[] = {
+static struct spi_board_info omap3evm_spi_board_info[] = {
        [0] = {
                .modalias               = "ads7846",
                .bus_num                = 1,
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
new file mode 100644 (file)
index 0000000..5f7d2c1
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3logic.c
+ *
+ * Copyright (C) 2010 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Copyright (C) 2010 Logic Product Development, Inc.
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * Modified from Beagle, EVM, and RX51
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
+
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc-smsc911x.h>
+#include <plat/gpmc.h>
+#include <plat/sdrc.h>
+
+#define OMAP3LOGIC_SMSC911X_CS                 1
+
+#define OMAP3530_LV_SOM_MMC_GPIO_CD            110
+#define OMAP3530_LV_SOM_MMC_GPIO_WP            126
+#define OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ      152
+
+#define OMAP3_TORPEDO_MMC_GPIO_CD              127
+#define OMAP3_TORPEDO_SMSC911X_GPIO_IRQ                129
+
+static struct regulator_consumer_supply omap3logic_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data omap3logic_vmmc1 = {
+       .constraints = {
+               .name                   = "VMMC1",
+               .min_uV                 = 1850000,
+               .max_uV                 = 3150000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &omap3logic_vmmc1_supply,
+};
+
+static struct twl4030_gpio_platform_data omap3logic_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),
+};
+
+static struct twl4030_platform_data omap3logic_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .gpio           = &omap3logic_gpio_data,
+       .vmmc1          = &omap3logic_vmmc1,
+};
+
+static struct i2c_board_info __initdata omap3logic_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &omap3logic_twldata,
+       },
+};
+
+static int __init omap3logic_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, omap3logic_i2c_boardinfo,
+                               ARRAY_SIZE(omap3logic_i2c_boardinfo));
+       return 0;
+}
+
+static struct omap2_hsmmc_info __initdata board_mmc_info[] = {
+       {
+               .name           = "external",
+               .mmc            = 1,
+               .caps           = MMC_CAP_4_BIT_DATA,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
+static void __init board_mmc_init(void)
+{
+       if (machine_is_omap3530_lv_som()) {
+               /* OMAP3530 LV SOM board */
+               board_mmc_info[0].gpio_cd = OMAP3530_LV_SOM_MMC_GPIO_CD;
+               board_mmc_info[0].gpio_wp = OMAP3530_LV_SOM_MMC_GPIO_WP;
+               omap_mux_init_signal("gpio_110", OMAP_PIN_OUTPUT);
+               omap_mux_init_signal("gpio_126", OMAP_PIN_OUTPUT);
+       } else if (machine_is_omap3_torpedo()) {
+               /* OMAP3 Torpedo board */
+               board_mmc_info[0].gpio_cd = OMAP3_TORPEDO_MMC_GPIO_CD;
+               omap_mux_init_signal("gpio_127", OMAP_PIN_OUTPUT);
+       } else {
+               /* unsupported board */
+               printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+               return;
+       }
+
+       omap2_hsmmc_init(board_mmc_info);
+       /* link regulators to MMC adapters */
+       omap3logic_vmmc1_supply.dev = board_mmc_info[0].dev;
+}
+
+static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
+       .cs             = OMAP3LOGIC_SMSC911X_CS,
+       .gpio_irq       = -EINVAL,
+       .gpio_reset     = -EINVAL,
+       .flags          = IORESOURCE_IRQ_LOWLEVEL,
+};
+
+/* TODO/FIXME (comment by Peter Barada, LogicPD):
+ * Fix the PBIAS voltage for Torpedo MMC1 pins that
+ * are used for other needs (IRQs, etc).            */
+static void omap3torpedo_fix_pbias_voltage(void)
+{
+       u16 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
+       u32 reg;
+
+       if (machine_is_omap3_torpedo())
+       {
+               /* Set the bias for the pin */
+               reg = omap_ctrl_readl(control_pbias_offset);
+
+               reg &= ~OMAP343X_PBIASLITEPWRDNZ1;
+               omap_ctrl_writel(reg, control_pbias_offset);
+
+               /* 100ms delay required for PBIAS configuration */
+               msleep(100);
+
+               reg |= OMAP343X_PBIASLITEVMODE1;
+               reg |= OMAP343X_PBIASLITEPWRDNZ1;
+               omap_ctrl_writel(reg | 0x300, control_pbias_offset);
+       }
+}
+
+static inline void __init board_smsc911x_init(void)
+{
+       if (machine_is_omap3530_lv_som()) {
+               /* OMAP3530 LV SOM board */
+               board_smsc911x_data.gpio_irq =
+                                       OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ;
+               omap_mux_init_signal("gpio_152", OMAP_PIN_INPUT);
+       } else if (machine_is_omap3_torpedo()) {
+               /* OMAP3 Torpedo board */
+               board_smsc911x_data.gpio_irq = OMAP3_TORPEDO_SMSC911X_GPIO_IRQ;
+               omap_mux_init_signal("gpio_129", OMAP_PIN_INPUT);
+       } else {
+               /* unsupported board */
+               printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+               return;
+       }
+
+       gpmc_smsc911x_init(&board_smsc911x_data);
+}
+
+static void __init omap3logic_init_irq(void)
+{
+       omap2_init_common_hw(NULL, NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+       { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux       NULL
+#endif
+
+static void __init omap3logic_init(void)
+{
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap3torpedo_fix_pbias_voltage();
+       omap3logic_i2c_init();
+       omap_serial_init();
+       board_mmc_init();
+       board_smsc911x_init();
+
+       /* Ensure SDRC pins are mux'd for self-refresh */
+       omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+       omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+}
+
+MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_map_io,
+       .init_irq       = omap3logic_init_irq,
+       .init_machine   = omap3logic_init,
+       .timer          = &omap_timer,
+MACHINE_END
+
+MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_map_io,
+       .init_irq       = omap3logic_init_irq,
+       .init_machine   = omap3logic_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 41d6f549070c55affca195e9fa218786d8cae676..89ed1be2d62e0d7214ef968e44d73170ebe35a22 100644 (file)
@@ -32,7 +32,9 @@
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/gpio_keys.h>
+#include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/regulator/fixed.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -276,14 +278,14 @@ static void pandora_wl1251_init_card(struct mmc_card *card)
 static struct omap2_hsmmc_info omap3pandora_mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = 126,
                .ext_clock      = 0,
        },
        {
                .mmc            = 2,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = 127,
                .ext_clock      = 1,
@@ -291,7 +293,7 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
        },
        {
                .mmc            = 3,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .init_card      = pandora_wl1251_init_card,
@@ -344,6 +346,9 @@ static struct regulator_consumer_supply pandora_vmmc1_supply =
 static struct regulator_consumer_supply pandora_vmmc2_supply =
        REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
 
+static struct regulator_consumer_supply pandora_vmmc3_supply =
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.2");
+
 static struct regulator_consumer_supply pandora_vdda_dac_supply =
        REGULATOR_SUPPLY("vdda_dac", "omapdss");
 
@@ -488,6 +493,33 @@ static struct regulator_init_data pandora_vsim = {
        .consumer_supplies      = &pandora_adac_supply,
 };
 
+/* Fixed regulator internal to Wifi module */
+static struct regulator_init_data pandora_vmmc3 = {
+       .constraints = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &pandora_vmmc3_supply,
+};
+
+static struct fixed_voltage_config pandora_vwlan = {
+       .supply_name            = "vwlan",
+       .microvolts             = 1800000, /* 1.8V */
+       .gpio                   = PANDORA_WIFI_NRESET_GPIO,
+       .startup_delay          = 50000, /* 50ms */
+       .enable_high            = 1,
+       .enabled_at_boot        = 0,
+       .init_data              = &pandora_vmmc3,
+};
+
+static struct platform_device pandora_vwlan_device = {
+       .name           = "reg-fixed-voltage",
+       .id             = 1,
+       .dev = {
+               .platform_data = &pandora_vwlan,
+       },
+};
+
 static struct twl4030_usb_data omap3pandora_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
@@ -501,6 +533,8 @@ static struct twl4030_codec_data omap3pandora_codec_data = {
        .audio = &omap3pandora_audio_data,
 };
 
+static struct twl4030_bci_platform_data pandora_bci_data;
+
 static struct twl4030_platform_data omap3pandora_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -516,6 +550,7 @@ static struct twl4030_platform_data omap3pandora_twldata = {
        .vaux4          = &pandora_vaux4,
        .vsim           = &pandora_vsim,
        .keypad         = &pandora_kp_data,
+       .bci            = &pandora_bci_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -644,19 +679,8 @@ static void pandora_wl1251_init(void)
        if (pandora_wl1251_pdata.irq < 0)
                goto fail_irq;
 
-       ret = gpio_request(PANDORA_WIFI_NRESET_GPIO, "wl1251 nreset");
-       if (ret < 0)
-               goto fail_irq;
-
-       /* start powered so that it probes with MMC subsystem */
-       ret = gpio_direction_output(PANDORA_WIFI_NRESET_GPIO, 1);
-       if (ret < 0)
-               goto fail_nreset;
-
        return;
 
-fail_nreset:
-       gpio_free(PANDORA_WIFI_NRESET_GPIO);
 fail_irq:
        gpio_free(PANDORA_WIFI_IRQ_GPIO);
 fail:
@@ -668,6 +692,7 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
        &pandora_keys_gpio,
        &pandora_dss_device,
        &pandora_wl1251_data,
+       &pandora_vwlan_device,
 };
 
 static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
index bc5ac83bd4cf19824a432b8135357999577a6431..f2527212541347afc144cc1c2df375304c6ce6a1 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -38,7 +39,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 #include <plat/display.h>
 
 #include <plat/mcspi.h>
@@ -52,6 +52,7 @@
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #define OMAP3STALKER_ETHR_START        0x2c000000
@@ -275,7 +276,7 @@ static struct regulator_init_data omap3stalker_vsim = {
 static struct omap2_hsmmc_info mmc[] = {
        {
         .mmc           = 1,
-        .wires         = 4,
+        .caps          = MMC_CAP_4_BIT_DATA,
         .gpio_cd       = -EINVAL,
         .gpio_wp       = 23,
         },
@@ -389,7 +390,7 @@ static struct twl4030_usb_data omap3stalker_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_LEFT),
        KEY(0, 1, KEY_DOWN),
        KEY(0, 2, KEY_ENTER),
@@ -564,7 +565,7 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
        .single_channel         = 1,    /* 0: slave, 1: master */
 };
 
-struct spi_board_info omap3stalker_spi_board_info[] = {
+static struct spi_board_info omap3stalker_spi_board_info[] = {
        [0] = {
               .modalias        = "ads7846",
               .bus_num         = 1,
index 0e99ce584dbfc518f68ec87c75af1a5e9e3562e1..41104bb8774cf3a42fa96996ae4376b4624449cf 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <plat/mcspi.h>
 #include <linux/spi/spi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #include <asm/setup.h>
 
@@ -61,7 +62,7 @@
 #define TB_BL_PWM_TIMER                9
 #define TB_KILL_POWER_GPIO     168
 
-unsigned long touchbook_revision;
+static unsigned long touchbook_revision;
 
 static struct mtd_partition omap3touchbook_nand_partitions[] = {
        /* All the partition sizes are listed in terms of NAND block size */
@@ -108,7 +109,7 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 29,
        },
        {}      /* Terminator */
index db69bcadf4c7400e60cba20659d73ddfaf893e49..702f2a63f2c1b891ca8afdd1bf6f34b6c9016699 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/usb/otg.h>
 #include <linux/i2c/twl.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+#include "timer-gp.h"
+
 #include "hsmmc.h"
+#include "control.h"
+
+#define GPIO_HUB_POWER         1
+#define GPIO_HUB_NRESET                62
+
+static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "pandaboard::status1",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 7,
+       },
+       {
+               .name                   = "pandaboard::status2",
+               .default_trigger        = "mmc0",
+               .gpio                   = 8,
+       },
+};
 
+static struct gpio_led_platform_data gpio_led_info = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_led_info,
+       },
+};
+
+static struct platform_device *panda_devices[] __initdata = {
+       &leds_gpio,
+};
 
 static void __init omap4_panda_init_irq(void)
 {
@@ -47,6 +81,56 @@ static void __init omap4_panda_init_irq(void)
        omap_gpio_init();
 }
 
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .phy_reset  = false,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[2]  = -EINVAL
+};
+
+static void __init omap4_ehci_init(void)
+{
+       int ret;
+
+
+       /* disable the power to the usb hub prior to init */
+       ret = gpio_request(GPIO_HUB_POWER, "hub_power");
+       if (ret) {
+               pr_err("Cannot request GPIO %d\n", GPIO_HUB_POWER);
+               goto error1;
+       }
+       gpio_export(GPIO_HUB_POWER, 0);
+       gpio_direction_output(GPIO_HUB_POWER, 0);
+       gpio_set_value(GPIO_HUB_POWER, 0);
+
+       /* reset phy+hub */
+       ret = gpio_request(GPIO_HUB_NRESET, "hub_nreset");
+       if (ret) {
+               pr_err("Cannot request GPIO %d\n", GPIO_HUB_NRESET);
+               goto error2;
+       }
+       gpio_export(GPIO_HUB_NRESET, 0);
+       gpio_direction_output(GPIO_HUB_NRESET, 0);
+       gpio_set_value(GPIO_HUB_NRESET, 0);
+       gpio_set_value(GPIO_HUB_NRESET, 1);
+
+       usb_ehci_init(&ehci_pdata);
+
+       /* enable power to hub */
+       gpio_set_value(GPIO_HUB_POWER, 1);
+       return;
+
+error2:
+       gpio_free(GPIO_HUB_POWER);
+error1:
+       pr_err("Unable to initialize EHCI power/reset\n");
+       return;
+
+}
+
 static struct omap_musb_board_data musb_board_data = {
        .interface_type         = MUSB_INTERFACE_UTMI,
        .mode                   = MUSB_PERIPHERAL,
@@ -56,7 +140,7 @@ static struct omap_musb_board_data musb_board_data = {
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = -EINVAL,
        },
        {}      /* Terminator */
@@ -67,10 +151,6 @@ static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
                .supply = "vmmc",
                .dev_name = "mmci-omap-hs.0",
        },
-       {
-               .supply = "vmmc",
-               .dev_name = "mmci-omap-hs.1",
-       },
 };
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
@@ -89,7 +169,14 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 {
-       struct omap_mmc_platform_data *pdata = dev->platform_data;
+       struct omap_mmc_platform_data *pdata;
+
+       /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+       if (!dev) {
+               pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
+               return;
+       }
+       pdata = dev->platform_data;
 
        pdata->init =   omap4_twl6030_hsmmc_late_init;
 }
@@ -156,7 +243,7 @@ static struct regulator_init_data omap4_panda_vmmc = {
                                        | REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 2,
+       .num_consumer_supplies  = 1,
        .consumer_supplies      = omap4_panda_vmmc_supply,
 };
 
@@ -274,13 +361,13 @@ static int __init omap4_panda_i2c_init(void)
 }
 static void __init omap4_panda_init(void)
 {
-       int status;
-
        omap4_panda_i2c_init();
+       platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
        omap_serial_init();
        omap4_twl6030_hsmmc_init(mmc);
        /* OMAP4 Panda uses internal transceiver so register nop transceiver */
        usb_nop_xceiv_register();
+       omap4_ehci_init();
        /* FIXME: allow multi-omap to boot until musb is updated for omap4 */
        if (!cpu_is_omap44xx())
                usb_musb_init(&musb_board_data);
index 5e528ca015a1a38b69a7b4cf89661c173e868497..7053bc0b46dbf4531387990a7d4019551533c693 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -303,13 +304,13 @@ static void __init overo_flash_init(void)
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
        },
        {
                .mmc            = 2,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .transceiver    = true,
index ce28a851dcd3f06f954ccd64a03e72c30e229854..3fec4d62a91adae012bff4a250a2eb7f2e11a56d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
 
 #include <plat/mcspi.h>
 #include <plat/board.h>
@@ -32,6 +33,8 @@
 #include <plat/onenand.h>
 #include <plat/gpmc-smc91x.h>
 
+#include <mach/board-rx51.h>
+
 #include <sound/tlv320aic3x.h>
 #include <sound/tpa6130a2-plat.h>
 
@@ -104,6 +107,10 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
        },
 };
 
+static struct platform_device rx51_charger_device = {
+       .name = "isp1704_charger",
+};
+
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 
 #define RX51_GPIO_CAMERA_LENS_COVER    110
@@ -184,7 +191,7 @@ static void __init rx51_add_gpio_keys(void)
 }
 #endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        /*
         * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
         * connected to the ground" matrix state.
@@ -302,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .name           = "external",
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .cover_only     = true,
                .gpio_cd        = 160,
                .gpio_wp        = -EINVAL,
@@ -311,7 +318,8 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .name           = "internal",
                .mmc            = 2,
-               .wires          = 8, /* See also rx51_mmc2_remux */
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+                                               /* See also rx51_mmc2_remux */
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .nonremovable   = true,
@@ -689,7 +697,6 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
 };
 
 
-
 static struct twl4030_platform_data rx51_twldata __initdata = {
        .irq_base               = TWL4030_IRQ_BASE,
        .irq_end                = TWL4030_IRQ_END,
@@ -710,10 +717,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
        .vio                    = &rx51_vio,
 };
 
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
-       .gpio_reset             = 60,
-};
-
 static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
        .id                     = TPA6130A2,
        .power_gpio             = 98,
@@ -728,6 +731,17 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
        },
 };
 
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+       .setup = &rx51_aic34_setup,
+       .gpio_reset = 60,
+};
+
 static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
        {
                I2C_BOARD_INFO("tlv320aic3x", 0x18),
@@ -909,5 +923,6 @@ void __init rx51_peripherals_init(void)
        spi_register_board_info(rx51_peripherals_spi_board_info,
                                ARRAY_SIZE(rx51_peripherals_spi_board_info));
        omap2_hsmmc_init(mmc);
+       platform_device_register(&rx51_charger_device);
 }
 
index f392844195d26d5b19619960dbc9a886173fccac..a43b2c5c838b0929ebd7429574ca5d3b332db5fa 100644 (file)
@@ -43,7 +43,7 @@ struct sdram_timings {
        u32 tWTR;
 };
 
-struct omap_sdrc_params rx51_sdrc_params[4];
+static struct omap_sdrc_params rx51_sdrc_params[4];
 
 static const struct sdram_timings rx51_timings[] = {
        {
index 5a1005ba9815541777641f6ed7b446273c123e59..85503fed4e132b6e08ee3fa9a6f6cf8ee1be3b8f 100644 (file)
@@ -20,6 +20,8 @@
 #include <plat/vram.h>
 #include <plat/mcspi.h>
 
+#include <mach/board-rx51.h>
+
 #include "mux.h"
 
 #define RX51_LCD_RESET_GPIO    90
index 1d7f827b04082b02870ddccca909e7c21eb2baab..007ebdc6c993eec5a8d73243a18a6be382557501 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <plat/gpmc.h>
 
+#include <mach/board-zoom.h>
+
 #define ZOOM_SMSC911X_CS       7
 #define ZOOM_SMSC911X_GPIO     158
 #define ZOOM_QUADUART_CS       3
index 189a6d1600b208ef448ea210139d2d3faa056e29..86c9b210295214c175638df2997745d2643cd447 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 #include <linux/wl12xx.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -26,6 +27,8 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 
+#include <mach/board-zoom.h>
+
 #include "mux.h"
 #include "hsmmc.h"
 
@@ -33,7 +36,7 @@
 #define OMAP_ZOOM_WLAN_IRQ_GPIO                (162)
 
 /* Zoom2 has Qwerty keyboard*/
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_E),
        KEY(0, 1, KEY_R),
        KEY(0, 2, KEY_T),
@@ -197,14 +200,14 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .name           = "external",
                .mmc            = 1,
-               .wires          = 4,
+               .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_wp        = -EINVAL,
                .power_saving   = true,
        },
        {
                .name           = "internal",
                .mmc            = 2,
-               .wires          = 8,
+               .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
                .nonremovable   = true,
@@ -238,6 +241,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
        return 0;
 }
 
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
 
 static int zoom_batt_table[] = {
 /* 0 C*/
@@ -307,6 +315,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
 
 static int __init omap_i2c_init(void)
 {
+       if (machine_is_omap_zoom2()) {
+               zoom_audio_data.ramp_delay_value = 3;   /* 161 ms */
+               zoom_audio_data.hs_extmute = 1;
+               zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+       }
        omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
                        ARRAY_SIZE(zoom_i2c_boardinfo));
        omap_register_i2c_bus(2, 400, NULL, 0);
@@ -336,4 +349,5 @@ void __init zoom_peripherals_init(void)
        platform_device_register(&omap_vwlan_device);
        usb_musb_init(&musb_board_data);
        enable_board_wakeup_source();
+       omap_serial_init();
 }
index 24bbd0def64ff4b3e6617dc01910c491a7b557c8..2992a9f3a5855f98b4f230935404d64095f3dfd2 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/i2c/twl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -23,6 +24,7 @@
 
 #include <mach/board-zoom.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 
@@ -34,41 +36,6 @@ static void __init omap_zoom2_init_irq(void)
        omap_gpio_init();
 }
 
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
-       .irq_line       = 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
-       .audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
-       .audio_mclk = 26000000,
-       .audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-
-       /* platform_data for children goes here */
-       .bci            = &zoom2_bci_data,
-       .madc           = &zoom2_madc_data,
-       .usb            = &zoom2_usb_data,
-       .gpio           = &zoom2_gpio_data,
-       .keypad         = &zoom2_kp_twl4030_data,
-       .codec          = &zoom2_codec_data,
-       .vmmc1          = &zoom2_vmmc1,
-       .vmmc2          = &zoom2_vmmc2,
-       .vsim           = &zoom2_vsim,
-
-};
-
-#endif
-
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
        /* WLAN IRQ - GPIO 162 */
index b2bb3ff971ac9c940a73d6f093350c45126cc6f8..5adde12c039542d0e27a20ef947abb3040fd5938 100644 (file)
@@ -22,6 +22,7 @@
 #include <plat/board.h>
 #include <plat/usb.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
 
index 605f531783a828703cdf18e88bb77e3cd3d5fbb3..b5babf5440e420c2dcf0edd009cfdf184c6c6c04 100644 (file)
@@ -395,7 +395,7 @@ void omap2_clk_disable_unused(struct clk *clk)
        if ((regval32 & (1 << clk->enable_bit)) == v)
                return;
 
-       printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
+       pr_debug("Disabling unused clock \"%s\"\n", clk->name);
        if (cpu_is_omap34xx()) {
                omap2_clk_enable(clk);
                omap2_clk_disable(clk);
index 5f2066a6ba7460343d9ed535167e6aec92acdaaf..21f856252ad86e3c95ac14ba75620a8385ce1676 100644 (file)
@@ -27,6 +27,7 @@
 #include "prm-regbits-24xx.h"
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define OMAP_CM_REGADDR                 OMAP2420_CM_REGADDR
 
@@ -89,6 +90,12 @@ static struct clk alt_ck = {         /* Typical 54M or 48M, may not exist */
        .clkdm_name     = "wkup_clkdm",
 };
 
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+       .name           = "mcbsp_clks",
+       .ops            = &clkops_null,
+};
+
 /*
  * Analog domain root source clocks
  */
@@ -1135,14 +1142,34 @@ static struct clk mcbsp1_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+       { .div = 1, .val = 0, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+       { .parent = &func_96m_ck,  .rates = common_mcbsp_96m_rates },
+       { .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
+       { .parent = NULL }
+};
+
 static struct clk mcbsp1_fck = {
        .name           = "mcbsp1_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_mask    = OMAP2_MCBSP1_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp2_ick = {
@@ -1159,10 +1186,14 @@ static struct clk mcbsp2_fck = {
        .name           = "mcbsp2_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_mask    = OMAP2_MCBSP2_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcspi1_ick = {
@@ -1721,6 +1752,9 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "osc_ck",       &osc_ck,        CK_242X),
        CLK(NULL,       "sys_ck",       &sys_ck,        CK_242X),
        CLK(NULL,       "alt_ck",       &alt_ck,        CK_242X),
+       CLK("omap-mcbsp.1",     "pad_fck",      &mcbsp_clks,    CK_242X),
+       CLK("omap-mcbsp.2",     "pad_fck",      &mcbsp_clks,    CK_242X),
+       CLK(NULL,       "mcbsp_clks",   &mcbsp_clks,    CK_242X),
        /* internal analog sources */
        CLK(NULL,       "dpll_ck",      &dpll_ck,       CK_242X),
        CLK(NULL,       "apll96_ck",    &apll96_ck,     CK_242X),
@@ -1728,6 +1762,8 @@ static struct omap_clk omap2420_clks[] = {
        /* internal prcm root sources */
        CLK(NULL,       "func_54m_ck",  &func_54m_ck,   CK_242X),
        CLK(NULL,       "core_ck",      &core_ck,       CK_242X),
+       CLK("omap-mcbsp.1",     "prcm_fck",     &func_96m_ck,   CK_242X),
+       CLK("omap-mcbsp.2",     "prcm_fck",     &func_96m_ck,   CK_242X),
        CLK(NULL,       "func_96m_ck",  &func_96m_ck,   CK_242X),
        CLK(NULL,       "func_48m_ck",  &func_48m_ck,   CK_242X),
        CLK(NULL,       "func_12m_ck",  &func_12m_ck,   CK_242X),
index 701a1716019ebbda3a973cbb1317a008e758ef58..e32afcbdfb88aabdfd69979d478e6f21cce491d0 100644 (file)
@@ -27,6 +27,7 @@
 #include "prm-regbits-24xx.h"
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define OMAP_CM_REGADDR                        OMAP2430_CM_REGADDR
 
@@ -89,6 +90,12 @@ static struct clk alt_ck = {         /* Typical 54M or 48M, may not exist */
        .clkdm_name     = "wkup_clkdm",
 };
 
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+       .name           = "mcbsp_clks",
+       .ops            = &clkops_null,
+};
+
 /*
  * Analog domain root source clocks
  */
@@ -1123,14 +1130,34 @@ static struct clk mcbsp1_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+       { .div = 1, .val = 0, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+       { .parent = &func_96m_ck,  .rates = common_mcbsp_96m_rates },
+       { .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
+       { .parent = NULL }
+};
+
 static struct clk mcbsp1_fck = {
        .name           = "mcbsp1_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_mask    = OMAP2_MCBSP1_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp2_ick = {
@@ -1147,10 +1174,14 @@ static struct clk mcbsp2_fck = {
        .name           = "mcbsp2_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_mask    = OMAP2_MCBSP2_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp3_ick = {
@@ -1167,10 +1198,14 @@ static struct clk mcbsp3_fck = {
        .name           = "mcbsp3_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP3_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+       .clksel_mask    = OMAP2_MCBSP3_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp4_ick = {
@@ -1187,10 +1222,14 @@ static struct clk mcbsp4_fck = {
        .name           = "mcbsp4_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP4_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+       .clksel_mask    = OMAP2_MCBSP4_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp5_ick = {
@@ -1207,10 +1246,14 @@ static struct clk mcbsp5_fck = {
        .name           = "mcbsp5_fck",
        .ops            = &clkops_omap2_dflt_wait,
        .parent         = &func_96m_ck,
+       .init           = &omap2_init_clksel_parent,
        .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP5_SHIFT,
-       .recalc         = &followparent_recalc,
+       .clksel_reg     = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+       .clksel_mask    = OMAP2_MCBSP5_CLKS_MASK,
+       .clksel         = mcbsp_fck_clksel,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk mcspi1_ick = {
@@ -1808,6 +1851,12 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "osc_ck",       &osc_ck,        CK_243X),
        CLK(NULL,       "sys_ck",       &sys_ck,        CK_243X),
        CLK(NULL,       "alt_ck",       &alt_ck,        CK_243X),
+       CLK("omap-mcbsp.1",     "pad_fck",      &mcbsp_clks,    CK_243X),
+       CLK("omap-mcbsp.2",     "pad_fck",      &mcbsp_clks,    CK_243X),
+       CLK("omap-mcbsp.3",     "pad_fck",      &mcbsp_clks,    CK_243X),
+       CLK("omap-mcbsp.4",     "pad_fck",      &mcbsp_clks,    CK_243X),
+       CLK("omap-mcbsp.5",     "pad_fck",      &mcbsp_clks,    CK_243X),
+       CLK(NULL,       "mcbsp_clks",   &mcbsp_clks,    CK_243X),
        /* internal analog sources */
        CLK(NULL,       "dpll_ck",      &dpll_ck,       CK_243X),
        CLK(NULL,       "apll96_ck",    &apll96_ck,     CK_243X),
@@ -1815,6 +1864,11 @@ static struct omap_clk omap2430_clks[] = {
        /* internal prcm root sources */
        CLK(NULL,       "func_54m_ck",  &func_54m_ck,   CK_243X),
        CLK(NULL,       "core_ck",      &core_ck,       CK_243X),
+       CLK("omap-mcbsp.1",     "prcm_fck",     &func_96m_ck,   CK_243X),
+       CLK("omap-mcbsp.2",     "prcm_fck",     &func_96m_ck,   CK_243X),
+       CLK("omap-mcbsp.3",     "prcm_fck",     &func_96m_ck,   CK_243X),
+       CLK("omap-mcbsp.4",     "prcm_fck",     &func_96m_ck,   CK_243X),
+       CLK("omap-mcbsp.5",     "prcm_fck",     &func_96m_ck,   CK_243X),
        CLK(NULL,       "func_96m_ck",  &func_96m_ck,   CK_243X),
        CLK(NULL,       "func_48m_ck",  &func_48m_ck,   CK_243X),
        CLK(NULL,       "func_12m_ck",  &func_12m_ck,   CK_243X),
index c73906d1745833cb0d44511404439d808a9ab556..d85ecd5aebfd1d64358f4f91789b65c542df9c43 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/list.h>
 
-#include <plat/control.h>
 #include <plat/clkdev_omap.h>
 
 #include "clock.h"
@@ -33,6 +32,7 @@
 #include "cm-regbits-34xx.h"
 #include "prm.h"
 #include "prm-regbits-34xx.h"
+#include "control.h"
 
 /*
  * clocks
@@ -2465,6 +2465,16 @@ static struct clk uart3_fck = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk uart4_fck = {
+       .name           = "uart4_fck",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &per_48m_fck,
+       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_bit     = OMAP3630_EN_UART4_SHIFT,
+       .clkdm_name     = "per_clkdm",
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpt2_fck = {
        .name           = "gpt2_fck",
        .ops            = &clkops_omap2_dflt_wait,
@@ -2715,6 +2725,16 @@ static struct clk uart3_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk uart4_ick = {
+       .name           = "uart4_ick",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &per_l4_ick,
+       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .enable_bit     = OMAP3630_EN_UART4_SHIFT,
+       .clkdm_name     = "per_clkdm",
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpt9_ick = {
        .name           = "gpt9_ick",
        .ops            = &clkops_omap2_dflt_wait,
@@ -3188,6 +3208,11 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "osc_sys_ck",   &osc_sys_ck,    CK_3XXX),
        CLK(NULL,       "sys_ck",       &sys_ck,        CK_3XXX),
        CLK(NULL,       "sys_altclk",   &sys_altclk,    CK_3XXX),
+       CLK("omap-mcbsp.1",     "pad_fck",      &mcbsp_clks,    CK_3XXX),
+       CLK("omap-mcbsp.2",     "pad_fck",      &mcbsp_clks,    CK_3XXX),
+       CLK("omap-mcbsp.3",     "pad_fck",      &mcbsp_clks,    CK_3XXX),
+       CLK("omap-mcbsp.4",     "pad_fck",      &mcbsp_clks,    CK_3XXX),
+       CLK("omap-mcbsp.5",     "pad_fck",      &mcbsp_clks,    CK_3XXX),
        CLK(NULL,       "mcbsp_clks",   &mcbsp_clks,    CK_3XXX),
        CLK(NULL,       "sys_clkout1",  &sys_clkout1,   CK_3XXX),
        CLK(NULL,       "dpll1_ck",     &dpll1_ck,      CK_3XXX),
@@ -3253,6 +3278,8 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "cpefuse_fck",  &cpefuse_fck,   CK_3430ES2 | CK_AM35XX),
        CLK(NULL,       "ts_fck",       &ts_fck,        CK_3430ES2 | CK_AM35XX),
        CLK(NULL,       "usbtll_fck",   &usbtll_fck,    CK_3430ES2 | CK_AM35XX),
+       CLK("omap-mcbsp.1",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
+       CLK("omap-mcbsp.5",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
        CLK(NULL,       "core_96m_fck", &core_96m_fck,  CK_3XXX),
        CLK("mmci-omap-hs.2",   "fck",  &mmchs3_fck,    CK_3430ES2 | CK_AM35XX),
        CLK("mmci-omap-hs.1",   "fck",  &mmchs2_fck,    CK_3XXX),
@@ -3346,9 +3373,13 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX),
        CLK(NULL,       "gpt12_ick",    &gpt12_ick,     CK_3XXX),
        CLK(NULL,       "gpt1_ick",     &gpt1_ick,      CK_3XXX),
+       CLK("omap-mcbsp.2",     "prcm_fck",     &per_96m_fck,   CK_3XXX),
+       CLK("omap-mcbsp.3",     "prcm_fck",     &per_96m_fck,   CK_3XXX),
+       CLK("omap-mcbsp.4",     "prcm_fck",     &per_96m_fck,   CK_3XXX),
        CLK(NULL,       "per_96m_fck",  &per_96m_fck,   CK_3XXX),
        CLK(NULL,       "per_48m_fck",  &per_48m_fck,   CK_3XXX),
        CLK(NULL,       "uart3_fck",    &uart3_fck,     CK_3XXX),
+       CLK(NULL,       "uart4_fck",    &uart4_fck,     CK_36XX),
        CLK(NULL,       "gpt2_fck",     &gpt2_fck,      CK_3XXX),
        CLK(NULL,       "gpt3_fck",     &gpt3_fck,      CK_3XXX),
        CLK(NULL,       "gpt4_fck",     &gpt4_fck,      CK_3XXX),
@@ -3372,6 +3403,7 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "gpio2_ick",    &gpio2_ick,     CK_3XXX),
        CLK(NULL,       "wdt3_ick",     &wdt3_ick,      CK_3XXX),
        CLK(NULL,       "uart3_ick",    &uart3_ick,     CK_3XXX),
+       CLK(NULL,       "uart4_ick",    &uart4_ick,     CK_36XX),
        CLK(NULL,       "gpt9_ick",     &gpt9_ick,      CK_3XXX),
        CLK(NULL,       "gpt8_ick",     &gpt8_ick,      CK_3XXX),
        CLK(NULL,       "gpt7_ick",     &gpt7_ick,      CK_3XXX),
index e10db7a90cb270f5f833cd1b9076bd7b6cb38356..1599836ba3d9ba2787aa38f4414d88b346dc37bb 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * XXX Some of the ES1 clocks have been removed/changed; once support
+ * is added for discriminating clocks by ES level, these should be added back
+ * in.
  */
 
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/clk.h>
-
-#include <plat/control.h>
 #include <plat/clkdev_omap.h>
 
 #include "clock.h"
@@ -32,6 +34,7 @@
 #include "cm-regbits-44xx.h"
 #include "prm.h"
 #include "prm-regbits-44xx.h"
+#include "control.h"
 
 /* Root clocks */
 
@@ -175,21 +178,27 @@ static struct clk sys_clkin_ck = {
        .recalc         = &omap2_clksel_recalc,
 };
 
+static struct clk tie_low_clock_ck = {
+       .name           = "tie_low_clock_ck",
+       .rate           = 0,
+       .ops            = &clkops_null,
+};
+
 static struct clk utmi_phy_clkout_ck = {
        .name           = "utmi_phy_clkout_ck",
-       .rate           = 12000000,
+       .rate           = 60000000,
        .ops            = &clkops_null,
 };
 
 static struct clk xclk60mhsp1_ck = {
        .name           = "xclk60mhsp1_ck",
-       .rate           = 12000000,
+       .rate           = 60000000,
        .ops            = &clkops_null,
 };
 
 static struct clk xclk60mhsp2_ck = {
        .name           = "xclk60mhsp2_ck",
-       .rate           = 12000000,
+       .rate           = 60000000,
        .ops            = &clkops_null,
 };
 
@@ -201,39 +210,23 @@ static struct clk xclk60motg_ck = {
 
 /* Module clocks and DPLL outputs */
 
-static const struct clksel_rate div2_1to2_rates[] = {
-       { .div = 1, .val = 0, .flags = RATE_IN_4430 },
-       { .div = 2, .val = 1, .flags = RATE_IN_4430 },
-       { .div = 0 },
-};
-
-static const struct clksel dpll_sys_ref_clk_div[] = {
-       { .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+static const struct clksel abe_dpll_bypass_clk_mux_sel[] = {
+       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
+       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
-static struct clk dpll_sys_ref_clk = {
-       .name           = "dpll_sys_ref_clk",
+static struct clk abe_dpll_bypass_clk_mux_ck = {
+       .name           = "abe_dpll_bypass_clk_mux_ck",
        .parent         = &sys_clkin_ck,
-       .clksel         = dpll_sys_ref_clk_div,
-       .clksel_reg     = OMAP4430_CM_DPLL_SYS_REF_CLKSEL,
-       .clksel_mask    = OMAP4430_CLKSEL_0_0_MASK,
        .ops            = &clkops_null,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate,
-};
-
-static const struct clksel abe_dpll_refclk_mux_sel[] = {
-       { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
-       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
+       .recalc         = &followparent_recalc,
 };
 
 static struct clk abe_dpll_refclk_mux_ck = {
        .name           = "abe_dpll_refclk_mux_ck",
-       .parent         = &dpll_sys_ref_clk,
-       .clksel         = abe_dpll_refclk_mux_sel,
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP4430_CM_ABE_PLL_REF_CLKSEL,
        .clksel_mask    = OMAP4430_CLKSEL_0_0_MASK,
@@ -244,7 +237,7 @@ static struct clk abe_dpll_refclk_mux_ck = {
 /* DPLL_ABE */
 static struct dpll_data dpll_abe_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_ABE,
-       .clk_bypass     = &sys_clkin_ck,
+       .clk_bypass     = &abe_dpll_bypass_clk_mux_ck,
        .clk_ref        = &abe_dpll_refclk_mux_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_ABE,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
@@ -310,6 +303,12 @@ static struct clk abe_clk = {
        .set_rate       = &omap2_clksel_set_rate,
 };
 
+static const struct clksel_rate div2_1to2_rates[] = {
+       { .div = 1, .val = 0, .flags = RATE_IN_4430 },
+       { .div = 2, .val = 1, .flags = RATE_IN_4430 },
+       { .div = 0 },
+};
+
 static const struct clksel aess_fclk_div[] = {
        { .parent = &abe_clk, .rates = div2_1to2_rates },
        { .parent = NULL },
@@ -380,14 +379,14 @@ static struct clk dpll_abe_m3_ck = {
 };
 
 static const struct clksel core_hsd_byp_clk_mux_sel[] = {
-       { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
        { .parent = &dpll_abe_m3_ck, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
 static struct clk core_hsd_byp_clk_mux_ck = {
        .name           = "core_hsd_byp_clk_mux_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .clksel         = core_hsd_byp_clk_mux_sel,
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP4430_CM_CLKSEL_DPLL_CORE,
@@ -400,7 +399,7 @@ static struct clk core_hsd_byp_clk_mux_ck = {
 static struct dpll_data dpll_core_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_CORE,
        .clk_bypass     = &core_hsd_byp_clk_mux_ck,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_CORE,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_CORE,
@@ -418,7 +417,7 @@ static struct dpll_data dpll_core_dd = {
 
 static struct clk dpll_core_ck = {
        .name           = "dpll_core_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_core_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_null,
@@ -596,14 +595,14 @@ static struct clk dpll_core_m7_ck = {
 };
 
 static const struct clksel iva_hsd_byp_clk_mux_sel[] = {
-       { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
        { .parent = &div_iva_hs_clk, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
 static struct clk iva_hsd_byp_clk_mux_ck = {
        .name           = "iva_hsd_byp_clk_mux_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .ops            = &clkops_null,
        .recalc         = &followparent_recalc,
 };
@@ -612,7 +611,7 @@ static struct clk iva_hsd_byp_clk_mux_ck = {
 static struct dpll_data dpll_iva_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_IVA,
        .clk_bypass     = &iva_hsd_byp_clk_mux_ck,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_IVA,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_IVA,
@@ -630,7 +629,7 @@ static struct dpll_data dpll_iva_dd = {
 
 static struct clk dpll_iva_ck = {
        .name           = "dpll_iva_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_iva_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_omap3_noncore_dpll_ops,
@@ -672,7 +671,7 @@ static struct clk dpll_iva_m5_ck = {
 static struct dpll_data dpll_mpu_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_MPU,
        .clk_bypass     = &div_mpu_hs_clk,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_MPU,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_MPU,
@@ -690,7 +689,7 @@ static struct dpll_data dpll_mpu_dd = {
 
 static struct clk dpll_mpu_ck = {
        .name           = "dpll_mpu_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_mpu_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_omap3_noncore_dpll_ops,
@@ -724,14 +723,14 @@ static struct clk per_hs_clk_div_ck = {
 };
 
 static const struct clksel per_hsd_byp_clk_mux_sel[] = {
-       { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
        { .parent = &per_hs_clk_div_ck, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
 static struct clk per_hsd_byp_clk_mux_ck = {
        .name           = "per_hsd_byp_clk_mux_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .clksel         = per_hsd_byp_clk_mux_sel,
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP4430_CM_CLKSEL_DPLL_PER,
@@ -744,7 +743,7 @@ static struct clk per_hsd_byp_clk_mux_ck = {
 static struct dpll_data dpll_per_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_PER,
        .clk_bypass     = &per_hsd_byp_clk_mux_ck,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_PER,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_PER,
@@ -762,7 +761,7 @@ static struct dpll_data dpll_per_dd = {
 
 static struct clk dpll_per_ck = {
        .name           = "dpll_per_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_per_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_omap3_noncore_dpll_ops,
@@ -858,8 +857,8 @@ static struct clk dpll_per_m7_ck = {
 /* DPLL_UNIPRO */
 static struct dpll_data dpll_unipro_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_UNIPRO,
-       .clk_bypass     = &dpll_sys_ref_clk,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .clk_bypass     = &sys_clkin_ck,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_UNIPRO,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_UNIPRO,
@@ -877,7 +876,7 @@ static struct dpll_data dpll_unipro_dd = {
 
 static struct clk dpll_unipro_ck = {
        .name           = "dpll_unipro_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_unipro_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_omap3_noncore_dpll_ops,
@@ -914,7 +913,8 @@ static struct clk usb_hs_clk_div_ck = {
 static struct dpll_data dpll_usb_dd = {
        .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_USB,
        .clk_bypass     = &usb_hs_clk_div_ck,
-       .clk_ref        = &dpll_sys_ref_clk,
+       .flags          = DPLL_J_TYPE | DPLL_NO_DCO_SEL,
+       .clk_ref        = &sys_clkin_ck,
        .control_reg    = OMAP4430_CM_CLKMODE_DPLL_USB,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_USB,
@@ -927,13 +927,12 @@ static struct dpll_data dpll_usb_dd = {
        .max_multiplier = OMAP4430_MAX_DPLL_MULT,
        .max_divider    = OMAP4430_MAX_DPLL_DIV,
        .min_divider    = 1,
-       .flags          = DPLL_J_TYPE | DPLL_NO_DCO_SEL
 };
 
 
 static struct clk dpll_usb_ck = {
        .name           = "dpll_usb_ck",
-       .parent         = &dpll_sys_ref_clk,
+       .parent         = &sys_clkin_ck,
        .dpll_data      = &dpll_usb_dd,
        .init           = &omap2_init_dpll_parent,
        .ops            = &clkops_omap3_noncore_dpll_ops,
@@ -1222,7 +1221,7 @@ static struct clk per_abe_24m_fclk = {
 static const struct clksel pmd_stm_clock_mux_sel[] = {
        { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
        { .parent = &dpll_core_m6_ck, .rates = div_1_1_rates },
-       { .parent = &dpll_per_m7_ck, .rates = div_1_2_rates },
+       { .parent = &tie_low_clock_ck, .rates = div_1_2_rates },
        { .parent = NULL },
 };
 
@@ -1240,10 +1239,15 @@ static struct clk pmd_trace_clk_mux_ck = {
        .recalc         = &followparent_recalc,
 };
 
+static const struct clksel syc_clk_div_div[] = {
+       { .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+       { .parent = NULL },
+};
+
 static struct clk syc_clk_div_ck = {
        .name           = "syc_clk_div_ck",
        .parent         = &sys_clkin_ck,
-       .clksel         = dpll_sys_ref_clk_div,
+       .clksel         = syc_clk_div_div,
        .clksel_reg     = OMAP4430_CM_ABE_DSS_SYS_CLKSEL,
        .clksel_mask    = OMAP4430_CLKSEL_0_0_MASK,
        .ops            = &clkops_null,
@@ -1284,13 +1288,13 @@ static struct clk aess_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk cust_efuse_fck = {
-       .name           = "cust_efuse_fck",
+static struct clk bandgap_fclk = {
+       .name           = "bandgap_fclk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_cefuse_clkdm",
-       .parent         = &sys_clkin_ck,
+       .enable_reg     = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .parent         = &sys_32k_ck,
        .recalc         = &followparent_recalc,
 };
 
@@ -1344,6 +1348,56 @@ static struct clk dmic_fck = {
        .clkdm_name     = "abe_clkdm",
 };
 
+static struct clk dsp_fck = {
+       .name           = "dsp_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_TESLA_TESLA_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "tesla_clkdm",
+       .parent         = &dpll_iva_m4_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dss_sys_clk = {
+       .name           = "dss_sys_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_DSS_DSS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT,
+       .clkdm_name     = "l3_dss_clkdm",
+       .parent         = &syc_clk_div_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dss_tv_clk = {
+       .name           = "dss_tv_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_DSS_DSS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_TV_CLK_SHIFT,
+       .clkdm_name     = "l3_dss_clkdm",
+       .parent         = &extalt_clkin_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dss_dss_clk = {
+       .name           = "dss_dss_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_DSS_DSS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DSSCLK_SHIFT,
+       .clkdm_name     = "l3_dss_clkdm",
+       .parent         = &dpll_per_m5_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dss_48mhz_clk = {
+       .name           = "dss_48mhz_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_DSS_DSS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT,
+       .clkdm_name     = "l3_dss_clkdm",
+       .parent         = &func_48mc_fclk,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk dss_fck = {
        .name           = "dss_fck",
        .ops            = &clkops_omap2_dflt,
@@ -1354,18 +1408,18 @@ static struct clk dss_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk ducati_ick = {
-       .name           = "ducati_ick",
+static struct clk efuse_ctrl_cust_fck = {
+       .name           = "efuse_ctrl_cust_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
-       .clkdm_name     = "ducati_clkdm",
-       .parent         = &ducati_clk_mux_ck,
+       .enable_reg     = OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_cefuse_clkdm",
+       .parent         = &sys_clkin_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk emif1_ick = {
-       .name           = "emif1_ick",
+static struct clk emif1_fck = {
+       .name           = "emif1_fck",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -1375,8 +1429,8 @@ static struct clk emif1_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk emif2_ick = {
-       .name           = "emif2_ick",
+static struct clk emif2_fck = {
+       .name           = "emif2_fck",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -1407,42 +1461,24 @@ static struct clk fdif_fck = {
        .clkdm_name     = "iss_clkdm",
 };
 
-static const struct clksel per_sgx_fclk_div[] = {
-       { .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
-       { .parent = NULL },
-};
-
-static struct clk per_sgx_fclk = {
-       .name           = "per_sgx_fclk",
-       .parent         = &dpll_per_m2x2_ck,
-       .clksel         = per_sgx_fclk_div,
-       .clksel_reg     = OMAP4430_CM_GFX_GFX_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_PER_192M_MASK,
-       .ops            = &clkops_null,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate,
-};
-
-static const struct clksel sgx_clk_mux_sel[] = {
-       { .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
-       { .parent = &per_sgx_fclk, .rates = div_1_1_rates },
-       { .parent = NULL },
+static struct clk fpka_fck = {
+       .name           = "fpka_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_secure_clkdm",
+       .parent         = &l4_div_ck,
+       .recalc         = &followparent_recalc,
 };
 
-/* Merged sgx_clk_mux into gfx */
-static struct clk gfx_fck = {
-       .name           = "gfx_fck",
-       .parent         = &dpll_core_m7_ck,
-       .clksel         = sgx_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_GFX_GFX_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_SGX_FCLK_MASK,
+static struct clk gpio1_dbclk = {
+       .name           = "gpio1_dbclk",
        .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_GFX_GFX_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l3_gfx_clkdm",
+       .enable_reg     = OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio1_ick = {
@@ -1455,6 +1491,16 @@ static struct clk gpio1_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk gpio2_dbclk = {
+       .name           = "gpio2_dbclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_GPIO2_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpio2_ick = {
        .name           = "gpio2_ick",
        .ops            = &clkops_omap2_dflt,
@@ -1465,6 +1511,16 @@ static struct clk gpio2_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk gpio3_dbclk = {
+       .name           = "gpio3_dbclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpio3_ick = {
        .name           = "gpio3_ick",
        .ops            = &clkops_omap2_dflt,
@@ -1475,6 +1531,16 @@ static struct clk gpio3_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk gpio4_dbclk = {
+       .name           = "gpio4_dbclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_GPIO4_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpio4_ick = {
        .name           = "gpio4_ick",
        .ops            = &clkops_omap2_dflt,
@@ -1485,6 +1551,16 @@ static struct clk gpio4_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk gpio5_dbclk = {
+       .name           = "gpio5_dbclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_GPIO5_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpio5_ick = {
        .name           = "gpio5_ick",
        .ops            = &clkops_omap2_dflt,
@@ -1495,6 +1571,16 @@ static struct clk gpio5_ick = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk gpio6_dbclk = {
+       .name           = "gpio6_dbclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_GPIO6_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk gpio6_ick = {
        .name           = "gpio6_ick",
        .ops            = &clkops_omap2_dflt,
@@ -1515,278 +1601,114 @@ static struct clk gpmc_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static const struct clksel dmt1_clk_mux_sel[] = {
-       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
-       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
+static const struct clksel sgx_clk_mux_sel[] = {
+       { .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
+       { .parent = &dpll_per_m7_ck, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
-/*
- * Merged dmt1_clk_mux into gptimer1
- * gptimer1 renamed temporarily into gpt1 to match OMAP3 convention
- */
-static struct clk gpt1_fck = {
-       .name           = "gpt1_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
+/* Merged sgx_clk_mux into gpu */
+static struct clk gpu_fck = {
+       .name           = "gpu_fck",
+       .parent         = &dpll_core_m7_ck,
+       .clksel         = sgx_clk_mux_sel,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .clksel_reg     = OMAP4430_CM_GFX_GFX_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_SGX_FCLK_MASK,
        .ops            = &clkops_omap2_dflt,
        .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_GFX_GFX_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_wkup_clkdm",
+       .clkdm_name     = "l3_gfx_clkdm",
 };
 
-/*
- * Merged cm2_dm10_mux into gptimer10
- * gptimer10 renamed temporarily into gpt10 to match OMAP3 convention
- */
-static struct clk gpt10_fck = {
-       .name           = "gpt10_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+static struct clk hdq1w_fck = {
+       .name           = "hdq1w_fck",
        .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_HDQ1W_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_12m_fclk,
+       .recalc         = &followparent_recalc,
 };
 
-/*
- * Merged cm2_dm11_mux into gptimer11
- * gptimer11 renamed temporarily into gpt11 to match OMAP3 convention
- */
-static struct clk gpt11_fck = {
-       .name           = "gpt11_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+static const struct clksel hsi_fclk_div[] = {
+       { .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
+       { .parent = NULL },
+};
+
+/* Merged hsi_fclk into hsi */
+static struct clk hsi_fck = {
+       .name           = "hsi_fck",
+       .parent         = &dpll_per_m2x2_ck,
+       .clksel         = hsi_fclk_div,
+       .clksel_reg     = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_24_25_MASK,
        .ops            = &clkops_omap2_dflt,
        .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
+       .enable_reg     = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l3_init_clkdm",
+};
+
+static struct clk i2c1_fck = {
+       .name           = "i2c1_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_I2C1_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_96m_fclk,
+       .recalc         = &followparent_recalc,
 };
 
-/*
- * Merged cm2_dm2_mux into gptimer2
- * gptimer2 renamed temporarily into gpt2 to match OMAP3 convention
- */
-static struct clk gpt2_fck = {
-       .name           = "gpt2_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+static struct clk i2c2_fck = {
+       .name           = "i2c2_fck",
        .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_I2C2_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_96m_fclk,
+       .recalc         = &followparent_recalc,
 };
 
-/*
- * Merged cm2_dm3_mux into gptimer3
- * gptimer3 renamed temporarily into gpt3 to match OMAP3 convention
- */
-static struct clk gpt3_fck = {
-       .name           = "gpt3_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+static struct clk i2c3_fck = {
+       .name           = "i2c3_fck",
        .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_I2C3_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_96m_fclk,
+       .recalc         = &followparent_recalc,
 };
 
-/*
- * Merged cm2_dm4_mux into gptimer4
- * gptimer4 renamed temporarily into gpt4 to match OMAP3 convention
- */
-static struct clk gpt4_fck = {
-       .name           = "gpt4_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-};
-
-static const struct clksel timer5_sync_mux_sel[] = {
-       { .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
-       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-/*
- * Merged timer5_sync_mux into gptimer5
- * gptimer5 renamed temporarily into gpt5 to match OMAP3 convention
- */
-static struct clk gpt5_fck = {
-       .name           = "gpt5_fck",
-       .parent         = &syc_clk_div_ck,
-       .clksel         = timer5_sync_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-};
-
-/*
- * Merged timer6_sync_mux into gptimer6
- * gptimer6 renamed temporarily into gpt6 to match OMAP3 convention
- */
-static struct clk gpt6_fck = {
-       .name           = "gpt6_fck",
-       .parent         = &syc_clk_div_ck,
-       .clksel         = timer5_sync_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-};
-
-/*
- * Merged timer7_sync_mux into gptimer7
- * gptimer7 renamed temporarily into gpt7 to match OMAP3 convention
- */
-static struct clk gpt7_fck = {
-       .name           = "gpt7_fck",
-       .parent         = &syc_clk_div_ck,
-       .clksel         = timer5_sync_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-};
-
-/*
- * Merged timer8_sync_mux into gptimer8
- * gptimer8 renamed temporarily into gpt8 to match OMAP3 convention
- */
-static struct clk gpt8_fck = {
-       .name           = "gpt8_fck",
-       .parent         = &syc_clk_div_ck,
-       .clksel         = timer5_sync_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-};
-
-/*
- * Merged cm2_dm9_mux into gptimer9
- * gptimer9 renamed temporarily into gpt9 to match OMAP3 convention
- */
-static struct clk gpt9_fck = {
-       .name           = "gpt9_fck",
-       .parent         = &sys_clkin_ck,
-       .clksel         = dmt1_clk_mux_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-};
-
-static struct clk hdq1w_fck = {
-       .name           = "hdq1w_fck",
-       .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_HDQ1W_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_12m_fclk,
-       .recalc         = &followparent_recalc,
-};
-
-/* Merged hsi_fclk into hsi */
-static struct clk hsi_ick = {
-       .name           = "hsi_ick",
-       .parent         = &dpll_per_m2x2_ck,
-       .clksel         = per_sgx_fclk_div,
-       .clksel_reg     = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_24_25_MASK,
-       .ops            = &clkops_omap2_dflt,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate,
-       .enable_reg     = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
-       .clkdm_name     = "l3_init_clkdm",
-};
-
-static struct clk i2c1_fck = {
-       .name           = "i2c1_fck",
-       .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_I2C1_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_96m_fclk,
-       .recalc         = &followparent_recalc,
-};
-
-static struct clk i2c2_fck = {
-       .name           = "i2c2_fck",
+static struct clk i2c4_fck = {
+       .name           = "i2c4_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_I2C2_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_I2C4_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
        .parent         = &func_96m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk i2c3_fck = {
-       .name           = "i2c3_fck",
+static struct clk ipu_fck = {
+       .name           = "ipu_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_I2C3_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_96m_fclk,
+       .enable_reg     = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "ducati_clkdm",
+       .parent         = &ducati_clk_mux_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk i2c4_fck = {
-       .name           = "i2c4_fck",
+static struct clk iss_ctrlclk = {
+       .name           = "iss_ctrlclk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_I2C4_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
+       .enable_reg     = OMAP4430_CM_CAM_ISS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT,
+       .clkdm_name     = "iss_clkdm",
        .parent         = &func_96m_fclk,
        .recalc         = &followparent_recalc,
 };
@@ -1801,8 +1723,8 @@ static struct clk iss_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk ivahd_ick = {
-       .name           = "ivahd_ick",
+static struct clk iva_fck = {
+       .name           = "iva_fck",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -1811,8 +1733,8 @@ static struct clk ivahd_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk keyboard_fck = {
-       .name           = "keyboard_fck",
+static struct clk kbd_fck = {
+       .name           = "kbd_fck",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
@@ -1821,8 +1743,8 @@ static struct clk keyboard_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk l3_instr_interconnect_ick = {
-       .name           = "l3_instr_interconnect_ick",
+static struct clk l3_instr_ick = {
+       .name           = "l3_instr_ick",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -1831,8 +1753,8 @@ static struct clk l3_instr_interconnect_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk l3_interconnect_3_ick = {
-       .name           = "l3_interconnect_3_ick",
+static struct clk l3_main_3_ick = {
+       .name           = "l3_main_3_ick",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -2005,6 +1927,16 @@ static struct clk mcbsp4_fck = {
        .clkdm_name     = "l4_per_clkdm",
 };
 
+static struct clk mcpdm_fck = {
+       .name           = "mcpdm_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM1_ABE_PDM_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &pad_clks_ck,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk mcspi1_fck = {
        .name           = "mcspi1_fck",
        .ops            = &clkops_omap2_dflt,
@@ -2105,33 +2037,33 @@ static struct clk mmc5_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk ocp_wp1_ick = {
-       .name           = "ocp_wp1_ick",
+static struct clk ocp2scp_usb_phy_phy_48m = {
+       .name           = "ocp2scp_usb_phy_phy_48m",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
-       .clkdm_name     = "l3_instr_clkdm",
-       .parent         = &l3_div_ck,
+       .enable_reg     = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_PHY_48M_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &func_48m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk pdm_fck = {
-       .name           = "pdm_fck",
+static struct clk ocp2scp_usb_phy_ick = {
+       .name           = "ocp2scp_usb_phy_ick",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM1_ABE_PDM_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-       .parent         = &pad_clks_ck,
+       .enable_reg     = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &l4_div_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk pkaeip29_fck = {
-       .name           = "pkaeip29_fck",
+static struct clk ocp_wp_noc_ick = {
+       .name           = "ocp_wp_noc_ick",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_secure_clkdm",
-       .parent         = &l4_div_ck,
+       .enable_reg     = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l3_instr_clkdm",
+       .parent         = &l3_div_ck,
        .recalc         = &followparent_recalc,
 };
 
@@ -2145,8 +2077,8 @@ static struct clk rng_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk sha2md51_fck = {
-       .name           = "sha2md51_fck",
+static struct clk sha2md5_fck = {
+       .name           = "sha2md5_fck",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
@@ -2155,8 +2087,8 @@ static struct clk sha2md51_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk sl2_ick = {
-       .name           = "sl2_ick",
+static struct clk sl2if_ick = {
+       .name           = "sl2if_ick",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_IVAHD_SL2_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
@@ -2165,129 +2097,340 @@ static struct clk sl2_ick = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk slimbus1_fck = {
-       .name           = "slimbus1_fck",
+static struct clk slimbus1_fclk_1 = {
+       .name           = "slimbus1_fclk_1",
        .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_FCLK1_SHIFT,
        .clkdm_name     = "abe_clkdm",
-       .parent         = &ocp_abe_iclk,
+       .parent         = &func_24m_clk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk slimbus2_fck = {
-       .name           = "slimbus2_fck",
+static struct clk slimbus1_fclk_0 = {
+       .name           = "slimbus1_fclk_0",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-       .parent         = &l4_div_ck,
+       .enable_reg     = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_FCLK0_SHIFT,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &abe_24m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk sr_core_fck = {
-       .name           = "sr_core_fck",
+static struct clk slimbus1_fclk_2 = {
+       .name           = "slimbus1_fclk_2",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_ao_clkdm",
-       .parent         = &l4_wkup_clk_mux_ck,
+       .enable_reg     = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_FCLK2_SHIFT,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &pad_clks_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk sr_iva_fck = {
-       .name           = "sr_iva_fck",
+static struct clk slimbus1_slimbus_clk = {
+       .name           = "slimbus1_slimbus_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_ao_clkdm",
-       .parent         = &l4_wkup_clk_mux_ck,
+       .enable_reg     = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &slimbus_clk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk sr_mpu_fck = {
-       .name           = "sr_mpu_fck",
+static struct clk slimbus1_fck = {
+       .name           = "slimbus1_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
+       .enable_reg     = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_ao_clkdm",
-       .parent         = &l4_wkup_clk_mux_ck,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &ocp_abe_iclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk tesla_ick = {
-       .name           = "tesla_ick",
+static struct clk slimbus2_fclk_1 = {
+       .name           = "slimbus2_fclk_1",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_TESLA_TESLA_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
-       .clkdm_name     = "tesla_clkdm",
-       .parent         = &dpll_iva_m4_ck,
+       .enable_reg     = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &per_abe_24m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk uart1_fck = {
-       .name           = "uart1_fck",
+static struct clk slimbus2_fclk_0 = {
+       .name           = "slimbus2_fclk_0",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_UART1_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT,
        .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_48m_fclk,
+       .parent         = &func_24mc_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk uart2_fck = {
-       .name           = "uart2_fck",
+static struct clk slimbus2_slimbus_clk = {
+       .name           = "slimbus2_slimbus_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_UART2_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT,
        .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_48m_fclk,
+       .parent         = &pad_slimbus_core_clks_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk uart3_fck = {
-       .name           = "uart3_fck",
+static struct clk slimbus2_fck = {
+       .name           = "slimbus2_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_48m_fclk,
+       .parent         = &l4_div_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk uart4_fck = {
-       .name           = "uart4_fck",
+static struct clk smartreflex_core_fck = {
+       .name           = "smartreflex_core_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_per_clkdm",
-       .parent         = &func_48m_fclk,
+       .clkdm_name     = "l4_ao_clkdm",
+       .parent         = &l4_wkup_clk_mux_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk unipro1_fck = {
-       .name           = "unipro1_fck",
+static struct clk smartreflex_iva_fck = {
+       .name           = "smartreflex_iva_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INIT_UNIPRO1_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l3_init_clkdm",
-       .parent         = &func_96m_fclk,
+       .clkdm_name     = "l4_ao_clkdm",
+       .parent         = &l4_wkup_clk_mux_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usb_host_fck = {
-       .name           = "usb_host_fck",
+static struct clk smartreflex_mpu_fck = {
+       .name           = "smartreflex_mpu_fck",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l3_init_clkdm",
-       .parent         = &init_60m_fclk,
+       .clkdm_name     = "l4_ao_clkdm",
+       .parent         = &l4_wkup_clk_mux_ck,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usb_host_fs_fck = {
-       .name           = "usb_host_fs_fck",
-       .ops            = &clkops_omap2_dflt,
+/* Merged dmt1_clk_mux into timer1 */
+static struct clk timer1_fck = {
+       .name           = "timer1_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_wkup_clkdm",
+};
+
+/* Merged cm2_dm10_mux into timer10 */
+static struct clk timer10_fck = {
+       .name           = "timer10_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm11_mux into timer11 */
+static struct clk timer11_fck = {
+       .name           = "timer11_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm2_mux into timer2 */
+static struct clk timer2_fck = {
+       .name           = "timer2_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm3_mux into timer3 */
+static struct clk timer3_fck = {
+       .name           = "timer3_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm4_mux into timer4 */
+static struct clk timer4_fck = {
+       .name           = "timer4_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+static const struct clksel timer5_sync_mux_sel[] = {
+       { .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
+       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
+       { .parent = NULL },
+};
+
+/* Merged timer5_sync_mux into timer5 */
+static struct clk timer5_fck = {
+       .name           = "timer5_fck",
+       .parent         = &syc_clk_div_ck,
+       .clksel         = timer5_sync_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+};
+
+/* Merged timer6_sync_mux into timer6 */
+static struct clk timer6_fck = {
+       .name           = "timer6_fck",
+       .parent         = &syc_clk_div_ck,
+       .clksel         = timer5_sync_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+};
+
+/* Merged timer7_sync_mux into timer7 */
+static struct clk timer7_fck = {
+       .name           = "timer7_fck",
+       .parent         = &syc_clk_div_ck,
+       .clksel         = timer5_sync_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+};
+
+/* Merged timer8_sync_mux into timer8 */
+static struct clk timer8_fck = {
+       .name           = "timer8_fck",
+       .parent         = &syc_clk_div_ck,
+       .clksel         = timer5_sync_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+};
+
+/* Merged cm2_dm9_mux into timer9 */
+static struct clk timer9_fck = {
+       .name           = "timer9_fck",
+       .parent         = &sys_clkin_ck,
+       .clksel         = abe_dpll_bypass_clk_mux_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_MASK,
+       .ops            = &clkops_omap2_dflt,
+       .recalc         = &omap2_clksel_recalc,
+       .enable_reg     = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+};
+
+static struct clk uart1_fck = {
+       .name           = "uart1_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_48m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk uart2_fck = {
+       .name           = "uart2_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_48m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk uart3_fck = {
+       .name           = "uart3_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_48m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk uart4_fck = {
+       .name           = "uart4_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_per_clkdm",
+       .parent         = &func_48m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_host_fs_fck = {
+       .name           = "usb_host_fs_fck",
+       .ops            = &clkops_omap2_dflt,
        .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
        .clkdm_name     = "l3_init_clkdm",
@@ -2295,75 +2438,138 @@ static struct clk usb_host_fs_fck = {
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usb_otg_ick = {
-       .name           = "usb_otg_ick",
+static struct clk usb_host_hs_utmi_p3_clk = {
+       .name           = "usb_host_hs_utmi_p3_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT,
        .clkdm_name     = "l3_init_clkdm",
-       .parent         = &l3_div_ck,
+       .parent         = &init_60m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usb_tll_ick = {
-       .name           = "usb_tll_ick",
+static struct clk usb_host_hs_hsic60m_p1_clk = {
+       .name           = "usb_host_hs_hsic60m_p1_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT,
        .clkdm_name     = "l3_init_clkdm",
-       .parent         = &l4_div_ck,
+       .parent         = &init_60m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usbphyocp2scp_ick = {
-       .name           = "usbphyocp2scp_ick",
+static struct clk usb_host_hs_hsic60m_p2_clk = {
+       .name           = "usb_host_hs_hsic60m_p2_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT,
        .clkdm_name     = "l3_init_clkdm",
-       .parent         = &l4_div_ck,
+       .parent         = &init_60m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usim_fck = {
-       .name           = "usim_fck",
+static const struct clksel utmi_p1_gfclk_sel[] = {
+       { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+       { .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+       { .parent = NULL },
+};
+
+static struct clk utmi_p1_gfclk = {
+       .name           = "utmi_p1_gfclk",
+       .parent         = &init_60m_fclk,
+       .clksel         = utmi_p1_gfclk_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_UTMI_P1_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p1_clk = {
+       .name           = "usb_host_hs_utmi_p1_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_WKUP_USIM_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .parent         = &sys_32k_ck,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &utmi_p1_gfclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk wdt2_fck = {
-       .name           = "wdt2_fck",
+static const struct clksel utmi_p2_gfclk_sel[] = {
+       { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+       { .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+       { .parent = NULL },
+};
+
+static struct clk utmi_p2_gfclk = {
+       .name           = "utmi_p2_gfclk",
+       .parent         = &init_60m_fclk,
+       .clksel         = utmi_p2_gfclk_sel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_UTMI_P2_MASK,
+       .ops            = &clkops_null,
+       .recalc         = &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p2_clk = {
+       .name           = "usb_host_hs_utmi_p2_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .parent         = &sys_32k_ck,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &utmi_p2_gfclk,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk wdt3_fck = {
-       .name           = "wdt3_fck",
+static struct clk usb_host_hs_hsic480m_p1_clk = {
+       .name           = "usb_host_hs_hsic480m_p1_clk",
        .ops            = &clkops_omap2_dflt,
-       .enable_reg     = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &dpll_usb_m2_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_host_hs_hsic480m_p2_clk = {
+       .name           = "usb_host_hs_hsic480m_p2_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &dpll_usb_m2_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_host_hs_func48mclk = {
+       .name           = "usb_host_hs_func48mclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &func_48mc_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_host_hs_fck = {
+       .name           = "usb_host_hs_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
        .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
-       .clkdm_name     = "abe_clkdm",
-       .parent         = &sys_32k_ck,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &init_60m_fclk,
        .recalc         = &followparent_recalc,
 };
 
-/* Remaining optional clocks */
 static const struct clksel otg_60m_gfclk_sel[] = {
        { .parent = &utmi_phy_clkout_ck, .rates = div_1_0_rates },
        { .parent = &xclk60motg_ck, .rates = div_1_1_rates },
        { .parent = NULL },
 };
 
-static struct clk otg_60m_gfclk_ck = {
-       .name           = "otg_60m_gfclk_ck",
+static struct clk otg_60m_gfclk = {
+       .name           = "otg_60m_gfclk",
        .parent         = &utmi_phy_clkout_ck,
        .clksel         = otg_60m_gfclk_sel,
        .init           = &omap2_init_clksel_parent,
@@ -2373,38 +2579,74 @@ static struct clk otg_60m_gfclk_ck = {
        .recalc         = &omap2_clksel_recalc,
 };
 
-static const struct clksel stm_clk_div_div[] = {
-       { .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
-       { .parent = NULL },
+static struct clk usb_otg_hs_xclk = {
+       .name           = "usb_otg_hs_xclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_XCLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &otg_60m_gfclk,
+       .recalc         = &followparent_recalc,
 };
 
-static struct clk stm_clk_div_ck = {
-       .name           = "stm_clk_div_ck",
-       .parent         = &pmd_stm_clock_mux_ck,
-       .clksel         = stm_clk_div_div,
-       .clksel_reg     = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
-       .ops            = &clkops_null,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate,
+static struct clk usb_otg_hs_ick = {
+       .name           = "usb_otg_hs_ick",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &l3_div_ck,
+       .recalc         = &followparent_recalc,
 };
 
-static const struct clksel trace_clk_div_div[] = {
-       { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
-       { .parent = NULL },
+static struct clk usb_phy_cm_clk32k = {
+       .name           = "usb_phy_cm_clk32k",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_ALWON_USBPHY_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_CLK32K_SHIFT,
+       .clkdm_name     = "l4_ao_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
 };
 
-static struct clk trace_clk_div_ck = {
-       .name           = "trace_clk_div_ck",
-       .parent         = &pmd_trace_clk_mux_ck,
-       .clksel         = trace_clk_div_div,
-       .clksel_reg     = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
-       .ops            = &clkops_null,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate,
+static struct clk usb_tll_hs_usb_ch2_clk = {
+       .name           = "usb_tll_hs_usb_ch2_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &init_60m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch0_clk = {
+       .name           = "usb_tll_hs_usb_ch0_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &init_60m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch1_clk = {
+       .name           = "usb_tll_hs_usb_ch1_clk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &init_60m_fclk,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_ick = {
+       .name           = "usb_tll_hs_ick",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l3_init_clkdm",
+       .parent         = &l4_div_ck,
+       .recalc         = &followparent_recalc,
 };
 
 static const struct clksel_rate div2_14to18_rates[] = {
@@ -2418,8 +2660,8 @@ static const struct clksel usim_fclk_div[] = {
        { .parent = NULL },
 };
 
-static struct clk usim_fclk = {
-       .name           = "usim_fclk",
+static struct clk usim_ck = {
+       .name           = "usim_ck",
        .parent         = &dpll_per_m4_ck,
        .clksel         = usim_fclk_div,
        .clksel_reg     = OMAP4430_CM_WKUP_USIM_CLKCTRL,
@@ -2430,38 +2672,79 @@ static struct clk usim_fclk = {
        .set_rate       = &omap2_clksel_set_rate,
 };
 
-static const struct clksel utmi_p1_gfclk_sel[] = {
-       { .parent = &init_60m_fclk, .rates = div_1_0_rates },
-       { .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+static struct clk usim_fclk = {
+       .name           = "usim_fclk",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_WKUP_USIM_CLKCTRL,
+       .enable_bit     = OMAP4430_OPTFCLKEN_FCLK_SHIFT,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .parent         = &usim_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk usim_fck = {
+       .name           = "usim_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_WKUP_USIM_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_HWCTRL,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk wd_timer2_fck = {
+       .name           = "wd_timer2_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "l4_wkup_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk wd_timer3_fck = {
+       .name           = "wd_timer3_fck",
+       .ops            = &clkops_omap2_dflt,
+       .enable_reg     = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL,
+       .clkdm_name     = "abe_clkdm",
+       .parent         = &sys_32k_ck,
+       .recalc         = &followparent_recalc,
+};
+
+/* Remaining optional clocks */
+static const struct clksel stm_clk_div_div[] = {
+       { .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
        { .parent = NULL },
 };
 
-static struct clk utmi_p1_gfclk_ck = {
-       .name           = "utmi_p1_gfclk_ck",
-       .parent         = &init_60m_fclk,
-       .clksel         = utmi_p1_gfclk_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_UTMI_P1_MASK,
+static struct clk stm_clk_div_ck = {
+       .name           = "stm_clk_div_ck",
+       .parent         = &pmd_stm_clock_mux_ck,
+       .clksel         = stm_clk_div_div,
+       .clksel_reg     = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
        .ops            = &clkops_null,
        .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
 };
 
-static const struct clksel utmi_p2_gfclk_sel[] = {
-       { .parent = &init_60m_fclk, .rates = div_1_0_rates },
-       { .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+static const struct clksel trace_clk_div_div[] = {
+       { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
        { .parent = NULL },
 };
 
-static struct clk utmi_p2_gfclk_ck = {
-       .name           = "utmi_p2_gfclk_ck",
-       .parent         = &init_60m_fclk,
-       .clksel         = utmi_p2_gfclk_sel,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_UTMI_P2_MASK,
+static struct clk trace_clk_div_ck = {
+       .name           = "trace_clk_div_ck",
+       .parent         = &pmd_trace_clk_mux_ck,
+       .clksel         = trace_clk_div_div,
+       .clksel_reg     = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+       .clksel_mask    = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
        .ops            = &clkops_null,
        .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate,
 };
 
 /*
@@ -2483,11 +2766,12 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "virt_27000000_ck",             &virt_27000000_ck,      CK_443X),
        CLK(NULL,       "virt_38400000_ck",             &virt_38400000_ck,      CK_443X),
        CLK(NULL,       "sys_clkin_ck",                 &sys_clkin_ck,  CK_443X),
+       CLK(NULL,       "tie_low_clock_ck",             &tie_low_clock_ck,      CK_443X),
        CLK(NULL,       "utmi_phy_clkout_ck",           &utmi_phy_clkout_ck,    CK_443X),
        CLK(NULL,       "xclk60mhsp1_ck",               &xclk60mhsp1_ck,        CK_443X),
        CLK(NULL,       "xclk60mhsp2_ck",               &xclk60mhsp2_ck,        CK_443X),
        CLK(NULL,       "xclk60motg_ck",                &xclk60motg_ck, CK_443X),
-       CLK(NULL,       "dpll_sys_ref_clk",             &dpll_sys_ref_clk,      CK_443X),
+       CLK(NULL,       "abe_dpll_bypass_clk_mux_ck",   &abe_dpll_bypass_clk_mux_ck,    CK_443X),
        CLK(NULL,       "abe_dpll_refclk_mux_ck",       &abe_dpll_refclk_mux_ck,        CK_443X),
        CLK(NULL,       "dpll_abe_ck",                  &dpll_abe_ck,   CK_443X),
        CLK(NULL,       "dpll_abe_m2x2_ck",             &dpll_abe_m2x2_ck,      CK_443X),
@@ -2557,46 +2841,48 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "aes1_fck",                     &aes1_fck,      CK_443X),
        CLK(NULL,       "aes2_fck",                     &aes2_fck,      CK_443X),
        CLK(NULL,       "aess_fck",                     &aess_fck,      CK_443X),
-       CLK(NULL,       "cust_efuse_fck",               &cust_efuse_fck,        CK_443X),
+       CLK(NULL,       "bandgap_fclk",                 &bandgap_fclk,  CK_443X),
        CLK(NULL,       "des3des_fck",                  &des3des_fck,   CK_443X),
        CLK(NULL,       "dmic_sync_mux_ck",             &dmic_sync_mux_ck,      CK_443X),
        CLK(NULL,       "dmic_fck",                     &dmic_fck,      CK_443X),
+       CLK(NULL,       "dsp_fck",                      &dsp_fck,       CK_443X),
+       CLK(NULL,       "dss_sys_clk",                  &dss_sys_clk,   CK_443X),
+       CLK(NULL,       "dss_tv_clk",                   &dss_tv_clk,    CK_443X),
+       CLK(NULL,       "dss_dss_clk",                  &dss_dss_clk,   CK_443X),
+       CLK(NULL,       "dss_48mhz_clk",                &dss_48mhz_clk, CK_443X),
        CLK(NULL,       "dss_fck",                      &dss_fck,       CK_443X),
-       CLK(NULL,       "ducati_ick",                   &ducati_ick,    CK_443X),
-       CLK(NULL,       "emif1_ick",                    &emif1_ick,     CK_443X),
-       CLK(NULL,       "emif2_ick",                    &emif2_ick,     CK_443X),
+       CLK(NULL,       "efuse_ctrl_cust_fck",          &efuse_ctrl_cust_fck,   CK_443X),
+       CLK(NULL,       "emif1_fck",                    &emif1_fck,     CK_443X),
+       CLK(NULL,       "emif2_fck",                    &emif2_fck,     CK_443X),
        CLK(NULL,       "fdif_fck",                     &fdif_fck,      CK_443X),
-       CLK(NULL,       "per_sgx_fclk",                 &per_sgx_fclk,  CK_443X),
-       CLK(NULL,       "gfx_fck",                      &gfx_fck,       CK_443X),
+       CLK(NULL,       "fpka_fck",                     &fpka_fck,      CK_443X),
+       CLK(NULL,       "gpio1_dbck",                   &gpio1_dbclk,   CK_443X),
        CLK(NULL,       "gpio1_ick",                    &gpio1_ick,     CK_443X),
+       CLK(NULL,       "gpio2_dbck",                   &gpio2_dbclk,   CK_443X),
        CLK(NULL,       "gpio2_ick",                    &gpio2_ick,     CK_443X),
+       CLK(NULL,       "gpio3_dbck",                   &gpio3_dbclk,   CK_443X),
        CLK(NULL,       "gpio3_ick",                    &gpio3_ick,     CK_443X),
+       CLK(NULL,       "gpio4_dbck",                   &gpio4_dbclk,   CK_443X),
        CLK(NULL,       "gpio4_ick",                    &gpio4_ick,     CK_443X),
+       CLK(NULL,       "gpio5_dbck",                   &gpio5_dbclk,   CK_443X),
        CLK(NULL,       "gpio5_ick",                    &gpio5_ick,     CK_443X),
+       CLK(NULL,       "gpio6_dbck",                   &gpio6_dbclk,   CK_443X),
        CLK(NULL,       "gpio6_ick",                    &gpio6_ick,     CK_443X),
        CLK(NULL,       "gpmc_ick",                     &gpmc_ick,      CK_443X),
-       CLK(NULL,       "gpt1_fck",                     &gpt1_fck,      CK_443X),
-       CLK(NULL,       "gpt10_fck",                    &gpt10_fck,     CK_443X),
-       CLK(NULL,       "gpt11_fck",                    &gpt11_fck,     CK_443X),
-       CLK(NULL,       "gpt2_fck",                     &gpt2_fck,      CK_443X),
-       CLK(NULL,       "gpt3_fck",                     &gpt3_fck,      CK_443X),
-       CLK(NULL,       "gpt4_fck",                     &gpt4_fck,      CK_443X),
-       CLK(NULL,       "gpt5_fck",                     &gpt5_fck,      CK_443X),
-       CLK(NULL,       "gpt6_fck",                     &gpt6_fck,      CK_443X),
-       CLK(NULL,       "gpt7_fck",                     &gpt7_fck,      CK_443X),
-       CLK(NULL,       "gpt8_fck",                     &gpt8_fck,      CK_443X),
-       CLK(NULL,       "gpt9_fck",                     &gpt9_fck,      CK_443X),
+       CLK(NULL,       "gpu_fck",                      &gpu_fck,       CK_443X),
        CLK("omap2_hdq.0",      "fck",                          &hdq1w_fck,     CK_443X),
-       CLK(NULL,       "hsi_ick",                      &hsi_ick,       CK_443X),
+       CLK(NULL,       "hsi_fck",                      &hsi_fck,       CK_443X),
        CLK("i2c_omap.1",       "fck",                          &i2c1_fck,      CK_443X),
        CLK("i2c_omap.2",       "fck",                          &i2c2_fck,      CK_443X),
        CLK("i2c_omap.3",       "fck",                          &i2c3_fck,      CK_443X),
        CLK("i2c_omap.4",       "fck",                          &i2c4_fck,      CK_443X),
+       CLK(NULL,       "ipu_fck",                      &ipu_fck,       CK_443X),
+       CLK(NULL,       "iss_ctrlclk",                  &iss_ctrlclk,   CK_443X),
        CLK(NULL,       "iss_fck",                      &iss_fck,       CK_443X),
-       CLK(NULL,       "ivahd_ick",                    &ivahd_ick,     CK_443X),
-       CLK(NULL,       "keyboard_fck",                 &keyboard_fck,  CK_443X),
-       CLK(NULL,       "l3_instr_interconnect_ick",    &l3_instr_interconnect_ick,     CK_443X),
-       CLK(NULL,       "l3_interconnect_3_ick",        &l3_interconnect_3_ick, CK_443X),
+       CLK(NULL,       "iva_fck",                      &iva_fck,       CK_443X),
+       CLK(NULL,       "kbd_fck",                      &kbd_fck,       CK_443X),
+       CLK(NULL,       "l3_instr_ick",                 &l3_instr_ick,  CK_443X),
+       CLK(NULL,       "l3_main_3_ick",                &l3_main_3_ick, CK_443X),
        CLK(NULL,       "mcasp_sync_mux_ck",            &mcasp_sync_mux_ck,     CK_443X),
        CLK(NULL,       "mcasp_fck",                    &mcasp_fck,     CK_443X),
        CLK(NULL,       "mcbsp1_sync_mux_ck",           &mcbsp1_sync_mux_ck,    CK_443X),
@@ -2607,6 +2893,7 @@ static struct omap_clk omap44xx_clks[] = {
        CLK("omap-mcbsp.3",     "fck",                          &mcbsp3_fck,    CK_443X),
        CLK(NULL,       "mcbsp4_sync_mux_ck",           &mcbsp4_sync_mux_ck,    CK_443X),
        CLK("omap-mcbsp.4",     "fck",                          &mcbsp4_fck,    CK_443X),
+       CLK(NULL,       "mcpdm_fck",                    &mcpdm_fck,     CK_443X),
        CLK("omap2_mcspi.1",    "fck",                          &mcspi1_fck,    CK_443X),
        CLK("omap2_mcspi.2",    "fck",                          &mcspi2_fck,    CK_443X),
        CLK("omap2_mcspi.3",    "fck",                          &mcspi3_fck,    CK_443X),
@@ -2616,43 +2903,66 @@ static struct omap_clk omap44xx_clks[] = {
        CLK("mmci-omap-hs.2",   "fck",                          &mmc3_fck,      CK_443X),
        CLK("mmci-omap-hs.3",   "fck",                          &mmc4_fck,      CK_443X),
        CLK("mmci-omap-hs.4",   "fck",                          &mmc5_fck,      CK_443X),
-       CLK(NULL,       "ocp_wp1_ick",                  &ocp_wp1_ick,   CK_443X),
-       CLK(NULL,       "pdm_fck",                      &pdm_fck,       CK_443X),
-       CLK(NULL,       "pkaeip29_fck",                 &pkaeip29_fck,  CK_443X),
+       CLK(NULL,       "ocp2scp_usb_phy_phy_48m",      &ocp2scp_usb_phy_phy_48m,       CK_443X),
+       CLK(NULL,       "ocp2scp_usb_phy_ick",          &ocp2scp_usb_phy_ick,   CK_443X),
+       CLK(NULL,       "ocp_wp_noc_ick",               &ocp_wp_noc_ick,        CK_443X),
        CLK("omap_rng", "ick",                          &rng_ick,       CK_443X),
-       CLK(NULL,       "sha2md51_fck",                 &sha2md51_fck,  CK_443X),
-       CLK(NULL,       "sl2_ick",                      &sl2_ick,       CK_443X),
+       CLK(NULL,       "sha2md5_fck",                  &sha2md5_fck,   CK_443X),
+       CLK(NULL,       "sl2if_ick",                    &sl2if_ick,     CK_443X),
+       CLK(NULL,       "slimbus1_fclk_1",              &slimbus1_fclk_1,       CK_443X),
+       CLK(NULL,       "slimbus1_fclk_0",              &slimbus1_fclk_0,       CK_443X),
+       CLK(NULL,       "slimbus1_fclk_2",              &slimbus1_fclk_2,       CK_443X),
+       CLK(NULL,       "slimbus1_slimbus_clk",         &slimbus1_slimbus_clk,  CK_443X),
        CLK(NULL,       "slimbus1_fck",                 &slimbus1_fck,  CK_443X),
+       CLK(NULL,       "slimbus2_fclk_1",              &slimbus2_fclk_1,       CK_443X),
+       CLK(NULL,       "slimbus2_fclk_0",              &slimbus2_fclk_0,       CK_443X),
+       CLK(NULL,       "slimbus2_slimbus_clk",         &slimbus2_slimbus_clk,  CK_443X),
        CLK(NULL,       "slimbus2_fck",                 &slimbus2_fck,  CK_443X),
-       CLK(NULL,       "sr_core_fck",                  &sr_core_fck,   CK_443X),
-       CLK(NULL,       "sr_iva_fck",                   &sr_iva_fck,    CK_443X),
-       CLK(NULL,       "sr_mpu_fck",                   &sr_mpu_fck,    CK_443X),
-       CLK(NULL,       "tesla_ick",                    &tesla_ick,     CK_443X),
+       CLK(NULL,       "smartreflex_core_fck",         &smartreflex_core_fck,  CK_443X),
+       CLK(NULL,       "smartreflex_iva_fck",          &smartreflex_iva_fck,   CK_443X),
+       CLK(NULL,       "smartreflex_mpu_fck",          &smartreflex_mpu_fck,   CK_443X),
+       CLK(NULL,       "gpt1_fck",                     &timer1_fck,    CK_443X),
+       CLK(NULL,       "gpt10_fck",                    &timer10_fck,   CK_443X),
+       CLK(NULL,       "gpt11_fck",                    &timer11_fck,   CK_443X),
+       CLK(NULL,       "gpt2_fck",                     &timer2_fck,    CK_443X),
+       CLK(NULL,       "gpt3_fck",                     &timer3_fck,    CK_443X),
+       CLK(NULL,       "gpt4_fck",                     &timer4_fck,    CK_443X),
+       CLK(NULL,       "gpt5_fck",                     &timer5_fck,    CK_443X),
+       CLK(NULL,       "gpt6_fck",                     &timer6_fck,    CK_443X),
+       CLK(NULL,       "gpt7_fck",                     &timer7_fck,    CK_443X),
+       CLK(NULL,       "gpt8_fck",                     &timer8_fck,    CK_443X),
+       CLK(NULL,       "gpt9_fck",                     &timer9_fck,    CK_443X),
        CLK(NULL,       "uart1_fck",                    &uart1_fck,     CK_443X),
        CLK(NULL,       "uart2_fck",                    &uart2_fck,     CK_443X),
        CLK(NULL,       "uart3_fck",                    &uart3_fck,     CK_443X),
        CLK(NULL,       "uart4_fck",                    &uart4_fck,     CK_443X),
-       CLK(NULL,       "unipro1_fck",                  &unipro1_fck,   CK_443X),
-       CLK(NULL,       "usb_host_fck",                 &usb_host_fck,  CK_443X),
        CLK(NULL,       "usb_host_fs_fck",              &usb_host_fs_fck,       CK_443X),
-       CLK("musb_hdrc",        "ick",                          &usb_otg_ick,   CK_443X),
-       CLK(NULL,       "usb_tll_ick",                  &usb_tll_ick,   CK_443X),
-       CLK(NULL,       "usbphyocp2scp_ick",            &usbphyocp2scp_ick,     CK_443X),
+       CLK(NULL,       "usb_host_hs_utmi_p3_clk",      &usb_host_hs_utmi_p3_clk,       CK_443X),
+       CLK(NULL,       "usb_host_hs_hsic60m_p1_clk",   &usb_host_hs_hsic60m_p1_clk,    CK_443X),
+       CLK(NULL,       "usb_host_hs_hsic60m_p2_clk",   &usb_host_hs_hsic60m_p2_clk,    CK_443X),
+       CLK(NULL,       "utmi_p1_gfclk",                &utmi_p1_gfclk, CK_443X),
+       CLK(NULL,       "usb_host_hs_utmi_p1_clk",      &usb_host_hs_utmi_p1_clk,       CK_443X),
+       CLK(NULL,       "utmi_p2_gfclk",                &utmi_p2_gfclk, CK_443X),
+       CLK(NULL,       "usb_host_hs_utmi_p2_clk",      &usb_host_hs_utmi_p2_clk,       CK_443X),
+       CLK(NULL,       "usb_host_hs_hsic480m_p1_clk",  &usb_host_hs_hsic480m_p1_clk,   CK_443X),
+       CLK(NULL,       "usb_host_hs_hsic480m_p2_clk",  &usb_host_hs_hsic480m_p2_clk,   CK_443X),
+       CLK(NULL,       "usb_host_hs_func48mclk",       &usb_host_hs_func48mclk,        CK_443X),
+       CLK(NULL,       "usb_host_hs_fck",              &usb_host_hs_fck,       CK_443X),
+       CLK(NULL,       "otg_60m_gfclk",                &otg_60m_gfclk, CK_443X),
+       CLK(NULL,       "usb_otg_hs_xclk",              &usb_otg_hs_xclk,       CK_443X),
+       CLK("musb_hdrc",        "ick",                          &usb_otg_hs_ick,        CK_443X),
+       CLK(NULL,       "usb_phy_cm_clk32k",            &usb_phy_cm_clk32k,     CK_443X),
+       CLK(NULL,       "usb_tll_hs_usb_ch2_clk",       &usb_tll_hs_usb_ch2_clk,        CK_443X),
+       CLK(NULL,       "usb_tll_hs_usb_ch0_clk",       &usb_tll_hs_usb_ch0_clk,        CK_443X),
+       CLK(NULL,       "usb_tll_hs_usb_ch1_clk",       &usb_tll_hs_usb_ch1_clk,        CK_443X),
+       CLK(NULL,       "usb_tll_hs_ick",               &usb_tll_hs_ick,        CK_443X),
+       CLK(NULL,       "usim_ck",                      &usim_ck,       CK_443X),
+       CLK(NULL,       "usim_fclk",                    &usim_fclk,     CK_443X),
        CLK(NULL,       "usim_fck",                     &usim_fck,      CK_443X),
-       CLK("omap_wdt", "fck",                          &wdt2_fck,      CK_443X),
-       CLK(NULL,       "wdt3_fck",                     &wdt3_fck,      CK_443X),
-       CLK(NULL,       "otg_60m_gfclk_ck",             &otg_60m_gfclk_ck,      CK_443X),
+       CLK("omap_wdt", "fck",                          &wd_timer2_fck, CK_443X),
+       CLK(NULL,       "wd_timer3_fck",                &wd_timer3_fck, CK_443X),
        CLK(NULL,       "stm_clk_div_ck",               &stm_clk_div_ck,        CK_443X),
        CLK(NULL,       "trace_clk_div_ck",             &trace_clk_div_ck,      CK_443X),
-       CLK(NULL,       "usim_fclk",                    &usim_fclk,     CK_443X),
-       CLK(NULL,       "utmi_p1_gfclk_ck",             &utmi_p1_gfclk_ck,      CK_443X),
-       CLK(NULL,       "utmi_p2_gfclk_ck",             &utmi_p2_gfclk_ck,      CK_443X),
-       CLK(NULL,       "gpio1_dbck",                   &dummy_ck,      CK_443X),
-       CLK(NULL,       "gpio2_dbck",                   &dummy_ck,      CK_443X),
-       CLK(NULL,       "gpio3_dbck",                   &dummy_ck,      CK_443X),
-       CLK(NULL,       "gpio4_dbck",                   &dummy_ck,      CK_443X),
-       CLK(NULL,       "gpio5_dbck",                   &dummy_ck,      CK_443X),
-       CLK(NULL,       "gpio6_dbck",                   &dummy_ck,      CK_443X),
        CLK(NULL,       "gpmc_ck",                      &dummy_ck,      CK_443X),
        CLK(NULL,       "gpt1_ick",                     &dummy_ck,      CK_443X),
        CLK(NULL,       "gpt2_ick",                     &dummy_ck,      CK_443X),
@@ -2669,19 +2979,19 @@ static struct omap_clk omap44xx_clks[] = {
        CLK("i2c_omap.2",       "ick",                          &dummy_ck,      CK_443X),
        CLK("i2c_omap.3",       "ick",                          &dummy_ck,      CK_443X),
        CLK("i2c_omap.4",       "ick",                          &dummy_ck,      CK_443X),
+       CLK("mmci-omap-hs.0",   "ick",                          &dummy_ck,      CK_443X),
+       CLK("mmci-omap-hs.1",   "ick",                          &dummy_ck,      CK_443X),
+       CLK("mmci-omap-hs.2",   "ick",                          &dummy_ck,      CK_443X),
+       CLK("mmci-omap-hs.3",   "ick",                          &dummy_ck,      CK_443X),
+       CLK("mmci-omap-hs.4",   "ick",                          &dummy_ck,      CK_443X),
        CLK("omap-mcbsp.1",     "ick",                          &dummy_ck,      CK_443X),
        CLK("omap-mcbsp.2",     "ick",                          &dummy_ck,      CK_443X),
        CLK("omap-mcbsp.3",     "ick",                          &dummy_ck,      CK_443X),
        CLK("omap-mcbsp.4",     "ick",                          &dummy_ck,      CK_443X),
-       CLK("omap2_mcspi.1",    "ick",                  &dummy_ck,      CK_443X),
-       CLK("omap2_mcspi.2",    "ick",                  &dummy_ck,      CK_443X),
-       CLK("omap2_mcspi.3",    "ick",                  &dummy_ck,      CK_443X),
-       CLK("omap2_mcspi.4",    "ick",                  &dummy_ck,      CK_443X),
-       CLK("mmci-omap-hs.0",   "ick",          &dummy_ck,      CK_443X),
-       CLK("mmci-omap-hs.1",   "ick",          &dummy_ck,      CK_443X),
-       CLK("mmci-omap-hs.2",   "ick",          &dummy_ck,      CK_443X),
-       CLK("mmci-omap-hs.3",   "ick",          &dummy_ck,      CK_443X),
-       CLK("mmci-omap-hs.4",   "ick",          &dummy_ck,      CK_443X),
+       CLK("omap2_mcspi.1",    "ick",                          &dummy_ck,      CK_443X),
+       CLK("omap2_mcspi.2",    "ick",                          &dummy_ck,      CK_443X),
+       CLK("omap2_mcspi.3",    "ick",                          &dummy_ck,      CK_443X),
+       CLK("omap2_mcspi.4",    "ick",                          &dummy_ck,      CK_443X),
        CLK(NULL,       "uart1_ick",                    &dummy_ck,      CK_443X),
        CLK(NULL,       "uart2_ick",                    &dummy_ck,      CK_443X),
        CLK(NULL,       "uart3_ick",                    &dummy_ck,      CK_443X),
index 5d80cb897489505839a847c460cc9ade5e1bb05b..6fb61b1a0d46105f7d18fb8434d3d91caaa4be41 100644 (file)
@@ -258,97 +258,6 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
 
 }
 
-/**
- * _init_wkdep_usecount - initialize wkdep usecounts to match hardware
- * @clkdm: clockdomain to initialize wkdep usecounts
- *
- * Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
- * If a wakeup dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0.  Software should clear all
- * software wakeup dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0.  No return value.
- */
-static void _init_wkdep_usecount(struct clockdomain *clkdm)
-{
-       u32 v;
-       struct clkdm_dep *cd;
-
-       if (!clkdm->wkdep_srcs)
-               return;
-
-       for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
-               if (!omap_chip_is(cd->omap_chip))
-                       continue;
-
-               if (!cd->clkdm && cd->clkdm_name)
-                       cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
-               if (!cd->clkdm) {
-                       WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
-                            "found\n", clkdm->name, cd->clkdm_name);
-                       continue;
-               }
-
-               v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
-                                           PM_WKDEP,
-                                           (1 << cd->clkdm->dep_bit));
-
-               if (v)
-                       pr_debug("clockdomain: %s: wakeup dependency already "
-                                "set to wake up when %s wakes\n",
-                                clkdm->name, cd->clkdm->name);
-
-               atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
-       }
-}
-
-/**
- * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
- * @clkdm: clockdomain to initialize sleepdep usecounts
- *
- * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
- * If a sleep dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0.  Software should clear all
- * software sleep dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0.  No return value.
- */
-static void _init_sleepdep_usecount(struct clockdomain *clkdm)
-{
-       u32 v;
-       struct clkdm_dep *cd;
-
-       if (!cpu_is_omap34xx())
-               return;
-
-       if (!clkdm->sleepdep_srcs)
-               return;
-
-       for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
-               if (!omap_chip_is(cd->omap_chip))
-                       continue;
-
-               if (!cd->clkdm && cd->clkdm_name)
-                       cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
-               if (!cd->clkdm) {
-                       WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
-                            "not found\n", clkdm->name, cd->clkdm_name);
-                       continue;
-               }
-
-               v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
-                                           OMAP3430_CM_SLEEPDEP,
-                                           (1 << cd->clkdm->dep_bit));
-
-               if (v)
-                       pr_debug("clockdomain: %s: sleep dependency already "
-                                "set to prevent from idling until %s "
-                                "idles\n", clkdm->name, cd->clkdm->name);
-
-               atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
-       }
-};
-
 /* Public functions */
 
 /**
@@ -379,12 +288,17 @@ void clkdm_init(struct clockdomain **clkdms,
                        _autodep_lookup(autodep);
 
        /*
-        * Ensure that the *dep_usecount registers reflect the current
-        * state of the PRCM.
+        * Put all clockdomains into software-supervised mode; PM code
+        * should later enable hardware-supervised mode as appropriate
         */
        list_for_each_entry(clkdm, &clkdm_list, node) {
-               _init_wkdep_usecount(clkdm);
-               _init_sleepdep_usecount(clkdm);
+               if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+                       omap2_clkdm_wakeup(clkdm);
+               else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
+                       omap2_clkdm_deny_idle(clkdm);
+
+               clkdm_clear_all_wkdeps(clkdm);
+               clkdm_clear_all_sleepdeps(clkdm);
        }
 }
 
@@ -592,6 +506,9 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
                if (!omap_chip_is(cd->omap_chip))
                        continue;
 
+               if (!cd->clkdm && cd->clkdm_name)
+                       cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
                /* PRM accesses are slow, so minimize them */
                mask |= 1 << cd->clkdm->dep_bit;
                atomic_set(&cd->wkdep_usecount, 0);
@@ -752,6 +669,9 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
                if (!omap_chip_is(cd->omap_chip))
                        continue;
 
+               if (!cd->clkdm && cd->clkdm_name)
+                       cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
                /* PRM accesses are slow, so minimize them */
                mask |= 1 << cd->clkdm->dep_bit;
                atomic_set(&cd->sleepdep_usecount, 0);
index fe82b79d5f3b8ac44cfadefd5f658d4a9b4977b0..4f959a7d881c82712557f58f2f0115d358af868a 100644 (file)
 #define OMAP3430_ST_MCBSP2_MASK                                (1 << 0)
 
 /* CM_AUTOIDLE_PER */
+#define OMAP3630_AUTO_UART4_MASK                       (1 << 18)
+#define OMAP3630_AUTO_UART4_SHIFT                      18
 #define OMAP3430_AUTO_GPIO6_MASK                       (1 << 17)
 #define OMAP3430_AUTO_GPIO6_SHIFT                      17
 #define OMAP3430_AUTO_GPIO5_MASK                       (1 << 16)
index ac8458e43252ad486bf46dd71c5556d237f0e66b..0b72be43377664e710c5f38d91b968e71feaac3a 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * OMAP44xx Clock Management register bits
  *
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul@pwsan.com)
  * Rajendra Nayak (rnayak@ti.com)
 #include "cm.h"
 
 
-/* Used by CM_L3_1_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/*
+ * Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP,
+ * CM_TESLA_DYNAMICDEP
+ */
 #define OMAP4430_ABE_DYNDEP_SHIFT                              3
-#define OMAP4430_ABE_DYNDEP_MASK                               BITFIELD(3, 3)
+#define OMAP4430_ABE_DYNDEP_MASK                               (1 << 3)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_ABE_STATDEP_SHIFT                             3
-#define OMAP4430_ABE_STATDEP_MASK                              BITFIELD(3, 3)
+#define OMAP4430_ABE_STATDEP_MASK                              (1 << 3)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_ALWONCORE_DYNDEP_SHIFT                                16
-#define OMAP4430_ALWONCORE_DYNDEP_MASK                         BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_DYNDEP_MASK                         (1 << 16)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
 #define OMAP4430_ALWONCORE_STATDEP_SHIFT                       16
-#define OMAP4430_ALWONCORE_STATDEP_MASK                                BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_STATDEP_MASK                                (1 << 16)
 
 /*
- * Used by CM_AUTOIDLE_DPLL_PER, CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB,
- * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
- * CM_AUTOIDLE_DPLL_DDRPHY, CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU
+ * Used by CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
+ * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_DDRPHY,
+ * CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU, CM_AUTOIDLE_DPLL_PER,
+ * CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB
  */
 #define OMAP4430_AUTO_DPLL_MODE_SHIFT                          0
-#define OMAP4430_AUTO_DPLL_MODE_MASK                           BITFIELD(0, 2)
+#define OMAP4430_AUTO_DPLL_MODE_MASK                           (0x7 << 0)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_CEFUSE_DYNDEP_SHIFT                           17
-#define OMAP4430_CEFUSE_DYNDEP_MASK                            BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_DYNDEP_MASK                            (1 << 17)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
 #define OMAP4430_CEFUSE_STATDEP_SHIFT                          17
-#define OMAP4430_CEFUSE_STATDEP_MASK                           BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_STATDEP_MASK                           (1 << 17)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_SHIFT               13
-#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK                        BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK                        (1 << 13)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_SHIFT           12
-#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK            BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK            (1 << 12)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_LP_CLK_SHIFT                  9
-#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK                   BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK                   (1 << 9)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_SYSCLK_SHIFT                  11
-#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK                   BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK                   (1 << 11)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_X2_CLK_SHIFT                  8
-#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK                   BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK                   (1 << 8)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_SHIFT               11
-#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK                        BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK                        (1 << 11)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_SHIFT              12
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK               BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK               (1 << 12)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_SHIFT              13
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK               BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK               (1 << 13)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_SHIFT           9
-#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK            BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK            (1 << 9)
+
+/* Used by CM_ALWON_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_SHIFT                12
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_MASK         (1 << 12)
 
 /* Used by CM_EMU_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT           9
-#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK            BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK            (1 << 9)
 
 /* Used by CM_CEFUSE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT          9
-#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK           BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK           (1 << 9)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DLL_CLK_SHIFT                     9
-#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK                      BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK                      (1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT10_GFCLK_SHIFT                 9
-#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK                  BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK                  (1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT11_GFCLK_SHIFT                 10
-#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK                  BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK                  (1 << 10)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT2_GFCLK_SHIFT                  11
-#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK                   BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK                   (1 << 11)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT3_GFCLK_SHIFT                  12
-#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK                   BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK                   (1 << 12)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT4_GFCLK_SHIFT                  13
-#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK                   BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK                   (1 << 13)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT9_GFCLK_SHIFT                  14
-#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK                   BITFIELD(14, 14)
+#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK                   (1 << 14)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_SHIFT           10
-#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK            BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK            (1 << 10)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DSS_FCLK_SHIFT                    9
-#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK                     BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK                     (1 << 9)
 
 /* Used by CM_DUCATI_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DUCATI_GCLK_SHIFT                 8
-#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK                  BITFIELD(8, 8)
-
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_SHIFT              10
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_MASK               BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK                  (1 << 8)
 
 /* Used by CM_EMU_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_SHIFT                 8
-#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK                  BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK                  (1 << 8)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_FDIF_GFCLK_SHIFT                  10
-#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK                   BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK                   (1 << 10)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_SHIFT              15
-#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK               BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK               (1 << 15)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_SHIFT              10
-#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK               BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK               (1 << 10)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_SHIFT                11
-#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK         BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK         (1 << 11)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_SHIFT          20
-#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK           BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK           (1 << 20)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_SHIFT               26
-#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK                        BITFIELD(26, 26)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK                        (1 << 26)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_SHIFT          21
-#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK           BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK           (1 << 21)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_SHIFT               27
-#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK                        BITFIELD(27, 27)
-
-/* Used by CM_L3INIT_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_SHIFT              31
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_MASK               BITFIELD(31, 31)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK                        (1 << 27)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_SHIFT             13
-#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK              BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK              (1 << 13)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_SHIFT              12
-#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK               BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK               (1 << 12)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_SHIFT           28
-#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK            BITFIELD(28, 28)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK            (1 << 28)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_SHIFT           29
-#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK            BITFIELD(29, 29)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK            (1 << 29)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_SHIFT              11
-#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK               BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK               (1 << 11)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_SHIFT              16
-#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK               BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK               (1 << 16)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_SHIFT           17
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK            BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK            (1 << 17)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_SHIFT           18
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK            BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK            (1 << 18)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_SHIFT           19
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK            BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK            (1 << 19)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ISS_GCLK_SHIFT                    8
-#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK                     BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK                     (1 << 8)
 
 /* Used by CM_IVAHD_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_SHIFT              8
-#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK               BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK               (1 << 8)
 
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_SHIFT       14
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_MASK                BITFIELD(14, 14)
+/* Used by CM_D2D_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_SHIFT              10
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_MASK               (1 << 10)
 
 /* Used by CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_1_GICLK_SHIFT                  8
-#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK                   BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK                   (1 << 8)
 
 /* Used by CM_L3_2_CLKSTCTRL, CM_L3_2_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_2_GICLK_SHIFT                  8
-#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK                   BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK                   (1 << 8)
 
 /* Used by CM_D2D_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_SDMA_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_SHIFT               8
-#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK                        BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK                        (1 << 8)
 
 /* Used by CM_GFX_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_SHIFT               8
-#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK                        BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK                        (1 << 8)
 
 /* Used by CM_L3INSTR_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_SHIFT              8
-#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK               BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK               (1 << 8)
 
 /* Used by CM_L4SEC_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_SHIFT             8
-#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK              BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK              (1 << 8)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_AO_ICLK_SHIFT                  8
-#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK                   BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK                   (1 << 8)
 
 /* Used by CM_CEFUSE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_SHIFT             8
-#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK              BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK              (1 << 8)
 
 /* Used by CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_D2D_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_SHIFT                        9
-#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK                 BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK                 (1 << 9)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_SHIFT               9
-#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK                        BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK                        (1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_PER_GICLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK                 (1 << 8)
 
 /* Used by CM_L4SEC_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_SHIFT             9
-#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK              BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK              (1 << 9)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_SHIFT               12
-#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK                        BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK                        (1 << 12)
 
 /* Used by CM_MPU_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_SHIFT                        8
-#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK                 BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK                 (1 << 8)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_SHIFT               9
-#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK                        BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK                        (1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_SHIFT              16
-#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK               BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK               (1 << 16)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_SHIFT               17
-#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK                        BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK                        (1 << 17)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_SHIFT               18
-#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK                        BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK                        (1 << 18)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_SHIFT               19
-#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK                        BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK                        (1 << 19)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_SHIFT           25
-#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK            BITFIELD(25, 25)
-
-/* Used by CM_EMU_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_SHIFT            10
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_MASK             BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK            (1 << 25)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_SHIFT            20
-#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK             BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK             (1 << 20)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_SHIFT            21
-#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK             BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK             (1 << 21)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_SHIFT            22
-#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK             BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK             (1 << 22)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_SHIFT               24
-#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK                        BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK                        (1 << 24)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_SHIFT                        10
-#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK                 BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK                 (1 << 10)
 
 /* Used by CM_GFX_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SGX_GFCLK_SHIFT                   9
-#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK                    BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK                    (1 << 9)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_SHIFT              11
-#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK               BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK               (1 << 11)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_SHIFT               10
-#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK                        BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK                        (1 << 10)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_SHIFT               9
-#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK                        BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK                        (1 << 9)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SYS_CLK_SHIFT                     8
-#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK                      BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK                      (1 << 8)
 
 /* Used by CM_TESLA_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_SHIFT              8
-#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK               BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK               (1 << 8)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_SHIFT               22
-#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK                        BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK                        (1 << 22)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_SHIFT               23
-#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK                        BITFIELD(23, 23)
+#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK                        (1 << 23)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_SHIFT               24
-#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK                        BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK                        (1 << 24)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_SHIFT             10
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_MASK              (1 << 10)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_SHIFT                        14
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_MASK                 (1 << 14)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_SHIFT             15
-#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK              BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK              (1 << 15)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_USIM_GFCLK_SHIFT                  10
-#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK                   BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK                   (1 << 10)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_SHIFT               30
-#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK                        BITFIELD(30, 30)
+#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK                        (1 << 30)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_SHIFT             25
-#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK              BITFIELD(25, 25)
+#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK              (1 << 25)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT              11
-#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK               BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK               (1 << 11)
 
 /*
- * Used by CM_WKUP_TIMER1_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
+ * Used by CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL,
+ * CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL,
+ * CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
  * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
  * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
  * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL,
- * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
- * CM1_ABE_TIMER8_CLKCTRL
+ * CM_WKUP_TIMER1_CLKCTRL
  */
 #define OMAP4430_CLKSEL_SHIFT                                  24
-#define OMAP4430_CLKSEL_MASK                                   BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_MASK                                   (1 << 24)
 
 /*
  * Renamed from CLKSEL Used by CM_ABE_DSS_SYS_CLKSEL, CM_ABE_PLL_REF_CLKSEL,
- * CM_DPLL_SYS_REF_CLKSEL, CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT,
- * CM_CLKSEL_USB_60MHZ
+ * CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT, CM_CLKSEL_USB_60MHZ
  */
 #define OMAP4430_CLKSEL_0_0_SHIFT                              0
-#define OMAP4430_CLKSEL_0_0_MASK                               BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_0_0_MASK                               (1 << 0)
 
 /* Renamed from CLKSEL Used by CM_BYPCLK_DPLL_IVA, CM_BYPCLK_DPLL_MPU */
 #define OMAP4430_CLKSEL_0_1_SHIFT                              0
-#define OMAP4430_CLKSEL_0_1_MASK                               BITFIELD(0, 1)
+#define OMAP4430_CLKSEL_0_1_MASK                               (0x3 << 0)
 
 /* Renamed from CLKSEL Used by CM_L3INIT_HSI_CLKCTRL */
 #define OMAP4430_CLKSEL_24_25_SHIFT                            24
-#define OMAP4430_CLKSEL_24_25_MASK                             BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_24_25_MASK                             (0x3 << 24)
 
 /* Used by CM_L3INIT_USB_OTG_CLKCTRL */
 #define OMAP4430_CLKSEL_60M_SHIFT                              24
-#define OMAP4430_CLKSEL_60M_MASK                               BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_60M_MASK                               (1 << 24)
 
 /* Used by CM1_ABE_AESS_CLKCTRL */
 #define OMAP4430_CLKSEL_AESS_FCLK_SHIFT                                24
-#define OMAP4430_CLKSEL_AESS_FCLK_MASK                         BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_AESS_FCLK_MASK                         (1 << 24)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_CORE_SHIFT                             0
-#define OMAP4430_CLKSEL_CORE_MASK                              BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_CORE_MASK                              (1 << 0)
 
-/* Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
 #define OMAP4430_CLKSEL_CORE_1_1_SHIFT                         1
-#define OMAP4430_CLKSEL_CORE_1_1_MASK                          BITFIELD(1, 1)
+#define OMAP4430_CLKSEL_CORE_1_1_MASK                          (1 << 1)
 
 /* Used by CM_WKUP_USIM_CLKCTRL */
 #define OMAP4430_CLKSEL_DIV_SHIFT                              24
-#define OMAP4430_CLKSEL_DIV_MASK                               BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_DIV_MASK                               (1 << 24)
 
 /* Used by CM_CAM_FDIF_CLKCTRL */
 #define OMAP4430_CLKSEL_FCLK_SHIFT                             24
-#define OMAP4430_CLKSEL_FCLK_MASK                              BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_FCLK_MASK                              (0x3 << 24)
 
 /* Used by CM_L4PER_MCBSP4_CLKCTRL */
 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT                  25
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK                   BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK                   (1 << 25)
 
 /*
  * Renamed from CLKSEL_INTERNAL_SOURCE Used by CM1_ABE_DMIC_CLKCTRL,
  * CM1_ABE_MCBSP3_CLKCTRL
  */
 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_SHIFT     26
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK      BITFIELD(26, 27)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK      (0x3 << 26)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_L3_SHIFT                               4
-#define OMAP4430_CLKSEL_L3_MASK                                        BITFIELD(4, 4)
+#define OMAP4430_CLKSEL_L3_MASK                                        (1 << 4)
 
-/* Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
 #define OMAP4430_CLKSEL_L3_SHADOW_SHIFT                                2
-#define OMAP4430_CLKSEL_L3_SHADOW_MASK                         BITFIELD(2, 2)
+#define OMAP4430_CLKSEL_L3_SHADOW_MASK                         (1 << 2)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_L4_SHIFT                               8
-#define OMAP4430_CLKSEL_L4_MASK                                        BITFIELD(8, 8)
+#define OMAP4430_CLKSEL_L4_MASK                                        (1 << 8)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_CLKSEL_OPP_SHIFT                              0
-#define OMAP4430_CLKSEL_OPP_MASK                               BITFIELD(0, 1)
-
-/* Used by CM_GFX_GFX_CLKCTRL */
-#define OMAP4430_CLKSEL_PER_192M_SHIFT                         25
-#define OMAP4430_CLKSEL_PER_192M_MASK                          BITFIELD(25, 26)
+#define OMAP4430_CLKSEL_OPP_MASK                               (0x3 << 0)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT                      27
-#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK                       BITFIELD(27, 29)
+#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK                       (0x7 << 27)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_CLKSEL_PMD_TRACE_CLK_SHIFT                    24
-#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK                     BITFIELD(24, 26)
+#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK                     (0x7 << 24)
 
 /* Used by CM_GFX_GFX_CLKCTRL */
 #define OMAP4430_CLKSEL_SGX_FCLK_SHIFT                         24
-#define OMAP4430_CLKSEL_SGX_FCLK_MASK                          BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SGX_FCLK_MASK                          (1 << 24)
 
 /*
  * Used by CM1_ABE_DMIC_CLKCTRL, CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL,
  * CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL
  */
 #define OMAP4430_CLKSEL_SOURCE_SHIFT                           24
-#define OMAP4430_CLKSEL_SOURCE_MASK                            BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_SOURCE_MASK                            (0x3 << 24)
 
 /* Renamed from CLKSEL_SOURCE Used by CM_L4PER_MCBSP4_CLKCTRL */
 #define OMAP4430_CLKSEL_SOURCE_24_24_SHIFT                     24
-#define OMAP4430_CLKSEL_SOURCE_24_24_MASK                      BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SOURCE_24_24_MASK                      (1 << 24)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_CLKSEL_UTMI_P1_SHIFT                          24
-#define OMAP4430_CLKSEL_UTMI_P1_MASK                           BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_UTMI_P1_MASK                           (1 << 24)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_CLKSEL_UTMI_P2_SHIFT                          25
-#define OMAP4430_CLKSEL_UTMI_P2_MASK                           BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_UTMI_P2_MASK                           (1 << 25)
 
 /*
- * Used by CM_WKUP_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_D2D_CLKSTCTRL,
- * CM_DUCATI_CLKSTCTRL, CM_L3INSTR_CLKSTCTRL, CM_L3_1_CLKSTCTRL,
- * CM_L3_2_CLKSTCTRL, CM_L4CFG_CLKSTCTRL, CM_MEMIF_CLKSTCTRL,
- * CM_SDMA_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_L4PER_CLKSTCTRL, CM_L4SEC_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL, CM_CAM_CLKSTCTRL, CM_CEFUSE_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3_1_CLKSTCTRL_RESTORE,
- * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL_RESTORE,
- * CM_L4PER_CLKSTCTRL_RESTORE, CM_MEMIF_CLKSTCTRL_RESTORE, CM_ALWON_CLKSTCTRL,
- * CM_IVAHD_CLKSTCTRL, CM_DSS_CLKSTCTRL, CM_MPU_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
- * CM1_ABE_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE
+ * Used by CM1_ABE_CLKSTCTRL, CM_ALWON_CLKSTCTRL, CM_CAM_CLKSTCTRL,
+ * CM_CEFUSE_CLKSTCTRL, CM_D2D_CLKSTCTRL, CM_DSS_CLKSTCTRL,
+ * CM_DUCATI_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_IVAHD_CLKSTCTRL,
+ * CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3INSTR_CLKSTCTRL,
+ * CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE, CM_L3_2_CLKSTCTRL,
+ * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE,
+ * CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE, CM_L4SEC_CLKSTCTRL,
+ * CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE, CM_MPU_CLKSTCTRL,
+ * CM_MPU_CLKSTCTRL_RESTORE, CM_SDMA_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
+ * CM_WKUP_CLKSTCTRL
  */
 #define OMAP4430_CLKTRCTRL_SHIFT                               0
-#define OMAP4430_CLKTRCTRL_MASK                                        BITFIELD(0, 1)
+#define OMAP4430_CLKTRCTRL_MASK                                        (0x3 << 0)
 
 /* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_CORE_DPLL_EMU_DIV_SHIFT                       0
-#define OMAP4430_CORE_DPLL_EMU_DIV_MASK                                BITFIELD(0, 6)
+#define OMAP4430_CORE_DPLL_EMU_DIV_MASK                                (0x7f << 0)
 
 /* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_CORE_DPLL_EMU_MULT_SHIFT                      8
-#define OMAP4430_CORE_DPLL_EMU_MULT_MASK                       BITFIELD(8, 18)
+#define OMAP4430_CORE_DPLL_EMU_MULT_MASK                       (0x7ff << 8)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_CUSTOM_SHIFT                                  6
+#define OMAP4430_CUSTOM_MASK                                   (0x3 << 6)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_D2D_DYNDEP_SHIFT                              18
-#define OMAP4430_D2D_DYNDEP_MASK                               BITFIELD(18, 18)
+#define OMAP4430_D2D_DYNDEP_MASK                               (1 << 18)
 
 /* Used by CM_MPU_STATICDEP */
 #define OMAP4430_D2D_STATDEP_SHIFT                             18
-#define OMAP4430_D2D_STATDEP_MASK                              BITFIELD(18, 18)
+#define OMAP4430_D2D_STATDEP_MASK                              (1 << 18)
 
 /*
- * Used by CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
- * CM_SSC_DELTAMSTEP_DPLL_USB, CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE,
- * CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
- * CM_SSC_DELTAMSTEP_DPLL_DDRPHY, CM_SSC_DELTAMSTEP_DPLL_IVA,
- * CM_SSC_DELTAMSTEP_DPLL_MPU
+ * Used by CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
+ * CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE, CM_SSC_DELTAMSTEP_DPLL_DDRPHY,
+ * CM_SSC_DELTAMSTEP_DPLL_IVA, CM_SSC_DELTAMSTEP_DPLL_MPU,
+ * CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
+ * CM_SSC_DELTAMSTEP_DPLL_USB
  */
 #define OMAP4430_DELTAMSTEP_SHIFT                              0
-#define OMAP4430_DELTAMSTEP_MASK                               BITFIELD(0, 19)
+#define OMAP4430_DELTAMSTEP_MASK                               (0xfffff << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DLL_OVERRIDE_SHIFT                            2
-#define OMAP4430_DLL_OVERRIDE_MASK                             BITFIELD(2, 2)
+#define OMAP4430_DLL_OVERRIDE_MASK                             (1 << 2)
 
 /* Renamed from DLL_OVERRIDE Used by CM_DLL_CTRL */
 #define OMAP4430_DLL_OVERRIDE_0_0_SHIFT                                0
-#define OMAP4430_DLL_OVERRIDE_0_0_MASK                         BITFIELD(0, 0)
+#define OMAP4430_DLL_OVERRIDE_0_0_MASK                         (1 << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DLL_RESET_SHIFT                               3
-#define OMAP4430_DLL_RESET_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_DLL_RESET_MASK                                        (1 << 3)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO, CM_CLKSEL_DPLL_USB,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
+ * CM_CLKSEL_DPLL_USB
  */
 #define OMAP4430_DPLL_BYP_CLKSEL_SHIFT                         23
-#define OMAP4430_DPLL_BYP_CLKSEL_MASK                          BITFIELD(23, 23)
+#define OMAP4430_DPLL_BYP_CLKSEL_MASK                          (1 << 23)
 
 /* Used by CM_CLKDCOLDO_DPLL_USB */
 #define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT                        8
-#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK                 BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK                 (1 << 8)
 
-/* Used by CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_CORE */
+/* Used by CM_CLKSEL_DPLL_CORE, CM_CLKSEL_DPLL_CORE_RESTORE */
 #define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_SHIFT                   20
-#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK                    BITFIELD(20, 20)
+#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK                    (1 << 20)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_DIV_SHIFT                      0
-#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK                       BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK                       (0x1f << 0)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_SHIFT                 5
-#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK                  BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK                  (1 << 5)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT                        8
-#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK                 BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK                 (1 << 8)
 
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
 #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_SHIFT                 10
-#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK                  BITFIELD(10, 10)
+#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK                  (1 << 10)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_CLKOUT_DIV_SHIFT                         0
-#define OMAP4430_DPLL_CLKOUT_DIV_MASK                          BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUT_DIV_MASK                          (0x1f << 0)
 
 /* Renamed from DPLL_CLKOUT_DIV Used by CM_DIV_M2_DPLL_USB */
 #define OMAP4430_DPLL_CLKOUT_DIV_0_6_SHIFT                     0
-#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK                      BITFIELD(0, 6)
+#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK                      (0x7f << 0)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_SHIFT                    5
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK                     BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK                     (1 << 5)
 
 /* Renamed from DPLL_CLKOUT_DIVCHACK Used by CM_DIV_M2_DPLL_USB */
 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_SHIFT             7
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK              BITFIELD(7, 7)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK              (1 << 7)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
  */
 #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT                   8
-#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK                    BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK                    (1 << 8)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DPLL_CORE_DPLL_EN_SHIFT                       8
-#define OMAP4430_DPLL_CORE_DPLL_EN_MASK                                BITFIELD(8, 10)
+#define OMAP4430_DPLL_CORE_DPLL_EN_MASK                                (0x7 << 8)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DPLL_CORE_M2_DIV_SHIFT                                11
-#define OMAP4430_DPLL_CORE_M2_DIV_MASK                         BITFIELD(11, 15)
+#define OMAP4430_DPLL_CORE_M2_DIV_MASK                         (0x1f << 11)
 
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
 #define OMAP4430_DPLL_CORE_M5_DIV_SHIFT                                3
-#define OMAP4430_DPLL_CORE_M5_DIV_MASK                         BITFIELD(3, 7)
-
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_SHIFT                        1
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_MASK                 BITFIELD(1, 1)
+#define OMAP4430_DPLL_CORE_M5_DIV_MASK                         (0x1f << 3)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_DIV_SHIFT                                        0
-#define OMAP4430_DPLL_DIV_MASK                                 BITFIELD(0, 6)
+#define OMAP4430_DPLL_DIV_MASK                                 (0x7f << 0)
 
 /* Renamed from DPLL_DIV Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_DIV_0_7_SHIFT                            0
-#define OMAP4430_DPLL_DIV_0_7_MASK                             BITFIELD(0, 7)
+#define OMAP4430_DPLL_DIV_0_7_MASK                             (0xff << 0)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER
  */
 #define OMAP4430_DPLL_DRIFTGUARD_EN_SHIFT                      8
-#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK                       BITFIELD(8, 8)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK                       (1 << 8)
 
 /* Renamed from DPLL_DRIFTGUARD_EN Used by CM_CLKMODE_DPLL_UNIPRO */
 #define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_SHIFT                  3
-#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK                   BITFIELD(3, 3)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK                   (1 << 3)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_EN_SHIFT                                 0
-#define OMAP4430_DPLL_EN_MASK                                  BITFIELD(0, 2)
+#define OMAP4430_DPLL_EN_MASK                                  (0x7 << 0)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_LPMODE_EN_SHIFT                          10
-#define OMAP4430_DPLL_LPMODE_EN_MASK                           BITFIELD(10, 10)
+#define OMAP4430_DPLL_LPMODE_EN_MASK                           (1 << 10)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_MULT_SHIFT                               8
-#define OMAP4430_DPLL_MULT_MASK                                        BITFIELD(8, 18)
+#define OMAP4430_DPLL_MULT_MASK                                        (0x7ff << 8)
 
 /* Renamed from DPLL_MULT Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_MULT_USB_SHIFT                           8
-#define OMAP4430_DPLL_MULT_USB_MASK                            BITFIELD(8, 19)
+#define OMAP4430_DPLL_MULT_USB_MASK                            (0xfff << 8)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_REGM4XEN_SHIFT                           11
-#define OMAP4430_DPLL_REGM4XEN_MASK                            BITFIELD(11, 11)
+#define OMAP4430_DPLL_REGM4XEN_MASK                            (1 << 11)
 
 /* Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_SD_DIV_SHIFT                             24
-#define OMAP4430_DPLL_SD_DIV_MASK                              BITFIELD(24, 31)
+#define OMAP4430_DPLL_SD_DIV_MASK                              (0xff << 24)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_ACK_SHIFT                            13
-#define OMAP4430_DPLL_SSC_ACK_MASK                             BITFIELD(13, 13)
+#define OMAP4430_DPLL_SSC_ACK_MASK                             (1 << 13)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_DOWNSPREAD_SHIFT                     14
-#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK                      BITFIELD(14, 14)
+#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK                      (1 << 14)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_EN_SHIFT                             12
-#define OMAP4430_DPLL_SSC_EN_MASK                              BITFIELD(12, 12)
+#define OMAP4430_DPLL_SSC_EN_MASK                              (1 << 12)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_DSS_DYNDEP_SHIFT                              8
-#define OMAP4430_DSS_DYNDEP_MASK                               BITFIELD(8, 8)
+#define OMAP4430_DSS_DYNDEP_MASK                               (1 << 8)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE
  */
 #define OMAP4430_DSS_STATDEP_SHIFT                             8
-#define OMAP4430_DSS_STATDEP_MASK                              BITFIELD(8, 8)
+#define OMAP4430_DSS_STATDEP_MASK                              (1 << 8)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_DUCATI_DYNDEP_SHIFT                           0
-#define OMAP4430_DUCATI_DYNDEP_MASK                            BITFIELD(0, 0)
+#define OMAP4430_DUCATI_DYNDEP_MASK                            (1 << 0)
 
-/* Used by CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP */
+/* Used by CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE */
 #define OMAP4430_DUCATI_STATDEP_SHIFT                          0
-#define OMAP4430_DUCATI_STATDEP_MASK                           BITFIELD(0, 0)
+#define OMAP4430_DUCATI_STATDEP_MASK                           (1 << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_FREQ_UPDATE_SHIFT                             0
-#define OMAP4430_FREQ_UPDATE_MASK                              BITFIELD(0, 0)
+#define OMAP4430_FREQ_UPDATE_MASK                              (1 << 0)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_FUNC_SHIFT                                    16
+#define OMAP4430_FUNC_MASK                                     (0xfff << 16)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_GFX_DYNDEP_SHIFT                              10
-#define OMAP4430_GFX_DYNDEP_MASK                               BITFIELD(10, 10)
+#define OMAP4430_GFX_DYNDEP_MASK                               (1 << 10)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_GFX_STATDEP_SHIFT                             10
-#define OMAP4430_GFX_STATDEP_MASK                              BITFIELD(10, 10)
+#define OMAP4430_GFX_STATDEP_MASK                              (1 << 10)
 
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
 #define OMAP4430_GPMC_FREQ_UPDATE_SHIFT                                0
-#define OMAP4430_GPMC_FREQ_UPDATE_MASK                         BITFIELD(0, 0)
+#define OMAP4430_GPMC_FREQ_UPDATE_MASK                         (1 << 0)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_DIV_SHIFT                   0
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK                    BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK                    (0x1f << 0)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_SHIFT              5
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK               BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK               (1 << 5)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_SHIFT             8
-#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK              BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK              (1 << 8)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_SHIFT                  12
-#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK                   BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK                   (1 << 12)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_DIV_SHIFT                   0
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK                    BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK                    (0x1f << 0)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_SHIFT              5
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK               BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK               (1 << 5)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_SHIFT             8
-#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK              BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK              (1 << 8)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_SHIFT                  12
-#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK                   BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK                   (1 << 12)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_DIV_SHIFT                   0
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK                    BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK                    (0x1f << 0)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_SHIFT              5
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK               BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK               (1 << 5)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_SHIFT             8
-#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK              BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK              (1 << 8)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_SHIFT                  12
-#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK                   BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK                   (1 << 12)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_DIV_SHIFT                   0
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK                    BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK                    (0x1f << 0)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_SHIFT              5
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK               BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK               (1 << 5)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_SHIFT             8
-#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK              BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK              (1 << 8)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_SHIFT                  12
-#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK                   BITFIELD(12, 12)
-
-/*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK                   (1 << 12)
+
+/*
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
  * CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
  */
 #define OMAP4430_IDLEST_SHIFT                                  16
-#define OMAP4430_IDLEST_MASK                                   BITFIELD(16, 17)
+#define OMAP4430_IDLEST_MASK                                   (0x3 << 16)
 
-/* Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/*
+ * Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_ISS_DYNDEP_SHIFT                              9
-#define OMAP4430_ISS_DYNDEP_MASK                               BITFIELD(9, 9)
+#define OMAP4430_ISS_DYNDEP_MASK                               (1 << 9)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_ISS_STATDEP_SHIFT                             9
-#define OMAP4430_ISS_STATDEP_MASK                              BITFIELD(9, 9)
+#define OMAP4430_ISS_STATDEP_MASK                              (1 << 9)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_TESLA_DYNAMICDEP */
 #define OMAP4430_IVAHD_DYNDEP_SHIFT                            2
-#define OMAP4430_IVAHD_DYNDEP_MASK                             BITFIELD(2, 2)
+#define OMAP4430_IVAHD_DYNDEP_MASK                             (1 << 2)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_DSS_STATICDEP, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_IVAHD_STATDEP_SHIFT                           2
-#define OMAP4430_IVAHD_STATDEP_MASK                            BITFIELD(2, 2)
+#define OMAP4430_IVAHD_STATDEP_MASK                            (1 << 2)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_L3INIT_DYNDEP_SHIFT                           7
-#define OMAP4430_L3INIT_DYNDEP_MASK                            BITFIELD(7, 7)
+#define OMAP4430_L3INIT_DYNDEP_MASK                            (1 << 7)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
+ * CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3INIT_STATDEP_SHIFT                          7
-#define OMAP4430_L3INIT_STATDEP_MASK                           BITFIELD(7, 7)
+#define OMAP4430_L3INIT_STATDEP_MASK                           (1 << 7)
 
 /*
- * Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_DSS_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_DSS_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
  */
 #define OMAP4430_L3_1_DYNDEP_SHIFT                             5
-#define OMAP4430_L3_1_DYNDEP_MASK                              BITFIELD(5, 5)
+#define OMAP4430_L3_1_DYNDEP_MASK                              (1 << 5)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3_1_STATDEP_SHIFT                            5
-#define OMAP4430_L3_1_STATDEP_MASK                             BITFIELD(5, 5)
+#define OMAP4430_L3_1_STATDEP_MASK                             (1 << 5)
 
 /*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_SDMA_DYNAMICDEP,
- * CM_GFX_DYNAMICDEP, CM_L4SEC_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_CAM_DYNAMICDEP, CM_IVAHD_DYNAMICDEP
+ * Used by CM_CAM_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE,
+ * CM_DUCATI_DYNAMICDEP, CM_EMU_DYNAMICDEP, CM_GFX_DYNAMICDEP,
+ * CM_IVAHD_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4SEC_DYNAMICDEP, CM_SDMA_DYNAMICDEP
  */
 #define OMAP4430_L3_2_DYNDEP_SHIFT                             6
-#define OMAP4430_L3_2_DYNDEP_MASK                              BITFIELD(6, 6)
+#define OMAP4430_L3_2_DYNDEP_MASK                              (1 << 6)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3_2_STATDEP_SHIFT                            6
-#define OMAP4430_L3_2_STATDEP_MASK                             BITFIELD(6, 6)
+#define OMAP4430_L3_2_STATDEP_MASK                             (1 << 6)
 
-/* Used by CM_L3_1_DYNAMICDEP */
+/* Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4CFG_DYNDEP_SHIFT                            12
-#define OMAP4430_L4CFG_DYNDEP_MASK                             BITFIELD(12, 12)
+#define OMAP4430_L4CFG_DYNDEP_MASK                             (1 << 12)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4CFG_STATDEP_SHIFT                           12
-#define OMAP4430_L4CFG_STATDEP_MASK                            BITFIELD(12, 12)
+#define OMAP4430_L4CFG_STATDEP_MASK                            (1 << 12)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4PER_DYNDEP_SHIFT                            13
-#define OMAP4430_L4PER_DYNDEP_MASK                             BITFIELD(13, 13)
+#define OMAP4430_L4PER_DYNDEP_MASK                             (1 << 13)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4PER_STATDEP_SHIFT                           13
-#define OMAP4430_L4PER_STATDEP_MASK                            BITFIELD(13, 13)
+#define OMAP4430_L4PER_STATDEP_MASK                            (1 << 13)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_L4SEC_DYNDEP_SHIFT                            14
-#define OMAP4430_L4SEC_DYNDEP_MASK                             BITFIELD(14, 14)
+#define OMAP4430_L4SEC_DYNDEP_MASK                             (1 << 14)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE
  */
 #define OMAP4430_L4SEC_STATDEP_SHIFT                           14
-#define OMAP4430_L4SEC_STATDEP_MASK                            BITFIELD(14, 14)
+#define OMAP4430_L4SEC_STATDEP_MASK                            (1 << 14)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4WKUP_DYNDEP_SHIFT                           15
-#define OMAP4430_L4WKUP_DYNDEP_MASK                            BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_DYNDEP_MASK                            (1 << 15)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4WKUP_STATDEP_SHIFT                          15
-#define OMAP4430_L4WKUP_STATDEP_MASK                           BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_STATDEP_MASK                           (1 << 15)
 
 /*
- * Used by CM_D2D_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_MPU_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP
  */
 #define OMAP4430_MEMIF_DYNDEP_SHIFT                            4
-#define OMAP4430_MEMIF_DYNDEP_MASK                             BITFIELD(4, 4)
+#define OMAP4430_MEMIF_DYNDEP_MASK                             (1 << 4)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_MEMIF_STATDEP_SHIFT                           4
-#define OMAP4430_MEMIF_STATDEP_MASK                            BITFIELD(4, 4)
+#define OMAP4430_MEMIF_STATDEP_MASK                            (1 << 4)
 
 /*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
  */
 #define OMAP4430_MODFREQDIV_EXPONENT_SHIFT                     8
-#define OMAP4430_MODFREQDIV_EXPONENT_MASK                      BITFIELD(8, 10)
+#define OMAP4430_MODFREQDIV_EXPONENT_MASK                      (0x7 << 8)
 
 /*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
  */
 #define OMAP4430_MODFREQDIV_MANTISSA_SHIFT                     0
-#define OMAP4430_MODFREQDIV_MANTISSA_MASK                      BITFIELD(0, 6)
-
-/*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+#define OMAP4430_MODFREQDIV_MANTISSA_MASK                      (0x7f << 0)
+
+/*
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
  * CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
  */
 #define OMAP4430_MODULEMODE_SHIFT                              0
-#define OMAP4430_MODULEMODE_MASK                               BITFIELD(0, 1)
+#define OMAP4430_MODULEMODE_MASK                               (0x3 << 0)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT                     9
-#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK                      BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK                      (1 << 9)
 
 /* Used by CM_WKUP_BANDGAP_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT                      8
-#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK                       BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK                       (1 << 8)
 
-/* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
-#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT                                9
-#define OMAP4430_OPTFCLKEN_CLK32K_MASK                         BITFIELD(9, 9)
+/* Used by CM_ALWON_USBPHY_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT                                8
+#define OMAP4430_OPTFCLKEN_CLK32K_MASK                         (1 << 8)
 
 /* Used by CM_CAM_ISS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT                       8
-#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK                                BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK                                (1 << 8)
 
 /*
- * Used by CM_WKUP_GPIO1_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE
+ * Used by CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE, CM_WKUP_GPIO1_CLKCTRL
  */
 #define OMAP4430_OPTFCLKEN_DBCLK_SHIFT                         8
-#define OMAP4430_OPTFCLKEN_DBCLK_MASK                          BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DBCLK_MASK                          (1 << 8)
 
 /* Used by CM_MEMIF_DLL_CLKCTRL, CM_MEMIF_DLL_H_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_DLL_CLK_SHIFT                       8
-#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK                                BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK                                (1 << 8)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_DSSCLK_SHIFT                                8
-#define OMAP4430_OPTFCLKEN_DSSCLK_MASK                         BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DSSCLK_MASK                         (1 << 8)
+
+/* Used by CM_WKUP_USIM_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_FCLK_SHIFT                          8
+#define OMAP4430_OPTFCLKEN_FCLK_MASK                           (1 << 8)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK0_SHIFT                         8
-#define OMAP4430_OPTFCLKEN_FCLK0_MASK                          BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_FCLK0_MASK                          (1 << 8)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK1_SHIFT                         9
-#define OMAP4430_OPTFCLKEN_FCLK1_MASK                          BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_FCLK1_MASK                          (1 << 9)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK2_SHIFT                         10
-#define OMAP4430_OPTFCLKEN_FCLK2_MASK                          BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_FCLK2_MASK                          (1 << 10)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT                    15
-#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK                     BITFIELD(15, 15)
+#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK                     (1 << 15)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT               13
-#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK                        BITFIELD(13, 13)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK                        (1 << 13)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT               14
-#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK                        BITFIELD(14, 14)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK                        (1 << 14)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT                        11
-#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK                 BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK                 (1 << 11)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT                        12
-#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK                 BITFIELD(12, 12)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK                 (1 << 12)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT                 8
-#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK                  BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK                  (1 << 8)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT               9
-#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK                        BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK                        (1 << 9)
 
 /* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PHY_48M_SHIFT                       8
-#define OMAP4430_OPTFCLKEN_PHY_48M_MASK                                BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PHY_48M_MASK                                (1 << 8)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT                   10
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK                    BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK                    (1 << 10)
 
 /* Renamed from OPTFCLKEN_SLIMBUS_CLK Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT             11
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK              BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK              (1 << 11)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT                       10
-#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK                                BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK                                (1 << 10)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT                                11
-#define OMAP4430_OPTFCLKEN_TV_CLK_MASK                         BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_TV_CLK_MASK                         (1 << 11)
 
 /* Used by CM_L3INIT_UNIPRO1_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_TXPHYCLK_SHIFT                      8
-#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK                       BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK                       (1 << 8)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT                   8
-#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK                    BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK                    (1 << 8)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT                   9
-#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK                    BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK                    (1 << 9)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT                   10
-#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK                    BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK                    (1 << 10)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT                   8
-#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK                    BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK                    (1 << 8)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT                   9
-#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK                    BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK                    (1 << 9)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT                   10
-#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK                    BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK                    (1 << 10)
 
 /* Used by CM_L3INIT_USB_OTG_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_XCLK_SHIFT                          8
-#define OMAP4430_OPTFCLKEN_XCLK_MASK                           BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_XCLK_MASK                           (1 << 8)
 
-/* Used by CM_EMU_OVERRIDE_DPLL_PER, CM_EMU_OVERRIDE_DPLL_CORE */
+/* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_OVERRIDE_ENABLE_SHIFT                         19
-#define OMAP4430_OVERRIDE_ENABLE_MASK                          BITFIELD(19, 19)
+#define OMAP4430_OVERRIDE_ENABLE_MASK                          (1 << 19)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_PAD_CLKS_GATE_SHIFT                           8
-#define OMAP4430_PAD_CLKS_GATE_MASK                            BITFIELD(8, 8)
+#define OMAP4430_PAD_CLKS_GATE_MASK                            (1 << 8)
 
 /* Used by CM_CORE_DVFS_CURRENT, CM_IVA_DVFS_CURRENT */
 #define OMAP4430_PERF_CURRENT_SHIFT                            0
-#define OMAP4430_PERF_CURRENT_MASK                             BITFIELD(0, 7)
+#define OMAP4430_PERF_CURRENT_MASK                             (0xff << 0)
 
 /*
  * Used by CM_CORE_DVFS_PERF1, CM_CORE_DVFS_PERF2, CM_CORE_DVFS_PERF3,
  * CM_IVA_DVFS_PERF_TESLA
  */
 #define OMAP4430_PERF_REQ_SHIFT                                        0
-#define OMAP4430_PERF_REQ_MASK                                 BITFIELD(0, 7)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_DIV_SHIFT                                0
-#define OMAP4430_PER_DPLL_EMU_DIV_MASK                         BITFIELD(0, 6)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_MULT_SHIFT                       8
-#define OMAP4430_PER_DPLL_EMU_MULT_MASK                                BITFIELD(8, 18)
+#define OMAP4430_PERF_REQ_MASK                                 (0xff << 0)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE1_COMPLETED_SHIFT                                0
-#define OMAP4430_PHASE1_COMPLETED_MASK                         BITFIELD(0, 0)
+#define OMAP4430_PHASE1_COMPLETED_MASK                         (1 << 0)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE2A_COMPLETED_SHIFT                       1
-#define OMAP4430_PHASE2A_COMPLETED_MASK                                BITFIELD(1, 1)
+#define OMAP4430_PHASE2A_COMPLETED_MASK                                (1 << 1)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE2B_COMPLETED_SHIFT                       2
-#define OMAP4430_PHASE2B_COMPLETED_MASK                                BITFIELD(2, 2)
+#define OMAP4430_PHASE2B_COMPLETED_MASK                                (1 << 2)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_PMD_STM_MUX_CTRL_SHIFT                                20
-#define OMAP4430_PMD_STM_MUX_CTRL_MASK                         BITFIELD(20, 21)
+#define OMAP4430_PMD_STM_MUX_CTRL_MASK                         (0x3 << 20)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT                      22
-#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK                       BITFIELD(22, 23)
+#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK                       (0x3 << 22)
 
-/* Used by CM_DYN_DEP_PRESCAL */
+/* Used by CM_DYN_DEP_PRESCAL, CM_DYN_DEP_PRESCAL_RESTORE */
 #define OMAP4430_PRESCAL_SHIFT                                 0
-#define OMAP4430_PRESCAL_MASK                                  BITFIELD(0, 5)
+#define OMAP4430_PRESCAL_MASK                                  (0x3f << 0)
 
-/* Used by REVISION_CM2, REVISION_CM1 */
-#define OMAP4430_REV_SHIFT                                     0
-#define OMAP4430_REV_MASK                                      BITFIELD(0, 7)
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_R_RTL_SHIFT                                   11
+#define OMAP4430_R_RTL_MASK                                    (0x1f << 11)
 
 /*
- * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
+ * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
  */
 #define OMAP4430_SAR_MODE_SHIFT                                        4
-#define OMAP4430_SAR_MODE_MASK                                 BITFIELD(4, 4)
+#define OMAP4430_SAR_MODE_MASK                                 (1 << 4)
 
 /* Used by CM_SCALE_FCLK */
 #define OMAP4430_SCALE_FCLK_SHIFT                              0
-#define OMAP4430_SCALE_FCLK_MASK                               BITFIELD(0, 0)
+#define OMAP4430_SCALE_FCLK_MASK                               (1 << 0)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_SCHEME_SHIFT                                  30
+#define OMAP4430_SCHEME_MASK                                   (0x3 << 30)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_SDMA_DYNDEP_SHIFT                             11
-#define OMAP4430_SDMA_DYNDEP_MASK                              BITFIELD(11, 11)
+#define OMAP4430_SDMA_DYNDEP_MASK                              (1 << 11)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_SDMA_STATDEP_SHIFT                            11
-#define OMAP4430_SDMA_STATDEP_MASK                             BITFIELD(11, 11)
+#define OMAP4430_SDMA_STATDEP_MASK                             (1 << 11)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_SLIMBUS_CLK_GATE_SHIFT                                10
-#define OMAP4430_SLIMBUS_CLK_GATE_MASK                         BITFIELD(10, 10)
+#define OMAP4430_SLIMBUS_CLK_GATE_MASK                         (1 << 10)
 
 /*
- * Used by CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_SAD2D_CLKCTRL,
- * CM_DUCATI_DUCATI_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+ * Used by CM1_ABE_AESS_CLKCTRL, CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL,
+ * CM_D2D_SAD2D_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
+ * CM_DUCATI_DUCATI_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL,
+ * CM_IVAHD_IVAHD_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_FS_CLKCTRL,
- * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
- * CM_IVAHD_IVAHD_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
+ * CM_L3INIT_XHPI_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_MPU_MPU_CLKCTRL,
+ * CM_SDMA_SDMA_CLKCTRL, CM_TESLA_TESLA_CLKCTRL
  */
 #define OMAP4430_STBYST_SHIFT                                  18
-#define OMAP4430_STBYST_MASK                                   BITFIELD(18, 18)
+#define OMAP4430_STBYST_MASK                                   (1 << 18)
 
 /*
- * Used by CM_IDLEST_DPLL_PER, CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB,
- * CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
- * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
  */
 #define OMAP4430_ST_DPLL_CLK_SHIFT                             0
-#define OMAP4430_ST_DPLL_CLK_MASK                              BITFIELD(0, 0)
+#define OMAP4430_ST_DPLL_CLK_MASK                              (1 << 0)
 
 /* Used by CM_CLKDCOLDO_DPLL_USB */
 #define OMAP4430_ST_DPLL_CLKDCOLDO_SHIFT                       9
-#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK                                BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK                                (1 << 9)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
  */
 #define OMAP4430_ST_DPLL_CLKOUT_SHIFT                          9
-#define OMAP4430_ST_DPLL_CLKOUT_MASK                           BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUT_MASK                           (1 << 9)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_ST_DPLL_CLKOUTHIF_SHIFT                       9
-#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK                                BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK                                (1 << 9)
 
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
 #define OMAP4430_ST_DPLL_CLKOUTX2_SHIFT                                11
-#define OMAP4430_ST_DPLL_CLKOUTX2_MASK                         BITFIELD(11, 11)
+#define OMAP4430_ST_DPLL_CLKOUTX2_MASK                         (1 << 11)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT1_SHIFT                    9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK                     BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK                     (1 << 9)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT2_SHIFT                    9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK                     BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK                     (1 << 9)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT3_SHIFT                    9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK                     BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK                     (1 << 9)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT4_SHIFT                    9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK                     BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK                     (1 << 9)
+
+/*
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
+ */
+#define OMAP4430_ST_MN_BYPASS_SHIFT                            8
+#define OMAP4430_ST_MN_BYPASS_MASK                             (1 << 8)
 
 /* Used by CM_SYS_CLKSEL */
 #define OMAP4430_SYS_CLKSEL_SHIFT                              0
-#define OMAP4430_SYS_CLKSEL_MASK                               BITFIELD(0, 2)
+#define OMAP4430_SYS_CLKSEL_MASK                               (0x7 << 0)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_TESLA_DYNDEP_SHIFT                            1
-#define OMAP4430_TESLA_DYNDEP_MASK                             BITFIELD(1, 1)
+#define OMAP4430_TESLA_DYNDEP_MASK                             (1 << 1)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_TESLA_STATDEP_SHIFT                           1
-#define OMAP4430_TESLA_STATDEP_MASK                            BITFIELD(1, 1)
+#define OMAP4430_TESLA_STATDEP_MASK                            (1 << 1)
 
 /*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_L4PER_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_DUCATI_DYNAMICDEP,
+ * CM_EMU_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE,
+ * CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
  */
 #define OMAP4430_WINDOWSIZE_SHIFT                              24
-#define OMAP4430_WINDOWSIZE_MASK                               BITFIELD(24, 27)
+#define OMAP4430_WINDOWSIZE_MASK                               (0xf << 24)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_X_MAJOR_SHIFT                                 8
+#define OMAP4430_X_MAJOR_MASK                                  (0x7 << 8)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_Y_MINOR_SHIFT                                 0
+#define OMAP4430_Y_MINOR_MASK                                  (0x3f << 0)
 #endif
index 336d94889e5b50ee1e613bb88e7dacc18dff4a3d..3c35a87cb90c48d819631775362d1841d9ebf106 100644 (file)
 #define OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET              0x0088
 #define OMAP4430_CM1_ABE_WDT3_CLKCTRL                  OMAP44XX_CM1_REGADDR(OMAP4430_CM1_ABE_MOD, 0x0088)
 
+/* CM1.RESTORE_CM1 register offsets */
+#define OMAP4_CM_CLKSEL_CORE_RESTORE_OFFSET            0x0000
+#define OMAP4430_CM_CLKSEL_CORE_RESTORE                        OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_DIV_M2_DPLL_CORE_RESTORE_OFFSET       0x0004
+#define OMAP4430_CM_DIV_M2_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_DIV_M3_DPLL_CORE_RESTORE_OFFSET       0x0008
+#define OMAP4430_CM_DIV_M3_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_DIV_M4_DPLL_CORE_RESTORE_OFFSET       0x000c
+#define OMAP4430_CM_DIV_M4_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_DIV_M5_DPLL_CORE_RESTORE_OFFSET       0x0010
+#define OMAP4430_CM_DIV_M5_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_DIV_M6_DPLL_CORE_RESTORE_OFFSET       0x0014
+#define OMAP4430_CM_DIV_M6_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_DIV_M7_DPLL_CORE_RESTORE_OFFSET       0x0018
+#define OMAP4430_CM_DIV_M7_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_CLKSEL_DPLL_CORE_RESTORE_OFFSET       0x001c
+#define OMAP4430_CM_CLKSEL_DPLL_CORE_RESTORE           OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET       0x0020
+#define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE   OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET       0x0024
+#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE   OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET      0x0028
+#define OMAP4430_CM_CLKMODE_DPLL_CORE_RESTORE          OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET    0x002c
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG2_RESTORE                OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG1_RESTORE_OFFSET    0x0030
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG1_RESTORE                OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_AUTOIDLE_DPLL_CORE_RESTORE_OFFSET     0x0034
+#define OMAP4430_CM_AUTOIDLE_DPLL_CORE_RESTORE         OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_MPU_CLKSTCTRL_RESTORE_OFFSET          0x0038
+#define OMAP4430_CM_MPU_CLKSTCTRL_RESTORE              OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_CM1_PROFILING_CLKCTRL_RESTORE_OFFSET  0x003c
+#define OMAP4430_CM_CM1_PROFILING_CLKCTRL_RESTORE      OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET                0x0040
+#define OMAP4430_CM_DYN_DEP_PRESCAL_RESTORE            OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0040)
+
 /* CM2 */
 
 /* CM2.OCP_SOCKET_CM2 register offsets */
 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_PER            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0068)
 #define OMAP4_CM_SSC_MODFREQDIV_DPLL_PER_OFFSET                0x006c
 #define OMAP4430_CM_SSC_MODFREQDIV_DPLL_PER            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x006c)
-#define OMAP4_CM_EMU_OVERRIDE_DPLL_PER_OFFSET          0x0070
-#define OMAP4430_CM_EMU_OVERRIDE_DPLL_PER              OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0070)
 #define OMAP4_CM_CLKMODE_DPLL_USB_OFFSET               0x0080
 #define OMAP4430_CM_CLKMODE_DPLL_USB                   OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0080)
 #define OMAP4_CM_IDLEST_DPLL_USB_OFFSET                        0x0084
 #define OMAP4430_CM_ALWON_SR_IVA_CLKCTRL               OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0030)
 #define OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET          0x0038
 #define OMAP4430_CM_ALWON_SR_CORE_CLKCTRL              OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0038)
+#define OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET           0x0040
+#define OMAP4430_CM_ALWON_USBPHY_CLKCTRL               OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0040)
 
 /* CM2.CORE_CM2 register offsets */
 #define OMAP4_CM_L3_1_CLKSTCTRL_OFFSET                 0x0000
 #define OMAP4430_CM_CEFUSE_CLKSTCTRL                   OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0000)
 #define OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET          0x0020
 #define OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL              OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0020)
+
+/* CM2.RESTORE_CM2 register offsets */
+#define OMAP4_CM_L3_1_CLKSTCTRL_RESTORE_OFFSET         0x0000
+#define OMAP4430_CM_L3_1_CLKSTCTRL_RESTORE             OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_L3_2_CLKSTCTRL_RESTORE_OFFSET         0x0004
+#define OMAP4430_CM_L3_2_CLKSTCTRL_RESTORE             OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_L4CFG_CLKSTCTRL_RESTORE_OFFSET                0x0008
+#define OMAP4430_CM_L4CFG_CLKSTCTRL_RESTORE            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET                0x000c
+#define OMAP4430_CM_MEMIF_CLKSTCTRL_RESTORE            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_L4PER_CLKSTCTRL_RESTORE_OFFSET                0x0010
+#define OMAP4430_CM_L4PER_CLKSTCTRL_RESTORE            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_L3INIT_CLKSTCTRL_RESTORE_OFFSET       0x0014
+#define OMAP4430_CM_L3INIT_CLKSTCTRL_RESTORE           OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_L3INSTR_L3_3_CLKCTRL_RESTORE_OFFSET   0x0018
+#define OMAP4430_CM_L3INSTR_L3_3_CLKCTRL_RESTORE       OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE_OFFSET       0x001c
+#define OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE   OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE_OFFSET        0x0020
+#define OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE    OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_CM2_PROFILING_CLKCTRL_RESTORE_OFFSET  0x0024
+#define OMAP4430_CM_CM2_PROFILING_CLKCTRL_RESTORE      OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_D2D_STATICDEP_RESTORE_OFFSET          0x0028
+#define OMAP4430_CM_D2D_STATICDEP_RESTORE              OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_L3_1_DYNAMICDEP_RESTORE_OFFSET                0x002c
+#define OMAP4430_CM_L3_1_DYNAMICDEP_RESTORE            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_L3_2_DYNAMICDEP_RESTORE_OFFSET                0x0030
+#define OMAP4430_CM_L3_2_DYNAMICDEP_RESTORE            OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_D2D_DYNAMICDEP_RESTORE_OFFSET         0x0034
+#define OMAP4430_CM_D2D_DYNAMICDEP_RESTORE             OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_L4CFG_DYNAMICDEP_RESTORE_OFFSET       0x0038
+#define OMAP4430_CM_L4CFG_DYNAMICDEP_RESTORE           OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_L4PER_DYNAMICDEP_RESTORE_OFFSET       0x003c
+#define OMAP4430_CM_L4PER_DYNAMICDEP_RESTORE           OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_L4PER_GPIO2_CLKCTRL_RESTORE_OFFSET    0x0040
+#define OMAP4430_CM_L4PER_GPIO2_CLKCTRL_RESTORE                OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0040)
+#define OMAP4_CM_L4PER_GPIO3_CLKCTRL_RESTORE_OFFSET    0x0044
+#define OMAP4430_CM_L4PER_GPIO3_CLKCTRL_RESTORE                OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0044)
+#define OMAP4_CM_L4PER_GPIO4_CLKCTRL_RESTORE_OFFSET    0x0048
+#define OMAP4430_CM_L4PER_GPIO4_CLKCTRL_RESTORE                OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0048)
+#define OMAP4_CM_L4PER_GPIO5_CLKCTRL_RESTORE_OFFSET    0x004c
+#define OMAP4430_CM_L4PER_GPIO5_CLKCTRL_RESTORE                OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x004c)
+#define OMAP4_CM_L4PER_GPIO6_CLKCTRL_RESTORE_OFFSET    0x0050
+#define OMAP4430_CM_L4PER_GPIO6_CLKCTRL_RESTORE                OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0050)
+#define OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET        0x0054
+#define OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE    OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0054)
+#define OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET 0x0058
+#define OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE     OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0058)
+#define OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET         0x005c
+#define OMAP4430_CM_SDMA_STATICDEP_RESTORE             OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x005c)
 #endif
index b101091e95d638505e8c4874bb2b0fbef494e99e..f8a660a1a4a6f5303a5c5bc2e335add1d833ff1f 100644 (file)
@@ -43,7 +43,6 @@
  *                 using separate functional clock
  *   0x3 disabled: Module is disabled and cannot be accessed
  *
- * TODO: Need to handle module accessible in idle state
  */
 int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
 {
@@ -52,9 +51,11 @@ int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
        if (!clkctrl_reg)
                return 0;
 
-       omap_test_timeout(((__raw_readl(clkctrl_reg) &
-                           OMAP4430_IDLEST_MASK) == 0),
-                         MAX_MODULE_READY_TIME, i);
+       omap_test_timeout((
+               ((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) == 0) ||
+                (((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) >>
+                 OMAP4430_IDLEST_SHIFT) == 0x2)),
+               MAX_MODULE_READY_TIME, i);
 
        return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 }
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
new file mode 100644 (file)
index 0000000..778929f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/mach-omap2/common.c
+ *
+ * Code common to all OMAP2+ machines.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/mux.h>
+
+#include <plat/clock.h>
+
+#include "sdrc.h"
+#include "control.h"
+
+/* Global address base setup code */
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+
+static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
+{
+       omap2_set_globals_tap(omap2_globals);
+       omap2_set_globals_sdrc(omap2_globals);
+       omap2_set_globals_control(omap2_globals);
+       omap2_set_globals_prcm(omap2_globals);
+}
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct omap_globals omap242x_globals = {
+       .class  = OMAP242X_CLASS,
+       .tap    = OMAP2_L4_IO_ADDRESS(0x48014000),
+       .sdrc   = OMAP2420_SDRC_BASE,
+       .sms    = OMAP2420_SMS_BASE,
+       .ctrl   = OMAP242X_CTRL_BASE,
+       .prm    = OMAP2420_PRM_BASE,
+       .cm     = OMAP2420_CM_BASE,
+       .uart1_phys     = OMAP2_UART1_BASE,
+       .uart2_phys     = OMAP2_UART2_BASE,
+       .uart3_phys     = OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_242x(void)
+{
+       __omap2_set_globals(&omap242x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct omap_globals omap243x_globals = {
+       .class  = OMAP243X_CLASS,
+       .tap    = OMAP2_L4_IO_ADDRESS(0x4900a000),
+       .sdrc   = OMAP243X_SDRC_BASE,
+       .sms    = OMAP243X_SMS_BASE,
+       .ctrl   = OMAP243X_CTRL_BASE,
+       .prm    = OMAP2430_PRM_BASE,
+       .cm     = OMAP2430_CM_BASE,
+       .uart1_phys     = OMAP2_UART1_BASE,
+       .uart2_phys     = OMAP2_UART2_BASE,
+       .uart3_phys     = OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_243x(void)
+{
+       __omap2_set_globals(&omap243x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP3)
+
+static struct omap_globals omap3_globals = {
+       .class  = OMAP343X_CLASS,
+       .tap    = OMAP2_L4_IO_ADDRESS(0x4830A000),
+       .sdrc   = OMAP343X_SDRC_BASE,
+       .sms    = OMAP343X_SMS_BASE,
+       .ctrl   = OMAP343X_CTRL_BASE,
+       .prm    = OMAP3430_PRM_BASE,
+       .cm     = OMAP3430_CM_BASE,
+       .uart1_phys     = OMAP3_UART1_BASE,
+       .uart2_phys     = OMAP3_UART2_BASE,
+       .uart3_phys     = OMAP3_UART3_BASE,
+       .uart4_phys     = OMAP3_UART4_BASE,     /* Only on 3630 */
+};
+
+void __init omap2_set_globals_3xxx(void)
+{
+       __omap2_set_globals(&omap3_globals);
+}
+
+void __init omap3_map_io(void)
+{
+       omap2_set_globals_3xxx();
+       omap34xx_map_common_io();
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct omap_globals omap4_globals = {
+       .class  = OMAP443X_CLASS,
+       .tap    = OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
+       .ctrl   = OMAP443X_SCM_BASE,
+       .ctrl_pad       = OMAP443X_CTRL_BASE,
+       .prm    = OMAP4430_PRM_BASE,
+       .cm     = OMAP4430_CM_BASE,
+       .cm2    = OMAP4430_CM2_BASE,
+       .uart1_phys     = OMAP4_UART1_BASE,
+       .uart2_phys     = OMAP4_UART2_BASE,
+       .uart3_phys     = OMAP4_UART3_BASE,
+       .uart4_phys     = OMAP4_UART4_BASE,
+};
+
+void __init omap2_set_globals_443x(void)
+{
+       omap2_set_globals_tap(&omap4_globals);
+       omap2_set_globals_control(&omap4_globals);
+       omap2_set_globals_prcm(&omap4_globals);
+}
+#endif
+
index a8d20eef2306e8ddb558f96b2cc0ceeb6a542b25..1fa3294b6048b443a3b279ec8b14f78984c38246 100644 (file)
 #include <linux/io.h>
 
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/sdrc.h>
+
 #include "cm-regbits-34xx.h"
 #include "prm-regbits-34xx.h"
 #include "cm.h"
 #include "prm.h"
 #include "sdrc.h"
+#include "pm.h"
+#include "control.h"
 
 static void __iomem *omap2_ctrl_base;
+static void __iomem *omap4_ctrl_pad_base;
 
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 struct omap3_scratchpad {
@@ -137,6 +140,7 @@ static struct omap3_control_regs control_context;
 #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
 
 #define OMAP_CTRL_REGADDR(reg)         (omap2_ctrl_base + (reg))
+#define OMAP4_CTRL_PAD_REGADDR(reg)    (omap4_ctrl_pad_base + (reg))
 
 void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
 {
@@ -145,6 +149,12 @@ void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
                omap2_ctrl_base = ioremap(omap2_globals->ctrl, SZ_4K);
                WARN_ON(!omap2_ctrl_base);
        }
+
+       /* Static mapping, never released */
+       if (omap2_globals->ctrl_pad) {
+               omap4_ctrl_pad_base = ioremap(omap2_globals->ctrl_pad, SZ_4K);
+               WARN_ON(!omap4_ctrl_pad_base);
+       }
 }
 
 void __iomem *omap_ctrl_base_get(void)
@@ -182,6 +192,23 @@ void omap_ctrl_writel(u32 val, u16 offset)
        __raw_writel(val, OMAP_CTRL_REGADDR(offset));
 }
 
+/*
+ * On OMAP4 control pad are not addressable from control
+ * core base. So the common omap_ctrl_read/write APIs breaks
+ * Hence export separate APIs to manage the omap4 pad control
+ * registers. This APIs will work only for OMAP4
+ */
+
+u32 omap4_ctrl_pad_readl(u16 offset)
+{
+       return __raw_readl(OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
+void omap4_ctrl_pad_writel(u32 val, u16 offset)
+{
+       __raw_writel(val, OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 /*
  * Clears the scratchpad contents in case of cold boot-
@@ -190,7 +217,7 @@ void omap_ctrl_writel(u32 val, u16 offset)
 void omap3_clear_scratchpad_contents(void)
 {
        u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET;
-       u32 *v_addr;
+       void __iomem *v_addr;
        u32 offset = 0;
        v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM);
        if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) &
@@ -206,7 +233,7 @@ void omap3_clear_scratchpad_contents(void)
 /* Populate the scratchpad structure with restore structure */
 void omap3_save_scratchpad_contents(void)
 {
-       void * __iomem scratchpad_address;
+       void  __iomem *scratchpad_address;
        u32 arm_context_addr;
        struct omap3_scratchpad scratchpad_contents;
        struct omap3_scratchpad_prcm_block prcm_block_contents;
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
new file mode 100644 (file)
index 0000000..b6c6b7c
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * arch/arm/mach-omap2/control.h
+ *
+ * OMAP2/3/4 System Control Module definitions
+ *
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
+#define __ARCH_ARM_MACH_OMAP2_CONTROL_H
+
+#include <mach/io.h>
+#include <mach/ctrl_module_core_44xx.h>
+#include <mach/ctrl_module_wkup_44xx.h>
+#include <mach/ctrl_module_pad_core_44xx.h>
+#include <mach/ctrl_module_pad_wkup_44xx.h>
+
+#ifndef __ASSEMBLY__
+#define OMAP242X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#else
+#define OMAP242X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)                                     \
+               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#endif /* __ASSEMBLY__ */
+
+/*
+ * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
+ * OMAP24XX and OMAP34XX.
+ */
+
+/* Control submodule offsets */
+
+#define OMAP2_CONTROL_INTERFACE                0x000
+#define OMAP2_CONTROL_PADCONFS         0x030
+#define OMAP2_CONTROL_GENERAL          0x270
+#define OMAP343X_CONTROL_MEM_WKUP      0x600
+#define OMAP343X_CONTROL_PADCONFS_WKUP 0xa00
+#define OMAP343X_CONTROL_GENERAL_WKUP  0xa60
+
+/* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
+
+#define OMAP2_CONTROL_SYSCONFIG                (OMAP2_CONTROL_INTERFACE + 0x10)
+
+/* CONTROL_GENERAL register offsets common to OMAP2 & 3 */
+#define OMAP2_CONTROL_DEVCONF0         (OMAP2_CONTROL_GENERAL + 0x0004)
+#define OMAP2_CONTROL_MSUSPENDMUX_0    (OMAP2_CONTROL_GENERAL + 0x0020)
+#define OMAP2_CONTROL_MSUSPENDMUX_1    (OMAP2_CONTROL_GENERAL + 0x0024)
+#define OMAP2_CONTROL_MSUSPENDMUX_2    (OMAP2_CONTROL_GENERAL + 0x0028)
+#define OMAP2_CONTROL_MSUSPENDMUX_3    (OMAP2_CONTROL_GENERAL + 0x002c)
+#define OMAP2_CONTROL_MSUSPENDMUX_4    (OMAP2_CONTROL_GENERAL + 0x0030)
+#define OMAP2_CONTROL_MSUSPENDMUX_5    (OMAP2_CONTROL_GENERAL + 0x0034)
+#define OMAP2_CONTROL_SEC_CTRL         (OMAP2_CONTROL_GENERAL + 0x0040)
+#define OMAP2_CONTROL_RPUB_KEY_H_0     (OMAP2_CONTROL_GENERAL + 0x0090)
+#define OMAP2_CONTROL_RPUB_KEY_H_1     (OMAP2_CONTROL_GENERAL + 0x0094)
+#define OMAP2_CONTROL_RPUB_KEY_H_2     (OMAP2_CONTROL_GENERAL + 0x0098)
+#define OMAP2_CONTROL_RPUB_KEY_H_3     (OMAP2_CONTROL_GENERAL + 0x009c)
+
+/* 242x-only CONTROL_GENERAL register offsets */
+#define OMAP242X_CONTROL_DEVCONF       OMAP2_CONTROL_DEVCONF0 /* match TRM */
+#define OMAP242X_CONTROL_OCM_RAM_PERM  (OMAP2_CONTROL_GENERAL + 0x0068)
+
+/* 243x-only CONTROL_GENERAL register offsets */
+/* CONTROL_IVA2_BOOT{ADDR,MOD} are at the same place on 343x - noted below */
+#define OMAP243X_CONTROL_DEVCONF1      (OMAP2_CONTROL_GENERAL + 0x0078)
+#define OMAP243X_CONTROL_CSIRXFE       (OMAP2_CONTROL_GENERAL + 0x007c)
+#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 OMAP24XX_CONTROL_EMU_SUPPORT   (OMAP2_CONTROL_GENERAL + 0x0008)
+#define OMAP24XX_CONTROL_SEC_TEST      (OMAP2_CONTROL_GENERAL + 0x0044)
+#define OMAP24XX_CONTROL_PSA_CTRL      (OMAP2_CONTROL_GENERAL + 0x0048)
+#define OMAP24XX_CONTROL_PSA_CMD       (OMAP2_CONTROL_GENERAL + 0x004c)
+#define OMAP24XX_CONTROL_PSA_VALUE     (OMAP2_CONTROL_GENERAL + 0x0050)
+#define OMAP24XX_CONTROL_SEC_EMU       (OMAP2_CONTROL_GENERAL + 0x0060)
+#define OMAP24XX_CONTROL_SEC_TAP       (OMAP2_CONTROL_GENERAL + 0x0064)
+#define OMAP24XX_CONTROL_OCM_PUB_RAM_ADD       (OMAP2_CONTROL_GENERAL + 0x006c)
+#define OMAP24XX_CONTROL_EXT_SEC_RAM_START_ADD (OMAP2_CONTROL_GENERAL + 0x0070)
+#define OMAP24XX_CONTROL_EXT_SEC_RAM_STOP_ADD  (OMAP2_CONTROL_GENERAL + 0x0074)
+#define OMAP24XX_CONTROL_SEC_STATUS            (OMAP2_CONTROL_GENERAL + 0x0080)
+#define OMAP24XX_CONTROL_SEC_ERR_STATUS                (OMAP2_CONTROL_GENERAL + 0x0084)
+#define OMAP24XX_CONTROL_STATUS                        (OMAP2_CONTROL_GENERAL + 0x0088)
+#define OMAP24XX_CONTROL_GENERAL_PURPOSE_STATUS        (OMAP2_CONTROL_GENERAL + 0x008c)
+#define OMAP24XX_CONTROL_RAND_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00a0)
+#define OMAP24XX_CONTROL_RAND_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00a4)
+#define OMAP24XX_CONTROL_RAND_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00a8)
+#define OMAP24XX_CONTROL_RAND_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00ac)
+#define OMAP24XX_CONTROL_CUST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00b0)
+#define OMAP24XX_CONTROL_CUST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00b4)
+#define OMAP24XX_CONTROL_TEST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00c0)
+#define OMAP24XX_CONTROL_TEST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00c4)
+#define OMAP24XX_CONTROL_TEST_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00c8)
+#define OMAP24XX_CONTROL_TEST_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00cc)
+#define OMAP24XX_CONTROL_TEST_KEY_4    (OMAP2_CONTROL_GENERAL + 0x00d0)
+#define OMAP24XX_CONTROL_TEST_KEY_5    (OMAP2_CONTROL_GENERAL + 0x00d4)
+#define OMAP24XX_CONTROL_TEST_KEY_6    (OMAP2_CONTROL_GENERAL + 0x00d8)
+#define OMAP24XX_CONTROL_TEST_KEY_7    (OMAP2_CONTROL_GENERAL + 0x00dc)
+#define OMAP24XX_CONTROL_TEST_KEY_8    (OMAP2_CONTROL_GENERAL + 0x00e0)
+#define OMAP24XX_CONTROL_TEST_KEY_9    (OMAP2_CONTROL_GENERAL + 0x00e4)
+
+#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0)
+
+/* 34xx-only CONTROL_GENERAL register offsets */
+#define OMAP343X_CONTROL_PADCONF_OFF   (OMAP2_CONTROL_GENERAL + 0x0000)
+#define OMAP343X_CONTROL_MEM_DFTRW0    (OMAP2_CONTROL_GENERAL + 0x0008)
+#define OMAP343X_CONTROL_MEM_DFTRW1    (OMAP2_CONTROL_GENERAL + 0x000c)
+#define OMAP343X_CONTROL_DEVCONF1      (OMAP2_CONTROL_GENERAL + 0x0068)
+#define OMAP343X_CONTROL_CSIRXFE               (OMAP2_CONTROL_GENERAL + 0x006c)
+#define OMAP343X_CONTROL_SEC_STATUS            (OMAP2_CONTROL_GENERAL + 0x0070)
+#define OMAP343X_CONTROL_SEC_ERR_STATUS                (OMAP2_CONTROL_GENERAL + 0x0074)
+#define OMAP343X_CONTROL_SEC_ERR_STATUS_DEBUG  (OMAP2_CONTROL_GENERAL + 0x0078)
+#define OMAP343X_CONTROL_STATUS                        (OMAP2_CONTROL_GENERAL + 0x0080)
+#define OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS        (OMAP2_CONTROL_GENERAL + 0x0084)
+#define OMAP343X_CONTROL_RPUB_KEY_H_4  (OMAP2_CONTROL_GENERAL + 0x00a0)
+#define OMAP343X_CONTROL_RAND_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00a8)
+#define OMAP343X_CONTROL_RAND_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00ac)
+#define OMAP343X_CONTROL_RAND_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00b0)
+#define OMAP343X_CONTROL_RAND_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00b4)
+#define OMAP343X_CONTROL_TEST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00c8)
+#define OMAP343X_CONTROL_TEST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00cc)
+#define OMAP343X_CONTROL_TEST_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00d0)
+#define OMAP343X_CONTROL_TEST_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00d4)
+#define OMAP343X_CONTROL_TEST_KEY_4    (OMAP2_CONTROL_GENERAL + 0x00d8)
+#define OMAP343X_CONTROL_TEST_KEY_5    (OMAP2_CONTROL_GENERAL + 0x00dc)
+#define OMAP343X_CONTROL_TEST_KEY_6    (OMAP2_CONTROL_GENERAL + 0x00e0)
+#define OMAP343X_CONTROL_TEST_KEY_7    (OMAP2_CONTROL_GENERAL + 0x00e4)
+#define OMAP343X_CONTROL_TEST_KEY_8    (OMAP2_CONTROL_GENERAL + 0x00e8)
+#define OMAP343X_CONTROL_TEST_KEY_9    (OMAP2_CONTROL_GENERAL + 0x00ec)
+#define OMAP343X_CONTROL_TEST_KEY_10   (OMAP2_CONTROL_GENERAL + 0x00f0)
+#define OMAP343X_CONTROL_TEST_KEY_11   (OMAP2_CONTROL_GENERAL + 0x00f4)
+#define OMAP343X_CONTROL_TEST_KEY_12   (OMAP2_CONTROL_GENERAL + 0x00f8)
+#define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
+#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
+#define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP343X_CONTROL_DEBOBS(i)     (OMAP2_CONTROL_GENERAL + 0x01B0 \
+                                       + ((i) >> 1) * 4 + (!((i) & 1)) * 2)
+#define OMAP343X_CONTROL_PROG_IO0      (OMAP2_CONTROL_GENERAL + 0x01D4)
+#define OMAP343X_CONTROL_PROG_IO1      (OMAP2_CONTROL_GENERAL + 0x01D8)
+#define OMAP343X_CONTROL_DSS_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E0)
+#define OMAP343X_CONTROL_CORE_DPLL_SPREADING   (OMAP2_CONTROL_GENERAL + 0x01E4)
+#define OMAP343X_CONTROL_PER_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E8)
+#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING        (OMAP2_CONTROL_GENERAL + 0x01EC)
+#define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02B0)
+#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02B4)
+#define OMAP343X_CONTROL_SRAMLDO4      (OMAP2_CONTROL_GENERAL + 0x02B8)
+#define OMAP343X_CONTROL_SRAMLDO5      (OMAP2_CONTROL_GENERAL + 0x02C0)
+#define OMAP343X_CONTROL_CSI           (OMAP2_CONTROL_GENERAL + 0x02C4)
+
+/* AM35XX only CONTROL_GENERAL register offsets */
+#define AM35XX_CONTROL_MSUSPENDMUX_6    (OMAP2_CONTROL_GENERAL + 0x0038)
+#define AM35XX_CONTROL_DEVCONF2         (OMAP2_CONTROL_GENERAL + 0x0310)
+#define AM35XX_CONTROL_DEVCONF3         (OMAP2_CONTROL_GENERAL + 0x0314)
+#define AM35XX_CONTROL_CBA_PRIORITY     (OMAP2_CONTROL_GENERAL + 0x0320)
+#define AM35XX_CONTROL_LVL_INTR_CLEAR   (OMAP2_CONTROL_GENERAL + 0x0324)
+#define AM35XX_CONTROL_IP_SW_RESET      (OMAP2_CONTROL_GENERAL + 0x0328)
+#define AM35XX_CONTROL_IPSS_CLK_CTRL    (OMAP2_CONTROL_GENERAL + 0x032C)
+
+/* 34xx PADCONF register offsets */
+#define OMAP343X_PADCONF_ETK(i)                (OMAP2_CONTROL_PADCONFS + 0x5a8 + \
+                                               (i)*2)
+#define OMAP343X_PADCONF_ETK_CLK       OMAP343X_PADCONF_ETK(0)
+#define OMAP343X_PADCONF_ETK_CTL       OMAP343X_PADCONF_ETK(1)
+#define OMAP343X_PADCONF_ETK_D0                OMAP343X_PADCONF_ETK(2)
+#define OMAP343X_PADCONF_ETK_D1                OMAP343X_PADCONF_ETK(3)
+#define OMAP343X_PADCONF_ETK_D2                OMAP343X_PADCONF_ETK(4)
+#define OMAP343X_PADCONF_ETK_D3                OMAP343X_PADCONF_ETK(5)
+#define OMAP343X_PADCONF_ETK_D4                OMAP343X_PADCONF_ETK(6)
+#define OMAP343X_PADCONF_ETK_D5                OMAP343X_PADCONF_ETK(7)
+#define OMAP343X_PADCONF_ETK_D6                OMAP343X_PADCONF_ETK(8)
+#define OMAP343X_PADCONF_ETK_D7                OMAP343X_PADCONF_ETK(9)
+#define OMAP343X_PADCONF_ETK_D8                OMAP343X_PADCONF_ETK(10)
+#define OMAP343X_PADCONF_ETK_D9                OMAP343X_PADCONF_ETK(11)
+#define OMAP343X_PADCONF_ETK_D10       OMAP343X_PADCONF_ETK(12)
+#define OMAP343X_PADCONF_ETK_D11       OMAP343X_PADCONF_ETK(13)
+#define OMAP343X_PADCONF_ETK_D12       OMAP343X_PADCONF_ETK(14)
+#define OMAP343X_PADCONF_ETK_D13       OMAP343X_PADCONF_ETK(15)
+#define OMAP343X_PADCONF_ETK_D14       OMAP343X_PADCONF_ETK(16)
+#define OMAP343X_PADCONF_ETK_D15       OMAP343X_PADCONF_ETK(17)
+
+/* 34xx GENERAL_WKUP regist offsets */
+#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
+                                               0x008 + (i))
+#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
+#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C)
+#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010)
+#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
+#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
+
+/* 34xx D2D idle-related pins, handled by PM core */
+#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
+#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
+
+/*
+ * REVISIT: This list of registers is not comprehensive - there are more
+ * that should be added.
+ */
+
+/*
+ * Control module register bit defines - these should eventually go into
+ * their own regbits file.  Some of these will be complicated, depending
+ * on the device type (general-purpose, emulator, test, secure, bad, other)
+ * 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_FSR_MASK          (1 << 4)
+#define OMAP2_MCBSP1_CLKR_MASK         (1 << 3)
+#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 */
+
+/* CONTROL_STATUS bits */
+#define OMAP2_DEVICETYPE_MASK          (0x7 << 8)
+#define OMAP2_SYSBOOT_5_MASK           (1 << 5)
+#define OMAP2_SYSBOOT_4_MASK           (1 << 4)
+#define OMAP2_SYSBOOT_3_MASK           (1 << 3)
+#define OMAP2_SYSBOOT_2_MASK           (1 << 2)
+#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)
+
+/* CONTROL_PROG_IO1 bits */
+#define OMAP3630_PRG_SDMMC1_SPEEDCTRL  (1 << 20)
+
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT       0
+#define OMAP3_IVA2_BOOTMOD_MASK                (0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE                (0x1 << 0)
+
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0     (1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0    (1 << 14)
+
+#define OMAP343X_SCRATCHPAD_ROM                (OMAP343X_CTRL_BASE + 0x860)
+#define OMAP343X_SCRATCHPAD            (OMAP343X_CTRL_BASE + 0x910)
+#define OMAP343X_SCRATCHPAD_ROM_OFFSET 0x19C
+
+/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */
+#define AM35XX_USBOTG_VBUSP_CLK_SHIFT   0
+#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT   1
+#define AM35XX_VPFE_VBUSP_CLK_SHIFT     2
+#define AM35XX_HECC_VBUSP_CLK_SHIFT     3
+#define AM35XX_USBOTG_FCLK_SHIFT        8
+#define AM35XX_CPGMAC_FCLK_SHIFT        9
+#define AM35XX_VPFE_FCLK_SHIFT          10
+
+/*AM35XX CONTROL_LVL_INTR_CLEAR bits*/
+#define AM35XX_CPGMAC_C0_MISC_PULSE_CLR        BIT(0)
+#define AM35XX_CPGMAC_C0_RX_PULSE_CLR  BIT(1)
+#define AM35XX_CPGMAC_C0_RX_THRESH_CLR BIT(2)
+#define AM35XX_CPGMAC_C0_TX_PULSE_CLR  BIT(3)
+#define AM35XX_USBOTGSS_INT_CLR                BIT(4)
+#define AM35XX_VPFE_CCDC_VD0_INT_CLR   BIT(5)
+#define AM35XX_VPFE_CCDC_VD1_INT_CLR   BIT(6)
+#define AM35XX_VPFE_CCDC_VD2_INT_CLR   BIT(7)
+
+/*AM35XX CONTROL_IP_SW_RESET bits*/
+#define AM35XX_USBOTGSS_SW_RST         BIT(0)
+#define AM35XX_CPGMACSS_SW_RST         BIT(1)
+#define AM35XX_VPFE_VBUSP_SW_RST       BIT(2)
+#define AM35XX_HECC_SW_RST             BIT(3)
+#define AM35XX_VPFE_PCLK_SW_RST                BIT(4)
+
+/*
+ * CONTROL OMAP STATUS register to identify OMAP3 features
+ */
+#define OMAP3_CONTROL_OMAP_STATUS      0x044c
+
+#define OMAP3_SGX_SHIFT                        13
+#define OMAP3_SGX_MASK                 (3 << OMAP3_SGX_SHIFT)
+#define                FEAT_SGX_FULL           0
+#define                FEAT_SGX_HALF           1
+#define                FEAT_SGX_NONE           2
+
+#define OMAP3_IVA_SHIFT                        12
+#define OMAP3_IVA_MASK                 (1 << OMAP3_SGX_SHIFT)
+#define                FEAT_IVA                0
+#define                FEAT_IVA_NONE           1
+
+#define OMAP3_L2CACHE_SHIFT            10
+#define OMAP3_L2CACHE_MASK             (3 << OMAP3_L2CACHE_SHIFT)
+#define                FEAT_L2CACHE_NONE       0
+#define                FEAT_L2CACHE_64KB       1
+#define                FEAT_L2CACHE_128KB      2
+#define                FEAT_L2CACHE_256KB      3
+
+#define OMAP3_ISP_SHIFT                        5
+#define OMAP3_ISP_MASK                 (1 << OMAP3_ISP_SHIFT)
+#define                FEAT_ISP                0
+#define                FEAT_ISP_NONE           1
+
+#define OMAP3_NEON_SHIFT               4
+#define OMAP3_NEON_MASK                        (1 << OMAP3_NEON_SHIFT)
+#define                FEAT_NEON               0
+#define                FEAT_NEON_NONE          1
+
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_ARCH_OMAP2PLUS
+extern void __iomem *omap_ctrl_base_get(void);
+extern u8 omap_ctrl_readb(u16 offset);
+extern u16 omap_ctrl_readw(u16 offset);
+extern u32 omap_ctrl_readl(u16 offset);
+extern u32 omap4_ctrl_pad_readl(u16 offset);
+extern void omap_ctrl_writeb(u8 val, u16 offset);
+extern void omap_ctrl_writew(u16 val, u16 offset);
+extern void omap_ctrl_writel(u32 val, u16 offset);
+extern void omap4_ctrl_pad_writel(u32 val, u16 offset);
+
+extern void omap3_save_scratchpad_contents(void);
+extern void omap3_clear_scratchpad_contents(void);
+extern u32 *get_restore_pointer(void);
+extern u32 *get_es3_restore_pointer(void);
+extern u32 omap3_arm_context[128];
+extern void omap3_control_save_context(void);
+extern void omap3_control_restore_context(void);
+
+#else
+#define omap_ctrl_base_get()           0
+#define omap_ctrl_readb(x)             0
+#define omap_ctrl_readw(x)             0
+#define omap_ctrl_readl(x)             0
+#define omap4_ctrl_pad_readl(x)                0
+#define omap_ctrl_writeb(x, y)         WARN_ON(1)
+#define omap_ctrl_writew(x, y)         WARN_ON(1)
+#define omap_ctrl_writel(x, y)         WARN_ON(1)
+#define omap4_ctrl_pad_writel(x, y)    WARN_ON(1)
+#endif
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM_MACH_OMAP2_CONTROL_H */
+
index 3d3d035db9aff62ce522e0080e570cfdbf8e70cc..0d50b45d041c1d30d1f2aa1b8c84ed8ad7b1d667 100644 (file)
 #include <plat/irqs.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
-#include <plat/control.h>
 #include <plat/serial.h>
 
 #include "pm.h"
+#include "control.h"
 
 #ifdef CONFIG_CPU_IDLE
 
@@ -60,7 +60,8 @@ struct omap3_processor_cx {
 
 struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
 struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *cam_pd;
 
 /*
  * The latencies/thresholds for various C states have
@@ -233,14 +234,60 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
                               struct cpuidle_state *state)
 {
        struct cpuidle_state *new_state = next_valid_state(dev, state);
+       u32 core_next_state, per_next_state = 0, per_saved_state = 0;
+       u32 cam_state;
+       struct omap3_processor_cx *cx;
+       int ret;
 
        if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
                BUG_ON(!dev->safe_state);
                new_state = dev->safe_state;
+               goto select_state;
        }
 
+       cx = cpuidle_get_statedata(state);
+       core_next_state = cx->core_state;
+
+       /*
+        * FIXME: we currently manage device-specific idle states
+        *        for PER and CORE in combination with CPU-specific
+        *        idle states.  This is wrong, and device-specific
+        *        idle managment needs to be separated out into 
+        *        its own code.
+        */
+
+       /*
+        * Prevent idle completely if CAM is active.
+        * CAM does not have wakeup capability in OMAP3.
+        */
+       cam_state = pwrdm_read_pwrst(cam_pd);
+       if (cam_state == PWRDM_POWER_ON) {
+               new_state = dev->safe_state;
+               goto select_state;
+       }
+
+       /*
+        * Prevent PER off if CORE is not in retention or off as this
+        * would disable PER wakeups completely.
+        */
+       per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
+       if ((per_next_state == PWRDM_POWER_OFF) &&
+           (core_next_state > PWRDM_POWER_RET))
+               per_next_state = PWRDM_POWER_RET;
+
+       /* Are we changing PER target state? */
+       if (per_next_state != per_saved_state)
+               pwrdm_set_next_pwrst(per_pd, per_next_state);
+
+select_state:
        dev->last_state = new_state;
-       return omap3_enter_idle(dev, new_state);
+       ret = omap3_enter_idle(dev, new_state);
+
+       /* Restore original PER state if it was modified */
+       if (per_next_state != per_saved_state)
+               pwrdm_set_next_pwrst(per_pd, per_saved_state);
+
+       return ret;
 }
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -328,7 +375,8 @@ void omap_init_power_states(void)
                        cpuidle_params_table[OMAP3_STATE_C2].threshold;
        omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
        omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+                               CPUIDLE_FLAG_CHECK_BM;
 
        /* C3 . MPU CSWR + Core inactive */
        omap3_power_states[OMAP3_STATE_C3].valid =
@@ -426,6 +474,8 @@ int __init omap3_idle_init(void)
 
        mpu_pd = pwrdm_lookup("mpu_pwrdm");
        core_pd = pwrdm_lookup("core_pwrdm");
+       per_pd = pwrdm_lookup("per_pwrdm");
+       cam_pd = pwrdm_lookup("cam_pwrdm");
 
        omap_init_power_states();
        cpuidle_register_driver(&omap3_idle_driver);
index b27e7cbb3f2936187692b0dcc8066477afd68ba5..5a0c148e23bc8fe3a76b25dc80d3933a06caf981 100644 (file)
@@ -9,12 +9,12 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
 
-#include <plat/control.h>
 #include <plat/tc.h>
 #include <plat/board.h>
+#include <plat/mcbsp.h>
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "mux.h"
+#include "control.h"
 
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
@@ -235,6 +238,43 @@ static inline void omap_init_mbox(void) { }
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+       .name   = "omap-pcm-audio",
+       .id     = -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+       platform_device_register(&omap_mcbsp1);
+       platform_device_register(&omap_mcbsp2);
+       if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+               platform_device_register(&omap_mcbsp3);
+               platform_device_register(&omap_mcbsp4);
+       }
+       if (cpu_is_omap243x() || cpu_is_omap34xx())
+               platform_device_register(&omap_mcbsp5);
+
+       platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <plat/mcspi.h>
@@ -500,7 +540,7 @@ static inline void omap_init_sham(void) { }
 
 #if defined(CONFIG_CRYPTO_DEV_OMAP_AES) || defined(CONFIG_CRYPTO_DEV_OMAP_AES_MODULE)
 
-#ifdef CONFIG_ARCH_OMAP24XX
+#ifdef CONFIG_ARCH_OMAP2
 static struct resource omap2_aes_resources[] = {
        {
                .start  = OMAP24XX_SEC_AES_BASE,
@@ -522,7 +562,7 @@ static int omap2_aes_resources_sz = ARRAY_SIZE(omap2_aes_resources);
 #define omap2_aes_resources_sz         0
 #endif
 
-#ifdef CONFIG_ARCH_OMAP34XX
+#ifdef CONFIG_ARCH_OMAP3
 static struct resource omap3_aes_resources[] = {
        {
                .start  = OMAP34XX_SEC_AES_BASE,
@@ -694,7 +734,7 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                omap_mux_init_signal("sdmmc_dat0", 0);
                omap_mux_init_signal("sdmmc_dat_dir0", 0);
                omap_mux_init_signal("sdmmc_cmd_dir", 0);
-               if (mmc_controller->slots[0].wires == 4) {
+               if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
                        omap_mux_init_signal("sdmmc_dat1", 0);
                        omap_mux_init_signal("sdmmc_dat2", 0);
                        omap_mux_init_signal("sdmmc_dat3", 0);
@@ -722,8 +762,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                                OMAP_PIN_INPUT_PULLUP);
                        omap_mux_init_signal("sdmmc1_dat0",
                                OMAP_PIN_INPUT_PULLUP);
-                       if (mmc_controller->slots[0].wires == 4 ||
-                               mmc_controller->slots[0].wires == 8) {
+                       if (mmc_controller->slots[0].caps &
+                               (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
                                omap_mux_init_signal("sdmmc1_dat1",
                                        OMAP_PIN_INPUT_PULLUP);
                                omap_mux_init_signal("sdmmc1_dat2",
@@ -731,7 +771,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                                omap_mux_init_signal("sdmmc1_dat3",
                                        OMAP_PIN_INPUT_PULLUP);
                        }
-                       if (mmc_controller->slots[0].wires == 8) {
+                       if (mmc_controller->slots[0].caps &
+                                               MMC_CAP_8_BIT_DATA) {
                                omap_mux_init_signal("sdmmc1_dat4",
                                        OMAP_PIN_INPUT_PULLUP);
                                omap_mux_init_signal("sdmmc1_dat5",
@@ -755,8 +796,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                         * For 8 wire configurations, Lines DAT4, 5, 6 and 7 need to be muxed
                         * in the board-*.c files
                         */
-                       if (mmc_controller->slots[0].wires == 4 ||
-                               mmc_controller->slots[0].wires == 8) {
+                       if (mmc_controller->slots[0].caps &
+                               (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
                                omap_mux_init_signal("sdmmc2_dat1",
                                        OMAP_PIN_INPUT_PULLUP);
                                omap_mux_init_signal("sdmmc2_dat2",
@@ -764,7 +805,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
                                omap_mux_init_signal("sdmmc2_dat3",
                                        OMAP_PIN_INPUT_PULLUP);
                        }
-                       if (mmc_controller->slots[0].wires == 8) {
+                       if (mmc_controller->slots[0].caps &
+                                                       MMC_CAP_8_BIT_DATA) {
                                omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
                                        OMAP_PIN_INPUT_PULLUP);
                                omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5",
@@ -815,13 +857,13 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
                case 3:
                        if (!cpu_is_omap44xx())
                                return;
-                       base = OMAP4_MMC4_BASE + OMAP4_MMC_REG_OFFSET;
+                       base = OMAP4_MMC4_BASE;
                        irq = OMAP44XX_IRQ_MMC4;
                        break;
                case 4:
                        if (!cpu_is_omap44xx())
                                return;
-                       base = OMAP4_MMC5_BASE + OMAP4_MMC_REG_OFFSET;
+                       base = OMAP4_MMC5_BASE;
                        irq = OMAP44XX_IRQ_MMC5;
                        break;
                default:
@@ -832,10 +874,8 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
                        size = OMAP2420_MMC_SIZE;
                        name = "mmci-omap";
                } else if (cpu_is_omap44xx()) {
-                       if (i < 3) {
-                               base += OMAP4_MMC_REG_OFFSET;
+                       if (i < 3)
                                irq += OMAP44XX_IRQ_GIC_START;
-                       }
                        size = OMAP4_HSMMC_SIZE;
                        name = "mmci-omap-hs";
                } else {
@@ -911,12 +951,74 @@ static inline void omap_init_vout(void) {}
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Inorder to avoid any assumptions from bootloader regarding WDT
+ * settings, WDT module is reset during init. This enables the watchdog
+ * timer. Hence it is required to disable the watchdog after the WDT reset
+ * during init. Otherwise the system would reboot as per the default
+ * watchdog timer registers settings.
+ */
+#define OMAP_WDT_WPS   (0x34)
+#define OMAP_WDT_SPR   (0x48)
+
+static int omap2_disable_wdt(struct omap_hwmod *oh, void *unused)
+{
+       void __iomem *base;
+       int ret;
+
+       if (!oh) {
+               pr_err("%s: Could not look up wdtimer_hwmod\n", __func__);
+               return -EINVAL;
+       }
+
+       base = omap_hwmod_get_mpu_rt_va(oh);
+       if (!base) {
+               pr_err("%s: Could not get the base address for %s\n",
+                               oh->name, __func__);
+               return -EINVAL;
+       }
+
+       /* Enable the clocks before accessing the WDT registers */
+       ret = omap_hwmod_enable(oh);
+       if (ret) {
+               pr_err("%s: Could not enable clocks for %s\n",
+                               oh->name, __func__);
+               return ret;
+       }
+
+       /* sequence required to disable watchdog */
+       __raw_writel(0xAAAA, base + OMAP_WDT_SPR);
+       while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+               cpu_relax();
+
+       __raw_writel(0x5555, base + OMAP_WDT_SPR);
+       while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+               cpu_relax();
+
+       ret = omap_hwmod_idle(oh);
+       if (ret)
+               pr_err("%s: Could not disable clocks for %s\n",
+                               oh->name, __func__);
+
+       return ret;
+}
+
+static void __init omap_disable_wdt(void)
+{
+       if (cpu_class_is_omap2())
+               omap_hwmod_for_each_by_class("wd_timer",
+                                               omap2_disable_wdt, NULL);
+       return;
+}
+
 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_disable_wdt();
        omap_hsmmc_reset();
+       omap_init_audio();
        omap_init_camera();
        omap_init_mbox();
        omap_init_mcspi();
@@ -930,3 +1032,39 @@ static int __init omap2_init_devices(void)
        return 0;
 }
 arch_initcall(omap2_init_devices);
+
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+struct omap_device_pm_latency omap_wdt_latency[] = {
+       [0] = {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags           = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+
+static int __init omap_init_wdt(void)
+{
+       int id = -1;
+       struct omap_device *od;
+       struct omap_hwmod *oh;
+       char *oh_name = "wd_timer2";
+       char *dev_name = "omap_wdt";
+
+       if (!cpu_class_is_omap2())
+               return 0;
+
+       oh = omap_hwmod_lookup(oh_name);
+       if (!oh) {
+               pr_err("Could not look up wd_timer%d hwmod\n", id);
+               return -EINVAL;
+       }
+
+       od = omap_device_build(dev_name, id, oh, NULL, 0,
+                               omap_wdt_latency,
+                               ARRAY_SIZE(omap_wdt_latency), 0);
+       WARN(IS_ERR(od), "Cant build omap_device for %s:%s.\n",
+                               dev_name, oh->name);
+       return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
new file mode 100644 (file)
index 0000000..703f150
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-smsc911x.c
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from linux/arch/arm/mach-omap2/gpmc-smc91x.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/smsc911x.h>
+
+#include <plat/board.h>
+#include <plat/gpmc.h>
+#include <plat/gpmc-smsc911x.h>
+
+static struct omap_smsc911x_platform_data *gpmc_cfg;
+
+static struct resource gpmc_smsc911x_resources[] = {
+       [0] = {
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config gpmc_smsc911x_config = {
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_16BIT,
+};
+
+static struct platform_device gpmc_smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(gpmc_smsc911x_resources),
+       .resource       = gpmc_smsc911x_resources,
+       .dev            = {
+               .platform_data = &gpmc_smsc911x_config,
+       },
+};
+
+/*
+ * Initialize smsc911x device connected to the GPMC. Note that we
+ * assume that pin multiplexing is done in the board-*.c file,
+ * or in the bootloader.
+ */
+void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
+{
+       unsigned long cs_mem_base;
+       int ret;
+
+       gpmc_cfg = board_data;
+
+       if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+               return;
+       }
+
+       gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
+       gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
+
+       if (gpio_request(gpmc_cfg->gpio_irq, "smsc911x irq") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
+                               gpmc_cfg->gpio_irq);
+               goto free1;
+       }
+
+       gpio_direction_input(gpmc_cfg->gpio_irq);
+       gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+       gpmc_smsc911x_resources[1].flags |=
+                                       (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
+
+       if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
+               ret = gpio_request(gpmc_cfg->gpio_reset, "smsc911x reset");
+               if (ret) {
+                       printk(KERN_ERR "Failed to request GPIO%d for smsc911x reset\n",
+                                       gpmc_cfg->gpio_reset);
+                       goto free2;
+               }
+
+               gpio_direction_output(gpmc_cfg->gpio_reset, 1);
+               gpio_set_value(gpmc_cfg->gpio_reset, 0);
+               msleep(100);
+               gpio_set_value(gpmc_cfg->gpio_reset, 1);
+       }
+
+       if (platform_device_register(&gpmc_smsc911x_device) < 0) {
+               printk(KERN_ERR "Unable to register smsc911x device\n");
+               gpio_free(gpmc_cfg->gpio_reset);
+               goto free2;
+       }
+
+       return;
+
+free2:
+       gpio_free(gpmc_cfg->gpio_irq);
+free1:
+       gpmc_cs_free(gpmc_cfg->cs);
+
+       printk(KERN_ERR "Could not initialize smsc911x\n");
+}
index c8f647b6205e4707f432de5b0ec4ef4d014499da..34272e4863fd9a15d54cf114152c3202d3b1bbe2 100644 (file)
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <mach/hardware.h>
-#include <plat/control.h>
 #include <plat/mmc.h>
 #include <plat/omap-pm.h>
 
 #include "hsmmc.h"
+#include "control.h"
 
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
@@ -135,10 +135,11 @@ static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot,
         *
         * FIXME handle VMMC1A as needed ...
         */
-       reg = omap_ctrl_readl(control_pbias_offset);
-       reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
-                                       OMAP4_USBC1_ICUSB_PWRDNZ);
-       omap_ctrl_writel(reg, control_pbias_offset);
+       reg = omap4_ctrl_pad_readl(control_pbias_offset);
+       reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+               OMAP4_MMC1_PWRDNZ_MASK |
+               OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+       omap4_ctrl_pad_writel(reg, control_pbias_offset);
 }
 
 static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
@@ -147,30 +148,33 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
        u32 reg;
 
        if (power_on) {
-               reg = omap_ctrl_readl(control_pbias_offset);
-               reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ;
+               reg = omap4_ctrl_pad_readl(control_pbias_offset);
+               reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK;
                if ((1 << vdd) <= MMC_VDD_165_195)
-                       reg &= ~OMAP4_MMC1_PBIASLITE_VMODE;
+                       reg &= ~OMAP4_MMC1_PBIASLITE_VMODE_MASK;
                else
-                       reg |= OMAP4_MMC1_PBIASLITE_VMODE;
-               reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
-                                               OMAP4_USBC1_ICUSB_PWRDNZ);
-               omap_ctrl_writel(reg, control_pbias_offset);
+                       reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK;
+               reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+                       OMAP4_MMC1_PWRDNZ_MASK |
+                       OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+               omap4_ctrl_pad_writel(reg, control_pbias_offset);
                /* 4 microsec delay for comparator to generate an error*/
                udelay(4);
-               reg = omap_ctrl_readl(control_pbias_offset);
-               if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR) {
+               reg = omap4_ctrl_pad_readl(control_pbias_offset);
+               if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) {
                        pr_err("Pbias Voltage is not same as LDO\n");
                        /* Caution : On VMODE_ERROR Power Down MMC IO */
-                       reg &= ~(OMAP4_MMC1_PWRDNZ | OMAP4_USBC1_ICUSB_PWRDNZ);
-                       omap_ctrl_writel(reg, control_pbias_offset);
+                       reg &= ~(OMAP4_MMC1_PWRDNZ_MASK |
+                               OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+                       omap4_ctrl_pad_writel(reg, control_pbias_offset);
                }
        } else {
-               reg = omap_ctrl_readl(control_pbias_offset);
-                reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ |
-                       OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PWRDNZ |
-                       OMAP4_USBC1_ICUSB_PWRDNZ);
-               omap_ctrl_writel(reg, control_pbias_offset);
+               reg = omap4_ctrl_pad_readl(control_pbias_offset);
+               reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+                       OMAP4_MMC1_PWRDNZ_MASK |
+                       OMAP4_MMC1_PBIASLITE_VMODE_MASK |
+                       OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+               omap4_ctrl_pad_writel(reg, control_pbias_offset);
        }
 }
 
@@ -218,17 +222,18 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
                        control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
                }
        } else {
-               control_pbias_offset = OMAP44XX_CONTROL_PBIAS_LITE;
-               control_mmc1 = OMAP44XX_CONTROL_MMC1;
-               reg = omap_ctrl_readl(control_mmc1);
-               reg |= (OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 |
-                       OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1);
-               reg &= ~(OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 |
-                       OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3);
-               reg |= (OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL |
-                       OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL |
-                       OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL);
-               omap_ctrl_writel(reg, control_mmc1);
+               control_pbias_offset =
+                       OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE;
+               control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1;
+               reg = omap4_ctrl_pad_readl(control_mmc1);
+               reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK |
+                       OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK);
+               reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK |
+                       OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK);
+               reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK|
+                       OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK |
+                       OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK);
+               omap4_ctrl_pad_writel(reg, control_mmc1);
        }
 
        for (c = controllers; c->mmc; c++) {
@@ -258,9 +263,13 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
                                "mmc%islot%i", c->mmc, 1);
                mmc->slots[0].name = hc->name;
                mmc->nr_slots = 1;
-               mmc->slots[0].wires = c->wires;
+               mmc->slots[0].caps = c->caps;
                mmc->slots[0].internal_clock = !c->ext_clock;
                mmc->dma_mask = 0xffffffff;
+               if (cpu_is_omap44xx())
+                       mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
+               else
+                       mmc->reg_offset = 0;
 
                mmc->get_context_loss_count = hsmmc_get_context_loss;
 
@@ -298,6 +307,9 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
                else
                        mmc->slots[0].features |= HSMMC_HAS_PBIAS;
 
+               if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
+                       mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
                switch (c->mmc) {
                case 1:
                        if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
@@ -316,16 +328,20 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
                        }
 
                        /* Omap3630 HSMMC1 supports only 4-bit */
-                       if (cpu_is_omap3630() && c->wires > 4) {
-                               c->wires = 4;
-                               mmc->slots[0].wires = c->wires;
+                       if (cpu_is_omap3630() &&
+                                       (c->caps & MMC_CAP_8_BIT_DATA)) {
+                               c->caps &= ~MMC_CAP_8_BIT_DATA;
+                               c->caps |= MMC_CAP_4_BIT_DATA;
+                               mmc->slots[0].caps = c->caps;
                        }
                        break;
                case 2:
                        if (c->ext_clock)
                                c->transceiver = 1;
-                       if (c->transceiver && c->wires > 4)
-                               c->wires = 4;
+                       if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
+                               c->caps &= ~MMC_CAP_8_BIT_DATA;
+                               c->caps |= MMC_CAP_4_BIT_DATA;
+                       }
                        /* FALLTHROUGH */
                case 3:
                        if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
index 0f8a2e6ee284130f9a4ced41f445e1f51f5bdb2c..f119348827d46d029c3cc7544ca1293420b7156c 100644 (file)
@@ -10,7 +10,8 @@ struct mmc_card;
 
 struct omap2_hsmmc_info {
        u8      mmc;            /* controller 1/2/3 */
-       u8      wires;          /* 1/4/8 wires */
+       u32     caps;           /* 4/8 wires and any additional host
+                                * capabilities OR'd (ref. linux/mmc/host.h) */
        bool    transceiver;    /* MMC-2 option */
        bool    ext_clock;      /* use external pin for input clock */
        bool    cover_only;     /* No card detect - just cover switch */
index 9a879f9595098dd5e3fcb303b8d205af744d3a28..5f9086c65e48262835a39d3c7c86b000eba543dd 100644 (file)
 #include <asm/cputype.h>
 
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/cpu.h>
 
 #include <mach/id.h>
 
+#include "control.h"
+
 static struct omap_chip_id omap_chip;
 static unsigned int omap_revision;
 
@@ -60,7 +61,7 @@ int omap_type(void)
        } else if (cpu_is_omap34xx()) {
                val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
        } else if (cpu_is_omap44xx()) {
-               val = omap_ctrl_readl(OMAP44XX_CONTROL_STATUS);
+               val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
        } else {
                pr_err("Cannot detect omap type!\n");
                goto out;
@@ -298,7 +299,6 @@ static void __init omap4_check_revision(void)
        u32 idcode;
        u16 hawkeye;
        u8 rev;
-       char *rev_name = "ES1.0";
 
        /*
         * The IC rev detection is done with hawkeye and rev.
@@ -309,14 +309,39 @@ static void __init omap4_check_revision(void)
        hawkeye = (idcode >> 12) & 0xffff;
        rev = (idcode >> 28) & 0xff;
 
-       if ((hawkeye == 0xb852) && (rev == 0x0)) {
-               omap_revision = OMAP4430_REV_ES1_0;
-               omap_chip.oc |= CHIP_IS_OMAP4430ES1;
-               pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
-               return;
+       /*
+        * Few initial ES2.0 samples IDCODE is same as ES1.0
+        * Use ARM register to detect the correct ES version
+        */
+       if (!rev) {
+               idcode = read_cpuid(CPUID_ID);
+               rev = (idcode & 0xf) - 1;
+       }
+
+       switch (hawkeye) {
+       case 0xb852:
+               switch (rev) {
+               case 0:
+                       omap_revision = OMAP4430_REV_ES1_0;
+                       omap_chip.oc |= CHIP_IS_OMAP4430ES1;
+                       break;
+               case 1:
+                       omap_revision = OMAP4430_REV_ES2_0;
+                       omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+                       break;
+               default:
+                       omap_revision = OMAP4430_REV_ES2_0;
+                       omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+       }
+       break;
+       default:
+               /* Unknown default to latest silicon rev as default*/
+               omap_revision = OMAP4430_REV_ES2_0;
+               omap_chip.oc |= CHIP_IS_OMAP4430ES2;
        }
 
-       pr_err("Unknown OMAP4 CPU id\n");
+       pr_info("OMAP%04x ES%d.0\n",
+                       omap_rev() >> 16, ((omap_rev() >> 12) & 0xf) + 1);
 }
 
 #define OMAP3_SHOW_FEATURE(feat)               \
@@ -361,30 +386,54 @@ static void __init omap3_cpuinfo(void)
                strcpy(cpu_name, "OMAP3503");
        }
 
-       switch (rev) {
-       case OMAP_REVBITS_00:
-               strcpy(cpu_rev, "1.0");
-               break;
-       case OMAP_REVBITS_01:
-               strcpy(cpu_rev, "1.1");
-               break;
-       case OMAP_REVBITS_02:
-               strcpy(cpu_rev, "1.2");
-               break;
-       case OMAP_REVBITS_10:
-               strcpy(cpu_rev, "2.0");
-               break;
-       case OMAP_REVBITS_20:
-               strcpy(cpu_rev, "2.1");
-               break;
-       case OMAP_REVBITS_30:
-               strcpy(cpu_rev, "3.0");
-               break;
-       case OMAP_REVBITS_40:
-       /* FALLTHROUGH */
-       default:
-               /* Use the latest known revision as default */
-               strcpy(cpu_rev, "3.1");
+       if (cpu_is_omap3630()) {
+               switch (rev) {
+               case OMAP_REVBITS_00:
+                       strcpy(cpu_rev, "1.0");
+                       break;
+               case OMAP_REVBITS_01:
+                       strcpy(cpu_rev, "1.1");
+                       break;
+               case OMAP_REVBITS_02:
+                       /* FALLTHROUGH */
+               default:
+                       /* Use the latest known revision as default */
+                       strcpy(cpu_rev, "1.2");
+               }
+       } else if (cpu_is_omap3505() || cpu_is_omap3517()) {
+               switch (rev) {
+               case OMAP_REVBITS_00:
+                       strcpy(cpu_rev, "1.0");
+                       break;
+               case OMAP_REVBITS_01:
+                       /* FALLTHROUGH */
+               default:
+                       /* Use the latest known revision as default */
+                       strcpy(cpu_rev, "1.1");
+               }
+       } else {
+               switch (rev) {
+               case OMAP_REVBITS_00:
+                       strcpy(cpu_rev, "1.0");
+                       break;
+               case OMAP_REVBITS_01:
+                       strcpy(cpu_rev, "2.0");
+                       break;
+               case OMAP_REVBITS_02:
+                       strcpy(cpu_rev, "2.1");
+                       break;
+               case OMAP_REVBITS_03:
+                       strcpy(cpu_rev, "3.0");
+                       break;
+               case OMAP_REVBITS_04:
+                       strcpy(cpu_rev, "3.1");
+                       break;
+               case OMAP_REVBITS_05:
+                       /* FALLTHROUGH */
+               default:
+                       /* Use the latest known revision as default */
+                       strcpy(cpu_rev, "3.1.2");
+               }
        }
 
        /* Print verbose information */
diff --git a/arch/arm/mach-omap2/include/mach/board-flash.h b/arch/arm/mach-omap2/include/mach/board-flash.h
deleted file mode 100644 (file)
index b2242ae..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  board-sdp.h
- *
- *  Information structures for SDP-specific board config data
- *
- *  Copyright (C) 2009 Nokia Corporation
- *  Copyright (C) 2009 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/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <plat/gpmc.h>
-
-#define PDC_NOR                1
-#define PDC_NAND       2
-#define PDC_ONENAND    3
-#define DBG_MPDB       4
-
-struct flash_partitions {
-       struct mtd_partition *parts;
-       int nr_parts;
-};
-
-extern void board_flash_init(struct flash_partitions [],
-                               char chip_sel[][GPMC_CS_NUM]);
diff --git a/arch/arm/mach-omap2/include/mach/board-rx51.h b/arch/arm/mach-omap2/include/mach/board-rx51.h
new file mode 100644 (file)
index 0000000..b76f49e
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Defines for rx51 boards
+ */
+
+#ifndef _OMAP_BOARD_RX51_H
+#define _OMAP_BOARD_RX51_H
+
+extern void __init rx51_peripherals_init(void);
+extern void __init rx51_video_mem_init(void);
+
+#endif
index 3af69d2c3dcde626a6f74cdff393cc3be7926201..f93ca3928c3bd65aaa63473a72e732a869a89930 100644 (file)
@@ -1,11 +1,9 @@
 /*
  * Defines for zoom boards
  */
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
 #define ZOOM_NAND_CS    0
 
-extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO     153
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
new file mode 100644 (file)
index 0000000..2f7ac70
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * OMAP44xx CTRL_MODULE_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_CORE                                 0x4a002000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_CORE_IP_REVISION                     0x0000
+#define OMAP4_CTRL_MODULE_CORE_IP_HWINFO                       0x0004
+#define OMAP4_CTRL_MODULE_CORE_IP_SYSCONFIG                    0x0010
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_0               0x0200
+#define OMAP4_CTRL_MODULE_CORE_ID_CODE                         0x0204
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_1               0x0208
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_2               0x020c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_3               0x0210
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_0              0x0214
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1              0x0218
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_USB_CONF               0x021c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_VDD_WKUP           0x0228
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP               0x0260
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_0             0x0264
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_1             0x0268
+#define OMAP4_CTRL_MODULE_CORE_STATUS                          0x02c4
+#define OMAP4_CTRL_MODULE_CORE_DEV_CONF                                0x0300
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_IVA_VOLTAGE_CTRL         0x0314
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_MPU_VOLTAGE_CTRL         0x0318
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_IVA_VOLTAGE_CTRL                0x0320
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_MPU_VOLTAGE_CTRL                0x0324
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_CORE_VOLTAGE_CTRL       0x0328
+#define OMAP4_CTRL_MODULE_CORE_TEMP_SENSOR                     0x032c
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_0               0x0330
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_1               0x0334
+#define OMAP4_CTRL_MODULE_CORE_USBOTGHS_CONTROL                        0x033c
+#define OMAP4_CTRL_MODULE_CORE_DSS_CONTROL                     0x0340
+#define OMAP4_CTRL_MODULE_CORE_HWOBS_CONTROL                   0x0350
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_FINAL_MUX_SEL            0x0400
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_MMR_MPU                  0x0408
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL0              0x042c
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL1              0x0430
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL2              0x0434
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL3              0x0438
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL0                   0x0440
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL1                   0x0444
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL2                   0x0448
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_FREQLOCK_SEL          0x044c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_TINITZ_SEL            0x0450
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_PHASELOCK_SEL         0x0454
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_0            0x0480
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_1            0x0484
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_2            0x0488
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_3            0x048c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_4            0x0490
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_5            0x0494
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_6            0x0498
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_7            0x049c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_8            0x04a0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_9            0x04a4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_10           0x04a8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_11           0x04ac
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_12           0x04b0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_13           0x04b4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_14           0x04b8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_15           0x04bc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_16           0x04c0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_17           0x04c4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_18           0x04c8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_19           0x04cc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_20           0x04d0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_21           0x04d4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_22           0x04d8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_23           0x04dc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_24           0x04e0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_25           0x04e4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_26           0x04e8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_27           0x04ec
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_28           0x04f0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_29           0x04f4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_30           0x04f8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_31           0x04fc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT                      30
+#define OMAP4_IP_REV_SCHEME_MASK                       (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT                                16
+#define OMAP4_IP_REV_FUNC_MASK                         (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT                         11
+#define OMAP4_IP_REV_RTL_MASK                          (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT                       8
+#define OMAP4_IP_REV_MAJOR_MASK                                (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT                      6
+#define OMAP4_IP_REV_CUSTOM_MASK                       (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT                       0
+#define OMAP4_IP_REV_MINOR_MASK                                (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT                          0
+#define OMAP4_IP_HWINFO_MASK                           (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT              2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK               (0x3 << 2)
+
+/* STD_FUSE_DIE_ID_0 */
+#define OMAP4_STD_FUSE_DIE_ID_0_SHIFT                  0
+#define OMAP4_STD_FUSE_DIE_ID_0_MASK                   (0xffffffff << 0)
+
+/* ID_CODE */
+#define OMAP4_STD_FUSE_IDCODE_SHIFT                    0
+#define OMAP4_STD_FUSE_IDCODE_MASK                     (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_1 */
+#define OMAP4_STD_FUSE_DIE_ID_1_SHIFT                  0
+#define OMAP4_STD_FUSE_DIE_ID_1_MASK                   (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_2 */
+#define OMAP4_STD_FUSE_DIE_ID_2_SHIFT                  0
+#define OMAP4_STD_FUSE_DIE_ID_2_MASK                   (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_3 */
+#define OMAP4_STD_FUSE_DIE_ID_3_SHIFT                  0
+#define OMAP4_STD_FUSE_DIE_ID_3_MASK                   (0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_0 */
+#define OMAP4_STD_FUSE_PROD_ID_0_SHIFT                 0
+#define OMAP4_STD_FUSE_PROD_ID_0_MASK                  (0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_1 */
+#define OMAP4_STD_FUSE_PROD_ID_1_SHIFT                 0
+#define OMAP4_STD_FUSE_PROD_ID_1_MASK                  (0xffffffff << 0)
+
+/* STD_FUSE_USB_CONF */
+#define OMAP4_USB_PROD_ID_SHIFT                                16
+#define OMAP4_USB_PROD_ID_MASK                         (0xffff << 16)
+#define OMAP4_USB_VENDOR_ID_SHIFT                      0
+#define OMAP4_USB_VENDOR_ID_MASK                       (0xffff << 0)
+
+/* STD_FUSE_OPP_VDD_WKUP */
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_SHIFT              0
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_MASK               (0xffffffff << 0)
+
+/* STD_FUSE_OPP_BGAP */
+#define OMAP4_STD_FUSE_OPP_BGAP_SHIFT                  0
+#define OMAP4_STD_FUSE_OPP_BGAP_MASK                   (0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_0 */
+#define OMAP4_STD_FUSE_OPP_DPLL_0_SHIFT                        0
+#define OMAP4_STD_FUSE_OPP_DPLL_0_MASK                 (0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_1 */
+#define OMAP4_STD_FUSE_OPP_DPLL_1_SHIFT                        0
+#define OMAP4_STD_FUSE_OPP_DPLL_1_MASK                 (0xffffffff << 0)
+
+/* STATUS */
+#define OMAP4_ATTILA_CONF_SHIFT                                11
+#define OMAP4_ATTILA_CONF_MASK                         (0x3 << 11)
+#define OMAP4_DEVICE_TYPE_SHIFT                                8
+#define OMAP4_DEVICE_TYPE_MASK                         (0x7 << 8)
+#define OMAP4_SYS_BOOT_SHIFT                           0
+#define OMAP4_SYS_BOOT_MASK                            (0xff << 0)
+
+/* DEV_CONF */
+#define OMAP4_DEV_CONF_SHIFT                           1
+#define OMAP4_DEV_CONF_MASK                            (0x7fffffff << 1)
+#define OMAP4_USBPHY_PD_SHIFT                          0
+#define OMAP4_USBPHY_PD_MASK                           (1 << 0)
+
+/* LDOVBB_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_SHIFT             26
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_MASK              (1 << 26)
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_SHIFT              21
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_MASK               (0x1f << 21)
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_SHIFT             16
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_MASK              (0x1f << 16)
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_SHIFT             10
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_MASK              (1 << 10)
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_SHIFT              5
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_MASK               (0x1f << 5)
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_SHIFT             0
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_MASK              (0x1f << 0)
+
+/* LDOVBB_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_SHIFT             26
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_MASK              (1 << 26)
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_SHIFT              21
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_MASK               (0x1f << 21)
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_SHIFT             16
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_MASK              (0x1f << 16)
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_SHIFT             10
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_MASK              (1 << 10)
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_SHIFT              5
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_MASK               (0x1f << 5)
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_SHIFT             0
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_MASK              (0x1f << 0)
+
+/* LDOSRAM_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_SHIFT                26
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_MASK         (1 << 26)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_SHIFT         21
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_MASK          (0x1f << 21)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_SHIFT                16
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_MASK         (0x1f << 16)
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_SHIFT                10
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_MASK         (1 << 10)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_SHIFT         5
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_MASK          (0x1f << 5)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_SHIFT                0
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_MASK         (0x1f << 0)
+
+/* LDOSRAM_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_SHIFT                26
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_MASK         (1 << 26)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_SHIFT         21
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_MASK          (0x1f << 21)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_SHIFT                16
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_MASK         (0x1f << 16)
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_SHIFT                10
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_MASK         (1 << 10)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_SHIFT         5
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_MASK          (0x1f << 5)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_SHIFT                0
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_MASK         (0x1f << 0)
+
+/* LDOSRAM_CORE_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_SHIFT       26
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_MASK                (1 << 26)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_SHIFT                21
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_MASK         (0x1f << 21)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_SHIFT       16
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_MASK                (0x1f << 16)
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_SHIFT       10
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_MASK                (1 << 10)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_SHIFT                5
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_MASK         (0x1f << 5)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT       0
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK                (0x1f << 0)
+
+/* TEMP_SENSOR */
+#define OMAP4_BGAP_TEMPSOFF_SHIFT                      12
+#define OMAP4_BGAP_TEMPSOFF_MASK                       (1 << 12)
+#define OMAP4_BGAP_TSHUT_SHIFT                         11
+#define OMAP4_BGAP_TSHUT_MASK                          (1 << 11)
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT          10
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK           (1 << 10)
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT               9
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK                        (1 << 9)
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT              8
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK               (1 << 8)
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT             0
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK              (0xff << 0)
+
+/* DPLL_NWELL_TRIM_0 */
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT       29
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_MASK                (1 << 29)
+#define OMAP4_DPLL_ABE_NWELL_TRIM_SHIFT                        24
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MASK                 (0x1f << 24)
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_SHIFT       23
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_MASK                (1 << 23)
+#define OMAP4_DPLL_PER_NWELL_TRIM_SHIFT                        18
+#define OMAP4_DPLL_PER_NWELL_TRIM_MASK                 (0x1f << 18)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_SHIFT      17
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_MASK       (1 << 17)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_SHIFT               12
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MASK                        (0x1f << 12)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_SHIFT       11
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_MASK                (1 << 11)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_SHIFT                        6
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MASK                 (0x1f << 6)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_SHIFT       5
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_MASK                (1 << 5)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_SHIFT                        0
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MASK                 (0x1f << 0)
+
+/* DPLL_NWELL_TRIM_1 */
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_SHIFT    29
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_MASK     (1 << 29)
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_SHIFT             24
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MASK              (0x1f << 24)
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_SHIFT       23
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_MASK                (1 << 23)
+#define OMAP4_DPLL_USB_NWELL_TRIM_SHIFT                        18
+#define OMAP4_DPLL_USB_NWELL_TRIM_MASK                 (0x1f << 18)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_SHIFT      17
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_MASK       (1 << 17)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_SHIFT               12
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MASK                        (0x1f << 12)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_SHIFT      11
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_MASK       (1 << 11)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_SHIFT               6
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MASK                        (0x1f << 6)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_SHIFT      5
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_MASK       (1 << 5)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_SHIFT               0
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MASK                        (0x1f << 0)
+
+/* USBOTGHS_CONTROL */
+#define OMAP4_DISCHRGVBUS_SHIFT                                8
+#define OMAP4_DISCHRGVBUS_MASK                         (1 << 8)
+#define OMAP4_CHRGVBUS_SHIFT                           7
+#define OMAP4_CHRGVBUS_MASK                            (1 << 7)
+#define OMAP4_DRVVBUS_SHIFT                            6
+#define OMAP4_DRVVBUS_MASK                             (1 << 6)
+#define OMAP4_IDPULLUP_SHIFT                           5
+#define OMAP4_IDPULLUP_MASK                            (1 << 5)
+#define OMAP4_IDDIG_SHIFT                              4
+#define OMAP4_IDDIG_MASK                               (1 << 4)
+#define OMAP4_SESSEND_SHIFT                            3
+#define OMAP4_SESSEND_MASK                             (1 << 3)
+#define OMAP4_VBUSVALID_SHIFT                          2
+#define OMAP4_VBUSVALID_MASK                           (1 << 2)
+#define OMAP4_BVALID_SHIFT                             1
+#define OMAP4_BVALID_MASK                              (1 << 1)
+#define OMAP4_AVALID_SHIFT                             0
+#define OMAP4_AVALID_MASK                              (1 << 0)
+
+/* DSS_CONTROL */
+#define OMAP4_DSS_MUX6_SELECT_SHIFT                    0
+#define OMAP4_DSS_MUX6_SELECT_MASK                     (1 << 0)
+
+/* HWOBS_CONTROL */
+#define OMAP4_HWOBS_CLKDIV_SEL_SHIFT                   3
+#define OMAP4_HWOBS_CLKDIV_SEL_MASK                    (0x1f << 3)
+#define OMAP4_HWOBS_ALL_ZERO_MODE_SHIFT                        2
+#define OMAP4_HWOBS_ALL_ZERO_MODE_MASK                 (1 << 2)
+#define OMAP4_HWOBS_ALL_ONE_MODE_SHIFT                 1
+#define OMAP4_HWOBS_ALL_ONE_MODE_MASK                  (1 << 1)
+#define OMAP4_HWOBS_MACRO_ENABLE_SHIFT                 0
+#define OMAP4_HWOBS_MACRO_ENABLE_MASK                  (1 << 0)
+
+/* DEBOBS_FINAL_MUX_SEL */
+#define OMAP4_SELECT_SHIFT                             0
+#define OMAP4_SELECT_MASK                              (0xffffffff << 0)
+
+/* DEBOBS_MMR_MPU */
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_SHIFT              0
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_MASK               (0xf << 0)
+
+/* CONF_SDMA_REQ_SEL0 */
+#define OMAP4_MULT_SHIFT                               0
+#define OMAP4_MULT_MASK                                        (0x7f << 0)
+
+/* CONF_CLK_SEL0 */
+#define OMAP4_MULT_CONF_CLK_SEL0_SHIFT                 0
+#define OMAP4_MULT_CONF_CLK_SEL0_MASK                  (0x7 << 0)
+
+/* CONF_CLK_SEL1 */
+#define OMAP4_MULT_CONF_CLK_SEL1_SHIFT                 0
+#define OMAP4_MULT_CONF_CLK_SEL1_MASK                  (0x7 << 0)
+
+/* CONF_CLK_SEL2 */
+#define OMAP4_MULT_CONF_CLK_SEL2_SHIFT                 0
+#define OMAP4_MULT_CONF_CLK_SEL2_MASK                  (0x7 << 0)
+
+/* CONF_DPLL_FREQLOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_SHIFT                0
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_MASK         (0x7 << 0)
+
+/* CONF_DPLL_TINITZ_SEL */
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_SHIFT          0
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_MASK           (0x7 << 0)
+
+/* CONF_DPLL_PHASELOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_SHIFT       0
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_MASK                (0x7 << 0)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_MODE_SHIFT                               0
+#define OMAP4_MODE_MASK                                        (0xf << 0)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h
new file mode 100644 (file)
index 0000000..c88420d
--- /dev/null
@@ -0,0 +1,1409 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_CORE                             0x4a100000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_REVISION                 0x0000
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_HWINFO                   0x0004
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_SYSCONFIG                        0x0010
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_0       0x01d8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_1       0x01dc
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_2       0x01e0
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_3       0x01e4
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_4       0x01e8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_5       0x01ec
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_6       0x01f0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_GLOBAL      0x05a0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_MODE                0x05a4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_0  0x05a8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_1  0x05ac
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_0  0x05b0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_1  0x05b4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_0  0x05b8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_1  0x05bc
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_2  0x05c0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC           0x05c4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SLIMBUS             0x05c8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE           0x0600
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0               0x0604
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX           0x0608
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_AVDAC               0x060c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDMI_TX_PHY         0x0610
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC2                        0x0614
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY              0x0618
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP             0x061c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB2PHYCORE         0x0620
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1               0x0624
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1                        0x0628
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HSI                 0x062c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB                 0x0630
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDQ                 0x0634
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_0         0x0638
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_1         0x063c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2         0x0640
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_3         0x0644
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_0         0x0648
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_1         0x064c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2         0x0650
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3         0x0654
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_BUS_HOLD            0x0658
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_C2C                 0x065c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_RW       0x0660
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R                0x0664
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R_C0     0x0668
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1             0x0700
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2             0x0704
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_3             0x0708
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_4             0x070c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT                              30
+#define OMAP4_IP_REV_SCHEME_MASK                               (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT                                        16
+#define OMAP4_IP_REV_FUNC_MASK                                 (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT                                 11
+#define OMAP4_IP_REV_RTL_MASK                                  (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT                               8
+#define OMAP4_IP_REV_MAJOR_MASK                                        (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT                              6
+#define OMAP4_IP_REV_CUSTOM_MASK                               (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT                               0
+#define OMAP4_IP_REV_MINOR_MASK                                        (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT                                  0
+#define OMAP4_IP_HWINFO_MASK                                   (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT                      2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK                       (0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_SHIFT              31
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_MASK               (1 << 31)
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_SHIFT              30
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_MASK               (1 << 30)
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_SHIFT             29
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_MASK              (1 << 29)
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_SHIFT             28
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_MASK              (1 << 28)
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_SHIFT             27
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_MASK              (1 << 27)
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_SHIFT             26
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_MASK              (1 << 26)
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_SHIFT              25
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_MASK               (1 << 25)
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_SHIFT              24
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_MASK               (1 << 24)
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_SHIFT              23
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_MASK               (1 << 23)
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_SHIFT              22
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_MASK               (1 << 22)
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_SHIFT              21
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_MASK               (1 << 21)
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_SHIFT              20
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_MASK               (1 << 20)
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_SHIFT              19
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_MASK               (1 << 19)
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_SHIFT              18
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_MASK               (1 << 18)
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_SHIFT              17
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_MASK               (1 << 17)
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_SHIFT              16
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_MASK               (1 << 16)
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_SHIFT             15
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_MASK              (1 << 15)
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_SHIFT             14
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_MASK              (1 << 14)
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_SHIFT             13
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_MASK              (1 << 13)
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_SHIFT             12
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_MASK              (1 << 12)
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_SHIFT             11
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_MASK              (1 << 11)
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_SHIFT             10
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_MASK              (1 << 10)
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_SHIFT              9
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_MASK               (1 << 9)
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_SHIFT              8
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_MASK               (1 << 8)
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_SHIFT              7
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_MASK               (1 << 7)
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_SHIFT              6
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_MASK               (1 << 6)
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_SHIFT              5
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_MASK               (1 << 5)
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_SHIFT              4
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_MASK               (1 << 4)
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_SHIFT              3
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_MASK               (1 << 3)
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_SHIFT              2
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_MASK               (1 << 2)
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_SHIFT              1
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_MASK               (1 << 1)
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_SHIFT              0
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_MASK               (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_1 */
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_SHIFT            31
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_MASK             (1 << 31)
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_SHIFT           30
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_MASK            (1 << 30)
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_SHIFT             29
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_MASK              (1 << 29)
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_SHIFT             28
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_MASK              (1 << 28)
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_SHIFT             27
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_MASK              (1 << 27)
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_SHIFT             26
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_MASK              (1 << 26)
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_SHIFT             25
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_MASK              (1 << 25)
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_SHIFT             24
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_MASK              (1 << 24)
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_SHIFT             23
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_MASK              (1 << 23)
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_SHIFT             22
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_MASK              (1 << 22)
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_SHIFT             21
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_MASK              (1 << 21)
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_SHIFT             20
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_MASK              (1 << 20)
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_SHIFT             19
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_MASK              (1 << 19)
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_SHIFT             18
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_MASK              (1 << 18)
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_SHIFT             17
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_MASK              (1 << 17)
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_SHIFT             16
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_MASK              (1 << 16)
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_SHIFT          15
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_MASK           (1 << 15)
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_SHIFT          14
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_MASK           (1 << 14)
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_SHIFT              13
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_MASK               (1 << 13)
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_SHIFT              12
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_MASK               (1 << 12)
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_SHIFT            11
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_MASK             (1 << 11)
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_SHIFT            10
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_MASK             (1 << 10)
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_SHIFT            9
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_MASK             (1 << 9)
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_SHIFT            8
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_MASK             (1 << 8)
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_SHIFT            7
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_MASK             (1 << 7)
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_SHIFT            6
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_MASK             (1 << 6)
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_SHIFT            5
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_MASK             (1 << 5)
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_SHIFT             4
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_MASK              (1 << 4)
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_SHIFT         3
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_MASK          (1 << 3)
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_SHIFT              2
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_MASK               (1 << 2)
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_SHIFT              1
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_MASK               (1 << 1)
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_SHIFT         0
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_MASK          (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_2 */
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_SHIFT       31
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_MASK                (1 << 31)
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_SHIFT                30
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_MASK         (1 << 30)
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_SHIFT         29
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_MASK          (1 << 29)
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_SHIFT         28
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_MASK          (1 << 28)
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_SHIFT       27
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_MASK                (1 << 27)
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_SHIFT           26
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_MASK            (1 << 26)
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_SHIFT           25
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_MASK            (1 << 25)
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_SHIFT           24
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_MASK            (1 << 24)
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_SHIFT           23
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_MASK            (1 << 23)
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_SHIFT           22
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_MASK            (1 << 22)
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_SHIFT           21
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_MASK            (1 << 21)
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_SHIFT           20
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_MASK            (1 << 20)
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_SHIFT           19
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_MASK            (1 << 19)
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_SHIFT            18
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_MASK             (1 << 18)
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_SHIFT            17
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_MASK             (1 << 17)
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_SHIFT                16
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_MASK         (1 << 16)
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_SHIFT                15
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_MASK         (1 << 15)
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT     14
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK      (1 << 14)
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT       13
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK                (1 << 13)
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT    12
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK     (1 << 12)
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT    11
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK     (1 << 11)
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT    10
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK     (1 << 10)
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT    9
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK     (1 << 9)
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT    8
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK     (1 << 8)
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT    7
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK     (1 << 7)
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT    6
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK     (1 << 6)
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT    5
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK     (1 << 5)
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT     4
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK      (1 << 4)
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT     3
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK      (1 << 3)
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT     2
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK      (1 << 2)
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT     1
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK      (1 << 1)
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_SHIFT       0
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_MASK                (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_3 */
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_SHIFT            31
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_MASK             (1 << 31)
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_SHIFT            30
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_MASK             (1 << 30)
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_SHIFT            29
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_MASK             (1 << 29)
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_SHIFT            28
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_MASK             (1 << 28)
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_SHIFT           27
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_MASK            (1 << 27)
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_SHIFT           26
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_MASK            (1 << 26)
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_SHIFT            25
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_MASK             (1 << 25)
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_SHIFT              24
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_MASK               (1 << 24)
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_SHIFT              23
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_MASK               (1 << 23)
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_SHIFT              22
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_MASK               (1 << 22)
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_SHIFT              21
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_MASK               (1 << 21)
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_SHIFT              20
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_MASK               (1 << 20)
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_SHIFT              19
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_MASK               (1 << 19)
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_SHIFT              18
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_MASK               (1 << 18)
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_SHIFT              17
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_MASK               (1 << 17)
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_SHIFT               16
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_MASK                        (1 << 16)
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_SHIFT              15
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_MASK               (1 << 15)
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_SHIFT              14
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_MASK               (1 << 14)
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_SHIFT             13
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_MASK              (1 << 13)
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_SHIFT             12
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_MASK              (1 << 12)
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_SHIFT         11
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_MASK          (1 << 11)
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_SHIFT         10
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_MASK          (1 << 10)
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_SHIFT         9
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_MASK          (1 << 9)
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_SHIFT         8
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_MASK          (1 << 8)
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_SHIFT              7
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_MASK               (1 << 7)
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_SHIFT                6
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_MASK         (1 << 6)
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_SHIFT         5
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_MASK          (1 << 5)
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_SHIFT       4
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_MASK                (1 << 4)
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_SHIFT       3
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_MASK                (1 << 3)
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_SHIFT                2
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_MASK         (1 << 2)
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_SHIFT         1
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_MASK          (1 << 1)
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_SHIFT         0
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_MASK          (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_4 */
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_SHIFT            31
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_MASK             (1 << 31)
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_SHIFT            30
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_MASK             (1 << 30)
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT     29
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK      (1 << 29)
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT       28
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK                (1 << 28)
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT    27
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK     (1 << 27)
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT    26
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK     (1 << 26)
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT    25
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK     (1 << 25)
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT    24
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK     (1 << 24)
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT    23
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK     (1 << 23)
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT    22
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK     (1 << 22)
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT    21
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK     (1 << 21)
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT    20
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK     (1 << 20)
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT     19
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK      (1 << 19)
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT     18
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK      (1 << 18)
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT     17
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK      (1 << 17)
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT     16
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK      (1 << 16)
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_SHIFT              15
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_MASK               (1 << 15)
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_SHIFT              14
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_MASK               (1 << 14)
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_SHIFT            13
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_MASK             (1 << 13)
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_SHIFT           12
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_MASK            (1 << 12)
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_SHIFT           11
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_MASK            (1 << 11)
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_SHIFT            10
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_MASK             (1 << 10)
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_SHIFT           9
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_MASK            (1 << 9)
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_SHIFT           8
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_MASK            (1 << 8)
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_SHIFT           7
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_MASK            (1 << 7)
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_SHIFT           6
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_MASK            (1 << 6)
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_SHIFT            5
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_MASK             (1 << 5)
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_SHIFT            4
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_MASK             (1 << 4)
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_SHIFT         3
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_MASK          (1 << 3)
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_SHIFT         2
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_MASK          (1 << 2)
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_SHIFT          1
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_MASK           (1 << 1)
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_SHIFT                0
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_MASK         (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_5 */
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_SHIFT             31
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_MASK              (1 << 31)
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_SHIFT             30
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_MASK              (1 << 30)
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_SHIFT              29
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_MASK               (1 << 29)
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_SHIFT              28
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_MASK               (1 << 28)
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_SHIFT              27
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_MASK               (1 << 27)
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_SHIFT              26
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_MASK               (1 << 26)
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_SHIFT              25
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_MASK               (1 << 25)
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_SHIFT              24
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_MASK               (1 << 24)
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_SHIFT              23
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_MASK               (1 << 23)
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_SHIFT              22
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_MASK               (1 << 22)
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_SHIFT              21
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_MASK               (1 << 21)
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_SHIFT              20
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_MASK               (1 << 20)
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_SHIFT             19
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_MASK              (1 << 19)
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_SHIFT             18
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_MASK              (1 << 18)
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_SHIFT             17
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_MASK              (1 << 17)
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_SHIFT             16
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_MASK              (1 << 16)
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_SHIFT             15
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_MASK              (1 << 15)
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_SHIFT             14
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_MASK              (1 << 14)
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_SHIFT             13
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_MASK              (1 << 13)
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_SHIFT             12
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_MASK              (1 << 12)
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_SHIFT         11
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_MASK          (1 << 11)
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_SHIFT         10
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_MASK          (1 << 10)
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_SHIFT            9
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_MASK             (1 << 9)
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_SHIFT            8
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_MASK             (1 << 8)
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_SHIFT            7
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_MASK             (1 << 7)
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_SHIFT            6
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_MASK             (1 << 6)
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_SHIFT            5
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_MASK             (1 << 5)
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_SHIFT            4
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_MASK             (1 << 4)
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_SHIFT            3
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_MASK             (1 << 3)
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_SHIFT            2
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_MASK             (1 << 2)
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_SHIFT            1
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_MASK             (1 << 1)
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_SHIFT            0
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_MASK             (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_6 */
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_SHIFT             7
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_MASK              (1 << 7)
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_SHIFT             6
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_MASK              (1 << 6)
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_SHIFT             5
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_MASK              (1 << 5)
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_SHIFT             4
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_MASK              (1 << 4)
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_SHIFT             3
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_MASK              (1 << 3)
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_SHIFT             2
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_MASK              (1 << 2)
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_SHIFT             1
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_MASK              (1 << 1)
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_SHIFT             0
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_MASK              (1 << 0)
+
+/* CONTROL_PADCONF_GLOBAL */
+#define OMAP4_FORCE_OFFMODE_EN_SHIFT                           31
+#define OMAP4_FORCE_OFFMODE_EN_MASK                            (1 << 31)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_BANK0_SHIFT                              31
+#define OMAP4_VDDS_DV_BANK0_MASK                               (1 << 31)
+#define OMAP4_VDDS_DV_BANK1_SHIFT                              30
+#define OMAP4_VDDS_DV_BANK1_MASK                               (1 << 30)
+#define OMAP4_VDDS_DV_BANK3_SHIFT                              29
+#define OMAP4_VDDS_DV_BANK3_MASK                               (1 << 29)
+#define OMAP4_VDDS_DV_BANK4_SHIFT                              28
+#define OMAP4_VDDS_DV_BANK4_MASK                               (1 << 28)
+#define OMAP4_VDDS_DV_BANK5_SHIFT                              27
+#define OMAP4_VDDS_DV_BANK5_MASK                               (1 << 27)
+#define OMAP4_VDDS_DV_BANK6_SHIFT                              26
+#define OMAP4_VDDS_DV_BANK6_MASK                               (1 << 26)
+#define OMAP4_VDDS_DV_C2C_SHIFT                                        25
+#define OMAP4_VDDS_DV_C2C_MASK                                 (1 << 25)
+#define OMAP4_VDDS_DV_CAM_SHIFT                                        24
+#define OMAP4_VDDS_DV_CAM_MASK                                 (1 << 24)
+#define OMAP4_VDDS_DV_GPMC_SHIFT                               23
+#define OMAP4_VDDS_DV_GPMC_MASK                                        (1 << 23)
+#define OMAP4_VDDS_DV_SDMMC2_SHIFT                             22
+#define OMAP4_VDDS_DV_SDMMC2_MASK                              (1 << 22)
+
+/* CONTROL_SMART1IO_PADCONF_0 */
+#define OMAP4_ABE_DR0_SC_SHIFT                                 30
+#define OMAP4_ABE_DR0_SC_MASK                                  (0x3 << 30)
+#define OMAP4_CAM_DR0_SC_SHIFT                                 28
+#define OMAP4_CAM_DR0_SC_MASK                                  (0x3 << 28)
+#define OMAP4_FREF_DR2_SC_SHIFT                                        26
+#define OMAP4_FREF_DR2_SC_MASK                                 (0x3 << 26)
+#define OMAP4_FREF_DR3_SC_SHIFT                                        24
+#define OMAP4_FREF_DR3_SC_MASK                                 (0x3 << 24)
+#define OMAP4_GPIO_DR8_SC_SHIFT                                        22
+#define OMAP4_GPIO_DR8_SC_MASK                                 (0x3 << 22)
+#define OMAP4_GPIO_DR9_SC_SHIFT                                        20
+#define OMAP4_GPIO_DR9_SC_MASK                                 (0x3 << 20)
+#define OMAP4_GPMC_DR2_SC_SHIFT                                        18
+#define OMAP4_GPMC_DR2_SC_MASK                                 (0x3 << 18)
+#define OMAP4_GPMC_DR3_SC_SHIFT                                        16
+#define OMAP4_GPMC_DR3_SC_MASK                                 (0x3 << 16)
+#define OMAP4_GPMC_DR6_SC_SHIFT                                        14
+#define OMAP4_GPMC_DR6_SC_MASK                                 (0x3 << 14)
+#define OMAP4_HDMI_DR0_SC_SHIFT                                        12
+#define OMAP4_HDMI_DR0_SC_MASK                                 (0x3 << 12)
+#define OMAP4_MCSPI1_DR0_SC_SHIFT                              10
+#define OMAP4_MCSPI1_DR0_SC_MASK                               (0x3 << 10)
+#define OMAP4_UART1_DR0_SC_SHIFT                               8
+#define OMAP4_UART1_DR0_SC_MASK                                        (0x3 << 8)
+#define OMAP4_UART3_DR0_SC_SHIFT                               6
+#define OMAP4_UART3_DR0_SC_MASK                                        (0x3 << 6)
+#define OMAP4_UART3_DR1_SC_SHIFT                               4
+#define OMAP4_UART3_DR1_SC_MASK                                        (0x3 << 4)
+#define OMAP4_UNIPRO_DR0_SC_SHIFT                              2
+#define OMAP4_UNIPRO_DR0_SC_MASK                               (0x3 << 2)
+#define OMAP4_UNIPRO_DR1_SC_SHIFT                              0
+#define OMAP4_UNIPRO_DR1_SC_MASK                               (0x3 << 0)
+
+/* CONTROL_SMART1IO_PADCONF_1 */
+#define OMAP4_ABE_DR0_LB_SHIFT                                 30
+#define OMAP4_ABE_DR0_LB_MASK                                  (0x3 << 30)
+#define OMAP4_CAM_DR0_LB_SHIFT                                 28
+#define OMAP4_CAM_DR0_LB_MASK                                  (0x3 << 28)
+#define OMAP4_FREF_DR2_LB_SHIFT                                        26
+#define OMAP4_FREF_DR2_LB_MASK                                 (0x3 << 26)
+#define OMAP4_FREF_DR3_LB_SHIFT                                        24
+#define OMAP4_FREF_DR3_LB_MASK                                 (0x3 << 24)
+#define OMAP4_GPIO_DR8_LB_SHIFT                                        22
+#define OMAP4_GPIO_DR8_LB_MASK                                 (0x3 << 22)
+#define OMAP4_GPIO_DR9_LB_SHIFT                                        20
+#define OMAP4_GPIO_DR9_LB_MASK                                 (0x3 << 20)
+#define OMAP4_GPMC_DR2_LB_SHIFT                                        18
+#define OMAP4_GPMC_DR2_LB_MASK                                 (0x3 << 18)
+#define OMAP4_GPMC_DR3_LB_SHIFT                                        16
+#define OMAP4_GPMC_DR3_LB_MASK                                 (0x3 << 16)
+#define OMAP4_GPMC_DR6_LB_SHIFT                                        14
+#define OMAP4_GPMC_DR6_LB_MASK                                 (0x3 << 14)
+#define OMAP4_HDMI_DR0_LB_SHIFT                                        12
+#define OMAP4_HDMI_DR0_LB_MASK                                 (0x3 << 12)
+#define OMAP4_MCSPI1_DR0_LB_SHIFT                              10
+#define OMAP4_MCSPI1_DR0_LB_MASK                               (0x3 << 10)
+#define OMAP4_UART1_DR0_LB_SHIFT                               8
+#define OMAP4_UART1_DR0_LB_MASK                                        (0x3 << 8)
+#define OMAP4_UART3_DR0_LB_SHIFT                               6
+#define OMAP4_UART3_DR0_LB_MASK                                        (0x3 << 6)
+#define OMAP4_UART3_DR1_LB_SHIFT                               4
+#define OMAP4_UART3_DR1_LB_MASK                                        (0x3 << 4)
+#define OMAP4_UNIPRO_DR0_LB_SHIFT                              2
+#define OMAP4_UNIPRO_DR0_LB_MASK                               (0x3 << 2)
+#define OMAP4_UNIPRO_DR1_LB_SHIFT                              0
+#define OMAP4_UNIPRO_DR1_LB_MASK                               (0x3 << 0)
+
+/* CONTROL_SMART2IO_PADCONF_0 */
+#define OMAP4_C2C_DR0_LB_SHIFT                                 31
+#define OMAP4_C2C_DR0_LB_MASK                                  (1 << 31)
+#define OMAP4_DPM_DR1_LB_SHIFT                                 30
+#define OMAP4_DPM_DR1_LB_MASK                                  (1 << 30)
+#define OMAP4_DPM_DR2_LB_SHIFT                                 29
+#define OMAP4_DPM_DR2_LB_MASK                                  (1 << 29)
+#define OMAP4_DPM_DR3_LB_SHIFT                                 28
+#define OMAP4_DPM_DR3_LB_MASK                                  (1 << 28)
+#define OMAP4_GPIO_DR0_LB_SHIFT                                        27
+#define OMAP4_GPIO_DR0_LB_MASK                                 (1 << 27)
+#define OMAP4_GPIO_DR1_LB_SHIFT                                        26
+#define OMAP4_GPIO_DR1_LB_MASK                                 (1 << 26)
+#define OMAP4_GPIO_DR10_LB_SHIFT                               25
+#define OMAP4_GPIO_DR10_LB_MASK                                        (1 << 25)
+#define OMAP4_GPIO_DR2_LB_SHIFT                                        24
+#define OMAP4_GPIO_DR2_LB_MASK                                 (1 << 24)
+#define OMAP4_GPMC_DR0_LB_SHIFT                                        23
+#define OMAP4_GPMC_DR0_LB_MASK                                 (1 << 23)
+#define OMAP4_GPMC_DR1_LB_SHIFT                                        22
+#define OMAP4_GPMC_DR1_LB_MASK                                 (1 << 22)
+#define OMAP4_GPMC_DR4_LB_SHIFT                                        21
+#define OMAP4_GPMC_DR4_LB_MASK                                 (1 << 21)
+#define OMAP4_GPMC_DR5_LB_SHIFT                                        20
+#define OMAP4_GPMC_DR5_LB_MASK                                 (1 << 20)
+#define OMAP4_GPMC_DR7_LB_SHIFT                                        19
+#define OMAP4_GPMC_DR7_LB_MASK                                 (1 << 19)
+#define OMAP4_HSI2_DR0_LB_SHIFT                                        18
+#define OMAP4_HSI2_DR0_LB_MASK                                 (1 << 18)
+#define OMAP4_HSI2_DR1_LB_SHIFT                                        17
+#define OMAP4_HSI2_DR1_LB_MASK                                 (1 << 17)
+#define OMAP4_HSI2_DR2_LB_SHIFT                                        16
+#define OMAP4_HSI2_DR2_LB_MASK                                 (1 << 16)
+#define OMAP4_KPD_DR0_LB_SHIFT                                 15
+#define OMAP4_KPD_DR0_LB_MASK                                  (1 << 15)
+#define OMAP4_KPD_DR1_LB_SHIFT                                 14
+#define OMAP4_KPD_DR1_LB_MASK                                  (1 << 14)
+#define OMAP4_PDM_DR0_LB_SHIFT                                 13
+#define OMAP4_PDM_DR0_LB_MASK                                  (1 << 13)
+#define OMAP4_SDMMC2_DR0_LB_SHIFT                              12
+#define OMAP4_SDMMC2_DR0_LB_MASK                               (1 << 12)
+#define OMAP4_SDMMC3_DR0_LB_SHIFT                              11
+#define OMAP4_SDMMC3_DR0_LB_MASK                               (1 << 11)
+#define OMAP4_SDMMC4_DR0_LB_SHIFT                              10
+#define OMAP4_SDMMC4_DR0_LB_MASK                               (1 << 10)
+#define OMAP4_SDMMC4_DR1_LB_SHIFT                              9
+#define OMAP4_SDMMC4_DR1_LB_MASK                               (1 << 9)
+#define OMAP4_SPI3_DR0_LB_SHIFT                                        8
+#define OMAP4_SPI3_DR0_LB_MASK                                 (1 << 8)
+#define OMAP4_SPI3_DR1_LB_SHIFT                                        7
+#define OMAP4_SPI3_DR1_LB_MASK                                 (1 << 7)
+#define OMAP4_UART3_DR2_LB_SHIFT                               6
+#define OMAP4_UART3_DR2_LB_MASK                                        (1 << 6)
+#define OMAP4_UART3_DR3_LB_SHIFT                               5
+#define OMAP4_UART3_DR3_LB_MASK                                        (1 << 5)
+#define OMAP4_UART3_DR4_LB_SHIFT                               4
+#define OMAP4_UART3_DR4_LB_MASK                                        (1 << 4)
+#define OMAP4_UART3_DR5_LB_SHIFT                               3
+#define OMAP4_UART3_DR5_LB_MASK                                        (1 << 3)
+#define OMAP4_USBA0_DR1_LB_SHIFT                               2
+#define OMAP4_USBA0_DR1_LB_MASK                                        (1 << 2)
+#define OMAP4_USBA_DR2_LB_SHIFT                                        1
+#define OMAP4_USBA_DR2_LB_MASK                                 (1 << 1)
+
+/* CONTROL_SMART2IO_PADCONF_1 */
+#define OMAP4_USBB1_DR0_LB_SHIFT                               31
+#define OMAP4_USBB1_DR0_LB_MASK                                        (1 << 31)
+#define OMAP4_USBB2_DR0_LB_SHIFT                               30
+#define OMAP4_USBB2_DR0_LB_MASK                                        (1 << 30)
+#define OMAP4_USBA0_DR0_LB_SHIFT                               29
+#define OMAP4_USBA0_DR0_LB_MASK                                        (1 << 29)
+
+/* CONTROL_SMART3IO_PADCONF_0 */
+#define OMAP4_DMIC_DR0_MB_SHIFT                                        30
+#define OMAP4_DMIC_DR0_MB_MASK                                 (0x3 << 30)
+#define OMAP4_GPIO_DR3_MB_SHIFT                                        28
+#define OMAP4_GPIO_DR3_MB_MASK                                 (0x3 << 28)
+#define OMAP4_GPIO_DR4_MB_SHIFT                                        26
+#define OMAP4_GPIO_DR4_MB_MASK                                 (0x3 << 26)
+#define OMAP4_GPIO_DR5_MB_SHIFT                                        24
+#define OMAP4_GPIO_DR5_MB_MASK                                 (0x3 << 24)
+#define OMAP4_GPIO_DR6_MB_SHIFT                                        22
+#define OMAP4_GPIO_DR6_MB_MASK                                 (0x3 << 22)
+#define OMAP4_HSI_DR1_MB_SHIFT                                 20
+#define OMAP4_HSI_DR1_MB_MASK                                  (0x3 << 20)
+#define OMAP4_HSI_DR2_MB_SHIFT                                 18
+#define OMAP4_HSI_DR2_MB_MASK                                  (0x3 << 18)
+#define OMAP4_HSI_DR3_MB_SHIFT                                 16
+#define OMAP4_HSI_DR3_MB_MASK                                  (0x3 << 16)
+#define OMAP4_MCBSP2_DR0_MB_SHIFT                              14
+#define OMAP4_MCBSP2_DR0_MB_MASK                               (0x3 << 14)
+#define OMAP4_MCSPI4_DR0_MB_SHIFT                              12
+#define OMAP4_MCSPI4_DR0_MB_MASK                               (0x3 << 12)
+#define OMAP4_MCSPI4_DR1_MB_SHIFT                              10
+#define OMAP4_MCSPI4_DR1_MB_MASK                               (0x3 << 10)
+#define OMAP4_SDMMC3_DR0_MB_SHIFT                              8
+#define OMAP4_SDMMC3_DR0_MB_MASK                               (0x3 << 8)
+#define OMAP4_SPI2_DR0_MB_SHIFT                                        0
+#define OMAP4_SPI2_DR0_MB_MASK                                 (0x3 << 0)
+
+/* CONTROL_SMART3IO_PADCONF_1 */
+#define OMAP4_SPI2_DR1_MB_SHIFT                                        30
+#define OMAP4_SPI2_DR1_MB_MASK                                 (0x3 << 30)
+#define OMAP4_SPI2_DR2_MB_SHIFT                                        28
+#define OMAP4_SPI2_DR2_MB_MASK                                 (0x3 << 28)
+#define OMAP4_UART2_DR0_MB_SHIFT                               26
+#define OMAP4_UART2_DR0_MB_MASK                                        (0x3 << 26)
+#define OMAP4_UART2_DR1_MB_SHIFT                               24
+#define OMAP4_UART2_DR1_MB_MASK                                        (0x3 << 24)
+#define OMAP4_UART4_DR0_MB_SHIFT                               22
+#define OMAP4_UART4_DR0_MB_MASK                                        (0x3 << 22)
+#define OMAP4_HSI_DR0_MB_SHIFT                                 20
+#define OMAP4_HSI_DR0_MB_MASK                                  (0x3 << 20)
+
+/* CONTROL_SMART3IO_PADCONF_2 */
+#define OMAP4_DMIC_DR0_LB_SHIFT                                        31
+#define OMAP4_DMIC_DR0_LB_MASK                                 (1 << 31)
+#define OMAP4_GPIO_DR3_LB_SHIFT                                        30
+#define OMAP4_GPIO_DR3_LB_MASK                                 (1 << 30)
+#define OMAP4_GPIO_DR4_LB_SHIFT                                        29
+#define OMAP4_GPIO_DR4_LB_MASK                                 (1 << 29)
+#define OMAP4_GPIO_DR5_LB_SHIFT                                        28
+#define OMAP4_GPIO_DR5_LB_MASK                                 (1 << 28)
+#define OMAP4_GPIO_DR6_LB_SHIFT                                        27
+#define OMAP4_GPIO_DR6_LB_MASK                                 (1 << 27)
+#define OMAP4_HSI_DR1_LB_SHIFT                                 26
+#define OMAP4_HSI_DR1_LB_MASK                                  (1 << 26)
+#define OMAP4_HSI_DR2_LB_SHIFT                                 25
+#define OMAP4_HSI_DR2_LB_MASK                                  (1 << 25)
+#define OMAP4_HSI_DR3_LB_SHIFT                                 24
+#define OMAP4_HSI_DR3_LB_MASK                                  (1 << 24)
+#define OMAP4_MCBSP2_DR0_LB_SHIFT                              23
+#define OMAP4_MCBSP2_DR0_LB_MASK                               (1 << 23)
+#define OMAP4_MCSPI4_DR0_LB_SHIFT                              22
+#define OMAP4_MCSPI4_DR0_LB_MASK                               (1 << 22)
+#define OMAP4_MCSPI4_DR1_LB_SHIFT                              21
+#define OMAP4_MCSPI4_DR1_LB_MASK                               (1 << 21)
+#define OMAP4_SLIMBUS2_DR0_LB_SHIFT                            18
+#define OMAP4_SLIMBUS2_DR0_LB_MASK                             (1 << 18)
+#define OMAP4_SPI2_DR0_LB_SHIFT                                        16
+#define OMAP4_SPI2_DR0_LB_MASK                                 (1 << 16)
+#define OMAP4_SPI2_DR1_LB_SHIFT                                        15
+#define OMAP4_SPI2_DR1_LB_MASK                                 (1 << 15)
+#define OMAP4_SPI2_DR2_LB_SHIFT                                        14
+#define OMAP4_SPI2_DR2_LB_MASK                                 (1 << 14)
+#define OMAP4_UART2_DR0_LB_SHIFT                               13
+#define OMAP4_UART2_DR0_LB_MASK                                        (1 << 13)
+#define OMAP4_UART2_DR1_LB_SHIFT                               12
+#define OMAP4_UART2_DR1_LB_MASK                                        (1 << 12)
+#define OMAP4_UART4_DR0_LB_SHIFT                               11
+#define OMAP4_UART4_DR0_LB_MASK                                        (1 << 11)
+#define OMAP4_HSI_DR0_LB_SHIFT                                 10
+#define OMAP4_HSI_DR0_LB_MASK                                  (1 << 10)
+
+/* CONTROL_USBB_HSIC */
+#define OMAP4_USBB2_DR1_SR_SHIFT                               30
+#define OMAP4_USBB2_DR1_SR_MASK                                        (0x3 << 30)
+#define OMAP4_USBB2_DR1_I_SHIFT                                        27
+#define OMAP4_USBB2_DR1_I_MASK                                 (0x7 << 27)
+#define OMAP4_USBB1_DR1_SR_SHIFT                               25
+#define OMAP4_USBB1_DR1_SR_MASK                                        (0x3 << 25)
+#define OMAP4_USBB1_DR1_I_SHIFT                                        22
+#define OMAP4_USBB1_DR1_I_MASK                                 (0x7 << 22)
+#define OMAP4_USBB1_HSIC_DATA_WD_SHIFT                         20
+#define OMAP4_USBB1_HSIC_DATA_WD_MASK                          (0x3 << 20)
+#define OMAP4_USBB1_HSIC_STROBE_WD_SHIFT                       18
+#define OMAP4_USBB1_HSIC_STROBE_WD_MASK                                (0x3 << 18)
+#define OMAP4_USBB2_HSIC_DATA_WD_SHIFT                         16
+#define OMAP4_USBB2_HSIC_DATA_WD_MASK                          (0x3 << 16)
+#define OMAP4_USBB2_HSIC_STROBE_WD_SHIFT                       14
+#define OMAP4_USBB2_HSIC_STROBE_WD_MASK                                (0x3 << 14)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT          13
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_MASK           (1 << 13)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_SHIFT                 11
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_MASK                  (0x3 << 11)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT                10
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK         (1 << 10)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_SHIFT               8
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_MASK                        (0x3 << 8)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT          7
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_MASK           (1 << 7)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_SHIFT                 5
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_MASK                  (0x3 << 5)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT                4
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK         (1 << 4)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_SHIFT               2
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_MASK                        (0x3 << 2)
+
+/* CONTROL_SLIMBUS */
+#define OMAP4_SLIMBUS1_DR0_MB_SHIFT                            30
+#define OMAP4_SLIMBUS1_DR0_MB_MASK                             (0x3 << 30)
+#define OMAP4_SLIMBUS1_DR1_MB_SHIFT                            28
+#define OMAP4_SLIMBUS1_DR1_MB_MASK                             (0x3 << 28)
+#define OMAP4_SLIMBUS2_DR0_MB_SHIFT                            26
+#define OMAP4_SLIMBUS2_DR0_MB_MASK                             (0x3 << 26)
+#define OMAP4_SLIMBUS2_DR1_MB_SHIFT                            24
+#define OMAP4_SLIMBUS2_DR1_MB_MASK                             (0x3 << 24)
+#define OMAP4_SLIMBUS2_DR2_MB_SHIFT                            22
+#define OMAP4_SLIMBUS2_DR2_MB_MASK                             (0x3 << 22)
+#define OMAP4_SLIMBUS2_DR3_MB_SHIFT                            20
+#define OMAP4_SLIMBUS2_DR3_MB_MASK                             (0x3 << 20)
+#define OMAP4_SLIMBUS1_DR0_LB_SHIFT                            19
+#define OMAP4_SLIMBUS1_DR0_LB_MASK                             (1 << 19)
+#define OMAP4_SLIMBUS2_DR1_LB_SHIFT                            18
+#define OMAP4_SLIMBUS2_DR1_LB_MASK                             (1 << 18)
+
+/* CONTROL_PBIASLITE */
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_SHIFT                    31
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_MASK                     (1 << 31)
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_SHIFT               30
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_MASK                        (1 << 30)
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_SHIFT                 29
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_MASK                  (1 << 29)
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_SHIFT                      28
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_MASK                       (1 << 28)
+#define OMAP4_USIM_PBIASLITE_VMODE_SHIFT                       27
+#define OMAP4_USIM_PBIASLITE_VMODE_MASK                                (1 << 27)
+#define OMAP4_MMC1_PWRDNZ_SHIFT                                        26
+#define OMAP4_MMC1_PWRDNZ_MASK                                 (1 << 26)
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_SHIFT                    25
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_MASK                     (1 << 25)
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_SHIFT               24
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_MASK                        (1 << 24)
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_SHIFT                 23
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK                  (1 << 23)
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_SHIFT                      22
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK                       (1 << 22)
+#define OMAP4_MMC1_PBIASLITE_VMODE_SHIFT                       21
+#define OMAP4_MMC1_PBIASLITE_VMODE_MASK                                (1 << 21)
+#define OMAP4_USBC1_ICUSB_PWRDNZ_SHIFT                         20
+#define OMAP4_USBC1_ICUSB_PWRDNZ_MASK                          (1 << 20)
+
+/* CONTROL_I2C_0 */
+#define OMAP4_I2C4_SDA_GLFENB_SHIFT                            31
+#define OMAP4_I2C4_SDA_GLFENB_MASK                             (1 << 31)
+#define OMAP4_I2C4_SDA_LOAD_BITS_SHIFT                         29
+#define OMAP4_I2C4_SDA_LOAD_BITS_MASK                          (0x3 << 29)
+#define OMAP4_I2C4_SDA_PULLUPRESX_SHIFT                                28
+#define OMAP4_I2C4_SDA_PULLUPRESX_MASK                         (1 << 28)
+#define OMAP4_I2C3_SDA_GLFENB_SHIFT                            27
+#define OMAP4_I2C3_SDA_GLFENB_MASK                             (1 << 27)
+#define OMAP4_I2C3_SDA_LOAD_BITS_SHIFT                         25
+#define OMAP4_I2C3_SDA_LOAD_BITS_MASK                          (0x3 << 25)
+#define OMAP4_I2C3_SDA_PULLUPRESX_SHIFT                                24
+#define OMAP4_I2C3_SDA_PULLUPRESX_MASK                         (1 << 24)
+#define OMAP4_I2C2_SDA_GLFENB_SHIFT                            23
+#define OMAP4_I2C2_SDA_GLFENB_MASK                             (1 << 23)
+#define OMAP4_I2C2_SDA_LOAD_BITS_SHIFT                         21
+#define OMAP4_I2C2_SDA_LOAD_BITS_MASK                          (0x3 << 21)
+#define OMAP4_I2C2_SDA_PULLUPRESX_SHIFT                                20
+#define OMAP4_I2C2_SDA_PULLUPRESX_MASK                         (1 << 20)
+#define OMAP4_I2C1_SDA_GLFENB_SHIFT                            19
+#define OMAP4_I2C1_SDA_GLFENB_MASK                             (1 << 19)
+#define OMAP4_I2C1_SDA_LOAD_BITS_SHIFT                         17
+#define OMAP4_I2C1_SDA_LOAD_BITS_MASK                          (0x3 << 17)
+#define OMAP4_I2C1_SDA_PULLUPRESX_SHIFT                                16
+#define OMAP4_I2C1_SDA_PULLUPRESX_MASK                         (1 << 16)
+#define OMAP4_I2C4_SCL_GLFENB_SHIFT                            15
+#define OMAP4_I2C4_SCL_GLFENB_MASK                             (1 << 15)
+#define OMAP4_I2C4_SCL_LOAD_BITS_SHIFT                         13
+#define OMAP4_I2C4_SCL_LOAD_BITS_MASK                          (0x3 << 13)
+#define OMAP4_I2C4_SCL_PULLUPRESX_SHIFT                                12
+#define OMAP4_I2C4_SCL_PULLUPRESX_MASK                         (1 << 12)
+#define OMAP4_I2C3_SCL_GLFENB_SHIFT                            11
+#define OMAP4_I2C3_SCL_GLFENB_MASK                             (1 << 11)
+#define OMAP4_I2C3_SCL_LOAD_BITS_SHIFT                         9
+#define OMAP4_I2C3_SCL_LOAD_BITS_MASK                          (0x3 << 9)
+#define OMAP4_I2C3_SCL_PULLUPRESX_SHIFT                                8
+#define OMAP4_I2C3_SCL_PULLUPRESX_MASK                         (1 << 8)
+#define OMAP4_I2C2_SCL_GLFENB_SHIFT                            7
+#define OMAP4_I2C2_SCL_GLFENB_MASK                             (1 << 7)
+#define OMAP4_I2C2_SCL_LOAD_BITS_SHIFT                         5
+#define OMAP4_I2C2_SCL_LOAD_BITS_MASK                          (0x3 << 5)
+#define OMAP4_I2C2_SCL_PULLUPRESX_SHIFT                                4
+#define OMAP4_I2C2_SCL_PULLUPRESX_MASK                         (1 << 4)
+#define OMAP4_I2C1_SCL_GLFENB_SHIFT                            3
+#define OMAP4_I2C1_SCL_GLFENB_MASK                             (1 << 3)
+#define OMAP4_I2C1_SCL_LOAD_BITS_SHIFT                         1
+#define OMAP4_I2C1_SCL_LOAD_BITS_MASK                          (0x3 << 1)
+#define OMAP4_I2C1_SCL_PULLUPRESX_SHIFT                                0
+#define OMAP4_I2C1_SCL_PULLUPRESX_MASK                         (1 << 0)
+
+/* CONTROL_CAMERA_RX */
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_SHIFT                  31
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_MASK                   (1 << 31)
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT                  29
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_MASK                   (0x3 << 29)
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT                  24
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_MASK                   (0x1f << 24)
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_SHIFT                    22
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_MASK                     (0x3 << 22)
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_SHIFT                   21
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK                    (1 << 21)
+#define OMAP4_CAMERARX_CSI22_CAMMODE_SHIFT                     19
+#define OMAP4_CAMERARX_CSI22_CAMMODE_MASK                      (0x3 << 19)
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_SHIFT                   18
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK                    (1 << 18)
+#define OMAP4_CAMERARX_CSI21_CAMMODE_SHIFT                     16
+#define OMAP4_CAMERARX_CSI21_CAMMODE_MASK                      (0x3 << 16)
+
+/* CONTROL_AVDAC */
+#define OMAP4_AVDAC_ACEN_SHIFT                                 31
+#define OMAP4_AVDAC_ACEN_MASK                                  (1 << 31)
+#define OMAP4_AVDAC_TVOUTBYPASS_SHIFT                          30
+#define OMAP4_AVDAC_TVOUTBYPASS_MASK                           (1 << 30)
+#define OMAP4_AVDAC_INPUTINV_SHIFT                             29
+#define OMAP4_AVDAC_INPUTINV_MASK                              (1 << 29)
+#define OMAP4_AVDAC_CTL_SHIFT                                  13
+#define OMAP4_AVDAC_CTL_MASK                                   (0xffff << 13)
+#define OMAP4_AVDAC_CTL_WR_ACK_SHIFT                           12
+#define OMAP4_AVDAC_CTL_WR_ACK_MASK                            (1 << 12)
+
+/* CONTROL_HDMI_TX_PHY */
+#define OMAP4_HDMITXPHY_PADORDER_SHIFT                         31
+#define OMAP4_HDMITXPHY_PADORDER_MASK                          (1 << 31)
+#define OMAP4_HDMITXPHY_TXVALID_SHIFT                          30
+#define OMAP4_HDMITXPHY_TXVALID_MASK                           (1 << 30)
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_SHIFT                      29
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_MASK                       (1 << 29)
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_SHIFT                     28
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_MASK                      (1 << 28)
+
+/* CONTROL_MMC2 */
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_SHIFT                      31
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_MASK                       (1 << 31)
+
+/* CONTROL_DSIPHY */
+#define OMAP4_DSI2_LANEENABLE_SHIFT                            29
+#define OMAP4_DSI2_LANEENABLE_MASK                             (0x7 << 29)
+#define OMAP4_DSI1_LANEENABLE_SHIFT                            24
+#define OMAP4_DSI1_LANEENABLE_MASK                             (0x1f << 24)
+#define OMAP4_DSI1_PIPD_SHIFT                                  19
+#define OMAP4_DSI1_PIPD_MASK                                   (0x1f << 19)
+#define OMAP4_DSI2_PIPD_SHIFT                                  14
+#define OMAP4_DSI2_PIPD_MASK                                   (0x1f << 14)
+
+/* CONTROL_MCBSPLP */
+#define OMAP4_ALBCTRLRX_FSX_SHIFT                              31
+#define OMAP4_ALBCTRLRX_FSX_MASK                               (1 << 31)
+#define OMAP4_ALBCTRLRX_CLKX_SHIFT                             30
+#define OMAP4_ALBCTRLRX_CLKX_MASK                              (1 << 30)
+#define OMAP4_ABE_MCBSP1_DR_EN_SHIFT                           29
+#define OMAP4_ABE_MCBSP1_DR_EN_MASK                            (1 << 29)
+
+/* CONTROL_USB2PHYCORE */
+#define OMAP4_USB2PHY_AUTORESUME_EN_SHIFT                      31
+#define OMAP4_USB2PHY_AUTORESUME_EN_MASK                       (1 << 31)
+#define OMAP4_USB2PHY_DISCHGDET_SHIFT                          30
+#define OMAP4_USB2PHY_DISCHGDET_MASK                           (1 << 30)
+#define OMAP4_USB2PHY_GPIOMODE_SHIFT                           29
+#define OMAP4_USB2PHY_GPIOMODE_MASK                            (1 << 29)
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_SHIFT                    28
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_MASK                     (1 << 28)
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_SHIFT                   27
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_MASK                    (1 << 27)
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_SHIFT                   26
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_MASK                    (1 << 26)
+#define OMAP4_USB2PHY_CHG_VSRC_EN_SHIFT                                25
+#define OMAP4_USB2PHY_CHG_VSRC_EN_MASK                         (1 << 25)
+#define OMAP4_USB2PHY_CHG_ISINK_EN_SHIFT                       24
+#define OMAP4_USB2PHY_CHG_ISINK_EN_MASK                                (1 << 24)
+#define OMAP4_USB2PHY_CHG_DET_STATUS_SHIFT                     21
+#define OMAP4_USB2PHY_CHG_DET_STATUS_MASK                      (0x7 << 21)
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_SHIFT                    20
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_MASK                     (1 << 20)
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_SHIFT                    19
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_MASK                     (1 << 19)
+#define OMAP4_USB2PHY_DATADET_SHIFT                            18
+#define OMAP4_USB2PHY_DATADET_MASK                             (1 << 18)
+#define OMAP4_USB2PHY_SINKONDP_SHIFT                           17
+#define OMAP4_USB2PHY_SINKONDP_MASK                            (1 << 17)
+#define OMAP4_USB2PHY_SRCONDM_SHIFT                            16
+#define OMAP4_USB2PHY_SRCONDM_MASK                             (1 << 16)
+#define OMAP4_USB2PHY_RESTARTCHGDET_SHIFT                      15
+#define OMAP4_USB2PHY_RESTARTCHGDET_MASK                       (1 << 15)
+#define OMAP4_USB2PHY_CHGDETDONE_SHIFT                         14
+#define OMAP4_USB2PHY_CHGDETDONE_MASK                          (1 << 14)
+#define OMAP4_USB2PHY_CHGDETECTED_SHIFT                                13
+#define OMAP4_USB2PHY_CHGDETECTED_MASK                         (1 << 13)
+#define OMAP4_USB2PHY_MCPCPUEN_SHIFT                           12
+#define OMAP4_USB2PHY_MCPCPUEN_MASK                            (1 << 12)
+#define OMAP4_USB2PHY_MCPCMODEEN_SHIFT                         11
+#define OMAP4_USB2PHY_MCPCMODEEN_MASK                          (1 << 11)
+#define OMAP4_USB2PHY_RESETDONEMCLK_SHIFT                      10
+#define OMAP4_USB2PHY_RESETDONEMCLK_MASK                       (1 << 10)
+#define OMAP4_USB2PHY_UTMIRESETDONE_SHIFT                      9
+#define OMAP4_USB2PHY_UTMIRESETDONE_MASK                       (1 << 9)
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_SHIFT                   8
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_MASK                    (1 << 8)
+#define OMAP4_USB2PHY_DATAPOLARITYN_SHIFT                      7
+#define OMAP4_USB2PHY_DATAPOLARITYN_MASK                       (1 << 7)
+#define OMAP4_USBDPLL_FREQLOCK_SHIFT                           6
+#define OMAP4_USBDPLL_FREQLOCK_MASK                            (1 << 6)
+#define OMAP4_USB2PHY_RESETDONETCLK_SHIFT                      5
+#define OMAP4_USB2PHY_RESETDONETCLK_MASK                       (1 << 5)
+
+/* CONTROL_I2C_1 */
+#define OMAP4_HDMI_DDC_SDA_GLFENB_SHIFT                                31
+#define OMAP4_HDMI_DDC_SDA_GLFENB_MASK                         (1 << 31)
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_SHIFT                     29
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_MASK                      (0x3 << 29)
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_SHIFT                    28
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK                     (1 << 28)
+#define OMAP4_HDMI_DDC_SCL_GLFENB_SHIFT                                27
+#define OMAP4_HDMI_DDC_SCL_GLFENB_MASK                         (1 << 27)
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_SHIFT                     25
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_MASK                      (0x3 << 25)
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_SHIFT                    24
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK                     (1 << 24)
+#define OMAP4_HDMI_DDC_SDA_HSMODE_SHIFT                                23
+#define OMAP4_HDMI_DDC_SDA_HSMODE_MASK                         (1 << 23)
+#define OMAP4_HDMI_DDC_SDA_NMODE_SHIFT                         22
+#define OMAP4_HDMI_DDC_SDA_NMODE_MASK                          (1 << 22)
+#define OMAP4_HDMI_DDC_SCL_HSMODE_SHIFT                                21
+#define OMAP4_HDMI_DDC_SCL_HSMODE_MASK                         (1 << 21)
+#define OMAP4_HDMI_DDC_SCL_NMODE_SHIFT                         20
+#define OMAP4_HDMI_DDC_SCL_NMODE_MASK                          (1 << 20)
+
+/* CONTROL_MMC1 */
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_SHIFT                     31
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK                      (1 << 31)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_SHIFT                     30
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK                      (1 << 30)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_SHIFT                     29
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK                      (1 << 29)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_SHIFT                     28
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK                      (1 << 28)
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_SHIFT                       27
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_MASK                                (1 << 27)
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_SHIFT                       26
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK                                (1 << 26)
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_SHIFT                       25
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK                                (1 << 25)
+#define OMAP4_USBC1_DR0_SPEEDCTRL_SHIFT                                24
+#define OMAP4_USBC1_DR0_SPEEDCTRL_MASK                         (1 << 24)
+#define OMAP4_USB_FD_CDEN_SHIFT                                        23
+#define OMAP4_USB_FD_CDEN_MASK                                 (1 << 23)
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_SHIFT                       22
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_MASK                                (1 << 22)
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_SHIFT                       21
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_MASK                                (1 << 21)
+
+/* CONTROL_HSI */
+#define OMAP4_HSI1_CALLOOP_SEL_SHIFT                           31
+#define OMAP4_HSI1_CALLOOP_SEL_MASK                            (1 << 31)
+#define OMAP4_HSI1_CALMUX_SEL_SHIFT                            30
+#define OMAP4_HSI1_CALMUX_SEL_MASK                             (1 << 30)
+#define OMAP4_HSI2_CALLOOP_SEL_SHIFT                           29
+#define OMAP4_HSI2_CALLOOP_SEL_MASK                            (1 << 29)
+#define OMAP4_HSI2_CALMUX_SEL_SHIFT                            28
+#define OMAP4_HSI2_CALMUX_SEL_MASK                             (1 << 28)
+
+/* CONTROL_USB */
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_SHIFT          31
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_MASK           (1 << 31)
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_SHIFT          30
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_MASK           (1 << 30)
+
+/* CONTROL_HDQ */
+#define OMAP4_HDQ_SIO_PWRDNZ_SHIFT                             31
+#define OMAP4_HDQ_SIO_PWRDNZ_MASK                              (1 << 31)
+
+/* CONTROL_LPDDR2IO1_0 */
+#define OMAP4_LPDDR2IO1_GR4_SR_SHIFT                           30
+#define OMAP4_LPDDR2IO1_GR4_SR_MASK                            (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR4_I_SHIFT                            27
+#define OMAP4_LPDDR2IO1_GR4_I_MASK                             (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR4_WD_SHIFT                           25
+#define OMAP4_LPDDR2IO1_GR4_WD_MASK                            (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR3_SR_SHIFT                           22
+#define OMAP4_LPDDR2IO1_GR3_SR_MASK                            (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR3_I_SHIFT                            19
+#define OMAP4_LPDDR2IO1_GR3_I_MASK                             (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR3_WD_SHIFT                           17
+#define OMAP4_LPDDR2IO1_GR3_WD_MASK                            (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR2_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO1_GR2_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR2_I_SHIFT                            11
+#define OMAP4_LPDDR2IO1_GR2_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR2_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO1_GR2_WD_MASK                            (0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR1_SR_SHIFT                           6
+#define OMAP4_LPDDR2IO1_GR1_SR_MASK                            (0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR1_I_SHIFT                            3
+#define OMAP4_LPDDR2IO1_GR1_I_MASK                             (0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR1_WD_SHIFT                           1
+#define OMAP4_LPDDR2IO1_GR1_WD_MASK                            (0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_1 */
+#define OMAP4_LPDDR2IO1_GR8_SR_SHIFT                           30
+#define OMAP4_LPDDR2IO1_GR8_SR_MASK                            (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR8_I_SHIFT                            27
+#define OMAP4_LPDDR2IO1_GR8_I_MASK                             (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR8_WD_SHIFT                           25
+#define OMAP4_LPDDR2IO1_GR8_WD_MASK                            (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR7_SR_SHIFT                           22
+#define OMAP4_LPDDR2IO1_GR7_SR_MASK                            (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR7_I_SHIFT                            19
+#define OMAP4_LPDDR2IO1_GR7_I_MASK                             (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR7_WD_SHIFT                           17
+#define OMAP4_LPDDR2IO1_GR7_WD_MASK                            (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR6_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO1_GR6_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR6_I_SHIFT                            11
+#define OMAP4_LPDDR2IO1_GR6_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR6_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO1_GR6_WD_MASK                            (0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR5_SR_SHIFT                           6
+#define OMAP4_LPDDR2IO1_GR5_SR_MASK                            (0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR5_I_SHIFT                            3
+#define OMAP4_LPDDR2IO1_GR5_I_MASK                             (0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR5_WD_SHIFT                           1
+#define OMAP4_LPDDR2IO1_GR5_WD_MASK                            (0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_2 */
+#define OMAP4_LPDDR2IO1_GR11_SR_SHIFT                          30
+#define OMAP4_LPDDR2IO1_GR11_SR_MASK                           (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR11_I_SHIFT                           27
+#define OMAP4_LPDDR2IO1_GR11_I_MASK                            (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR11_WD_SHIFT                          25
+#define OMAP4_LPDDR2IO1_GR11_WD_MASK                           (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR10_SR_SHIFT                          22
+#define OMAP4_LPDDR2IO1_GR10_SR_MASK                           (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR10_I_SHIFT                           19
+#define OMAP4_LPDDR2IO1_GR10_I_MASK                            (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR10_WD_SHIFT                          17
+#define OMAP4_LPDDR2IO1_GR10_WD_MASK                           (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR9_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO1_GR9_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR9_I_SHIFT                            11
+#define OMAP4_LPDDR2IO1_GR9_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR9_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO1_GR9_WD_MASK                            (0x3 << 9)
+
+/* CONTROL_LPDDR2IO1_3 */
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_SHIFT                      31
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_MASK                       (1 << 31)
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_SHIFT                      30
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_MASK                       (1 << 30)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_SHIFT                  29
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_MASK                   (1 << 29)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_SHIFT                  28
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_MASK                   (1 << 28)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_SHIFT                   27
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_MASK                    (1 << 27)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_SHIFT                   26
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_MASK                    (1 << 26)
+#define OMAP4_LPDDR21_VREF_CA_TAP0_SHIFT                       25
+#define OMAP4_LPDDR21_VREF_CA_TAP0_MASK                                (1 << 25)
+#define OMAP4_LPDDR21_VREF_CA_TAP1_SHIFT                       24
+#define OMAP4_LPDDR21_VREF_CA_TAP1_MASK                                (1 << 24)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_SHIFT                 23
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_MASK                  (1 << 23)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_SHIFT                 22
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_MASK                  (1 << 22)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_SHIFT                  21
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_MASK                   (1 << 21)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_SHIFT                  20
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_MASK                   (1 << 20)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_SHIFT                 19
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_MASK                  (1 << 19)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_SHIFT                 18
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_MASK                  (1 << 18)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_SHIFT                  17
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_MASK                   (1 << 17)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_SHIFT                  16
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_MASK                   (1 << 16)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_SHIFT                      15
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_MASK                       (1 << 15)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_SHIFT                      14
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_MASK                       (1 << 14)
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_SHIFT                       13
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_MASK                                (1 << 13)
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_SHIFT                       12
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_MASK                                (1 << 12)
+
+/* CONTROL_LPDDR2IO2_0 */
+#define OMAP4_LPDDR2IO2_GR4_SR_SHIFT                           30
+#define OMAP4_LPDDR2IO2_GR4_SR_MASK                            (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR4_I_SHIFT                            27
+#define OMAP4_LPDDR2IO2_GR4_I_MASK                             (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR4_WD_SHIFT                           25
+#define OMAP4_LPDDR2IO2_GR4_WD_MASK                            (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR3_SR_SHIFT                           22
+#define OMAP4_LPDDR2IO2_GR3_SR_MASK                            (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR3_I_SHIFT                            19
+#define OMAP4_LPDDR2IO2_GR3_I_MASK                             (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR3_WD_SHIFT                           17
+#define OMAP4_LPDDR2IO2_GR3_WD_MASK                            (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR2_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO2_GR2_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR2_I_SHIFT                            11
+#define OMAP4_LPDDR2IO2_GR2_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR2_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO2_GR2_WD_MASK                            (0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR1_SR_SHIFT                           6
+#define OMAP4_LPDDR2IO2_GR1_SR_MASK                            (0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR1_I_SHIFT                            3
+#define OMAP4_LPDDR2IO2_GR1_I_MASK                             (0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR1_WD_SHIFT                           1
+#define OMAP4_LPDDR2IO2_GR1_WD_MASK                            (0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_1 */
+#define OMAP4_LPDDR2IO2_GR8_SR_SHIFT                           30
+#define OMAP4_LPDDR2IO2_GR8_SR_MASK                            (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR8_I_SHIFT                            27
+#define OMAP4_LPDDR2IO2_GR8_I_MASK                             (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR8_WD_SHIFT                           25
+#define OMAP4_LPDDR2IO2_GR8_WD_MASK                            (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR7_SR_SHIFT                           22
+#define OMAP4_LPDDR2IO2_GR7_SR_MASK                            (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR7_I_SHIFT                            19
+#define OMAP4_LPDDR2IO2_GR7_I_MASK                             (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR7_WD_SHIFT                           17
+#define OMAP4_LPDDR2IO2_GR7_WD_MASK                            (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR6_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO2_GR6_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR6_I_SHIFT                            11
+#define OMAP4_LPDDR2IO2_GR6_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR6_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO2_GR6_WD_MASK                            (0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR5_SR_SHIFT                           6
+#define OMAP4_LPDDR2IO2_GR5_SR_MASK                            (0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR5_I_SHIFT                            3
+#define OMAP4_LPDDR2IO2_GR5_I_MASK                             (0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR5_WD_SHIFT                           1
+#define OMAP4_LPDDR2IO2_GR5_WD_MASK                            (0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_2 */
+#define OMAP4_LPDDR2IO2_GR11_SR_SHIFT                          30
+#define OMAP4_LPDDR2IO2_GR11_SR_MASK                           (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR11_I_SHIFT                           27
+#define OMAP4_LPDDR2IO2_GR11_I_MASK                            (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR11_WD_SHIFT                          25
+#define OMAP4_LPDDR2IO2_GR11_WD_MASK                           (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR10_SR_SHIFT                          22
+#define OMAP4_LPDDR2IO2_GR10_SR_MASK                           (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR10_I_SHIFT                           19
+#define OMAP4_LPDDR2IO2_GR10_I_MASK                            (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR10_WD_SHIFT                          17
+#define OMAP4_LPDDR2IO2_GR10_WD_MASK                           (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR9_SR_SHIFT                           14
+#define OMAP4_LPDDR2IO2_GR9_SR_MASK                            (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR9_I_SHIFT                            11
+#define OMAP4_LPDDR2IO2_GR9_I_MASK                             (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR9_WD_SHIFT                           9
+#define OMAP4_LPDDR2IO2_GR9_WD_MASK                            (0x3 << 9)
+
+/* CONTROL_LPDDR2IO2_3 */
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_SHIFT                      31
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_MASK                       (1 << 31)
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_SHIFT                      30
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_MASK                       (1 << 30)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_SHIFT                  29
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_MASK                   (1 << 29)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_SHIFT                  28
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_MASK                   (1 << 28)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_SHIFT                   27
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_MASK                    (1 << 27)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_SHIFT                   26
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_MASK                    (1 << 26)
+#define OMAP4_LPDDR22_VREF_CA_TAP0_SHIFT                       25
+#define OMAP4_LPDDR22_VREF_CA_TAP0_MASK                                (1 << 25)
+#define OMAP4_LPDDR22_VREF_CA_TAP1_SHIFT                       24
+#define OMAP4_LPDDR22_VREF_CA_TAP1_MASK                                (1 << 24)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_SHIFT                 23
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_MASK                  (1 << 23)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_SHIFT                 22
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_MASK                  (1 << 22)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_SHIFT                  21
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_MASK                   (1 << 21)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_SHIFT                  20
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_MASK                   (1 << 20)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_SHIFT                 19
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_MASK                  (1 << 19)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_SHIFT                 18
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_MASK                  (1 << 18)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_SHIFT                  17
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_MASK                   (1 << 17)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_SHIFT                  16
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_MASK                   (1 << 16)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_SHIFT                      15
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_MASK                       (1 << 15)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_SHIFT                      14
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_MASK                       (1 << 14)
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_SHIFT                       13
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_MASK                                (1 << 13)
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_SHIFT                       12
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_MASK                                (1 << 12)
+
+/* CONTROL_BUS_HOLD */
+#define OMAP4_ABE_DMIC_DIN3_EN_SHIFT                           31
+#define OMAP4_ABE_DMIC_DIN3_EN_MASK                            (1 << 31)
+#define OMAP4_MCSPI1_CS3_EN_SHIFT                              30
+#define OMAP4_MCSPI1_CS3_EN_MASK                               (1 << 30)
+
+/* CONTROL_C2C */
+#define OMAP4_MIRROR_MODE_EN_SHIFT                             31
+#define OMAP4_MIRROR_MODE_EN_MASK                              (1 << 31)
+#define OMAP4_C2C_SPARE_SHIFT                                  24
+#define OMAP4_C2C_SPARE_MASK                                   (0x7f << 24)
+
+/* CORE_CONTROL_SPARE_RW */
+#define OMAP4_CORE_CONTROL_SPARE_RW_SHIFT                      0
+#define OMAP4_CORE_CONTROL_SPARE_RW_MASK                       (0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R */
+#define OMAP4_CORE_CONTROL_SPARE_R_SHIFT                       0
+#define OMAP4_CORE_CONTROL_SPARE_R_MASK                                (0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R_C0 */
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_SHIFT                    31
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_MASK                     (1 << 31)
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_SHIFT                    30
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_MASK                     (1 << 30)
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_SHIFT                    29
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_MASK                     (1 << 29)
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_SHIFT                    28
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_MASK                     (1 << 28)
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_SHIFT                    27
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_MASK                     (1 << 27)
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_SHIFT                    26
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_MASK                     (1 << 26)
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_SHIFT                    25
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_MASK                     (1 << 25)
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_SHIFT                    24
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_MASK                     (1 << 24)
+
+/* CONTROL_EFUSE_1 */
+#define OMAP4_AVDAC_TRIM_BYTE3_SHIFT                           24
+#define OMAP4_AVDAC_TRIM_BYTE3_MASK                            (0x7f << 24)
+#define OMAP4_AVDAC_TRIM_BYTE2_SHIFT                           16
+#define OMAP4_AVDAC_TRIM_BYTE2_MASK                            (0xff << 16)
+#define OMAP4_AVDAC_TRIM_BYTE1_SHIFT                           8
+#define OMAP4_AVDAC_TRIM_BYTE1_MASK                            (0xff << 8)
+#define OMAP4_AVDAC_TRIM_BYTE0_SHIFT                           0
+#define OMAP4_AVDAC_TRIM_BYTE0_MASK                            (0xff << 0)
+
+/* CONTROL_EFUSE_2 */
+#define OMAP4_EFUSE_SMART2TEST_P0_SHIFT                                31
+#define OMAP4_EFUSE_SMART2TEST_P0_MASK                         (1 << 31)
+#define OMAP4_EFUSE_SMART2TEST_P1_SHIFT                                30
+#define OMAP4_EFUSE_SMART2TEST_P1_MASK                         (1 << 30)
+#define OMAP4_EFUSE_SMART2TEST_P2_SHIFT                                29
+#define OMAP4_EFUSE_SMART2TEST_P2_MASK                         (1 << 29)
+#define OMAP4_EFUSE_SMART2TEST_P3_SHIFT                                28
+#define OMAP4_EFUSE_SMART2TEST_P3_MASK                         (1 << 28)
+#define OMAP4_EFUSE_SMART2TEST_N0_SHIFT                                27
+#define OMAP4_EFUSE_SMART2TEST_N0_MASK                         (1 << 27)
+#define OMAP4_EFUSE_SMART2TEST_N1_SHIFT                                26
+#define OMAP4_EFUSE_SMART2TEST_N1_MASK                         (1 << 26)
+#define OMAP4_EFUSE_SMART2TEST_N2_SHIFT                                25
+#define OMAP4_EFUSE_SMART2TEST_N2_MASK                         (1 << 25)
+#define OMAP4_EFUSE_SMART2TEST_N3_SHIFT                                24
+#define OMAP4_EFUSE_SMART2TEST_N3_MASK                         (1 << 24)
+#define OMAP4_LPDDR2_PTV_N1_SHIFT                              23
+#define OMAP4_LPDDR2_PTV_N1_MASK                               (1 << 23)
+#define OMAP4_LPDDR2_PTV_N2_SHIFT                              22
+#define OMAP4_LPDDR2_PTV_N2_MASK                               (1 << 22)
+#define OMAP4_LPDDR2_PTV_N3_SHIFT                              21
+#define OMAP4_LPDDR2_PTV_N3_MASK                               (1 << 21)
+#define OMAP4_LPDDR2_PTV_N4_SHIFT                              20
+#define OMAP4_LPDDR2_PTV_N4_MASK                               (1 << 20)
+#define OMAP4_LPDDR2_PTV_N5_SHIFT                              19
+#define OMAP4_LPDDR2_PTV_N5_MASK                               (1 << 19)
+#define OMAP4_LPDDR2_PTV_P1_SHIFT                              18
+#define OMAP4_LPDDR2_PTV_P1_MASK                               (1 << 18)
+#define OMAP4_LPDDR2_PTV_P2_SHIFT                              17
+#define OMAP4_LPDDR2_PTV_P2_MASK                               (1 << 17)
+#define OMAP4_LPDDR2_PTV_P3_SHIFT                              16
+#define OMAP4_LPDDR2_PTV_P3_MASK                               (1 << 16)
+#define OMAP4_LPDDR2_PTV_P4_SHIFT                              15
+#define OMAP4_LPDDR2_PTV_P4_MASK                               (1 << 15)
+#define OMAP4_LPDDR2_PTV_P5_SHIFT                              14
+#define OMAP4_LPDDR2_PTV_P5_MASK                               (1 << 14)
+
+/* CONTROL_EFUSE_3 */
+#define OMAP4_STD_FUSE_SPARE_1_SHIFT                           24
+#define OMAP4_STD_FUSE_SPARE_1_MASK                            (0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_2_SHIFT                           16
+#define OMAP4_STD_FUSE_SPARE_2_MASK                            (0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_3_SHIFT                           8
+#define OMAP4_STD_FUSE_SPARE_3_MASK                            (0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_4_SHIFT                           0
+#define OMAP4_STD_FUSE_SPARE_4_MASK                            (0xff << 0)
+
+/* CONTROL_EFUSE_4 */
+#define OMAP4_STD_FUSE_SPARE_5_SHIFT                           24
+#define OMAP4_STD_FUSE_SPARE_5_MASK                            (0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_6_SHIFT                           16
+#define OMAP4_STD_FUSE_SPARE_6_MASK                            (0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_7_SHIFT                           8
+#define OMAP4_STD_FUSE_SPARE_7_MASK                            (0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_8_SHIFT                           0
+#define OMAP4_STD_FUSE_SPARE_8_MASK                            (0xff << 0)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h
new file mode 100644 (file)
index 0000000..17c9b37
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_WKUP                                     0x4a31e000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_REVISION                         0x0000
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_HWINFO                           0x0004
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_SYSCONFIG                                0x0010
+#define OMAP4_CTRL_MODULE_PAD_WKUP_PADCONF_WAKEUPEVENT_0               0x007c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_0      0x05a0
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_1      0x05a4
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_PADCONF_MODE                        0x05a8
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_XTAL_OSCILLATOR             0x05ac
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_USIMIO                      0x0600
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2                       0x0604
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_JTAG                                0x0608
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SYS                         0x060c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_RW               0x0614
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R                        0x0618
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R_C0             0x061c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT                              30
+#define OMAP4_IP_REV_SCHEME_MASK                               (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT                                        16
+#define OMAP4_IP_REV_FUNC_MASK                                 (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT                                 11
+#define OMAP4_IP_REV_RTL_MASK                                  (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT                               8
+#define OMAP4_IP_REV_MAJOR_MASK                                        (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT                              6
+#define OMAP4_IP_REV_CUSTOM_MASK                               (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT                               0
+#define OMAP4_IP_REV_MINOR_MASK                                        (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT                                  0
+#define OMAP4_IP_HWINFO_MASK                                   (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT                      2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK                       (0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_SHIFT              24
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_MASK               (1 << 24)
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_SHIFT              23
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_MASK               (1 << 23)
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_SHIFT         22
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_MASK          (1 << 22)
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_SHIFT             21
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_MASK              (1 << 21)
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_SHIFT              20
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_MASK               (1 << 20)
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_SHIFT            19
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_MASK             (1 << 19)
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_SHIFT             18
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_MASK              (1 << 18)
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_SHIFT             17
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_MASK              (1 << 17)
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_SHIFT   16
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_MASK    (1 << 16)
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_SHIFT           15
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_MASK            (1 << 15)
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_SHIFT          14
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_MASK           (1 << 14)
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_SHIFT               13
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_MASK                        (1 << 13)
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_SHIFT         12
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_MASK          (1 << 12)
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_SHIFT         11
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_MASK          (1 << 11)
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_SHIFT         10
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_MASK          (1 << 10)
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_SHIFT         9
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_MASK          (1 << 9)
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_SHIFT         8
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_MASK          (1 << 8)
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_SHIFT                7
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_MASK         (1 << 7)
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_SHIFT                        6
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_MASK                 (1 << 6)
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_SHIFT                        5
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_MASK                 (1 << 5)
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_SHIFT           4
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_MASK            (1 << 4)
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_SHIFT                        3
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_MASK                 (1 << 3)
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_SHIFT             2
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_MASK              (1 << 2)
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_SHIFT               1
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_MASK                        (1 << 1)
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_SHIFT                        0
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_MASK                 (1 << 0)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_0 */
+#define OMAP4_FREF_DR0_SC_SHIFT                                        30
+#define OMAP4_FREF_DR0_SC_MASK                                 (0x3 << 30)
+#define OMAP4_FREF_DR1_SC_SHIFT                                        28
+#define OMAP4_FREF_DR1_SC_MASK                                 (0x3 << 28)
+#define OMAP4_FREF_DR4_SC_SHIFT                                        26
+#define OMAP4_FREF_DR4_SC_MASK                                 (0x3 << 26)
+#define OMAP4_FREF_DR5_SC_SHIFT                                        24
+#define OMAP4_FREF_DR5_SC_MASK                                 (0x3 << 24)
+#define OMAP4_FREF_DR6_SC_SHIFT                                        22
+#define OMAP4_FREF_DR6_SC_MASK                                 (0x3 << 22)
+#define OMAP4_FREF_DR7_SC_SHIFT                                        20
+#define OMAP4_FREF_DR7_SC_MASK                                 (0x3 << 20)
+#define OMAP4_GPIO_DR7_SC_SHIFT                                        18
+#define OMAP4_GPIO_DR7_SC_MASK                                 (0x3 << 18)
+#define OMAP4_DPM_DR0_SC_SHIFT                                 14
+#define OMAP4_DPM_DR0_SC_MASK                                  (0x3 << 14)
+#define OMAP4_SIM_DR0_SC_SHIFT                                 12
+#define OMAP4_SIM_DR0_SC_MASK                                  (0x3 << 12)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_1 */
+#define OMAP4_FREF_DR0_LB_SHIFT                                        30
+#define OMAP4_FREF_DR0_LB_MASK                                 (0x3 << 30)
+#define OMAP4_FREF_DR1_LB_SHIFT                                        28
+#define OMAP4_FREF_DR1_LB_MASK                                 (0x3 << 28)
+#define OMAP4_FREF_DR4_LB_SHIFT                                        26
+#define OMAP4_FREF_DR4_LB_MASK                                 (0x3 << 26)
+#define OMAP4_FREF_DR5_LB_SHIFT                                        24
+#define OMAP4_FREF_DR5_LB_MASK                                 (0x3 << 24)
+#define OMAP4_FREF_DR6_LB_SHIFT                                        22
+#define OMAP4_FREF_DR6_LB_MASK                                 (0x3 << 22)
+#define OMAP4_FREF_DR7_LB_SHIFT                                        20
+#define OMAP4_FREF_DR7_LB_MASK                                 (0x3 << 20)
+#define OMAP4_GPIO_DR7_LB_SHIFT                                        18
+#define OMAP4_GPIO_DR7_LB_MASK                                 (0x3 << 18)
+#define OMAP4_DPM_DR0_LB_SHIFT                                 14
+#define OMAP4_DPM_DR0_LB_MASK                                  (0x3 << 14)
+#define OMAP4_SIM_DR0_LB_SHIFT                                 12
+#define OMAP4_SIM_DR0_LB_MASK                                  (0x3 << 12)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_FREF_SHIFT                               31
+#define OMAP4_VDDS_DV_FREF_MASK                                        (1 << 31)
+#define OMAP4_VDDS_DV_BANK2_SHIFT                              30
+#define OMAP4_VDDS_DV_BANK2_MASK                               (1 << 30)
+
+/* CONTROL_XTAL_OSCILLATOR */
+#define OMAP4_OSCILLATOR_BOOST_SHIFT                           31
+#define OMAP4_OSCILLATOR_BOOST_MASK                            (1 << 31)
+#define OMAP4_OSCILLATOR_OS_OUT_SHIFT                          30
+#define OMAP4_OSCILLATOR_OS_OUT_MASK                           (1 << 30)
+
+/* CONTROL_USIMIO */
+#define OMAP4_PAD_USIM_CLK_LOW_SHIFT                           31
+#define OMAP4_PAD_USIM_CLK_LOW_MASK                            (1 << 31)
+#define OMAP4_PAD_USIM_RST_LOW_SHIFT                           29
+#define OMAP4_PAD_USIM_RST_LOW_MASK                            (1 << 29)
+#define OMAP4_USIM_PWRDNZ_SHIFT                                        28
+#define OMAP4_USIM_PWRDNZ_MASK                                 (1 << 28)
+
+/* CONTROL_I2C_2 */
+#define OMAP4_SR_SDA_GLFENB_SHIFT                              31
+#define OMAP4_SR_SDA_GLFENB_MASK                               (1 << 31)
+#define OMAP4_SR_SDA_LOAD_BITS_SHIFT                           29
+#define OMAP4_SR_SDA_LOAD_BITS_MASK                            (0x3 << 29)
+#define OMAP4_SR_SDA_PULLUPRESX_SHIFT                          28
+#define OMAP4_SR_SDA_PULLUPRESX_MASK                           (1 << 28)
+#define OMAP4_SR_SCL_GLFENB_SHIFT                              27
+#define OMAP4_SR_SCL_GLFENB_MASK                               (1 << 27)
+#define OMAP4_SR_SCL_LOAD_BITS_SHIFT                           25
+#define OMAP4_SR_SCL_LOAD_BITS_MASK                            (0x3 << 25)
+#define OMAP4_SR_SCL_PULLUPRESX_SHIFT                          24
+#define OMAP4_SR_SCL_PULLUPRESX_MASK                           (1 << 24)
+
+/* CONTROL_JTAG */
+#define OMAP4_JTAG_NTRST_EN_SHIFT                              31
+#define OMAP4_JTAG_NTRST_EN_MASK                               (1 << 31)
+#define OMAP4_JTAG_TCK_EN_SHIFT                                        30
+#define OMAP4_JTAG_TCK_EN_MASK                                 (1 << 30)
+#define OMAP4_JTAG_RTCK_EN_SHIFT                               29
+#define OMAP4_JTAG_RTCK_EN_MASK                                        (1 << 29)
+#define OMAP4_JTAG_TDI_EN_SHIFT                                        28
+#define OMAP4_JTAG_TDI_EN_MASK                                 (1 << 28)
+#define OMAP4_JTAG_TDO_EN_SHIFT                                        27
+#define OMAP4_JTAG_TDO_EN_MASK                                 (1 << 27)
+
+/* CONTROL_SYS */
+#define OMAP4_SYS_NRESWARM_PIPU_SHIFT                          31
+#define OMAP4_SYS_NRESWARM_PIPU_MASK                           (1 << 31)
+
+/* WKUP_CONTROL_SPARE_RW */
+#define OMAP4_WKUP_CONTROL_SPARE_RW_SHIFT                      0
+#define OMAP4_WKUP_CONTROL_SPARE_RW_MASK                       (0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R */
+#define OMAP4_WKUP_CONTROL_SPARE_R_SHIFT                       0
+#define OMAP4_WKUP_CONTROL_SPARE_R_MASK                                (0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R_C0 */
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_SHIFT                    31
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_MASK                     (1 << 31)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_SHIFT                    30
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_MASK                     (1 << 30)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_SHIFT                    29
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_MASK                     (1 << 29)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_SHIFT                    28
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_MASK                     (1 << 28)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_SHIFT                    27
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_MASK                     (1 << 27)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_SHIFT                    26
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_MASK                     (1 << 26)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_SHIFT                    25
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_MASK                     (1 << 25)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_SHIFT                    24
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_MASK                     (1 << 24)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
new file mode 100644 (file)
index 0000000..a0af9ba
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * OMAP44xx CTRL_MODULE_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_WKUP                         0x4a30c000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_WKUP_IP_REVISION             0x0000
+#define OMAP4_CTRL_MODULE_WKUP_IP_HWINFO               0x0004
+#define OMAP4_CTRL_MODULE_WKUP_IP_SYSCONFIG            0x0010
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_0    0x0460
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_1    0x0464
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_2    0x0468
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_3    0x046c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_4    0x0470
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_5    0x0474
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_6    0x0478
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_7    0x047c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_8    0x0480
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_9    0x0484
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_10   0x0488
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_11   0x048c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_12   0x0490
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_13   0x0494
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_14   0x0498
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_15   0x049c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_16   0x04a0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_17   0x04a4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_18   0x04a8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_19   0x04ac
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_20   0x04b0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_21   0x04b4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_22   0x04b8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_23   0x04bc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_24   0x04c0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_25   0x04c4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_26   0x04c8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_27   0x04cc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_28   0x04d0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_29   0x04d4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_30   0x04d8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_31   0x04dc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT              30
+#define OMAP4_IP_REV_SCHEME_MASK               (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT                        16
+#define OMAP4_IP_REV_FUNC_MASK                 (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT                 11
+#define OMAP4_IP_REV_RTL_MASK                  (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT               8
+#define OMAP4_IP_REV_MAJOR_MASK                        (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT              6
+#define OMAP4_IP_REV_CUSTOM_MASK               (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT               0
+#define OMAP4_IP_REV_MINOR_MASK                        (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT                  0
+#define OMAP4_IP_HWINFO_MASK                   (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT      2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK       (0x3 << 2)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_WKUP_MODE_SHIFT                  0
+#define OMAP4_WKUP_MODE_MASK                           (1 << 0)
+
+#endif
index b9ea70bce5635d431ef2651058bd72b0619420df..40562ddd3ee4fe29ea1e173a61d778225d28b01d 100644 (file)
@@ -36,6 +36,7 @@
 #include "clock2xxx.h"
 #include "clock3xxx.h"
 #include "clock44xx.h"
+#include "io.h"
 
 #include <plat/omap-pm.h>
 #include <plat/powerdomain.h>
@@ -323,6 +324,9 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
                omap2430_hwmod_init();
        else if (cpu_is_omap34xx())
                omap3xxx_hwmod_init();
+       else if (cpu_is_omap44xx())
+               omap44xx_hwmod_init();
+
        /* The OPP tables have to be registered before a clk init */
        omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
 
@@ -342,9 +346,7 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
 #ifndef CONFIG_PM_RUNTIME
        skip_setup_idle = 1;
 #endif
-       if (cpu_is_omap24xx() || cpu_is_omap34xx())   /* FIXME: OMAP4 */
-               omap_hwmod_late_init(skip_setup_idle);
-
+       omap_hwmod_late_init(skip_setup_idle);
        if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
                omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
                _omap2_init_reprogram_sdrc();
diff --git a/arch/arm/mach-omap2/io.h b/arch/arm/mach-omap2/io.h
new file mode 100644 (file)
index 0000000..fd230c6
--- /dev/null
@@ -0,0 +1,7 @@
+
+#ifndef __MACH_OMAP2_IO_H__
+#define __MACH_OMAP2_IO_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /*  __MACH_OMAP2_IO_H__ */
index 26aeef560aa3920ac2c663d50985266bd10138d7..32eeabe9d2abeb6e235fdd7ed9d2ead76c58fe30 100644 (file)
@@ -47,7 +47,6 @@ static struct omap_irq_bank {
 } __attribute__ ((aligned(4))) irq_banks[] = {
        {
                /* MPU INTC */
-               .base_reg       = 0,
                .nr_irqs        = 96,
        },
 };
index 42dbfa46e656de6ec04819b0bf19e6e321d0c2c7..40ddecab93a9b42694216619cb4fa9834e50eb69 100644 (file)
@@ -181,7 +181,7 @@ static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
 static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
                omap_mbox_type_t irq)
 {
-       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       struct omap_mbox2_priv *p = mbox->priv;
        u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 
        l = mbox_read_reg(p->irqenable);
@@ -192,7 +192,7 @@ static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
 static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
                omap_mbox_type_t irq)
 {
-       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       struct omap_mbox2_priv *p = mbox->priv;
        u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
        l = mbox_read_reg(p->irqdisable);
        l &= ~bit;
@@ -202,7 +202,7 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
 static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
                omap_mbox_type_t irq)
 {
-       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       struct omap_mbox2_priv *p = mbox->priv;
        u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 
        mbox_write_reg(bit, p->irqstatus);
@@ -214,7 +214,7 @@ static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
 static int omap2_mbox_is_irq(struct omap_mbox *mbox,
                omap_mbox_type_t irq)
 {
-       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       struct omap_mbox2_priv *p = mbox->priv;
        u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
        u32 enable = mbox_read_reg(p->irqenable);
        u32 status = mbox_read_reg(p->irqstatus);
index 467aae245781c91c6ac4535a5d7d7295e5251ec6..f9c9df5b5ff1d7b6d6e4a24b3cb9da2c00d88f92 100644 (file)
 #include <plat/cpu.h>
 #include <plat/mcbsp.h>
 
-#include "mux.h"
+#include "control.h"
 
-static void omap2_mcbsp2_mux_setup(void)
+
+/* McBSP internal signal muxing functions */
+
+void omap2_mcbsp1_mux_clkr_src(u8 mux)
 {
-       omap_mux_init_signal("eac_ac_sclk.mcbsp2_clkx", OMAP_PULL_ENA);
-       omap_mux_init_signal("eac_ac_fs.mcbsp2_fsx", OMAP_PULL_ENA);
-       omap_mux_init_signal("eac_ac_din.mcbsp2_dr", OMAP_PULL_ENA);
-       omap_mux_init_signal("eac_ac_dout.mcbsp2_dx", OMAP_PULL_ENA);
-       omap_mux_init_gpio(117, OMAP_PULL_ENA);
-       /*
-        * TODO: Need to add MUX settings for OMAP 2430 SDP
-        */
+       u32 v;
+
+       v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+       if (mux == CLKR_SRC_CLKR)
+               v &= ~OMAP2_MCBSP1_CLKR_MASK;
+       else if (mux == CLKR_SRC_CLKX)
+               v |= OMAP2_MCBSP1_CLKR_MASK;
+       omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
 }
+EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
 
-static void omap2_mcbsp_request(unsigned int id)
+void omap2_mcbsp1_mux_fsr_src(u8 mux)
 {
-       if (cpu_is_omap2420() && (id == OMAP_MCBSP2))
-               omap2_mcbsp2_mux_setup();
+       u32 v;
+
+       v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+       if (mux == FSR_SRC_FSR)
+               v &= ~OMAP2_MCBSP1_FSR_MASK;
+       else if (mux == FSR_SRC_FSX)
+               v |= OMAP2_MCBSP1_FSR_MASK;
+       omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
 }
+EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
 
-static struct omap_mcbsp_ops omap2_mcbsp_ops = {
-       .request        = omap2_mcbsp_request,
-};
+/* McBSP CLKS source switching function */
+
+int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
+{
+       struct omap_mcbsp *mcbsp;
+       struct clk *fck_src;
+       char *fck_src_name;
+       int r;
+
+       if (!omap_mcbsp_check_valid_id(id)) {
+               pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
+               return -EINVAL;
+       }
+       mcbsp = id_to_mcbsp_ptr(id);
+
+       if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+               fck_src_name = "pad_fck";
+       else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+               fck_src_name = "prcm_fck";
+       else
+               return -EINVAL;
+
+       fck_src = clk_get(mcbsp->dev, fck_src_name);
+       if (IS_ERR_OR_NULL(fck_src)) {
+               pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
+                      fck_src_name);
+               return -EINVAL;
+       }
+
+       clk_disable(mcbsp->fclk);
+
+       r = clk_set_parent(mcbsp->fclk, fck_src);
+       if (IS_ERR_VALUE(r)) {
+               pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
+                      "clks", fck_src_name);
+               clk_put(fck_src);
+               return -EINVAL;
+       }
+
+       clk_enable(mcbsp->fclk);
+
+       clk_put(fck_src);
+
+       return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
+
+
+/* Platform data */
 
 #ifdef CONFIG_ARCH_OMAP2420
 static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
@@ -55,7 +112,6 @@ static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP24XX_MCBSP2_BASE,
@@ -63,7 +119,6 @@ static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
 };
 #define OMAP2420_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2420_mcbsp_pdata)
@@ -82,7 +137,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP24XX_MCBSP2_BASE,
@@ -90,7 +144,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP2430_MCBSP3_BASE,
@@ -98,7 +151,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
                .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP2430_MCBSP4_BASE,
@@ -106,7 +158,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
                .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP2430_MCBSP5_BASE,
@@ -114,7 +165,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
                .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
        },
 };
 #define OMAP2430_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2430_mcbsp_pdata)
@@ -133,7 +183,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
                .buffer_size    = 0x80, /* The FIFO has 128 locations */
        },
        {
@@ -143,7 +192,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
                .buffer_size    = 0x500, /* The FIFO has 1024 + 256 locations */
        },
        {
@@ -153,7 +201,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
                .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
                .buffer_size    = 0x80, /* The FIFO has 128 locations */
        },
        {
@@ -162,7 +209,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
                .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
                .buffer_size    = 0x80, /* The FIFO has 128 locations */
        },
        {
@@ -171,7 +217,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
                .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
                .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
-               .ops            = &omap2_mcbsp_ops,
                .buffer_size    = 0x80, /* The FIFO has 128 locations */
        },
 };
@@ -189,28 +234,24 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
                .dma_rx_sync    = OMAP44XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP44XX_DMA_MCBSP1_TX,
                .tx_irq         = OMAP44XX_IRQ_MCBSP1,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP44XX_MCBSP2_BASE,
                .dma_rx_sync    = OMAP44XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP44XX_DMA_MCBSP2_TX,
                .tx_irq         = OMAP44XX_IRQ_MCBSP2,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP44XX_MCBSP3_BASE,
                .dma_rx_sync    = OMAP44XX_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP44XX_DMA_MCBSP3_TX,
                .tx_irq         = OMAP44XX_IRQ_MCBSP3,
-               .ops            = &omap2_mcbsp_ops,
        },
        {
                .phys_base      = OMAP44XX_MCBSP4_BASE,
                .dma_rx_sync    = OMAP44XX_DMA_MCBSP4_RX,
                .dma_tx_sync    = OMAP44XX_DMA_MCBSP4_TX,
                .tx_irq         = OMAP44XX_IRQ_MCBSP4,
-               .ops            = &omap2_mcbsp_ops,
        },
 };
 #define OMAP44XX_MCBSP_PDATA_SZ                ARRAY_SIZE(omap44xx_mcbsp_pdata)
index ab403b2ed26befb6058309e26e3b75688eb46905..074536ae401fa11dcf439e0abce049df9f2b406a 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -36,8 +35,7 @@
 
 #include <asm/system.h>
 
-#include <plat/control.h>
-
+#include "control.h"
 #include "mux.h"
 
 #define OMAP_MUX_BASE_OFFSET           0x30    /* Offset from CTRL_BASE */
@@ -87,7 +85,7 @@ static char *omap_mux_options;
 int __init omap_mux_init_gpio(int gpio, int val)
 {
        struct omap_mux_entry *e;
-       struct omap_mux *gpio_mux;
+       struct omap_mux *gpio_mux = NULL;
        u16 old_mode;
        u16 mux_mode;
        int found = 0;
@@ -127,17 +125,16 @@ int __init omap_mux_init_gpio(int gpio, int val)
        return 0;
 }
 
-int __init omap_mux_init_signal(char *muxname, int val)
+int __init omap_mux_init_signal(const char *muxname, int val)
 {
        struct omap_mux_entry *e;
-       char *m0_name = NULL, *mode_name = NULL;
-       int found = 0;
+       const char *mode_name;
+       int found = 0, mode0_len = 0;
 
        mode_name = strchr(muxname, '.');
        if (mode_name) {
-               *mode_name = '\0';
+               mode0_len = strlen(muxname) - strlen(mode_name);
                mode_name++;
-               m0_name = muxname;
        } else {
                mode_name = muxname;
        }
@@ -147,9 +144,11 @@ int __init omap_mux_init_signal(char *muxname, int val)
                char *m0_entry = m->muxnames[0];
                int i;
 
-               if (m0_name && strcmp(m0_name, m0_entry))
+               /* First check for full name in mode0.muxmode format */
+               if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
                        continue;
 
+               /* Then check for muxmode only */
                for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
                        char *mode_cur = m->muxnames[i];
 
index a8e040c2c7e9817aa67115b0e52860dd81653369..350c04f27383963c581f9b29246a8eebecc691e6 100644 (file)
@@ -120,7 +120,7 @@ int omap_mux_init_gpio(int gpio, int val);
  * @muxname:           Mux name in mode0_name.signal_name format
  * @val:               Options for the mux register value
  */
-int omap_mux_init_signal(char *muxname, int val);
+int omap_mux_init_signal(const char *muxname, int val);
 
 #else
 
index fdb04a7eb8aa7dbdef25e90aa51208eb170e779f..414af5434456e84dc8c8623e2f7507827b66b926 100644 (file)
@@ -507,7 +507,7 @@ static struct omap_mux __initdata omap2420_muxmodes[] = {
  * Balls for 447-pin POP package
  */
 #ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2420_pop_ball[] = {
+static struct omap_ball __initdata omap2420_pop_ball[] = {
        _OMAP2420_BALLENTRY(CAM_D0, "y4", NULL),
        _OMAP2420_BALLENTRY(CAM_D1, "y3", NULL),
        _OMAP2420_BALLENTRY(CAM_D2, "u7", NULL),
index 7dcaaa8af32a1544ef23db937622f8c34008b3c0..84d2c5a7ecd7ed729da67a18e67509a4973a18d3 100644 (file)
@@ -586,7 +586,7 @@ static struct omap_mux __initdata omap2430_muxmodes[] = {
  * 447-pin s-PBGA Package, 0.00mm Ball Pitch (Bottom)
  */
 #ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2430_pop_ball[] = {
+static struct omap_ball __initdata omap2430_pop_ball[] = {
        _OMAP2430_BALLENTRY(CAM_D0, "t8", NULL),
        _OMAP2430_BALLENTRY(CAM_D1, "t4", NULL),
        _OMAP2430_BALLENTRY(CAM_D10, "r4", NULL),
index f64d7eea34519763a7fb0d343bcc02dfdcad577a..574e54ea3ab7f5f5947701d36f8bdc902bc0a98a 100644 (file)
@@ -931,7 +931,7 @@ struct omap_ball __initdata omap3_cbc_ball[] = {
  * Signals different on CUS package compared to superset
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_mux __initdata omap3_cus_subset[] = {
+static struct omap_mux __initdata omap3_cus_subset[] = {
        _OMAP3_MUXENTRY(CAM_D10, 109,
                "cam_d10", NULL, NULL, NULL,
                "gpio_109", NULL, NULL, "safe_mode"),
@@ -1077,7 +1077,7 @@ struct omap_mux __initdata omap3_cus_subset[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_ball __initdata omap3_cus_ball[] = {
+static struct omap_ball __initdata omap3_cus_ball[] = {
        _OMAP3_BALLENTRY(CAM_D0, "ab18", NULL),
        _OMAP3_BALLENTRY(CAM_D1, "ac18", NULL),
        _OMAP3_BALLENTRY(CAM_D10, "f21", NULL),
@@ -1269,7 +1269,7 @@ struct omap_ball __initdata omap3_cus_ball[] = {
  * Signals different on CBB package comapared to superset
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_mux __initdata omap3_cbb_subset[] = {
+static struct omap_mux __initdata omap3_cbb_subset[] = {
        _OMAP3_MUXENTRY(CAM_D10, 109,
                "cam_d10", NULL, NULL, NULL,
                "gpio_109", NULL, NULL, "safe_mode"),
@@ -1390,7 +1390,7 @@ struct omap_mux __initdata omap3_cbb_subset[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_ball __initdata omap3_cbb_ball[] = {
+static struct omap_ball __initdata omap3_cbb_ball[] = {
        _OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
        _OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
        _OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
@@ -1600,7 +1600,7 @@ struct omap_ball __initdata omap3_cbb_ball[] = {
  * Signals different on 36XX CBP package comapared to 34XX CBC package
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBP)
-struct omap_mux __initdata omap36xx_cbp_subset[] = {
+static struct omap_mux __initdata omap36xx_cbp_subset[] = {
        _OMAP3_MUXENTRY(CAM_D0, 99,
                "cam_d0", NULL, "csi2_dx2", NULL,
                "gpio_99", NULL, NULL, "safe_mode"),
@@ -1818,7 +1818,7 @@ struct omap_mux __initdata omap36xx_cbp_subset[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined (CONFIG_OMAP_PACKAGE_CBP)
-struct omap_ball __initdata omap36xx_cbp_ball[] = {
+static struct omap_ball __initdata omap36xx_cbp_ball[] = {
        _OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
        _OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
        _OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
index 13dc9794dcc2ea68fe9115cff7be9cd8c074a484..923f9f5f91ce96fc2588f41503b53795e6cdea21 100644 (file)
@@ -61,10 +61,14 @@ static int __init omap_l2_cache_init(void)
        omap_smc1(0x102, 0x1);
 
        /*
-        * 32KB way size, 16-way associativity,
-        * parity disabled
+        * 16-way associativity, parity disabled
+        * Way size - 32KB (es1.0)
+        * Way size - 64KB (es2.0 +)
         */
-       l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+       if (omap_rev() == OMAP4430_REV_ES1_0)
+               l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+       else
+               l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff);
 
        return 0;
 }
index cb911d7d1a3c1535ba88eda74577ea6ef2e1ecd0..5a30658444d0f84d8a8c8bbb7553ee9db07a5959 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * This code manages "OMAP modules" (on-chip devices) and their
- * integration with Linux device driver and bus code.
- *
- * References:
+ * Introduction
+ * ------------
+ * One way to view an OMAP SoC is as a collection of largely unrelated
+ * IP blocks connected by interconnects.  The IP blocks include
+ * devices such as ARM processors, audio serial interfaces, UARTs,
+ * etc.  Some of these devices, like the DSP, are created by TI;
+ * others, like the SGX, largely originate from external vendors.  In
+ * TI's documentation, on-chip devices are referred to as "OMAP
+ * modules."  Some of these IP blocks are identical across several
+ * OMAP versions.  Others are revised frequently.
+ *
+ * These OMAP modules are tied together by various interconnects.
+ * Most of the address and data flow between modules is via OCP-based
+ * interconnects such as the L3 and L4 buses; but there are other
+ * interconnects that distribute the hardware clock tree, handle idle
+ * and reset signaling, supply power, and connect the modules to
+ * various pads or balls on the OMAP package.
+ *
+ * OMAP hwmod provides a consistent way to describe the on-chip
+ * hardware blocks and their integration into the rest of the chip.
+ * This description can be automatically generated from the TI
+ * hardware database.  OMAP hwmod provides a standard, consistent API
+ * to reset, enable, idle, and disable these hardware blocks.  And
+ * hwmod provides a way for other core code, such as the Linux device
+ * code or the OMAP power management and address space mapping code,
+ * to query the hardware database.
+ *
+ * Using hwmod
+ * -----------
+ * Drivers won't call hwmod functions directly.  That is done by the
+ * omap_device code, and in rare occasions, by custom integration code
+ * in arch/arm/ *omap*.  The omap_device code includes functions to
+ * build a struct platform_device using omap_hwmod data, and that is
+ * currently how hwmod data is communicated to drivers and to the
+ * Linux driver model.  Most drivers will call omap_hwmod functions only
+ * indirectly, via pm_runtime*() functions.
+ *
+ * From a layering perspective, here is where the OMAP hwmod code
+ * fits into the kernel software stack:
+ *
+ *            +-------------------------------+
+ *            |      Device driver code       |
+ *            |      (e.g., drivers/)         |
+ *            +-------------------------------+
+ *            |      Linux driver model       |
+ *            |     (platform_device /        |
+ *            |  platform_driver data/code)   |
+ *            +-------------------------------+
+ *            | OMAP core-driver integration  |
+ *            |(arch/arm/mach-omap2/devices.c)|
+ *            +-------------------------------+
+ *            |      omap_device code         |
+ *            | (../plat-omap/omap_device.c)  |
+ *            +-------------------------------+
+ *   ---->    |    omap_hwmod code/data       |    <-----
+ *            | (../mach-omap2/omap_hwmod*)   |
+ *            +-------------------------------+
+ *            | OMAP clock/PRCM/register fns  |
+ *            | (__raw_{read,write}l, clk*)   |
+ *            +-------------------------------+
+ *
+ * Device drivers should not contain any OMAP-specific code or data in
+ * them.  They should only contain code to operate the IP block that
+ * the driver is responsible for.  This is because these IP blocks can
+ * also appear in other SoCs, either from TI (such as DaVinci) or from
+ * other manufacturers; and drivers should be reusable across other
+ * platforms.
+ *
+ * The OMAP hwmod code also will attempt to reset and idle all on-chip
+ * devices upon boot.  The goal here is for the kernel to be
+ * completely self-reliant and independent from bootloaders.  This is
+ * to ensure a repeatable configuration, both to ensure consistent
+ * runtime behavior, and to make it easier for others to reproduce
+ * bugs.
+ *
+ * OMAP module activity states
+ * ---------------------------
+ * The hwmod code considers modules to be in one of several activity
+ * states.  IP blocks start out in an UNKNOWN state, then once they
+ * are registered via the hwmod code, proceed to the REGISTERED state.
+ * Once their clock names are resolved to clock pointers, the module
+ * enters the CLKS_INITED state; and finally, once the module has been
+ * reset and the integration registers programmed, the INITIALIZED state
+ * is entered.  The hwmod code will then place the module into either
+ * the IDLE state to save power, or in the case of a critical system
+ * module, the ENABLED state.
+ *
+ * OMAP core integration code can then call omap_hwmod*() functions
+ * directly to move the module between the IDLE, ENABLED, and DISABLED
+ * states, as needed.  This is done during both the PM idle loop, and
+ * in the OMAP core integration code's implementation of the PM runtime
+ * functions.
+ *
+ * References
+ * ----------
+ * This is a partial list.
  * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
  * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
  * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
 #include <plat/powerdomain.h>
 #include <plat/clock.h>
 #include <plat/omap_hwmod.h>
+#include <plat/prcm.h>
 
 #include "cm.h"
+#include "prm.h"
 
-/* Maximum microseconds to wait for OMAP module to reset */
-#define MAX_MODULE_RESET_WAIT          10000
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT      10000
 
 /* Name of the OMAP hwmod for the MPU */
 #define MPU_INITIATOR_NAME             "mpu"
@@ -90,7 +184,7 @@ static int _update_sysc_cache(struct omap_hwmod *oh)
 
        /* XXX ensure module interface clock is up */
 
-       oh->_sysc_cache = omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+       oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
 
        if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
                oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
@@ -117,7 +211,7 @@ static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
 
        if (oh->_sysc_cache != v) {
                oh->_sysc_cache = v;
-               omap_hwmod_writel(v, oh, oh->class->sysc->sysc_offs);
+               omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
        }
 }
 
@@ -544,6 +638,36 @@ static int _disable_clocks(struct omap_hwmod *oh)
        return 0;
 }
 
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_opt_clk *oc;
+       int i;
+
+       pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
+
+       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+               if (oc->_clk) {
+                       pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
+                                oc->_clk->name);
+                       clk_enable(oc->_clk);
+               }
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_opt_clk *oc;
+       int i;
+
+       pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
+
+       for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+               if (oc->_clk) {
+                       pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
+                                oc->_clk->name);
+                       clk_disable(oc->_clk);
+               }
+}
+
 /**
  * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
  * @oh: struct omap_hwmod *
@@ -622,7 +746,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
 }
 
 /**
- * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG
+ * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * If module is marked as SWSUP_SIDLE, force the module out of slave
@@ -630,7 +754,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
  * as SWSUP_MSUSPEND, force the module out of master standby;
  * otherwise, configure it for smart-standby.  No return value.
  */
-static void _sysc_enable(struct omap_hwmod *oh)
+static void _enable_sysc(struct omap_hwmod *oh)
 {
        u8 idlemode, sf;
        u32 v;
@@ -653,14 +777,6 @@ static void _sysc_enable(struct omap_hwmod *oh)
                _set_master_standbymode(oh, idlemode, &v);
        }
 
-       if (sf & SYSC_HAS_AUTOIDLE) {
-               idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
-                       0 : 1;
-               _set_module_autoidle(oh, idlemode, &v);
-       }
-
-       /* XXX OCP ENAWAKEUP bit? */
-
        /*
         * XXX The clock framework should handle this, by
         * calling into this code.  But this must wait until the
@@ -671,10 +787,25 @@ static void _sysc_enable(struct omap_hwmod *oh)
                _set_clockactivity(oh, oh->class->sysc->clockact, &v);
 
        _write_sysconfig(v, oh);
+
+       /* If slave is in SMARTIDLE, also enable wakeup */
+       if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE))
+               _enable_wakeup(oh);
+
+       /*
+        * Set the autoidle bit only after setting the smartidle bit
+        * Setting this will not have any impact on the other modules.
+        */
+       if (sf & SYSC_HAS_AUTOIDLE) {
+               idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
+                       0 : 1;
+               _set_module_autoidle(oh, idlemode, &v);
+               _write_sysconfig(v, oh);
+       }
 }
 
 /**
- * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG
+ * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * If module is marked as SWSUP_SIDLE, force the module into slave
@@ -682,7 +813,7 @@ static void _sysc_enable(struct omap_hwmod *oh)
  * as SWSUP_MSUSPEND, force the module into master standby; otherwise,
  * configure it for smart-standby.  No return value.
  */
-static void _sysc_idle(struct omap_hwmod *oh)
+static void _idle_sysc(struct omap_hwmod *oh)
 {
        u8 idlemode, sf;
        u32 v;
@@ -709,13 +840,13 @@ static void _sysc_idle(struct omap_hwmod *oh)
 }
 
 /**
- * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG
+ * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * Force the module into slave idle and master suspend. No return
  * value.
  */
-static void _sysc_shutdown(struct omap_hwmod *oh)
+static void _shutdown_sysc(struct omap_hwmod *oh)
 {
        u32 v;
        u8 sf;
@@ -767,10 +898,10 @@ static struct omap_hwmod *_lookup(const char *name)
  * @data: not used; pass NULL
  *
  * Called by omap_hwmod_late_init() (after omap2_clk_init()).
- * Resolves all clock names embedded in the hwmod.  Must be called
- * with omap_hwmod_mutex held.  Returns -EINVAL if the omap_hwmod
- * has not yet been registered or if the clocks have already been
- * initialized, 0 on success, or a non-zero error on failure.
+ * Resolves all clock names embedded in the hwmod.  Returns -EINVAL if
+ * the omap_hwmod has not yet been registered or if the clocks have
+ * already been initialized, 0 on success, or a non-zero error on
+ * failure.
  */
 static int _init_clocks(struct omap_hwmod *oh, void *data)
 {
@@ -833,57 +964,203 @@ static int _wait_target_ready(struct omap_hwmod *oh)
        return ret;
 }
 
+/**
+ * _lookup_hardreset - return the register bit shift for this hwmod/reset line
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line in the context of this hwmod
+ *
+ * Return the bit position of the reset line that match the
+ * input name. Return -ENOENT if not found.
+ */
+static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       int i;
+
+       for (i = 0; i < oh->rst_lines_cnt; i++) {
+               const char *rst_line = oh->rst_lines[i].name;
+               if (!strcmp(rst_line, name)) {
+                       u8 shift = oh->rst_lines[i].rst_shift;
+                       pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n",
+                                oh->name, rst_line, shift);
+
+                       return shift;
+               }
+       }
+
+       return -ENOENT;
+}
+
+/**
+ * _assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       u8 shift;
+
+       if (!oh)
+               return -EINVAL;
+
+       shift = _lookup_hardreset(oh, name);
+       if (IS_ERR_VALUE(shift))
+               return shift;
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
+                                                 shift);
+       else if (cpu_is_omap44xx())
+               return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
+                                                 shift);
+       else
+               return -EINVAL;
+}
+
+/**
+ * _deassert_hardreset - deassert the HW reset line of submodules contained
+ * in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       u8 shift;
+       int r;
+
+       if (!oh)
+               return -EINVAL;
+
+       shift = _lookup_hardreset(oh, name);
+       if (IS_ERR_VALUE(shift))
+               return shift;
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
+                                                shift);
+       else if (cpu_is_omap44xx())
+               r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
+                                                shift);
+       else
+               return -EINVAL;
+
+       if (r == -EBUSY)
+               pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
+
+       return r;
+}
+
+/**
+ * _read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the state of the reset line.
+ */
+static int _read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       u8 shift;
+
+       if (!oh)
+               return -EINVAL;
+
+       shift = _lookup_hardreset(oh, name);
+       if (IS_ERR_VALUE(shift))
+               return shift;
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
+                                                      shift);
+       } else if (cpu_is_omap44xx()) {
+               return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
+                                                      shift);
+       } else {
+               return -EINVAL;
+       }
+}
+
 /**
  * _reset - reset an omap_hwmod
  * @oh: struct omap_hwmod *
  *
  * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit.  hwmod must be
- * enabled for this to work.  Must be called with omap_hwmod_mutex
- * held.  Returns -EINVAL if the hwmod cannot be reset this way or if
- * the hwmod is in the wrong state, -ETIMEDOUT if the module did not
- * reset in time, or 0 upon success.
+ * enabled for this to work.  Returns -EINVAL if the hwmod cannot be
+ * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
+ * the module did not reset in time, or 0 upon success.
+ *
+ * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
+ * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead
+ * use the SYSCONFIG softreset bit to provide the status.
+ *
+ * Note that some IP like McBSP does have a reset control but no reset status.
  */
 static int _reset(struct omap_hwmod *oh)
 {
-       u32 r, v;
+       u32 v;
        int c = 0;
+       int ret = 0;
 
        if (!oh->class->sysc ||
-           !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET) ||
-           (oh->class->sysc->sysc_flags & SYSS_MISSING))
+           !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
                return -EINVAL;
 
        /* clocks must be on for this operation */
        if (oh->_state != _HWMOD_STATE_ENABLED) {
-               WARN(1, "omap_hwmod: %s: reset can only be entered from "
-                    "enabled state\n", oh->name);
+               pr_warning("omap_hwmod: %s: reset can only be entered from "
+                          "enabled state\n", oh->name);
                return -EINVAL;
        }
 
+       /* For some modules, all optionnal clocks need to be enabled as well */
+       if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+               _enable_optional_clocks(oh);
+
        pr_debug("omap_hwmod: %s: resetting\n", oh->name);
 
        v = oh->_sysc_cache;
-       r = _set_softreset(oh, &v);
-       if (r)
-               return r;
+       ret = _set_softreset(oh, &v);
+       if (ret)
+               goto dis_opt_clks;
        _write_sysconfig(v, oh);
 
-       omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) &
-                          SYSS_RESETDONE_MASK),
-                         MAX_MODULE_RESET_WAIT, c);
-
-       if (c == MAX_MODULE_RESET_WAIT)
-               WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n",
-                    oh->name, MAX_MODULE_RESET_WAIT);
+       if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
+               omap_test_timeout((omap_hwmod_read(oh,
+                                                   oh->class->sysc->syss_offs)
+                                  & SYSS_RESETDONE_MASK),
+                                 MAX_MODULE_SOFTRESET_WAIT, c);
+       else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS)
+               omap_test_timeout(!(omap_hwmod_read(oh,
+                                                    oh->class->sysc->sysc_offs)
+                                  & SYSC_TYPE2_SOFTRESET_MASK),
+                                 MAX_MODULE_SOFTRESET_WAIT, c);
+
+       if (c == MAX_MODULE_SOFTRESET_WAIT)
+               pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
+                          oh->name, MAX_MODULE_SOFTRESET_WAIT);
        else
-               pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c);
+               pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
 
        /*
         * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
         * _wait_target_ready() or _reset()
         */
 
-       return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0;
+       ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
+
+dis_opt_clks:
+       if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+               _disable_optional_clocks(oh);
+
+       return ret;
 }
 
 /**
@@ -891,9 +1168,11 @@ static int _reset(struct omap_hwmod *oh)
  * @oh: struct omap_hwmod *
  *
  * Enables an omap_hwmod @oh such that the MPU can access the hwmod's
- * register target.  Must be called with omap_hwmod_mutex held.
- * Returns -EINVAL if the hwmod is in the wrong state or passes along
- * the return value of _wait_target_ready().
+ * register target.  (This function has a full name --
+ * _omap_hwmod_enable() rather than simply _enable() -- because it is
+ * currently required by the pm34xx.c idle loop.)  Returns -EINVAL if
+ * the hwmod is in the wrong state or passes along the return value of
+ * _wait_target_ready().
  */
 int _omap_hwmod_enable(struct omap_hwmod *oh)
 {
@@ -909,6 +1188,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
 
        pr_debug("omap_hwmod: %s: enabling\n", oh->name);
 
+       /*
+        * If an IP contains only one HW reset line, then de-assert it in order
+        * to allow to enable the clocks. Otherwise the PRCM will return
+        * Intransition status, and the init will failed.
+        */
+       if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
+            oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
+               _deassert_hardreset(oh, oh->rst_lines[0].name);
+
        /* XXX mux balls */
 
        _add_initiator_dep(oh, mpu_oh);
@@ -922,7 +1210,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
                if (oh->class->sysc) {
                        if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
                                _update_sysc_cache(oh);
-                       _sysc_enable(oh);
+                       _enable_sysc(oh);
                }
        } else {
                pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
@@ -933,12 +1221,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
 }
 
 /**
- * _idle - idle an omap_hwmod
+ * _omap_hwmod_idle - idle an omap_hwmod
  * @oh: struct omap_hwmod *
  *
  * Idles an omap_hwmod @oh.  This should be called once the hwmod has
- * no further work.  Returns -EINVAL if the hwmod is in the wrong
- * state or returns 0.
+ * no further work.  (This function has a full name --
+ * _omap_hwmod_idle() rather than simply _idle() -- because it is
+ * currently required by the pm34xx.c idle loop.)  Returns -EINVAL if
+ * the hwmod is in the wrong state or returns 0.
  */
 int _omap_hwmod_idle(struct omap_hwmod *oh)
 {
@@ -951,7 +1241,7 @@ int _omap_hwmod_idle(struct omap_hwmod *oh)
        pr_debug("omap_hwmod: %s: idling\n", oh->name);
 
        if (oh->class->sysc)
-               _sysc_idle(oh);
+               _idle_sysc(oh);
        _del_initiator_dep(oh, mpu_oh);
        _disable_clocks(oh);
 
@@ -981,10 +1271,21 @@ static int _shutdown(struct omap_hwmod *oh)
        pr_debug("omap_hwmod: %s: disabling\n", oh->name);
 
        if (oh->class->sysc)
-               _sysc_shutdown(oh);
-       _del_initiator_dep(oh, mpu_oh);
-       /* XXX what about the other system initiators here? DMA, tesla, d2d */
-       _disable_clocks(oh);
+               _shutdown_sysc(oh);
+
+       /*
+        * If an IP contains only one HW reset line, then assert it
+        * before disabling the clocks and shutting down the IP.
+        */
+       if (oh->rst_lines_cnt == 1)
+               _assert_hardreset(oh, oh->rst_lines[0].name);
+
+       /* clocks and deps are already disabled in idle */
+       if (oh->_state == _HWMOD_STATE_ENABLED) {
+               _del_initiator_dep(oh, mpu_oh);
+               /* XXX what about the other system initiators here? dma, dsp */
+               _disable_clocks(oh);
+       }
        /* XXX Should this code also force-disable the optional clocks? */
 
        /* XXX mux any associated balls to safe mode */
@@ -1000,11 +1301,10 @@ static int _shutdown(struct omap_hwmod *oh)
  * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1
  *
  * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register.  Must be called with omap_hwmod_mutex held.
- * @skip_setup_idle is intended to be used on a system that will not
- * call omap_hwmod_enable() to enable devices (e.g., a system without
- * PM runtime).  Returns -EINVAL if the hwmod is in the wrong state or
- * returns 0.
+ * OCP_SYSCONFIG register.  @skip_setup_idle is intended to be used on
+ * a system that will not call omap_hwmod_enable() to enable devices
+ * (e.g., a system without PM runtime).  Returns -EINVAL if the hwmod
+ * is in the wrong state or returns 0.
  */
 static int _setup(struct omap_hwmod *oh, void *data)
 {
@@ -1034,8 +1334,19 @@ static int _setup(struct omap_hwmod *oh, void *data)
                }
        }
 
+       mutex_init(&oh->_mutex);
        oh->_state = _HWMOD_STATE_INITIALIZED;
 
+       /*
+        * In the case of hwmod with hardreset that should not be
+        * de-assert at boot time, we have to keep the module
+        * initialized, because we cannot enable it properly with the
+        * reset asserted. Exit without warning because that behavior is
+        * expected.
+        */
+       if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
+               return 0;
+
        r = _omap_hwmod_enable(oh);
        if (r) {
                pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
@@ -1044,16 +1355,16 @@ static int _setup(struct omap_hwmod *oh, void *data)
        }
 
        if (!(oh->flags & HWMOD_INIT_NO_RESET)) {
+               _reset(oh);
+
                /*
-                * XXX Do the OCP_SYSCONFIG bits need to be
-                * reprogrammed after a reset?  If not, then this can
-                * be removed.  If they do, then probably the
-                * _omap_hwmod_enable() function should be split to avoid the
-                * rewrite of the OCP_SYSCONFIG register.
+                * OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
+                * The _omap_hwmod_enable() function should be split to
+                * avoid the rewrite of the OCP_SYSCONFIG register.
                 */
                if (oh->class->sysc) {
                        _update_sysc_cache(oh);
-                       _sysc_enable(oh);
+                       _enable_sysc(oh);
                }
        }
 
@@ -1067,14 +1378,20 @@ static int _setup(struct omap_hwmod *oh, void *data)
 
 /* Public functions */
 
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs)
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
 {
-       return __raw_readl(oh->_mpu_rt_va + reg_offs);
+       if (oh->flags & HWMOD_16BIT_REG)
+               return __raw_readw(oh->_mpu_rt_va + reg_offs);
+       else
+               return __raw_readl(oh->_mpu_rt_va + reg_offs);
 }
 
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs)
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
 {
-       __raw_writel(v, oh->_mpu_rt_va + reg_offs);
+       if (oh->flags & HWMOD_16BIT_REG)
+               __raw_writew(v, oh->_mpu_rt_va + reg_offs);
+       else
+               __raw_writel(v, oh->_mpu_rt_va + reg_offs);
 }
 
 /**
@@ -1309,7 +1626,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
  * omap_hwmod_enable - enable an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Enable an omap_hwomd @oh.  Intended to be called by omap_device_enable().
+ * Enable an omap_hwmod @oh.  Intended to be called by omap_device_enable().
  * Returns -EINVAL on error or passes along the return value from _enable().
  */
 int omap_hwmod_enable(struct omap_hwmod *oh)
@@ -1319,9 +1636,9 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
        if (!oh)
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        r = _omap_hwmod_enable(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return r;
 }
@@ -1331,7 +1648,7 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
  * omap_hwmod_idle - idle an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Idle an omap_hwomd @oh.  Intended to be called by omap_device_idle().
+ * Idle an omap_hwmod @oh.  Intended to be called by omap_device_idle().
  * Returns -EINVAL on error or passes along the return value from _idle().
  */
 int omap_hwmod_idle(struct omap_hwmod *oh)
@@ -1339,9 +1656,9 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
        if (!oh)
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _omap_hwmod_idle(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
@@ -1350,7 +1667,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
  * omap_hwmod_shutdown - shutdown an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Shutdown an omap_hwomd @oh.  Intended to be called by
+ * Shutdown an omap_hwmod @oh.  Intended to be called by
  * omap_device_shutdown().  Returns -EINVAL on error or passes along
  * the return value from _shutdown().
  */
@@ -1359,9 +1676,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
        if (!oh)
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _shutdown(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
@@ -1374,9 +1691,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
  */
 int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
 {
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _enable_clocks(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
@@ -1389,9 +1706,9 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
  */
 int omap_hwmod_disable_clocks(struct omap_hwmod *oh)
 {
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _disable_clocks(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
@@ -1421,7 +1738,7 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
         * Forces posted writes to complete on the OCP thread handling
         * register writes
         */
-       omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+       omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
 }
 
 /**
@@ -1430,20 +1747,18 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
  *
  * Under some conditions, a driver may wish to reset the entire device.
  * Called from omap_device code.  Returns -EINVAL on error or passes along
- * the return value from _reset()/_enable().
+ * the return value from _reset().
  */
 int omap_hwmod_reset(struct omap_hwmod *oh)
 {
        int r;
 
-       if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED))
+       if (!oh)
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        r = _reset(oh);
-       if (!r)
-               r = _omap_hwmod_enable(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return r;
 }
@@ -1468,7 +1783,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
 {
        int ret, i;
 
-       ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt;
+       ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt;
 
        for (i = 0; i < oh->slaves_cnt; i++)
                ret += oh->slaves[i]->addr_cnt;
@@ -1501,10 +1816,10 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
                r++;
        }
 
-       for (i = 0; i < oh->sdma_chs_cnt; i++) {
-               (res + r)->name = (oh->sdma_chs + i)->name;
-               (res + r)->start = (oh->sdma_chs + i)->dma_ch;
-               (res + r)->end = (oh->sdma_chs + i)->dma_ch;
+       for (i = 0; i < oh->sdma_reqs_cnt; i++) {
+               (res + r)->name = (oh->sdma_reqs + i)->name;
+               (res + r)->start = (oh->sdma_reqs + i)->dma_req;
+               (res + r)->end = (oh->sdma_reqs + i)->dma_req;
                (res + r)->flags = IORESOURCE_DMA;
                r++;
        }
@@ -1644,9 +1959,9 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
            !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _enable_wakeup(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
@@ -1669,13 +1984,91 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
            !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
                return -EINVAL;
 
-       mutex_lock(&omap_hwmod_mutex);
+       mutex_lock(&oh->_mutex);
        _disable_wakeup(oh);
-       mutex_unlock(&omap_hwmod_mutex);
+       mutex_unlock(&oh->_mutex);
 
        return 0;
 }
 
+/**
+ * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.  Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _assert_hardreset().
+ */
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       int ret;
+
+       if (!oh)
+               return -EINVAL;
+
+       mutex_lock(&oh->_mutex);
+       ret = _assert_hardreset(oh, name);
+       mutex_unlock(&oh->_mutex);
+
+       return ret;
+}
+
+/**
+ * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.  Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _deassert_hardreset().
+ */
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       int ret;
+
+       if (!oh)
+               return -EINVAL;
+
+       mutex_lock(&oh->_mutex);
+       ret = _deassert_hardreset(oh, name);
+       mutex_unlock(&oh->_mutex);
+
+       return ret;
+}
+
+/**
+ * omap_hwmod_read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the current state of the hwmod @oh's reset line named @name:
+ * returns -EINVAL upon parameter error or if this operation
+ * is unsupported on the current OMAP; otherwise, passes along the return
+ * value from _read_hardreset().
+ */
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+       int ret;
+
+       if (!oh)
+               return -EINVAL;
+
+       mutex_lock(&oh->_mutex);
+       ret = _read_hardreset(oh, name);
+       mutex_unlock(&oh->_mutex);
+
+       return ret;
+}
+
+
 /**
  * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
  * @classname: struct omap_hwmod_class name to search for
index 3cc768e8bc04f41a38ae335f941eb5577009037a..adf6e3632a2b262aecf09756802e4622a439a7af 100644 (file)
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2420 hardware module integration data
@@ -33,6 +35,7 @@ static struct omap_hwmod omap2420_mpu_hwmod;
 static struct omap_hwmod omap2420_iva_hwmod;
 static struct omap_hwmod omap2420_l3_main_hwmod;
 static struct omap_hwmod omap2420_l4_core_hwmod;
+static struct omap_hwmod omap2420_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -71,6 +74,9 @@ static struct omap_hwmod omap2420_l3_main_hwmod = {
 };
 
 static struct omap_hwmod omap2420_l4_wkup_hwmod;
+static struct omap_hwmod omap2420_uart1_hwmod;
+static struct omap_hwmod omap2420_uart2_hwmod;
+static struct omap_hwmod omap2420_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
        .user   = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART1_BASE,
+               .pa_end         = OMAP2_UART1_BASE + SZ_8K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+       .master         = &omap2420_l4_core_hwmod,
+       .slave          = &omap2420_uart1_hwmod,
+       .clk            = "uart1_ick",
+       .addr           = omap2420_uart1_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2420_uart1_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2420_uart2_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART2_BASE,
+               .pa_end         = OMAP2_UART2_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+       .master         = &omap2420_l4_core_hwmod,
+       .slave          = &omap2420_uart2_hwmod,
+       .clk            = "uart2_ick",
+       .addr           = omap2420_uart2_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2420_uart2_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2420_uart3_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART3_BASE,
+               .pa_end         = OMAP2_UART3_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+       .master         = &omap2420_l4_core_hwmod,
+       .slave          = &omap2420_uart3_hwmod,
+       .clk            = "uart3_ick",
+       .addr           = omap2420_uart3_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2420_uart3_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
        &omap2420_l3_main__l4_core,
@@ -87,6 +147,9 @@ static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
        &omap2420_l4_core__l4_wkup,
+       &omap2_l4_core__uart1,
+       &omap2_l4_core__uart2,
+       &omap2_l4_core__uart3,
 };
 
 /* L4 CORE */
@@ -165,12 +228,206 @@ static struct omap_hwmod omap2420_iva_hwmod = {
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
+       {
+               .pa_start       = 0x48022000,
+               .pa_end         = 0x4802207f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
+       .master         = &omap2420_l4_wkup_hwmod,
+       .slave          = &omap2420_wd_timer2_hwmod,
+       .clk            = "mpu_wdt_ick",
+       .addr           = omap2420_wd_timer2_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap2420_wd_timer2_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_wd_timer_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_wd_timer_hwmod_class = {
+       .name = "wd_timer",
+       .sysc = &omap2420_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
+       &omap2420_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2420_wd_timer2_hwmod = {
+       .name           = "wd_timer2",
+       .class          = &omap2420_wd_timer_hwmod_class,
+       .main_clk       = "mpu_wdt_fck",
+       .prcm           = {
+               .omap2 = {
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+                       .module_offs = WKUP_MOD,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+               },
+       },
+       .slaves         = omap2420_wd_timer2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2420_wd_timer2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+       .rev_offs       = 0x50,
+       .sysc_offs      = 0x54,
+       .syss_offs      = 0x58,
+       .sysc_flags     = (SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+       .name = "uart",
+       .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+       { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
+       &omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2420_uart1_hwmod = {
+       .name           = "uart1",
+       .mpu_irqs       = uart1_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart1_mpu_irqs),
+       .sdma_reqs      = uart1_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart1_sdma_reqs),
+       .main_clk       = "uart1_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_UART1_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+               },
+       },
+       .slaves         = omap2420_uart1_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2420_uart1_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+       { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
+       &omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2420_uart2_hwmod = {
+       .name           = "uart2",
+       .mpu_irqs       = uart2_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart2_mpu_irqs),
+       .sdma_reqs      = uart2_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart2_sdma_reqs),
+       .main_clk       = "uart2_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_UART2_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+               },
+       },
+       .slaves         = omap2420_uart2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2420_uart2_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+       { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
+       &omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2420_uart3_hwmod = {
+       .name           = "uart3",
+       .mpu_irqs       = uart3_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart3_mpu_irqs),
+       .sdma_reqs      = uart3_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart3_sdma_reqs),
+       .main_clk       = "uart3_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 2,
+                       .module_bit = OMAP24XX_EN_UART3_SHIFT,
+                       .idlest_reg_id = 2,
+                       .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+               },
+       },
+       .slaves         = omap2420_uart3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2420_uart3_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
 static __initdata struct omap_hwmod *omap2420_hwmods[] = {
        &omap2420_l3_main_hwmod,
        &omap2420_l4_core_hwmod,
        &omap2420_l4_wkup_hwmod,
        &omap2420_mpu_hwmod,
        &omap2420_iva_hwmod,
+       &omap2420_wd_timer2_hwmod,
+       &omap2420_uart1_hwmod,
+       &omap2420_uart2_hwmod,
+       &omap2420_uart3_hwmod,
        NULL,
 };
 
index 4526628ed287222cba29d2f42521fbaaca052f37..12d939e456cfd4ac9cb4e74768d20af003dc1127 100644 (file)
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2430 hardware module integration data
@@ -33,6 +35,7 @@ static struct omap_hwmod omap2430_mpu_hwmod;
 static struct omap_hwmod omap2430_iva_hwmod;
 static struct omap_hwmod omap2430_l3_main_hwmod;
 static struct omap_hwmod omap2430_l4_core_hwmod;
+static struct omap_hwmod omap2430_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
@@ -71,6 +74,9 @@ static struct omap_hwmod omap2430_l3_main_hwmod = {
 };
 
 static struct omap_hwmod omap2430_l4_wkup_hwmod;
+static struct omap_hwmod omap2430_uart1_hwmod;
+static struct omap_hwmod omap2430_uart2_hwmod;
+static struct omap_hwmod omap2430_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
        .user   = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2430_uart1_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART1_BASE,
+               .pa_end         = OMAP2_UART1_BASE + SZ_8K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+       .master         = &omap2430_l4_core_hwmod,
+       .slave          = &omap2430_uart1_hwmod,
+       .clk            = "uart1_ick",
+       .addr           = omap2430_uart1_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2430_uart1_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2430_uart2_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART2_BASE,
+               .pa_end         = OMAP2_UART2_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+       .master         = &omap2430_l4_core_hwmod,
+       .slave          = &omap2430_uart2_hwmod,
+       .clk            = "uart2_ick",
+       .addr           = omap2430_uart2_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2430_uart2_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2430_uart3_addr_space[] = {
+       {
+               .pa_start       = OMAP2_UART3_BASE,
+               .pa_end         = OMAP2_UART3_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+       .master         = &omap2430_l4_core_hwmod,
+       .slave          = &omap2430_uart3_hwmod,
+       .clk            = "uart3_ick",
+       .addr           = omap2430_uart3_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap2430_uart3_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
        &omap2430_l3_main__l4_core,
@@ -104,6 +164,9 @@ static struct omap_hwmod omap2430_l4_core_hwmod = {
 /* Slave interfaces on the L4_WKUP interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
        &omap2430_l4_core__l4_wkup,
+       &omap2_l4_core__uart1,
+       &omap2_l4_core__uart2,
+       &omap2_l4_core__uart3,
 };
 
 /* Master interfaces on the L4_WKUP interconnect */
@@ -165,12 +228,206 @@ static struct omap_hwmod omap2430_iva_hwmod = {
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+       {
+               .pa_start       = 0x49016000,
+               .pa_end         = 0x4901607f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+       .master         = &omap2430_l4_wkup_hwmod,
+       .slave          = &omap2430_wd_timer2_hwmod,
+       .clk            = "mpu_wdt_ick",
+       .addr           = omap2430_wd_timer2_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap2430_wd_timer2_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_wd_timer_sysc = {
+       .rev_offs       = 0x0,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_wd_timer_hwmod_class = {
+       .name = "wd_timer",
+       .sysc = &omap2430_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
+       &omap2430_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2430_wd_timer2_hwmod = {
+       .name           = "wd_timer2",
+       .class          = &omap2430_wd_timer_hwmod_class,
+       .main_clk       = "mpu_wdt_fck",
+       .prcm           = {
+               .omap2 = {
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+                       .module_offs = WKUP_MOD,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+               },
+       },
+       .slaves         = omap2430_wd_timer2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2430_wd_timer2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+       .rev_offs       = 0x50,
+       .sysc_offs      = 0x54,
+       .syss_offs      = 0x58,
+       .sysc_flags     = (SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+       .name = "uart",
+       .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+       { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
+       &omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2430_uart1_hwmod = {
+       .name           = "uart1",
+       .mpu_irqs       = uart1_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart1_mpu_irqs),
+       .sdma_reqs      = uart1_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart1_sdma_reqs),
+       .main_clk       = "uart1_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_UART1_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+               },
+       },
+       .slaves         = omap2430_uart1_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2430_uart1_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+       { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
+       &omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2430_uart2_hwmod = {
+       .name           = "uart2",
+       .mpu_irqs       = uart2_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart2_mpu_irqs),
+       .sdma_reqs      = uart2_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart2_sdma_reqs),
+       .main_clk       = "uart2_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP24XX_EN_UART2_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+               },
+       },
+       .slaves         = omap2430_uart2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2430_uart2_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+       { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
+       &omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2430_uart3_hwmod = {
+       .name           = "uart3",
+       .mpu_irqs       = uart3_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart3_mpu_irqs),
+       .sdma_reqs      = uart3_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart3_sdma_reqs),
+       .main_clk       = "uart3_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 2,
+                       .module_bit = OMAP24XX_EN_UART3_SHIFT,
+                       .idlest_reg_id = 2,
+                       .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+               },
+       },
+       .slaves         = omap2430_uart3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap2430_uart3_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
 static __initdata struct omap_hwmod *omap2430_hwmods[] = {
        &omap2430_l3_main_hwmod,
        &omap2430_l4_core_hwmod,
        &omap2430_l4_wkup_hwmod,
        &omap2430_mpu_hwmod,
        &omap2430_iva_hwmod,
+       &omap2430_wd_timer2_hwmod,
+       &omap2430_uart1_hwmod,
+       &omap2430_uart2_hwmod,
+       &omap2430_uart3_hwmod,
        NULL,
 };
 
index 5d8eb58ba5e340f68875f28936aa38d6451b8ebd..cb97ecf0a3f6fa20762a11f0446a400e02a02ad2 100644 (file)
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
 
 /*
  * OMAP3xxx hardware module integration data
@@ -36,6 +38,7 @@ static struct omap_hwmod omap3xxx_iva_hwmod;
 static struct omap_hwmod omap3xxx_l3_main_hwmod;
 static struct omap_hwmod omap3xxx_l4_core_hwmod;
 static struct omap_hwmod omap3xxx_l4_per_hwmod;
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -82,6 +85,10 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
 };
 
 static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_uart1_hwmod;
+static struct omap_hwmod omap3xxx_uart2_hwmod;
+static struct omap_hwmod omap3xxx_uart3_hwmod;
+static struct omap_hwmod omap3xxx_uart4_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
@@ -90,6 +97,78 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
        .user   = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
+       {
+               .pa_start       = OMAP3_UART1_BASE,
+               .pa_end         = OMAP3_UART1_BASE + SZ_8K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
+       .master         = &omap3xxx_l4_core_hwmod,
+       .slave          = &omap3xxx_uart1_hwmod,
+       .clk            = "uart1_ick",
+       .addr           = omap3xxx_uart1_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap3xxx_uart1_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
+       {
+               .pa_start       = OMAP3_UART2_BASE,
+               .pa_end         = OMAP3_UART2_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
+       .master         = &omap3xxx_l4_core_hwmod,
+       .slave          = &omap3xxx_uart2_hwmod,
+       .clk            = "uart2_ick",
+       .addr           = omap3xxx_uart2_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap3xxx_uart2_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
+       {
+               .pa_start       = OMAP3_UART3_BASE,
+               .pa_end         = OMAP3_UART3_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
+       .master         = &omap3xxx_l4_per_hwmod,
+       .slave          = &omap3xxx_uart3_hwmod,
+       .clk            = "uart3_ick",
+       .addr           = omap3xxx_uart3_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap3xxx_uart3_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART4 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
+       {
+               .pa_start       = OMAP3_UART4_BASE,
+               .pa_end         = OMAP3_UART4_BASE + SZ_1K - 1,
+               .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+       },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
+       .master         = &omap3xxx_l4_per_hwmod,
+       .slave          = &omap3xxx_uart4_hwmod,
+       .clk            = "uart4_ick",
+       .addr           = omap3xxx_uart4_addr_space,
+       .addr_cnt       = ARRAY_SIZE(omap3xxx_uart4_addr_space),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
        &omap3xxx_l3_main__l4_core,
@@ -98,6 +177,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
        &omap3xxx_l4_core__l4_wkup,
+       &omap3_l4_core__uart1,
+       &omap3_l4_core__uart2,
 };
 
 /* L4 CORE */
@@ -119,6 +200,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_per_slaves[] = {
 
 /* Master interfaces on the L4_PER interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
+       &omap3_l4_per__uart3,
+       &omap3_l4_per__uart4,
 };
 
 /* L4 PER */
@@ -197,6 +280,235 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
+       {
+               .pa_start       = 0x48314000,
+               .pa_end         = 0x4831407f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
+       .master         = &omap3xxx_l4_wkup_hwmod,
+       .slave          = &omap3xxx_wd_timer2_hwmod,
+       .clk            = "wdt2_ick",
+       .addr           = omap3xxx_wd_timer2_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap3xxx_wd_timer2_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
+       .name = "wd_timer",
+       .sysc = &omap3xxx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
+       &omap3xxx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
+       .name           = "wd_timer2",
+       .class          = &omap3xxx_wd_timer_hwmod_class,
+       .main_clk       = "wdt2_fck",
+       .prcm           = {
+               .omap2 = {
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP3430_EN_WDT2_SHIFT,
+                       .module_offs = WKUP_MOD,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
+               },
+       },
+       .slaves         = omap3xxx_wd_timer2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART common */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+       .rev_offs       = 0x50,
+       .sysc_offs      = 0x54,
+       .syss_offs      = 0x58,
+       .sysc_flags     = (SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+                          SYSC_HAS_AUTOIDLE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+       .name = "uart",
+       .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+       { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
+       &omap3_l4_core__uart1,
+};
+
+static struct omap_hwmod omap3xxx_uart1_hwmod = {
+       .name           = "uart1",
+       .mpu_irqs       = uart1_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart1_mpu_irqs),
+       .sdma_reqs      = uart1_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart1_sdma_reqs),
+       .main_clk       = "uart1_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP3430_EN_UART1_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+               },
+       },
+       .slaves         = omap3xxx_uart1_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap3xxx_uart1_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+       { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
+       &omap3_l4_core__uart2,
+};
+
+static struct omap_hwmod omap3xxx_uart2_hwmod = {
+       .name           = "uart2",
+       .mpu_irqs       = uart2_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart2_mpu_irqs),
+       .sdma_reqs      = uart2_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart2_sdma_reqs),
+       .main_clk       = "uart2_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = CORE_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP3430_EN_UART2_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+               },
+       },
+       .slaves         = omap3xxx_uart2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap3xxx_uart2_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+       { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+       { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+       { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
+       &omap3_l4_per__uart3,
+};
+
+static struct omap_hwmod omap3xxx_uart3_hwmod = {
+       .name           = "uart3",
+       .mpu_irqs       = uart3_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart3_mpu_irqs),
+       .sdma_reqs      = uart3_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart3_sdma_reqs),
+       .main_clk       = "uart3_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = OMAP3430_PER_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP3430_EN_UART3_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+               },
+       },
+       .slaves         = omap3xxx_uart3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap3xxx_uart3_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART4 */
+
+static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
+       { .irq = INT_36XX_UART4_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
+       { .name = "rx", .dma_req = OMAP36XX_DMA_UART4_RX, },
+       { .name = "tx", .dma_req = OMAP36XX_DMA_UART4_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
+       &omap3_l4_per__uart4,
+};
+
+static struct omap_hwmod omap3xxx_uart4_hwmod = {
+       .name           = "uart4",
+       .mpu_irqs       = uart4_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(uart4_mpu_irqs),
+       .sdma_reqs      = uart4_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(uart4_sdma_reqs),
+       .main_clk       = "uart4_fck",
+       .prcm           = {
+               .omap2 = {
+                       .module_offs = OMAP3430_PER_MOD,
+                       .prcm_reg_id = 1,
+                       .module_bit = OMAP3630_EN_UART4_SHIFT,
+                       .idlest_reg_id = 1,
+                       .idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+               },
+       },
+       .slaves         = omap3xxx_uart4_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap3xxx_uart4_slaves),
+       .class          = &uart_class,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
        &omap3xxx_l3_main_hwmod,
        &omap3xxx_l4_core_hwmod,
@@ -204,6 +516,11 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
        &omap3xxx_l4_wkup_hwmod,
        &omap3xxx_mpu_hwmod,
        &omap3xxx_iva_hwmod,
+       &omap3xxx_wd_timer2_hwmod,
+       &omap3xxx_uart1_hwmod,
+       &omap3xxx_uart2_hwmod,
+       &omap3xxx_uart3_hwmod,
+       &omap3xxx_uart4_hwmod,
        NULL,
 };
 
@@ -211,5 +528,3 @@ int __init omap3xxx_hwmod_init(void)
 {
        return omap_hwmod_init(omap3xxx_hwmods);
 }
-
-
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
new file mode 100644 (file)
index 0000000..7274db4
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * Hardware modules present on the OMAP44xx chips
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Paul Walmsley
+ * Benoit Cousson
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can 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/io.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/cpu.h>
+
+#include "omap_hwmod_common_data.h"
+
+#include "cm.h"
+#include "prm-regbits-44xx.h"
+
+/* Base offset for all OMAP4 interrupts external to MPUSS */
+#define OMAP44XX_IRQ_GIC_START 32
+
+/* Base offset for all OMAP4 dma requests */
+#define OMAP44XX_DMA_REQ_START  1
+
+/* Backward references (IPs with Bus Master capability) */
+static struct omap_hwmod omap44xx_dmm_hwmod;
+static struct omap_hwmod omap44xx_emif_fw_hwmod;
+static struct omap_hwmod omap44xx_l3_instr_hwmod;
+static struct omap_hwmod omap44xx_l3_main_1_hwmod;
+static struct omap_hwmod omap44xx_l3_main_2_hwmod;
+static struct omap_hwmod omap44xx_l3_main_3_hwmod;
+static struct omap_hwmod omap44xx_l4_abe_hwmod;
+static struct omap_hwmod omap44xx_l4_cfg_hwmod;
+static struct omap_hwmod omap44xx_l4_per_hwmod;
+static struct omap_hwmod omap44xx_l4_wkup_hwmod;
+static struct omap_hwmod omap44xx_mpu_hwmod;
+static struct omap_hwmod omap44xx_mpu_private_hwmod;
+
+/*
+ * Interconnects omap_hwmod structures
+ * hwmods that compose the global OMAP interconnect
+ */
+
+/*
+ * 'dmm' class
+ * instance(s): dmm
+ */
+static struct omap_hwmod_class omap44xx_dmm_hwmod_class = {
+       .name = "dmm",
+};
+
+/* dmm interface data */
+/* l3_main_1 -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
+       .master         = &omap44xx_l3_main_1_hwmod,
+       .slave          = &omap44xx_dmm_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = {
+       .master         = &omap44xx_mpu_hwmod,
+       .slave          = &omap44xx_dmm_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dmm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
+       &omap44xx_l3_main_1__dmm,
+       &omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod_irq_info omap44xx_dmm_irqs[] = {
+       { .irq = 113 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod omap44xx_dmm_hwmod = {
+       .name           = "dmm",
+       .class          = &omap44xx_dmm_hwmod_class,
+       .slaves         = omap44xx_dmm_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_dmm_slaves),
+       .mpu_irqs       = omap44xx_dmm_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_dmm_irqs),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'emif_fw' class
+ * instance(s): emif_fw
+ */
+static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
+       .name = "emif_fw",
+};
+
+/* emif_fw interface data */
+/* dmm -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
+       .master         = &omap44xx_dmm_hwmod,
+       .slave          = &omap44xx_emif_fw_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__emif_fw = {
+       .master         = &omap44xx_l4_cfg_hwmod,
+       .slave          = &omap44xx_emif_fw_hwmod,
+       .clk            = "l4_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* emif_fw slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
+       &omap44xx_dmm__emif_fw,
+       &omap44xx_l4_cfg__emif_fw,
+};
+
+static struct omap_hwmod omap44xx_emif_fw_hwmod = {
+       .name           = "emif_fw",
+       .class          = &omap44xx_emif_fw_hwmod_class,
+       .slaves         = omap44xx_emif_fw_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_emif_fw_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l3' class
+ * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3
+ */
+static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
+       .name = "l3",
+};
+
+/* l3_instr interface data */
+/* l3_main_3 -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = {
+       .master         = &omap44xx_l3_main_3_hwmod,
+       .slave          = &omap44xx_l3_instr_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_instr slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
+       &omap44xx_l3_main_3__l3_instr,
+};
+
+static struct omap_hwmod omap44xx_l3_instr_hwmod = {
+       .name           = "l3_instr",
+       .class          = &omap44xx_l3_hwmod_class,
+       .slaves         = omap44xx_l3_instr_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_instr_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
+       .master         = &omap44xx_l3_main_2_hwmod,
+       .slave          = &omap44xx_l3_main_1_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
+       .master         = &omap44xx_l4_cfg_hwmod,
+       .slave          = &omap44xx_l3_main_1_hwmod,
+       .clk            = "l4_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
+       .master         = &omap44xx_mpu_hwmod,
+       .slave          = &omap44xx_l3_main_1_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
+       &omap44xx_l3_main_2__l3_main_1,
+       &omap44xx_l4_cfg__l3_main_1,
+       &omap44xx_mpu__l3_main_1,
+};
+
+static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
+       .name           = "l3_main_1",
+       .class          = &omap44xx_l3_hwmod_class,
+       .slaves         = omap44xx_l3_main_1_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_1_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 interface data */
+/* l3_main_1 -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
+       .master         = &omap44xx_l3_main_1_hwmod,
+       .slave          = &omap44xx_l3_main_2_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
+       .master         = &omap44xx_l4_cfg_hwmod,
+       .slave          = &omap44xx_l3_main_2_hwmod,
+       .clk            = "l4_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
+       &omap44xx_l3_main_1__l3_main_2,
+       &omap44xx_l4_cfg__l3_main_2,
+};
+
+static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
+       .name           = "l3_main_2",
+       .class          = &omap44xx_l3_hwmod_class,
+       .slaves         = omap44xx_l3_main_2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_3 interface data */
+/* l3_main_1 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
+       .master         = &omap44xx_l3_main_1_hwmod,
+       .slave          = &omap44xx_l3_main_3_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = {
+       .master         = &omap44xx_l3_main_2_hwmod,
+       .slave          = &omap44xx_l3_main_3_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
+       .master         = &omap44xx_l4_cfg_hwmod,
+       .slave          = &omap44xx_l3_main_3_hwmod,
+       .clk            = "l4_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
+       &omap44xx_l3_main_1__l3_main_3,
+       &omap44xx_l3_main_2__l3_main_3,
+       &omap44xx_l4_cfg__l3_main_3,
+};
+
+static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
+       .name           = "l3_main_3",
+       .class          = &omap44xx_l3_hwmod_class,
+       .slaves         = omap44xx_l3_main_3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l3_main_3_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup
+ */
+static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
+       .name = "l4",
+};
+
+/* l4_abe interface data */
+/* l3_main_1 -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
+       .master         = &omap44xx_l3_main_1_hwmod,
+       .slave          = &omap44xx_l4_abe_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
+       .master         = &omap44xx_mpu_hwmod,
+       .slave          = &omap44xx_l4_abe_hwmod,
+       .clk            = "ocp_abe_iclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_abe slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
+       &omap44xx_l3_main_1__l4_abe,
+       &omap44xx_mpu__l4_abe,
+};
+
+static struct omap_hwmod omap44xx_l4_abe_hwmod = {
+       .name           = "l4_abe",
+       .class          = &omap44xx_l4_hwmod_class,
+       .slaves         = omap44xx_l4_abe_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_abe_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_cfg interface data */
+/* l3_main_1 -> l4_cfg */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
+       .master         = &omap44xx_l3_main_1_hwmod,
+       .slave          = &omap44xx_l4_cfg_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
+       &omap44xx_l3_main_1__l4_cfg,
+};
+
+static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
+       .name           = "l4_cfg",
+       .class          = &omap44xx_l4_hwmod_class,
+       .slaves         = omap44xx_l4_cfg_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_cfg_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per interface data */
+/* l3_main_2 -> l4_per */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
+       .master         = &omap44xx_l3_main_2_hwmod,
+       .slave          = &omap44xx_l4_per_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
+       &omap44xx_l3_main_2__l4_per,
+};
+
+static struct omap_hwmod omap44xx_l4_per_hwmod = {
+       .name           = "l4_per",
+       .class          = &omap44xx_l4_hwmod_class,
+       .slaves         = omap44xx_l4_per_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_per_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_wkup interface data */
+/* l4_cfg -> l4_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
+       .master         = &omap44xx_l4_cfg_hwmod,
+       .slave          = &omap44xx_l4_wkup_hwmod,
+       .clk            = "l4_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
+       &omap44xx_l4_cfg__l4_wkup,
+};
+
+static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
+       .name           = "l4_wkup",
+       .class          = &omap44xx_l4_hwmod_class,
+       .slaves         = omap44xx_l4_wkup_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_l4_wkup_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu_bus' class
+ * instance(s): mpu_private
+ */
+static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
+       .name = "mpu_bus",
+};
+
+/* mpu_private interface data */
+/* mpu -> mpu_private */
+static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
+       .master         = &omap44xx_mpu_hwmod,
+       .slave          = &omap44xx_mpu_private_hwmod,
+       .clk            = "l3_div_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu_private slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
+       &omap44xx_mpu__mpu_private,
+};
+
+static struct omap_hwmod omap44xx_mpu_private_hwmod = {
+       .name           = "mpu_private",
+       .class          = &omap44xx_mpu_bus_hwmod_class,
+       .slaves         = omap44xx_mpu_private_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_mpu_private_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu' class
+ * mpu sub-system
+ */
+
+static struct omap_hwmod_class omap44xx_mpu_hwmod_class = {
+       .name = "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
+       { .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START },
+       { .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
+       { .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* mpu master ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
+       &omap44xx_mpu__l3_main_1,
+       &omap44xx_mpu__l4_abe,
+       &omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod omap44xx_mpu_hwmod = {
+       .name           = "mpu",
+       .class          = &omap44xx_mpu_hwmod_class,
+       .flags          = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+       .mpu_irqs       = omap44xx_mpu_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_mpu_irqs),
+       .main_clk       = "dpll_mpu_m2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL,
+               },
+       },
+       .masters        = omap44xx_mpu_masters,
+       .masters_cnt    = ARRAY_SIZE(omap44xx_mpu_masters),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+                          SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+/*
+ * 'uart' class
+ * universal asynchronous receiver/transmitter (uart)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
+       .rev_offs       = 0x0050,
+       .sysc_offs      = 0x0054,
+       .syss_offs      = 0x0058,
+       .sysc_flags     = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
+       .name = "wd_timer",
+       .sysc = &omap44xx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod omap44xx_wd_timer2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
+       { .irq = 80 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
+       {
+               .pa_start       = 0x4a314000,
+               .pa_end         = 0x4a31407f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
+       .name = "uart",
+       .sysc = &omap44xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod omap44xx_uart1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
+       { .irq = 72 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
+       { .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
+       { .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
+       {
+               .pa_start       = 0x4806a000,
+               .pa_end         = 0x4806a0ff,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l4_per -> uart1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
+       .master         = &omap44xx_l4_per_hwmod,
+       .slave          = &omap44xx_uart1_hwmod,
+       .clk            = "l4_div_ck",
+       .addr           = omap44xx_uart1_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_uart1_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
+       &omap44xx_l4_per__uart1,
+};
+
+static struct omap_hwmod omap44xx_uart1_hwmod = {
+       .name           = "uart1",
+       .class          = &omap44xx_uart_hwmod_class,
+       .mpu_irqs       = omap44xx_uart1_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_uart1_irqs),
+       .sdma_reqs      = omap44xx_uart1_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(omap44xx_uart1_sdma_reqs),
+       .main_clk       = "uart1_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_uart1_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_uart1_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart2 */
+static struct omap_hwmod omap44xx_uart2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
+       { .irq = 73 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
+       { .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
+       { .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
+       {
+               .pa_start       = 0x4806c000,
+               .pa_end         = 0x4806c0ff,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
+       .master         = &omap44xx_l4_wkup_hwmod,
+       .slave          = &omap44xx_wd_timer2_hwmod,
+       .clk            = "l4_wkup_clk_mux_ck",
+       .addr           = omap44xx_wd_timer2_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_wd_timer2_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* wd_timer2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
+       &omap44xx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
+       .name           = "wd_timer2",
+       .class          = &omap44xx_wd_timer_hwmod_class,
+       .mpu_irqs       = omap44xx_wd_timer2_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_wd_timer2_irqs),
+       .main_clk       = "wd_timer2_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_wd_timer2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_wd_timer2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* wd_timer3 */
+static struct omap_hwmod omap44xx_wd_timer3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
+       { .irq = 36 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+       {
+               .pa_start       = 0x40130000,
+               .pa_end         = 0x4013007f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l4_per -> uart2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
+       .master         = &omap44xx_l4_per_hwmod,
+       .slave          = &omap44xx_uart2_hwmod,
+       .clk            = "l4_div_ck",
+       .addr           = omap44xx_uart2_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_uart2_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
+       &omap44xx_l4_per__uart2,
+};
+
+static struct omap_hwmod omap44xx_uart2_hwmod = {
+       .name           = "uart2",
+       .class          = &omap44xx_uart_hwmod_class,
+       .mpu_irqs       = omap44xx_uart2_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_uart2_irqs),
+       .sdma_reqs      = omap44xx_uart2_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(omap44xx_uart2_sdma_reqs),
+       .main_clk       = "uart2_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_uart2_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_uart2_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart3 */
+static struct omap_hwmod omap44xx_uart3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
+       { .irq = 74 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
+       { .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
+       { .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
+       {
+               .pa_start       = 0x48020000,
+               .pa_end         = 0x480200ff,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l4_abe -> wd_timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+       .master         = &omap44xx_l4_abe_hwmod,
+       .slave          = &omap44xx_wd_timer3_hwmod,
+       .clk            = "ocp_abe_iclk",
+       .addr           = omap44xx_wd_timer3_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_wd_timer3_addrs),
+       .user           = OCP_USER_MPU,
+};
+
+/* l4_abe -> wd_timer3 (dma) */
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+       {
+               .pa_start       = 0x49030000,
+               .pa_end         = 0x4903007f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l4_per -> uart3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
+       .master         = &omap44xx_l4_per_hwmod,
+       .slave          = &omap44xx_uart3_hwmod,
+       .clk            = "l4_div_ck",
+       .addr           = omap44xx_uart3_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_uart3_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
+       &omap44xx_l4_per__uart3,
+};
+
+static struct omap_hwmod omap44xx_uart3_hwmod = {
+       .name           = "uart3",
+       .class          = &omap44xx_uart_hwmod_class,
+       .flags          = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+       .mpu_irqs       = omap44xx_uart3_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_uart3_irqs),
+       .sdma_reqs      = omap44xx_uart3_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(omap44xx_uart3_sdma_reqs),
+       .main_clk       = "uart3_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_uart3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_uart3_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart4 */
+static struct omap_hwmod omap44xx_uart4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
+       { .irq = 70 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
+       { .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
+       { .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
+       {
+               .pa_start       = 0x4806e000,
+               .pa_end         = 0x4806e0ff,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+       .master         = &omap44xx_l4_abe_hwmod,
+       .slave          = &omap44xx_wd_timer3_hwmod,
+       .clk            = "ocp_abe_iclk",
+       .addr           = omap44xx_wd_timer3_dma_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_wd_timer3_dma_addrs),
+       .user           = OCP_USER_SDMA,
+};
+
+/* wd_timer3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
+       &omap44xx_l4_abe__wd_timer3,
+       &omap44xx_l4_abe__wd_timer3_dma,
+};
+
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+       .name           = "wd_timer3",
+       .class          = &omap44xx_wd_timer_hwmod_class,
+       .mpu_irqs       = omap44xx_wd_timer3_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_wd_timer3_irqs),
+       .main_clk       = "wd_timer3_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_wd_timer3_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_wd_timer3_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per -> uart4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
+       .master         = &omap44xx_l4_per_hwmod,
+       .slave          = &omap44xx_uart4_hwmod,
+       .clk            = "l4_div_ck",
+       .addr           = omap44xx_uart4_addrs,
+       .addr_cnt       = ARRAY_SIZE(omap44xx_uart4_addrs),
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
+       &omap44xx_l4_per__uart4,
+};
+
+static struct omap_hwmod omap44xx_uart4_hwmod = {
+       .name           = "uart4",
+       .class          = &omap44xx_uart_hwmod_class,
+       .mpu_irqs       = omap44xx_uart4_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap44xx_uart4_irqs),
+       .sdma_reqs      = omap44xx_uart4_sdma_reqs,
+       .sdma_reqs_cnt  = ARRAY_SIZE(omap44xx_uart4_sdma_reqs),
+       .main_clk       = "uart4_fck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+               },
+       },
+       .slaves         = omap44xx_uart4_slaves,
+       .slaves_cnt     = ARRAY_SIZE(omap44xx_uart4_slaves),
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
+       /* dmm class */
+       &omap44xx_dmm_hwmod,
+       /* emif_fw class */
+       &omap44xx_emif_fw_hwmod,
+       /* l3 class */
+       &omap44xx_l3_instr_hwmod,
+       &omap44xx_l3_main_1_hwmod,
+       &omap44xx_l3_main_2_hwmod,
+       &omap44xx_l3_main_3_hwmod,
+       /* l4 class */
+       &omap44xx_l4_abe_hwmod,
+       &omap44xx_l4_cfg_hwmod,
+       &omap44xx_l4_per_hwmod,
+       &omap44xx_l4_wkup_hwmod,
+       /* mpu_bus class */
+       &omap44xx_mpu_private_hwmod,
+
+       /* mpu class */
+       &omap44xx_mpu_hwmod,
+       /* wd_timer class */
+       &omap44xx_wd_timer2_hwmod,
+       &omap44xx_wd_timer3_hwmod,
+
+       /* uart class */
+       &omap44xx_uart1_hwmod,
+       &omap44xx_uart2_hwmod,
+       &omap44xx_uart3_hwmod,
+       &omap44xx_uart4_hwmod,
+       NULL,
+};
+
+int __init omap44xx_hwmod_init(void)
+{
+       return omap_hwmod_init(omap44xx_hwmods);
+}
+
index 723b44e252fdc4ab5924a8b16d96f0645b22a2c0..5e81517a7af2040a8bff6a2e2eabc9a96e300b76 100644 (file)
 #include <plat/board.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/dmtimer.h>
 
 #include "prm.h"
 #include "cm.h"
 #include "pm.h"
 
 int omap2_pm_debug;
+u32 enable_off_mode;
+u32 sleep_while_idle;
+u32 wakeup_timer_seconds;
+u32 wakeup_timer_milliseconds;
 
 #define DUMP_PRM_MOD_REG(mod, reg)    \
        regs[reg_count].name = #mod "." #reg; \
@@ -162,7 +167,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us)
 
 static void pm_dbg_regset_store(u32 *ptr);
 
-struct dentry *pm_dbg_dir;
+static struct dentry *pm_dbg_dir;
 
 static int pm_dbg_init_done;
 
@@ -349,6 +354,23 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
        pwrdm->timer = t;
 }
 
+void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
+{
+       u32 tick_rate, cycles;
+
+       if (!seconds && !milliseconds)
+               return;
+
+       tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+       cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
+       omap_dm_timer_stop(gptimer_wakeup);
+       omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+       pr_info("PM: Resume timer in %u.%03u secs"
+               " (%d ticks at %d ticks/sec.)\n",
+               seconds, milliseconds, cycles, tick_rate);
+}
+
 static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
 {
        struct seq_file *s = (struct seq_file *)user;
@@ -494,8 +516,10 @@ int pm_dbg_regset_init(int reg_set)
 
 static int pwrdm_suspend_get(void *data, u64 *val)
 {
-       int ret;
-       ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
+       int ret = -EINVAL;
+
+       if (cpu_is_omap34xx())
+               ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
        *val = ret;
 
        if (ret >= 0)
@@ -505,7 +529,10 @@ static int pwrdm_suspend_get(void *data, u64 *val)
 
 static int pwrdm_suspend_set(void *data, u64 val)
 {
-       return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val);
+       if (cpu_is_omap34xx())
+               return omap3_pm_set_suspend_state(
+                       (struct powerdomain *)data, (int)val);
+       return -EINVAL;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
@@ -553,8 +580,10 @@ static int option_set(void *data, u64 val)
 
        *option = val;
 
-       if (option == &enable_off_mode)
-               omap3_pm_off_mode_enable(val);
+       if (option == &enable_off_mode) {
+               if (cpu_is_omap34xx())
+                       omap3_pm_off_mode_enable(val);
+       }
 
        return 0;
 }
@@ -609,6 +638,9 @@ static int __init pm_dbg_init(void)
                                   &sleep_while_idle, &pm_dbg_option_fops);
        (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
                                   &wakeup_timer_seconds, &pm_dbg_option_fops);
+       (void) debugfs_create_file("wakeup_timer_milliseconds",
+                       S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
+                       &pm_dbg_option_fops);
        pm_dbg_init_done = 1;
 
        return 0;
index 68f9f2e958917290f5814b7b186c33135d2ec2c4..59ca03b0e691c4dda171d68ffc30fce327352dbd 100644 (file)
 #include <plat/omap_device.h>
 #include <plat/common.h>
 
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
+
 static struct omap_device_pm_latency *pm_lats;
 
 static struct device *mpu_dev;
-static struct device *dsp_dev;
+static struct device *iva_dev;
 static struct device *l3_dev;
+static struct device *dsp_dev;
 
 struct device *omap2_get_mpuss_device(void)
 {
@@ -30,10 +34,10 @@ struct device *omap2_get_mpuss_device(void)
        return mpu_dev;
 }
 
-struct device *omap2_get_dsp_device(void)
+struct device *omap2_get_iva_device(void)
 {
-       WARN_ON_ONCE(!dsp_dev);
-       return dsp_dev;
+       WARN_ON_ONCE(!iva_dev);
+       return iva_dev;
 }
 
 struct device *omap2_get_l3_device(void)
@@ -42,6 +46,13 @@ struct device *omap2_get_l3_device(void)
        return l3_dev;
 }
 
+struct device *omap4_get_dsp_device(void)
+{
+       WARN_ON_ONCE(!dsp_dev);
+       return dsp_dev;
+}
+EXPORT_SYMBOL(omap4_get_dsp_device);
+
 /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
 static int _init_omap_device(char *name, struct device **new_dev)
 {
@@ -69,8 +80,60 @@ static int _init_omap_device(char *name, struct device **new_dev)
 static void omap2_init_processor_devices(void)
 {
        _init_omap_device("mpu", &mpu_dev);
-       _init_omap_device("iva", &dsp_dev);
-       _init_omap_device("l3_main", &l3_dev);
+       _init_omap_device("iva", &iva_dev);
+       if (cpu_is_omap44xx()) {
+               _init_omap_device("l3_main_1", &l3_dev);
+               _init_omap_device("dsp", &dsp_dev);
+       } else {
+               _init_omap_device("l3_main", &l3_dev);
+       }
+}
+
+/*
+ * This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+       u32 cur_state;
+       int sleep_switch = 0;
+       int ret = 0;
+
+       if (pwrdm == NULL || IS_ERR(pwrdm))
+               return -EINVAL;
+
+       while (!(pwrdm->pwrsts & (1 << state))) {
+               if (state == PWRDM_POWER_OFF)
+                       return ret;
+               state--;
+       }
+
+       cur_state = pwrdm_read_next_pwrst(pwrdm);
+       if (cur_state == state)
+               return ret;
+
+       if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+               omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+               sleep_switch = 1;
+               pwrdm_wait_transition(pwrdm);
+       }
+
+       ret = pwrdm_set_next_pwrst(pwrdm, state);
+       if (ret) {
+               printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+                      pwrdm->name);
+               goto err;
+       }
+
+       if (sleep_switch) {
+               omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+               pwrdm_wait_transition(pwrdm);
+               pwrdm_state_switch(pwrdm);
+       }
+
+err:
+       return ret;
 }
 
 static int __init omap2_common_pm_init(void)
index 3de6ece23fc8b306653fde7af790926df2e05e1e..0d75bfd1fdbef77870ed8213e3376658f5fc1420 100644 (file)
 
 #include <plat/powerdomain.h>
 
-extern u32 enable_off_mode;
-extern u32 sleep_while_idle;
-
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
 extern int omap3_can_sleep(void);
-extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 
 struct cpuidle_params {
@@ -48,10 +45,16 @@ extern struct omap_dm_timer *gptimer_wakeup;
 
 #ifdef CONFIG_PM_DEBUG
 extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds);
 extern int omap2_pm_debug;
+extern u32 enable_off_mode;
+extern u32 sleep_while_idle;
 #else
 #define omap2_pm_dump(mode, resume, us)                do {} while (0);
+#define omap2_pm_wakeup_on_timer(seconds, milliseconds)        do {} while (0);
 #define omap2_pm_debug                         0
+#define enable_off_mode 0
+#define sleep_while_idle 0
 #endif
 
 #if defined(CONFIG_CPU_IDLE)
index 6aeedeacdad86b78cb9ef511a822f20d7c40cd1c..a40457d81927e256ec1f6af538acf038c7e11eb1 100644 (file)
@@ -38,7 +38,6 @@
 #include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
-#include <plat/control.h>
 #include <plat/dma.h>
 #include <plat/board.h>
 
@@ -48,6 +47,7 @@
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
 #include "pm.h"
+#include "control.h"
 
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
@@ -245,6 +245,8 @@ static int omap2_can_sleep(void)
 {
        if (omap2_fclks_active())
                return 0;
+       if (!omap_uart_can_sleep())
+               return 0;
        if (osc_ck->usecount > 1)
                return 0;
        if (omap_dma_running())
index 7b03426c72a317307db1df3931a5018443117b33..75c0cd13ad8e0e78ca9686f35d9ec18b370cb6db 100644 (file)
 #include <plat/sram.h>
 #include <plat/clockdomain.h>
 #include <plat/powerdomain.h>
-#include <plat/control.h>
 #include <plat/serial.h>
 #include <plat/sdrc.h>
 #include <plat/prcm.h>
 #include <plat/gpmc.h>
 #include <plat/dma.h>
-#include <plat/dmtimer.h>
 
 #include <asm/tlbflush.h>
 
 #include "prm.h"
 #include "pm.h"
 #include "sdrc.h"
+#include "control.h"
 
 /* Scratchpad offsets */
-#define OMAP343X_TABLE_ADDRESS_OFFSET     0x31
-#define OMAP343X_TABLE_VALUE_OFFSET       0x30
-#define OMAP343X_CONTROL_REG_VALUE_OFFSET  0x32
-
-u32 enable_off_mode;
-u32 sleep_while_idle;
-u32 wakeup_timer_seconds;
-u32 wakeup_timer_milliseconds;
+#define OMAP343X_TABLE_ADDRESS_OFFSET     0xc4
+#define OMAP343X_TABLE_VALUE_OFFSET       0xc0
+#define OMAP343X_CONTROL_REG_VALUE_OFFSET  0xc8
 
 struct power_state {
        struct powerdomain *pwrdm;
@@ -316,7 +310,7 @@ static void restore_control_register(u32 val)
 /* Function to restore the table entry that was modified for enabling MMU */
 static void restore_table_entry(void)
 {
-       u32 *scratchpad_address;
+       void __iomem *scratchpad_address;
        u32 previous_value, control_reg_value;
        u32 *address;
 
@@ -351,7 +345,6 @@ void omap_sram_idle(void)
        int core_next_state = PWRDM_POWER_ON;
        int core_prev_state, per_prev_state;
        u32 sdrc_pwr = 0;
-       int per_state_modified = 0;
 
        if (!_omap_sram_idle)
                return;
@@ -385,9 +378,9 @@ void omap_sram_idle(void)
        /* Enable IO-PAD and IO-CHAIN wakeups */
        per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
        core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
-       if (omap3_has_io_wakeup() && \
-                       (per_next_state < PWRDM_POWER_ON ||
-                       core_next_state < PWRDM_POWER_ON)) {
+       if (omap3_has_io_wakeup() &&
+           (per_next_state < PWRDM_POWER_ON ||
+            core_next_state < PWRDM_POWER_ON)) {
                prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
                omap3_enable_io_chain();
        }
@@ -395,20 +388,12 @@ void omap_sram_idle(void)
        /* PER */
        if (per_next_state < PWRDM_POWER_ON) {
                omap_uart_prepare_idle(2);
+               omap_uart_prepare_idle(3);
                omap2_gpio_prepare_for_idle(per_next_state);
-               if (per_next_state == PWRDM_POWER_OFF) {
-                       if (core_next_state == PWRDM_POWER_ON) {
-                               per_next_state = PWRDM_POWER_RET;
-                               pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
-                               per_state_modified = 1;
-                       } else
+               if (per_next_state == PWRDM_POWER_OFF)
                                omap3_per_save_context();
-               }
        }
 
-       if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
-               omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
-
        /* CORE */
        if (core_next_state < PWRDM_POWER_ON) {
                omap_uart_prepare_idle(0);
@@ -475,8 +460,7 @@ void omap_sram_idle(void)
                if (per_prev_state == PWRDM_POWER_OFF)
                        omap3_per_restore_context();
                omap_uart_resume_idle(2);
-               if (per_state_modified)
-                       pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
+               omap_uart_resume_idle(3);
        }
 
        /* Disable IO-PAD and IO-CHAIN wakeup */
@@ -501,51 +485,6 @@ int omap3_can_sleep(void)
        return 1;
 }
 
-/* This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported. Function is assuming that clkdm doesn't have
- * hw_sup mode enabled. */
-int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
-{
-       u32 cur_state;
-       int sleep_switch = 0;
-       int ret = 0;
-
-       if (pwrdm == NULL || IS_ERR(pwrdm))
-               return -EINVAL;
-
-       while (!(pwrdm->pwrsts & (1 << state))) {
-               if (state == PWRDM_POWER_OFF)
-                       return ret;
-               state--;
-       }
-
-       cur_state = pwrdm_read_next_pwrst(pwrdm);
-       if (cur_state == state)
-               return ret;
-
-       if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
-               omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
-               sleep_switch = 1;
-               pwrdm_wait_transition(pwrdm);
-       }
-
-       ret = pwrdm_set_next_pwrst(pwrdm, state);
-       if (ret) {
-               printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
-                      pwrdm->name);
-               goto err;
-       }
-
-       if (sleep_switch) {
-               omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
-               pwrdm_wait_transition(pwrdm);
-               pwrdm_state_switch(pwrdm);
-       }
-
-err:
-       return ret;
-}
-
 static void omap3_pm_idle(void)
 {
        local_irq_disable();
@@ -567,23 +506,6 @@ out:
 #ifdef CONFIG_SUSPEND
 static suspend_state_t suspend_state;
 
-static void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
-{
-       u32 tick_rate, cycles;
-
-       if (!seconds && !milliseconds)
-               return;
-
-       tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
-       cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
-       omap_dm_timer_stop(gptimer_wakeup);
-       omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
-
-       pr_info("PM: Resume timer in %u.%03u secs"
-               " (%d ticks at %d ticks/sec.)\n",
-               seconds, milliseconds, cycles, tick_rate);
-}
-
 static int omap3_pm_prepare(void)
 {
        disable_hlt();
@@ -604,7 +526,7 @@ static int omap3_pm_suspend(void)
                pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
        /* Set ones wanted by suspend */
        list_for_each_entry(pwrst, &pwrst_list, node) {
-               if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+               if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
                        goto restore;
                if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
                        goto restore;
@@ -625,7 +547,7 @@ restore:
                               pwrst->pwrdm->name, pwrst->next_state);
                        ret = -1;
                }
-               set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+               omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
        }
        if (ret)
                printk(KERN_ERR "Could not enter target state in pm_suspend\n");
@@ -756,6 +678,14 @@ static void __init omap3_d2d_idle(void)
 
 static void __init prcm_setup_regs(void)
 {
+       u32 omap3630_auto_uart4_mask = cpu_is_omap3630() ?
+                                       OMAP3630_AUTO_UART4_MASK : 0;
+       u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
+                                       OMAP3630_EN_UART4_MASK : 0;
+       u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
+                                       OMAP3630_GRPSEL_UART4_MASK : 0;
+
+
        /* XXX Reset all wkdeps. This should be done when initializing
         * powerdomains */
        prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
@@ -842,6 +772,7 @@ static void __init prcm_setup_regs(void)
                CM_AUTOIDLE);
 
        cm_write_mod_reg(
+               omap3630_auto_uart4_mask |
                OMAP3430_AUTO_GPIO6_MASK |
                OMAP3430_AUTO_GPIO5_MASK |
                OMAP3430_AUTO_GPIO4_MASK |
@@ -918,14 +849,16 @@ static void __init prcm_setup_regs(void)
                                OMAP3430_DSS_MOD, PM_WKEN);
 
        /* Enable wakeups in PER */
-       prm_write_mod_reg(OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
+       prm_write_mod_reg(omap3630_en_uart4_mask |
+                         OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
                          OMAP3430_EN_GPIO4_MASK | OMAP3430_EN_GPIO5_MASK |
                          OMAP3430_EN_GPIO6_MASK | OMAP3430_EN_UART3_MASK |
                          OMAP3430_EN_MCBSP2_MASK | OMAP3430_EN_MCBSP3_MASK |
                          OMAP3430_EN_MCBSP4_MASK,
                          OMAP3430_PER_MOD, PM_WKEN);
        /* and allow them to wake up MPU */
-       prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2_MASK |
+       prm_write_mod_reg(omap3630_grpsel_uart4_mask |
+                         OMAP3430_GRPSEL_GPIO2_MASK |
                          OMAP3430_GRPSEL_GPIO3_MASK |
                          OMAP3430_GRPSEL_GPIO4_MASK |
                          OMAP3430_GRPSEL_GPIO5_MASK |
@@ -974,7 +907,7 @@ void omap3_pm_off_mode_enable(int enable)
 
        list_for_each_entry(pwrst, &pwrst_list, node) {
                pwrst->next_state = state;
-               set_pwrdm_state(pwrst->pwrdm, state);
+               omap_set_pwrdm_state(pwrst->pwrdm, state);
        }
 }
 
@@ -1019,7 +952,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
        if (pwrdm_has_hdwr_sar(pwrdm))
                pwrdm_enable_hdwr_sar(pwrdm);
 
-       return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+       return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
 }
 
 /*
@@ -1029,9 +962,6 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
  */
 static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
 {
-       clkdm_clear_all_wkdeps(clkdm);
-       clkdm_clear_all_sleepdeps(clkdm);
-
        if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
                omap2_clkdm_allow_idle(clkdm);
        else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c
new file mode 100644 (file)
index 0000000..784989f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Runtime PM support code for OMAP
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+int omap_pm_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int r, ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       ret = pm_generic_runtime_suspend(dev);
+
+       if (!ret && dev->parent == &omap_device_parent) {
+               r = omap_device_idle(pdev);
+               WARN_ON(r);
+       }
+
+       return ret;
+};
+
+int omap_pm_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int r;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (dev->parent == &omap_device_parent) {
+               r = omap_device_enable(pdev);
+               WARN_ON(r);
+       }
+
+       return pm_generic_runtime_resume(dev);
+};
+#else
+#define omap_pm_runtime_suspend NULL
+#define omap_pm_runtime_resume NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static int __init omap_pm_runtime_init(void)
+{
+       const struct dev_pm_ops *pm;
+       struct dev_pm_ops *omap_pm;
+
+       pm = platform_bus_get_pm_ops();
+       if (!pm) {
+               pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+       if (!omap_pm) {
+               pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       omap_pm->runtime_suspend = omap_pm_runtime_suspend;
+       omap_pm->runtime_resume = omap_pm_runtime_resume;
+
+       platform_bus_set_pm_ops(omap_pm);
+
+       return 0;
+}
+core_initcall(omap_pm_runtime_init);
index c7219513472aee81da1bb127cc8bd6806a8b4dcd..9c01b55d6102d58ff447870913ef3b28edd25954 100644 (file)
@@ -98,7 +98,7 @@ static struct powerdomain dss_44xx_pwrdm = {
        .prcm_offs        = OMAP4430_PRM_DSS_MOD,
        .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
        .pwrsts           = PWRSTS_OFF_RET_ON,
-       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .pwrsts_logic_ret = PWRSTS_OFF,
        .banks            = 1,
        .pwrsts_mem_ret = {
                [0] = PWRDM_POWER_OFF,  /* dss_mem */
index 995b7edbf18de4021bfde8da349c6c9158048687..298a22a754e20a56e428aeaed051cdd7b2b923f7 100644 (file)
 #define OMAP3430_EN_MPU_SHIFT                          1
 
 /* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER shared bits */
+
+#define OMAP3630_EN_UART4_MASK                         (1 << 18)
+#define OMAP3630_EN_UART4_SHIFT                                18
 #define OMAP3430_EN_GPIO6_MASK                         (1 << 17)
 #define OMAP3430_EN_GPIO6_SHIFT                                17
 #define OMAP3430_EN_GPIO5_MASK                         (1 << 16)
 #define OMAP3430_EN_MCBSP2_SHIFT                       0
 
 /* CM_IDLEST_PER, PM_WKST_PER shared bits */
+#define OMAP3630_ST_UART4_SHIFT                                18
+#define OMAP3630_ST_UART4_MASK                         (1 << 18)
 #define OMAP3430_ST_GPIO6_SHIFT                                17
 #define OMAP3430_ST_GPIO6_MASK                         (1 << 17)
 #define OMAP3430_ST_GPIO5_SHIFT                                16
index c20137497c92fe3f88bcb16b1d9fa72b1b8013f0..a51846e3a6faac854d0d9a7c692123a12e9184f4 100644 (file)
 #include <plat/common.h>
 #include <plat/prcm.h>
 #include <plat/irqs.h>
-#include <plat/control.h>
 
 #include "clock.h"
 #include "clock2xxx.h"
 #include "cm.h"
 #include "prm.h"
 #include "prm-regbits-24xx.h"
+#include "prm-regbits-44xx.h"
+#include "control.h"
 
 static void __iomem *prm_base;
 static void __iomem *cm_base;
@@ -118,7 +119,7 @@ struct omap3_prcm_regs {
        u32 wkup_pm_wken;
 };
 
-struct omap3_prcm_regs prcm_context;
+static struct omap3_prcm_regs prcm_context;
 
 u32 omap_prcm_get_reset_sources(void)
 {
@@ -161,8 +162,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd)
                prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
                                                 OMAP2_RM_RSTCTRL);
        if (cpu_is_omap44xx())
-               prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
-                                                OMAP4_RM_RSTCTRL);
+               prm_set_mod_reg_bits(OMAP4430_RST_GLOBAL_WARM_SW_MASK,
+                                    prcm_offs, OMAP4_RM_RSTCTRL);
 }
 
 static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg)
@@ -215,6 +216,30 @@ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
        return v;
 }
 
+/* Read a PRM register, AND it, and shift the result down to bit 0 */
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask)
+{
+       u32 v;
+
+       v = __raw_readl(reg);
+       v &= mask;
+       v >>= __ffs(mask);
+
+       return v;
+}
+
+/* Read-modify-write a register in a PRM module. Caller must lock */
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg)
+{
+       u32 v;
+
+       v = __raw_readl(reg);
+       v &= ~mask;
+       v |= bits;
+       __raw_writel(v, reg);
+
+       return v;
+}
 /* Read a register in a CM module */
 u32 cm_read_mod_reg(s16 module, u16 idx)
 {
index 7fd6023edf967a6c693a62c8d2bdc19e174266c0..9e63cb743a976a9506e0f431ca6ecd24b4c20fae 100644 (file)
 #define OMAP3430_MEMRETSTATE_MASK                      (1 << 8)
 
 /* PM_MPUGRPSEL_PER, PM_IVA2GRPSEL_PER shared bits */
+#define OMAP3630_GRPSEL_UART4_MASK                     (1 << 18)
 #define OMAP3430_GRPSEL_GPIO6_MASK                     (1 << 17)
 #define OMAP3430_GRPSEL_GPIO5_MASK                     (1 << 16)
 #define OMAP3430_GRPSEL_GPIO4_MASK                     (1 << 15)
index 597be4a2b9ffe7308100970109d45b5b0e4b6646..25b19b6101779e6fb596f4f2c02bde8cbeb828d2 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * OMAP44xx Power Management register bits
  *
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul@pwsan.com)
  * Rajendra Nayak (rnayak@ti.com)
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ABBOFF_ACT_EXPORT_SHIFT                               1
-#define OMAP4430_ABBOFF_ACT_EXPORT_MASK                                        BITFIELD(1, 1)
+#define OMAP4430_ABBOFF_ACT_EXPORT_MASK                                        (1 << 1)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ABBOFF_SLEEP_EXPORT_SHIFT                             2
-#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK                              BITFIELD(2, 2)
+#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK                              (1 << 2)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_ABB_IVA_DONE_EN_SHIFT                                 31
-#define OMAP4430_ABB_IVA_DONE_EN_MASK                                  BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_EN_MASK                                  (1 << 31)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_ABB_IVA_DONE_ST_SHIFT                                 31
-#define OMAP4430_ABB_IVA_DONE_ST_MASK                                  BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_ST_MASK                                  (1 << 31)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_ABB_MPU_DONE_EN_SHIFT                                 7
-#define OMAP4430_ABB_MPU_DONE_EN_MASK                                  BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_EN_MASK                                  (1 << 7)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_ABB_MPU_DONE_ST_SHIFT                                 7
-#define OMAP4430_ABB_MPU_DONE_ST_MASK                                  BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_ST_MASK                                  (1 << 7)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_ACTIVE_FBB_SEL_SHIFT                                  2
-#define OMAP4430_ACTIVE_FBB_SEL_MASK                                   BITFIELD(2, 2)
+#define OMAP4430_ACTIVE_FBB_SEL_MASK                                   (1 << 2)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_ACTIVE_RBB_SEL_SHIFT                                  1
-#define OMAP4430_ACTIVE_RBB_SEL_MASK                                   BITFIELD(1, 1)
+#define OMAP4430_ACTIVE_RBB_SEL_MASK                                   (1 << 1)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_AESSMEM_ONSTATE_SHIFT                                 16
-#define OMAP4430_AESSMEM_ONSTATE_MASK                                  BITFIELD(16, 17)
+#define OMAP4430_AESSMEM_ONSTATE_MASK                                  (0x3 << 16)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_AESSMEM_RETSTATE_SHIFT                                        8
-#define OMAP4430_AESSMEM_RETSTATE_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_AESSMEM_RETSTATE_MASK                                 (1 << 8)
 
 /* Used by PM_ABE_PWRSTST */
 #define OMAP4430_AESSMEM_STATEST_SHIFT                                 4
-#define OMAP4430_AESSMEM_STATEST_MASK                                  BITFIELD(4, 5)
+#define OMAP4430_AESSMEM_STATEST_MASK                                  (0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_AIPOFF_SHIFT                                          8
-#define OMAP4430_AIPOFF_MASK                                           BITFIELD(8, 8)
+#define OMAP4430_AIPOFF_MASK                                           (1 << 8)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT                            0
-#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK                             BITFIELD(0, 1)
+#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK                             (0x3 << 0)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT                             4
-#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK                              BITFIELD(4, 5)
+#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK                              (0x3 << 4)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT                             2
-#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK                              BITFIELD(2, 3)
+#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK                              (0x3 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_RA_ERR_SHIFT                                     25
+#define OMAP4430_BYPS_RA_ERR_MASK                                      (1 << 25)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_SA_ERR_SHIFT                                     24
+#define OMAP4430_BYPS_SA_ERR_MASK                                      (1 << 24)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_TIMEOUT_ERR_SHIFT                                        26
+#define OMAP4430_BYPS_TIMEOUT_ERR_MASK                                 (1 << 26)
+
+/* Used by PRM_RSTST */
+#define OMAP4430_C2C_RST_SHIFT                                         10
+#define OMAP4430_C2C_RST_MASK                                          (1 << 10)
 
 /* Used by PM_CAM_PWRSTCTRL */
 #define OMAP4430_CAM_MEM_ONSTATE_SHIFT                                 16
-#define OMAP4430_CAM_MEM_ONSTATE_MASK                                  BITFIELD(16, 17)
+#define OMAP4430_CAM_MEM_ONSTATE_MASK                                  (0x3 << 16)
 
 /* Used by PM_CAM_PWRSTST */
 #define OMAP4430_CAM_MEM_STATEST_SHIFT                                 4
-#define OMAP4430_CAM_MEM_STATEST_MASK                                  BITFIELD(4, 5)
+#define OMAP4430_CAM_MEM_STATEST_MASK                                  (0x3 << 4)
 
 /* Used by PRM_CLKREQCTRL */
 #define OMAP4430_CLKREQ_COND_SHIFT                                     0
-#define OMAP4430_CLKREQ_COND_MASK                                      BITFIELD(0, 2)
+#define OMAP4430_CLKREQ_COND_MASK                                      (0x7 << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_CORE_L_SHIFT                                        0
-#define OMAP4430_CMDRA_VDD_CORE_L_MASK                                 BITFIELD(0, 7)
+#define OMAP4430_CMDRA_VDD_CORE_L_MASK                                 (0xff << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_IVA_L_SHIFT                                 8
-#define OMAP4430_CMDRA_VDD_IVA_L_MASK                                  BITFIELD(8, 15)
+#define OMAP4430_CMDRA_VDD_IVA_L_MASK                                  (0xff << 8)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_MPU_L_SHIFT                                 16
-#define OMAP4430_CMDRA_VDD_MPU_L_MASK                                  BITFIELD(16, 23)
+#define OMAP4430_CMDRA_VDD_MPU_L_MASK                                  (0xff << 16)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_CORE_L_SHIFT                                  4
-#define OMAP4430_CMD_VDD_CORE_L_MASK                                   BITFIELD(4, 4)
+#define OMAP4430_CMD_VDD_CORE_L_MASK                                   (1 << 4)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_IVA_L_SHIFT                                   12
-#define OMAP4430_CMD_VDD_IVA_L_MASK                                    BITFIELD(12, 12)
+#define OMAP4430_CMD_VDD_IVA_L_MASK                                    (1 << 12)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_MPU_L_SHIFT                                   17
-#define OMAP4430_CMD_VDD_MPU_L_MASK                                    BITFIELD(17, 17)
+#define OMAP4430_CMD_VDD_MPU_L_MASK                                    (1 << 17)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OCMRAM_ONSTATE_SHIFT                             18
-#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK                              BITFIELD(18, 19)
+#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK                              (0x3 << 18)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OCMRAM_RETSTATE_SHIFT                            9
-#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK                             BITFIELD(9, 9)
+#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK                             (1 << 9)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_CORE_OCMRAM_STATEST_SHIFT                             6
-#define OMAP4430_CORE_OCMRAM_STATEST_MASK                              BITFIELD(6, 7)
+#define OMAP4430_CORE_OCMRAM_STATEST_MASK                              (0x3 << 6)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OTHER_BANK_ONSTATE_SHIFT                         16
-#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK                          BITFIELD(16, 17)
+#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK                          (0x3 << 16)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OTHER_BANK_RETSTATE_SHIFT                                8
-#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK                         BITFIELD(8, 8)
+#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK                         (1 << 8)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_CORE_OTHER_BANK_STATEST_SHIFT                         4
-#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK                          BITFIELD(4, 5)
+#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK                          (0x3 << 4)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_CUSTOM_SHIFT                                          6
+#define OMAP4430_CUSTOM_MASK                                           (0x3 << 6)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_DATA_SHIFT                                            16
-#define OMAP4430_DATA_MASK                                             BITFIELD(16, 23)
+#define OMAP4430_DATA_MASK                                             (0xff << 16)
 
 /* Used by PRM_DEVICE_OFF_CTRL */
 #define OMAP4430_DEVICE_OFF_ENABLE_SHIFT                               0
-#define OMAP4430_DEVICE_OFF_ENABLE_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_DEVICE_OFF_ENABLE_MASK                                        (1 << 0)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_DFILTEREN_SHIFT                                       6
-#define OMAP4430_DFILTEREN_MASK                                                BITFIELD(6, 6)
+#define OMAP4430_DFILTEREN_MASK                                                (1 << 6)
 
-/* Used by PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
+/*
+ * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
+ * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
+ */
+#define OMAP4430_DISABLE_RTA_EXPORT_SHIFT                              0
+#define OMAP4430_DISABLE_RTA_EXPORT_MASK                               (1 << 0)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
 #define OMAP4430_DPLL_ABE_RECAL_EN_SHIFT                               4
-#define OMAP4430_DPLL_ABE_RECAL_EN_MASK                                        BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_EN_MASK                                        (1 << 4)
 
-/* Used by PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_DPLL_ABE_RECAL_ST_SHIFT                               4
-#define OMAP4430_DPLL_ABE_RECAL_ST_MASK                                        BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_ST_MASK                                        (1 << 4)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_CORE_RECAL_EN_SHIFT                              0
-#define OMAP4430_DPLL_CORE_RECAL_EN_MASK                               BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_EN_MASK                               (1 << 0)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_CORE_RECAL_ST_SHIFT                              0
-#define OMAP4430_DPLL_CORE_RECAL_ST_MASK                               BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_ST_MASK                               (1 << 0)
 
 /* Used by PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_DDRPHY_RECAL_EN_SHIFT                            6
-#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK                             BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK                             (1 << 6)
 
 /* Used by PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_DDRPHY_RECAL_ST_SHIFT                            6
-#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK                             BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK                             (1 << 6)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
 #define OMAP4430_DPLL_IVA_RECAL_EN_SHIFT                               2
-#define OMAP4430_DPLL_IVA_RECAL_EN_MASK                                        BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_EN_MASK                                        (1 << 2)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_DPLL_IVA_RECAL_ST_SHIFT                               2
-#define OMAP4430_DPLL_IVA_RECAL_ST_MASK                                        BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_ST_MASK                                        (1 << 2)
 
 /* Used by PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_MPU_RECAL_EN_SHIFT                               1
-#define OMAP4430_DPLL_MPU_RECAL_EN_MASK                                        BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_EN_MASK                                        (1 << 1)
 
 /* Used by PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_MPU_RECAL_ST_SHIFT                               1
-#define OMAP4430_DPLL_MPU_RECAL_ST_MASK                                        BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_ST_MASK                                        (1 << 1)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_PER_RECAL_EN_SHIFT                               3
-#define OMAP4430_DPLL_PER_RECAL_EN_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_EN_MASK                                        (1 << 3)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_PER_RECAL_ST_SHIFT                               3
-#define OMAP4430_DPLL_PER_RECAL_ST_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_ST_MASK                                        (1 << 3)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_UNIPRO_RECAL_EN_SHIFT                            7
-#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK                             BITFIELD(7, 7)
+#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK                             (1 << 7)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_UNIPRO_RECAL_ST_SHIFT                            7
-#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK                             BITFIELD(7, 7)
-
-/* Used by PRM_IRQENABLE_MPU */
-#define OMAP4430_DPLL_USB_RECAL_EN_SHIFT                               5
-#define OMAP4430_DPLL_USB_RECAL_EN_MASK                                        BITFIELD(5, 5)
-
-/* Used by PRM_IRQSTATUS_MPU */
-#define OMAP4430_DPLL_USB_RECAL_ST_SHIFT                               5
-#define OMAP4430_DPLL_USB_RECAL_ST_MASK                                        BITFIELD(5, 5)
+#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK                             (1 << 7)
 
 /* Used by PM_DSS_PWRSTCTRL */
 #define OMAP4430_DSS_MEM_ONSTATE_SHIFT                                 16
-#define OMAP4430_DSS_MEM_ONSTATE_MASK                                  BITFIELD(16, 17)
+#define OMAP4430_DSS_MEM_ONSTATE_MASK                                  (0x3 << 16)
 
 /* Used by PM_DSS_PWRSTCTRL */
 #define OMAP4430_DSS_MEM_RETSTATE_SHIFT                                        8
-#define OMAP4430_DSS_MEM_RETSTATE_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_DSS_MEM_RETSTATE_MASK                                 (1 << 8)
 
 /* Used by PM_DSS_PWRSTST */
 #define OMAP4430_DSS_MEM_STATEST_SHIFT                                 4
-#define OMAP4430_DSS_MEM_STATEST_MASK                                  BITFIELD(4, 5)
+#define OMAP4430_DSS_MEM_STATEST_MASK                                  (0x3 << 4)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_L2RAM_ONSTATE_SHIFT                            20
-#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK                             BITFIELD(20, 21)
+#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK                             (0x3 << 20)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_L2RAM_RETSTATE_SHIFT                           10
-#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK                            BITFIELD(10, 10)
+#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK                            (1 << 10)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_DUCATI_L2RAM_STATEST_SHIFT                            8
-#define OMAP4430_DUCATI_L2RAM_STATEST_MASK                             BITFIELD(8, 9)
+#define OMAP4430_DUCATI_L2RAM_STATEST_MASK                             (0x3 << 8)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_UNICACHE_ONSTATE_SHIFT                         22
-#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK                          BITFIELD(22, 23)
+#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK                          (0x3 << 22)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_UNICACHE_RETSTATE_SHIFT                                11
-#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK                         BITFIELD(11, 11)
+#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK                         (1 << 11)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT                         10
-#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK                          BITFIELD(10, 11)
+#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK                          (0x3 << 10)
 
 /* Used by RM_MPU_RSTST */
 #define OMAP4430_EMULATION_RST_SHIFT                                   0
-#define OMAP4430_EMULATION_RST_MASK                                    BITFIELD(0, 0)
+#define OMAP4430_EMULATION_RST_MASK                                    (1 << 0)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_EMULATION_RST1ST_SHIFT                                        3
-#define OMAP4430_EMULATION_RST1ST_MASK                                 BITFIELD(3, 3)
+#define OMAP4430_EMULATION_RST1ST_MASK                                 (1 << 3)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_EMULATION_RST2ST_SHIFT                                        4
-#define OMAP4430_EMULATION_RST2ST_MASK                                 BITFIELD(4, 4)
+#define OMAP4430_EMULATION_RST2ST_MASK                                 (1 << 4)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_EMULATION_SEQ1_RST1ST_SHIFT                           3
-#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK                            BITFIELD(3, 3)
+#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK                            (1 << 3)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_EMULATION_SEQ2_RST2ST_SHIFT                           4
-#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK                            BITFIELD(4, 4)
+#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK                            (1 << 4)
 
 /* Used by PM_EMU_PWRSTCTRL */
 #define OMAP4430_EMU_BANK_ONSTATE_SHIFT                                        16
-#define OMAP4430_EMU_BANK_ONSTATE_MASK                                 BITFIELD(16, 17)
+#define OMAP4430_EMU_BANK_ONSTATE_MASK                                 (0x3 << 16)
 
 /* Used by PM_EMU_PWRSTST */
 #define OMAP4430_EMU_BANK_STATEST_SHIFT                                        4
-#define OMAP4430_EMU_BANK_STATEST_MASK                                 BITFIELD(4, 5)
-
-/*
- * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
- * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
- */
-#define OMAP4430_ENABLE_RTA_EXPORT_SHIFT                               0
-#define OMAP4430_ENABLE_RTA_EXPORT_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_EMU_BANK_STATEST_MASK                                 (0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
-#define OMAP4430_ENFUNC1_SHIFT                                         3
-#define OMAP4430_ENFUNC1_MASK                                          BITFIELD(3, 3)
+#define OMAP4430_ENFUNC1_EXPORT_SHIFT                                  3
+#define OMAP4430_ENFUNC1_EXPORT_MASK                                   (1 << 3)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
-#define OMAP4430_ENFUNC3_SHIFT                                         5
-#define OMAP4430_ENFUNC3_MASK                                          BITFIELD(5, 5)
+#define OMAP4430_ENFUNC3_EXPORT_SHIFT                                  5
+#define OMAP4430_ENFUNC3_EXPORT_MASK                                   (1 << 5)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ENFUNC4_SHIFT                                         6
-#define OMAP4430_ENFUNC4_MASK                                          BITFIELD(6, 6)
+#define OMAP4430_ENFUNC4_MASK                                          (1 << 6)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ENFUNC5_SHIFT                                         7
-#define OMAP4430_ENFUNC5_MASK                                          BITFIELD(7, 7)
+#define OMAP4430_ENFUNC5_MASK                                          (1 << 7)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_ERRORGAIN_SHIFT                                       16
-#define OMAP4430_ERRORGAIN_MASK                                                BITFIELD(16, 23)
+#define OMAP4430_ERRORGAIN_MASK                                                (0xff << 16)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_ERROROFFSET_SHIFT                                     24
-#define OMAP4430_ERROROFFSET_MASK                                      BITFIELD(24, 31)
+#define OMAP4430_ERROROFFSET_MASK                                      (0xff << 24)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_EXTERNAL_WARM_RST_SHIFT                               5
-#define OMAP4430_EXTERNAL_WARM_RST_MASK                                        BITFIELD(5, 5)
+#define OMAP4430_EXTERNAL_WARM_RST_MASK                                        (1 << 5)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_FORCEUPDATE_SHIFT                                     1
-#define OMAP4430_FORCEUPDATE_MASK                                      BITFIELD(1, 1)
+#define OMAP4430_FORCEUPDATE_MASK                                      (1 << 1)
 
 /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
 #define OMAP4430_FORCEUPDATEWAIT_SHIFT                                 8
-#define OMAP4430_FORCEUPDATEWAIT_MASK                                  BITFIELD(8, 31)
+#define OMAP4430_FORCEUPDATEWAIT_MASK                                  (0xffffff << 8)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_TESLA */
 #define OMAP4430_FORCEWKUP_EN_SHIFT                                    10
-#define OMAP4430_FORCEWKUP_EN_MASK                                     BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_EN_MASK                                     (1 << 10)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_FORCEWKUP_ST_SHIFT                                    10
-#define OMAP4430_FORCEWKUP_ST_MASK                                     BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_ST_MASK                                     (1 << 10)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_FUNC_SHIFT                                            16
+#define OMAP4430_FUNC_MASK                                             (0xfff << 16)
 
 /* Used by PM_GFX_PWRSTCTRL */
 #define OMAP4430_GFX_MEM_ONSTATE_SHIFT                                 16
-#define OMAP4430_GFX_MEM_ONSTATE_MASK                                  BITFIELD(16, 17)
+#define OMAP4430_GFX_MEM_ONSTATE_MASK                                  (0x3 << 16)
 
 /* Used by PM_GFX_PWRSTST */
 #define OMAP4430_GFX_MEM_STATEST_SHIFT                                 4
-#define OMAP4430_GFX_MEM_STATEST_MASK                                  BITFIELD(4, 5)
+#define OMAP4430_GFX_MEM_STATEST_MASK                                  (0x3 << 4)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_GLOBAL_COLD_RST_SHIFT                                 0
-#define OMAP4430_GLOBAL_COLD_RST_MASK                                  BITFIELD(0, 0)
+#define OMAP4430_GLOBAL_COLD_RST_MASK                                  (1 << 0)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT                              1
-#define OMAP4430_GLOBAL_WARM_SW_RST_MASK                               BITFIELD(1, 1)
+#define OMAP4430_GLOBAL_WARM_SW_RST_MASK                               (1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_GLOBAL_WUEN_SHIFT                                     16
-#define OMAP4430_GLOBAL_WUEN_MASK                                      BITFIELD(16, 16)
+#define OMAP4430_GLOBAL_WUEN_MASK                                      (1 << 16)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_HSMCODE_SHIFT                                         0
-#define OMAP4430_HSMCODE_MASK                                          BITFIELD(0, 2)
+#define OMAP4430_HSMCODE_MASK                                          (0x7 << 0)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_HSMODEEN_SHIFT                                                3
-#define OMAP4430_HSMODEEN_MASK                                         BITFIELD(3, 3)
+#define OMAP4430_HSMODEEN_MASK                                         (1 << 3)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_HSSCLH_SHIFT                                          16
-#define OMAP4430_HSSCLH_MASK                                           BITFIELD(16, 23)
+#define OMAP4430_HSSCLH_MASK                                           (0xff << 16)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_HSSCLL_SHIFT                                          24
-#define OMAP4430_HSSCLL_MASK                                           BITFIELD(24, 31)
+#define OMAP4430_HSSCLL_MASK                                           (0xff << 24)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_HWA_MEM_ONSTATE_SHIFT                                 16
-#define OMAP4430_HWA_MEM_ONSTATE_MASK                                  BITFIELD(16, 17)
+#define OMAP4430_HWA_MEM_ONSTATE_MASK                                  (0x3 << 16)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_HWA_MEM_RETSTATE_SHIFT                                        8
-#define OMAP4430_HWA_MEM_RETSTATE_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_HWA_MEM_RETSTATE_MASK                                 (1 << 8)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_HWA_MEM_STATEST_SHIFT                                 4
-#define OMAP4430_HWA_MEM_STATEST_MASK                                  BITFIELD(4, 5)
+#define OMAP4430_HWA_MEM_STATEST_MASK                                  (0x3 << 4)
 
 /* Used by RM_MPU_RSTST */
 #define OMAP4430_ICECRUSHER_MPU_RST_SHIFT                              1
-#define OMAP4430_ICECRUSHER_MPU_RST_MASK                               BITFIELD(1, 1)
+#define OMAP4430_ICECRUSHER_MPU_RST_MASK                               (1 << 1)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_ICECRUSHER_RST1ST_SHIFT                               5
-#define OMAP4430_ICECRUSHER_RST1ST_MASK                                        BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_RST1ST_MASK                                        (1 << 5)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_ICECRUSHER_RST2ST_SHIFT                               6
-#define OMAP4430_ICECRUSHER_RST2ST_MASK                                        BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_RST2ST_MASK                                        (1 << 6)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_ICECRUSHER_SEQ1_RST1ST_SHIFT                          5
-#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK                           BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK                           (1 << 5)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_ICECRUSHER_SEQ2_RST2ST_SHIFT                          6
-#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK                           BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK                           (1 << 6)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_ICEPICK_RST_SHIFT                                     9
-#define OMAP4430_ICEPICK_RST_MASK                                      BITFIELD(9, 9)
+#define OMAP4430_ICEPICK_RST_MASK                                      (1 << 9)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_INITVDD_SHIFT                                         2
-#define OMAP4430_INITVDD_MASK                                          BITFIELD(2, 2)
+#define OMAP4430_INITVDD_MASK                                          (1 << 2)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_INITVOLTAGE_SHIFT                                     8
-#define OMAP4430_INITVOLTAGE_MASK                                      BITFIELD(8, 15)
+#define OMAP4430_INITVOLTAGE_MASK                                      (0xff << 8)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_INTRANSITION_SHIFT                                    20
-#define OMAP4430_INTRANSITION_MASK                                     BITFIELD(20, 20)
+#define OMAP4430_INTRANSITION_MASK                                     (1 << 20)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_IO_EN_SHIFT                                           9
-#define OMAP4430_IO_EN_MASK                                            BITFIELD(9, 9)
+#define OMAP4430_IO_EN_MASK                                            (1 << 9)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_IO_ON_STATUS_SHIFT                                    5
-#define OMAP4430_IO_ON_STATUS_MASK                                     BITFIELD(5, 5)
+#define OMAP4430_IO_ON_STATUS_MASK                                     (1 << 5)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_IO_ST_SHIFT                                           9
-#define OMAP4430_IO_ST_MASK                                            BITFIELD(9, 9)
+#define OMAP4430_IO_ST_MASK                                            (1 << 9)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOCLK_OVERRIDE_SHIFT                                 0
-#define OMAP4430_ISOCLK_OVERRIDE_MASK                                  BITFIELD(0, 0)
+#define OMAP4430_ISOCLK_OVERRIDE_MASK                                  (1 << 0)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOCLK_STATUS_SHIFT                                   1
-#define OMAP4430_ISOCLK_STATUS_MASK                                    BITFIELD(1, 1)
+#define OMAP4430_ISOCLK_STATUS_MASK                                    (1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOOVR_EXTEND_SHIFT                                   4
-#define OMAP4430_ISOOVR_EXTEND_MASK                                    BITFIELD(4, 4)
+#define OMAP4430_ISOOVR_EXTEND_MASK                                    (1 << 4)
 
 /* Used by PRM_IO_COUNT */
 #define OMAP4430_ISO_2_ON_TIME_SHIFT                                   0
-#define OMAP4430_ISO_2_ON_TIME_MASK                                    BITFIELD(0, 7)
+#define OMAP4430_ISO_2_ON_TIME_MASK                                    (0xff << 0)
 
 /* Used by PM_L3INIT_PWRSTCTRL */
 #define OMAP4430_L3INIT_BANK1_ONSTATE_SHIFT                            16
-#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK                             BITFIELD(16, 17)
+#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK                             (0x3 << 16)
 
 /* Used by PM_L3INIT_PWRSTCTRL */
 #define OMAP4430_L3INIT_BANK1_RETSTATE_SHIFT                           8
-#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK                            BITFIELD(8, 8)
+#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK                            (1 << 8)
 
 /* Used by PM_L3INIT_PWRSTST */
 #define OMAP4430_L3INIT_BANK1_STATEST_SHIFT                            4
-#define OMAP4430_L3INIT_BANK1_STATEST_MASK                             BITFIELD(4, 5)
+#define OMAP4430_L3INIT_BANK1_STATEST_MASK                             (0x3 << 4)
+
+/*
+ * Used by PM_ABE_PWRSTST, PM_CORE_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
+ */
+#define OMAP4430_LASTPOWERSTATEENTERED_SHIFT                           24
+#define OMAP4430_LASTPOWERSTATEENTERED_MASK                            (0x3 << 24)
 
 /*
- * Used by PM_CORE_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL,
- * PM_MPU_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL,
- * PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_LOGICRETSTATE_SHIFT                                   2
-#define OMAP4430_LOGICRETSTATE_MASK                                    BITFIELD(2, 2)
+#define OMAP4430_LOGICRETSTATE_MASK                                    (1 << 2)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_LOGICSTATEST_SHIFT                                    2
-#define OMAP4430_LOGICSTATEST_MASK                                     BITFIELD(2, 2)
+#define OMAP4430_LOGICSTATEST_MASK                                     (1 << 2)
 
 /*
- * Used by RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT,
- * RM_WKUP_L4WKUP_CONTEXT, RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT,
- * RM_WKUP_SYNCTIMER_CONTEXT, RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT,
- * RM_WKUP_USIM_CONTEXT, RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT,
- * RM_EMU_DEBUGSS_CONTEXT, RM_D2D_SAD2D_CONTEXT, RM_D2D_SAD2D_FW_CONTEXT,
- * RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
- * RM_L3INSTR_L3_INSTR_CONTEXT, RM_L3INSTR_OCP_WP1_CONTEXT,
- * RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT, RM_L3_2_OCMC_RAM_CONTEXT,
- * RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT, RM_MEMIF_DLL_CONTEXT,
- * RM_MEMIF_DLL_H_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT,
- * RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
- * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
- * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
- * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
- * RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
+ * Used by RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
  * RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT, RM_ABE_MCBSP3_CONTEXT,
  * RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT, RM_ABE_TIMER5_CONTEXT,
  * RM_ABE_TIMER6_CONTEXT, RM_ABE_TIMER7_CONTEXT, RM_ABE_TIMER8_CONTEXT,
- * RM_ABE_WDT3_CONTEXT, RM_GFX_GFX_CONTEXT, RM_MPU_MPU_CONTEXT,
- * RM_CEFUSE_CEFUSE_CONTEXT, RM_ALWON_MDMINTC_CONTEXT,
- * RM_ALWON_SR_CORE_CONTEXT, RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT,
- * RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT, RM_L4PER_ADC_CONTEXT,
- * RM_L4PER_DMTIMER10_CONTEXT, RM_L4PER_DMTIMER11_CONTEXT,
- * RM_L4PER_DMTIMER2_CONTEXT, RM_L4PER_DMTIMER3_CONTEXT,
- * RM_L4PER_DMTIMER4_CONTEXT, RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT,
- * RM_L4PER_HDQ1W_CONTEXT, RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
- * RM_L4PER_I2C2_CONTEXT, RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT,
- * RM_L4PER_I2C5_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT,
- * RM_L4PER_MCASP3_CONTEXT, RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT,
- * RM_L4PER_MCSPI2_CONTEXT, RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT,
- * RM_L4PER_MGATE_CONTEXT, RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT,
- * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_MSPROHG_CONTEXT,
- * RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT,
- * RM_TESLA_TESLA_CONTEXT, RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT
+ * RM_ABE_WDT3_CONTEXT, RM_ALWON_MDMINTC_CONTEXT, RM_ALWON_SR_CORE_CONTEXT,
+ * RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT, RM_CAM_FDIF_CONTEXT,
+ * RM_CAM_ISS_CONTEXT, RM_CEFUSE_CEFUSE_CONTEXT, RM_D2D_SAD2D_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT,
+ * RM_DUCATI_DUCATI_CONTEXT, RM_EMU_DEBUGSS_CONTEXT, RM_GFX_GFX_CONTEXT,
+ * RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
+ * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
+ * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
+ * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
+ * RM_L3INSTR_L3_3_CONTEXT, RM_L3INSTR_L3_INSTR_CONTEXT,
+ * RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT,
+ * RM_L3_2_OCMC_RAM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT,
+ * RM_L4PER_ADC_CONTEXT, RM_L4PER_DMTIMER10_CONTEXT,
+ * RM_L4PER_DMTIMER11_CONTEXT, RM_L4PER_DMTIMER2_CONTEXT,
+ * RM_L4PER_DMTIMER3_CONTEXT, RM_L4PER_DMTIMER4_CONTEXT,
+ * RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT, RM_L4PER_HDQ1W_CONTEXT,
+ * RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT, RM_L4PER_I2C2_CONTEXT,
+ * RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT, RM_L4PER_I2C5_CONTEXT,
+ * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT, RM_L4PER_MCASP3_CONTEXT,
+ * RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT, RM_L4PER_MCSPI2_CONTEXT,
+ * RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT, RM_L4PER_MGATE_CONTEXT,
+ * RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT, RM_L4PER_MMCSD5_CONTEXT,
+ * RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT,
+ * RM_L4SEC_PKAEIP29_CONTEXT, RM_MEMIF_DLL_CONTEXT, RM_MEMIF_DLL_H_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MPU_MPU_CONTEXT, RM_TESLA_TESLA_CONTEXT,
+ * RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT, RM_WKUP_L4WKUP_CONTEXT,
+ * RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT, RM_WKUP_SYNCTIMER_CONTEXT,
+ * RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT, RM_WKUP_USIM_CONTEXT,
+ * RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT
  */
 #define OMAP4430_LOSTCONTEXT_DFF_SHIFT                                 0
-#define OMAP4430_LOSTCONTEXT_DFF_MASK                                  BITFIELD(0, 0)
+#define OMAP4430_LOSTCONTEXT_DFF_MASK                                  (1 << 0)
 
 /*
  * Used by RM_D2D_MODEM_ICR_CONTEXT, RM_D2D_SAD2D_CONTEXT,
- * RM_D2D_SAD2D_FW_CONTEXT, RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DSS_CONTEXT, RM_DUCATI_DUCATI_CONTEXT,
+ * RM_L3INIT_HSI_CONTEXT, RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT,
+ * RM_L3INIT_MMC6_CONTEXT, RM_L3INIT_USB_HOST_CONTEXT,
+ * RM_L3INIT_USB_HOST_FS_CONTEXT, RM_L3INIT_USB_OTG_CONTEXT,
+ * RM_L3INIT_USB_TLL_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
  * RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_GPMC_CONTEXT,
  * RM_L3_2_L3_2_CONTEXT, RM_L4CFG_HW_SEM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT,
- * RM_L4CFG_MAILBOX_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT,
- * RM_MEMIF_EMIF_2_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
- * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_L3INIT_HSI_CONTEXT,
- * RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT, RM_L3INIT_MMC6_CONTEXT,
- * RM_L3INIT_USB_HOST_CONTEXT, RM_L3INIT_USB_HOST_FS_CONTEXT,
- * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_USB_TLL_CONTEXT, RM_DSS_DSS_CONTEXT,
- * RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT, RM_L4PER_GPIO4_CONTEXT,
- * RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT, RM_L4PER_I2C1_CONTEXT,
- * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT, RM_L4PER_UART2_CONTEXT,
- * RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT, RM_L4SEC_AES1_CONTEXT,
- * RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT, RM_L4SEC_DES3DES_CONTEXT,
- * RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT, RM_TESLA_TESLA_CONTEXT
+ * RM_L4CFG_MAILBOX_CONTEXT, RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT,
+ * RM_L4PER_GPIO4_CONTEXT, RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT,
+ * RM_L4PER_I2C1_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT,
+ * RM_L4PER_UART2_CONTEXT, RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT,
+ * RM_L4SEC_AES1_CONTEXT, RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT,
+ * RM_L4SEC_DES3DES_CONTEXT, RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
+ * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_TESLA_TESLA_CONTEXT
  */
 #define OMAP4430_LOSTCONTEXT_RFF_SHIFT                                 1
-#define OMAP4430_LOSTCONTEXT_RFF_MASK                                  BITFIELD(1, 1)
+#define OMAP4430_LOSTCONTEXT_RFF_MASK                                  (1 << 1)
 
 /* Used by RM_ABE_AESS_CONTEXT */
 #define OMAP4430_LOSTMEM_AESSMEM_SHIFT                                 8
-#define OMAP4430_LOSTMEM_AESSMEM_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_AESSMEM_MASK                                  (1 << 8)
 
 /* Used by RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT */
 #define OMAP4430_LOSTMEM_CAM_MEM_SHIFT                                 8
-#define OMAP4430_LOSTMEM_CAM_MEM_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CAM_MEM_MASK                                  (1 << 8)
 
 /* Used by RM_L3INSTR_OCP_WP1_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_SHIFT                          8
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK                           BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK                           (1 << 8)
 
 /* Renamed from LOSTMEM_CORE_NRET_BANK Used by RM_MEMIF_DMM_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_SHIFT                      9
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK                       BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK                       (1 << 9)
 
 /* Used by RM_L3_2_OCMC_RAM_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_OCMRAM_SHIFT                             8
-#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK                              BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK                              (1 << 8)
 
 /*
  * Used by RM_D2D_MODEM_ICR_CONTEXT, RM_MEMIF_DMM_CONTEXT,
  * RM_SDMA_SDMA_CONTEXT
  */
 #define OMAP4430_LOSTMEM_CORE_OTHER_BANK_SHIFT                         8
-#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK                          BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK                          (1 << 8)
 
 /* Used by RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT */
 #define OMAP4430_LOSTMEM_DSS_MEM_SHIFT                                 8
-#define OMAP4430_LOSTMEM_DSS_MEM_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DSS_MEM_MASK                                  (1 << 8)
 
 /* Used by RM_DUCATI_DUCATI_CONTEXT */
 #define OMAP4430_LOSTMEM_DUCATI_L2RAM_SHIFT                            9
-#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK                             BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK                             (1 << 9)
 
 /* Used by RM_DUCATI_DUCATI_CONTEXT */
 #define OMAP4430_LOSTMEM_DUCATI_UNICACHE_SHIFT                         8
-#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK                          BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK                          (1 << 8)
 
 /* Used by RM_EMU_DEBUGSS_CONTEXT */
 #define OMAP4430_LOSTMEM_EMU_BANK_SHIFT                                        8
-#define OMAP4430_LOSTMEM_EMU_BANK_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_EMU_BANK_MASK                                 (1 << 8)
 
 /* Used by RM_GFX_GFX_CONTEXT */
 #define OMAP4430_LOSTMEM_GFX_MEM_SHIFT                                 8
-#define OMAP4430_LOSTMEM_GFX_MEM_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_GFX_MEM_MASK                                  (1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_HWA_MEM_SHIFT                                 10
-#define OMAP4430_LOSTMEM_HWA_MEM_MASK                                  BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_HWA_MEM_MASK                                  (1 << 10)
 
 /*
  * Used by RM_L3INIT_CCPTX_CONTEXT, RM_L3INIT_EMAC_CONTEXT,
  * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_XHPI_CONTEXT
  */
 #define OMAP4430_LOSTMEM_L3INIT_BANK1_SHIFT                            8
-#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK                             BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK                             (1 << 8)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_L1_SHIFT                                  8
-#define OMAP4430_LOSTMEM_MPU_L1_MASK                                   BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_MPU_L1_MASK                                   (1 << 8)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_L2_SHIFT                                  9
-#define OMAP4430_LOSTMEM_MPU_L2_MASK                                   BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_MPU_L2_MASK                                   (1 << 9)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_RAM_SHIFT                                 10
-#define OMAP4430_LOSTMEM_MPU_RAM_MASK                                  BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_MPU_RAM_MASK                                  (1 << 10)
 
 /*
  * Used by RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
  * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT
  */
 #define OMAP4430_LOSTMEM_NONRETAINED_BANK_SHIFT                                8
-#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK                         BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK                         (1 << 8)
 
 /*
  * Used by RM_ABE_DMIC_CONTEXT, RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT,
  * RM_ABE_MCBSP3_CONTEXT, RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT
  */
 #define OMAP4430_LOSTMEM_PERIHPMEM_SHIFT                               8
-#define OMAP4430_LOSTMEM_PERIHPMEM_MASK                                        BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_PERIHPMEM_MASK                                        (1 << 8)
 
 /*
  * Used by RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_UART1_CONTEXT,
  * RM_L4SEC_CRYPTODMA_CONTEXT
  */
 #define OMAP4430_LOSTMEM_RETAINED_BANK_SHIFT                           8
-#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK                            BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK                            (1 << 8)
 
 /* Used by RM_IVAHD_SL2_CONTEXT */
 #define OMAP4430_LOSTMEM_SL2_MEM_SHIFT                                 8
-#define OMAP4430_LOSTMEM_SL2_MEM_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_SL2_MEM_MASK                                  (1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_TCM1_MEM_SHIFT                                        8
-#define OMAP4430_LOSTMEM_TCM1_MEM_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TCM1_MEM_MASK                                 (1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_TCM2_MEM_SHIFT                                        9
-#define OMAP4430_LOSTMEM_TCM2_MEM_MASK                                 BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TCM2_MEM_MASK                                 (1 << 9)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_EDMA_SHIFT                              10
-#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK                               BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK                               (1 << 10)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_L1_SHIFT                                        8
-#define OMAP4430_LOSTMEM_TESLA_L1_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TESLA_L1_MASK                                 (1 << 8)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_L2_SHIFT                                        9
-#define OMAP4430_LOSTMEM_TESLA_L2_MASK                                 BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TESLA_L2_MASK                                 (1 << 9)
 
 /* Used by RM_WKUP_SARRAM_CONTEXT */
 #define OMAP4430_LOSTMEM_WKUP_BANK_SHIFT                               8
-#define OMAP4430_LOSTMEM_WKUP_BANK_MASK                                        BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_WKUP_BANK_MASK                                        (1 << 8)
 
 /*
- * Used by PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_L3INIT_PWRSTCTRL,
- * PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
- * PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_IVAHD_PWRSTCTRL,
+ * PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_LOWPOWERSTATECHANGE_SHIFT                             4
-#define OMAP4430_LOWPOWERSTATECHANGE_MASK                              BITFIELD(4, 4)
-
-/* Used by PM_CORE_PWRSTCTRL */
-#define OMAP4430_MEMORYCHANGE_SHIFT                                    3
-#define OMAP4430_MEMORYCHANGE_MASK                                     BITFIELD(3, 3)
+#define OMAP4430_LOWPOWERSTATECHANGE_MASK                              (1 << 4)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_READY_SHIFT                                     1
-#define OMAP4430_MODEM_READY_MASK                                      BITFIELD(1, 1)
+#define OMAP4430_MODEM_READY_MASK                                      (1 << 1)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_SHUTDOWN_IRQ_SHIFT                              9
-#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK                               BITFIELD(9, 9)
+#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK                               (1 << 9)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_SLEEP_ST_SHIFT                                  16
-#define OMAP4430_MODEM_SLEEP_ST_MASK                                   BITFIELD(16, 16)
+#define OMAP4430_MODEM_SLEEP_ST_MASK                                   (1 << 16)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_WAKE_IRQ_SHIFT                                  8
-#define OMAP4430_MODEM_WAKE_IRQ_MASK                                   BITFIELD(8, 8)
+#define OMAP4430_MODEM_WAKE_IRQ_MASK                                   (1 << 8)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L1_ONSTATE_SHIFT                                  16
-#define OMAP4430_MPU_L1_ONSTATE_MASK                                   BITFIELD(16, 17)
+#define OMAP4430_MPU_L1_ONSTATE_MASK                                   (0x3 << 16)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L1_RETSTATE_SHIFT                                 8
-#define OMAP4430_MPU_L1_RETSTATE_MASK                                  BITFIELD(8, 8)
+#define OMAP4430_MPU_L1_RETSTATE_MASK                                  (1 << 8)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_L1_STATEST_SHIFT                                  4
-#define OMAP4430_MPU_L1_STATEST_MASK                                   BITFIELD(4, 5)
+#define OMAP4430_MPU_L1_STATEST_MASK                                   (0x3 << 4)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L2_ONSTATE_SHIFT                                  18
-#define OMAP4430_MPU_L2_ONSTATE_MASK                                   BITFIELD(18, 19)
+#define OMAP4430_MPU_L2_ONSTATE_MASK                                   (0x3 << 18)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L2_RETSTATE_SHIFT                                 9
-#define OMAP4430_MPU_L2_RETSTATE_MASK                                  BITFIELD(9, 9)
+#define OMAP4430_MPU_L2_RETSTATE_MASK                                  (1 << 9)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_L2_STATEST_SHIFT                                  6
-#define OMAP4430_MPU_L2_STATEST_MASK                                   BITFIELD(6, 7)
+#define OMAP4430_MPU_L2_STATEST_MASK                                   (0x3 << 6)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_RAM_ONSTATE_SHIFT                                 20
-#define OMAP4430_MPU_RAM_ONSTATE_MASK                                  BITFIELD(20, 21)
+#define OMAP4430_MPU_RAM_ONSTATE_MASK                                  (0x3 << 20)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_RAM_RETSTATE_SHIFT                                        10
-#define OMAP4430_MPU_RAM_RETSTATE_MASK                                 BITFIELD(10, 10)
+#define OMAP4430_MPU_RAM_RETSTATE_MASK                                 (1 << 10)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_RAM_STATEST_SHIFT                                 8
-#define OMAP4430_MPU_RAM_STATEST_MASK                                  BITFIELD(8, 9)
+#define OMAP4430_MPU_RAM_STATEST_MASK                                  (0x3 << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT                           2
-#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK                            BITFIELD(2, 2)
+#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK                            (1 << 2)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_MPU_WDT_RST_SHIFT                                     3
-#define OMAP4430_MPU_WDT_RST_MASK                                      BITFIELD(3, 3)
+#define OMAP4430_MPU_WDT_RST_MASK                                      (1 << 3)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_NONRETAINED_BANK_ONSTATE_SHIFT                                18
-#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK                         BITFIELD(18, 19)
+#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK                         (0x3 << 18)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_NONRETAINED_BANK_RETSTATE_SHIFT                       9
-#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK                                BITFIELD(9, 9)
+#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK                                (1 << 9)
 
 /* Used by PM_L4PER_PWRSTST */
 #define OMAP4430_NONRETAINED_BANK_STATEST_SHIFT                                6
-#define OMAP4430_NONRETAINED_BANK_STATEST_MASK                         BITFIELD(6, 7)
+#define OMAP4430_NONRETAINED_BANK_STATEST_MASK                         (0x3 << 6)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_OCP_NRET_BANK_ONSTATE_SHIFT                           24
-#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK                            BITFIELD(24, 25)
+#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK                            (0x3 << 24)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_OCP_NRET_BANK_RETSTATE_SHIFT                          12
-#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK                           BITFIELD(12, 12)
+#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK                           (1 << 12)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_OCP_NRET_BANK_STATEST_SHIFT                           12
-#define OMAP4430_OCP_NRET_BANK_STATEST_MASK                            BITFIELD(12, 13)
+#define OMAP4430_OCP_NRET_BANK_STATEST_MASK                            (0x3 << 12)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_OFF_SHIFT                                             0
-#define OMAP4430_OFF_MASK                                              BITFIELD(0, 7)
-
-/* Used by PRM_LDO_BANDGAP_CTRL */
-#define OMAP4430_OFF_ENABLE_SHIFT                                      0
-#define OMAP4430_OFF_ENABLE_MASK                                       BITFIELD(0, 0)
+#define OMAP4430_OFF_MASK                                              (0xff << 0)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_ON_SHIFT                                              24
-#define OMAP4430_ON_MASK                                               BITFIELD(24, 31)
+#define OMAP4430_ON_MASK                                               (0xff << 24)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_ONLP_SHIFT                                            16
-#define OMAP4430_ONLP_MASK                                             BITFIELD(16, 23)
+#define OMAP4430_ONLP_MASK                                             (0xff << 16)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_OPP_CHANGE_SHIFT                                      2
-#define OMAP4430_OPP_CHANGE_MASK                                       BITFIELD(2, 2)
+#define OMAP4430_OPP_CHANGE_MASK                                       (1 << 2)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_OPP_SEL_SHIFT                                         0
-#define OMAP4430_OPP_SEL_MASK                                          BITFIELD(0, 1)
+#define OMAP4430_OPP_SEL_MASK                                          (0x3 << 0)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_PCHARGECNT_VALUE_SHIFT                                        0
-#define OMAP4430_PCHARGECNT_VALUE_MASK                                 BITFIELD(0, 5)
+#define OMAP4430_PCHARGECNT_VALUE_MASK                                 (0x3f << 0)
 
 /* Used by PRM_PSCON_COUNT */
 #define OMAP4430_PCHARGE_TIME_SHIFT                                    0
-#define OMAP4430_PCHARGE_TIME_MASK                                     BITFIELD(0, 7)
+#define OMAP4430_PCHARGE_TIME_MASK                                     (0xff << 0)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_PERIPHMEM_ONSTATE_SHIFT                               20
-#define OMAP4430_PERIPHMEM_ONSTATE_MASK                                        BITFIELD(20, 21)
+#define OMAP4430_PERIPHMEM_ONSTATE_MASK                                        (0x3 << 20)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_PERIPHMEM_RETSTATE_SHIFT                              10
-#define OMAP4430_PERIPHMEM_RETSTATE_MASK                               BITFIELD(10, 10)
+#define OMAP4430_PERIPHMEM_RETSTATE_MASK                               (1 << 10)
 
 /* Used by PM_ABE_PWRSTST */
 #define OMAP4430_PERIPHMEM_STATEST_SHIFT                               8
-#define OMAP4430_PERIPHMEM_STATEST_MASK                                        BITFIELD(8, 9)
+#define OMAP4430_PERIPHMEM_STATEST_MASK                                        (0x3 << 8)
 
 /* Used by PRM_PHASE1_CNDP */
 #define OMAP4430_PHASE1_CNDP_SHIFT                                     0
-#define OMAP4430_PHASE1_CNDP_MASK                                      BITFIELD(0, 31)
+#define OMAP4430_PHASE1_CNDP_MASK                                      (0xffffffff << 0)
 
 /* Used by PRM_PHASE2A_CNDP */
 #define OMAP4430_PHASE2A_CNDP_SHIFT                                    0
-#define OMAP4430_PHASE2A_CNDP_MASK                                     BITFIELD(0, 31)
+#define OMAP4430_PHASE2A_CNDP_MASK                                     (0xffffffff << 0)
 
 /* Used by PRM_PHASE2B_CNDP */
 #define OMAP4430_PHASE2B_CNDP_SHIFT                                    0
-#define OMAP4430_PHASE2B_CNDP_MASK                                     BITFIELD(0, 31)
+#define OMAP4430_PHASE2B_CNDP_MASK                                     (0xffffffff << 0)
 
 /* Used by PRM_PSCON_COUNT */
 #define OMAP4430_PONOUT_2_PGOODIN_TIME_SHIFT                           8
-#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK                            BITFIELD(8, 15)
+#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK                            (0xff << 8)
 
 /*
- * Used by PM_EMU_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL,
- * PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL,
- * PM_CEFUSE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
- * PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_EMU_PWRSTCTRL, PM_GFX_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_POWERSTATE_SHIFT                                      0
-#define OMAP4430_POWERSTATE_MASK                                       BITFIELD(0, 1)
+#define OMAP4430_POWERSTATE_MASK                                       (0x3 << 0)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_POWERSTATEST_SHIFT                                    0
-#define OMAP4430_POWERSTATEST_MASK                                     BITFIELD(0, 1)
+#define OMAP4430_POWERSTATEST_MASK                                     (0x3 << 0)
 
 /* Used by PRM_PWRREQCTRL */
 #define OMAP4430_PWRREQ_COND_SHIFT                                     0
-#define OMAP4430_PWRREQ_COND_MASK                                      BITFIELD(0, 1)
+#define OMAP4430_PWRREQ_COND_MASK                                      (0x3 << 0)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_CORE_L_SHIFT                                        3
-#define OMAP4430_RACEN_VDD_CORE_L_MASK                                 BITFIELD(3, 3)
+#define OMAP4430_RACEN_VDD_CORE_L_MASK                                 (1 << 3)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_IVA_L_SHIFT                                 11
-#define OMAP4430_RACEN_VDD_IVA_L_MASK                                  BITFIELD(11, 11)
+#define OMAP4430_RACEN_VDD_IVA_L_MASK                                  (1 << 11)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_MPU_L_SHIFT                                 20
-#define OMAP4430_RACEN_VDD_MPU_L_MASK                                  BITFIELD(20, 20)
+#define OMAP4430_RACEN_VDD_MPU_L_MASK                                  (1 << 20)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_CORE_L_SHIFT                                  2
-#define OMAP4430_RAC_VDD_CORE_L_MASK                                   BITFIELD(2, 2)
+#define OMAP4430_RAC_VDD_CORE_L_MASK                                   (1 << 2)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_IVA_L_SHIFT                                   10
-#define OMAP4430_RAC_VDD_IVA_L_MASK                                    BITFIELD(10, 10)
+#define OMAP4430_RAC_VDD_IVA_L_MASK                                    (1 << 10)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_MPU_L_SHIFT                                   19
-#define OMAP4430_RAC_VDD_MPU_L_MASK                                    BITFIELD(19, 19)
+#define OMAP4430_RAC_VDD_MPU_L_MASK                                    (1 << 19)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_DOWN_COUNT_SHIFT                                 16
-#define OMAP4430_RAMP_DOWN_COUNT_MASK                                  BITFIELD(16, 21)
+#define OMAP4430_RAMP_DOWN_COUNT_MASK                                  (0x3f << 16)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_DOWN_PRESCAL_SHIFT                               24
-#define OMAP4430_RAMP_DOWN_PRESCAL_MASK                                        BITFIELD(24, 25)
+#define OMAP4430_RAMP_DOWN_PRESCAL_MASK                                        (0x3 << 24)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_UP_COUNT_SHIFT                                   0
-#define OMAP4430_RAMP_UP_COUNT_MASK                                    BITFIELD(0, 5)
+#define OMAP4430_RAMP_UP_COUNT_MASK                                    (0x3f << 0)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_UP_PRESCAL_SHIFT                                 8
-#define OMAP4430_RAMP_UP_PRESCAL_MASK                                  BITFIELD(8, 9)
+#define OMAP4430_RAMP_UP_PRESCAL_MASK                                  (0x3 << 8)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_CORE_L_SHIFT                                  1
-#define OMAP4430_RAV_VDD_CORE_L_MASK                                   BITFIELD(1, 1)
+#define OMAP4430_RAV_VDD_CORE_L_MASK                                   (1 << 1)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_IVA_L_SHIFT                                   9
-#define OMAP4430_RAV_VDD_IVA_L_MASK                                    BITFIELD(9, 9)
+#define OMAP4430_RAV_VDD_IVA_L_MASK                                    (1 << 9)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_MPU_L_SHIFT                                   18
-#define OMAP4430_RAV_VDD_MPU_L_MASK                                    BITFIELD(18, 18)
+#define OMAP4430_RAV_VDD_MPU_L_MASK                                    (1 << 18)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_REGADDR_SHIFT                                         8
-#define OMAP4430_REGADDR_MASK                                          BITFIELD(8, 15)
+#define OMAP4430_REGADDR_MASK                                          (0xff << 8)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_RET_SHIFT                                             8
-#define OMAP4430_RET_MASK                                              BITFIELD(8, 15)
+#define OMAP4430_RET_MASK                                              (0xff << 8)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_RETAINED_BANK_ONSTATE_SHIFT                           16
-#define OMAP4430_RETAINED_BANK_ONSTATE_MASK                            BITFIELD(16, 17)
+#define OMAP4430_RETAINED_BANK_ONSTATE_MASK                            (0x3 << 16)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_RETAINED_BANK_RETSTATE_SHIFT                          8
-#define OMAP4430_RETAINED_BANK_RETSTATE_MASK                           BITFIELD(8, 8)
+#define OMAP4430_RETAINED_BANK_RETSTATE_MASK                           (1 << 8)
 
 /* Used by PM_L4PER_PWRSTST */
 #define OMAP4430_RETAINED_BANK_STATEST_SHIFT                           4
-#define OMAP4430_RETAINED_BANK_STATEST_MASK                            BITFIELD(4, 5)
+#define OMAP4430_RETAINED_BANK_STATEST_MASK                            (0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_RETMODE_ENABLE_SHIFT                                  0
-#define OMAP4430_RETMODE_ENABLE_MASK                                   BITFIELD(0, 0)
+#define OMAP4430_RETMODE_ENABLE_MASK                                   (1 << 0)
 
-/* Used by REVISION_PRM */
-#define OMAP4430_REV_SHIFT                                             0
-#define OMAP4430_REV_MASK                                              BITFIELD(0, 7)
-
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
 #define OMAP4430_RST1_SHIFT                                            0
-#define OMAP4430_RST1_MASK                                             BITFIELD(0, 0)
+#define OMAP4430_RST1_MASK                                             (1 << 0)
 
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
 #define OMAP4430_RST1ST_SHIFT                                          0
-#define OMAP4430_RST1ST_MASK                                           BITFIELD(0, 0)
+#define OMAP4430_RST1ST_MASK                                           (1 << 0)
 
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
 #define OMAP4430_RST2_SHIFT                                            1
-#define OMAP4430_RST2_MASK                                             BITFIELD(1, 1)
+#define OMAP4430_RST2_MASK                                             (1 << 1)
 
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
 #define OMAP4430_RST2ST_SHIFT                                          1
-#define OMAP4430_RST2ST_MASK                                           BITFIELD(1, 1)
+#define OMAP4430_RST2ST_MASK                                           (1 << 1)
 
 /* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL */
 #define OMAP4430_RST3_SHIFT                                            2
-#define OMAP4430_RST3_MASK                                             BITFIELD(2, 2)
+#define OMAP4430_RST3_MASK                                             (1 << 2)
 
 /* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST */
 #define OMAP4430_RST3ST_SHIFT                                          2
-#define OMAP4430_RST3ST_MASK                                           BITFIELD(2, 2)
+#define OMAP4430_RST3ST_MASK                                           (1 << 2)
 
 /* Used by PRM_RSTTIME */
 #define OMAP4430_RSTTIME1_SHIFT                                                0
-#define OMAP4430_RSTTIME1_MASK                                         BITFIELD(0, 9)
+#define OMAP4430_RSTTIME1_MASK                                         (0x3ff << 0)
 
 /* Used by PRM_RSTTIME */
 #define OMAP4430_RSTTIME2_SHIFT                                                10
-#define OMAP4430_RSTTIME2_MASK                                         BITFIELD(10, 14)
+#define OMAP4430_RSTTIME2_MASK                                         (0x1f << 10)
 
 /* Used by PRM_RSTCTRL */
 #define OMAP4430_RST_GLOBAL_COLD_SW_SHIFT                              1
-#define OMAP4430_RST_GLOBAL_COLD_SW_MASK                               BITFIELD(1, 1)
+#define OMAP4430_RST_GLOBAL_COLD_SW_MASK                               (1 << 1)
 
 /* Used by PRM_RSTCTRL */
 #define OMAP4430_RST_GLOBAL_WARM_SW_SHIFT                              0
-#define OMAP4430_RST_GLOBAL_WARM_SW_MASK                               BITFIELD(0, 0)
+#define OMAP4430_RST_GLOBAL_WARM_SW_MASK                               (1 << 0)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_R_RTL_SHIFT                                           11
+#define OMAP4430_R_RTL_MASK                                            (0x1f << 11)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_CORE_L_SHIFT                                   0
-#define OMAP4430_SA_VDD_CORE_L_MASK                                    BITFIELD(0, 0)
+#define OMAP4430_SA_VDD_CORE_L_MASK                                    (1 << 0)
 
 /* Renamed from SA_VDD_CORE_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_CORE_L_0_6_SHIFT                               0
-#define OMAP4430_SA_VDD_CORE_L_0_6_MASK                                        BITFIELD(0, 6)
+#define OMAP4430_SA_VDD_CORE_L_0_6_MASK                                        (0x7f << 0)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_IVA_L_SHIFT                                    8
-#define OMAP4430_SA_VDD_IVA_L_MASK                                     BITFIELD(8, 8)
+#define OMAP4430_SA_VDD_IVA_L_MASK                                     (1 << 8)
 
 /* Renamed from SA_VDD_IVA_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT                     8
-#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK                      BITFIELD(8, 14)
+#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK                      (0x7f << 8)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_MPU_L_SHIFT                                    16
-#define OMAP4430_SA_VDD_MPU_L_MASK                                     BITFIELD(16, 16)
+#define OMAP4430_SA_VDD_MPU_L_MASK                                     (1 << 16)
 
 /* Renamed from SA_VDD_MPU_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT                     16
-#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK                      BITFIELD(16, 22)
+#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK                      (0x7f << 16)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_SCHEME_SHIFT                                          30
+#define OMAP4430_SCHEME_MASK                                           (0x3 << 30)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_SCLH_SHIFT                                            0
-#define OMAP4430_SCLH_MASK                                             BITFIELD(0, 7)
+#define OMAP4430_SCLH_MASK                                             (0xff << 0)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_SCLL_SHIFT                                            8
-#define OMAP4430_SCLL_MASK                                             BITFIELD(8, 15)
+#define OMAP4430_SCLL_MASK                                             (0xff << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_SECURE_WDT_RST_SHIFT                                  4
-#define OMAP4430_SECURE_WDT_RST_MASK                                   BITFIELD(4, 4)
+#define OMAP4430_SECURE_WDT_RST_MASK                                   (1 << 4)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_SL2_MEM_ONSTATE_SHIFT                                 18
-#define OMAP4430_SL2_MEM_ONSTATE_MASK                                  BITFIELD(18, 19)
+#define OMAP4430_SL2_MEM_ONSTATE_MASK                                  (0x3 << 18)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_SL2_MEM_RETSTATE_SHIFT                                        9
-#define OMAP4430_SL2_MEM_RETSTATE_MASK                                 BITFIELD(9, 9)
+#define OMAP4430_SL2_MEM_RETSTATE_MASK                                 (1 << 9)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_SL2_MEM_STATEST_SHIFT                                 6
-#define OMAP4430_SL2_MEM_STATEST_MASK                                  BITFIELD(6, 7)
+#define OMAP4430_SL2_MEM_STATEST_MASK                                  (0x3 << 6)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_SLAVEADDR_SHIFT                                       0
-#define OMAP4430_SLAVEADDR_MASK                                                BITFIELD(0, 6)
+#define OMAP4430_SLAVEADDR_MASK                                                (0x7f << 0)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SLEEP_RBB_SEL_SHIFT                                   3
-#define OMAP4430_SLEEP_RBB_SEL_MASK                                    BITFIELD(3, 3)
+#define OMAP4430_SLEEP_RBB_SEL_MASK                                    (1 << 3)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_SLPCNT_VALUE_SHIFT                                    16
-#define OMAP4430_SLPCNT_VALUE_MASK                                     BITFIELD(16, 23)
+#define OMAP4430_SLPCNT_VALUE_MASK                                     (0xff << 16)
 
 /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
 #define OMAP4430_SMPSWAITTIMEMAX_SHIFT                                 8
-#define OMAP4430_SMPSWAITTIMEMAX_MASK                                  BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMAX_MASK                                  (0xffff << 8)
 
 /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
 #define OMAP4430_SMPSWAITTIMEMIN_SHIFT                                 8
-#define OMAP4430_SMPSWAITTIMEMIN_MASK                                  BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMIN_MASK                                  (0xffff << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_CORE_SHIFT                                        1
+#define OMAP4430_SMPS_RA_ERR_CORE_MASK                                 (1 << 1)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_IVA_SHIFT                                 9
+#define OMAP4430_SMPS_RA_ERR_IVA_MASK                                  (1 << 9)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_MPU_SHIFT                                 17
+#define OMAP4430_SMPS_RA_ERR_MPU_MASK                                  (1 << 17)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_CORE_SHIFT                                        0
+#define OMAP4430_SMPS_SA_ERR_CORE_MASK                                 (1 << 0)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_IVA_SHIFT                                 8
+#define OMAP4430_SMPS_SA_ERR_IVA_MASK                                  (1 << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_MPU_SHIFT                                 16
+#define OMAP4430_SMPS_SA_ERR_MPU_MASK                                  (1 << 16)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_SHIFT                           2
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_MASK                            (1 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_SHIFT                            10
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_MASK                             (1 << 10)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_SHIFT                            18
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_MASK                             (1 << 18)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SR2EN_SHIFT                                           0
-#define OMAP4430_SR2EN_MASK                                            BITFIELD(0, 0)
+#define OMAP4430_SR2EN_MASK                                            (1 << 0)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_SR2_IN_TRANSITION_SHIFT                               6
-#define OMAP4430_SR2_IN_TRANSITION_MASK                                        BITFIELD(6, 6)
+#define OMAP4430_SR2_IN_TRANSITION_MASK                                        (1 << 6)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_SR2_STATUS_SHIFT                                      3
-#define OMAP4430_SR2_STATUS_MASK                                       BITFIELD(3, 4)
+#define OMAP4430_SR2_STATUS_MASK                                       (0x3 << 3)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SR2_WTCNT_VALUE_SHIFT                                 8
-#define OMAP4430_SR2_WTCNT_VALUE_MASK                                  BITFIELD(8, 15)
+#define OMAP4430_SR2_WTCNT_VALUE_MASK                                  (0xff << 8)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_SRAMLDO_STATUS_SHIFT                                  8
-#define OMAP4430_SRAMLDO_STATUS_MASK                                   BITFIELD(8, 8)
+#define OMAP4430_SRAMLDO_STATUS_MASK                                   (1 << 8)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_SRAM_IN_TRANSITION_SHIFT                              9
-#define OMAP4430_SRAM_IN_TRANSITION_MASK                               BITFIELD(9, 9)
+#define OMAP4430_SRAM_IN_TRANSITION_MASK                               (1 << 9)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_SRMODEEN_SHIFT                                                4
-#define OMAP4430_SRMODEEN_MASK                                         BITFIELD(4, 4)
+#define OMAP4430_SRMODEEN_MASK                                         (1 << 4)
 
 /* Used by PRM_VOLTSETUP_WARMRESET */
 #define OMAP4430_STABLE_COUNT_SHIFT                                    0
-#define OMAP4430_STABLE_COUNT_MASK                                     BITFIELD(0, 5)
+#define OMAP4430_STABLE_COUNT_MASK                                     (0x3f << 0)
 
 /* Used by PRM_VOLTSETUP_WARMRESET */
 #define OMAP4430_STABLE_PRESCAL_SHIFT                                  8
-#define OMAP4430_STABLE_PRESCAL_MASK                                   BITFIELD(8, 9)
+#define OMAP4430_STABLE_PRESCAL_MASK                                   (0x3 << 8)
+
+/* Used by PRM_LDO_BANDGAP_SETUP */
+#define OMAP4430_STARTUP_COUNT_SHIFT                                   0
+#define OMAP4430_STARTUP_COUNT_MASK                                    (0xff << 0)
+
+/* Renamed from STARTUP_COUNT Used by PRM_SRAM_COUNT */
+#define OMAP4430_STARTUP_COUNT_24_31_SHIFT                             24
+#define OMAP4430_STARTUP_COUNT_24_31_MASK                              (0xff << 24)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM1_MEM_ONSTATE_SHIFT                                        20
-#define OMAP4430_TCM1_MEM_ONSTATE_MASK                                 BITFIELD(20, 21)
+#define OMAP4430_TCM1_MEM_ONSTATE_MASK                                 (0x3 << 20)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM1_MEM_RETSTATE_SHIFT                               10
-#define OMAP4430_TCM1_MEM_RETSTATE_MASK                                        BITFIELD(10, 10)
+#define OMAP4430_TCM1_MEM_RETSTATE_MASK                                        (1 << 10)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_TCM1_MEM_STATEST_SHIFT                                        8
-#define OMAP4430_TCM1_MEM_STATEST_MASK                                 BITFIELD(8, 9)
+#define OMAP4430_TCM1_MEM_STATEST_MASK                                 (0x3 << 8)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM2_MEM_ONSTATE_SHIFT                                        22
-#define OMAP4430_TCM2_MEM_ONSTATE_MASK                                 BITFIELD(22, 23)
+#define OMAP4430_TCM2_MEM_ONSTATE_MASK                                 (0x3 << 22)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM2_MEM_RETSTATE_SHIFT                               11
-#define OMAP4430_TCM2_MEM_RETSTATE_MASK                                        BITFIELD(11, 11)
+#define OMAP4430_TCM2_MEM_RETSTATE_MASK                                        (1 << 11)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_TCM2_MEM_STATEST_SHIFT                                        10
-#define OMAP4430_TCM2_MEM_STATEST_MASK                                 BITFIELD(10, 11)
+#define OMAP4430_TCM2_MEM_STATEST_MASK                                 (0x3 << 10)
 
 /* Used by RM_TESLA_RSTST */
 #define OMAP4430_TESLASS_EMU_RSTST_SHIFT                               2
-#define OMAP4430_TESLASS_EMU_RSTST_MASK                                        BITFIELD(2, 2)
+#define OMAP4430_TESLASS_EMU_RSTST_MASK                                        (1 << 2)
 
 /* Used by RM_TESLA_RSTST */
 #define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_SHIFT                         3
-#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK                          BITFIELD(3, 3)
+#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK                          (1 << 3)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_EDMA_ONSTATE_SHIFT                              20
-#define OMAP4430_TESLA_EDMA_ONSTATE_MASK                               BITFIELD(20, 21)
+#define OMAP4430_TESLA_EDMA_ONSTATE_MASK                               (0x3 << 20)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_EDMA_RETSTATE_SHIFT                             10
-#define OMAP4430_TESLA_EDMA_RETSTATE_MASK                              BITFIELD(10, 10)
+#define OMAP4430_TESLA_EDMA_RETSTATE_MASK                              (1 << 10)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_EDMA_STATEST_SHIFT                              8
-#define OMAP4430_TESLA_EDMA_STATEST_MASK                               BITFIELD(8, 9)
+#define OMAP4430_TESLA_EDMA_STATEST_MASK                               (0x3 << 8)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L1_ONSTATE_SHIFT                                        16
-#define OMAP4430_TESLA_L1_ONSTATE_MASK                                 BITFIELD(16, 17)
+#define OMAP4430_TESLA_L1_ONSTATE_MASK                                 (0x3 << 16)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L1_RETSTATE_SHIFT                               8
-#define OMAP4430_TESLA_L1_RETSTATE_MASK                                        BITFIELD(8, 8)
+#define OMAP4430_TESLA_L1_RETSTATE_MASK                                        (1 << 8)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_L1_STATEST_SHIFT                                        4
-#define OMAP4430_TESLA_L1_STATEST_MASK                                 BITFIELD(4, 5)
+#define OMAP4430_TESLA_L1_STATEST_MASK                                 (0x3 << 4)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L2_ONSTATE_SHIFT                                        18
-#define OMAP4430_TESLA_L2_ONSTATE_MASK                                 BITFIELD(18, 19)
+#define OMAP4430_TESLA_L2_ONSTATE_MASK                                 (0x3 << 18)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L2_RETSTATE_SHIFT                               9
-#define OMAP4430_TESLA_L2_RETSTATE_MASK                                        BITFIELD(9, 9)
+#define OMAP4430_TESLA_L2_RETSTATE_MASK                                        (1 << 9)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_L2_STATEST_SHIFT                                        6
-#define OMAP4430_TESLA_L2_STATEST_MASK                                 BITFIELD(6, 7)
+#define OMAP4430_TESLA_L2_STATEST_MASK                                 (0x3 << 6)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_TIMEOUT_SHIFT                                         0
-#define OMAP4430_TIMEOUT_MASK                                          BITFIELD(0, 15)
+#define OMAP4430_TIMEOUT_MASK                                          (0xffff << 0)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_TIMEOUTEN_SHIFT                                       3
-#define OMAP4430_TIMEOUTEN_MASK                                                BITFIELD(3, 3)
+#define OMAP4430_TIMEOUTEN_MASK                                                (1 << 3)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_TRANSITION_EN_SHIFT                                   8
-#define OMAP4430_TRANSITION_EN_MASK                                    BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_EN_MASK                                    (1 << 8)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_TRANSITION_ST_SHIFT                                   8
-#define OMAP4430_TRANSITION_ST_MASK                                    BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_ST_MASK                                    (1 << 8)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_VALID_SHIFT                                           24
-#define OMAP4430_VALID_MASK                                            BITFIELD(24, 24)
+#define OMAP4430_VALID_MASK                                            (1 << 24)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_BYPASSACK_EN_SHIFT                                 14
-#define OMAP4430_VC_BYPASSACK_EN_MASK                                  BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_EN_MASK                                  (1 << 14)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_BYPASSACK_ST_SHIFT                                 14
-#define OMAP4430_VC_BYPASSACK_ST_MASK                                  BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_ST_MASK                                  (1 << 14)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
+#define OMAP4430_VC_CORE_VPACK_EN_SHIFT                                        22
+#define OMAP4430_VC_CORE_VPACK_EN_MASK                                 (1 << 22)
+
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
+#define OMAP4430_VC_CORE_VPACK_ST_SHIFT                                        22
+#define OMAP4430_VC_CORE_VPACK_ST_MASK                                 (1 << 22)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_IVA_VPACK_EN_SHIFT                                 30
-#define OMAP4430_VC_IVA_VPACK_EN_MASK                                  BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_EN_MASK                                  (1 << 30)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_IVA_VPACK_ST_SHIFT                                 30
-#define OMAP4430_VC_IVA_VPACK_ST_MASK                                  BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_ST_MASK                                  (1 << 30)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VC_MPU_VPACK_EN_SHIFT                                 6
-#define OMAP4430_VC_MPU_VPACK_EN_MASK                                  BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_EN_MASK                                  (1 << 6)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VC_MPU_VPACK_ST_SHIFT                                 6
-#define OMAP4430_VC_MPU_VPACK_ST_MASK                                  BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_ST_MASK                                  (1 << 6)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_RAERR_EN_SHIFT                                     12
-#define OMAP4430_VC_RAERR_EN_MASK                                      BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_EN_MASK                                      (1 << 12)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_RAERR_ST_SHIFT                                     12
-#define OMAP4430_VC_RAERR_ST_MASK                                      BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_ST_MASK                                      (1 << 12)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_SAERR_EN_SHIFT                                     11
-#define OMAP4430_VC_SAERR_EN_MASK                                      BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_EN_MASK                                      (1 << 11)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_SAERR_ST_SHIFT                                     11
-#define OMAP4430_VC_SAERR_ST_MASK                                      BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_ST_MASK                                      (1 << 11)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_TOERR_EN_SHIFT                                     13
-#define OMAP4430_VC_TOERR_EN_MASK                                      BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_EN_MASK                                      (1 << 13)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_TOERR_ST_SHIFT                                     13
-#define OMAP4430_VC_TOERR_ST_MASK                                      BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_ST_MASK                                      (1 << 13)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_VDDMAX_SHIFT                                          24
-#define OMAP4430_VDDMAX_MASK                                           BITFIELD(24, 31)
+#define OMAP4430_VDDMAX_MASK                                           (0xff << 24)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_VDDMIN_SHIFT                                          16
-#define OMAP4430_VDDMIN_MASK                                           BITFIELD(16, 23)
+#define OMAP4430_VDDMIN_MASK                                           (0xff << 16)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_CORE_I2C_DISABLE_SHIFT                            12
-#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK                             BITFIELD(12, 12)
+#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK                             (1 << 12)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT                           8
-#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK                            BITFIELD(8, 8)
+#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK                            (1 << 8)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_IVA_I2C_DISABLE_SHIFT                             14
-#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK                              BITFIELD(14, 14)
+#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK                              (1 << 14)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_IVA_PRESENCE_SHIFT                                        9
-#define OMAP4430_VDD_IVA_PRESENCE_MASK                                 BITFIELD(9, 9)
+#define OMAP4430_VDD_IVA_PRESENCE_MASK                                 (1 << 9)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT                            7
-#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK                             BITFIELD(7, 7)
+#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK                             (1 << 7)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_MPU_I2C_DISABLE_SHIFT                             13
-#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK                              BITFIELD(13, 13)
+#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK                              (1 << 13)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_MPU_PRESENCE_SHIFT                                        8
-#define OMAP4430_VDD_MPU_PRESENCE_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_VDD_MPU_PRESENCE_MASK                                 (1 << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT                            6
-#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK                             BITFIELD(6, 6)
+#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK                             (1 << 6)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_CORE_SHIFT                                        4
+#define OMAP4430_VFSM_RA_ERR_CORE_MASK                                 (1 << 4)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_IVA_SHIFT                                 12
+#define OMAP4430_VFSM_RA_ERR_IVA_MASK                                  (1 << 12)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_MPU_SHIFT                                 20
+#define OMAP4430_VFSM_RA_ERR_MPU_MASK                                  (1 << 20)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_CORE_SHIFT                                        3
+#define OMAP4430_VFSM_SA_ERR_CORE_MASK                                 (1 << 3)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_IVA_SHIFT                                 11
+#define OMAP4430_VFSM_SA_ERR_IVA_MASK                                  (1 << 11)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_MPU_SHIFT                                 19
+#define OMAP4430_VFSM_SA_ERR_MPU_MASK                                  (1 << 19)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_SHIFT                           5
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_MASK                            (1 << 5)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_SHIFT                            13
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_MASK                             (1 << 13)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_SHIFT                            21
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_MASK                             (1 << 21)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_CORE_L_SHIFT                                        0
-#define OMAP4430_VOLRA_VDD_CORE_L_MASK                                 BITFIELD(0, 7)
+#define OMAP4430_VOLRA_VDD_CORE_L_MASK                                 (0xff << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_IVA_L_SHIFT                                 8
-#define OMAP4430_VOLRA_VDD_IVA_L_MASK                                  BITFIELD(8, 15)
+#define OMAP4430_VOLRA_VDD_IVA_L_MASK                                  (0xff << 8)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_MPU_L_SHIFT                                 16
-#define OMAP4430_VOLRA_VDD_MPU_L_MASK                                  BITFIELD(16, 23)
+#define OMAP4430_VOLRA_VDD_MPU_L_MASK                                  (0xff << 16)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_VPENABLE_SHIFT                                                0
-#define OMAP4430_VPENABLE_MASK                                         BITFIELD(0, 0)
+#define OMAP4430_VPENABLE_MASK                                         (1 << 0)
 
 /* Used by PRM_VP_CORE_STATUS, PRM_VP_IVA_STATUS, PRM_VP_MPU_STATUS */
 #define OMAP4430_VPINIDLE_SHIFT                                                0
-#define OMAP4430_VPINIDLE_MASK                                         BITFIELD(0, 0)
+#define OMAP4430_VPINIDLE_MASK                                         (1 << 0)
 
 /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
 #define OMAP4430_VPVOLTAGE_SHIFT                                       0
-#define OMAP4430_VPVOLTAGE_MASK                                                BITFIELD(0, 7)
+#define OMAP4430_VPVOLTAGE_MASK                                                (0xff << 0)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_EQVALUE_EN_SHIFT                              20
-#define OMAP4430_VP_CORE_EQVALUE_EN_MASK                               BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_EN_MASK                               (1 << 20)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_EQVALUE_ST_SHIFT                              20
-#define OMAP4430_VP_CORE_EQVALUE_ST_MASK                               BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_ST_MASK                               (1 << 20)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_MAXVDD_EN_SHIFT                               18
-#define OMAP4430_VP_CORE_MAXVDD_EN_MASK                                        BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_EN_MASK                                        (1 << 18)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_MAXVDD_ST_SHIFT                               18
-#define OMAP4430_VP_CORE_MAXVDD_ST_MASK                                        BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_ST_MASK                                        (1 << 18)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_MINVDD_EN_SHIFT                               17
-#define OMAP4430_VP_CORE_MINVDD_EN_MASK                                        BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_EN_MASK                                        (1 << 17)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_MINVDD_ST_SHIFT                               17
-#define OMAP4430_VP_CORE_MINVDD_ST_MASK                                        BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_ST_MASK                                        (1 << 17)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_NOSMPSACK_EN_SHIFT                            19
-#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK                             BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK                             (1 << 19)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_NOSMPSACK_ST_SHIFT                            19
-#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK                             BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK                             (1 << 19)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_SHIFT                                16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK                         BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK                         (1 << 16)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_SHIFT                                16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK                         BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK                         (1 << 16)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_TRANXDONE_EN_SHIFT                            21
-#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK                             BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK                             (1 << 21)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_TRANXDONE_ST_SHIFT                            21
-#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK                             BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK                             (1 << 21)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_EQVALUE_EN_SHIFT                               28
-#define OMAP4430_VP_IVA_EQVALUE_EN_MASK                                        BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_EN_MASK                                        (1 << 28)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_EQVALUE_ST_SHIFT                               28
-#define OMAP4430_VP_IVA_EQVALUE_ST_MASK                                        BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_ST_MASK                                        (1 << 28)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_MAXVDD_EN_SHIFT                                        26
-#define OMAP4430_VP_IVA_MAXVDD_EN_MASK                                 BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_EN_MASK                                 (1 << 26)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_MAXVDD_ST_SHIFT                                        26
-#define OMAP4430_VP_IVA_MAXVDD_ST_MASK                                 BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_ST_MASK                                 (1 << 26)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_MINVDD_EN_SHIFT                                        25
-#define OMAP4430_VP_IVA_MINVDD_EN_MASK                                 BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_EN_MASK                                 (1 << 25)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_MINVDD_ST_SHIFT                                        25
-#define OMAP4430_VP_IVA_MINVDD_ST_MASK                                 BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_ST_MASK                                 (1 << 25)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_NOSMPSACK_EN_SHIFT                             27
-#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK                              BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK                              (1 << 27)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_NOSMPSACK_ST_SHIFT                             27
-#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK                              BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK                              (1 << 27)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_SHIFT                         24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK                          BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK                          (1 << 24)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_SHIFT                         24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK                          BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK                          (1 << 24)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_TRANXDONE_EN_SHIFT                             29
-#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK                              BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK                              (1 << 29)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_TRANXDONE_ST_SHIFT                             29
-#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK                              BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK                              (1 << 29)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_EQVALUE_EN_SHIFT                               4
-#define OMAP4430_VP_MPU_EQVALUE_EN_MASK                                        BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_EN_MASK                                        (1 << 4)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_EQVALUE_ST_SHIFT                               4
-#define OMAP4430_VP_MPU_EQVALUE_ST_MASK                                        BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_ST_MASK                                        (1 << 4)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_MAXVDD_EN_SHIFT                                        2
-#define OMAP4430_VP_MPU_MAXVDD_EN_MASK                                 BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_EN_MASK                                 (1 << 2)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_MAXVDD_ST_SHIFT                                        2
-#define OMAP4430_VP_MPU_MAXVDD_ST_MASK                                 BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_ST_MASK                                 (1 << 2)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_MINVDD_EN_SHIFT                                        1
-#define OMAP4430_VP_MPU_MINVDD_EN_MASK                                 BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_EN_MASK                                 (1 << 1)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_MINVDD_ST_SHIFT                                        1
-#define OMAP4430_VP_MPU_MINVDD_ST_MASK                                 BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_ST_MASK                                 (1 << 1)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_NOSMPSACK_EN_SHIFT                             3
-#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK                              BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK                              (1 << 3)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_NOSMPSACK_ST_SHIFT                             3
-#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK                              BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK                              (1 << 3)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_SHIFT                         0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK                          BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK                          (1 << 0)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_SHIFT                         0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK                          BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK                          (1 << 0)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_TRANXDONE_EN_SHIFT                             5
-#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK                              BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK                              (1 << 5)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_TRANXDONE_ST_SHIFT                             5
-#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK                              BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK                              (1 << 5)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_VSETUPCNT_VALUE_SHIFT                                 8
-#define OMAP4430_VSETUPCNT_VALUE_MASK                                  BITFIELD(8, 15)
+#define OMAP4430_VSETUPCNT_VALUE_MASK                                  (0xff << 8)
 
 /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
 #define OMAP4430_VSTEPMAX_SHIFT                                                0
-#define OMAP4430_VSTEPMAX_MASK                                         BITFIELD(0, 7)
+#define OMAP4430_VSTEPMAX_MASK                                         (0xff << 0)
 
 /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
 #define OMAP4430_VSTEPMIN_SHIFT                                                0
-#define OMAP4430_VSTEPMIN_MASK                                         BITFIELD(0, 7)
+#define OMAP4430_VSTEPMIN_MASK                                         (0xff << 0)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_WAKE_MODEM_SHIFT                                      0
-#define OMAP4430_WAKE_MODEM_MASK                                       BITFIELD(0, 0)
+#define OMAP4430_WAKE_MODEM_MASK                                       (1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_DUCATI_SHIFT                            1
-#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK                             BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK                             (1 << 1)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_DISPC_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DISPC_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_SDMA_SHIFT                              3
-#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK                               BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK                               (1 << 3)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_TESLA_SHIFT                             2
-#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK                              BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK                              (1 << 2)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_SHIFT                          6
-#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK                           BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK                           (1 << 6)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_SHIFT                          2
-#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK                           BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK                           (1 << 2)
 
 /* Used by PM_L4PER_DMTIMER10_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER10_MPU_SHIFT                           0
-#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK                            BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK                            (1 << 0)
 
 /* Used by PM_L4PER_DMTIMER11_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_SHIFT                                1
-#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK                         BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK                         (1 << 1)
 
 /* Used by PM_L4PER_DMTIMER11_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER11_MPU_SHIFT                           0
-#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK                            BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK                            (1 << 0)
 
 /* Used by PM_L4PER_DMTIMER2_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER2_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_DMTIMER3_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_DMTIMER3_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER3_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_DMTIMER4_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_DMTIMER4_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER4_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_DMTIMER9_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_DMTIMER9_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER9_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK                             (1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_DUCATI_SHIFT                             5
-#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK                              BITFIELD(5, 5)
+#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK                              (1 << 5)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_MPU_SHIFT                                        4
-#define OMAP4430_WKUPDEP_DSI1_MPU_MASK                                 BITFIELD(4, 4)
+#define OMAP4430_WKUPDEP_DSI1_MPU_MASK                                 (1 << 4)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_SDMA_SHIFT                               7
-#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK                                        BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK                                        (1 << 7)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_TESLA_SHIFT                              6
-#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK                               BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK                               (1 << 6)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_DUCATI_SHIFT                             9
-#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK                              BITFIELD(9, 9)
+#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK                              (1 << 9)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_MPU_SHIFT                                        8
-#define OMAP4430_WKUPDEP_DSI2_MPU_MASK                                 BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_DSI2_MPU_MASK                                 (1 << 8)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_SDMA_SHIFT                               11
-#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK                                        BITFIELD(11, 11)
+#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK                                        (1 << 11)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_TESLA_SHIFT                              10
-#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK                               BITFIELD(10, 10)
+#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK                               (1 << 10)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_SHIFT                       1
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK                                BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK                                (1 << 1)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_SHIFT                       1
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK                                BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK                                (1 << 1)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_GPIO3_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_GPIO3_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_GPIO4_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_GPIO4_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_GPIO5_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_GPIO5_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_GPIO6_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_GPIO6_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIDMA_SDMA_SHIFT                            19
-#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK                             BITFIELD(19, 19)
+#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK                             (1 << 19)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_SHIFT                          13
-#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK                           BITFIELD(13, 13)
+#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK                           (1 << 13)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_MPU_SHIFT                             12
-#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK                              BITFIELD(12, 12)
+#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK                              (1 << 12)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_SHIFT                           14
-#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK                            BITFIELD(14, 14)
+#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK                            (1 << 14)
 
 /* Used by PM_L4PER_HECC1_WKDEP */
 #define OMAP4430_WKUPDEP_HECC1_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_HECC1_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC1_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L4PER_HECC2_WKDEP */
 #define OMAP4430_WKUPDEP_HECC2_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_HECC2_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC2_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_DSP_TESLA_SHIFT                           6
-#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK                            BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK                            (1 << 6)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_SHIFT                          1
-#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK                           BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK                           (1 << 1)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_MCU_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK                              (1 << 0)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L4PER_I2C5_WKDEP */
 #define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_SHIFT                           7
-#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK                            BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK                            (1 << 7)
 
 /* Used by PM_L4PER_I2C5_WKDEP */
 #define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK                             (1 << 0)
 
 /* Used by PM_WKUP_KEYBOARD_WKDEP */
 #define OMAP4430_WKUPDEP_KEYBOARD_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK                             (1 << 0)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_SHIFT                         7
-#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK                          BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK                          (1 << 7)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK                           (1 << 0)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_SHIFT                                2
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK                         BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK                         (1 << 2)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_SHIFT                         7
-#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK                          BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK                          (1 << 7)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_SHIFT                                2
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK                         BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK                         (1 << 2)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_SHIFT                         7
-#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK                          BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK                          (1 << 7)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_SHIFT                                6
-#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK                         BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK                         (1 << 6)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_SHIFT                          0
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK                           BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK                           (1 << 0)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_SHIFT                                2
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK                         BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK                         (1 << 2)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MCSPI3_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI3_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MCSPI3_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI3_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MCSPI4_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI4_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MCSPI4_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI4_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_DUCATI_SHIFT                             1
-#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK                              BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK                              (1 << 1)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_MMC1_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC1_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_SDMA_SHIFT                               3
-#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK                                        (1 << 3)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_TESLA_SHIFT                              2
-#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK                               BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK                               (1 << 2)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_DUCATI_SHIFT                             1
-#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK                              BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK                              (1 << 1)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_MMC2_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC2_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_SDMA_SHIFT                               3
-#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK                                        (1 << 3)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_TESLA_SHIFT                              2
-#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK                               BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK                               (1 << 2)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_DUCATI_SHIFT                             1
-#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK                              BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK                              (1 << 1)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_MMC6_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC6_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_TESLA_SHIFT                              2
-#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK                               BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK                               (1 << 2)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_SDMA_SHIFT                             3
-#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK                              BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK                              (1 << 3)
 
 /* Used by PM_L3INIT_PCIESS_WKDEP */
 #define OMAP4430_WKUPDEP_PCIESS_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK                               (1 << 0)
 
 /* Used by PM_L3INIT_PCIESS_WKDEP */
 #define OMAP4430_WKUPDEP_PCIESS_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_DMA_SDMA_SHIFT                            7
-#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK                             BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK                             (1 << 7)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_DMA_TESLA_SHIFT                           6
-#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK                            BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK                            (1 << 6)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_IRQ_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK                              (1 << 0)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_SHIFT                           2
-#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK                            BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK                            (1 << 2)
 
 /* Used by PM_WKUP_RTC_WKDEP */
 #define OMAP4430_WKUPDEP_RTC_MPU_SHIFT                                 0
-#define OMAP4430_WKUPDEP_RTC_MPU_MASK                                  BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_RTC_MPU_MASK                                  (1 << 0)
 
 /* Used by PM_L3INIT_SATA_WKDEP */
 #define OMAP4430_WKUPDEP_SATA_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_SATA_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SATA_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_L3INIT_SATA_WKDEP */
 #define OMAP4430_WKUPDEP_SATA_TESLA_SHIFT                              2
-#define OMAP4430_WKUPDEP_SATA_TESLA_MASK                               BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SATA_TESLA_MASK                               (1 << 2)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_SHIFT                       7
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK                                BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK                                (1 << 7)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_SHIFT                      6
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK                       BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK                       (1 << 6)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_SHIFT                                0
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK                         BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK                         (1 << 0)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_SHIFT                      2
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK                       BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK                       (1 << 2)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_SHIFT                       7
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK                                BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK                                (1 << 7)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_SHIFT                      6
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK                       BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK                       (1 << 6)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_SHIFT                                0
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK                         BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK                         (1 << 0)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_SHIFT                      2
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK                       BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK                       (1 << 2)
 
 /* Used by PM_ALWON_SR_CORE_WKDEP */
 #define OMAP4430_WKUPDEP_SR_CORE_DUCATI_SHIFT                          1
-#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK                           BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK                           (1 << 1)
 
 /* Used by PM_ALWON_SR_CORE_WKDEP */
 #define OMAP4430_WKUPDEP_SR_CORE_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK                              (1 << 0)
 
 /* Used by PM_ALWON_SR_IVA_WKDEP */
 #define OMAP4430_WKUPDEP_SR_IVA_DUCATI_SHIFT                           1
-#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK                            BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK                            (1 << 1)
 
 /* Used by PM_ALWON_SR_IVA_WKDEP */
 #define OMAP4430_WKUPDEP_SR_IVA_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ALWON_SR_MPU_WKDEP */
 #define OMAP4430_WKUPDEP_SR_MPU_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK                               (1 << 0)
 
 /* Used by PM_WKUP_TIMER12_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER12_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK                              (1 << 0)
 
 /* Used by PM_WKUP_TIMER1_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER1_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_TIMER5_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER5_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_TIMER5_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER5_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_TIMER6_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER6_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_TIMER6_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER6_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_TIMER7_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER7_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_TIMER7_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER7_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_ABE_TIMER8_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER8_MPU_SHIFT                              0
-#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK                               BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK                               (1 << 0)
 
 /* Used by PM_ABE_TIMER8_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER8_TESLA_SHIFT                            2
-#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK                             BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK                             (1 << 2)
 
 /* Used by PM_L4PER_UART1_WKDEP */
 #define OMAP4430_WKUPDEP_UART1_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_UART1_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART1_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L4PER_UART1_WKDEP */
 #define OMAP4430_WKUPDEP_UART1_SDMA_SHIFT                              3
-#define OMAP4430_WKUPDEP_UART1_SDMA_MASK                               BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART1_SDMA_MASK                               (1 << 3)
 
 /* Used by PM_L4PER_UART2_WKDEP */
 #define OMAP4430_WKUPDEP_UART2_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_UART2_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART2_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L4PER_UART2_WKDEP */
 #define OMAP4430_WKUPDEP_UART2_SDMA_SHIFT                              3
-#define OMAP4430_WKUPDEP_UART2_SDMA_MASK                               BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART2_SDMA_MASK                               (1 << 3)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_DUCATI_SHIFT                            1
-#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK                             BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK                             (1 << 1)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_UART3_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART3_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_SDMA_SHIFT                              3
-#define OMAP4430_WKUPDEP_UART3_SDMA_MASK                               BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART3_SDMA_MASK                               (1 << 3)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_TESLA_SHIFT                             2
-#define OMAP4430_WKUPDEP_UART3_TESLA_MASK                              BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_UART3_TESLA_MASK                              (1 << 2)
 
 /* Used by PM_L4PER_UART4_WKDEP */
 #define OMAP4430_WKUPDEP_UART4_MPU_SHIFT                               0
-#define OMAP4430_WKUPDEP_UART4_MPU_MASK                                        BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART4_MPU_MASK                                        (1 << 0)
 
 /* Used by PM_L4PER_UART4_WKDEP */
 #define OMAP4430_WKUPDEP_UART4_SDMA_SHIFT                              3
-#define OMAP4430_WKUPDEP_UART4_SDMA_MASK                               BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART4_SDMA_MASK                               (1 << 3)
 
 /* Used by PM_L3INIT_UNIPRO1_WKDEP */
 #define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_SHIFT                          1
-#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK                           BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK                           (1 << 1)
 
 /* Used by PM_L3INIT_UNIPRO1_WKDEP */
 #define OMAP4430_WKUPDEP_UNIPRO1_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK                              (1 << 0)
 
 /* Used by PM_L3INIT_USB_HOST_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_DUCATI_SHIFT                         1
-#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK                          BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK                          (1 << 1)
 
 /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_SHIFT                      1
-#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK                       BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK                       (1 << 1)
 
 /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_SHIFT                         0
-#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK                          BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK                          (1 << 0)
 
 /* Used by PM_L3INIT_USB_HOST_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_MPU_SHIFT                            0
-#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK                             BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK                             (1 << 0)
 
 /* Used by PM_L3INIT_USB_OTG_WKDEP */
 #define OMAP4430_WKUPDEP_USB_OTG_DUCATI_SHIFT                          1
-#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK                           BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK                           (1 << 1)
 
 /* Used by PM_L3INIT_USB_OTG_WKDEP */
 #define OMAP4430_WKUPDEP_USB_OTG_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK                              (1 << 0)
 
 /* Used by PM_L3INIT_USB_TLL_WKDEP */
 #define OMAP4430_WKUPDEP_USB_TLL_DUCATI_SHIFT                          1
-#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK                           BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK                           (1 << 1)
 
 /* Used by PM_L3INIT_USB_TLL_WKDEP */
 #define OMAP4430_WKUPDEP_USB_TLL_MPU_SHIFT                             0
-#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK                              BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK                              (1 << 0)
 
 /* Used by PM_WKUP_USIM_WKDEP */
 #define OMAP4430_WKUPDEP_USIM_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_USIM_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USIM_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_WKUP_USIM_WKDEP */
 #define OMAP4430_WKUPDEP_USIM_SDMA_SHIFT                               3
-#define OMAP4430_WKUPDEP_USIM_SDMA_MASK                                        BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_USIM_SDMA_MASK                                        (1 << 3)
 
 /* Used by PM_WKUP_WDT2_WKDEP */
 #define OMAP4430_WKUPDEP_WDT2_DUCATI_SHIFT                             1
-#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK                              BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK                              (1 << 1)
 
 /* Used by PM_WKUP_WDT2_WKDEP */
 #define OMAP4430_WKUPDEP_WDT2_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_WDT2_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT2_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_ABE_WDT3_WKDEP */
 #define OMAP4430_WKUPDEP_WDT3_MPU_SHIFT                                        0
-#define OMAP4430_WKUPDEP_WDT3_MPU_MASK                                 BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT3_MPU_MASK                                 (1 << 0)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_SHIFT                                8
-#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK                         BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK                         (1 << 8)
 
 /* Used by PM_L3INIT_XHPI_WKDEP */
 #define OMAP4430_WKUPDEP_XHPI_DUCATI_SHIFT                             1
-#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK                              BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK                              (1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_WUCLK_CTRL_SHIFT                                      8
-#define OMAP4430_WUCLK_CTRL_MASK                                       BITFIELD(8, 8)
+#define OMAP4430_WUCLK_CTRL_MASK                                       (1 << 8)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_WUCLK_STATUS_SHIFT                                    9
-#define OMAP4430_WUCLK_STATUS_MASK                                     BITFIELD(9, 9)
+#define OMAP4430_WUCLK_STATUS_MASK                                     (1 << 9)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_X_MAJOR_SHIFT                                         8
+#define OMAP4430_X_MAJOR_MASK                                          (0x7 << 8)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_Y_MINOR_SHIFT                                         0
+#define OMAP4430_Y_MINOR_MASK                                          (0x3f << 0)
 #endif
index 588873b9303aa57c38bc716cb3c8b81a61b8d1d9..7be040b2fdab138ad180b5f140866f775b2c79ae 100644 (file)
@@ -5,7 +5,7 @@
  * OMAP2/3 Power/Reset Management (PRM) register definitions
  *
  * Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Nokia Corporation
  *
  * Written by Paul Walmsley
  *
@@ -246,6 +246,15 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
        return prm_rmw_mod_reg_bits(bits, 0x0, module, idx);
 }
 
+/* These omap2_ PRM functions apply to both OMAP2 and 3 */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
+
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+
 #endif
 
 /*
@@ -398,4 +407,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
 #define OMAP_POWERSTATE_MASK                           (0x3 << 0)
 
 
+/*
+ * MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP
+ * submodule to exit hardreset
+ */
+#define MAX_MODULE_HARDRESET_WAIT              10000
+
+
 #endif
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
new file mode 100644 (file)
index 0000000..421771e
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * OMAP2/3 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * Benoît Cousson
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "prm-regbits-34xx.h"
+
+/**
+ * omap2_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL if called while running on a non-OMAP2/3 chip.
+ */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+{
+       if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
+                                      (1 << shift));
+}
+
+/**
+ * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * place the submodule into reset.  Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+{
+       u32 mask;
+
+       if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+               return -EINVAL;
+
+       mask = 1 << shift;
+       prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL);
+
+       return 0;
+}
+
+/**
+ * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning.  Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+{
+       u32 mask;
+       int c;
+
+       if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+               return -EINVAL;
+
+       mask = 1 << shift;
+
+       /* Check the current status to avoid de-asserting the line twice */
+       if (prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0)
+               return -EEXIST;
+
+       /* Clear the reset status by writing 1 to the status bit */
+       prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST);
+       /* de-assert the reset control line */
+       prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL);
+       /* wait the status to be set */
+       omap_test_timeout(prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
+                                                 mask),
+                         MAX_MODULE_HARDRESET_WAIT, c);
+
+       return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
new file mode 100644 (file)
index 0000000..a1ff918
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * OMAP4 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * Benoît Cousson
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-44xx.h"
+
+/*
+ * Address offset (in bytes) between the reset control and the reset
+ * status registers: 4 bytes on OMAP4
+ */
+#define OMAP4_RST_CTRL_ST_OFFSET               4
+
+/**
+ * omap4_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL upon parameter error.
+ */
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift)
+{
+       if (!cpu_is_omap44xx() || !rstctrl_reg)
+               return -EINVAL;
+
+       return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift));
+}
+
+/**
+ * omap4_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * place the submodule into reset.  Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+       u32 mask;
+
+       if (!cpu_is_omap44xx() || !rstctrl_reg)
+               return -EINVAL;
+
+       mask = 1 << shift;
+       omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg);
+
+       return 0;
+}
+
+/**
+ * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning.  Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+       u32 mask;
+       void __iomem *rstst_reg;
+       int c;
+
+       if (!cpu_is_omap44xx() || !rstctrl_reg)
+               return -EINVAL;
+
+       rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET;
+
+       mask = 1 << shift;
+
+       /* Check the current status to avoid de-asserting the line twice */
+       if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0)
+               return -EEXIST;
+
+       /* Clear the reset status by writing 1 to the status bit */
+       omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg);
+       /* de-assert the reset control line */
+       omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg);
+       /* wait the status to be set */
+       omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask),
+                         MAX_MODULE_HARDRESET_WAIT, c);
+
+       return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
index fe8ef26431e5a91d9f9d3497f8473943a6a06c09..59839dbabd84b0b8420f2794ee6e43ec7ae23149 100644 (file)
 #define OMAP4430_PRM_IRQSTATUS_TESLA                   OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0030)
 #define OMAP4_PRM_IRQENABLE_TESLA_OFFSET               0x0038
 #define OMAP4430_PRM_IRQENABLE_TESLA                   OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0038)
-#define OMAP4_PRM_PRM_PROFILING_CLKCTRL_OFFSET         0x0040
-#define OMAP4430_PRM_PRM_PROFILING_CLKCTRL             OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
+#define OMAP4_CM_PRM_PROFILING_CLKCTRL_OFFSET          0x0040
+#define OMAP4430_CM_PRM_PROFILING_CLKCTRL              OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
 
 /* PRM.CKGEN_PRM register offsets */
 #define OMAP4_CM_ABE_DSS_SYS_CLKSEL_OFFSET             0x0000
 #define OMAP4430_CM_ABE_DSS_SYS_CLKSEL                 OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0000)
-#define OMAP4_CM_DPLL_SYS_REF_CLKSEL_OFFSET            0x0004
-#define OMAP4430_CM_DPLL_SYS_REF_CLKSEL                        OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0004)
 #define OMAP4_CM_L4_WKUP_CLKSEL_OFFSET                 0x0008
 #define OMAP4430_CM_L4_WKUP_CLKSEL                     OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0008)
 #define OMAP4_CM_ABE_PLL_REF_CLKSEL_OFFSET             0x000c
 #define OMAP4430_PRM_LDO_ABB_IVA_SETUP                 OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00d8)
 #define OMAP4_PRM_LDO_ABB_IVA_CTRL_OFFSET              0x00dc
 #define OMAP4430_PRM_LDO_ABB_IVA_CTRL                  OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00dc)
-#define OMAP4_PRM_LDO_BANDGAP_CTRL_OFFSET              0x00e0
-#define OMAP4430_PRM_LDO_BANDGAP_CTRL                  OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
+#define OMAP4_PRM_LDO_BANDGAP_SETUP_OFFSET             0x00e0
+#define OMAP4430_PRM_LDO_BANDGAP_SETUP                 OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
 #define OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET               0x00e4
 #define OMAP4430_PRM_DEVICE_OFF_CTRL                   OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e4)
 #define OMAP4_PRM_PHASE1_CNDP_OFFSET                   0x00e8
 #define OMAP4430_PRM_PHASE2B_CNDP                      OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f0)
 #define OMAP4_PRM_MODEM_IF_CTRL_OFFSET                 0x00f4
 #define OMAP4430_PRM_MODEM_IF_CTRL                     OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f4)
+#define OMAP4_PRM_VC_ERRST_OFFSET                      0x00f8
+#define OMAP4430_PRM_VC_ERRST                          OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f8)
 
 /*
  * PRCM_MPU
 /* PRCM_MPU.DEVICE_PRM register offsets */
 #define OMAP4_PRCM_MPU_PRM_RSTST_OFFSET                        0x0000
 #define OMAP4430_PRCM_MPU_PRM_RSTST                    OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0000)
+#define OMAP4_PRCM_MPU_PRM_PSCON_COUNT_OFFSET          0x0004
+#define OMAP4430_PRCM_MPU_PRM_PSCON_COUNT              OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0004)
 
 /* PRCM_MPU.CPU0 register offsets */
 #define OMAP4_PM_CPU0_PWRSTCTRL_OFFSET                 0x0000
index 566e991ede81248057eeb3fbab3aca2078353276..becf0e38ef7ed58a293588ef0b294a02c560e972 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/serial_8250.h>
+#include <linux/pm_runtime.h>
+
+#ifdef CONFIG_SERIAL_OMAP
+#include <plat/omap-serial.h>
+#endif
 
 #include <plat/common.h>
 #include <plat/board.h>
 #include <plat/clock.h>
-#include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "prm.h"
 #include "pm.h"
+#include "cm.h"
 #include "prm-regbits-34xx.h"
+#include "control.h"
 
 #define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV    0x52
 #define UART_OMAP_WER          0x17    /* Wake-up enable register */
@@ -48,6 +59,8 @@
  */
 #define DEFAULT_TIMEOUT 0
 
+#define MAX_UART_HWMOD_NAME_LEN                16
+
 struct omap_uart_state {
        int num;
        int can_sleep;
@@ -58,14 +71,21 @@ struct omap_uart_state {
        void __iomem *wk_en;
        u32 wk_mask;
        u32 padconf;
+       u32 dma_enabled;
 
        struct clk *ick;
        struct clk *fck;
        int clocked;
 
-       struct plat_serial8250_port *p;
+       int irq;
+       int regshift;
+       int irqflags;
+       void __iomem *membase;
+       resource_size_t mapbase;
+
        struct list_head node;
-       struct platform_device pdev;
+       struct omap_hwmod *oh;
+       struct platform_device *pdev;
 
        u32 errata;
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
@@ -83,75 +103,47 @@ struct omap_uart_state {
 };
 
 static LIST_HEAD(uart_list);
+static u8 num_uarts;
 
-static struct plat_serial8250_port serial_platform_data0[] = {
-       {
-               .irq            = 72,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = OMAP24XX_BASE_BAUD * 16,
-       }, {
-               .flags          = 0
-       }
-};
+/*
+ * Since these idle/enable hooks are used in the idle path itself
+ * which has interrupts disabled, use the non-locking versions of
+ * the hwmod enable/disable functions.
+ */
+static int uart_idle_hwmod(struct omap_device *od)
+{
+       _omap_hwmod_idle(od->hwmods[0]);
 
-static struct plat_serial8250_port serial_platform_data1[] = {
-       {
-               .irq            = 73,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = OMAP24XX_BASE_BAUD * 16,
-       }, {
-               .flags          = 0
-       }
-};
+       return 0;
+}
 
-static struct plat_serial8250_port serial_platform_data2[] = {
-       {
-               .irq            = 74,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = OMAP24XX_BASE_BAUD * 16,
-       }, {
-               .flags          = 0
-       }
-};
+static int uart_enable_hwmod(struct omap_device *od)
+{
+       _omap_hwmod_enable(od->hwmods[0]);
 
-static struct plat_serial8250_port serial_platform_data3[] = {
+       return 0;
+}
+
+static struct omap_device_pm_latency omap_uart_latency[] = {
        {
-               .irq            = 70,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = OMAP24XX_BASE_BAUD * 16,
-       }, {
-               .flags          = 0
-       }
+               .deactivate_func = uart_idle_hwmod,
+               .activate_func   = uart_enable_hwmod,
+               .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
 };
 
-void __init omap2_set_globals_uart(struct omap_globals *omap2_globals)
-{
-       serial_platform_data0[0].mapbase = omap2_globals->uart1_phys;
-       serial_platform_data1[0].mapbase = omap2_globals->uart2_phys;
-       serial_platform_data2[0].mapbase = omap2_globals->uart3_phys;
-       serial_platform_data3[0].mapbase = omap2_globals->uart4_phys;
-}
-
 static inline unsigned int __serial_read_reg(struct uart_port *up,
-                                          int offset)
+                                            int offset)
 {
        offset <<= up->regshift;
        return (unsigned int)__raw_readb(up->membase + offset);
 }
 
-static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+static inline unsigned int serial_read_reg(struct omap_uart_state *uart,
                                           int offset)
 {
-       offset <<= up->regshift;
-       return (unsigned int)__raw_readb(up->membase + offset);
+       offset <<= uart->regshift;
+       return (unsigned int)__raw_readb(uart->membase + offset);
 }
 
 static inline void __serial_write_reg(struct uart_port *up, int offset,
@@ -161,11 +153,11 @@ static inline void __serial_write_reg(struct uart_port *up, int offset,
        __raw_writeb(value, up->membase + offset);
 }
 
-static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
                                    int value)
 {
-       offset <<= p->regshift;
-       __raw_writeb(value, p->membase + offset);
+       offset <<= uart->regshift;
+       __raw_writeb(value, uart->membase + offset);
 }
 
 /*
@@ -173,14 +165,12 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
+
 static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
-       struct plat_serial8250_port *p = uart->p;
-
-       serial_write_reg(p, UART_OMAP_MDR1, 0x07);
-       serial_write_reg(p, UART_OMAP_SCR, 0x08);
-       serial_write_reg(p, UART_OMAP_MDR1, 0x00);
-       serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
+       serial_write_reg(uart, UART_OMAP_MDR1, 0x07);
+       serial_write_reg(uart, UART_OMAP_SCR, 0x08);
+       serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
@@ -197,24 +187,23 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
                u8 fcr_val)
 {
-       struct plat_serial8250_port *p = uart->p;
        u8 timeout = 255;
 
-       serial_write_reg(p, UART_OMAP_MDR1, mdr1_val);
+       serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
        udelay(2);
-       serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
+       serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
                        UART_FCR_CLEAR_RCVR);
        /*
         * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
         * TX_FIFO_E bit is 1.
         */
-       while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) &
+       while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
                                (UART_LSR_THRE | UART_LSR_DR))) {
                timeout--;
                if (!timeout) {
                        /* Should *never* happen. we warn and carry on */
-                       dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n",
-                               serial_read_reg(p, UART_LSR));
+                       dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
+                       serial_read_reg(uart, UART_LSR));
                        break;
                }
                udelay(1);
@@ -224,23 +213,22 @@ static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
 static void omap_uart_save_context(struct omap_uart_state *uart)
 {
        u16 lcr = 0;
-       struct plat_serial8250_port *p = uart->p;
 
        if (!enable_off_mode)
                return;
 
-       lcr = serial_read_reg(p, UART_LCR);
-       serial_write_reg(p, UART_LCR, 0xBF);
-       uart->dll = serial_read_reg(p, UART_DLL);
-       uart->dlh = serial_read_reg(p, UART_DLM);
-       serial_write_reg(p, UART_LCR, lcr);
-       uart->ier = serial_read_reg(p, UART_IER);
-       uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
-       uart->scr = serial_read_reg(p, UART_OMAP_SCR);
-       uart->wer = serial_read_reg(p, UART_OMAP_WER);
-       serial_write_reg(p, UART_LCR, 0x80);
-       uart->mcr = serial_read_reg(p, UART_MCR);
-       serial_write_reg(p, UART_LCR, lcr);
+       lcr = serial_read_reg(uart, UART_LCR);
+       serial_write_reg(uart, UART_LCR, 0xBF);
+       uart->dll = serial_read_reg(uart, UART_DLL);
+       uart->dlh = serial_read_reg(uart, UART_DLM);
+       serial_write_reg(uart, UART_LCR, lcr);
+       uart->ier = serial_read_reg(uart, UART_IER);
+       uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC);
+       uart->scr = serial_read_reg(uart, UART_OMAP_SCR);
+       uart->wer = serial_read_reg(uart, UART_OMAP_WER);
+       serial_write_reg(uart, UART_LCR, 0x80);
+       uart->mcr = serial_read_reg(uart, UART_MCR);
+       serial_write_reg(uart, UART_LCR, lcr);
 
        uart->context_valid = 1;
 }
@@ -248,7 +236,6 @@ static void omap_uart_save_context(struct omap_uart_state *uart)
 static void omap_uart_restore_context(struct omap_uart_state *uart)
 {
        u16 efr = 0;
-       struct plat_serial8250_port *p = uart->p;
 
        if (!enable_off_mode)
                return;
@@ -261,29 +248,30 @@ static void omap_uart_restore_context(struct omap_uart_state *uart)
        if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
                omap_uart_mdr1_errataset(uart, 0x07, 0xA0);
        else
-               serial_write_reg(p, UART_OMAP_MDR1, 0x7);
-       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-       efr = serial_read_reg(p, UART_EFR);
-       serial_write_reg(p, UART_EFR, UART_EFR_ECB);
-       serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-       serial_write_reg(p, UART_IER, 0x0);
-       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-       serial_write_reg(p, UART_DLL, uart->dll);
-       serial_write_reg(p, UART_DLM, uart->dlh);
-       serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-       serial_write_reg(p, UART_IER, uart->ier);
-       serial_write_reg(p, UART_LCR, 0x80);
-       serial_write_reg(p, UART_MCR, uart->mcr);
-       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-       serial_write_reg(p, UART_EFR, efr);
-       serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
-       serial_write_reg(p, UART_OMAP_SCR, uart->scr);
-       serial_write_reg(p, UART_OMAP_WER, uart->wer);
-       serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+               serial_write_reg(uart, UART_OMAP_MDR1, 0x7);
+       serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+       efr = serial_read_reg(uart, UART_EFR);
+       serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
+       serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+       serial_write_reg(uart, UART_IER, 0x0);
+       serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+       serial_write_reg(uart, UART_DLL, uart->dll);
+       serial_write_reg(uart, UART_DLM, uart->dlh);
+       serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+       serial_write_reg(uart, UART_IER, uart->ier);
+       serial_write_reg(uart, UART_LCR, 0x80);
+       serial_write_reg(uart, UART_MCR, uart->mcr);
+       serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+       serial_write_reg(uart, UART_EFR, efr);
+       serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
+       serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
+       serial_write_reg(uart, UART_OMAP_WER, uart->wer);
+       serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
        if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
                omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
        else
-               serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+               /* UART 16x mode */
+               serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 #else
 static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
@@ -295,8 +283,7 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
        if (uart->clocked)
                return;
 
-       clk_enable(uart->ick);
-       clk_enable(uart->fck);
+       omap_device_enable(uart->pdev);
        uart->clocked = 1;
        omap_uart_restore_context(uart);
 }
@@ -310,8 +297,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
 
        omap_uart_save_context(uart);
        uart->clocked = 0;
-       clk_disable(uart->ick);
-       clk_disable(uart->fck);
+       omap_device_idle(uart->pdev);
 }
 
 static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
@@ -349,18 +335,24 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
 }
 
 static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
-                                         int enable)
+                                              int enable)
 {
-       struct plat_serial8250_port *p = uart->p;
-       u16 sysc;
+       u8 idlemode;
 
-       sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
-       if (enable)
-               sysc |= 0x2 << 3;
-       else
-               sysc |= 0x1 << 3;
+       if (enable) {
+               /**
+                * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
+                * in Smartidle Mode When Configured for DMA Operations.
+                */
+               if (uart->dma_enabled)
+                       idlemode = HWMOD_IDLEMODE_FORCE;
+               else
+                       idlemode = HWMOD_IDLEMODE_SMART;
+       } else {
+               idlemode = HWMOD_IDLEMODE_NO;
+       }
 
-       serial_write_reg(p, UART_OMAP_SYSC, sysc);
+       omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
 }
 
 static void omap_uart_block_sleep(struct omap_uart_state *uart)
@@ -377,7 +369,7 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart)
 
 static void omap_uart_allow_sleep(struct omap_uart_state *uart)
 {
-       if (device_may_wakeup(&uart->pdev.dev))
+       if (device_may_wakeup(&uart->pdev->dev))
                omap_uart_enable_wakeup(uart);
        else
                omap_uart_disable_wakeup(uart);
@@ -472,6 +464,7 @@ int omap_uart_can_sleep(void)
  * UART will not idle or sleep for its timeout period.
  *
  **/
+/* static int first_interrupt; */
 static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
 {
        struct omap_uart_state *uart = dev_id;
@@ -483,7 +476,6 @@ static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
 
 static void omap_uart_idle_init(struct omap_uart_state *uart)
 {
-       struct plat_serial8250_port *p = uart->p;
        int ret;
 
        uart->can_sleep = 0;
@@ -495,7 +487,7 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
        omap_uart_smart_idle_enable(uart, 0);
 
        if (cpu_is_omap34xx()) {
-               u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+               u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
                u32 wk_mask = 0;
                u32 padconf = 0;
 
@@ -514,19 +506,17 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
                        wk_mask = OMAP3430_ST_UART3_MASK;
                        padconf = 0x19e;
                        break;
+               case 3:
+                       wk_mask = OMAP3630_ST_UART4_MASK;
+                       padconf = 0x0d2;
+                       break;
                }
                uart->wk_mask = wk_mask;
                uart->padconf = padconf;
        } else if (cpu_is_omap24xx()) {
                u32 wk_mask = 0;
+               u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
 
-               if (cpu_is_omap2430()) {
-                       uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
-                       uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
-               } else if (cpu_is_omap2420()) {
-                       uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
-                       uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
-               }
                switch (uart->num) {
                case 0:
                        wk_mask = OMAP24XX_ST_UART1_MASK;
@@ -535,10 +525,19 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
                        wk_mask = OMAP24XX_ST_UART2_MASK;
                        break;
                case 2:
+                       wk_en = OMAP24XX_PM_WKEN2;
+                       wk_st = OMAP24XX_PM_WKST2;
                        wk_mask = OMAP24XX_ST_UART3_MASK;
                        break;
                }
                uart->wk_mask = wk_mask;
+               if (cpu_is_omap2430()) {
+                       uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, wk_en);
+                       uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, wk_st);
+               } else if (cpu_is_omap2420()) {
+                       uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, wk_en);
+                       uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, wk_st);
+               }
        } else {
                uart->wk_en = NULL;
                uart->wk_st = NULL;
@@ -546,9 +545,9 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
                uart->padconf = 0;
        }
 
-       p->irqflags |= IRQF_SHARED;
-       ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
-                         "serial idle", (void *)uart);
+       uart->irqflags |= IRQF_SHARED;
+       ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
+                                  IRQF_SHARED, "serial idle", (void *)uart);
        WARN_ON(ret);
 }
 
@@ -558,11 +557,17 @@ void omap_uart_enable_irqs(int enable)
        struct omap_uart_state *uart;
 
        list_for_each_entry(uart, &uart_list, node) {
-               if (enable)
-                       ret = request_irq(uart->p->irq, omap_uart_interrupt,
-                               IRQF_SHARED, "serial idle", (void *)uart);
-               else
-                       free_irq(uart->p->irq, (void *)uart);
+               if (enable) {
+                       pm_runtime_put_sync(&uart->pdev->dev);
+                       ret = request_threaded_irq(uart->irq, NULL,
+                                                  omap_uart_interrupt,
+                                                  IRQF_SHARED,
+                                                  "serial idle",
+                                                  (void *)uart);
+               } else {
+                       pm_runtime_get_noresume(&uart->pdev->dev);
+                       free_irq(uart->irq, (void *)uart);
+               }
        }
 }
 
@@ -570,10 +575,9 @@ static ssize_t sleep_timeout_show(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
 {
-       struct platform_device *pdev = container_of(dev,
-                                       struct platform_device, dev);
-       struct omap_uart_state *uart = container_of(pdev,
-                                       struct omap_uart_state, pdev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap_device *odev = to_omap_device(pdev);
+       struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
 
        return sprintf(buf, "%u\n", uart->timeout / HZ);
 }
@@ -582,10 +586,9 @@ static ssize_t sleep_timeout_store(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf, size_t n)
 {
-       struct platform_device *pdev = container_of(dev,
-                                       struct platform_device, dev);
-       struct omap_uart_state *uart = container_of(pdev,
-                                       struct omap_uart_state, pdev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap_device *odev = to_omap_device(pdev);
+       struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
        unsigned int value;
 
        if (sscanf(buf, "%u", &value) != 1) {
@@ -608,48 +611,15 @@ static DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show,
 #define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
 #else
 static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+       /* Needed to enable UART clocks when built without CONFIG_PM */
+       omap_uart_enable_clocks(uart);
+}
 #define DEV_CREATE_FILE(dev, attr)
 #endif /* CONFIG_PM */
 
-static struct omap_uart_state omap_uart[] = {
-       {
-               .pdev = {
-                       .name                   = "serial8250",
-                       .id                     = PLAT8250_DEV_PLATFORM,
-                       .dev                    = {
-                               .platform_data  = serial_platform_data0,
-                       },
-               },
-       }, {
-               .pdev = {
-                       .name                   = "serial8250",
-                       .id                     = PLAT8250_DEV_PLATFORM1,
-                       .dev                    = {
-                               .platform_data  = serial_platform_data1,
-                       },
-               },
-       }, {
-               .pdev = {
-                       .name                   = "serial8250",
-                       .id                     = PLAT8250_DEV_PLATFORM2,
-                       .dev                    = {
-                               .platform_data  = serial_platform_data2,
-                       },
-               },
-       },
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-       {
-               .pdev = {
-                       .name                   = "serial8250",
-                       .id                     = 3,
-                       .dev                    = {
-                               .platform_data  = serial_platform_data3,
-                       },
-               },
-       },
-#endif
-};
-
+#ifndef CONFIG_SERIAL_OMAP
 /*
  * Override the default 8250 read handler: mem_serial_in()
  * Empty RX fifo read causes an abort on omap3630 and omap4
@@ -682,71 +652,44 @@ static void serial_out_override(struct uart_port *up, int offset, int value)
        }
        __serial_write_reg(up, offset, value);
 }
+#endif
+
 void __init omap_serial_early_init(void)
 {
-       int i, nr_ports;
-       char name[16];
+       int i = 0;
 
-       if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-               nr_ports = 3;
-       else
-               nr_ports = ARRAY_SIZE(omap_uart);
+       do {
+               char oh_name[MAX_UART_HWMOD_NAME_LEN];
+               struct omap_hwmod *oh;
+               struct omap_uart_state *uart;
 
-       /*
-        * Make sure the serial ports are muxed on at this point.
-        * You have to mux them off in device drivers later on
-        * if not needed.
-        */
+               snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
+                        "uart%d", i + 1);
+               oh = omap_hwmod_lookup(oh_name);
+               if (!oh)
+                       break;
 
-       for (i = 0; i < nr_ports; i++) {
-               struct omap_uart_state *uart = &omap_uart[i];
-               struct platform_device *pdev = &uart->pdev;
-               struct device *dev = &pdev->dev;
-               struct plat_serial8250_port *p = dev->platform_data;
+               uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
+               if (WARN_ON(!uart))
+                       return;
+
+               uart->oh = oh;
+               uart->num = i++;
+               list_add_tail(&uart->node, &uart_list);
+               num_uarts++;
 
-               /* Don't map zero-based physical address */
-               if (p->mapbase == 0) {
-                       dev_warn(dev, "no physical address for uart#%d,"
-                                " so skipping early_init...\n", i);
-                       continue;
-               }
                /*
-                * Module 4KB + L4 interconnect 4KB
-                * Static mapping, never released
+                * NOTE: omap_hwmod_init() has not yet been called,
+                *       so no hwmod functions will work yet.
                 */
-               p->membase = ioremap(p->mapbase, SZ_8K);
-               if (!p->membase) {
-                       dev_err(dev, "ioremap failed for uart%i\n", i + 1);
-                       continue;
-               }
-
-               sprintf(name, "uart%d_ick", i + 1);
-               uart->ick = clk_get(NULL, name);
-               if (IS_ERR(uart->ick)) {
-                       dev_err(dev, "Could not get uart%d_ick\n", i + 1);
-                       uart->ick = NULL;
-               }
 
-               sprintf(name, "uart%d_fck", i+1);
-               uart->fck = clk_get(NULL, name);
-               if (IS_ERR(uart->fck)) {
-                       dev_err(dev, "Could not get uart%d_fck\n", i + 1);
-                       uart->fck = NULL;
-               }
-
-               /* FIXME: Remove this once the clkdev is ready */
-               if (!cpu_is_omap44xx()) {
-                       if (!uart->ick || !uart->fck)
-                               continue;
-               }
-
-               uart->num = i;
-               p->private_data = uart;
-               uart->p = p;
-
-               if (cpu_is_omap44xx())
-                       p->irq += 32;
-       }
+               /*
+                * During UART early init, device need to be probed
+                * to determine SoC specific init before omap_device
+                * is ready.  Therefore, don't allow idle here
+                */
+               uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
+       } while (1);
 }
 
 /**
@@ -763,53 +706,135 @@ void __init omap_serial_early_init(void)
 void __init omap_serial_init_port(int port)
 {
        struct omap_uart_state *uart;
-       struct platform_device *pdev;
-       struct device *dev;
-
-       BUG_ON(port < 0);
-       BUG_ON(port >= ARRAY_SIZE(omap_uart));
-
-       uart = &omap_uart[port];
-       pdev = &uart->pdev;
-       dev = &pdev->dev;
+       struct omap_hwmod *oh;
+       struct omap_device *od;
+       void *pdata = NULL;
+       u32 pdata_size = 0;
+       char *name;
+#ifndef CONFIG_SERIAL_OMAP
+       struct plat_serial8250_port ports[2] = {
+               {},
+               {.flags = 0},
+       };
+       struct plat_serial8250_port *p = &ports[0];
+#else
+       struct omap_uart_port_info omap_up;
+#endif
 
-       /* Don't proceed if there's no clocks available */
-       if (unlikely(!uart->ick || !uart->fck)) {
-               WARN(1, "%s: can't init uart%d, no clocks available\n",
-                    kobject_name(&dev->kobj), port);
+       if (WARN_ON(port < 0))
+               return;
+       if (WARN_ON(port >= num_uarts))
                return;
-       }
-
-       omap_uart_enable_clocks(uart);
-
-       omap_uart_reset(uart);
-       omap_uart_idle_init(uart);
 
-       list_add_tail(&uart->node, &uart_list);
+       list_for_each_entry(uart, &uart_list, node)
+               if (port == uart->num)
+                       break;
 
-       if (WARN_ON(platform_device_register(pdev)))
-               return;
+       oh = uart->oh;
+       uart->dma_enabled = 0;
+#ifndef CONFIG_SERIAL_OMAP
+       name = "serial8250";
 
-       if ((cpu_is_omap34xx() && uart->padconf) ||
-           (uart->wk_en && uart->wk_mask)) {
-               device_init_wakeup(dev, true);
-               DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
-       }
+       /*
+        * !! 8250 driver does not use standard IORESOURCE* It
+        * has it's own custom pdata that can be taken from
+        * the hwmod resource data.  But, this needs to be
+        * done after the build.
+        *
+        * ?? does it have to be done before the register ??
+        * YES, because platform_device_data_add() copies
+        * pdata, it does not use a pointer.
+        */
+       p->flags = UPF_BOOT_AUTOCONF;
+       p->iotype = UPIO_MEM;
+       p->regshift = 2;
+       p->uartclk = OMAP24XX_BASE_BAUD * 16;
+       p->irq = oh->mpu_irqs[0].irq;
+       p->mapbase = oh->slaves[0]->addr->pa_start;
+       p->membase = omap_hwmod_get_mpu_rt_va(oh);
+       p->irqflags = IRQF_SHARED;
+       p->private_data = uart;
 
        /*
         * omap44xx: Never read empty UART fifo
         * omap3xxx: Never read empty UART fifo on UARTs
         * with IP rev >=0x52
         */
+       uart->regshift = p->regshift;
+       uart->membase = p->membase;
        if (cpu_is_omap44xx())
                uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
-       else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
+       else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
                        >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
                uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
 
        if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) {
-               uart->p->serial_in = serial_in_override;
-               uart->p->serial_out = serial_out_override;
+               p->serial_in = serial_in_override;
+               p->serial_out = serial_out_override;
+       }
+
+       pdata = &ports[0];
+       pdata_size = 2 * sizeof(struct plat_serial8250_port);
+#else
+
+       name = DRIVER_NAME;
+
+       omap_up.dma_enabled = uart->dma_enabled;
+       omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
+       omap_up.mapbase = oh->slaves[0]->addr->pa_start;
+       omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
+       omap_up.irqflags = IRQF_SHARED;
+       omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+       pdata = &omap_up;
+       pdata_size = sizeof(struct omap_uart_port_info);
+#endif
+
+       if (WARN_ON(!oh))
+               return;
+
+       od = omap_device_build(name, uart->num, oh, pdata, pdata_size,
+                              omap_uart_latency,
+                              ARRAY_SIZE(omap_uart_latency), false);
+       WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
+            name, oh->name);
+
+       uart->irq = oh->mpu_irqs[0].irq;
+       uart->regshift = 2;
+       uart->mapbase = oh->slaves[0]->addr->pa_start;
+       uart->membase = omap_hwmod_get_mpu_rt_va(oh);
+       uart->pdev = &od->pdev;
+
+       oh->dev_attr = uart;
+
+       /*
+        * Because of early UART probing, UART did not get idled
+        * on init.  Now that omap_device is ready, ensure full idle
+        * before doing omap_device_enable().
+        */
+       omap_hwmod_idle(uart->oh);
+
+       omap_device_enable(uart->pdev);
+       omap_uart_idle_init(uart);
+       omap_uart_reset(uart);
+       omap_hwmod_enable_wakeup(uart->oh);
+       omap_device_idle(uart->pdev);
+
+       /*
+        * Need to block sleep long enough for interrupt driven
+        * driver to start.  Console driver is in polling mode
+        * so device needs to be kept enabled while polling driver
+        * is in use.
+        */
+       if (uart->timeout)
+               uart->timeout = (30 * HZ);
+       omap_uart_block_sleep(uart);
+       uart->timeout = DEFAULT_TIMEOUT;
+
+       if ((cpu_is_omap34xx() && uart->padconf) ||
+           (uart->wk_en && uart->wk_mask)) {
+               device_init_wakeup(&od->pdev.dev, true);
+               DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
        }
 
        /* Enable the MDR1 errata for OMAP3 */
@@ -826,13 +851,8 @@ void __init omap_serial_init_port(int port)
  */
 void __init omap_serial_init(void)
 {
-       int i, nr_ports;
-
-       if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-               nr_ports = 3;
-       else
-               nr_ports = ARRAY_SIZE(omap_uart);
+       struct omap_uart_state *uart;
 
-       for (i = 0; i < nr_ports; i++)
-               omap_serial_init_port(i);
+       list_for_each_entry(uart, &uart_list, node)
+               omap_serial_init_port(uart->num);
 }
index ba53191ae4c55bfdaf4515f4edd0a9ca67bce4b9..2fb205a7f285505b46cd4c75b113673fe352809b 100644 (file)
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <plat/control.h>
 
 #include "cm.h"
 #include "prm.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define SDRC_SCRATCHPAD_SEM_V  0xfa00291c
 
index de99ba2a57ab21c1c82ce739e94e2f306668337c..3637274af5be5bfc0f26c09367b7a7d0bab809d5 100644 (file)
@@ -129,8 +129,11 @@ ENTRY(omap3_sram_configure_core_dpll)
        ldr     r4, [sp, #80]
        str     r4, omap_sdrc_mr_1_val
 skip_cs1_params:
+       mrc     p15, 0, r8, c1, c0, 0   @ read ctrl register
+       bic     r10, r8, #0x800         @ clear Z-bit, disable branch prediction
+       mcr     p15, 0, r10, c1, c0, 0  @ write ctrl register
        dsb                             @ flush buffered writes to interconnect
-
+       isb                             @ prevent speculative exec past here
        cmp     r3, #1                  @ if increasing SDRC clk rate,
        bleq    configure_sdrc          @ program the SDRC regs early (for RFR)
        cmp     r1, #SDRC_UNLOCK_DLL    @ set the intended DLL state
@@ -148,6 +151,7 @@ skip_cs1_params:
        beq     return_to_sdram         @ return to SDRAM code, otherwise,
        bl      configure_sdrc          @ reprogram SDRC regs now
 return_to_sdram:
+       mcr     p15, 0, r8, c1, c0, 0   @ restore ctrl register
        isb                             @ prevent speculative exec past here
        mov     r0, #0                  @ return value
        ldmfd   sp!, {r1-r12, pc}       @ restore regs and return
index 74fbed8491f273f0b11a90c5c150a1b427fe831f..e13c29eecf2b54d3cdf17cdff24ea18c8f2f7ee9 100644 (file)
@@ -40,6 +40,8 @@
 #include <plat/dmtimer.h>
 #include <asm/localtimer.h>
 
+#include "timer-gp.h"
+
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID         12
 
@@ -228,8 +230,10 @@ static void __init omap2_gp_clocksource_init(void)
 static void __init omap2_gp_timer_init(void)
 {
 #ifdef CONFIG_LOCAL_TIMERS
-       twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
-       BUG_ON(!twd_base);
+       if (cpu_is_omap44xx()) {
+               twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
+               BUG_ON(!twd_base);
+       }
 #endif
        omap_dm_timer_init();
 
diff --git a/arch/arm/mach-omap2/timer-gp.h b/arch/arm/mach-omap2/timer-gp.h
new file mode 100644 (file)
index 0000000..5c1072c
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * OMAP2/3 GPTIMER support.headers
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
+
+extern int __init omap2_gp_clockevent_set_gptimer(u8 id);
+
+#endif
index a216d88b04b5c4f0690a7c32b514084b78590800..1481078763b805fdba84802256f78e1a63c9b093 100644 (file)
 
 #include <asm/irq.h>
 
-#include <plat/control.h>
 #include <plat/usb.h>
 #include <plat/board.h>
 
+#include "control.h"
+#include "mux.h"
+
 #define INT_USB_IRQ_GEN                INT_24XX_USB_IRQ_GEN
 #define INT_USB_IRQ_NISO       INT_24XX_USB_IRQ_NISO
 #define INT_USB_IRQ_ISO                INT_24XX_USB_IRQ_ISO
 #define INT_USB_IRQ_HGEN       INT_24XX_USB_IRQ_HGEN
 #define INT_USB_IRQ_OTG                INT_24XX_USB_IRQ_OTG
 
-#include "mux.h"
-
 #if defined(CONFIG_ARCH_OMAP2)
 
 #ifdef CONFIG_USB_GADGET_OMAP
index 08b410343870ae2518afb4303110d5807dfc12d1..aaa1166df9640a925e50c822cd3ddd777080b4d6 100644 (file)
@@ -382,6 +382,31 @@ struct platform_device pxa_device_i2s = {
        .num_resources  = ARRAY_SIZE(pxai2s_resources),
 };
 
+struct platform_device pxa_device_asoc_ssp1 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+       .name           = "pxa-ssp-dai",
+       .id             = 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+       .name           = "pxa-pcm-audio",
+       .id             = -1,
+};
+
 static u64 pxaficp_dmamask = ~(u32)0;
 
 struct platform_device pxa_device_ficp = {
index 715e8bd02e248930e449c4e6c2c169054c837c6e..2fd5a8b35757ac5463303b278d3970d7d4df9d02 100644 (file)
@@ -39,4 +39,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
 
 extern struct platform_device pxa3xx_device_gcu;
 
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
 void __init pxa_register_device(struct platform_device *dev, void *data);
index 12e5b9f01e6f6271f73623aa47f5be826b86bd2a..d1fbf29d561c5cbe4b49e634ccb9953f6b1a4f27 100644 (file)
@@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
        &pxa_device_pmu,
        &pxa_device_i2s,
+       &pxa_device_asoc_ssp1,
+       &pxa_device_asoc_ssp2,
+       &pxa_device_asoc_ssp3,
+       &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
index c85c3a7abd314f84cce570a79d4f38ecce21ecce..d1c747cdacf879f32f947c54795e86ba06435efc 100644 (file)
@@ -593,6 +593,11 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
        &pxa_device_pmu,
        &pxa_device_i2s,
+       &pxa_device_asoc_ssp1,
+       &pxa_device_asoc_ssp2,
+       &pxa_device_asoc_ssp3,
+       &pxa_device_asoc_ssp4,
+       &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
index f25fb6245bd787bc93636163b241f8fefe9f0210..702f7a68e87d593f18bb60ef54091cec561726c1 100644 (file)
@@ -45,6 +45,16 @@ int wm9713_irq;
 int lcd_id;
 int lcd_orientation;
 
+struct platform_device pxa_device_wm9713_audio = {
+       .name           = "wm9713-codec",
+       .id             = -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+       platform_device_register(&pxa_device_wm9713_audio);
+}
+
 static struct resource smc91x_resources[] = {
        [0] = {
                .start  = ZYLONITE_ETH_PHYS + 0x300,
@@ -408,6 +418,7 @@ static void __init zylonite_init(void)
        zylonite_init_nand();
        zylonite_init_leds();
        zylonite_init_ohci();
+       zylonite_init_wm9713_audio();
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
index 9648fbc36eecd391f6e7a14f005e0645fa824af5..3838335f125b65067d9e771b7e48af8ca1b07218 100644 (file)
@@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
                s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
                s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
                s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+               break;
        default:
-               printk(KERN_DEBUG "Invalid I2S Controller number!");
+               printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+                       pdev->id);
                return -EINVAL;
        }
 
@@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
                s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
                break;
        default:
-               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+                       pdev->id);
                return -EINVAL;
        }
 
@@ -333,3 +336,16 @@ void __init s3c64xx_ac97_setup_gpio(int num)
        else
                s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 }
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+       .name             = "s3c24xx-pcm-audio",
+       .id               = -1,
+       .dev              = {
+               .dma_mask = &s3c_device_audio_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+
index ec8865c03a1965d0ae51c7f64251fd8e0a08beae..77488facfe4cab45ad9c8c9ea996e06138ec0074 100644 (file)
@@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
+       &s3c_device_pcm,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,
 
index a57713c1954abe0ca329648d7fc398c8ac3d64f7..acd9552f8ada7bb6fd10d2b5cc5377d14632ca74 100644 (file)
@@ -16,6 +16,10 @@ config ARCH_TEGRA_2x_SOC
 
 endchoice
 
+config TEGRA_PCI
+       bool "PCI Express support"
+       select PCI
+
 comment "Tegra board type"
 
 config MACH_HARMONY
@@ -47,4 +51,11 @@ config TEGRA_DEBUG_UARTE
 
 endchoice
 
+config TEGRA_SYSTEM_DMA
+       bool "Enable system DMA driver for NVIDIA Tegra SoCs"
+       default y
+       help
+         Adds system DMA functionality for NVIDIA Tegra SoCs, used by
+         several Tegra device drivers
+
 endif
index 51e9370eed99bb4ffb23323610fff4e5f3cd9787..cdbc68e4c0ca2738492edc665e31df47354fa6fe 100644 (file)
@@ -1,14 +1,21 @@
 obj-y                                   += common.o
 obj-y                                   += io.o
-obj-y                                   += irq.o
+obj-y                                   += irq.o legacy_irq.o
 obj-y                                   += clock.o
 obj-y                                   += timer.o
 obj-y                                   += gpio.o
 obj-y                                   += pinmux.o
+obj-y                                  += fuse.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += clock.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_dvfs.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += pinmux-t2-tables.o
 obj-$(CONFIG_SMP)                       += platsmp.o localtimer.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o
+obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
+obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
 
 obj-${CONFIG_MACH_HARMONY}              += board-harmony.o
 obj-${CONFIG_MACH_HARMONY}              += board-harmony-pinmux.o
+obj-${CONFIG_MACH_HARMONY}              += board-harmony-pcie.o
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
new file mode 100644 (file)
index 0000000..f7e7d45
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-tegra/board-harmony-pcie.c
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/pinmux.h>
+#include "board.h"
+
+#ifdef CONFIG_TEGRA_PCI
+
+static int __init harmony_pcie_init(void)
+{
+       int err;
+
+       if (!machine_is_harmony())
+               return 0;
+
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_NORMAL);
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_NORMAL);
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
+
+       err = tegra_pcie_init(true, true);
+       if (err)
+               goto err_pcie;
+
+       return 0;
+
+err_pcie:
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_TRISTATE);
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
+       tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
+
+       return err;
+}
+
+subsys_initcall(harmony_pcie_init);
+
+#endif
index 3d06354136f2663ff2f80cdbfa9b441671dc4146..0de565ca37c550709fd077278a398eccac7ace5c 100644 (file)
@@ -27,6 +27,7 @@ void __init tegra_common_init(void);
 void __init tegra_map_common_io(void);
 void __init tegra_init_irq(void);
 void __init tegra_init_clock(void);
+int __init tegra_pcie_init(bool init_port0, bool init_port1);
 
 extern struct sys_timer tegra_timer;
 #endif
index 03ad578349b98aa55e89f8639ff49663dd0f8d6d..ae19f95585be119c51456a9d2d75183fc3b1ff4c 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
+#include <linux/regulator/consumer.h>
 #include <asm/clkdev.h>
 
 #include "clock.h"
+#include "board.h"
+#include "fuse.h"
 
 static LIST_HEAD(clocks);
 
 static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(dvfs_lock);
+
+static int clk_is_dvfs(struct clk *c)
+{
+       return (c->dvfs != NULL);
+};
+
+static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
+{
+       struct dvfs_table *t;
+
+       if (d->table == NULL)
+               return -ENODEV;
+
+       for (t = d->table; t->rate != 0; t++) {
+               if (rate <= t->rate) {
+                       if (!d->reg)
+                               return 0;
+
+                       return regulator_set_voltage(d->reg,
+                               t->millivolts * 1000,
+                               d->max_millivolts * 1000);
+               }
+       }
+
+       return -EINVAL;
+}
+
+static void dvfs_init(struct clk *c)
+{
+       int process_id;
+       int i;
+       struct dvfs_table *table;
+
+       process_id = c->dvfs->cpu ? tegra_core_process_id() :
+               tegra_cpu_process_id();
+
+       for (i = 0; i < c->dvfs->process_id_table_length; i++)
+               if (process_id == c->dvfs->process_id_table[i].process_id)
+                       c->dvfs->table = c->dvfs->process_id_table[i].table;
+
+       if (c->dvfs->table == NULL) {
+               pr_err("Failed to find dvfs table for clock %s process %d\n",
+                       c->name, process_id);
+               return;
+       }
+
+       c->dvfs->max_millivolts = 0;
+       for (table = c->dvfs->table; table->rate != 0; table++)
+               if (c->dvfs->max_millivolts < table->millivolts)
+                       c->dvfs->max_millivolts = table->millivolts;
+
+       c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
+
+       if (IS_ERR(c->dvfs->reg)) {
+               pr_err("Failed to get regulator %s for clock %s\n",
+                       c->dvfs->reg_id, c->name);
+               c->dvfs->reg = NULL;
+               return;
+       }
+
+       if (c->refcnt > 0)
+               dvfs_set_rate(c->dvfs, c->rate);
+}
 
 struct clk *tegra_get_clock_by_name(const char *name)
 {
@@ -48,14 +115,31 @@ struct clk *tegra_get_clock_by_name(const char *name)
        return ret;
 }
 
+static void clk_recalculate_rate(struct clk *c)
+{
+       u64 rate;
+
+       if (!c->parent)
+               return;
+
+       rate = c->parent->rate;
+
+       if (c->mul != 0 && c->div != 0) {
+               rate = rate * c->mul;
+               do_div(rate, c->div);
+       }
+
+       if (rate > c->max_rate)
+               pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
+                       c->name, rate, c->max_rate);
+
+       c->rate = rate;
+}
+
 int clk_reparent(struct clk *c, struct clk *parent)
 {
        pr_debug("%s: %s\n", __func__, c->name);
-       if (c->refcnt && c->parent)
-               clk_disable_locked(c->parent);
        c->parent = parent;
-       if (c->refcnt && c->parent)
-               clk_enable_locked(c->parent);
        list_del(&c->sibling);
        list_add_tail(&c->sibling, &parent->children);
        return 0;
@@ -67,8 +151,7 @@ static void propagate_rate(struct clk *c)
        pr_debug("%s: %s\n", __func__, c->name);
        list_for_each_entry(clkp, &c->children, sibling) {
                pr_debug("   %s\n", clkp->name);
-               if (clkp->ops->recalculate_rate)
-                       clkp->ops->recalculate_rate(clkp);
+               clk_recalculate_rate(clkp);
                propagate_rate(clkp);
        }
 }
@@ -77,6 +160,8 @@ void clk_init(struct clk *c)
 {
        unsigned long flags;
 
+       pr_debug("%s: %s\n", __func__, c->name);
+
        spin_lock_irqsave(&clock_lock, flags);
 
        INIT_LIST_HEAD(&c->children);
@@ -85,6 +170,8 @@ void clk_init(struct clk *c)
        if (c->ops && c->ops->init)
                c->ops->init(c);
 
+       clk_recalculate_rate(c);
+
        list_add(&c->node, &clocks);
 
        if (c->parent)
@@ -122,13 +209,38 @@ int clk_enable_locked(struct clk *c)
        return 0;
 }
 
+int clk_enable_cansleep(struct clk *c)
+{
+       int ret;
+       unsigned long flags;
+
+       mutex_lock(&dvfs_lock);
+
+       if (clk_is_dvfs(c) && c->refcnt > 0)
+               dvfs_set_rate(c->dvfs, c->rate);
+
+       spin_lock_irqsave(&clock_lock, flags);
+       ret = clk_enable_locked(c);
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       mutex_unlock(&dvfs_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_enable_cansleep);
+
 int clk_enable(struct clk *c)
 {
        int ret;
        unsigned long flags;
+
+       if (clk_is_dvfs(c))
+               BUG();
+
        spin_lock_irqsave(&clock_lock, flags);
        ret = clk_enable_locked(c);
        spin_unlock_irqrestore(&clock_lock, flags);
+
        return ret;
 }
 EXPORT_SYMBOL(clk_enable);
@@ -152,9 +264,30 @@ void clk_disable_locked(struct clk *c)
        c->refcnt--;
 }
 
+void clk_disable_cansleep(struct clk *c)
+{
+       unsigned long flags;
+
+       mutex_lock(&dvfs_lock);
+
+       spin_lock_irqsave(&clock_lock, flags);
+       clk_disable_locked(c);
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       if (clk_is_dvfs(c) && c->refcnt == 0)
+               dvfs_set_rate(c->dvfs, c->rate);
+
+       mutex_unlock(&dvfs_lock);
+}
+EXPORT_SYMBOL(clk_disable_cansleep);
+
 void clk_disable(struct clk *c)
 {
        unsigned long flags;
+
+       if (clk_is_dvfs(c))
+               BUG();
+
        spin_lock_irqsave(&clock_lock, flags);
        clk_disable_locked(c);
        spin_unlock_irqrestore(&clock_lock, flags);
@@ -175,6 +308,8 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent)
        if (ret)
                return ret;
 
+       clk_recalculate_rate(c);
+
        propagate_rate(c);
 
        return 0;
@@ -197,22 +332,69 @@ struct clk *clk_get_parent(struct clk *c)
 }
 EXPORT_SYMBOL(clk_get_parent);
 
-int clk_set_rate(struct clk *c, unsigned long rate)
+int clk_set_rate_locked(struct clk *c, unsigned long rate)
+{
+       int ret;
+
+       if (rate > c->max_rate)
+               rate = c->max_rate;
+
+       if (!c->ops || !c->ops->set_rate)
+               return -ENOSYS;
+
+       ret = c->ops->set_rate(c, rate);
+
+       if (ret)
+               return ret;
+
+       clk_recalculate_rate(c);
+
+       propagate_rate(c);
+
+       return 0;
+}
+
+int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
 {
        int ret = 0;
        unsigned long flags;
 
+       pr_debug("%s: %s\n", __func__, c->name);
+
+       mutex_lock(&dvfs_lock);
+
+       if (rate > c->rate)
+               ret = dvfs_set_rate(c->dvfs, rate);
+       if (ret)
+               goto out;
+
        spin_lock_irqsave(&clock_lock, flags);
+       ret = clk_set_rate_locked(c, rate);
+       spin_unlock_irqrestore(&clock_lock, flags);
 
-       pr_debug("%s: %s\n", __func__, c->name);
+       if (ret)
+               goto out;
 
-       if (c->ops && c->ops->set_rate)
-               ret = c->ops->set_rate(c, rate);
-       else
-               ret = -ENOSYS;
+       ret = dvfs_set_rate(c->dvfs, rate);
 
-       propagate_rate(c);
+out:
+       mutex_unlock(&dvfs_lock);
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate_cansleep);
+
+int clk_set_rate(struct clk *c, unsigned long rate)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       pr_debug("%s: %s\n", __func__, c->name);
+
+       if (clk_is_dvfs(c))
+               BUG();
 
+       spin_lock_irqsave(&clock_lock, flags);
+       ret = clk_set_rate_locked(c, rate);
        spin_unlock_irqrestore(&clock_lock, flags);
 
        return ret;
@@ -235,6 +417,20 @@ unsigned long clk_get_rate(struct clk *c)
 }
 EXPORT_SYMBOL(clk_get_rate);
 
+long clk_round_rate(struct clk *c, unsigned long rate)
+{
+       pr_debug("%s: %s\n", __func__, c->name);
+
+       if (!c->ops || !c->ops->round_rate)
+               return -ENOSYS;
+
+       if (rate > c->max_rate)
+               rate = c->max_rate;
+
+       return c->ops->round_rate(c, rate);
+}
+EXPORT_SYMBOL(clk_round_rate);
+
 static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
 {
        struct clk *c;
@@ -308,13 +504,28 @@ void tegra_periph_reset_assert(struct clk *c)
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
-int __init tegra_init_clock(void)
+void __init tegra_init_clock(void)
 {
        tegra2_init_clocks();
+}
+
+int __init tegra_init_dvfs(void)
+{
+       struct clk *c, *safe;
+
+       mutex_lock(&dvfs_lock);
+
+       list_for_each_entry_safe(c, safe, &clocks, node)
+               if (c->dvfs)
+                       dvfs_init(c);
+
+       mutex_unlock(&dvfs_lock);
 
        return 0;
 }
 
+late_initcall(tegra_init_dvfs);
+
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *clk_debugfs_root;
 
@@ -324,7 +535,7 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
        struct clk *child;
        struct clk *safe;
        const char *state = "uninit";
-       char div[5] = {0};
+       char div[8] = {0};
 
        if (c->state == ON)
                state = "on";
@@ -332,16 +543,26 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
                state = "off";
 
        if (c->mul != 0 && c->div != 0) {
-               BUG_ON(c->mul > 2);
-               if (c->mul > c->div)
-                       snprintf(div, sizeof(div), "x%d", c->mul / c->div);
-               else
+               if (c->mul > c->div) {
+                       int mul = c->mul / c->div;
+                       int mul2 = (c->mul * 10 / c->div) % 10;
+                       int mul3 = (c->mul * 10) % c->div;
+                       if (mul2 == 0 && mul3 == 0)
+                               snprintf(div, sizeof(div), "x%d", mul);
+                       else if (mul3 == 0)
+                               snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
+                       else
+                               snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
+               } else {
                        snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
                                (c->div % c->mul) ? ".5" : "");
+               }
        }
 
-       seq_printf(s, "%*s%-*s %-6s %-3d %-5s %-10lu\n",
-               level * 3 + 1, c->set ? "" : "*",
+       seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
+               level * 3 + 1, "",
+               c->rate > c->max_rate ? '!' : ' ',
+               !c->set ? '*' : ' ',
                30 - level * 3, c->name,
                state, c->refcnt, div, c->rate);
        list_for_each_entry_safe(child, safe, &c->children, sibling) {
@@ -353,8 +574,8 @@ static int clock_tree_show(struct seq_file *s, void *data)
 {
        struct clk *c;
        unsigned long flags;
-       seq_printf(s, " clock                          state  ref div   rate      \n");
-       seq_printf(s, "-----------------------------------------------------------\n");
+       seq_printf(s, "   clock                          state  ref div      rate\n");
+       seq_printf(s, "--------------------------------------------------------------\n");
        spin_lock_irqsave(&clock_lock, flags);
        list_for_each_entry(c, &clocks, node)
                if (c->parent == NULL)
index af7c70e2a3baf4a29c8860ccc0ca51cd026cb1cd..94fd859770f1a992a0bd001e265a781c3bf7448b 100644 (file)
 #define DIV_U71                        (1 << 1)
 #define DIV_U71_FIXED          (1 << 2)
 #define DIV_2                  (1 << 3)
-#define PLL_FIXED              (1 << 4)
-#define PLL_HAS_CPCON          (1 << 5)
-#define MUX                    (1 << 6)
-#define PLLD                   (1 << 7)
-#define PERIPH_NO_RESET                (1 << 8)
-#define PERIPH_NO_ENB          (1 << 9)
-#define PERIPH_EMC_ENB         (1 << 10)
-#define PERIPH_MANUAL_RESET    (1 << 11)
-#define PLL_ALT_MISC_REG       (1 << 12)
+#define DIV_U16                        (1 << 4)
+#define PLL_FIXED              (1 << 5)
+#define PLL_HAS_CPCON          (1 << 6)
+#define MUX                    (1 << 7)
+#define PLLD                   (1 << 8)
+#define PERIPH_NO_RESET                (1 << 9)
+#define PERIPH_NO_ENB          (1 << 10)
+#define PERIPH_EMC_ENB         (1 << 11)
+#define PERIPH_MANUAL_RESET    (1 << 12)
+#define PLL_ALT_MISC_REG       (1 << 13)
+#define PLLU                   (1 << 14)
 #define ENABLE_ON_INIT         (1 << 28)
 
 struct clk;
+struct regulator;
+
+struct dvfs_table {
+       unsigned long rate;
+       int millivolts;
+};
+
+struct dvfs_process_id_table {
+       int process_id;
+       struct dvfs_table *table;
+};
+
+
+struct dvfs {
+       struct regulator *reg;
+       struct dvfs_table *table;
+       int max_millivolts;
+
+       int process_id_table_length;
+       const char *reg_id;
+       bool cpu;
+       struct dvfs_process_id_table process_id_table[];
+};
 
 struct clk_mux_sel {
        struct clk      *input;
@@ -58,12 +83,9 @@ struct clk_ops {
        void            (*init)(struct clk *);
        int             (*enable)(struct clk *);
        void            (*disable)(struct clk *);
-       void            (*recalc)(struct clk *);
        int             (*set_parent)(struct clk *, struct clk *);
        int             (*set_rate)(struct clk *, unsigned long);
-       unsigned long   (*get_rate)(struct clk *);
        long            (*round_rate)(struct clk *, unsigned long);
-       unsigned long   (*recalculate_rate)(struct clk *);
 };
 
 enum clk_state {
@@ -85,6 +107,7 @@ struct clk {
        struct clk                      *parent;
        struct clk_lookup               lookup;
        unsigned long                   rate;
+       unsigned long                   max_rate;
        u32                             flags;
        u32                             refcnt;
        const char                      *name;
@@ -103,10 +126,6 @@ struct clk {
        unsigned long                   cf_max;
        unsigned long                   vco_min;
        unsigned long                   vco_max;
-       u32                             m;
-       u32                             n;
-       u32                             p;
-       u32                             cpcon;
        const struct clk_pll_table      *pll_table;
 
        /* DIV */
@@ -117,6 +136,12 @@ struct clk {
        const struct clk_mux_sel        *inputs;
        u32                             sel;
        u32                             reg_mask;
+
+       /* Virtual cpu clock */
+       struct clk                      *main;
+       struct clk                      *backup;
+
+       struct dvfs                     *dvfs;
 };
 
 
@@ -141,6 +166,7 @@ unsigned long clk_measure_input_freq(void);
 void clk_disable_locked(struct clk *c);
 int clk_enable_locked(struct clk *c);
 int clk_set_parent_locked(struct clk *c, struct clk *parent);
+int clk_set_rate_locked(struct clk *c, unsigned long rate);
 int clk_reparent(struct clk *c, struct clk *parent);
 void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
 
index 039a514b61ef1e5f0c9142a4aa81ccf021c96c95..7c91e2b9d643fa5c18e07a606a1b5a543645c383 100644 (file)
 
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
 
 #include <asm/hardware/cache-l2x0.h>
 
 #include <mach/iomap.h>
+#include <mach/dma.h>
 
 #include "board.h"
 #include "clock.h"
+#include "fuse.h"
 
 static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
        /* name         parent          rate            enabled */
@@ -35,8 +39,8 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
        { "pll_p_out2", "pll_p",        48000000,       true },
        { "pll_p_out3", "pll_p",        72000000,       true },
        { "pll_p_out4", "pll_p",        108000000,      true },
-       { "sys",        "pll_p_out4",   108000000,      true },
-       { "hclk",       "sys",          108000000,      true },
+       { "sclk",       "pll_p_out4",   108000000,      true },
+       { "hclk",       "sclk",         108000000,      true },
        { "pclk",       "hclk",         54000000,       true },
        { NULL,         NULL,           0,              0},
 };
@@ -51,11 +55,16 @@ void __init tegra_init_cache(void)
 
        l2x0_init(p, 0x6C080001, 0x8200c3fe);
 #endif
+
 }
 
 void __init tegra_common_init(void)
 {
+       tegra_init_fuse();
        tegra_init_clock();
        tegra_clk_init_from_table(common_clk_init_table);
        tegra_init_cache();
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+       tegra_dma_init();
+#endif
 }
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
new file mode 100644 (file)
index 0000000..fea5719
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * arch/arm/mach-tegra/cpu-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@google.com>
+ *     Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <mach/clk.h>
+
+/* Frequency table index must be sequential starting at 0 */
+static struct cpufreq_frequency_table freq_table[] = {
+       { 0, 312000 },
+       { 1, 456000 },
+       { 2, 608000 },
+       { 3, 760000 },
+       { 4, 816000 },
+       { 5, 912000 },
+       { 6, 1000000 },
+       { 7, CPUFREQ_TABLE_END },
+};
+
+#define NUM_CPUS       2
+
+static struct clk *cpu_clk;
+
+static unsigned long target_cpu_speed[NUM_CPUS];
+
+int tegra_verify_speed(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+unsigned int tegra_getspeed(unsigned int cpu)
+{
+       unsigned long rate;
+
+       if (cpu >= NUM_CPUS)
+               return 0;
+
+       rate = clk_get_rate(cpu_clk) / 1000;
+       return rate;
+}
+
+static int tegra_update_cpu_speed(void)
+{
+       int i;
+       unsigned long rate = 0;
+       int ret = 0;
+       struct cpufreq_freqs freqs;
+
+       for_each_online_cpu(i)
+               rate = max(rate, target_cpu_speed[i]);
+
+       freqs.old = tegra_getspeed(0);
+       freqs.new = rate;
+
+       if (freqs.old == freqs.new)
+               return ret;
+
+       for_each_online_cpu(freqs.cpu)
+               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+       printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
+              freqs.old, freqs.new);
+#endif
+
+       ret = clk_set_rate_cansleep(cpu_clk, freqs.new * 1000);
+       if (ret) {
+               pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
+                       freqs.new);
+               return ret;
+       }
+
+       for_each_online_cpu(freqs.cpu)
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       return 0;
+}
+
+static int tegra_target(struct cpufreq_policy *policy,
+                      unsigned int target_freq,
+                      unsigned int relation)
+{
+       int idx;
+       unsigned int freq;
+
+       cpufreq_frequency_table_target(policy, freq_table, target_freq,
+               relation, &idx);
+
+       freq = freq_table[idx].frequency;
+
+       target_cpu_speed[policy->cpu] = freq;
+
+       return tegra_update_cpu_speed();
+}
+
+static int tegra_cpu_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu >= NUM_CPUS)
+               return -EINVAL;
+
+       cpu_clk = clk_get_sys(NULL, "cpu");
+       if (IS_ERR(cpu_clk))
+               return PTR_ERR(cpu_clk);
+
+       cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+       policy->cur = tegra_getspeed(policy->cpu);
+       target_cpu_speed[policy->cpu] = policy->cur;
+
+       /* FIXME: what's the actual transition time? */
+       policy->cpuinfo.transition_latency = 300 * 1000;
+
+       policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+       cpumask_copy(policy->related_cpus, cpu_possible_mask);
+
+       return 0;
+}
+
+static int tegra_cpu_exit(struct cpufreq_policy *policy)
+{
+       cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       clk_put(cpu_clk);
+       return 0;
+}
+
+static struct freq_attr *tegra_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver tegra_cpufreq_driver = {
+       .verify         = tegra_verify_speed,
+       .target         = tegra_target,
+       .get            = tegra_getspeed,
+       .init           = tegra_cpu_init,
+       .exit           = tegra_cpu_exit,
+       .name           = "tegra",
+       .attr           = tegra_cpufreq_attr,
+};
+
+static int __init tegra_cpufreq_init(void)
+{
+       return cpufreq_register_driver(&tegra_cpufreq_driver);
+}
+
+static void __exit tegra_cpufreq_exit(void)
+{
+        cpufreq_unregister_driver(&tegra_cpufreq_driver);
+}
+
+
+MODULE_AUTHOR("Colin Cross <ccross@android.com>");
+MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
+MODULE_LICENSE("GPL");
+module_init(tegra_cpufreq_init);
+module_exit(tegra_cpufreq_exit);
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
new file mode 100644 (file)
index 0000000..edda6ec
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * arch/arm/mach-tegra/dma.c
+ *
+ * System DMA driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+
+#define APB_DMA_GEN                            0x000
+#define GEN_ENABLE                             (1<<31)
+
+#define APB_DMA_CNTRL                          0x010
+
+#define APB_DMA_IRQ_MASK                       0x01c
+
+#define APB_DMA_IRQ_MASK_SET                   0x020
+
+#define APB_DMA_CHAN_CSR                       0x000
+#define CSR_ENB                                        (1<<31)
+#define CSR_IE_EOC                             (1<<30)
+#define CSR_HOLD                               (1<<29)
+#define CSR_DIR                                        (1<<28)
+#define CSR_ONCE                               (1<<27)
+#define CSR_FLOW                               (1<<21)
+#define CSR_REQ_SEL_SHIFT                      16
+#define CSR_REQ_SEL_MASK                       (0x1F<<CSR_REQ_SEL_SHIFT)
+#define CSR_REQ_SEL_INVALID                    (31<<CSR_REQ_SEL_SHIFT)
+#define CSR_WCOUNT_SHIFT                       2
+#define CSR_WCOUNT_MASK                                0xFFFC
+
+#define APB_DMA_CHAN_STA                               0x004
+#define STA_BUSY                               (1<<31)
+#define STA_ISE_EOC                            (1<<30)
+#define STA_HALT                               (1<<29)
+#define STA_PING_PONG                          (1<<28)
+#define STA_COUNT_SHIFT                                2
+#define STA_COUNT_MASK                         0xFFFC
+
+#define APB_DMA_CHAN_AHB_PTR                           0x010
+
+#define APB_DMA_CHAN_AHB_SEQ                           0x014
+#define AHB_SEQ_INTR_ENB                       (1<<31)
+#define AHB_SEQ_BUS_WIDTH_SHIFT                        28
+#define AHB_SEQ_BUS_WIDTH_MASK                 (0x7<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_8                    (0<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_16                   (1<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_32                   (2<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_64                   (3<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_128                  (4<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_DATA_SWAP                      (1<<27)
+#define AHB_SEQ_BURST_MASK                     (0x7<<24)
+#define AHB_SEQ_BURST_1                                (4<<24)
+#define AHB_SEQ_BURST_4                                (5<<24)
+#define AHB_SEQ_BURST_8                                (6<<24)
+#define AHB_SEQ_DBL_BUF                                (1<<19)
+#define AHB_SEQ_WRAP_SHIFT                     16
+#define AHB_SEQ_WRAP_MASK                      (0x7<<AHB_SEQ_WRAP_SHIFT)
+
+#define APB_DMA_CHAN_APB_PTR                           0x018
+
+#define APB_DMA_CHAN_APB_SEQ                           0x01c
+#define APB_SEQ_BUS_WIDTH_SHIFT                        28
+#define APB_SEQ_BUS_WIDTH_MASK                 (0x7<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_8                    (0<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_16                   (1<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_32                   (2<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_64                   (3<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_128                  (4<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_DATA_SWAP                      (1<<27)
+#define APB_SEQ_WRAP_SHIFT                     16
+#define APB_SEQ_WRAP_MASK                      (0x7<<APB_SEQ_WRAP_SHIFT)
+
+#define TEGRA_SYSTEM_DMA_CH_NR                 16
+#define TEGRA_SYSTEM_DMA_AVP_CH_NUM            4
+#define TEGRA_SYSTEM_DMA_CH_MIN                        0
+#define TEGRA_SYSTEM_DMA_CH_MAX        \
+       (TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1)
+
+#define NV_DMA_MAX_TRASFER_SIZE 0x10000
+
+const unsigned int ahb_addr_wrap_table[8] = {
+       0, 32, 64, 128, 256, 512, 1024, 2048
+};
+
+const unsigned int apb_addr_wrap_table[8] = {0, 1, 2, 4, 8, 16, 32, 64};
+
+const unsigned int bus_width_table[5] = {8, 16, 32, 64, 128};
+
+#define TEGRA_DMA_NAME_SIZE 16
+struct tegra_dma_channel {
+       struct list_head        list;
+       int                     id;
+       spinlock_t              lock;
+       char                    name[TEGRA_DMA_NAME_SIZE];
+       void  __iomem           *addr;
+       int                     mode;
+       int                     irq;
+
+       /* Register shadow */
+       u32                     csr;
+       u32                     ahb_seq;
+       u32                     ahb_ptr;
+       u32                     apb_seq;
+       u32                     apb_ptr;
+};
+
+#define  NV_DMA_MAX_CHANNELS  32
+
+static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
+static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req);
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req);
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch);
+static void tegra_dma_stop(struct tegra_dma_channel *ch);
+
+void tegra_dma_flush(struct tegra_dma_channel *ch)
+{
+}
+EXPORT_SYMBOL(tegra_dma_flush);
+
+void tegra_dma_dequeue(struct tegra_dma_channel *ch)
+{
+       struct tegra_dma_req *req;
+
+       req = list_entry(ch->list.next, typeof(*req), node);
+
+       tegra_dma_dequeue_req(ch, req);
+       return;
+}
+
+void tegra_dma_stop(struct tegra_dma_channel *ch)
+{
+       unsigned int csr;
+       unsigned int status;
+
+       csr = ch->csr;
+       csr &= ~CSR_IE_EOC;
+       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+       csr &= ~CSR_ENB;
+       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+       status = readl(ch->addr + APB_DMA_CHAN_STA);
+       if (status & STA_ISE_EOC)
+               writel(status, ch->addr + APB_DMA_CHAN_STA);
+}
+
+int tegra_dma_cancel(struct tegra_dma_channel *ch)
+{
+       unsigned int csr;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&ch->lock, irq_flags);
+       while (!list_empty(&ch->list))
+               list_del(ch->list.next);
+
+       csr = ch->csr;
+       csr &= ~CSR_REQ_SEL_MASK;
+       csr |= CSR_REQ_SEL_INVALID;
+
+       /* Set the enable as that is not shadowed */
+       csr |= CSR_ENB;
+       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+       tegra_dma_stop(ch);
+
+       spin_unlock_irqrestore(&ch->lock, irq_flags);
+       return 0;
+}
+
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *_req)
+{
+       unsigned int csr;
+       unsigned int status;
+       struct tegra_dma_req *req = NULL;
+       int found = 0;
+       unsigned long irq_flags;
+       int to_transfer;
+       int req_transfer_count;
+
+       spin_lock_irqsave(&ch->lock, irq_flags);
+       list_for_each_entry(req, &ch->list, node) {
+               if (req == _req) {
+                       list_del(&req->node);
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               spin_unlock_irqrestore(&ch->lock, irq_flags);
+               return 0;
+       }
+
+       /* STOP the DMA and get the transfer count.
+        * Getting the transfer count is tricky.
+        *  - Change the source selector to invalid to stop the DMA from
+        *    FIFO to memory.
+        *  - Read the status register to know the number of pending
+        *    bytes to be transfered.
+        *  - Finally stop or program the DMA to the next buffer in the
+        *    list.
+        */
+       csr = ch->csr;
+       csr &= ~CSR_REQ_SEL_MASK;
+       csr |= CSR_REQ_SEL_INVALID;
+
+       /* Set the enable as that is not shadowed */
+       csr |= CSR_ENB;
+       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+       /* Get the transfer count */
+       status = readl(ch->addr + APB_DMA_CHAN_STA);
+       to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
+       req_transfer_count = (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+       req_transfer_count += 1;
+       to_transfer += 1;
+
+       req->bytes_transferred = req_transfer_count;
+
+       if (status & STA_BUSY)
+               req->bytes_transferred -= to_transfer;
+
+       /* In continous transfer mode, DMA only tracks the count of the
+        * half DMA buffer. So, if the DMA already finished half the DMA
+        * then add the half buffer to the completed count.
+        *
+        *      FIXME: There can be a race here. What if the req to
+        *      dequue happens at the same time as the DMA just moved to
+        *      the new buffer and SW didn't yet received the interrupt?
+        */
+       if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
+               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+                       req->bytes_transferred += req_transfer_count;
+
+       req->bytes_transferred *= 4;
+
+       tegra_dma_stop(ch);
+       if (!list_empty(&ch->list)) {
+               /* if the list is not empty, queue the next request */
+               struct tegra_dma_req *next_req;
+               next_req = list_entry(ch->list.next,
+                       typeof(*next_req), node);
+               tegra_dma_update_hw(ch, next_req);
+       }
+       req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
+
+       spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+       /* Callback should be called without any lock */
+       req->complete(req);
+       return 0;
+}
+EXPORT_SYMBOL(tegra_dma_dequeue_req);
+
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch)
+{
+       unsigned long irq_flags;
+       bool is_empty;
+
+       spin_lock_irqsave(&ch->lock, irq_flags);
+       if (list_empty(&ch->list))
+               is_empty = true;
+       else
+               is_empty = false;
+       spin_unlock_irqrestore(&ch->lock, irq_flags);
+       return is_empty;
+}
+EXPORT_SYMBOL(tegra_dma_is_empty);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *_req)
+{
+       unsigned long irq_flags;
+       struct tegra_dma_req *req;
+
+       spin_lock_irqsave(&ch->lock, irq_flags);
+       list_for_each_entry(req, &ch->list, node) {
+               if (req == _req) {
+                       spin_unlock_irqrestore(&ch->lock, irq_flags);
+                       return true;
+               }
+       }
+       spin_unlock_irqrestore(&ch->lock, irq_flags);
+       return false;
+}
+EXPORT_SYMBOL(tegra_dma_is_req_inflight);
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req)
+{
+       unsigned long irq_flags;
+       int start_dma = 0;
+
+       if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
+               req->source_addr & 0x3 || req->dest_addr & 0x3) {
+               pr_err("Invalid DMA request for channel %d\n", ch->id);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ch->lock, irq_flags);
+
+       req->bytes_transferred = 0;
+       req->status = 0;
+       req->buffer_status = 0;
+       if (list_empty(&ch->list))
+               start_dma = 1;
+
+       list_add_tail(&req->node, &ch->list);
+
+       if (start_dma)
+               tegra_dma_update_hw(ch, req);
+
+       spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(tegra_dma_enqueue_req);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
+{
+       int channel;
+       struct tegra_dma_channel *ch;
+
+       /* first channel is the shared channel */
+       if (mode & TEGRA_DMA_SHARED) {
+               channel = TEGRA_SYSTEM_DMA_CH_MIN;
+       } else {
+               channel = find_first_zero_bit(channel_usage,
+                       ARRAY_SIZE(dma_channels));
+               if (channel >= ARRAY_SIZE(dma_channels))
+                       return NULL;
+       }
+       __set_bit(channel, channel_usage);
+       ch = &dma_channels[channel];
+       ch->mode = mode;
+       return ch;
+}
+EXPORT_SYMBOL(tegra_dma_allocate_channel);
+
+void tegra_dma_free_channel(struct tegra_dma_channel *ch)
+{
+       if (ch->mode & TEGRA_DMA_SHARED)
+               return;
+       tegra_dma_cancel(ch);
+       __clear_bit(ch->id, channel_usage);
+}
+EXPORT_SYMBOL(tegra_dma_free_channel);
+
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req)
+{
+       if (req->to_memory) {
+               ch->apb_ptr = req->source_addr;
+               ch->ahb_ptr = req->dest_addr;
+       } else {
+               ch->apb_ptr = req->dest_addr;
+               ch->ahb_ptr = req->source_addr;
+       }
+       writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+       writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+       req->status = TEGRA_DMA_REQ_INFLIGHT;
+       return;
+}
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req)
+{
+       int ahb_addr_wrap;
+       int apb_addr_wrap;
+       int ahb_bus_width;
+       int apb_bus_width;
+       int index;
+       unsigned long csr;
+
+
+       ch->csr |= CSR_FLOW;
+       ch->csr &= ~CSR_REQ_SEL_MASK;
+       ch->csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
+       ch->ahb_seq &= ~AHB_SEQ_BURST_MASK;
+       ch->ahb_seq |= AHB_SEQ_BURST_1;
+
+       /* One shot mode is always single buffered,
+        * continuous mode is always double buffered
+        * */
+       if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
+               ch->csr |= CSR_ONCE;
+               ch->ahb_seq &= ~AHB_SEQ_DBL_BUF;
+               ch->csr &= ~CSR_WCOUNT_MASK;
+               ch->csr |= ((req->size>>2) - 1) << CSR_WCOUNT_SHIFT;
+       } else {
+               ch->csr &= ~CSR_ONCE;
+               ch->ahb_seq |= AHB_SEQ_DBL_BUF;
+
+               /* In double buffered mode, we set the size to half the
+                * requested size and interrupt when half the buffer
+                * is full */
+               ch->csr &= ~CSR_WCOUNT_MASK;
+               ch->csr |= ((req->size>>3) - 1) << CSR_WCOUNT_SHIFT;
+       }
+
+       if (req->to_memory) {
+               ch->csr &= ~CSR_DIR;
+               ch->apb_ptr = req->source_addr;
+               ch->ahb_ptr = req->dest_addr;
+
+               apb_addr_wrap = req->source_wrap;
+               ahb_addr_wrap = req->dest_wrap;
+               apb_bus_width = req->source_bus_width;
+               ahb_bus_width = req->dest_bus_width;
+
+       } else {
+               ch->csr |= CSR_DIR;
+               ch->apb_ptr = req->dest_addr;
+               ch->ahb_ptr = req->source_addr;
+
+               apb_addr_wrap = req->dest_wrap;
+               ahb_addr_wrap = req->source_wrap;
+               apb_bus_width = req->dest_bus_width;
+               ahb_bus_width = req->source_bus_width;
+       }
+
+       apb_addr_wrap >>= 2;
+       ahb_addr_wrap >>= 2;
+
+       /* set address wrap for APB size */
+       index = 0;
+       do  {
+               if (apb_addr_wrap_table[index] == apb_addr_wrap)
+                       break;
+               index++;
+       } while (index < ARRAY_SIZE(apb_addr_wrap_table));
+       BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
+       ch->apb_seq &= ~APB_SEQ_WRAP_MASK;
+       ch->apb_seq |= index << APB_SEQ_WRAP_SHIFT;
+
+       /* set address wrap for AHB size */
+       index = 0;
+       do  {
+               if (ahb_addr_wrap_table[index] == ahb_addr_wrap)
+                       break;
+               index++;
+       } while (index < ARRAY_SIZE(ahb_addr_wrap_table));
+       BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
+       ch->ahb_seq &= ~AHB_SEQ_WRAP_MASK;
+       ch->ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
+
+       for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+               if (bus_width_table[index] == ahb_bus_width)
+                       break;
+       }
+       BUG_ON(index == ARRAY_SIZE(bus_width_table));
+       ch->ahb_seq &= ~AHB_SEQ_BUS_WIDTH_MASK;
+       ch->ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
+
+       for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+               if (bus_width_table[index] == apb_bus_width)
+                       break;
+       }
+       BUG_ON(index == ARRAY_SIZE(bus_width_table));
+       ch->apb_seq &= ~APB_SEQ_BUS_WIDTH_MASK;
+       ch->apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
+
+       ch->csr |= CSR_IE_EOC;
+
+       /* update hw registers with the shadow */
+       writel(ch->csr, ch->addr + APB_DMA_CHAN_CSR);
+       writel(ch->apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
+       writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+       writel(ch->ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
+       writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+       csr = ch->csr | CSR_ENB;
+       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+       req->status = TEGRA_DMA_REQ_INFLIGHT;
+}
+
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch)
+{
+       /* One shot with an interrupt to CPU after transfer */
+       ch->csr = CSR_ONCE | CSR_IE_EOC;
+       ch->ahb_seq = AHB_SEQ_BUS_WIDTH_32 | AHB_SEQ_INTR_ENB;
+       ch->apb_seq = APB_SEQ_BUS_WIDTH_32 | 1 << APB_SEQ_WRAP_SHIFT;
+}
+
+static void handle_oneshot_dma(struct tegra_dma_channel *ch)
+{
+       struct tegra_dma_req *req;
+
+       spin_lock(&ch->lock);
+       if (list_empty(&ch->list)) {
+               spin_unlock(&ch->lock);
+               return;
+       }
+
+       req = list_entry(ch->list.next, typeof(*req), node);
+       if (req) {
+               int bytes_transferred;
+
+               bytes_transferred =
+                       (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+               bytes_transferred += 1;
+               bytes_transferred <<= 2;
+
+               list_del(&req->node);
+               req->bytes_transferred = bytes_transferred;
+               req->status = TEGRA_DMA_REQ_SUCCESS;
+
+               spin_unlock(&ch->lock);
+               /* Callback should be called without any lock */
+               pr_debug("%s: transferred %d bytes\n", __func__,
+                       req->bytes_transferred);
+               req->complete(req);
+               spin_lock(&ch->lock);
+       }
+
+       if (!list_empty(&ch->list)) {
+               req = list_entry(ch->list.next, typeof(*req), node);
+               /* the complete function we just called may have enqueued
+                  another req, in which case dma has already started */
+               if (req->status != TEGRA_DMA_REQ_INFLIGHT)
+                       tegra_dma_update_hw(ch, req);
+       }
+       spin_unlock(&ch->lock);
+}
+
+static void handle_continuous_dma(struct tegra_dma_channel *ch)
+{
+       struct tegra_dma_req *req;
+
+       spin_lock(&ch->lock);
+       if (list_empty(&ch->list)) {
+               spin_unlock(&ch->lock);
+               return;
+       }
+
+       req = list_entry(ch->list.next, typeof(*req), node);
+       if (req) {
+               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
+                       /* Load the next request into the hardware, if available
+                        * */
+                       if (!list_is_last(&req->node, &ch->list)) {
+                               struct tegra_dma_req *next_req;
+
+                               next_req = list_entry(req->node.next,
+                                       typeof(*next_req), node);
+                               tegra_dma_update_hw_partial(ch, next_req);
+                       }
+                       req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
+                       req->status = TEGRA_DMA_REQ_SUCCESS;
+                       /* DMA lock is NOT held when callback is called */
+                       spin_unlock(&ch->lock);
+                       if (likely(req->threshold))
+                               req->threshold(req);
+                       return;
+
+               } else if (req->buffer_status ==
+                       TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
+                       /* Callback when the buffer is completely full (i.e on
+                        * the second  interrupt */
+                       int bytes_transferred;
+
+                       bytes_transferred =
+                               (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+                       bytes_transferred += 1;
+                       bytes_transferred <<= 3;
+
+                       req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
+                       req->bytes_transferred = bytes_transferred;
+                       req->status = TEGRA_DMA_REQ_SUCCESS;
+                       list_del(&req->node);
+
+                       /* DMA lock is NOT held when callbak is called */
+                       spin_unlock(&ch->lock);
+                       req->complete(req);
+                       return;
+
+               } else {
+                       BUG();
+               }
+       }
+       spin_unlock(&ch->lock);
+}
+
+static irqreturn_t dma_isr(int irq, void *data)
+{
+       struct tegra_dma_channel *ch = data;
+       unsigned long status;
+
+       status = readl(ch->addr + APB_DMA_CHAN_STA);
+       if (status & STA_ISE_EOC)
+               writel(status, ch->addr + APB_DMA_CHAN_STA);
+       else {
+               pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id);
+               return IRQ_HANDLED;
+       }
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t dma_thread_fn(int irq, void *data)
+{
+       struct tegra_dma_channel *ch = data;
+
+       if (ch->mode & TEGRA_DMA_MODE_ONESHOT)
+               handle_oneshot_dma(ch);
+       else
+               handle_continuous_dma(ch);
+
+
+       return IRQ_HANDLED;
+}
+
+int __init tegra_dma_init(void)
+{
+       int ret = 0;
+       int i;
+       unsigned int irq;
+       void __iomem *addr;
+
+       addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+       writel(GEN_ENABLE, addr + APB_DMA_GEN);
+       writel(0, addr + APB_DMA_CNTRL);
+       writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
+              addr + APB_DMA_IRQ_MASK_SET);
+
+       memset(channel_usage, 0, sizeof(channel_usage));
+       memset(dma_channels, 0, sizeof(dma_channels));
+
+       /* Reserve all the channels we are not supposed to touch */
+       for (i = 0; i < TEGRA_SYSTEM_DMA_CH_MIN; i++)
+               __set_bit(i, channel_usage);
+
+       for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+               struct tegra_dma_channel *ch = &dma_channels[i];
+
+               __clear_bit(i, channel_usage);
+
+               ch->id = i;
+               snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
+
+               ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+                       TEGRA_APB_DMA_CH0_SIZE * i);
+
+               spin_lock_init(&ch->lock);
+               INIT_LIST_HEAD(&ch->list);
+               tegra_dma_init_hw(ch);
+
+               irq = INT_APB_DMA_CH0 + i;
+               ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
+                       dma_channels[i].name, ch);
+               if (ret) {
+                       pr_err("Failed to register IRQ %d for DMA %d\n",
+                               irq, i);
+                       goto fail;
+               }
+               ch->irq = irq;
+       }
+       /* mark the shared channel allocated */
+       __set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
+
+       for (i = TEGRA_SYSTEM_DMA_CH_MAX+1; i < NV_DMA_MAX_CHANNELS; i++)
+               __set_bit(i, channel_usage);
+
+       return ret;
+fail:
+       writel(0, addr + APB_DMA_GEN);
+       for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+               struct tegra_dma_channel *ch = &dma_channels[i];
+               if (ch->irq)
+                       free_irq(ch->irq, ch);
+       }
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
+
+void tegra_dma_suspend(void)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+       u32 *ctx = apb_dma;
+       int i;
+
+       *ctx++ = readl(addr + APB_DMA_GEN);
+       *ctx++ = readl(addr + APB_DMA_CNTRL);
+       *ctx++ = readl(addr + APB_DMA_IRQ_MASK);
+
+       for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+               addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+                                 TEGRA_APB_DMA_CH0_SIZE * i);
+
+               *ctx++ = readl(addr + APB_DMA_CHAN_CSR);
+               *ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR);
+               *ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ);
+               *ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR);
+               *ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ);
+       }
+}
+
+void tegra_dma_resume(void)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+       u32 *ctx = apb_dma;
+       int i;
+
+       writel(*ctx++, addr + APB_DMA_GEN);
+       writel(*ctx++, addr + APB_DMA_CNTRL);
+       writel(*ctx++, addr + APB_DMA_IRQ_MASK);
+
+       for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+               addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+                                 TEGRA_APB_DMA_CH0_SIZE * i);
+
+               writel(*ctx++, addr + APB_DMA_CHAN_CSR);
+               writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR);
+               writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ);
+               writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR);
+               writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ);
+       }
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
new file mode 100644 (file)
index 0000000..1fa26d9
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "fuse.h"
+
+#define FUSE_UID_LOW           0x108
+#define FUSE_UID_HIGH          0x10c
+#define FUSE_SKU_INFO          0x110
+#define FUSE_SPARE_BIT         0x200
+
+static inline u32 fuse_readl(unsigned long offset)
+{
+       return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+static inline void fuse_writel(u32 value, unsigned long offset)
+{
+       writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+void tegra_init_fuse(void)
+{
+       u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+       reg |= 1 << 28;
+       writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+
+       pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
+               tegra_sku_id(), tegra_cpu_process_id(),
+               tegra_core_process_id());
+}
+
+unsigned long long tegra_chip_uid(void)
+{
+       unsigned long long lo, hi;
+
+       lo = fuse_readl(FUSE_UID_LOW);
+       hi = fuse_readl(FUSE_UID_HIGH);
+       return (hi << 32ull) | lo;
+}
+
+int tegra_sku_id(void)
+{
+       int sku_id;
+       u32 reg = fuse_readl(FUSE_SKU_INFO);
+       sku_id = reg & 0xFF;
+       return sku_id;
+}
+
+int tegra_cpu_process_id(void)
+{
+       int cpu_process_id;
+       u32 reg = fuse_readl(FUSE_SPARE_BIT);
+       cpu_process_id = (reg >> 6) & 3;
+       return cpu_process_id;
+}
+
+int tegra_core_process_id(void)
+{
+       int core_process_id;
+       u32 reg = fuse_readl(FUSE_SPARE_BIT);
+       core_process_id = (reg >> 12) & 3;
+       return core_process_id;
+}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
new file mode 100644 (file)
index 0000000..584b2e2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+unsigned long long tegra_chip_uid(void);
+int tegra_sku_id(void);
+int tegra_cpu_process_id(void);
+int tegra_core_process_id(void);
+void tegra_init_fuse(void);
index fe78fba25f3c7c39fdc494f3519ed956e76cbb5a..0775265e69f5e8fa7e67acef442f1ff9c02607a3 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -60,6 +61,13 @@ struct tegra_gpio_bank {
        int bank;
        int irq;
        spinlock_t lvl_lock[4];
+#ifdef CONFIG_PM
+       u32 cnf[4];
+       u32 out[4];
+       u32 oe[4];
+       u32 int_enb[4];
+       u32 int_lvl[4];
+#endif
 };
 
 
@@ -131,7 +139,7 @@ static struct gpio_chip tegra_gpio_chip = {
        .direction_output       = tegra_gpio_direction_output,
        .set                    = tegra_gpio_set,
        .base                   = 0,
-       .ngpio                  = ARCH_NR_GPIOS,
+       .ngpio                  = TEGRA_NR_GPIOS,
 };
 
 static void tegra_gpio_irq_ack(unsigned int irq)
@@ -244,6 +252,76 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
 }
 
+#ifdef CONFIG_PM
+void tegra_gpio_resume(void)
+{
+       unsigned long flags;
+       int b, p, i;
+
+       local_irq_save(flags);
+
+       for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+               struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+               for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+                       unsigned int gpio = (b<<5) | (p<<3);
+                       __raw_writel(bank->cnf[p], GPIO_CNF(gpio));
+                       __raw_writel(bank->out[p], GPIO_OUT(gpio));
+                       __raw_writel(bank->oe[p], GPIO_OE(gpio));
+                       __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
+                       __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
+               }
+       }
+
+       local_irq_restore(flags);
+
+       for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+               if (!desc || (desc->status & IRQ_WAKEUP))
+                       continue;
+               enable_irq(i);
+       }
+}
+
+void tegra_gpio_suspend(void)
+{
+       unsigned long flags;
+       int b, p, i;
+
+       for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+               if (!desc)
+                       continue;
+               if (desc->status & IRQ_WAKEUP) {
+                       int gpio = i - INT_GPIO_BASE;
+                       pr_debug("gpio %d.%d is wakeup\n", gpio/8, gpio&7);
+                       continue;
+               }
+               disable_irq(i);
+       }
+
+       local_irq_save(flags);
+       for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+               struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+               for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+                       unsigned int gpio = (b<<5) | (p<<3);
+                       bank->cnf[p] = __raw_readl(GPIO_CNF(gpio));
+                       bank->out[p] = __raw_readl(GPIO_OUT(gpio));
+                       bank->oe[p] = __raw_readl(GPIO_OE(gpio));
+                       bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
+                       bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
+               }
+       }
+       local_irq_restore(flags);
+}
+
+static int tegra_gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+       struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
+       return set_irq_wake(bank->irq, enable);
+}
+#endif
 
 static struct irq_chip tegra_gpio_irq_chip = {
        .name           = "GPIO",
@@ -251,6 +329,9 @@ static struct irq_chip tegra_gpio_irq_chip = {
        .mask           = tegra_gpio_irq_mask,
        .unmask         = tegra_gpio_irq_unmask,
        .set_type       = tegra_gpio_irq_set_type,
+#ifdef CONFIG_PM
+       .set_wake       = tegra_gpio_wake_enable,
+#endif
 };
 
 
@@ -274,7 +355,7 @@ static int __init tegra_gpio_init(void)
 
        gpiochip_add(&tegra_gpio_chip);
 
-       for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + ARCH_NR_GPIOS); i++) {
+       for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
                bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
 
                lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
@@ -312,15 +393,16 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
        for (i = 0; i < 7; i++) {
                for (j = 0; j < 4; j++) {
                        int gpio = tegra_gpio_compose(i, j, 0);
-                       seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
-                              i, j,
-                              __raw_readl(GPIO_CNF(gpio)),
-                              __raw_readl(GPIO_OE(gpio)),
-                              __raw_readl(GPIO_OUT(gpio)),
-                              __raw_readl(GPIO_IN(gpio)),
-                              __raw_readl(GPIO_INT_STA(gpio)),
-                              __raw_readl(GPIO_INT_ENB(gpio)),
-                              __raw_readl(GPIO_INT_LVL(gpio)));
+                       seq_printf(s,
+                               "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+                               i, j,
+                               __raw_readl(GPIO_CNF(gpio)),
+                               __raw_readl(GPIO_OE(gpio)),
+                               __raw_readl(GPIO_OUT(gpio)),
+                               __raw_readl(GPIO_IN(gpio)),
+                               __raw_readl(GPIO_INT_STA(gpio)),
+                               __raw_readl(GPIO_INT_ENB(gpio)),
+                               __raw_readl(GPIO_INT_LVL(gpio)));
                }
        }
        return 0;
index 2896f25ebfb57f0ce29cc43a4965763284166422..d7723955dac7486519618d3e2c3715267eee667d 100644 (file)
@@ -23,4 +23,9 @@
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
+int clk_enable_cansleep(struct clk *clk);
+void clk_disable_cansleep(struct clk *clk);
+int clk_set_rate_cansleep(struct clk *clk, unsigned long rate);
+int clk_set_parent_cansleep(struct clk *clk, struct clk *parent);
+
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
new file mode 100644 (file)
index 0000000..39011bd
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dma.h
+ *
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __MACH_TEGRA_DMA_H
+#define __MACH_TEGRA_DMA_H
+
+#include <linux/list.h>
+
+#if defined(CONFIG_TEGRA_SYSTEM_DMA)
+
+struct tegra_dma_req;
+struct tegra_dma_channel;
+
+#define TEGRA_DMA_REQ_SEL_CNTR                 0
+#define TEGRA_DMA_REQ_SEL_I2S_2                        1
+#define TEGRA_DMA_REQ_SEL_I2S_1                        2
+#define TEGRA_DMA_REQ_SEL_SPD_I                        3
+#define TEGRA_DMA_REQ_SEL_UI_I                 4
+#define TEGRA_DMA_REQ_SEL_MIPI                 5
+#define TEGRA_DMA_REQ_SEL_I2S2_2               6
+#define TEGRA_DMA_REQ_SEL_I2S2_1               7
+#define TEGRA_DMA_REQ_SEL_UARTA                        8
+#define TEGRA_DMA_REQ_SEL_UARTB                        9
+#define TEGRA_DMA_REQ_SEL_UARTC                        10
+#define TEGRA_DMA_REQ_SEL_SPI                  11
+#define TEGRA_DMA_REQ_SEL_AC97                 12
+#define TEGRA_DMA_REQ_SEL_ACMODEM              13
+#define TEGRA_DMA_REQ_SEL_SL4B                 14
+#define TEGRA_DMA_REQ_SEL_SL2B1                        15
+#define TEGRA_DMA_REQ_SEL_SL2B2                        16
+#define TEGRA_DMA_REQ_SEL_SL2B3                        17
+#define TEGRA_DMA_REQ_SEL_SL2B4                        18
+#define TEGRA_DMA_REQ_SEL_UARTD                        19
+#define TEGRA_DMA_REQ_SEL_UARTE                        20
+#define TEGRA_DMA_REQ_SEL_I2C                  21
+#define TEGRA_DMA_REQ_SEL_I2C2                 22
+#define TEGRA_DMA_REQ_SEL_I2C3                 23
+#define TEGRA_DMA_REQ_SEL_DVC_I2C              24
+#define TEGRA_DMA_REQ_SEL_OWR                  25
+#define TEGRA_DMA_REQ_SEL_INVALID              31
+
+enum tegra_dma_mode {
+       TEGRA_DMA_SHARED = 1,
+       TEGRA_DMA_MODE_CONTINOUS = 2,
+       TEGRA_DMA_MODE_ONESHOT = 4,
+};
+
+enum tegra_dma_req_error {
+       TEGRA_DMA_REQ_SUCCESS = 0,
+       TEGRA_DMA_REQ_ERROR_ABORTED,
+       TEGRA_DMA_REQ_INFLIGHT,
+};
+
+enum tegra_dma_req_buff_status {
+       TEGRA_DMA_REQ_BUF_STATUS_EMPTY = 0,
+       TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL,
+       TEGRA_DMA_REQ_BUF_STATUS_FULL,
+};
+
+struct tegra_dma_req {
+       struct list_head node;
+       unsigned int modid;
+       int instance;
+
+       /* Called when the req is complete and from the DMA ISR context.
+        * When this is called the req structure is no longer queued by
+        * the DMA channel.
+        *
+        * State of the DMA depends on the number of req it has. If there are
+        * no DMA requests queued up, then it will STOP the DMA. It there are
+        * more requests in the DMA, then it will queue the next request.
+        */
+       void (*complete)(struct tegra_dma_req *req);
+
+       /*  This is a called from the DMA ISR context when the DMA is still in
+        *  progress and is actively filling same buffer.
+        *
+        *  In case of continous mode receive, this threshold is 1/2 the buffer
+        *  size. In other cases, this will not even be called as there is no
+        *  hardware support for it.
+        *
+        * In the case of continous mode receive, if there is next req already
+        * queued, DMA programs the HW to use that req when this req is
+        * completed. If there is no "next req" queued, then DMA ISR doesn't do
+        * anything before calling this callback.
+        *
+        *      This is mainly used by the cases, where the clients has queued
+        *      only one req and want to get some sort of DMA threshold
+        *      callback to program the next buffer.
+        *
+        */
+       void (*threshold)(struct tegra_dma_req *req);
+
+       /* 1 to copy to memory.
+        * 0 to copy from the memory to device FIFO */
+       int to_memory;
+
+       void *virt_addr;
+
+       unsigned long source_addr;
+       unsigned long dest_addr;
+       unsigned long dest_wrap;
+       unsigned long source_wrap;
+       unsigned long source_bus_width;
+       unsigned long dest_bus_width;
+       unsigned long req_sel;
+       unsigned int size;
+
+       /* Updated by the DMA driver on the conpletion of the request. */
+       int bytes_transferred;
+       int status;
+
+       /* DMA completion tracking information */
+       int buffer_status;
+
+       /* Client specific data */
+       void *dev;
+};
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req);
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req);
+void tegra_dma_dequeue(struct tegra_dma_channel *ch);
+void tegra_dma_flush(struct tegra_dma_channel *ch);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req);
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode);
+void tegra_dma_free_channel(struct tegra_dma_channel *ch);
+
+int __init tegra_dma_init(void);
+
+#endif
+
+#endif
index 540e822e50f7c15c0afa4799f060d5c33c638fb3..e31f486d69a2d232768f1dd3e959d25cecb2da6e 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <mach/irqs.h>
 
-#define ARCH_NR_GPIOS          INT_GPIO_NR
+#define TEGRA_NR_GPIOS         INT_GPIO_NR
 
 #include <asm-generic/gpio.h>
 
@@ -35,7 +35,7 @@
 
 static inline int gpio_to_irq(unsigned int gpio)
 {
-       if (gpio < ARCH_NR_GPIOS)
+       if (gpio < TEGRA_NR_GPIOS)
                return INT_GPIO_BASE + gpio;
        return -EINVAL;
 }
index 6014edf60d9353d53ecea8fe08b0d5c7838b4719..56e43b3a5b97516161523f91a968e07368c1d71b 100644 (file)
@@ -21,4 +21,8 @@
 #ifndef __MACH_TEGRA_HARDWARE_H
 #define __MACH_TEGRA_HARDWARE_H
 
+#define PCIBIOS_MIN_IO                 0x1000
+#define PCIBIOS_MIN_MEM                        0
+#define pcibios_assign_all_busses()    1
+
 #endif
index 35edfc32ffc9d96280f43f47da841d63ff0fdc32..f0981b1ac59eea58d65a1bbd251ad660deb80a0f 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef __MACH_TEGRA_IO_H
 #define __MACH_TEGRA_IO_H
 
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
 
 /* On TEGRA, many peripherals are very closely packed in
  * two 256MB io windows (that actually only use about 64KB
  *
  */
 
+#define IO_IRAM_PHYS   0x40000000
+#define IO_IRAM_VIRT   0xFE400000
+#define IO_IRAM_SIZE   SZ_256K
+
 #define IO_CPU_PHYS     0x50040000
 #define IO_CPU_VIRT     0xFE000000
 #define IO_CPU_SIZE    SZ_16K
@@ -55,6 +59,8 @@
                IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) :       \
        IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ?             \
                IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) :       \
+       IO_TO_VIRT_BETWEEN((n), IO_IRAM_PHYS, IO_IRAM_SIZE) ?           \
+               IO_TO_VIRT_XLATE((n), IO_IRAM_PHYS, IO_IRAM_VIRT) :     \
        0)
 
 #ifndef __ASSEMBLER__
@@ -67,10 +73,20 @@ void tegra_iounmap(volatile void __iomem *addr);
 
 #define IO_ADDRESS(n) ((void __iomem *) IO_TO_VIRT(n))
 
+#ifdef CONFIG_TEGRA_PCI
+extern void __iomem *tegra_pcie_io_base;
+
+static inline void __iomem *__io(unsigned long addr)
+{
+       return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
+}
+#else
 static inline void __iomem *__io(unsigned long addr)
 {
        return (void __iomem *)addr;
 }
+#endif
+
 #define __io(a)         __io(a)
 #define __mem_pci(a)    (a)
 
index 1741f7dd7a9b71183c98b53cab88e688aa16b031..44a4f4bcf91f0e47bbbdddb7a667366e0588a607 100644 (file)
 
 #include <asm/sizes.h>
 
+#define TEGRA_IRAM_BASE                        0x40000000
+#define TEGRA_IRAM_SIZE                        SZ_256K
+
 #define TEGRA_ARM_PERIF_BASE           0x50040000
 #define TEGRA_ARM_PERIF_SIZE           SZ_8K
 
+#define TEGRA_ARM_PL310_BASE           0x50043000
+#define TEGRA_ARM_PL310_SIZE           SZ_4K
+
 #define TEGRA_ARM_INT_DIST_BASE                0x50041000
 #define TEGRA_ARM_INT_DIST_SIZE                SZ_4K
 
 #define TEGRA_FLOW_CTRL_BASE           0x60007000
 #define TEGRA_FLOW_CTRL_SIZE           20
 
-#define TEGRA_STATMON_BASE             0x6000C4000
+#define TEGRA_AHB_DMA_BASE             0x60008000
+#define TEGRA_AHB_DMA_SIZE             SZ_4K
+
+#define TEGRA_AHB_DMA_CH0_BASE         0x60009000
+#define TEGRA_AHB_DMA_CH0_SIZE         32
+
+#define TEGRA_APB_DMA_BASE             0x6000A000
+#define TEGRA_APB_DMA_SIZE             SZ_4K
+
+#define TEGRA_APB_DMA_CH0_BASE         0x6000B000
+#define TEGRA_APB_DMA_CH0_SIZE         32
+
+#define TEGRA_AHB_GIZMO_BASE           0x6000C004
+#define TEGRA_AHB_GIZMO_SIZE           0x10C
+
+#define TEGRA_STATMON_BASE             0x6000C400
 #define TEGRA_STATMON_SIZE             SZ_1K
 
 #define TEGRA_GPIO_BASE                        0x6000D000
 #define TEGRA_I2C3_BASE                        0x7000C500
 #define TEGRA_I2C3_SIZE                        SZ_256
 
-#define TEGRA_OWR_BASE                 0x7000D000
+#define TEGRA_OWR_BASE                 0x7000C600
 #define TEGRA_OWR_SIZE                 80
 
 #define TEGRA_DVC_BASE                 0x7000D000
 #define TEGRA_USB_BASE                 0xC5000000
 #define TEGRA_USB_SIZE                 SZ_16K
 
-#define TEGRA_USB1_BASE                        0xC5004000
-#define TEGRA_USB1_SIZE                        SZ_16K
-
-#define TEGRA_USB2_BASE                        0xC5008000
+#define TEGRA_USB2_BASE                        0xC5004000
 #define TEGRA_USB2_SIZE                        SZ_16K
 
+#define TEGRA_USB3_BASE                        0xC5008000
+#define TEGRA_USB3_SIZE                        SZ_16K
+
 #define TEGRA_SDMMC1_BASE              0xC8000000
 #define TEGRA_SDMMC1_SIZE              SZ_512
 
index 20f640edaa0d31e0247681db1dc68ca53125cb79..71bbf34229538e87b81d0bca740eeb952c712bd4 100644 (file)
@@ -25,6 +25,7 @@
 
 #define IRQ_LOCALTIMER                  29
 
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 /* Primary Interrupt Controller */
 #define INT_PRI_BASE                   (INT_GIC_BASE + 32)
 #define INT_TMR1                       (INT_PRI_BASE + 0)
 #define INT_GPIO_NR                    (28 * 8)
 
 #define NR_IRQS                                (INT_GPIO_BASE + INT_GPIO_NR)
+#endif
 
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
new file mode 100644 (file)
index 0000000..db1eb3d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-tegra/include/mach/legacy_irq.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+
+void tegra_legacy_mask_irq(unsigned int irq);
+void tegra_legacy_unmask_irq(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+void tegra_legacy_force_irq_set(unsigned int irq);
+void tegra_legacy_force_irq_clr(unsigned int irq);
+int tegra_legacy_force_irq_status(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+unsigned long tegra_legacy_vfiq(int nr);
+unsigned long tegra_legacy_class(int nr);
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-t2.h b/arch/arm/mach-tegra/include/mach/pinmux-t2.h
new file mode 100644 (file)
index 0000000..e5b9d74
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * linux/arch/arm/mach-tegra/include/mach/pinmux-t2.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PINMUX_T2_H
+#define __MACH_TEGRA_PINMUX_T2_H
+
+enum tegra_pingroup {
+       TEGRA_PINGROUP_ATA = 0,
+       TEGRA_PINGROUP_ATB,
+       TEGRA_PINGROUP_ATC,
+       TEGRA_PINGROUP_ATD,
+       TEGRA_PINGROUP_ATE,
+       TEGRA_PINGROUP_CDEV1,
+       TEGRA_PINGROUP_CDEV2,
+       TEGRA_PINGROUP_CRTP,
+       TEGRA_PINGROUP_CSUS,
+       TEGRA_PINGROUP_DAP1,
+       TEGRA_PINGROUP_DAP2,
+       TEGRA_PINGROUP_DAP3,
+       TEGRA_PINGROUP_DAP4,
+       TEGRA_PINGROUP_DDC,
+       TEGRA_PINGROUP_DTA,
+       TEGRA_PINGROUP_DTB,
+       TEGRA_PINGROUP_DTC,
+       TEGRA_PINGROUP_DTD,
+       TEGRA_PINGROUP_DTE,
+       TEGRA_PINGROUP_DTF,
+       TEGRA_PINGROUP_GMA,
+       TEGRA_PINGROUP_GMB,
+       TEGRA_PINGROUP_GMC,
+       TEGRA_PINGROUP_GMD,
+       TEGRA_PINGROUP_GME,
+       TEGRA_PINGROUP_GPU,
+       TEGRA_PINGROUP_GPU7,
+       TEGRA_PINGROUP_GPV,
+       TEGRA_PINGROUP_HDINT,
+       TEGRA_PINGROUP_I2CP,
+       TEGRA_PINGROUP_IRRX,
+       TEGRA_PINGROUP_IRTX,
+       TEGRA_PINGROUP_KBCA,
+       TEGRA_PINGROUP_KBCB,
+       TEGRA_PINGROUP_KBCC,
+       TEGRA_PINGROUP_KBCD,
+       TEGRA_PINGROUP_KBCE,
+       TEGRA_PINGROUP_KBCF,
+       TEGRA_PINGROUP_LCSN,
+       TEGRA_PINGROUP_LD0,
+       TEGRA_PINGROUP_LD1,
+       TEGRA_PINGROUP_LD10,
+       TEGRA_PINGROUP_LD11,
+       TEGRA_PINGROUP_LD12,
+       TEGRA_PINGROUP_LD13,
+       TEGRA_PINGROUP_LD14,
+       TEGRA_PINGROUP_LD15,
+       TEGRA_PINGROUP_LD16,
+       TEGRA_PINGROUP_LD17,
+       TEGRA_PINGROUP_LD2,
+       TEGRA_PINGROUP_LD3,
+       TEGRA_PINGROUP_LD4,
+       TEGRA_PINGROUP_LD5,
+       TEGRA_PINGROUP_LD6,
+       TEGRA_PINGROUP_LD7,
+       TEGRA_PINGROUP_LD8,
+       TEGRA_PINGROUP_LD9,
+       TEGRA_PINGROUP_LDC,
+       TEGRA_PINGROUP_LDI,
+       TEGRA_PINGROUP_LHP0,
+       TEGRA_PINGROUP_LHP1,
+       TEGRA_PINGROUP_LHP2,
+       TEGRA_PINGROUP_LHS,
+       TEGRA_PINGROUP_LM0,
+       TEGRA_PINGROUP_LM1,
+       TEGRA_PINGROUP_LPP,
+       TEGRA_PINGROUP_LPW0,
+       TEGRA_PINGROUP_LPW1,
+       TEGRA_PINGROUP_LPW2,
+       TEGRA_PINGROUP_LSC0,
+       TEGRA_PINGROUP_LSC1,
+       TEGRA_PINGROUP_LSCK,
+       TEGRA_PINGROUP_LSDA,
+       TEGRA_PINGROUP_LSDI,
+       TEGRA_PINGROUP_LSPI,
+       TEGRA_PINGROUP_LVP0,
+       TEGRA_PINGROUP_LVP1,
+       TEGRA_PINGROUP_LVS,
+       TEGRA_PINGROUP_OWC,
+       TEGRA_PINGROUP_PMC,
+       TEGRA_PINGROUP_PTA,
+       TEGRA_PINGROUP_RM,
+       TEGRA_PINGROUP_SDB,
+       TEGRA_PINGROUP_SDC,
+       TEGRA_PINGROUP_SDD,
+       TEGRA_PINGROUP_SDIO1,
+       TEGRA_PINGROUP_SLXA,
+       TEGRA_PINGROUP_SLXC,
+       TEGRA_PINGROUP_SLXD,
+       TEGRA_PINGROUP_SLXK,
+       TEGRA_PINGROUP_SPDI,
+       TEGRA_PINGROUP_SPDO,
+       TEGRA_PINGROUP_SPIA,
+       TEGRA_PINGROUP_SPIB,
+       TEGRA_PINGROUP_SPIC,
+       TEGRA_PINGROUP_SPID,
+       TEGRA_PINGROUP_SPIE,
+       TEGRA_PINGROUP_SPIF,
+       TEGRA_PINGROUP_SPIG,
+       TEGRA_PINGROUP_SPIH,
+       TEGRA_PINGROUP_UAA,
+       TEGRA_PINGROUP_UAB,
+       TEGRA_PINGROUP_UAC,
+       TEGRA_PINGROUP_UAD,
+       TEGRA_PINGROUP_UCA,
+       TEGRA_PINGROUP_UCB,
+       TEGRA_PINGROUP_UDA,
+       /* these pin groups only have pullup and pull down control */
+       TEGRA_PINGROUP_CK32,
+       TEGRA_PINGROUP_DDRC,
+       TEGRA_PINGROUP_PMCA,
+       TEGRA_PINGROUP_PMCB,
+       TEGRA_PINGROUP_PMCC,
+       TEGRA_PINGROUP_PMCD,
+       TEGRA_PINGROUP_PMCE,
+       TEGRA_PINGROUP_XM2C,
+       TEGRA_PINGROUP_XM2D,
+       TEGRA_MAX_PINGROUP,
+};
+
+enum tegra_drive_pingroup {
+       TEGRA_DRIVE_PINGROUP_AO1 = 0,
+       TEGRA_DRIVE_PINGROUP_AO2,
+       TEGRA_DRIVE_PINGROUP_AT1,
+       TEGRA_DRIVE_PINGROUP_AT2,
+       TEGRA_DRIVE_PINGROUP_CDEV1,
+       TEGRA_DRIVE_PINGROUP_CDEV2,
+       TEGRA_DRIVE_PINGROUP_CSUS,
+       TEGRA_DRIVE_PINGROUP_DAP1,
+       TEGRA_DRIVE_PINGROUP_DAP2,
+       TEGRA_DRIVE_PINGROUP_DAP3,
+       TEGRA_DRIVE_PINGROUP_DAP4,
+       TEGRA_DRIVE_PINGROUP_DBG,
+       TEGRA_DRIVE_PINGROUP_LCD1,
+       TEGRA_DRIVE_PINGROUP_LCD2,
+       TEGRA_DRIVE_PINGROUP_SDMMC2,
+       TEGRA_DRIVE_PINGROUP_SDMMC3,
+       TEGRA_DRIVE_PINGROUP_SPI,
+       TEGRA_DRIVE_PINGROUP_UAA,
+       TEGRA_DRIVE_PINGROUP_UAB,
+       TEGRA_DRIVE_PINGROUP_UART2,
+       TEGRA_DRIVE_PINGROUP_UART3,
+       TEGRA_DRIVE_PINGROUP_VI1,
+       TEGRA_DRIVE_PINGROUP_VI2,
+       TEGRA_DRIVE_PINGROUP_XM2A,
+       TEGRA_DRIVE_PINGROUP_XM2C,
+       TEGRA_DRIVE_PINGROUP_XM2D,
+       TEGRA_DRIVE_PINGROUP_XM2CLK,
+       TEGRA_DRIVE_PINGROUP_MEMCOMP,
+       TEGRA_MAX_DRIVE_PINGROUP,
+};
+
+#endif
+
index 41c8ce5b7c27564b7621397a86fe0b2722a1e48f..defd8775defa04d18f66cbe3b7106811a2c0fcd2 100644 (file)
 #ifndef __MACH_TEGRA_PINMUX_H
 #define __MACH_TEGRA_PINMUX_H
 
-enum tegra_pingroup {
-       TEGRA_PINGROUP_ATA = 0,
-       TEGRA_PINGROUP_ATB,
-       TEGRA_PINGROUP_ATC,
-       TEGRA_PINGROUP_ATD,
-       TEGRA_PINGROUP_ATE,
-       TEGRA_PINGROUP_CDEV1,
-       TEGRA_PINGROUP_CDEV2,
-       TEGRA_PINGROUP_CRTP,
-       TEGRA_PINGROUP_CSUS,
-       TEGRA_PINGROUP_DAP1,
-       TEGRA_PINGROUP_DAP2,
-       TEGRA_PINGROUP_DAP3,
-       TEGRA_PINGROUP_DAP4,
-       TEGRA_PINGROUP_DDC,
-       TEGRA_PINGROUP_DTA,
-       TEGRA_PINGROUP_DTB,
-       TEGRA_PINGROUP_DTC,
-       TEGRA_PINGROUP_DTD,
-       TEGRA_PINGROUP_DTE,
-       TEGRA_PINGROUP_DTF,
-       TEGRA_PINGROUP_GMA,
-       TEGRA_PINGROUP_GMB,
-       TEGRA_PINGROUP_GMC,
-       TEGRA_PINGROUP_GMD,
-       TEGRA_PINGROUP_GME,
-       TEGRA_PINGROUP_GPU,
-       TEGRA_PINGROUP_GPU7,
-       TEGRA_PINGROUP_GPV,
-       TEGRA_PINGROUP_HDINT,
-       TEGRA_PINGROUP_I2CP,
-       TEGRA_PINGROUP_IRRX,
-       TEGRA_PINGROUP_IRTX,
-       TEGRA_PINGROUP_KBCA,
-       TEGRA_PINGROUP_KBCB,
-       TEGRA_PINGROUP_KBCC,
-       TEGRA_PINGROUP_KBCD,
-       TEGRA_PINGROUP_KBCE,
-       TEGRA_PINGROUP_KBCF,
-       TEGRA_PINGROUP_LCSN,
-       TEGRA_PINGROUP_LD0,
-       TEGRA_PINGROUP_LD1,
-       TEGRA_PINGROUP_LD10,
-       TEGRA_PINGROUP_LD11,
-       TEGRA_PINGROUP_LD12,
-       TEGRA_PINGROUP_LD13,
-       TEGRA_PINGROUP_LD14,
-       TEGRA_PINGROUP_LD15,
-       TEGRA_PINGROUP_LD16,
-       TEGRA_PINGROUP_LD17,
-       TEGRA_PINGROUP_LD2,
-       TEGRA_PINGROUP_LD3,
-       TEGRA_PINGROUP_LD4,
-       TEGRA_PINGROUP_LD5,
-       TEGRA_PINGROUP_LD6,
-       TEGRA_PINGROUP_LD7,
-       TEGRA_PINGROUP_LD8,
-       TEGRA_PINGROUP_LD9,
-       TEGRA_PINGROUP_LDC,
-       TEGRA_PINGROUP_LDI,
-       TEGRA_PINGROUP_LHP0,
-       TEGRA_PINGROUP_LHP1,
-       TEGRA_PINGROUP_LHP2,
-       TEGRA_PINGROUP_LHS,
-       TEGRA_PINGROUP_LM0,
-       TEGRA_PINGROUP_LM1,
-       TEGRA_PINGROUP_LPP,
-       TEGRA_PINGROUP_LPW0,
-       TEGRA_PINGROUP_LPW1,
-       TEGRA_PINGROUP_LPW2,
-       TEGRA_PINGROUP_LSC0,
-       TEGRA_PINGROUP_LSC1,
-       TEGRA_PINGROUP_LSCK,
-       TEGRA_PINGROUP_LSDA,
-       TEGRA_PINGROUP_LSDI,
-       TEGRA_PINGROUP_LSPI,
-       TEGRA_PINGROUP_LVP0,
-       TEGRA_PINGROUP_LVP1,
-       TEGRA_PINGROUP_LVS,
-       TEGRA_PINGROUP_OWC,
-       TEGRA_PINGROUP_PMC,
-       TEGRA_PINGROUP_PTA,
-       TEGRA_PINGROUP_RM,
-       TEGRA_PINGROUP_SDB,
-       TEGRA_PINGROUP_SDC,
-       TEGRA_PINGROUP_SDD,
-       TEGRA_PINGROUP_SDIO1,
-       TEGRA_PINGROUP_SLXA,
-       TEGRA_PINGROUP_SLXC,
-       TEGRA_PINGROUP_SLXD,
-       TEGRA_PINGROUP_SLXK,
-       TEGRA_PINGROUP_SPDI,
-       TEGRA_PINGROUP_SPDO,
-       TEGRA_PINGROUP_SPIA,
-       TEGRA_PINGROUP_SPIB,
-       TEGRA_PINGROUP_SPIC,
-       TEGRA_PINGROUP_SPID,
-       TEGRA_PINGROUP_SPIE,
-       TEGRA_PINGROUP_SPIF,
-       TEGRA_PINGROUP_SPIG,
-       TEGRA_PINGROUP_SPIH,
-       TEGRA_PINGROUP_UAA,
-       TEGRA_PINGROUP_UAB,
-       TEGRA_PINGROUP_UAC,
-       TEGRA_PINGROUP_UAD,
-       TEGRA_PINGROUP_UCA,
-       TEGRA_PINGROUP_UCB,
-       TEGRA_PINGROUP_UDA,
-       /* these pin groups only have pullup and pull down control */
-       TEGRA_PINGROUP_CK32,
-       TEGRA_PINGROUP_DDRC,
-       TEGRA_PINGROUP_PMCA,
-       TEGRA_PINGROUP_PMCB,
-       TEGRA_PINGROUP_PMCC,
-       TEGRA_PINGROUP_PMCD,
-       TEGRA_PINGROUP_PMCE,
-       TEGRA_PINGROUP_XM2C,
-       TEGRA_PINGROUP_XM2D,
-       TEGRA_MAX_PINGROUP,
-};
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#include "pinmux-t2.h"
+#else
+#error "Undefined Tegra architecture"
+#endif
 
 enum tegra_mux_func {
        TEGRA_MUX_RSVD = 0x8000,
@@ -205,6 +90,7 @@ enum tegra_mux_func {
        TEGRA_MUX_VI,
        TEGRA_MUX_VI_SENSOR_CLK,
        TEGRA_MUX_XIO,
+       TEGRA_MUX_SAFE,
        TEGRA_MAX_MUX,
 };
 
@@ -219,6 +105,18 @@ enum tegra_tristate {
        TEGRA_TRI_TRISTATE = 1,
 };
 
+enum tegra_vddio {
+       TEGRA_VDDIO_BB = 0,
+       TEGRA_VDDIO_LCD,
+       TEGRA_VDDIO_VI,
+       TEGRA_VDDIO_UART,
+       TEGRA_VDDIO_DDR,
+       TEGRA_VDDIO_NAND,
+       TEGRA_VDDIO_SYS,
+       TEGRA_VDDIO_AUDIO,
+       TEGRA_VDDIO_SD,
+};
+
 struct tegra_pingroup_config {
        enum tegra_pingroup     pingroup;
        enum tegra_mux_func     func;
@@ -270,38 +168,6 @@ enum tegra_pull_strength {
        TEGRA_MAX_PULL,
 };
 
-enum tegra_drive_pingroup {
-       TEGRA_DRIVE_PINGROUP_AO1 = 0,
-       TEGRA_DRIVE_PINGROUP_AO2,
-       TEGRA_DRIVE_PINGROUP_AT1,
-       TEGRA_DRIVE_PINGROUP_AT2,
-       TEGRA_DRIVE_PINGROUP_CDEV1,
-       TEGRA_DRIVE_PINGROUP_CDEV2,
-       TEGRA_DRIVE_PINGROUP_CSUS,
-       TEGRA_DRIVE_PINGROUP_DAP1,
-       TEGRA_DRIVE_PINGROUP_DAP2,
-       TEGRA_DRIVE_PINGROUP_DAP3,
-       TEGRA_DRIVE_PINGROUP_DAP4,
-       TEGRA_DRIVE_PINGROUP_DBG,
-       TEGRA_DRIVE_PINGROUP_LCD1,
-       TEGRA_DRIVE_PINGROUP_LCD2,
-       TEGRA_DRIVE_PINGROUP_SDMMC2,
-       TEGRA_DRIVE_PINGROUP_SDMMC3,
-       TEGRA_DRIVE_PINGROUP_SPI,
-       TEGRA_DRIVE_PINGROUP_UAA,
-       TEGRA_DRIVE_PINGROUP_UAB,
-       TEGRA_DRIVE_PINGROUP_UART2,
-       TEGRA_DRIVE_PINGROUP_UART3,
-       TEGRA_DRIVE_PINGROUP_VI1,
-       TEGRA_DRIVE_PINGROUP_VI2,
-       TEGRA_DRIVE_PINGROUP_XM2A,
-       TEGRA_DRIVE_PINGROUP_XM2C,
-       TEGRA_DRIVE_PINGROUP_XM2D,
-       TEGRA_DRIVE_PINGROUP_XM2CLK,
-       TEGRA_DRIVE_PINGROUP_MEMCOMP,
-       TEGRA_MAX_DRIVE_PINGROUP,
-};
-
 enum tegra_drive {
        TEGRA_DRIVE_DIV_8 = 0,
        TEGRA_DRIVE_DIV_4,
@@ -331,18 +197,44 @@ struct tegra_drive_pingroup_config {
        enum tegra_slew slew_falling;
 };
 
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func);
-int tegra_pinmux_set_tristate(enum tegra_pingroup pg, enum tegra_tristate tristate);
-int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg, enum tegra_pullupdown pupd);
+struct tegra_drive_pingroup_desc {
+       const char *name;
+       s16 reg;
+};
+
+struct tegra_pingroup_desc {
+       const char *name;
+       int funcs[4];
+       int func_safe;
+       int vddio;
+       s16 tri_reg;    /* offset into the TRISTATE_REG_* register bank */
+       s16 mux_reg;    /* offset into the PIN_MUX_CTL_* register bank */
+       s16 pupd_reg;   /* offset into the PULL_UPDOWN_REG_* register bank */
+       s8 tri_bit;     /* offset into the TRISTATE_REG_* register bit */
+       s8 mux_bit;     /* offset into the PIN_MUX_CTL_* register bit */
+       s8 pupd_bit;    /* offset into the PULL_UPDOWN_REG_* register bit */
+};
+
+extern const struct tegra_pingroup_desc tegra_soc_pingroups[];
+extern const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[];
 
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
-       enum tegra_mux_func func, enum tegra_pullupdown pupd,
+int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
        enum tegra_tristate tristate);
+int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
+       enum tegra_pullupdown pupd);
 
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len);
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config,
+       int len);
 
 void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
        int len);
-
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+       int len);
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+       int len);
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+       int len, enum tegra_tristate tristate);
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+       int len, enum tegra_pullupdown pupd);
 #endif
 
index 9fe2c5c683d471e96e794a86be2061d9a46694a8..31848a9592f8770d3df1d28301913b2a8ffb52cc 100644 (file)
@@ -49,6 +49,12 @@ static struct map_desc tegra_io_desc[] __initdata = {
                .length = IO_CPU_SIZE,
                .type = MT_DEVICE,
        },
+       {
+               .virtual = IO_IRAM_VIRT,
+               .pfn = __phys_to_pfn(IO_IRAM_PHYS),
+               .length = IO_IRAM_SIZE,
+               .type = MT_DEVICE,
+       },
 };
 
 void __init tegra_map_common_io(void)
index 1fdbe708d43d12b5bc73ddf1c553461700932677..50a8dfb9a0cfe8cbb1dbdaeb8a913d5858000902 100644 (file)
@@ -4,6 +4,8 @@
  * Author:
  *     Colin Cross <ccross@google.com>
  *
+ * Copyright (C) 2010, NVIDIA Corporation
+ *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
 
 #include "board.h"
 
+#define INT_SYS_NR     (INT_GPIO_BASE - INT_PRI_BASE)
+#define INT_SYS_SZ     (INT_SEC_BASE - INT_PRI_BASE)
+#define PPI_NR         ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
+
+#define APBDMA_IRQ_STA_CPU  0x14
+#define APBDMA_IRQ_MASK_SET 0x20
+#define APBDMA_IRQ_MASK_CLR 0x24
+
+#define ICTLR_CPU_IER          0x20
+#define ICTLR_CPU_IER_SET      0x24
+#define ICTLR_CPU_IER_CLR      0x28
+#define ICTLR_CPU_IEP_CLASS    0x2c
+#define ICTLR_COP_IER          0x30
+#define ICTLR_COP_IER_SET      0x34
+#define ICTLR_COP_IER_CLR      0x38
+#define ICTLR_COP_IEP_CLASS    0x3c
+
+static void (*gic_mask_irq)(unsigned int irq);
+static void (*gic_unmask_irq)(unsigned int irq);
+
+#define irq_to_ictlr(irq) (((irq)-32) >> 5)
+static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
+#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
+
+static void tegra_mask(unsigned int irq)
+{
+       void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+       gic_mask_irq(irq);
+       writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR);
+}
+
+static void tegra_unmask(unsigned int irq)
+{
+       void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+       gic_unmask_irq(irq);
+       writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET);
+}
+
+#ifdef CONFIG_PM
+
+static int tegra_set_wake(unsigned int irq, unsigned int on)
+{
+       return 0;
+}
+#endif
+
+static struct irq_chip tegra_irq = {
+       .name           = "PPI",
+       .mask           = tegra_mask,
+       .unmask         = tegra_unmask,
+#ifdef CONFIG_PM
+       .set_wake       = tegra_set_wake,
+#endif
+};
+
 void __init tegra_init_irq(void)
 {
+       struct irq_chip *gic;
+       unsigned int i;
+
+       for (i = 0; i < PPI_NR; i++) {
+               writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
+               writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
+       }
+
        gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29);
        gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
+
+       gic = get_irq_chip(29);
+       gic_unmask_irq = gic->unmask;
+       gic_mask_irq = gic->mask;
+       tegra_irq.ack = gic->ack;
+#ifdef CONFIG_SMP
+       tegra_irq.set_affinity = gic->set_affinity;
+#endif
+
+       for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+               set_irq_chip(i, &tegra_irq);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+}
+
+#ifdef CONFIG_PM
+static u32 cop_ier[PPI_NR];
+static u32 cpu_ier[PPI_NR];
+static u32 cpu_iep[PPI_NR];
+
+void tegra_irq_suspend(void)
+{
+       unsigned long flags;
+       int i;
+
+       for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+               if (!desc)
+                       continue;
+               if (desc->status & IRQ_WAKEUP) {
+                       pr_debug("irq %d is wakeup\n", i);
+                       continue;
+               }
+               disable_irq(i);
+       }
+
+       local_irq_save(flags);
+       for (i = 0; i < PPI_NR; i++) {
+               void __iomem *ictlr = ictlr_to_virt(i);
+               cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
+               cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
+               cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
+               writel(~0, ictlr + ICTLR_COP_IER_CLR);
+       }
+       local_irq_restore(flags);
+}
+
+void tegra_irq_resume(void)
+{
+       unsigned long flags;
+       int i;
+
+       local_irq_save(flags);
+       for (i = 0; i < PPI_NR; i++) {
+               void __iomem *ictlr = ictlr_to_virt(i);
+               writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
+               writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+               writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
+               writel(0, ictlr + ICTLR_COP_IEP_CLASS);
+               writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
+               writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
+       }
+       local_irq_restore(flags);
+
+       for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+               if (!desc || (desc->status & IRQ_WAKEUP))
+                       continue;
+               enable_irq(i);
+       }
 }
+#endif
diff --git a/arch/arm/mach-tegra/legacy_irq.c b/arch/arm/mach-tegra/legacy_irq.c
new file mode 100644 (file)
index 0000000..7cc8601
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * arch/arm/mach-tegra/legacy_irq.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
+
+#define ICTLR_CPU_IER          0x20
+#define ICTLR_CPU_IER_SET      0x24
+#define ICTLR_CPU_IER_CLR      0x28
+#define ICTLR_CPU_IEP_CLASS    0x2C
+#define ICTLR_CPU_IEP_VFIQ     0x08
+#define ICTLR_CPU_IEP_FIR      0x14
+#define ICTLR_CPU_IEP_FIR_SET  0x18
+#define ICTLR_CPU_IEP_FIR_CLR  0x1c
+
+static void __iomem *ictlr_reg_base[] = {
+       IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
+       IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
+       IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
+       IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+};
+
+/* When going into deep sleep, the CPU is powered down, taking the GIC with it
+   In order to wake, the wake interrupts need to be enabled in the legacy
+   interrupt controller. */
+void tegra_legacy_unmask_irq(unsigned int irq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       writel(1 << (irq & 31), base + ICTLR_CPU_IER_SET);
+}
+
+void tegra_legacy_mask_irq(unsigned int irq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       writel(1 << (irq & 31), base + ICTLR_CPU_IER_CLR);
+}
+
+void tegra_legacy_force_irq_set(unsigned int irq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_SET);
+}
+
+void tegra_legacy_force_irq_clr(unsigned int irq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_CLR);
+}
+
+int tegra_legacy_force_irq_status(unsigned int irq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       return !!(readl(base + ICTLR_CPU_IEP_FIR) & (1 << (irq & 31)));
+}
+
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq)
+{
+       void __iomem *base;
+       pr_debug("%s: %d\n", __func__, irq);
+
+       irq -= 32;
+       base = ictlr_reg_base[irq>>5];
+       writel(fiq << (irq & 31), base + ICTLR_CPU_IEP_CLASS);
+}
+
+unsigned long tegra_legacy_vfiq(int nr)
+{
+       void __iomem *base;
+       base = ictlr_reg_base[nr];
+       return readl(base + ICTLR_CPU_IEP_VFIQ);
+}
+
+unsigned long tegra_legacy_class(int nr)
+{
+       void __iomem *base;
+       base = ictlr_reg_base[nr];
+       return readl(base + ICTLR_CPU_IEP_CLASS);
+}
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
new file mode 100644 (file)
index 0000000..53f5fa3
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * arch/arm/mach-tegra/pci.c
+ *
+ * PCIe host controller driver for TEGRA(2) SOCs
+ *
+ * Copyright (c) 2010, CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on NVIDIA PCIe driver
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * Bits taken from arch/arm/mach-dove/pcie.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <asm/sizes.h>
+#include <asm/mach/pci.h>
+
+#include <mach/pinmux.h>
+#include <mach/iomap.h>
+#include <mach/clk.h>
+
+/* register definitions */
+#define AFI_OFFSET     0x3800
+#define PADS_OFFSET    0x3000
+#define RP0_OFFSET     0x0000
+#define RP1_OFFSET     0x1000
+
+#define AFI_AXI_BAR0_SZ        0x00
+#define AFI_AXI_BAR1_SZ        0x04
+#define AFI_AXI_BAR2_SZ        0x08
+#define AFI_AXI_BAR3_SZ        0x0c
+#define AFI_AXI_BAR4_SZ        0x10
+#define AFI_AXI_BAR5_SZ        0x14
+
+#define AFI_AXI_BAR0_START     0x18
+#define AFI_AXI_BAR1_START     0x1c
+#define AFI_AXI_BAR2_START     0x20
+#define AFI_AXI_BAR3_START     0x24
+#define AFI_AXI_BAR4_START     0x28
+#define AFI_AXI_BAR5_START     0x2c
+
+#define AFI_FPCI_BAR0  0x30
+#define AFI_FPCI_BAR1  0x34
+#define AFI_FPCI_BAR2  0x38
+#define AFI_FPCI_BAR3  0x3c
+#define AFI_FPCI_BAR4  0x40
+#define AFI_FPCI_BAR5  0x44
+
+#define AFI_CACHE_BAR0_SZ      0x48
+#define AFI_CACHE_BAR0_ST      0x4c
+#define AFI_CACHE_BAR1_SZ      0x50
+#define AFI_CACHE_BAR1_ST      0x54
+
+#define AFI_MSI_BAR_SZ         0x60
+#define AFI_MSI_FPCI_BAR_ST    0x64
+#define AFI_MSI_AXI_BAR_ST     0x68
+
+#define AFI_CONFIGURATION              0xac
+#define  AFI_CONFIGURATION_EN_FPCI     (1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS   0xb0
+
+#define AFI_INTR_MASK          0xb4
+#define  AFI_INTR_MASK_INT_MASK        (1 << 0)
+#define  AFI_INTR_MASK_MSI_MASK        (1 << 8)
+
+#define AFI_INTR_CODE          0xb8
+#define  AFI_INTR_CODE_MASK    0xf
+#define  AFI_INTR_MASTER_ABORT 4
+#define  AFI_INTR_LEGACY       6
+
+#define AFI_INTR_SIGNATURE     0xbc
+#define AFI_SM_INTR_ENABLE     0xc4
+
+#define AFI_AFI_INTR_ENABLE            0xc8
+#define  AFI_INTR_EN_INI_SLVERR                (1 << 0)
+#define  AFI_INTR_EN_INI_DECERR                (1 << 1)
+#define  AFI_INTR_EN_TGT_SLVERR                (1 << 2)
+#define  AFI_INTR_EN_TGT_DECERR                (1 << 3)
+#define  AFI_INTR_EN_TGT_WRERR         (1 << 4)
+#define  AFI_INTR_EN_DFPCI_DECERR      (1 << 5)
+#define  AFI_INTR_EN_AXI_DECERR                (1 << 6)
+#define  AFI_INTR_EN_FPCI_TIMEOUT      (1 << 7)
+
+#define AFI_PCIE_CONFIG                                        0x0f8
+#define  AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE         (1 << 1)
+#define  AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE         (1 << 2)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK      (0xf << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE    (0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL      (0x1 << 20)
+
+#define AFI_FUSE                       0x104
+#define  AFI_FUSE_PCIE_T0_GEN2_DIS     (1 << 2)
+
+#define AFI_PEX0_CTRL                  0x110
+#define AFI_PEX1_CTRL                  0x118
+#define  AFI_PEX_CTRL_RST              (1 << 0)
+#define  AFI_PEX_CTRL_REFCLK_EN                (1 << 3)
+
+#define RP_VEND_XP     0x00000F00
+#define  RP_VEND_XP_DL_UP      (1 << 30)
+
+#define RP_LINK_CONTROL_STATUS                 0x00000090
+#define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK  0x3fff0000
+
+#define PADS_CTL_SEL           0x0000009C
+
+#define PADS_CTL               0x000000A0
+#define  PADS_CTL_IDDQ_1L      (1 << 0)
+#define  PADS_CTL_TX_DATA_EN_1L        (1 << 6)
+#define  PADS_CTL_RX_DATA_EN_1L        (1 << 10)
+
+#define PADS_PLL_CTL                           0x000000B8
+#define  PADS_PLL_CTL_RST_B4SM                 (1 << 1)
+#define  PADS_PLL_CTL_LOCKDET                  (1 << 8)
+#define  PADS_PLL_CTL_REFCLK_MASK              (0x3 << 16)
+#define  PADS_PLL_CTL_REFCLK_INTERNAL_CML      (0 << 16)
+#define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS     (1 << 16)
+#define  PADS_PLL_CTL_REFCLK_EXTERNAL          (2 << 16)
+#define  PADS_PLL_CTL_TXCLKREF_MASK            (0x1 << 20)
+#define  PADS_PLL_CTL_TXCLKREF_DIV10           (0 << 20)
+#define  PADS_PLL_CTL_TXCLKREF_DIV5            (1 << 20)
+
+/* PMC access is required for PCIE xclk (un)clamping */
+#define PMC_SCRATCH42          0x144
+#define PMC_SCRATCH42_PCX_CLAMP        (1 << 0)
+
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+#define pmc_writel(value, reg) \
+       __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+       __raw_readl((u32)reg_pmc_base + (reg))
+
+/*
+ * Tegra2 defines 1GB in the AXI address map for PCIe.
+ *
+ * That address space is split into different regions, with sizes and
+ * offsets as follows:
+ *
+ * 0x80000000 - 0x80003fff - PCI controller registers
+ * 0x80004000 - 0x80103fff - PCI configuration space
+ * 0x80104000 - 0x80203fff - PCI extended configuration space
+ * 0x80203fff - 0x803fffff - unused
+ * 0x80400000 - 0x8040ffff - downstream IO
+ * 0x80410000 - 0x8fffffff - unused
+ * 0x90000000 - 0x9fffffff - non-prefetchable memory
+ * 0xa0000000 - 0xbfffffff - prefetchable memory
+ */
+#define TEGRA_PCIE_BASE                0x80000000
+
+#define PCIE_REGS_SZ           SZ_16K
+#define PCIE_CFG_OFF           PCIE_REGS_SZ
+#define PCIE_CFG_SZ            SZ_1M
+#define PCIE_EXT_CFG_OFF       (PCIE_CFG_SZ + PCIE_CFG_OFF)
+#define PCIE_EXT_CFG_SZ                SZ_1M
+#define PCIE_IOMAP_SZ          (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
+
+#define MMIO_BASE              (TEGRA_PCIE_BASE + SZ_4M)
+#define MMIO_SIZE              SZ_64K
+#define MEM_BASE_0             (TEGRA_PCIE_BASE + SZ_256M)
+#define MEM_SIZE_0             SZ_128M
+#define MEM_BASE_1             (MEM_BASE_0 + MEM_SIZE_0)
+#define MEM_SIZE_1             SZ_128M
+#define PREFETCH_MEM_BASE_0    (MEM_BASE_1 + MEM_SIZE_1)
+#define PREFETCH_MEM_SIZE_0    SZ_128M
+#define PREFETCH_MEM_BASE_1    (PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
+#define PREFETCH_MEM_SIZE_1    SZ_128M
+
+#define  PCIE_CONF_BUS(b)      ((b) << 16)
+#define  PCIE_CONF_DEV(d)      ((d) << 11)
+#define  PCIE_CONF_FUNC(f)     ((f) << 8)
+#define  PCIE_CONF_REG(r)      \
+       (((r) & ~0x3) | (((r) < 256) ? PCIE_CFG_OFF : PCIE_EXT_CFG_OFF))
+
+struct tegra_pcie_port {
+       int                     index;
+       u8                      root_bus_nr;
+       void __iomem            *base;
+
+       bool                    link_up;
+
+       char                    io_space_name[16];
+       char                    mem_space_name[16];
+       char                    prefetch_space_name[20];
+       struct resource         res[3];
+};
+
+struct tegra_pcie_info {
+       struct tegra_pcie_port  port[2];
+       int                     num_ports;
+
+       void __iomem            *regs;
+       struct resource         res_mmio;
+
+       struct clk              *pex_clk;
+       struct clk              *afi_clk;
+       struct clk              *pcie_xclk;
+       struct clk              *pll_e;
+};
+
+static struct tegra_pcie_info tegra_pcie = {
+       .res_mmio = {
+               .name = "PCI IO",
+               .start = MMIO_BASE,
+               .end = MMIO_BASE + MMIO_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+void __iomem *tegra_pcie_io_base;
+EXPORT_SYMBOL(tegra_pcie_io_base);
+
+static inline void afi_writel(u32 value, unsigned long offset)
+{
+       writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 afi_readl(unsigned long offset)
+{
+       return readl(offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline void pads_writel(u32 value, unsigned long offset)
+{
+       writel(value, offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 pads_readl(unsigned long offset)
+{
+       return readl(offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static struct tegra_pcie_port *bus_to_port(int bus)
+{
+       int i;
+
+       for (i = tegra_pcie.num_ports - 1; i >= 0; i--) {
+               int rbus = tegra_pcie.port[i].root_bus_nr;
+               if (rbus != -1 && rbus == bus)
+                       break;
+       }
+
+       return i >= 0 ? tegra_pcie.port + i : NULL;
+}
+
+static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+                               int where, int size, u32 *val)
+{
+       struct tegra_pcie_port *pp = bus_to_port(bus->number);
+       void __iomem *addr;
+
+       if (pp) {
+               if (devfn != 0) {
+                       *val = 0xffffffff;
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               }
+
+               addr = pp->base + (where & ~0x3);
+       } else {
+               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+                                         PCIE_CONF_REG(where));
+       }
+
+       *val = readl(addr);
+
+       if (size == 1)
+               *val = (*val >> (8 * (where & 3))) & 0xff;
+       else if (size == 2)
+               *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 val)
+{
+       struct tegra_pcie_port *pp = bus_to_port(bus->number);
+       void __iomem *addr;
+
+       u32 mask;
+       u32 tmp;
+
+       if (pp) {
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+               addr = pp->base + (where & ~0x3);
+       } else {
+               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+                                         PCIE_CONF_REG(where));
+       }
+
+       if (size == 4) {
+               writel(val, addr);
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       if (size == 2)
+               mask = ~(0xffff << ((where & 0x3) * 8));
+       else if (size == 1)
+               mask = ~(0xff << ((where & 0x3) * 8));
+       else
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       tmp = readl(addr) & mask;
+       tmp |= val << ((where & 0x3) * 8);
+       writel(tmp, addr);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops tegra_pcie_ops = {
+       .read   = tegra_pcie_read_conf,
+       .write  = tegra_pcie_write_conf,
+};
+
+static void __devinit tegra_pcie_fixup_bridge(struct pci_dev *dev)
+{
+       u16 reg;
+
+       if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
+               pci_read_config_word(dev, PCI_COMMAND, &reg);
+               reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+               pci_write_config_word(dev, PCI_COMMAND, reg);
+       }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
+
+/* Tegra PCIE root complex wrongly reports device class */
+static void __devinit tegra_pcie_fixup_class(struct pci_dev *dev)
+{
+       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
+
+/* Tegra PCIE requires relaxed ordering */
+static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
+{
+       u16 val16;
+       int pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+
+       if (pos <= 0) {
+               dev_err(&dev->dev, "skipping relaxed ordering fixup\n");
+               return;
+       }
+
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &val16);
+       val16 |= PCI_EXP_DEVCTL_RELAX_EN;
+       pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, val16);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
+
+static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+       struct tegra_pcie_port *pp;
+
+       if (nr >= tegra_pcie.num_ports)
+               return 0;
+
+       pp = tegra_pcie.port + nr;
+       pp->root_bus_nr = sys->busnr;
+
+       /*
+        * IORESOURCE_IO
+        */
+       snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+                "PCIe %d I/O", pp->index);
+       pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+       pp->res[0].name = pp->io_space_name;
+       if (pp->index == 0) {
+               pp->res[0].start = PCIBIOS_MIN_IO;
+               pp->res[0].end = pp->res[0].start + SZ_32K - 1;
+       } else {
+               pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
+               pp->res[0].end = IO_SPACE_LIMIT;
+       }
+       pp->res[0].flags = IORESOURCE_IO;
+       if (request_resource(&ioport_resource, &pp->res[0]))
+               panic("Request PCIe IO resource failed\n");
+       sys->resource[0] = &pp->res[0];
+
+       /*
+        * IORESOURCE_MEM
+        */
+       snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+                "PCIe %d MEM", pp->index);
+       pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+       pp->res[1].name = pp->mem_space_name;
+       if (pp->index == 0) {
+               pp->res[1].start = MEM_BASE_0;
+               pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+       } else {
+               pp->res[1].start = MEM_BASE_1;
+               pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+       }
+       pp->res[1].flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, &pp->res[1]))
+               panic("Request PCIe Memory resource failed\n");
+       sys->resource[1] = &pp->res[1];
+
+       /*
+        * IORESOURCE_MEM | IORESOURCE_PREFETCH
+        */
+       snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
+                "PCIe %d PREFETCH MEM", pp->index);
+       pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
+       pp->res[2].name = pp->prefetch_space_name;
+       if (pp->index == 0) {
+               pp->res[2].start = PREFETCH_MEM_BASE_0;
+               pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+       } else {
+               pp->res[2].start = PREFETCH_MEM_BASE_1;
+               pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+       }
+       pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+       if (request_resource(&iomem_resource, &pp->res[2]))
+               panic("Request PCIe Prefetch Memory resource failed\n");
+       sys->resource[2] = &pp->res[2];
+
+       return 1;
+}
+
+static int tegra_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return INT_PCIE_INTR;
+}
+
+static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
+                                                 struct pci_sys_data *sys)
+{
+       struct tegra_pcie_port *pp;
+
+       if (nr >= tegra_pcie.num_ports)
+               return 0;
+
+       pp = tegra_pcie.port + nr;
+       pp->root_bus_nr = sys->busnr;
+
+       return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
+}
+
+static struct hw_pci tegra_pcie_hw __initdata = {
+       .nr_controllers = 2,
+       .setup          = tegra_pcie_setup,
+       .scan           = tegra_pcie_scan_bus,
+       .swizzle        = pci_std_swizzle,
+       .map_irq        = tegra_pcie_map_irq,
+};
+
+
+static irqreturn_t tegra_pcie_isr(int irq, void *arg)
+{
+       const char *err_msg[] = {
+               "Unknown",
+               "AXI slave error",
+               "AXI decode error",
+               "Target abort",
+               "Master abort",
+               "Invalid write",
+               "Response decoding error",
+               "AXI response decoding error",
+               "Transcation timeout",
+       };
+
+       u32 code, signature;
+
+       code = afi_readl(AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
+       signature = afi_readl(AFI_INTR_SIGNATURE);
+       afi_writel(0, AFI_INTR_CODE);
+
+       if (code == AFI_INTR_LEGACY)
+               return IRQ_NONE;
+
+       if (code >= ARRAY_SIZE(err_msg))
+               code = 0;
+
+       /*
+        * do not pollute kernel log with master abort reports since they
+        * happen a lot during enumeration
+        */
+       if (code == AFI_INTR_MASTER_ABORT)
+               pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+       else
+               pr_err("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+
+       return IRQ_HANDLED;
+}
+
+static void tegra_pcie_setup_translations(void)
+{
+       u32 fpci_bar;
+       u32 size;
+       u32 axi_address;
+
+       /* Bar 0: config Bar */
+       fpci_bar = ((u32)0xfdff << 16);
+       size = PCIE_CFG_SZ;
+       axi_address = TEGRA_PCIE_BASE + PCIE_CFG_OFF;
+       afi_writel(axi_address, AFI_AXI_BAR0_START);
+       afi_writel(size >> 12, AFI_AXI_BAR0_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR0);
+
+       /* Bar 1: extended config Bar */
+       fpci_bar = ((u32)0xfe1 << 20);
+       size = PCIE_EXT_CFG_SZ;
+       axi_address = TEGRA_PCIE_BASE + PCIE_EXT_CFG_OFF;
+       afi_writel(axi_address, AFI_AXI_BAR1_START);
+       afi_writel(size >> 12, AFI_AXI_BAR1_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR1);
+
+       /* Bar 2: downstream IO bar */
+       fpci_bar = ((__u32)0xfdfc << 16);
+       size = MMIO_SIZE;
+       axi_address = MMIO_BASE;
+       afi_writel(axi_address, AFI_AXI_BAR2_START);
+       afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR2);
+
+       /* Bar 3: prefetchable memory BAR */
+       fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
+       size =  PREFETCH_MEM_SIZE_0 +  PREFETCH_MEM_SIZE_1;
+       axi_address = PREFETCH_MEM_BASE_0;
+       afi_writel(axi_address, AFI_AXI_BAR3_START);
+       afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR3);
+
+       /* Bar 4: non prefetchable memory BAR */
+       fpci_bar = (((MEM_BASE_0 >> 12) & 0x0FFFFFFF) << 4) | 0x1;
+       size = MEM_SIZE_0 + MEM_SIZE_1;
+       axi_address = MEM_BASE_0;
+       afi_writel(axi_address, AFI_AXI_BAR4_START);
+       afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR4);
+
+       /* Bar 5: NULL out the remaining BAR as it is not used */
+       fpci_bar = 0;
+       size = 0;
+       axi_address = 0;
+       afi_writel(axi_address, AFI_AXI_BAR5_START);
+       afi_writel(size >> 12, AFI_AXI_BAR5_SZ);
+       afi_writel(fpci_bar, AFI_FPCI_BAR5);
+
+       /* map all upstream transactions as uncached */
+       afi_writel(PHYS_OFFSET, AFI_CACHE_BAR0_ST);
+       afi_writel(0, AFI_CACHE_BAR0_SZ);
+       afi_writel(0, AFI_CACHE_BAR1_ST);
+       afi_writel(0, AFI_CACHE_BAR1_SZ);
+
+       /* No MSI */
+       afi_writel(0, AFI_MSI_FPCI_BAR_ST);
+       afi_writel(0, AFI_MSI_BAR_SZ);
+       afi_writel(0, AFI_MSI_AXI_BAR_ST);
+       afi_writel(0, AFI_MSI_BAR_SZ);
+}
+
+static void tegra_pcie_enable_controller(void)
+{
+       u32 val, reg;
+       int i;
+
+       /* Enable slot clock and pulse the reset signals */
+       for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
+               val = afi_readl(reg) |  AFI_PEX_CTRL_REFCLK_EN;
+               afi_writel(val, reg);
+               val &= ~AFI_PEX_CTRL_RST;
+               afi_writel(val, reg);
+
+               val = afi_readl(reg) | AFI_PEX_CTRL_RST;
+               afi_writel(val, reg);
+       }
+
+       /* Enable dual controller and both ports */
+       val = afi_readl(AFI_PCIE_CONFIG);
+       val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
+                AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
+                AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
+       val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+       afi_writel(val, AFI_PCIE_CONFIG);
+
+       val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+       afi_writel(val, AFI_FUSE);
+
+       /* Initialze internal PHY, enable up to 16 PCIE lanes */
+       pads_writel(0x0, PADS_CTL_SEL);
+
+       /* override IDDQ to 1 on all 4 lanes */
+       val = pads_readl(PADS_CTL) | PADS_CTL_IDDQ_1L;
+       pads_writel(val, PADS_CTL);
+
+       /*
+        * set up PHY PLL inputs select PLLE output as refclock,
+        * set TX ref sel to div10 (not div5)
+        */
+       val = pads_readl(PADS_PLL_CTL);
+       val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+       val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
+       pads_writel(val, PADS_PLL_CTL);
+
+       /* take PLL out of reset  */
+       val = pads_readl(PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
+       pads_writel(val, PADS_PLL_CTL);
+
+       /*
+        * Hack, set the clock voltage to the DEFAULT provided by hw folks.
+        * This doesn't exist in the documentation
+        */
+       pads_writel(0xfa5cfa5c, 0xc8);
+
+       /* Wait for the PLL to lock */
+       do {
+               val = pads_readl(PADS_PLL_CTL);
+       } while (!(val & PADS_PLL_CTL_LOCKDET));
+
+       /* turn off IDDQ override */
+       val = pads_readl(PADS_CTL) & ~PADS_CTL_IDDQ_1L;
+       pads_writel(val, PADS_CTL);
+
+       /* enable TX/RX data */
+       val = pads_readl(PADS_CTL);
+       val |= (PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
+       pads_writel(val, PADS_CTL);
+
+       /* Take the PCIe interface module out of reset */
+       tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+
+       /* Finally enable PCIe */
+       val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
+       afi_writel(val, AFI_CONFIGURATION);
+
+       val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
+              AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
+              AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR);
+       afi_writel(val, AFI_AFI_INTR_ENABLE);
+       afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
+
+       /* FIXME: No MSI for now, only INT */
+       afi_writel(AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
+
+       /* Disable all execptions */
+       afi_writel(0, AFI_FPCI_ERROR_MASKS);
+
+       return;
+}
+
+static void tegra_pcie_xclk_clamp(bool clamp)
+{
+       u32 reg;
+
+       reg = pmc_readl(PMC_SCRATCH42) & ~PMC_SCRATCH42_PCX_CLAMP;
+
+       if (clamp)
+               reg |= PMC_SCRATCH42_PCX_CLAMP;
+
+       pmc_writel(reg, PMC_SCRATCH42);
+}
+
+static int tegra_pcie_power_on(void)
+{
+       tegra_pcie_xclk_clamp(true);
+       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+       tegra_pcie_xclk_clamp(false);
+
+       clk_enable(tegra_pcie.afi_clk);
+       clk_enable(tegra_pcie.pex_clk);
+       return clk_enable(tegra_pcie.pll_e);
+}
+
+static void tegra_pcie_power_off(void)
+{
+       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+       tegra_periph_reset_assert(tegra_pcie.afi_clk);
+       tegra_periph_reset_assert(tegra_pcie.pex_clk);
+
+       tegra_pcie_xclk_clamp(true);
+}
+
+static int tegra_pcie_clocks_get(void)
+{
+       int err;
+
+       tegra_pcie.pex_clk = clk_get(NULL, "pex");
+       if (IS_ERR(tegra_pcie.pex_clk))
+               return PTR_ERR(tegra_pcie.pex_clk);
+
+       tegra_pcie.afi_clk = clk_get(NULL, "afi");
+       if (IS_ERR(tegra_pcie.afi_clk)) {
+               err = PTR_ERR(tegra_pcie.afi_clk);
+               goto err_afi_clk;
+       }
+
+       tegra_pcie.pcie_xclk = clk_get(NULL, "pcie_xclk");
+       if (IS_ERR(tegra_pcie.pcie_xclk)) {
+               err =  PTR_ERR(tegra_pcie.pcie_xclk);
+               goto err_pcie_xclk;
+       }
+
+       tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
+       if (IS_ERR(tegra_pcie.pll_e)) {
+               err = PTR_ERR(tegra_pcie.pll_e);
+               goto err_pll_e;
+       }
+
+       return 0;
+
+err_pll_e:
+       clk_put(tegra_pcie.pcie_xclk);
+err_pcie_xclk:
+       clk_put(tegra_pcie.afi_clk);
+err_afi_clk:
+       clk_put(tegra_pcie.pex_clk);
+
+       return err;
+}
+
+static void tegra_pcie_clocks_put(void)
+{
+       clk_put(tegra_pcie.pll_e);
+       clk_put(tegra_pcie.pcie_xclk);
+       clk_put(tegra_pcie.afi_clk);
+       clk_put(tegra_pcie.pex_clk);
+}
+
+static int __init tegra_pcie_get_resources(void)
+{
+       struct resource *res_mmio = &tegra_pcie.res_mmio;
+       int err;
+
+       err = tegra_pcie_clocks_get();
+       if (err) {
+               pr_err("PCIE: failed to get clocks: %d\n", err);
+               return err;
+       }
+
+       err = tegra_pcie_power_on();
+       if (err) {
+               pr_err("PCIE: failed to power up: %d\n", err);
+               goto err_pwr_on;
+       }
+
+       tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
+       if (tegra_pcie.regs == NULL) {
+               pr_err("PCIE: Failed to map PCI/AFI registers\n");
+               err = -ENOMEM;
+               goto err_map_reg;
+       }
+
+       err = request_resource(&iomem_resource, res_mmio);
+       if (err) {
+               pr_err("PCIE: Failed to request resources: %d\n", err);
+               goto err_req_io;
+       }
+
+       tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
+                                            resource_size(res_mmio));
+       if (tegra_pcie_io_base == NULL) {
+               pr_err("PCIE: Failed to map IO\n");
+               err = -ENOMEM;
+               goto err_map_io;
+       }
+
+       err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
+                         IRQF_SHARED, "PCIE", &tegra_pcie);
+       if (err) {
+               pr_err("PCIE: Failed to register IRQ: %d\n", err);
+               goto err_irq;
+       }
+       set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
+
+       return 0;
+
+err_irq:
+       iounmap(tegra_pcie_io_base);
+err_map_io:
+       release_resource(&tegra_pcie.res_mmio);
+err_req_io:
+       iounmap(tegra_pcie.regs);
+err_map_reg:
+       tegra_pcie_power_off();
+err_pwr_on:
+       tegra_pcie_clocks_put();
+
+       return err;
+}
+
+/*
+ * FIXME: If there are no PCIe cards attached, then calling this function
+ * can result in the increase of the bootup time as there are big timeout
+ * loops.
+ */
+#define TEGRA_PCIE_LINKUP_TIMEOUT      200     /* up to 1.2 seconds */
+static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
+                                 u32 reset_reg)
+{
+       u32 reg;
+       int retries = 3;
+       int timeout;
+
+       do {
+               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+               while (timeout) {
+                       reg = readl(pp->base + RP_VEND_XP);
+
+                       if (reg & RP_VEND_XP_DL_UP)
+                               break;
+
+                       mdelay(1);
+                       timeout--;
+               }
+
+               if (!timeout)  {
+                       pr_err("PCIE: port %d: link down, retrying\n", idx);
+                       goto retry;
+               }
+
+               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+               while (timeout) {
+                       reg = readl(pp->base + RP_LINK_CONTROL_STATUS);
+
+                       if (reg & 0x20000000)
+                               return true;
+
+                       mdelay(1);
+                       timeout--;
+               }
+
+retry:
+               /* Pulse the PEX reset */
+               reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+               afi_writel(reg, reset_reg);
+               mdelay(1);
+               reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+               afi_writel(reg, reset_reg);
+
+               retries--;
+       } while (retries);
+
+       return false;
+}
+
+static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
+{
+       struct tegra_pcie_port *pp;
+
+       pp = tegra_pcie.port + tegra_pcie.num_ports;
+
+       pp->index = -1;
+       pp->base = tegra_pcie.regs + offset;
+       pp->link_up = tegra_pcie_check_link(pp, index, reset_reg);
+
+       if (!pp->link_up) {
+               pp->base = NULL;
+               printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
+               return;
+       }
+
+       tegra_pcie.num_ports++;
+       pp->index = index;
+       pp->root_bus_nr = -1;
+       memset(pp->res, 0, sizeof(pp->res));
+}
+
+int __init tegra_pcie_init(bool init_port0, bool init_port1)
+{
+       int err;
+
+       if (!(init_port0 || init_port1))
+               return -ENODEV;
+
+       err = tegra_pcie_get_resources();
+       if (err)
+               return err;
+
+       tegra_pcie_enable_controller();
+
+       /* setup the AFI address translations */
+       tegra_pcie_setup_translations();
+
+       if (init_port0)
+               tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
+
+       if (init_port1)
+               tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
+
+       pci_common_init(&tegra_pcie_hw);
+
+       return 0;
+}
diff --git a/arch/arm/mach-tegra/pinmux-t2-tables.c b/arch/arm/mach-tegra/pinmux-t2-tables.c
new file mode 100644 (file)
index 0000000..a6ea34e
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * linux/arch/arm/mach-tegra/pinmux-t2-tables.c
+ *
+ * Common pinmux configurations for Tegra 2 SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+
+#define DRIVE_PINGROUP(pg_name, r)                             \
+       [TEGRA_DRIVE_PINGROUP_ ## pg_name] = {                  \
+               .name = #pg_name,                               \
+               .reg = r                                        \
+       }
+
+const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
+       DRIVE_PINGROUP(AO1,             0x868),
+       DRIVE_PINGROUP(AO2,             0x86c),
+       DRIVE_PINGROUP(AT1,             0x870),
+       DRIVE_PINGROUP(AT2,             0x874),
+       DRIVE_PINGROUP(CDEV1,           0x878),
+       DRIVE_PINGROUP(CDEV2,           0x87c),
+       DRIVE_PINGROUP(CSUS,            0x880),
+       DRIVE_PINGROUP(DAP1,            0x884),
+       DRIVE_PINGROUP(DAP2,            0x888),
+       DRIVE_PINGROUP(DAP3,            0x88c),
+       DRIVE_PINGROUP(DAP4,            0x890),
+       DRIVE_PINGROUP(DBG,             0x894),
+       DRIVE_PINGROUP(LCD1,            0x898),
+       DRIVE_PINGROUP(LCD2,            0x89c),
+       DRIVE_PINGROUP(SDMMC2,          0x8a0),
+       DRIVE_PINGROUP(SDMMC3,          0x8a4),
+       DRIVE_PINGROUP(SPI,             0x8a8),
+       DRIVE_PINGROUP(UAA,             0x8ac),
+       DRIVE_PINGROUP(UAB,             0x8b0),
+       DRIVE_PINGROUP(UART2,           0x8b4),
+       DRIVE_PINGROUP(UART3,           0x8b8),
+       DRIVE_PINGROUP(VI1,             0x8bc),
+       DRIVE_PINGROUP(VI2,             0x8c0),
+       DRIVE_PINGROUP(XM2A,            0x8c4),
+       DRIVE_PINGROUP(XM2C,            0x8c8),
+       DRIVE_PINGROUP(XM2D,            0x8cc),
+       DRIVE_PINGROUP(XM2CLK,          0x8d0),
+       DRIVE_PINGROUP(MEMCOMP,         0x8d4),
+};
+
+#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe,         \
+                tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)    \
+       [TEGRA_PINGROUP_ ## pg_name] = {                        \
+               .name = #pg_name,                               \
+               .vddio = TEGRA_VDDIO_ ## vdd,                   \
+               .funcs = {                                      \
+                       TEGRA_MUX_ ## f0,                       \
+                       TEGRA_MUX_ ## f1,                       \
+                       TEGRA_MUX_ ## f2,                       \
+                       TEGRA_MUX_ ## f3,                       \
+               },                                              \
+               .func_safe = TEGRA_MUX_ ## f_safe,              \
+               .tri_reg = tri_r,                               \
+               .tri_bit = tri_b,                               \
+               .mux_reg = mux_r,                               \
+               .mux_bit = mux_b,                               \
+               .pupd_reg = pupd_r,                             \
+               .pupd_bit = pupd_b,                             \
+       }
+
+const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
+       PINGROUP(ATA,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x14, 0,  0x80, 24, 0xA0, 0),
+       PINGROUP(ATB,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 1,  0x80, 16, 0xA0, 2),
+       PINGROUP(ATC,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 2,  0x80, 22, 0xA0, 4),
+       PINGROUP(ATD,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 3,  0x80, 20, 0xA0, 6),
+       PINGROUP(ATE,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x18, 25, 0x80, 12, 0xA0, 8),
+       PINGROUP(CDEV1, AUDIO, OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    OSC,       0x14, 4,  0x88, 2,  0xA8, 0),
+       PINGROUP(CDEV2, AUDIO, OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     OSC,       0x14, 5,  0x88, 4,  0xA8, 2),
+       PINGROUP(CRTP,  LCD,   CRT,       RSVD,      RSVD,      RSVD,          RSVD,      0x20, 14, 0x98, 20, 0xA4, 24),
+       PINGROUP(CSUS,  VI,    PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6,  0x88, 6,  0xAC, 24),
+       PINGROUP(DAP1,  AUDIO, DAP1,      RSVD,      GMI,       SDIO2,         DAP1,      0x14, 7,  0x88, 20, 0xA0, 10),
+       PINGROUP(DAP2,  AUDIO, DAP2,      TWC,       RSVD,      GMI,           DAP2,      0x14, 8,  0x88, 22, 0xA0, 12),
+       PINGROUP(DAP3,  BB,    DAP3,      RSVD,      RSVD,      RSVD,          DAP3,      0x14, 9,  0x88, 24, 0xA0, 14),
+       PINGROUP(DAP4,  UART,  DAP4,      RSVD,      GMI,       RSVD,          DAP4,      0x14, 10, 0x88, 26, 0xA0, 16),
+       PINGROUP(DDC,   LCD,   I2C2,      RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 31, 0x88, 0,  0xB0, 28),
+       PINGROUP(DTA,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD4,     0x14, 11, 0x84, 20, 0xA0, 18),
+       PINGROUP(DTB,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 12, 0x84, 22, 0xA0, 20),
+       PINGROUP(DTC,   VI,    RSVD,      RSVD,      VI,        RSVD,          RSVD1,     0x14, 13, 0x84, 26, 0xA0, 22),
+       PINGROUP(DTD,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD1,     0x14, 14, 0x84, 28, 0xA0, 24),
+       PINGROUP(DTE,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 15, 0x84, 30, 0xA0, 26),
+       PINGROUP(DTF,   VI,    I2C3,      RSVD,      VI,        RSVD,          RSVD4,     0x20, 12, 0x98, 30, 0xA0, 28),
+       PINGROUP(GMA,   NAND,  UARTE,     SPI3,      GMI,       SDIO4,         SPI3,      0x14, 28, 0x84, 0,  0xB0, 20),
+       PINGROUP(GMB,   NAND,  IDE,       NAND,      GMI,       GMI_INT,       GMI,       0x18, 29, 0x88, 28, 0xB0, 22),
+       PINGROUP(GMC,   NAND,  UARTD,     SPI4,      GMI,       SFLASH,        SPI4,      0x14, 29, 0x84, 2,  0xB0, 24),
+       PINGROUP(GMD,   NAND,  RSVD,      NAND,      GMI,       SFLASH,        GMI,       0x18, 30, 0x88, 30, 0xB0, 26),
+       PINGROUP(GME,   NAND,  RSVD,      DAP5,      GMI,       SDIO4,         GMI,       0x18, 0,  0x8C, 0,  0xA8, 24),
+       PINGROUP(GPU,   UART,  PWM,       UARTA,     GMI,       RSVD,          RSVD4,     0x14, 16, 0x8C, 4,  0xA4, 20),
+       PINGROUP(GPU7,  SYS,   RTCK,      RSVD,      RSVD,      RSVD,          RTCK,      0x20, 11, 0x98, 28, 0xA4, 6),
+       PINGROUP(GPV,   SD,    PCIE,      RSVD,      RSVD,      RSVD,          PCIE,      0x14, 17, 0x8C, 2,  0xA0, 30),
+       PINGROUP(HDINT, LCD,   HDMI,      RSVD,      RSVD,      RSVD,          HDMI,      0x1C, 23, 0x84, 4,  0xAC, 22),
+       PINGROUP(I2CP,  SYS,   I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 18, 0x88, 8,  0xA4, 2),
+       PINGROUP(IRRX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 20, 0x88, 18, 0xA8, 22),
+       PINGROUP(IRTX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 19, 0x88, 16, 0xA8, 20),
+       PINGROUP(KBCA,  SYS,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, KBC,       0x14, 22, 0x88, 10, 0xA4, 8),
+       PINGROUP(KBCB,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x14, 21, 0x88, 12, 0xA4, 10),
+       PINGROUP(KBCC,  SYS,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL, KBC,       0x18, 26, 0x88, 14, 0xA4, 12),
+       PINGROUP(KBCD,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x20, 10, 0x98, 26, 0xA4, 14),
+       PINGROUP(KBCE,  SYS,   KBC,       NAND,      OWR,       RSVD,          KBC,       0x14, 26, 0x80, 28, 0xB0, 2),
+       PINGROUP(KBCF,  SYS,   KBC,       NAND,      TRACE,     MIO,           KBC,       0x14, 27, 0x80, 26, 0xB0, 0),
+       PINGROUP(LCSN,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 31, 0x90, 12, 0xAC, 20),
+       PINGROUP(LD0,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 0,  0x94, 0,  0xAC, 12),
+       PINGROUP(LD1,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 1,  0x94, 2,  0xAC, 12),
+       PINGROUP(LD10,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 10, 0x94, 20, 0xAC, 12),
+       PINGROUP(LD11,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 11, 0x94, 22, 0xAC, 12),
+       PINGROUP(LD12,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 12, 0x94, 24, 0xAC, 12),
+       PINGROUP(LD13,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 13, 0x94, 26, 0xAC, 12),
+       PINGROUP(LD14,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 14, 0x94, 28, 0xAC, 12),
+       PINGROUP(LD15,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 15, 0x94, 30, 0xAC, 12),
+       PINGROUP(LD16,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 16, 0x98, 0,  0xAC, 12),
+       PINGROUP(LD17,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 17, 0x98, 2,  0xAC, 12),
+       PINGROUP(LD2,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 2,  0x94, 4,  0xAC, 12),
+       PINGROUP(LD3,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 3,  0x94, 6,  0xAC, 12),
+       PINGROUP(LD4,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 4,  0x94, 8,  0xAC, 12),
+       PINGROUP(LD5,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 5,  0x94, 10, 0xAC, 12),
+       PINGROUP(LD6,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 6,  0x94, 12, 0xAC, 12),
+       PINGROUP(LD7,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 7,  0x94, 14, 0xAC, 12),
+       PINGROUP(LD8,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 8,  0x94, 16, 0xAC, 12),
+       PINGROUP(LD9,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 9,  0x94, 18, 0xAC, 12),
+       PINGROUP(LDC,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 30, 0x90, 14, 0xAC, 20),
+       PINGROUP(LDI,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 6,  0x98, 16, 0xAC, 18),
+       PINGROUP(LHP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 18, 0x98, 10, 0xAC, 16),
+       PINGROUP(LHP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 19, 0x98, 4,  0xAC, 14),
+       PINGROUP(LHP2,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 20, 0x98, 6,  0xAC, 14),
+       PINGROUP(LHS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x20, 7,  0x90, 22, 0xAC, 22),
+       PINGROUP(LM0,   LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 24, 0x90, 26, 0xAC, 22),
+       PINGROUP(LM1,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      CRT,           RSVD3,     0x1C, 25, 0x90, 28, 0xAC, 22),
+       PINGROUP(LPP,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 8,  0x98, 14, 0xAC, 18),
+       PINGROUP(LPW0,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 3,  0x90, 0,  0xAC, 20),
+       PINGROUP(LPW1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 4,  0x90, 2,  0xAC, 20),
+       PINGROUP(LPW2,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 5,  0x90, 4,  0xAC, 20),
+       PINGROUP(LSC0,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 27, 0x90, 18, 0xAC, 22),
+       PINGROUP(LSC1,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 28, 0x90, 20, 0xAC, 20),
+       PINGROUP(LSCK,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 29, 0x90, 16, 0xAC, 20),
+       PINGROUP(LSDA,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 1,  0x90, 8,  0xAC, 20),
+       PINGROUP(LSDI,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          DISPLAYA,  0x20, 2,  0x90, 6,  0xAC, 20),
+       PINGROUP(LSPI,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       HDMI,          DISPLAYA,  0x20, 0,  0x90, 10, 0xAC, 22),
+       PINGROUP(LVP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 21, 0x90, 30, 0xAC, 22),
+       PINGROUP(LVP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 22, 0x98, 8,  0xAC, 16),
+       PINGROUP(LVS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 26, 0x90, 24, 0xAC, 22),
+       PINGROUP(OWC,   SYS,   OWR,       RSVD,      RSVD,      RSVD,          OWR,       0x14, 31, 0x84, 8,  0xB0, 30),
+       PINGROUP(PMC,   SYS,   PWR_ON,    PWR_INTR,  RSVD,      RSVD,          PWR_ON,    0x14, 23, 0x98, 18, -1,   -1),
+       PINGROUP(PTA,   NAND,  I2C2,      HDMI,      GMI,       RSVD,          RSVD4,     0x14, 24, 0x98, 22, 0xA4, 4),
+       PINGROUP(RM,    UART,  I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 25, 0x80, 14, 0xA4, 0),
+       PINGROUP(SDB,   SD,    UARTA,     PWM,       SDIO3,     SPI2,          PWM,       0x20, 15, 0x8C, 10, -1,   -1),
+       PINGROUP(SDC,   SD,    PWM,       TWC,       SDIO3,     SPI3,          TWC,       0x18, 1,  0x8C, 12, 0xAC, 28),
+       PINGROUP(SDD,   SD,    UARTA,     PWM,       SDIO3,     SPI3,          PWM,       0x18, 2,  0x8C, 14, 0xAC, 30),
+       PINGROUP(SDIO1, BB,    SDIO1,     RSVD,      UARTE,     UARTA,         RSVD2,     0x14, 30, 0x80, 30, 0xB0, 18),
+       PINGROUP(SLXA,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 3,  0x84, 6,  0xA4, 22),
+       PINGROUP(SLXC,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 5,  0x84, 10, 0xA4, 26),
+       PINGROUP(SLXD,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 6,  0x84, 12, 0xA4, 28),
+       PINGROUP(SLXK,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 7,  0x84, 14, 0xA4, 30),
+       PINGROUP(SPDI,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 8,  0x8C, 8,  0xA4, 16),
+       PINGROUP(SPDO,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 9,  0x8C, 6,  0xA4, 18),
+       PINGROUP(SPIA,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 10, 0x8C, 30, 0xA8, 4),
+       PINGROUP(SPIB,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 11, 0x8C, 28, 0xA8, 6),
+       PINGROUP(SPIC,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 12, 0x8C, 26, 0xA8, 8),
+       PINGROUP(SPID,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 13, 0x8C, 24, 0xA8, 10),
+       PINGROUP(SPIE,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 14, 0x8C, 22, 0xA8, 12),
+       PINGROUP(SPIF,  AUDIO, SPI3,      SPI1,      SPI2,      RSVD,          RSVD4,     0x18, 15, 0x8C, 20, 0xA8, 14),
+       PINGROUP(SPIG,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 16, 0x8C, 18, 0xA8, 16),
+       PINGROUP(SPIH,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 17, 0x8C, 16, 0xA8, 18),
+       PINGROUP(UAA,   BB,    SPI3,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 18, 0x80, 0,  0xAC, 0),
+       PINGROUP(UAB,   BB,    SPI2,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 19, 0x80, 2,  0xAC, 2),
+       PINGROUP(UAC,   BB,    OWR,       RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 20, 0x80, 4,  0xAC, 4),
+       PINGROUP(UAD,   UART,  IRDA,      SPDIF,     UARTA,     SPI4,          SPDIF,     0x18, 21, 0x80, 6,  0xAC, 6),
+       PINGROUP(UCA,   UART,  UARTC,     RSVD,      GMI,       RSVD,          RSVD4,     0x18, 22, 0x84, 16, 0xAC, 8),
+       PINGROUP(UCB,   UART,  UARTC,     PWM,       GMI,       RSVD,          RSVD4,     0x18, 23, 0x84, 18, 0xAC, 10),
+       PINGROUP(UDA,   BB,    SPI1,      RSVD,      UARTD,     ULPI,          RSVD2,     0x20, 13, 0x80, 8,  0xB0, 16),
+       /* these pin groups only have pullup and pull down control */
+       PINGROUP(CK32,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 14),
+       PINGROUP(DDRC,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xAC, 26),
+       PINGROUP(PMCA,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 4),
+       PINGROUP(PMCB,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 6),
+       PINGROUP(PMCC,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 8),
+       PINGROUP(PMCD,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 10),
+       PINGROUP(PMCE,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 12),
+       PINGROUP(XM2C,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 30),
+       PINGROUP(XM2D,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 28),
+};
+
+#ifdef CONFIG_PM
+#define TRISTATE_REG_A         0x14
+#define TRISTATE_REG_NUM       4
+#define PIN_MUX_CTL_REG_A      0x80
+#define PIN_MUX_CTL_REG_NUM    8
+#define PULLUPDOWN_REG_A       0xa0
+#define PULLUPDOWN_REG_NUM     5
+
+static u32 pinmux_reg[TRISTATE_REG_NUM + PIN_MUX_CTL_REG_NUM +
+                    PULLUPDOWN_REG_NUM];
+
+static inline unsigned long pg_readl(unsigned long offset)
+{
+       return readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+static inline void pg_writel(unsigned long value, unsigned long offset)
+{
+       writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+void tegra_pinmux_suspend(void)
+{
+       unsigned int i;
+       u32 *ctx = pinmux_reg;
+
+       for (i = 0; i < TRISTATE_REG_NUM; i++)
+               *ctx++ = pg_readl(TRISTATE_REG_A + i*4);
+
+       for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+               *ctx++ = pg_readl(PIN_MUX_CTL_REG_A + i*4);
+
+       for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+               *ctx++ = pg_readl(PULLUPDOWN_REG_A + i*4);
+}
+
+void tegra_pinmux_resume(void)
+{
+       unsigned int i;
+       u32 *ctx = pinmux_reg;
+
+       for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+               pg_writel(*ctx++, PIN_MUX_CTL_REG_A + i*4);
+
+       for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+               pg_writel(*ctx++, PULLUPDOWN_REG_A + i*4);
+
+       for (i = 0; i < TRISTATE_REG_NUM; i++)
+               pg_writel(*ctx++, TRISTATE_REG_A + i*4);
+}
+#endif
index 13ae10237e84688565af92668975a2c11e58171a..f80d507671bc1b22921ab2821c8a2cde427f1b5f 100644 (file)
@@ -14,7 +14,8 @@
  *
  */
 
-
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
 #include <mach/iomap.h>
 #include <mach/pinmux.h>
 
-
-#define TEGRA_TRI_STATE(x)     (0x14 + (4 * (x)))
-#define TEGRA_PP_MUX_CTL(x)    (0x80 + (4 * (x)))
-#define TEGRA_PP_PU_PD(x)      (0xa0 + (4 * (x)))
-
-#define REG_A 0
-#define REG_B 1
-#define REG_C 2
-#define REG_D 3
-#define REG_E 4
-#define REG_F 5
-#define REG_G 6
-
-#define REG_N -1
-
 #define HSM_EN(reg)    (((reg) >> 2) & 0x1)
 #define SCHMT_EN(reg)  (((reg) >> 3) & 0x1)
 #define LPMD(reg)      (((reg) >> 4) & 0x3)
 #define SLWR(reg)      (((reg) >> 28) & 0x3)
 #define SLWF(reg)      (((reg) >> 30) & 0x3)
 
-struct tegra_pingroup_desc {
-       const char *name;
-       int funcs[4];
-       s8 tri_reg;     /* offset into the TRISTATE_REG_* register bank */
-       s8 tri_bit;     /* offset into the TRISTATE_REG_* register bit */
-       s8 mux_reg;     /* offset into the PIN_MUX_CTL_* register bank */
-       s8 mux_bit;     /* offset into the PIN_MUX_CTL_* register bit */
-       s8 pupd_reg;    /* offset into the PULL_UPDOWN_REG_* register bank */
-       s8 pupd_bit;    /* offset into the PULL_UPDOWN_REG_* register bit */
-};
-
-#define PINGROUP(pg_name, f0, f1, f2, f3,                      \
-                tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)    \
-       [TEGRA_PINGROUP_ ## pg_name] = {                        \
-               .name = #pg_name,                               \
-               .funcs = {                                      \
-                       TEGRA_MUX_ ## f0,                       \
-                       TEGRA_MUX_ ## f1,                       \
-                       TEGRA_MUX_ ## f2,                       \
-                       TEGRA_MUX_ ## f3,                       \
-               },                                              \
-               .tri_reg = REG_ ## tri_r,                       \
-               .tri_bit = tri_b,                               \
-               .mux_reg = REG_ ## mux_r,                       \
-               .mux_bit = mux_b,                               \
-               .pupd_reg = REG_ ## pupd_r,                     \
-               .pupd_bit = pupd_b,                             \
-       }
-
-static const struct tegra_pingroup_desc pingroups[TEGRA_MAX_PINGROUP] = {
-       PINGROUP(ATA,   IDE,       NAND,      GMI,       RSVD,          A, 0,  A, 24, A, 0),
-       PINGROUP(ATB,   IDE,       NAND,      GMI,       SDIO4,         A, 1,  A, 16, A, 2),
-       PINGROUP(ATC,   IDE,       NAND,      GMI,       SDIO4,         A, 2,  A, 22, A, 4),
-       PINGROUP(ATD,   IDE,       NAND,      GMI,       SDIO4,         A, 3,  A, 20, A, 6),
-       PINGROUP(ATE,   IDE,       NAND,      GMI,       RSVD,          B, 25, A, 12, A, 8),
-       PINGROUP(CDEV1, OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    A, 4,  C, 2,  C, 0),
-       PINGROUP(CDEV2, OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     A, 5,  C, 4,  C, 2),
-       PINGROUP(CRTP,  CRT,       RSVD,      RSVD,      RSVD,          D, 14, G, 20, B, 24),
-       PINGROUP(CSUS,  PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, A, 6,  C, 6,  D, 24),
-       PINGROUP(DAP1,  DAP1,      RSVD,      GMI,       SDIO2,         A, 7,  C, 20, A, 10),
-       PINGROUP(DAP2,  DAP2,      TWC,       RSVD,      GMI,           A, 8,  C, 22, A, 12),
-       PINGROUP(DAP3,  DAP3,      RSVD,      RSVD,      RSVD,          A, 9,  C, 24, A, 14),
-       PINGROUP(DAP4,  DAP4,      RSVD,      GMI,       RSVD,          A, 10, C, 26, A, 16),
-       PINGROUP(DDC,   I2C2,      RSVD,      RSVD,      RSVD,          B, 31, C, 0,  E, 28),
-       PINGROUP(DTA,   RSVD,      SDIO2,     VI,        RSVD,          A, 11, B, 20, A, 18),
-       PINGROUP(DTB,   RSVD,      RSVD,      VI,        SPI1,          A, 12, B, 22, A, 20),
-       PINGROUP(DTC,   RSVD,      RSVD,      VI,        RSVD,          A, 13, B, 26, A, 22),
-       PINGROUP(DTD,   RSVD,      SDIO2,     VI,        RSVD,          A, 14, B, 28, A, 24),
-       PINGROUP(DTE,   RSVD,      RSVD,      VI,        SPI1,          A, 15, B, 30, A, 26),
-       PINGROUP(DTF,   I2C3,      RSVD,      VI,        RSVD,          D, 12, G, 30, A, 28),
-       PINGROUP(GMA,   UARTE,     SPI3,      GMI,       SDIO4,         A, 28, B, 0,  E, 20),
-       PINGROUP(GMB,   IDE,       NAND,      GMI,       GMI_INT,       B, 29, C, 28, E, 22),
-       PINGROUP(GMC,   UARTD,     SPI4,      GMI,       SFLASH,        A, 29, B, 2,  E, 24),
-       PINGROUP(GMD,   RSVD,      NAND,      GMI,       SFLASH,        B, 30, C, 30, E, 26),
-       PINGROUP(GME,   RSVD,      DAP5,      GMI,       SDIO4,         B, 0,  D, 0,  C, 24),
-       PINGROUP(GPU,   PWM,       UARTA,     GMI,       RSVD,          A, 16, D, 4,  B, 20),
-       PINGROUP(GPU7,  RTCK,      RSVD,      RSVD,      RSVD,          D, 11, G, 28, B, 6),
-       PINGROUP(GPV,   PCIE,      RSVD,      RSVD,      RSVD,          A, 17, D, 2,  A, 30),
-       PINGROUP(HDINT, HDMI,      RSVD,      RSVD,      RSVD,          C, 23, B, 4,  D, 22),
-       PINGROUP(I2CP,  I2C,       RSVD,      RSVD,      RSVD,          A, 18, C, 8,  B, 2),
-       PINGROUP(IRRX,  UARTA,     UARTB,     GMI,       SPI4,          A, 20, C, 18, C, 22),
-       PINGROUP(IRTX,  UARTA,     UARTB,     GMI,       SPI4,          A, 19, C, 16, C, 20),
-       PINGROUP(KBCA,  KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, A, 22, C, 10, B, 8),
-       PINGROUP(KBCB,  KBC,       NAND,      SDIO2,     MIO,           A, 21, C, 12, B, 10),
-       PINGROUP(KBCC,  KBC,       NAND,      TRACE,     EMC_TEST1_DLL, B, 26, C, 14, B, 12),
-       PINGROUP(KBCD,  KBC,       NAND,      SDIO2,     MIO,           D, 10, G, 26, B, 14),
-       PINGROUP(KBCE,  KBC,       NAND,      OWR,       RSVD,          A, 26, A, 28, E, 2),
-       PINGROUP(KBCF,  KBC,       NAND,      TRACE,     MIO,           A, 27, A, 26, E, 0),
-       PINGROUP(LCSN,  DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          C, 31, E, 12, D, 20),
-       PINGROUP(LD0,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 0,  F, 0,  D, 12),
-       PINGROUP(LD1,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 1,  F, 2,  D, 12),
-       PINGROUP(LD10,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 10, F, 20, D, 12),
-       PINGROUP(LD11,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 11, F, 22, D, 12),
-       PINGROUP(LD12,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 12, F, 24, D, 12),
-       PINGROUP(LD13,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 13, F, 26, D, 12),
-       PINGROUP(LD14,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 14, F, 28, D, 12),
-       PINGROUP(LD15,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 15, F, 30, D, 12),
-       PINGROUP(LD16,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 16, G, 0,  D, 12),
-       PINGROUP(LD17,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 17, G, 2,  D, 12),
-       PINGROUP(LD2,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 2,  F, 4,  D, 12),
-       PINGROUP(LD3,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 3,  F, 6,  D, 12),
-       PINGROUP(LD4,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 4,  F, 8,  D, 12),
-       PINGROUP(LD5,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 5,  F, 10, D, 12),
-       PINGROUP(LD6,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 6,  F, 12, D, 12),
-       PINGROUP(LD7,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 7,  F, 14, D, 12),
-       PINGROUP(LD8,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 8,  F, 16, D, 12),
-       PINGROUP(LD9,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 9,  F, 18, D, 12),
-       PINGROUP(LDC,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 30, E, 14, D, 20),
-       PINGROUP(LDI,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 6,  G, 16, D, 18),
-       PINGROUP(LHP0,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 18, G, 10, D, 16),
-       PINGROUP(LHP1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 19, G, 4,  D, 14),
-       PINGROUP(LHP2,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 20, G, 6,  D, 14),
-       PINGROUP(LHS,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          D, 7,  E, 22, D, 22),
-       PINGROUP(LM0,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          C, 24, E, 26, D, 22),
-       PINGROUP(LM1,   DISPLAYA,  DISPLAYB,  RSVD,      CRT,           C, 25, E, 28, D, 22),
-       PINGROUP(LPP,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 8,  G, 14, D, 18),
-       PINGROUP(LPW0,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 3,  E, 0,  D, 20),
-       PINGROUP(LPW1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 4,  E, 2,  D, 20),
-       PINGROUP(LPW2,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 5,  E, 4,  D, 20),
-       PINGROUP(LSC0,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 27, E, 18, D, 22),
-       PINGROUP(LSC1,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          C, 28, E, 20, D, 20),
-       PINGROUP(LSCK,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          C, 29, E, 16, D, 20),
-       PINGROUP(LSDA,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 1,  E, 8,  D, 20),
-       PINGROUP(LSDI,  DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          D, 2,  E, 6,  D, 20),
-       PINGROUP(LSPI,  DISPLAYA,  DISPLAYB,  XIO,       HDMI,          D, 0,  E, 10, D, 22),
-       PINGROUP(LVP0,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 21, E, 30, D, 22),
-       PINGROUP(LVP1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 22, G, 8,  D, 16),
-       PINGROUP(LVS,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 26, E, 24, D, 22),
-       PINGROUP(OWC,   OWR,       RSVD,      RSVD,      RSVD,          A, 31, B, 8,  E, 30),
-       PINGROUP(PMC,   PWR_ON,    PWR_INTR,  RSVD,      RSVD,          A, 23, G, 18, N, -1),
-       PINGROUP(PTA,   I2C2,      HDMI,      GMI,       RSVD,          A, 24, G, 22, B, 4),
-       PINGROUP(RM,    I2C,       RSVD,      RSVD,      RSVD,          A, 25, A, 14, B, 0),
-       PINGROUP(SDB,   UARTA,     PWM,       SDIO3,     SPI2,          D, 15, D, 10, N, -1),
-       PINGROUP(SDC,   PWM,       TWC,       SDIO3,     SPI3,          B, 1,  D, 12, D, 28),
-       PINGROUP(SDD,   UARTA,     PWM,       SDIO3,     SPI3,          B, 2,  D, 14, D, 30),
-       PINGROUP(SDIO1, SDIO1,     RSVD,      UARTE,     UARTA,         A, 30, A, 30, E, 18),
-       PINGROUP(SLXA,  PCIE,      SPI4,      SDIO3,     SPI2,          B, 3,  B, 6,  B, 22),
-       PINGROUP(SLXC,  SPDIF,     SPI4,      SDIO3,     SPI2,          B, 5,  B, 10, B, 26),
-       PINGROUP(SLXD,  SPDIF,     SPI4,      SDIO3,     SPI2,          B, 6,  B, 12, B, 28),
-       PINGROUP(SLXK,  PCIE,      SPI4,      SDIO3,     SPI2,          B, 7,  B, 14, B, 30),
-       PINGROUP(SPDI,  SPDIF,     RSVD,      I2C,       SDIO2,         B, 8,  D, 8,  B, 16),
-       PINGROUP(SPDO,  SPDIF,     RSVD,      I2C,       SDIO2,         B, 9,  D, 6,  B, 18),
-       PINGROUP(SPIA,  SPI1,      SPI2,      SPI3,      GMI,           B, 10, D, 30, C, 4),
-       PINGROUP(SPIB,  SPI1,      SPI2,      SPI3,      GMI,           B, 11, D, 28, C, 6),
-       PINGROUP(SPIC,  SPI1,      SPI2,      SPI3,      GMI,           B, 12, D, 26, C, 8),
-       PINGROUP(SPID,  SPI2,      SPI1,      SPI2_ALT,  GMI,           B, 13, D, 24, C, 10),
-       PINGROUP(SPIE,  SPI2,      SPI1,      SPI2_ALT,  GMI,           B, 14, D, 22, C, 12),
-       PINGROUP(SPIF,  SPI3,      SPI1,      SPI2,      RSVD,          B, 15, D, 20, C, 14),
-       PINGROUP(SPIG,  SPI3,      SPI2,      SPI2_ALT,  I2C,           B, 16, D, 18, C, 16),
-       PINGROUP(SPIH,  SPI3,      SPI2,      SPI2_ALT,  I2C,           B, 17, D, 16, C, 18),
-       PINGROUP(UAA,   SPI3,      MIPI_HS,   UARTA,     ULPI,          B, 18, A, 0,  D, 0),
-       PINGROUP(UAB,   SPI2,      MIPI_HS,   UARTA,     ULPI,          B, 19, A, 2,  D, 2),
-       PINGROUP(UAC,   OWR,       RSVD,      RSVD,      RSVD,          B, 20, A, 4,  D, 4),
-       PINGROUP(UAD,   IRDA,      SPDIF,     UARTA,     SPI4,          B, 21, A, 6,  D, 6),
-       PINGROUP(UCA,   UARTC,     RSVD,      GMI,       RSVD,          B, 22, B, 16, D, 8),
-       PINGROUP(UCB,   UARTC,     PWM,       GMI,       RSVD,          B, 23, B, 18, D, 10),
-       PINGROUP(UDA,   SPI1,      RSVD,      UARTD,     ULPI,          D, 13, A, 8,  E, 16),
-       /* these pin groups only have pullup and pull down control */
-       PINGROUP(CK32,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 14),
-       PINGROUP(DDRC,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  D, 26),
-       PINGROUP(PMCA,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 4),
-       PINGROUP(PMCB,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 6),
-       PINGROUP(PMCC,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 8),
-       PINGROUP(PMCD,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 10),
-       PINGROUP(PMCE,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 12),
-       PINGROUP(XM2C,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  C, 30),
-       PINGROUP(XM2D,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  C, 28),
-};
+static const struct tegra_pingroup_desc *const pingroups = tegra_soc_pingroups;
+static const struct tegra_drive_pingroup_desc *const drive_pingroups = tegra_soc_drive_pingroups;
 
 static char *tegra_mux_names[TEGRA_MAX_MUX] = {
        [TEGRA_MUX_AHB_CLK] = "AHB_CLK",
@@ -256,48 +96,7 @@ static char *tegra_mux_names[TEGRA_MAX_MUX] = {
        [TEGRA_MUX_VI] = "VI",
        [TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
        [TEGRA_MUX_XIO] = "XIO",
-};
-
-struct tegra_drive_pingroup_desc {
-       const char *name;
-       s16 reg;
-};
-
-#define DRIVE_PINGROUP(pg_name, r)                             \
-       [TEGRA_DRIVE_PINGROUP_ ## pg_name] = {                  \
-               .name = #pg_name,                               \
-               .reg = r                                        \
-       }
-
-static const struct tegra_drive_pingroup_desc drive_pingroups[TEGRA_MAX_PINGROUP] = {
-       DRIVE_PINGROUP(AO1,             0x868),
-       DRIVE_PINGROUP(AO2,             0x86c),
-       DRIVE_PINGROUP(AT1,             0x870),
-       DRIVE_PINGROUP(AT2,             0x874),
-       DRIVE_PINGROUP(CDEV1,           0x878),
-       DRIVE_PINGROUP(CDEV2,           0x87c),
-       DRIVE_PINGROUP(CSUS,            0x880),
-       DRIVE_PINGROUP(DAP1,            0x884),
-       DRIVE_PINGROUP(DAP2,            0x888),
-       DRIVE_PINGROUP(DAP3,            0x88c),
-       DRIVE_PINGROUP(DAP4,            0x890),
-       DRIVE_PINGROUP(DBG,             0x894),
-       DRIVE_PINGROUP(LCD1,            0x898),
-       DRIVE_PINGROUP(LCD2,            0x89c),
-       DRIVE_PINGROUP(SDMMC2,  0x8a0),
-       DRIVE_PINGROUP(SDMMC3,  0x8a4),
-       DRIVE_PINGROUP(SPI,             0x8a8),
-       DRIVE_PINGROUP(UAA,             0x8ac),
-       DRIVE_PINGROUP(UAB,             0x8b0),
-       DRIVE_PINGROUP(UART2,           0x8b4),
-       DRIVE_PINGROUP(UART3,           0x8b8),
-       DRIVE_PINGROUP(VI1,             0x8bc),
-       DRIVE_PINGROUP(VI2,             0x8c0),
-       DRIVE_PINGROUP(XM2A,            0x8c4),
-       DRIVE_PINGROUP(XM2C,            0x8c8),
-       DRIVE_PINGROUP(XM2D,            0x8cc),
-       DRIVE_PINGROUP(XM2CLK,  0x8d0),
-       DRIVE_PINGROUP(MEMCOMP, 0x8d4),
+       [TEGRA_MUX_SAFE] = "<safe>",
 };
 
 static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
@@ -381,22 +180,27 @@ static inline void pg_writel(unsigned long value, unsigned long offset)
        writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
 }
 
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func)
+static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
 {
        int mux = -1;
        int i;
        unsigned long reg;
        unsigned long flags;
+       enum tegra_pingroup pg = config->pingroup;
+       enum tegra_mux_func func = config->func;
 
        if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
                return -ERANGE;
 
-       if (pingroups[pg].mux_reg == REG_N)
+       if (pingroups[pg].mux_reg < 0)
                return -EINVAL;
 
        if (func < 0)
                return -ERANGE;
 
+       if (func == TEGRA_MUX_SAFE)
+               func = pingroups[pg].func_safe;
+
        if (func & TEGRA_MUX_RSVD) {
                mux = func & 0x3;
        } else {
@@ -413,10 +217,10 @@ int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func)
 
        spin_lock_irqsave(&mux_lock, flags);
 
-       reg = pg_readl(TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+       reg = pg_readl(pingroups[pg].mux_reg);
        reg &= ~(0x3 << pingroups[pg].mux_bit);
        reg |= mux << pingroups[pg].mux_bit;
-       pg_writel(reg, TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+       pg_writel(reg, pingroups[pg].mux_reg);
 
        spin_unlock_irqrestore(&mux_lock, flags);
 
@@ -432,16 +236,16 @@ int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
        if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
                return -ERANGE;
 
-       if (pingroups[pg].tri_reg == REG_N)
+       if (pingroups[pg].tri_reg < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&mux_lock, flags);
 
-       reg = pg_readl(TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+       reg = pg_readl(pingroups[pg].tri_reg);
        reg &= ~(0x1 << pingroups[pg].tri_bit);
        if (tristate)
                reg |= 1 << pingroups[pg].tri_bit;
-       pg_writel(reg, TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+       pg_writel(reg, pingroups[pg].tri_reg);
 
        spin_unlock_irqrestore(&mux_lock, flags);
 
@@ -457,7 +261,7 @@ int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
        if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
                return -ERANGE;
 
-       if (pingroups[pg].pupd_reg == REG_N)
+       if (pingroups[pg].pupd_reg < 0)
                return -EINVAL;
 
        if (pupd != TEGRA_PUPD_NORMAL &&
@@ -468,38 +272,39 @@ int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
 
        spin_lock_irqsave(&mux_lock, flags);
 
-       reg = pg_readl(TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+       reg = pg_readl(pingroups[pg].pupd_reg);
        reg &= ~(0x3 << pingroups[pg].pupd_bit);
        reg |= pupd << pingroups[pg].pupd_bit;
-       pg_writel(reg, TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+       pg_writel(reg, pingroups[pg].pupd_reg);
 
        spin_unlock_irqrestore(&mux_lock, flags);
 
        return 0;
 }
 
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
-                                enum tegra_mux_func func,
-                                enum tegra_pullupdown pupd,
-                                enum tegra_tristate tristate)
+static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
 {
+       enum tegra_pingroup pingroup = config->pingroup;
+       enum tegra_mux_func func     = config->func;
+       enum tegra_pullupdown pupd   = config->pupd;
+       enum tegra_tristate tristate = config->tristate;
        int err;
 
-       if (pingroups[pingroup].mux_reg != REG_N) {
-               err = tegra_pinmux_set_func(pingroup, func);
+       if (pingroups[pingroup].mux_reg >= 0) {
+               err = tegra_pinmux_set_func(config);
                if (err < 0)
                        pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
                               pingroup_name(pingroup), func_name(func), err);
        }
 
-       if (pingroups[pingroup].pupd_reg != REG_N) {
+       if (pingroups[pingroup].pupd_reg >= 0) {
                err = tegra_pinmux_set_pullupdown(pingroup, pupd);
                if (err < 0)
                        pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
                               pingroup_name(pingroup), pupd_name(pupd), err);
        }
 
-       if (pingroups[pingroup].tri_reg != REG_N) {
+       if (pingroups[pingroup].tri_reg >= 0) {
                err = tegra_pinmux_set_tristate(pingroup, tristate);
                if (err < 0)
                        pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
@@ -507,17 +312,12 @@ void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
        }
 }
 
-
-
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len)
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               tegra_pinmux_config_pingroup(config[i].pingroup,
-                                            config[i].func,
-                                            config[i].pupd,
-                                            config[i].tristate);
+               tegra_pinmux_config_pingroup(&config[i]);
 }
 
 static const char *drive_pinmux_name(enum tegra_drive_pingroup pg)
@@ -784,6 +584,86 @@ void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
                                                     config[i].slew_falling);
 }
 
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+       int len)
+{
+       int i;
+       struct tegra_pingroup_config c;
+
+       for (i = 0; i < len; i++) {
+               int err;
+               c = config[i];
+               if (c.pingroup < 0 || c.pingroup >= TEGRA_MAX_PINGROUP) {
+                       WARN_ON(1);
+                       continue;
+               }
+               c.func = pingroups[c.pingroup].func_safe;
+               err = tegra_pinmux_set_func(&c);
+               if (err < 0)
+                       pr_err("%s: tegra_pinmux_set_func returned %d setting "
+                              "%s to %s\n", __func__, err,
+                              pingroup_name(c.pingroup), func_name(c.func));
+       }
+}
+
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+       int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               int err;
+               if (config[i].pingroup < 0 ||
+                   config[i].pingroup >= TEGRA_MAX_PINGROUP) {
+                       WARN_ON(1);
+                       continue;
+               }
+               err = tegra_pinmux_set_func(&config[i]);
+               if (err < 0)
+                       pr_err("%s: tegra_pinmux_set_func returned %d setting "
+                              "%s to %s\n", __func__, err,
+                              pingroup_name(config[i].pingroup),
+                              func_name(config[i].func));
+       }
+}
+
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+       int len, enum tegra_tristate tristate)
+{
+       int i;
+       int err;
+       enum tegra_pingroup pingroup;
+
+       for (i = 0; i < len; i++) {
+               pingroup = config[i].pingroup;
+               if (pingroups[pingroup].tri_reg >= 0) {
+                       err = tegra_pinmux_set_tristate(pingroup, tristate);
+                       if (err < 0)
+                               pr_err("pinmux: can't set pingroup %s tristate"
+                                       " to %s: %d\n", pingroup_name(pingroup),
+                                       tri_name(tristate), err);
+               }
+       }
+}
+
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+       int len, enum tegra_pullupdown pupd)
+{
+       int i;
+       int err;
+       enum tegra_pingroup pingroup;
+
+       for (i = 0; i < len; i++) {
+               pingroup = config[i].pingroup;
+               if (pingroups[pingroup].pupd_reg >= 0) {
+                       err = tegra_pinmux_set_pullupdown(pingroup, pupd);
+                       if (err < 0)
+                               pr_err("pinmux: can't set pingroup %s pullupdown"
+                                       " to %s: %d\n", pingroup_name(pingroup),
+                                       pupd_name(pupd), err);
+               }
+       }
+}
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -812,11 +692,11 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
                len = strlen(pingroups[i].name);
                dbg_pad_field(s, 5 - len);
 
-               if (pingroups[i].mux_reg == REG_N) {
+               if (pingroups[i].mux_reg < 0) {
                        seq_printf(s, "TEGRA_MUX_NONE");
                        len = strlen("NONE");
                } else {
-                       mux = (pg_readl(TEGRA_PP_MUX_CTL(pingroups[i].mux_reg)) >>
+                       mux = (pg_readl(pingroups[i].mux_reg) >>
                               pingroups[i].mux_bit) & 0x3;
                        if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
                                seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
@@ -829,21 +709,21 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
                }
                dbg_pad_field(s, 13-len);
 
-               if (pingroups[i].mux_reg == REG_N) {
+               if (pingroups[i].pupd_reg < 0) {
                        seq_printf(s, "TEGRA_PUPD_NORMAL");
                        len = strlen("NORMAL");
                } else {
-                       pupd = (pg_readl(TEGRA_PP_PU_PD(pingroups[i].pupd_reg)) >>
+                       pupd = (pg_readl(pingroups[i].pupd_reg) >>
                                pingroups[i].pupd_bit) & 0x3;
                        seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
                        len = strlen(pupd_name(pupd));
                }
                dbg_pad_field(s, 9 - len);
 
-               if (pingroups[i].tri_reg == REG_N) {
+               if (pingroups[i].tri_reg < 0) {
                        seq_printf(s, "TEGRA_TRI_NORMAL");
                } else {
-                       tri = (pg_readl(TEGRA_TRI_STATE(pingroups[i].tri_reg)) >>
+                       tri = (pg_readl(pingroups[i].tri_reg) >>
                               pingroups[i].tri_bit) & 0x1;
 
                        seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
index 426163231fff155cdd9c1a9094e33d3ac6fa7217..ae3b308e22a4d158b464d8b47f383a7509cf6efd 100644 (file)
 #include <mach/iomap.h>
 
 #include "clock.h"
+#include "fuse.h"
+#include "tegra2_dvfs.h"
 
 #define RST_DEVICES                    0x004
 #define RST_DEVICES_SET                        0x300
 #define RST_DEVICES_CLR                        0x304
+#define RST_DEVICES_NUM                        3
 
 #define CLK_OUT_ENB                    0x010
 #define CLK_OUT_ENB_SET                        0x320
 #define CLK_OUT_ENB_CLR                        0x324
+#define CLK_OUT_ENB_NUM                        3
+
+#define CLK_MASK_ARM                   0x44
+#define MISC_CLK_ENB                   0x48
 
 #define OSC_CTRL                       0x50
 #define OSC_CTRL_OSC_FREQ_MASK         (3<<30)
@@ -45,6 +52,7 @@
 #define OSC_CTRL_OSC_FREQ_19_2MHZ      (1<<30)
 #define OSC_CTRL_OSC_FREQ_12MHZ                (2<<30)
 #define OSC_CTRL_OSC_FREQ_26MHZ                (3<<30)
+#define OSC_CTRL_MASK                  0x3f2
 
 #define OSC_FREQ_DET                   0x58
 #define OSC_FREQ_DET_TRIG              (1<<31)
 #define OSC_FREQ_DET_BUSY              (1<<31)
 #define OSC_FREQ_DET_CNT_MASK          0xFFFF
 
+#define PERIPH_CLK_SOURCE_I2S1         0x100
+#define PERIPH_CLK_SOURCE_EMC          0x19c
+#define PERIPH_CLK_SOURCE_OSC          0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+       ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
 #define PERIPH_CLK_SOURCE_MASK         (3<<30)
 #define PERIPH_CLK_SOURCE_SHIFT                30
 #define PERIPH_CLK_SOURCE_ENABLE       (1<<28)
-#define PERIPH_CLK_SOURCE_DIV_MASK     0xFF
+#define PERIPH_CLK_SOURCE_DIVU71_MASK  0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK  0xFFFF
 #define PERIPH_CLK_SOURCE_DIV_SHIFT    0
 
 #define PLL_BASE                       0x0
@@ -79,8 +94,9 @@
 #define PLL_OUT_RESET_DISABLE          (1<<0)
 
 #define PLL_MISC(c)                    (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+#define PLL_MISC_LOCK_ENABLE(c)                (((c)->flags & PLLU) ? (1<<22) : (1<<18))
+
 #define PLL_MISC_DCCON_SHIFT           20
-#define PLL_MISC_LOCK_ENABLE           (1<<18)
 #define PLL_MISC_CPCON_SHIFT           8
 #define PLL_MISC_CPCON_MASK            (0xF<<PLL_MISC_CPCON_SHIFT)
 #define PLL_MISC_LFCON_SHIFT           4
 #define PLL_MISC_VCOCON_SHIFT          0
 #define PLL_MISC_VCOCON_MASK           (0xF<<PLL_MISC_VCOCON_SHIFT)
 
+#define PLLU_BASE_POST_DIV             (1<<20)
+
 #define PLLD_MISC_CLKENABLE            (1<<30)
 #define PLLD_MISC_DIV_RST              (1<<23)
 #define PLLD_MISC_DCCON_SHIFT          12
 
+#define PLLE_MISC_READY                        (1 << 15)
+
 #define PERIPH_CLK_TO_ENB_REG(c)       ((c->clk_num / 32) * 4)
 #define PERIPH_CLK_TO_ENB_SET_REG(c)   ((c->clk_num / 32) * 8)
 #define PERIPH_CLK_TO_ENB_BIT(c)       (1 << (c->clk_num % 32))
@@ -143,30 +163,37 @@ unsigned long clk_measure_input_freq(void)
        }
 }
 
-static int clk_div71_get_divider(struct clk *c, unsigned long rate)
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
 {
-       unsigned long divider_u71;
+       s64 divider_u71 = parent_rate * 2;
+       divider_u71 += rate - 1;
+       do_div(divider_u71, rate);
 
-       divider_u71 = DIV_ROUND_UP(c->rate * 2, rate);
+       if (divider_u71 - 2 < 0)
+               return 0;
 
-       if (divider_u71 - 2 > 255 || divider_u71 - 2 < 0)
+       if (divider_u71 - 2 > 255)
                return -EINVAL;
 
        return divider_u71 - 2;
 }
 
-static unsigned long tegra2_clk_recalculate_rate(struct clk *c)
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
 {
-       unsigned long rate;
-       rate = c->parent->rate;
+       s64 divider_u16;
 
-       if (c->mul != 0 && c->div != 0)
-               c->rate = rate * c->mul / c->div;
-       else
-               c->rate = rate;
-       return c->rate;
-}
+       divider_u16 = parent_rate;
+       divider_u16 += rate - 1;
+       do_div(divider_u16, rate);
+
+       if (divider_u16 - 1 < 0)
+               return 0;
 
+       if (divider_u16 - 1 > 255)
+               return -EINVAL;
+
+       return divider_u16 - 1;
+}
 
 /* clk_m functions */
 static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
@@ -244,7 +271,6 @@ static void tegra2_super_clk_init(struct clk *c)
        }
        BUG_ON(sel->input == NULL);
        c->parent = sel->input;
-       tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_super_clk_enable(struct clk *c)
@@ -266,6 +292,7 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
        u32 val;
        const struct clk_mux_sel *sel;
        int shift;
+
        val = clk_readl(c->reg + SUPER_CLK_MUX);;
        BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
                ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
@@ -273,11 +300,18 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
                SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
        for (sel = c->inputs; sel->input != NULL; sel++) {
                if (sel->input == p) {
-                       clk_reparent(c, p);
                        val &= ~(SUPER_SOURCE_MASK << shift);
                        val |= sel->value << shift;
+
+                       if (c->refcnt)
+                               clk_enable_locked(p);
+
                        clk_writel(val, c->reg);
-                       c->rate = c->parent->rate;
+
+                       if (c->refcnt && c->parent)
+                               clk_disable_locked(c->parent);
+
+                       clk_reparent(c, p);
                        return 0;
                }
        }
@@ -289,7 +323,61 @@ static struct clk_ops tegra_super_ops = {
        .enable                 = tegra2_super_clk_enable,
        .disable                = tegra2_super_clk_disable,
        .set_parent             = tegra2_super_clk_set_parent,
-       .recalculate_rate       = tegra2_clk_recalculate_rate,
+};
+
+/* virtual cpu clock functions */
+/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
+   To change the frequency of these clocks, the parent pll may need to be
+   reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
+   and then the clock moved back to the pll.  To hide this sequence, a virtual
+   clock handles it.
+ */
+static void tegra2_cpu_clk_init(struct clk *c)
+{
+}
+
+static int tegra2_cpu_clk_enable(struct clk *c)
+{
+       return 0;
+}
+
+static void tegra2_cpu_clk_disable(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       /* oops - don't disable the CPU clock! */
+       BUG();
+}
+
+static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       int ret;
+       ret = clk_set_parent_locked(c->parent, c->backup);
+       if (ret) {
+               pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
+               return ret;
+       }
+
+       ret = clk_set_rate_locked(c->main, rate);
+       if (ret) {
+               pr_err("Failed to change cpu pll to %lu\n", rate);
+               return ret;
+       }
+
+       ret = clk_set_parent_locked(c->parent, c->main);
+       if (ret) {
+               pr_err("Failed to switch cpu to clock %s\n", c->main->name);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct clk_ops tegra_cpu_ops = {
+       .init     = tegra2_cpu_clk_init,
+       .enable   = tegra2_cpu_clk_enable,
+       .disable  = tegra2_cpu_clk_disable,
+       .set_rate = tegra2_cpu_clk_set_rate,
 };
 
 /* bus clock functions */
@@ -299,7 +387,6 @@ static void tegra2_bus_clk_init(struct clk *c)
        c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
        c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
        c->mul = 1;
-       tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_bus_clk_enable(struct clk *c)
@@ -340,27 +427,15 @@ static struct clk_ops tegra_bus_ops = {
        .enable                 = tegra2_bus_clk_enable,
        .disable                = tegra2_bus_clk_disable,
        .set_rate               = tegra2_bus_clk_set_rate,
-       .recalculate_rate       = tegra2_clk_recalculate_rate,
 };
 
 /* PLL Functions */
-static unsigned long tegra2_pll_clk_recalculate_rate(struct clk *c)
-{
-       u64 rate;
-       rate = c->parent->rate;
-       rate *= c->n;
-       do_div(rate, c->m);
-       if (c->p == 2)
-               rate >>= 1;
-       c->rate = rate;
-       return c->rate;
-}
-
 static int tegra2_pll_clk_wait_for_lock(struct clk *c)
 {
        ktime_t before;
 
        before = ktime_get();
+
        while (!(clk_readl(c->reg + PLL_BASE) & PLL_BASE_LOCK)) {
                if (ktime_us_delta(ktime_get(), before) > 5000) {
                        pr_err("Timed out waiting for lock bit on pll %s",
@@ -380,24 +455,19 @@ static void tegra2_pll_clk_init(struct clk *c)
 
        if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
                pr_warning("Clock %s has unknown fixed frequency\n", c->name);
-               c->n = 1;
-               c->m = 0;
-               c->p = 1;
+               c->mul = 1;
+               c->div = 1;
        } else if (val & PLL_BASE_BYPASS) {
-               c->n = 1;
-               c->m = 1;
-               c->p = 1;
+               c->mul = 1;
+               c->div = 1;
        } else {
-               c->n = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-               c->m = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-               c->p = (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+               c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+               c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+               if (c->flags & PLLU)
+                       c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+               else
+                       c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
        }
-
-       val = clk_readl(c->reg + PLL_MISC(c));
-       if (c->flags & PLL_HAS_CPCON)
-               c->cpcon = (val & PLL_MISC_CPCON_MASK) >> PLL_MISC_CPCON_SHIFT;
-
-       tegra2_pll_clk_recalculate_rate(c);
 }
 
 static int tegra2_pll_clk_enable(struct clk *c)
@@ -411,7 +481,7 @@ static int tegra2_pll_clk_enable(struct clk *c)
        clk_writel(val, c->reg + PLL_BASE);
 
        val = clk_readl(c->reg + PLL_MISC(c));
-       val |= PLL_MISC_LOCK_ENABLE;
+       val |= PLL_MISC_LOCK_ENABLE(c);
        clk_writel(val, c->reg + PLL_MISC(c));
 
        tegra2_pll_clk_wait_for_lock(c);
@@ -441,33 +511,36 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
        input_rate = c->parent->rate;
        for (sel = c->pll_table; sel->input_rate != 0; sel++) {
                if (sel->input_rate == input_rate && sel->output_rate == rate) {
-                       c->n = sel->n;
-                       c->m = sel->m;
-                       c->p = sel->p;
-                       c->cpcon = sel->cpcon;
+                       c->mul = sel->n;
+                       c->div = sel->m * sel->p;
 
                        val = clk_readl(c->reg + PLL_BASE);
                        if (c->flags & PLL_FIXED)
                                val |= PLL_BASE_OVERRIDE;
                        val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
                                 PLL_BASE_DIVM_MASK);
-                       val |= (c->m << PLL_BASE_DIVM_SHIFT) |
-                               (c->n << PLL_BASE_DIVN_SHIFT);
-                       BUG_ON(c->p > 2);
-                       if (c->p == 2)
-                               val |= 1 << PLL_BASE_DIVP_SHIFT;
+                       val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+                               (sel->n << PLL_BASE_DIVN_SHIFT);
+                       BUG_ON(sel->p < 1 || sel->p > 2);
+                       if (c->flags & PLLU) {
+                               if (sel->p == 1)
+                                       val |= PLLU_BASE_POST_DIV;
+                       } else {
+                               if (sel->p == 2)
+                                       val |= 1 << PLL_BASE_DIVP_SHIFT;
+                       }
                        clk_writel(val, c->reg + PLL_BASE);
 
                        if (c->flags & PLL_HAS_CPCON) {
-                               val = c->cpcon << PLL_MISC_CPCON_SHIFT;
-                               val |= PLL_MISC_LOCK_ENABLE;
+                               val = clk_readl(c->reg + PLL_MISC(c));
+                               val &= ~PLL_MISC_CPCON_MASK;
+                               val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
                                clk_writel(val, c->reg + PLL_MISC(c));
                        }
 
                        if (c->state == ON)
                                tegra2_pll_clk_enable(c);
 
-                       c->rate = rate;
                        return 0;
                }
        }
@@ -479,7 +552,46 @@ static struct clk_ops tegra_pll_ops = {
        .enable                 = tegra2_pll_clk_enable,
        .disable                = tegra2_pll_clk_disable,
        .set_rate               = tegra2_pll_clk_set_rate,
-       .recalculate_rate       = tegra2_pll_clk_recalculate_rate,
+};
+
+static void tegra2_pllx_clk_init(struct clk *c)
+{
+       tegra2_pll_clk_init(c);
+
+       if (tegra_sku_id() == 7)
+               c->max_rate = 750000000;
+}
+
+static struct clk_ops tegra_pllx_ops = {
+       .init     = tegra2_pllx_clk_init,
+       .enable   = tegra2_pll_clk_enable,
+       .disable  = tegra2_pll_clk_disable,
+       .set_rate = tegra2_pll_clk_set_rate,
+};
+
+static int tegra2_plle_clk_enable(struct clk *c)
+{
+       u32 val;
+
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       mdelay(1);
+
+       val = clk_readl(c->reg + PLL_BASE);
+       if (!(val & PLLE_MISC_READY))
+               return -EBUSY;
+
+       val = clk_readl(c->reg + PLL_BASE);
+       val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+       clk_writel(val, c->reg + PLL_BASE);
+
+       return 0;
+}
+
+static struct clk_ops tegra_plle_ops = {
+       .init       = tegra2_pll_clk_init,
+       .enable     = tegra2_plle_clk_enable,
+       .set_rate   = tegra2_pll_clk_set_rate,
 };
 
 /* Clock divider ops */
@@ -503,8 +615,6 @@ static void tegra2_pll_div_clk_init(struct clk *c)
                c->div = 1;
                c->mul = 1;
        }
-
-       tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_pll_div_clk_enable(struct clk *c)
@@ -565,7 +675,7 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
        int divider_u71;
        pr_debug("%s: %s %lu\n", __func__, c->name, rate);
        if (c->flags & DIV_U71) {
-               divider_u71 = clk_div71_get_divider(c->parent, rate);
+               divider_u71 = clk_div71_get_divider(c->parent->rate, rate);
                if (divider_u71 >= 0) {
                        val = clk_readl(c->reg);
                        new_val = val >> c->reg_shift;
@@ -580,25 +690,37 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
                        clk_writel(val, c->reg);
                        c->div = divider_u71 + 2;
                        c->mul = 2;
-                       tegra2_clk_recalculate_rate(c);
                        return 0;
                }
        } else if (c->flags & DIV_2) {
-               if (c->parent->rate == rate * 2) {
-                       c->rate = rate;
+               if (c->parent->rate == rate * 2)
                        return 0;
-               }
        }
        return -EINVAL;
 }
 
+static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+       int divider;
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+       if (c->flags & DIV_U71) {
+               divider = clk_div71_get_divider(c->parent->rate, rate);
+               if (divider < 0)
+                       return divider;
+               return c->parent->rate * 2 / (divider + 2);
+       } else if (c->flags & DIV_2) {
+               return c->parent->rate / 2;
+       }
+       return -EINVAL;
+}
 
 static struct clk_ops tegra_pll_div_ops = {
        .init                   = tegra2_pll_div_clk_init,
        .enable                 = tegra2_pll_div_clk_enable,
        .disable                = tegra2_pll_div_clk_disable,
        .set_rate               = tegra2_pll_div_clk_set_rate,
-       .recalculate_rate       = tegra2_clk_recalculate_rate,
+       .round_rate             = tegra2_pll_div_clk_round_rate,
 };
 
 /* Periph clk ops */
@@ -621,9 +743,13 @@ static void tegra2_periph_clk_init(struct clk *c)
        }
 
        if (c->flags & DIV_U71) {
-               u32 divu71 = val & PERIPH_CLK_SOURCE_DIV_MASK;
+               u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
                c->div = divu71 + 2;
                c->mul = 2;
+       } else if (c->flags & DIV_U16) {
+               u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+               c->div = divu16 + 1;
+               c->mul = 1;
        } else {
                c->div = 1;
                c->mul = 1;
@@ -637,7 +763,6 @@ static void tegra2_periph_clk_init(struct clk *c)
                if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
                                PERIPH_CLK_TO_ENB_BIT(c))
                        c->state = OFF;
-       tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_periph_clk_enable(struct clk *c)
@@ -692,12 +817,19 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
        pr_debug("%s: %s %s\n", __func__, c->name, p->name);
        for (sel = c->inputs; sel->input != NULL; sel++) {
                if (sel->input == p) {
-                       clk_reparent(c, p);
                        val = clk_readl(c->reg);
                        val &= ~PERIPH_CLK_SOURCE_MASK;
                        val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
+
+                       if (c->refcnt)
+                               clk_enable_locked(p);
+
                        clk_writel(val, c->reg);
-                       c->rate = c->parent->rate;
+
+                       if (c->refcnt && c->parent)
+                               clk_disable_locked(c->parent);
+
+                       clk_reparent(c, p);
                        return 0;
                }
        }
@@ -708,20 +840,55 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
 static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
 {
        u32 val;
-       int divider_u71;
+       int divider;
        pr_debug("%s: %lu\n", __func__, rate);
        if (c->flags & DIV_U71) {
-               divider_u71 = clk_div71_get_divider(c->parent, rate);
-               if (divider_u71 >= 0) {
+               divider = clk_div71_get_divider(c->parent->rate, rate);
+               if (divider >= 0) {
                        val = clk_readl(c->reg);
-                       val &= ~PERIPH_CLK_SOURCE_DIV_MASK;
-                       val |= divider_u71;
+                       val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+                       val |= divider;
                        clk_writel(val, c->reg);
-                       c->div = divider_u71 + 2;
+                       c->div = divider + 2;
                        c->mul = 2;
-                       tegra2_clk_recalculate_rate(c);
                        return 0;
                }
+       } else if (c->flags & DIV_U16) {
+               divider = clk_div16_get_divider(c->parent->rate, rate);
+               if (divider >= 0) {
+                       val = clk_readl(c->reg);
+                       val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+                       val |= divider;
+                       clk_writel(val, c->reg);
+                       c->div = divider + 1;
+                       c->mul = 1;
+                       return 0;
+               }
+       } else if (c->parent->rate <= rate) {
+               c->div = 1;
+               c->mul = 1;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static long tegra2_periph_clk_round_rate(struct clk *c,
+       unsigned long rate)
+{
+       int divider;
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+       if (c->flags & DIV_U71) {
+               divider = clk_div71_get_divider(c->parent->rate, rate);
+               if (divider < 0)
+                       return divider;
+
+               return c->parent->rate * 2 / (divider + 2);
+       } else if (c->flags & DIV_U16) {
+               divider = clk_div16_get_divider(c->parent->rate, rate);
+               if (divider < 0)
+                       return divider;
+               return c->parent->rate / (divider + 1);
        }
        return -EINVAL;
 }
@@ -732,7 +899,7 @@ static struct clk_ops tegra_periph_clk_ops = {
        .disable                = &tegra2_periph_clk_disable,
        .set_parent             = &tegra2_periph_clk_set_parent,
        .set_rate               = &tegra2_periph_clk_set_rate,
-       .recalculate_rate       = &tegra2_clk_recalculate_rate,
+       .round_rate             = &tegra2_periph_clk_round_rate,
 };
 
 /* Clock doubler ops */
@@ -744,21 +911,108 @@ static void tegra2_clk_double_init(struct clk *c)
        if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
                        PERIPH_CLK_TO_ENB_BIT(c)))
                c->state = OFF;
-       tegra2_clk_recalculate_rate(c);
 };
 
+static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+       if (rate != 2 * c->parent->rate)
+               return -EINVAL;
+       c->mul = 2;
+       c->div = 1;
+       return 0;
+}
+
 static struct clk_ops tegra_clk_double_ops = {
        .init                   = &tegra2_clk_double_init,
        .enable                 = &tegra2_periph_clk_enable,
        .disable                = &tegra2_periph_clk_disable,
-       .recalculate_rate       = &tegra2_clk_recalculate_rate,
+       .set_rate               = &tegra2_clk_double_set_rate,
+};
+
+static void tegra2_audio_sync_clk_init(struct clk *c)
+{
+       int source;
+       const struct clk_mux_sel *sel;
+       u32 val = clk_readl(c->reg);
+       c->state = (val & (1<<4)) ? OFF : ON;
+       source = val & 0xf;
+       for (sel = c->inputs; sel->input != NULL; sel++)
+               if (sel->value == source)
+                       break;
+       BUG_ON(sel->input == NULL);
+       c->parent = sel->input;
+}
+
+static int tegra2_audio_sync_clk_enable(struct clk *c)
+{
+       clk_writel(0, c->reg);
+       return 0;
+}
+
+static void tegra2_audio_sync_clk_disable(struct clk *c)
+{
+       clk_writel(1, c->reg);
+}
+
+static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+       u32 val;
+       const struct clk_mux_sel *sel;
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       val = clk_readl(c->reg);
+                       val &= ~0xf;
+                       val |= sel->value;
+
+                       if (c->refcnt)
+                               clk_enable_locked(p);
+
+                       clk_writel(val, c->reg);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable_locked(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       unsigned long parent_rate;
+       if (!c->parent) {
+               pr_err("%s: clock has no parent\n", __func__);
+               return -EINVAL;
+       }
+       parent_rate = c->parent->rate;
+       if (rate != parent_rate) {
+               pr_err("%s: %s/%ld differs from parent %s/%ld\n",
+                       __func__,
+                       c->name, rate,
+                       c->parent->name, parent_rate);
+               return -EINVAL;
+       }
+       c->rate = parent_rate;
+       return 0;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+       .init       = tegra2_audio_sync_clk_init,
+       .enable     = tegra2_audio_sync_clk_enable,
+       .disable    = tegra2_audio_sync_clk_disable,
+       .set_rate   = tegra2_audio_sync_clk_set_rate,
+       .set_parent = tegra2_audio_sync_clk_set_parent,
 };
 
 /* Clock definitions */
 static struct clk tegra_clk_32k = {
        .name = "clk_32k",
-       .rate = 32678,
+       .rate = 32768,
        .ops  = NULL,
+       .max_rate = 32768,
 };
 
 static struct clk_pll_table tegra_pll_s_table[] = {
@@ -782,6 +1036,7 @@ static struct clk tegra_pll_s = {
        .vco_min   = 12000000,
        .vco_max   = 26000000,
        .pll_table = tegra_pll_s_table,
+       .max_rate  = 26000000,
 };
 
 static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -797,6 +1052,7 @@ static struct clk tegra_clk_m = {
        .reg       = 0x1fc,
        .reg_mask  = (1<<28),
        .reg_shift = 28,
+       .max_rate  = 26000000,
 };
 
 static struct clk_pll_table tegra_pll_c_table[] = {
@@ -816,6 +1072,7 @@ static struct clk tegra_pll_c = {
        .vco_min   = 20000000,
        .vco_max   = 1400000000,
        .pll_table = tegra_pll_c_table,
+       .max_rate  = 600000000,
 };
 
 static struct clk tegra_pll_c_out1 = {
@@ -825,9 +1082,18 @@ static struct clk tegra_pll_c_out1 = {
        .parent    = &tegra_pll_c,
        .reg       = 0x84,
        .reg_shift = 0,
+       .max_rate  = 600000000,
 };
 
 static struct clk_pll_table tegra_pll_m_table[] = {
+       { 12000000, 666000000, 666, 12, 1, 8},
+       { 13000000, 666000000, 666, 13, 1, 8},
+       { 19200000, 666000000, 555, 16, 1, 8},
+       { 26000000, 666000000, 666, 26, 1, 8},
+       { 12000000, 600000000, 600, 12, 1, 8},
+       { 13000000, 600000000, 600, 13, 1, 8},
+       { 19200000, 600000000, 375, 12, 1, 6},
+       { 26000000, 600000000, 600, 26, 1, 8},
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -844,6 +1110,7 @@ static struct clk tegra_pll_m = {
        .vco_min   = 20000000,
        .vco_max   = 1200000000,
        .pll_table = tegra_pll_m_table,
+       .max_rate  = 800000000,
 };
 
 static struct clk tegra_pll_m_out1 = {
@@ -853,6 +1120,7 @@ static struct clk tegra_pll_m_out1 = {
        .parent    = &tegra_pll_m,
        .reg       = 0x94,
        .reg_shift = 0,
+       .max_rate  = 600000000,
 };
 
 static struct clk_pll_table tegra_pll_p_table[] = {
@@ -880,6 +1148,7 @@ static struct clk tegra_pll_p = {
        .vco_min   = 20000000,
        .vco_max   = 1400000000,
        .pll_table = tegra_pll_p_table,
+       .max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out1 = {
@@ -889,6 +1158,7 @@ static struct clk tegra_pll_p_out1 = {
        .parent    = &tegra_pll_p,
        .reg       = 0xa4,
        .reg_shift = 0,
+       .max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out2 = {
@@ -898,6 +1168,7 @@ static struct clk tegra_pll_p_out2 = {
        .parent    = &tegra_pll_p,
        .reg       = 0xa4,
        .reg_shift = 16,
+       .max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out3 = {
@@ -907,6 +1178,7 @@ static struct clk tegra_pll_p_out3 = {
        .parent    = &tegra_pll_p,
        .reg       = 0xa8,
        .reg_shift = 0,
+       .max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out4 = {
@@ -916,6 +1188,7 @@ static struct clk tegra_pll_p_out4 = {
        .parent    = &tegra_pll_p,
        .reg       = 0xa8,
        .reg_shift = 16,
+       .max_rate  = 432000000,
 };
 
 static struct clk_pll_table tegra_pll_a_table[] = {
@@ -923,6 +1196,7 @@ static struct clk_pll_table tegra_pll_a_table[] = {
        { 28800000, 73728000, 64, 25, 1, 1},
        { 28800000, 11289600, 49, 25, 1, 1},
        { 28800000, 12288000, 64, 25, 1, 1},
+       { 28800000, 24000000,  5,  6, 1, 1},
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -939,6 +1213,7 @@ static struct clk tegra_pll_a = {
        .vco_min   = 20000000,
        .vco_max   = 1400000000,
        .pll_table = tegra_pll_a_table,
+       .max_rate  = 56448000,
 };
 
 static struct clk tegra_pll_a_out0 = {
@@ -948,6 +1223,7 @@ static struct clk tegra_pll_a_out0 = {
        .parent    = &tegra_pll_a,
        .reg       = 0xb4,
        .reg_shift = 0,
+       .max_rate  = 56448000,
 };
 
 static struct clk_pll_table tegra_pll_d_table[] = {
@@ -971,6 +1247,7 @@ static struct clk tegra_pll_d = {
        .vco_min   = 40000000,
        .vco_max   = 1000000000,
        .pll_table = tegra_pll_d_table,
+       .max_rate  = 1000000000,
 };
 
 static struct clk tegra_pll_d_out0 = {
@@ -978,19 +1255,20 @@ static struct clk tegra_pll_d_out0 = {
        .ops       = &tegra_pll_div_ops,
        .flags     = DIV_2 | PLLD,
        .parent    = &tegra_pll_d,
+       .max_rate  = 500000000,
 };
 
 static struct clk_pll_table tegra_pll_u_table[] = {
-       { 12000000, 480000000, 960, 12, 1, 0},
-       { 13000000, 480000000, 960, 13, 1, 0},
-       { 19200000, 480000000, 200, 4,  1, 0},
-       { 26000000, 480000000, 960, 26, 1, 0},
+       { 12000000, 480000000, 960, 12, 2, 0},
+       { 13000000, 480000000, 960, 13, 2, 0},
+       { 19200000, 480000000, 200, 4,  2, 0},
+       { 26000000, 480000000, 960, 26, 2, 0},
        { 0, 0, 0, 0, 0, 0 },
 };
 
 static struct clk tegra_pll_u = {
        .name      = "pll_u",
-       .flags     = 0,
+       .flags     = PLLU,
        .ops       = &tegra_pll_ops,
        .reg       = 0xc0,
        .input_min = 2000000,
@@ -1001,24 +1279,59 @@ static struct clk tegra_pll_u = {
        .vco_min   = 480000000,
        .vco_max   = 960000000,
        .pll_table = tegra_pll_u_table,
+       .max_rate  = 480000000,
 };
 
 static struct clk_pll_table tegra_pll_x_table[] = {
+       /* 1 GHz */
        { 12000000, 1000000000, 1000, 12, 1, 12},
        { 13000000, 1000000000, 1000, 13, 1, 12},
        { 19200000, 1000000000, 625,  12, 1, 8},
        { 26000000, 1000000000, 1000, 26, 1, 12},
-       { 12000000, 750000000,  750,  12, 1, 12},
-       { 13000000, 750000000,  750,  13, 1, 12},
-       { 19200000, 750000000,  625,  16, 1, 8},
-       { 26000000, 750000000,  750,  26, 1, 12},
+
+       /* 912 MHz */
+       { 12000000, 912000000,  912,  12, 1, 12},
+       { 13000000, 912000000,  912,  13, 1, 12},
+       { 19200000, 912000000,  760,  16, 1, 8},
+       { 26000000, 912000000,  912,  26, 1, 12},
+
+       /* 816 MHz */
+       { 12000000, 816000000,  816,  12, 1, 12},
+       { 13000000, 816000000,  816,  13, 1, 12},
+       { 19200000, 816000000,  680,  16, 1, 8},
+       { 26000000, 816000000,  816,  26, 1, 12},
+
+       /* 760 MHz */
+       { 12000000, 760000000,  760,  12, 1, 12},
+       { 13000000, 760000000,  760,  13, 1, 12},
+       { 19200000, 760000000,  950,  24, 1, 8},
+       { 26000000, 760000000,  760,  26, 1, 12},
+
+       /* 608 MHz */
+       { 12000000, 608000000,  760,  12, 1, 12},
+       { 13000000, 608000000,  760,  13, 1, 12},
+       { 19200000, 608000000,  380,  12, 1, 8},
+       { 26000000, 608000000,  760,  26, 1, 12},
+
+       /* 456 MHz */
+       { 12000000, 456000000,  456,  12, 1, 12},
+       { 13000000, 456000000,  456,  13, 1, 12},
+       { 19200000, 456000000,  380,  16, 1, 8},
+       { 26000000, 456000000,  456,  26, 1, 12},
+
+       /* 312 MHz */
+       { 12000000, 312000000,  312,  12, 1, 12},
+       { 13000000, 312000000,  312,  13, 1, 12},
+       { 19200000, 312000000,  260,  16, 1, 8},
+       { 26000000, 312000000,  312,  26, 1, 12},
+
        { 0, 0, 0, 0, 0, 0 },
 };
 
 static struct clk tegra_pll_x = {
        .name      = "pll_x",
        .flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
-       .ops       = &tegra_pll_ops,
+       .ops       = &tegra_pllx_ops,
        .reg       = 0xe0,
        .input_min = 2000000,
        .input_max = 31000000,
@@ -1028,6 +1341,24 @@ static struct clk tegra_pll_x = {
        .vco_min   = 20000000,
        .vco_max   = 1200000000,
        .pll_table = tegra_pll_x_table,
+       .max_rate  = 1000000000,
+};
+
+static struct clk_pll_table tegra_pll_e_table[] = {
+       { 12000000, 100000000,  200,  24, 1, 0 },
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+       .name      = "pll_e",
+       .flags     = PLL_ALT_MISC_REG,
+       .ops       = &tegra_plle_ops,
+       .input_min = 12000000,
+       .input_max = 12000000,
+       .max_rate  = 100000000,
+       .parent    = &tegra_clk_m,
+       .reg       = 0xe8,
+       .pll_table = tegra_pll_e_table,
 };
 
 static struct clk tegra_clk_d = {
@@ -1038,19 +1369,77 @@ static struct clk tegra_clk_d = {
        .reg       = 0x34,
        .reg_shift = 12,
        .parent    = &tegra_clk_m,
+       .max_rate  = 52000000,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+       const char *name;
+       int value;
+} mux_audio_sync_clk_sources[] = {
+       { .name = "spdif_in", .value = 0 },
+       { .name = "i2s1", .value = 1 },
+       { .name = "i2s2", .value = 2 },
+       { .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+       { .name = "ac97", .value = 3 },
+       { .name = "ext_audio_clk2", .value = 5 },
+       { .name = "ext_audio_clk1", .value = 6 },
+       { .name = "ext_vimclk", .value = 7 },
+#endif
+       { 0, 0 }
+};
+
+static struct clk tegra_clk_audio = {
+       .name      = "audio",
+       .inputs    = mux_audio_sync_clk,
+       .reg       = 0x38,
+       .max_rate  = 24000000,
+       .ops       = &tegra_audio_sync_clk_ops
 };
 
-/* FIXME: need tegra_audio
 static struct clk tegra_clk_audio_2x = {
-       .name      = "clk_d",
+       .name      = "audio_2x",
        .flags     = PERIPH_NO_RESET,
+       .max_rate  = 48000000,
        .ops       = &tegra_clk_double_ops,
        .clk_num   = 89,
        .reg       = 0x34,
        .reg_shift = 8,
-       .parent    = &tegra_audio,
+       .parent    = &tegra_clk_audio,
+};
+
+struct clk_lookup tegra_audio_clk_lookups[] = {
+       { .con_id = "audio", .clk = &tegra_clk_audio },
+       { .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+       int i;
+       struct clk_mux_sel *sel = mux_audio_sync_clk;
+       const struct audio_sources *src = mux_audio_sync_clk_sources;
+       struct clk_lookup *lookup;
+
+       for (i = 0; src->name; i++, sel++, src++) {
+               sel->input = tegra_get_clock_by_name(src->name);
+               if (!sel->input)
+                       pr_err("%s: could not find clk %s\n", __func__,
+                               src->name);
+               sel->value = src->value;
+       }
+
+       lookup = tegra_audio_clk_lookups;
+       for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+               clk_init(lookup->clk);
+               clkdev_add(lookup);
+       }
 }
-*/
 
 static struct clk_mux_sel mux_cclk[] = {
        { .input = &tegra_clk_m,        .value = 0},
@@ -1077,27 +1466,40 @@ static struct clk_mux_sel mux_sclk[] = {
        { 0, 0},
 };
 
-static struct clk tegra_clk_cpu = {
-       .name   = "cpu",
+static struct clk tegra_clk_cclk = {
+       .name   = "cclk",
        .inputs = mux_cclk,
        .reg    = 0x20,
        .ops    = &tegra_super_ops,
+       .max_rate = 1000000000,
 };
 
-static struct clk tegra_clk_sys = {
-       .name   = "sys",
+static struct clk tegra_clk_sclk = {
+       .name   = "sclk",
        .inputs = mux_sclk,
        .reg    = 0x28,
        .ops    = &tegra_super_ops,
+       .max_rate = 600000000,
+};
+
+static struct clk tegra_clk_virtual_cpu = {
+       .name      = "cpu",
+       .parent    = &tegra_clk_cclk,
+       .main      = &tegra_pll_x,
+       .backup    = &tegra_clk_m,
+       .ops       = &tegra_cpu_ops,
+       .max_rate  = 1000000000,
+       .dvfs      = &tegra_dvfs_virtual_cpu_dvfs,
 };
 
 static struct clk tegra_clk_hclk = {
        .name           = "hclk",
        .flags          = DIV_BUS,
-       .parent         = &tegra_clk_sys,
+       .parent         = &tegra_clk_sclk,
        .reg            = 0x30,
        .reg_shift      = 4,
        .ops            = &tegra_bus_ops,
+       .max_rate       = 240000000,
 };
 
 static struct clk tegra_clk_pclk = {
@@ -1107,6 +1509,7 @@ static struct clk tegra_clk_pclk = {
        .reg            = 0x30,
        .reg_shift      = 0,
        .ops            = &tegra_bus_ops,
+       .max_rate       = 108000000,
 };
 
 static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
@@ -1133,10 +1536,9 @@ static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
        { 0, 0},
 };
 
-static struct clk_mux_sel mux_plla_audio_pllp_clkm[] = {
-       {.input = &tegra_pll_a, .value = 0},
-       /* FIXME: no mux defined for tegra_audio
-       {.input = &tegra_audio, .value = 1},*/
+static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
+       {.input = &tegra_pll_a_out0, .value = 0},
+       {.input = &tegra_clk_audio_2x, .value = 1},
        {.input = &tegra_pll_p, .value = 2},
        {.input = &tegra_clk_m, .value = 3},
        { 0, 0},
@@ -1153,8 +1555,7 @@ static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
 static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
        {.input = &tegra_pll_p,     .value = 0},
        {.input = &tegra_pll_c,     .value = 1},
-       /* FIXME: no mux defined for tegra_audio
-       {.input = &tegra_audio,     .value = 2},*/
+       {.input = &tegra_clk_audio,     .value = 2},
        {.input = &tegra_clk_m,     .value = 3},
        {.input = &tegra_clk_32k,   .value = 4},
        { 0, 0},
@@ -1187,7 +1588,7 @@ static struct clk_mux_sel mux_clk_32k[] = {
        { 0, 0},
 };
 
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _inputs, _flags) \
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
        {                                               \
                .name      = _name,                     \
                .lookup    = {                          \
@@ -1199,72 +1600,79 @@ static struct clk_mux_sel mux_clk_32k[] = {
                .reg       = _reg,                      \
                .inputs    = _inputs,                   \
                .flags     = _flags,                    \
+               .max_rate  = _max,                      \
        }
 
 struct clk tegra_periph_clks[] = {
-       PERIPH_CLK("rtc",       "rtc-tegra",            NULL,   4,      0,      mux_clk_32k,                    PERIPH_NO_RESET),
-       PERIPH_CLK("timer",     "timer",                NULL,   5,      0,      mux_clk_m,                      0),
-       PERIPH_CLK("i2s1",      "i2s.0",                NULL,   11,     0x100,  mux_plla_audio_pllp_clkm,       MUX | DIV_U71),
-       PERIPH_CLK("i2s2",      "i2s.1",                NULL,   18,     0x104,  mux_plla_audio_pllp_clkm,       MUX | DIV_U71),
+       PERIPH_CLK("rtc",       "rtc-tegra",            NULL,   4,      0,      32768,     mux_clk_32k,                 PERIPH_NO_RESET),
+       PERIPH_CLK("timer",     "timer",                NULL,   5,      0,      26000000,  mux_clk_m,                   0),
+       PERIPH_CLK("i2s1",      "i2s.0",                NULL,   11,     0x100,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
+       PERIPH_CLK("i2s2",      "i2s.1",                NULL,   18,     0x104,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
        /* FIXME: spdif has 2 clocks but 1 enable */
-       PERIPH_CLK("spdif_out", "spdif_out",            NULL,   10,     0x108,  mux_plla_audio_pllp_clkm,       MUX | DIV_U71),
-       PERIPH_CLK("spdif_in",  "spdif_in",             NULL,   10,     0x10c,  mux_pllp_pllc_pllm,             MUX | DIV_U71),
-       PERIPH_CLK("pwm",       "pwm",                  NULL,   17,     0x110,  mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
-       PERIPH_CLK("spi",       "spi",                  NULL,   43,     0x114,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("xio",       "xio",                  NULL,   45,     0x120,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("twc",       "twc",                  NULL,   16,     0x12c,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sbc1",      "spi_tegra.0",          NULL,   41,     0x134,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sbc2",      "spi_tegra.1",          NULL,   44,     0x118,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sbc3",      "spi_tegra.2",          NULL,   46,     0x11c,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sbc4",      "spi_tegra.3",          NULL,   68,     0x1b4,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("ide",       "ide",                  NULL,   25,     0x144,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("ndflash",   "tegra_nand",           NULL,   13,     0x160,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
+       PERIPH_CLK("spdif_out", "spdif_out",            NULL,   10,     0x108,  100000000, mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
+       PERIPH_CLK("spdif_in",  "spdif_in",             NULL,   10,     0x10c,  100000000, mux_pllp_pllc_pllm,          MUX | DIV_U71),
+       PERIPH_CLK("pwm",       "pwm",                  NULL,   17,     0x110,  432000000, mux_pllp_pllc_audio_clkm_clk32,      MUX | DIV_U71),
+       PERIPH_CLK("spi",       "spi",                  NULL,   43,     0x114,  40000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("xio",       "xio",                  NULL,   45,     0x120,  150000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("twc",       "twc",                  NULL,   16,     0x12c,  150000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sbc1",      "spi_tegra.0",          NULL,   41,     0x134,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sbc2",      "spi_tegra.1",          NULL,   44,     0x118,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sbc3",      "spi_tegra.2",          NULL,   46,     0x11c,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sbc4",      "spi_tegra.3",          NULL,   68,     0x1b4,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("ide",       "ide",                  NULL,   25,     0x144,  100000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("ndflash",   "tegra_nand",           NULL,   13,     0x160,  164000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
        /* FIXME: vfir shares an enable with uartb */
-       PERIPH_CLK("vfir",      "vfir",                 NULL,   7,      0x168,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sdmmc1",    "sdhci-tegra.0",        NULL,   14,     0x150,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sdmmc2",    "sdhci-tegra.1",        NULL,   9,      0x154,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sdmmc3",    "sdhci-tegra.2",        NULL,   69,     0x1bc,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("sdmmc4",    "sdhci-tegra.3",        NULL,   15,     0x160,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("vde",       "vde",                  NULL,   61,     0x1c8,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("csite",     "csite",                NULL,   73,     0x1d4,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
+       PERIPH_CLK("vfir",      "vfir",                 NULL,   7,      0x168,  72000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sdmmc1",    "sdhci-tegra.0",        NULL,   14,     0x150,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc2",    "sdhci-tegra.1",        NULL,   9,      0x154,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc3",    "sdhci-tegra.2",        NULL,   69,     0x1bc,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc4",    "sdhci-tegra.3",        NULL,   15,     0x160,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("vde",       "vde",                  NULL,   61,     0x1c8,  250000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("csite",     "csite",                NULL,   73,     0x1d4,  144000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* max rate ??? */
        /* FIXME: what is la? */
-       PERIPH_CLK("la",        "la",                   NULL,   76,     0x1f8,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("owr",       "owr",                  NULL,   71,     0x1cc,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("nor",       "nor",                  NULL,   42,     0x1d0,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("mipi",      "mipi",                 NULL,   50,     0x174,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("i2c1",      "tegra-i2c.0",          NULL,   12,     0x124,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("i2c2",      "tegra-i2c.1",          NULL,   54,     0x198,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("i2c3",      "tegra-i2c.2",          NULL,   67,     0x1b8,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("dvc",       "tegra-i2c.3",          NULL,   47,     0x128,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("i2c1_i2c",  "tegra-i2c.0",          "i2c",  0,      0,      mux_pllp_out3,                  0),
-       PERIPH_CLK("i2c2_i2c",  "tegra-i2c.1",          "i2c",  0,      0,      mux_pllp_out3,                  0),
-       PERIPH_CLK("i2c3_i2c",  "tegra-i2c.2",          "i2c",  0,      0,      mux_pllp_out3,                  0),
-       PERIPH_CLK("dvc_i2c",   "tegra-i2c.3",          "i2c",  0,      0,      mux_pllp_out3,                  0),
-       PERIPH_CLK("uarta",     "uart.0",               NULL,   6,      0x178,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("uartb",     "uart.1",               NULL,   7,      0x17c,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("uartc",     "uart.2",               NULL,   55,     0x1a0,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("uartd",     "uart.3",               NULL,   65,     0x1c0,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("uarte",     "uart.4",               NULL,   66,     0x1c4,  mux_pllp_pllc_pllm_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("3d",        "3d",                   NULL,   24,     0x158,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71 | PERIPH_MANUAL_RESET),
-       PERIPH_CLK("2d",        "2d",                   NULL,   21,     0x15c,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
+       PERIPH_CLK("la",        "la",                   NULL,   76,     0x1f8,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("owr",       "tegra_w1",             NULL,   71,     0x1cc,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("nor",       "nor",                  NULL,   42,     0x1d0,  92000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("mipi",      "mipi",                 NULL,   50,     0x174,  60000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("i2c1",      "tegra-i2c.0",          NULL,   12,     0x124,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U16),
+       PERIPH_CLK("i2c2",      "tegra-i2c.1",          NULL,   54,     0x198,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U16),
+       PERIPH_CLK("i2c3",      "tegra-i2c.2",          NULL,   67,     0x1b8,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U16),
+       PERIPH_CLK("dvc",       "tegra-i2c.3",          NULL,   47,     0x128,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U16),
+       PERIPH_CLK("i2c1_i2c",  "tegra-i2c.0",          "i2c",  0,      0,      72000000,  mux_pllp_out3,                       0),
+       PERIPH_CLK("i2c2_i2c",  "tegra-i2c.1",          "i2c",  0,      0,      72000000,  mux_pllp_out3,                       0),
+       PERIPH_CLK("i2c3_i2c",  "tegra-i2c.2",          "i2c",  0,      0,      72000000,  mux_pllp_out3,                       0),
+       PERIPH_CLK("dvc_i2c",   "tegra-i2c.3",          "i2c",  0,      0,      72000000,  mux_pllp_out3,                       0),
+       PERIPH_CLK("uarta",     "uart.0",               NULL,   6,      0x178,  216000000, mux_pllp_pllc_pllm_clkm,     MUX),
+       PERIPH_CLK("uartb",     "uart.1",               NULL,   7,      0x17c,  216000000, mux_pllp_pllc_pllm_clkm,     MUX),
+       PERIPH_CLK("uartc",     "uart.2",               NULL,   55,     0x1a0,  216000000, mux_pllp_pllc_pllm_clkm,     MUX),
+       PERIPH_CLK("uartd",     "uart.3",               NULL,   65,     0x1c0,  216000000, mux_pllp_pllc_pllm_clkm,     MUX),
+       PERIPH_CLK("uarte",     "uart.4",               NULL,   66,     0x1c4,  216000000, mux_pllp_pllc_pllm_clkm,     MUX),
+       PERIPH_CLK("3d",        "3d",                   NULL,   24,     0x158,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
+       PERIPH_CLK("2d",        "2d",                   NULL,   21,     0x15c,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
        /* FIXME: vi and vi_sensor share an enable */
-       PERIPH_CLK("vi",        "vi",                   NULL,   20,     0x148,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
-       PERIPH_CLK("vi_sensor", "vi_sensor",            NULL,   20,     0x1a8,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
-       PERIPH_CLK("epp",       "epp",                  NULL,   19,     0x16c,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
-       PERIPH_CLK("mpe",       "mpe",                  NULL,   60,     0x170,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
-       PERIPH_CLK("host1x",    "host1x",               NULL,   28,     0x180,  mux_pllm_pllc_pllp_plla,        MUX | DIV_U71),
+       PERIPH_CLK("vi",        "vi",                   NULL,   20,     0x148,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("vi_sensor", "vi_sensor",            NULL,   20,     0x1a8,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
+       PERIPH_CLK("epp",       "epp",                  NULL,   19,     0x16c,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("mpe",       "mpe",                  NULL,   60,     0x170,  250000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("host1x",    "host1x",               NULL,   28,     0x180,  166000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
        /* FIXME: cve and tvo share an enable   */
-       PERIPH_CLK("cve",       "cve",                  NULL,   49,     0x140,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("tvo",       "tvo",                  NULL,   49,     0x188,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("hdmi",      "hdmi",                 NULL,   51,     0x18c,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("tvdac",     "tvdac",                NULL,   53,     0x194,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("disp1",     "tegrafb.0",            NULL,   27,     0x138,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("disp2",     "tegrafb.1",            NULL,   26,     0x13c,  mux_pllp_plld_pllc_clkm,        MUX | DIV_U71),
-       PERIPH_CLK("usbd",      "fsl-tegra-udc",        NULL,   22,     0,      mux_clk_m,                      0),
-       PERIPH_CLK("usb2",      "usb.1",                NULL,   58,     0,      mux_clk_m,                      0),
-       PERIPH_CLK("usb3",      "usb.2",                NULL,   59,     0,      mux_clk_m,                      0),
-       PERIPH_CLK("emc",       "emc",                  NULL,   57,     0x19c,  mux_pllm_pllc_pllp_clkm,        MUX | DIV_U71 | PERIPH_EMC_ENB),
-       PERIPH_CLK("dsi",       "dsi",                  NULL,   48,     0,      mux_plld,                       0),
+       PERIPH_CLK("cve",       "cve",                  NULL,   49,     0x140,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("tvo",       "tvo",                  NULL,   49,     0x188,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("hdmi",      "hdmi",                 NULL,   51,     0x18c,  148500000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("tvdac",     "tvdac",                NULL,   53,     0x194,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("disp1",     "tegrafb.0",            NULL,   27,     0x138,  190000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("disp2",     "tegrafb.1",            NULL,   26,     0x13c,  190000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* scales with voltage and process_id */
+       PERIPH_CLK("usbd",      "fsl-tegra-udc",        NULL,   22,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("usb2",      "tegra-ehci.1",         NULL,   58,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("usb3",      "tegra-ehci.2",         NULL,   59,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("emc",       "emc",                  NULL,   57,     0x19c,  800000000, mux_pllm_pllc_pllp_clkm,     MUX | DIV_U71 | PERIPH_EMC_ENB),
+       PERIPH_CLK("dsi",       "dsi",                  NULL,   48,     0,      500000000, mux_plld,                    0), /* scales with voltage */
+       PERIPH_CLK("csi",       "csi",                  NULL,   52,     0,      72000000,  mux_pllp_out3,               0),
+       PERIPH_CLK("isp",       "isp",                  NULL,   23,     0,      150000000, mux_clk_m,                   0), /* same frequency as VI */
+       PERIPH_CLK("csus",      "csus",                 NULL,   92,     0,      150000000, mux_clk_m,                   PERIPH_NO_RESET),
+       PERIPH_CLK("pex",       NULL,                   "pex",  70,     0,      26000000,  mux_clk_m,                   PERIPH_MANUAL_RESET),
+       PERIPH_CLK("afi",       NULL,                   "afi",  72,     0,      26000000,  mux_clk_m,                   PERIPH_MANUAL_RESET),
+       PERIPH_CLK("pcie_xclk", NULL,             "pcie_xclk",  74,     0,      26000000,  mux_clk_m,                   PERIPH_MANUAL_RESET),
 };
 
 #define CLK_DUPLICATE(_name, _dev, _con)               \
@@ -1286,6 +1694,9 @@ struct clk_duplicate tegra_clk_duplicates[] = {
        CLK_DUPLICATE("uartc",  "tegra_uart.2", NULL),
        CLK_DUPLICATE("uartd",  "tegra_uart.3", NULL),
        CLK_DUPLICATE("uarte",  "tegra_uart.4", NULL),
+       CLK_DUPLICATE("host1x", "tegrafb.0", "host1x"),
+       CLK_DUPLICATE("host1x", "tegrafb.1", "host1x"),
+       CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
 };
 
 #define CLK(dev, con, ck)      \
@@ -1315,11 +1726,13 @@ struct clk_lookup tegra_clk_lookups[] = {
        CLK(NULL,       "pll_d_out0",   &tegra_pll_d_out0),
        CLK(NULL,       "pll_u",        &tegra_pll_u),
        CLK(NULL,       "pll_x",        &tegra_pll_x),
-       CLK(NULL,       "cpu",          &tegra_clk_cpu),
-       CLK(NULL,       "sys",          &tegra_clk_sys),
+       CLK(NULL,       "pll_e",        &tegra_pll_e),
+       CLK(NULL,       "cclk",         &tegra_clk_cclk),
+       CLK(NULL,       "sclk",         &tegra_clk_sclk),
        CLK(NULL,       "hclk",         &tegra_clk_hclk),
        CLK(NULL,       "pclk",         &tegra_clk_pclk),
        CLK(NULL,       "clk_d",        &tegra_clk_d),
+       CLK(NULL,       "cpu",          &tegra_clk_virtual_cpu),
 };
 
 void __init tegra2_init_clocks(void)
@@ -1356,4 +1769,75 @@ void __init tegra2_init_clocks(void)
                                cd->name);
                }
        }
+
+       init_audio_sync_clock_mux();
+}
+
+#ifdef CONFIG_PM
+static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
+                          PERIPH_CLK_SOURCE_NUM + 3];
+
+void tegra_clk_suspend(void)
+{
+       unsigned long off, i;
+       u32 *ctx = clk_rst_suspend;
+
+       *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+
+       for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+                       off += 4) {
+               if (off == PERIPH_CLK_SOURCE_EMC)
+                       continue;
+               *ctx++ = clk_readl(off);
+       }
+
+       off = RST_DEVICES;
+       for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+               *ctx++ = clk_readl(off);
+
+       off = CLK_OUT_ENB;
+       for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+               *ctx++ = clk_readl(off);
+
+       *ctx++ = clk_readl(MISC_CLK_ENB);
+       *ctx++ = clk_readl(CLK_MASK_ARM);
+}
+
+void tegra_clk_resume(void)
+{
+       unsigned long off, i;
+       const u32 *ctx = clk_rst_suspend;
+       u32 val;
+
+       val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
+       val |= *ctx++;
+       clk_writel(val, OSC_CTRL);
+
+       /* enable all clocks before configuring clock sources */
+       clk_writel(0xbffffff9ul, CLK_OUT_ENB);
+       clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
+       clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
+       wmb();
+
+       for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+                       off += 4) {
+               if (off == PERIPH_CLK_SOURCE_EMC)
+                       continue;
+               clk_writel(*ctx++, off);
+       }
+       wmb();
+
+       off = RST_DEVICES;
+       for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+               clk_writel(*ctx++, off);
+       wmb();
+
+       off = CLK_OUT_ENB;
+       for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+               clk_writel(*ctx++, off);
+       wmb();
+
+       clk_writel(*ctx++, MISC_CLK_ENB);
+       clk_writel(*ctx++, CLK_MASK_ARM);
 }
+#endif
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c
new file mode 100644 (file)
index 0000000..5529c23
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include "clock.h"
+#include "tegra2_dvfs.h"
+
+static struct dvfs_table virtual_cpu_process_0[] = {
+       {314000000,  750},
+       {456000000,  825},
+       {608000000,  900},
+       {760000000,  975},
+       {817000000,  1000},
+       {912000000,  1050},
+       {1000000000, 1100},
+       {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_1[] = {
+       {314000000,  750},
+       {456000000,  825},
+       {618000000,  900},
+       {770000000,  975},
+       {827000000,  1000},
+       {922000000,  1050},
+       {1000000000, 1100},
+       {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_2[] = {
+       {494000000,  750},
+       {675000000,  825},
+       {817000000,  875},
+       {922000000,  925},
+       {1000000000, 975},
+       {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_3[] = {
+       {730000000,  750},
+       {760000000,  775},
+       {845000000,  800},
+       {1000000000, 875},
+       {0, 0},
+};
+
+struct dvfs tegra_dvfs_virtual_cpu_dvfs = {
+       .reg_id = "vdd_cpu",
+       .process_id_table = {
+               {
+                       .process_id = 0,
+                       .table = virtual_cpu_process_0,
+               },
+               {
+                       .process_id = 1,
+                       .table = virtual_cpu_process_1,
+               },
+               {
+                       .process_id = 2,
+                       .table = virtual_cpu_process_2,
+               },
+               {
+                       .process_id = 3,
+                       .table = virtual_cpu_process_3,
+               },
+       },
+       .process_id_table_length = 4,
+       .cpu = 1,
+};
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.h b/arch/arm/mach-tegra/tegra2_dvfs.h
new file mode 100644 (file)
index 0000000..f8c1adb
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
index fcb587f825ccf6c7b195277365e29e5aa58d2710..cac83a694880f6dd6d17a62d39387cbf58128144 100644 (file)
 #include <linux/amba/pl022.h>
 #include <linux/spi/spi.h>
 #include <linux/mfd/ab8500.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 #include <plat/pincfg.h>
 #include <plat/i2c.h>
+#include <plat/ske.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -49,6 +51,24 @@ static pin_cfg_t mop500_pins[] = {
        GPIO11_I2C2_SCL,
        GPIO229_I2C3_SDA,
        GPIO230_I2C3_SCL,
+
+       /* SKE keypad */
+       GPIO153_KP_I7,
+       GPIO154_KP_I6,
+       GPIO155_KP_I5,
+       GPIO156_KP_I4,
+       GPIO157_KP_O7,
+       GPIO158_KP_O6,
+       GPIO159_KP_O5,
+       GPIO160_KP_O4,
+       GPIO161_KP_I3,
+       GPIO162_KP_I2,
+       GPIO163_KP_I1,
+       GPIO164_KP_I0,
+       GPIO165_KP_O3,
+       GPIO166_KP_O2,
+       GPIO167_KP_O1,
+       GPIO168_KP_O0,
 };
 
 static void ab4500_spi_cs_control(u32 command)
@@ -148,12 +168,120 @@ static struct amba_device *amba_devs[] __initdata = {
        &u8500_ssp0_device,
 };
 
+static const unsigned int ux500_keymap[] = {
+       KEY(2, 5, KEY_END),
+       KEY(4, 1, KEY_POWER),
+       KEY(3, 5, KEY_VOLUMEDOWN),
+       KEY(1, 3, KEY_3),
+       KEY(5, 2, KEY_RIGHT),
+       KEY(5, 0, KEY_9),
+
+       KEY(0, 5, KEY_MENU),
+       KEY(7, 6, KEY_ENTER),
+       KEY(4, 5, KEY_0),
+       KEY(6, 7, KEY_2),
+       KEY(3, 4, KEY_UP),
+       KEY(3, 3, KEY_DOWN),
+
+       KEY(6, 4, KEY_SEND),
+       KEY(6, 2, KEY_BACK),
+       KEY(4, 2, KEY_VOLUMEUP),
+       KEY(5, 5, KEY_1),
+       KEY(4, 3, KEY_LEFT),
+       KEY(3, 2, KEY_7),
+};
+
+static const struct matrix_keymap_data ux500_keymap_data = {
+       .keymap         = ux500_keymap,
+       .keymap_size    = ARRAY_SIZE(ux500_keymap),
+};
+
+/*
+ * Nomadik SKE keypad
+ */
+#define ROW_PIN_I0      164
+#define ROW_PIN_I1      163
+#define ROW_PIN_I2      162
+#define ROW_PIN_I3      161
+#define ROW_PIN_I4      156
+#define ROW_PIN_I5      155
+#define ROW_PIN_I6      154
+#define ROW_PIN_I7      153
+#define COL_PIN_O0      168
+#define COL_PIN_O1      167
+#define COL_PIN_O2      166
+#define COL_PIN_O3      165
+#define COL_PIN_O4      160
+#define COL_PIN_O5      159
+#define COL_PIN_O6      158
+#define COL_PIN_O7      157
+
+#define SKE_KPD_MAX_ROWS        8
+#define SKE_KPD_MAX_COLS        8
+
+static int ske_kp_rows[] = {
+       ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
+       ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
+};
+
+/*
+ * ske_set_gpio_row: request and set gpio rows
+ */
+static int ske_set_gpio_row(int gpio)
+{
+       int ret;
+
+       ret = gpio_request(gpio, "ske-kp");
+       if (ret < 0) {
+               pr_err("ske_set_gpio_row: gpio request failed\n");
+               return ret;
+       }
+
+       ret = gpio_direction_output(gpio, 1);
+       if (ret < 0) {
+               pr_err("ske_set_gpio_row: gpio direction failed\n");
+               gpio_free(gpio);
+       }
+
+       return ret;
+}
+
+/*
+ * ske_kp_init - enable the gpio configuration
+ */
+static int ske_kp_init(void)
+{
+       int ret, i;
+
+       for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
+               ret = ske_set_gpio_row(ske_kp_rows[i]);
+               if (ret < 0) {
+                       pr_err("ske_kp_init: failed init\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct ske_keypad_platform_data ske_keypad_board = {
+       .init           = ske_kp_init,
+       .keymap_data    = &ux500_keymap_data,
+       .no_autorepeat  = true,
+       .krow           = SKE_KPD_MAX_ROWS,     /* 8x8 matrix */
+       .kcol           = SKE_KPD_MAX_COLS,
+       .debounce_ms    = 40,                   /* in millsecs */
+};
+
+
+
 /* add any platform devices here - TODO */
 static struct platform_device *platform_devs[] __initdata = {
        &u8500_i2c0_device,
        &ux500_i2c1_device,
        &ux500_i2c2_device,
        &ux500_i2c3_device,
+       &ux500_ske_keypad_device,
 };
 
 static void __init u8500_init_machine(void)
@@ -168,6 +296,7 @@ static void __init u8500_init_machine(void)
        ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
        ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
        ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
+       ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
 
        u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
 
index d8ab7f184fe439ec2492079a063def04c5e3c690..1675047daf20f74f5f00a1a7e88feab2e5c4f281 100644 (file)
@@ -477,6 +477,7 @@ static struct clk_lookup u8500_common_clks[] = {
        CLK(sdi5,       "sdi5",         NULL),
        CLK(uart2,      "uart2",        NULL),
        CLK(ske,        "ske",          NULL),
+       CLK(ske,        "nmk-ske-keypad",       NULL),
        CLK(sdi2,       "sdi2",         NULL),
        CLK(i2c0,       "nmk-i2c.0",    NULL),
        CLK(fsmc,       "fsmc",         NULL),
index 40032fecbc165538c9822fac801d7e72780d4c3b..cbbe69a76a7ccf773c4ea408bd1f5d268bbf6fbf 100644 (file)
@@ -292,3 +292,23 @@ void dma40_u8500ed_fixup(void)
        dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
        dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
 }
+
+struct resource keypad_resources[] = {
+       [0] = {
+               .start = U8500_SKE_BASE,
+               .end = U8500_SKE_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_DB8500_KB,
+               .end = IRQ_DB8500_KB,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device ux500_ske_keypad_device = {
+       .name = "nmk-ske-keypad",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(keypad_resources),
+       .resource = keypad_resources,
+};
index 33a120c2e82eaf0749e480149cdd2539c671aab8..b91a4d1211a27997141a38055151c45e19698078 100644 (file)
@@ -26,6 +26,7 @@ extern struct platform_device ux500_i2c3_device;
 extern struct platform_device u8500_i2c0_device;
 extern struct platform_device u8500_i2c4_device;
 extern struct platform_device u8500_dma40_device;
+extern struct platform_device ux500_ske_keypad_device;
 
 extern struct amba_device u8500_sdi0_device;
 extern struct amba_device u8500_sdi1_device;
index 66f8761cc823cfd5a3670c773da50b087822bb94..f923764ee16cb09706d3e0ecbfe889b760897847 100644 (file)
 #define GPIO152_KP_O9          PIN_CFG(152, ALT_C)
 
 #define GPIO153_GPIO           PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7          PIN_CFG(153, ALT_A)
+#define GPIO153_KP_I7          PIN_CFG_PULL(153, ALT_A, DOWN)
 #define GPIO153_LCD_D24                PIN_CFG(153, ALT_B)
 #define GPIO153_U2_RXD         PIN_CFG(153, ALT_C)
 
 #define GPIO154_GPIO           PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6          PIN_CFG(154, ALT_A)
+#define GPIO154_KP_I6          PIN_CFG_PULL(154, ALT_A, DOWN)
 #define GPIO154_LCD_D25                PIN_CFG(154, ALT_B)
 #define GPIO154_U2_TXD         PIN_CFG(154, ALT_C)
 
 #define GPIO155_GPIO           PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5          PIN_CFG(155, ALT_A)
+#define GPIO155_KP_I5          PIN_CFG_PULL(155, ALT_A, DOWN)
 #define GPIO155_LCD_D26                PIN_CFG(155, ALT_B)
 #define GPIO155_STMAPE_CLK     PIN_CFG(155, ALT_C)
 
 #define GPIO156_GPIO           PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4          PIN_CFG(156, ALT_A)
+#define GPIO156_KP_I4          PIN_CFG_PULL(156, ALT_A, DOWN)
 #define GPIO156_LCD_D27                PIN_CFG(156, ALT_B)
 #define GPIO156_STMAPE_DAT3    PIN_CFG(156, ALT_C)
 
 #define GPIO157_GPIO           PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7          PIN_CFG(157, ALT_A)
+#define GPIO157_KP_O7          PIN_CFG_PULL(157, ALT_A, UP)
 #define GPIO157_LCD_D28                PIN_CFG(157, ALT_B)
 #define GPIO157_STMAPE_DAT2    PIN_CFG(157, ALT_C)
 
 #define GPIO158_GPIO           PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6          PIN_CFG(158, ALT_A)
+#define GPIO158_KP_O6          PIN_CFG_PULL(158, ALT_A, UP)
 #define GPIO158_LCD_D29                PIN_CFG(158, ALT_B)
 #define GPIO158_STMAPE_DAT1    PIN_CFG(158, ALT_C)
 
 #define GPIO159_GPIO           PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5          PIN_CFG(159, ALT_A)
+#define GPIO159_KP_O5          PIN_CFG_PULL(159, ALT_A, UP)
 #define GPIO159_LCD_D30                PIN_CFG(159, ALT_B)
 #define GPIO159_STMAPE_DAT0    PIN_CFG(159, ALT_C)
 
 #define GPIO160_GPIO           PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4          PIN_CFG(160, ALT_A)
+#define GPIO160_KP_O4          PIN_CFG_PULL(160, ALT_A, UP)
 #define GPIO160_LCD_D31                PIN_CFG(160, ALT_B)
 #define GPIO160_NONE           PIN_CFG(160, ALT_C)
 
 #define GPIO161_GPIO           PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3          PIN_CFG(161, ALT_A)
+#define GPIO161_KP_I3          PIN_CFG_PULL(161, ALT_A, DOWN)
 #define GPIO161_LCD_D32                PIN_CFG(161, ALT_B)
 #define GPIO161_UARTMOD_RXD    PIN_CFG(161, ALT_C)
 
 #define GPIO162_GPIO           PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2          PIN_CFG(162, ALT_A)
+#define GPIO162_KP_I2          PIN_CFG_PULL(162, ALT_A, DOWN)
 #define GPIO162_LCD_D33                PIN_CFG(162, ALT_B)
 #define GPIO162_UARTMOD_TXD    PIN_CFG(162, ALT_C)
 
 #define GPIO163_GPIO           PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1          PIN_CFG(163, ALT_A)
+#define GPIO163_KP_I1          PIN_CFG_PULL(163, ALT_A, DOWN)
 #define GPIO163_LCD_D34                PIN_CFG(163, ALT_B)
 #define GPIO163_STMMOD_CLK     PIN_CFG(163, ALT_C)
 
 #define GPIO164_GPIO           PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0          PIN_CFG(164, ALT_A)
+#define GPIO164_KP_I0          PIN_CFG_PULL(164, ALT_A, UP)
 #define GPIO164_LCD_D35                PIN_CFG(164, ALT_B)
 #define GPIO164_STMMOD_DAT3    PIN_CFG(164, ALT_C)
 
 #define GPIO165_GPIO           PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3          PIN_CFG(165, ALT_A)
+#define GPIO165_KP_O3          PIN_CFG_PULL(165, ALT_A, UP)
 #define GPIO165_LCD_D36                PIN_CFG(165, ALT_B)
 #define GPIO165_STMMOD_DAT2    PIN_CFG(165, ALT_C)
 
 #define GPIO166_GPIO           PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2          PIN_CFG(166, ALT_A)
+#define GPIO166_KP_O2          PIN_CFG_PULL(166, ALT_A, UP)
 #define GPIO166_LCD_D37                PIN_CFG(166, ALT_B)
 #define GPIO166_STMMOD_DAT1    PIN_CFG(166, ALT_C)
 
 #define GPIO167_GPIO           PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1          PIN_CFG(167, ALT_A)
+#define GPIO167_KP_O1          PIN_CFG_PULL(167, ALT_A, UP)
 #define GPIO167_LCD_D38                PIN_CFG(167, ALT_B)
 #define GPIO167_STMMOD_DAT0    PIN_CFG(167, ALT_C)
 
 #define GPIO168_GPIO           PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0          PIN_CFG(168, ALT_A)
+#define GPIO168_KP_O0          PIN_CFG_PULL(168, ALT_A, UP)
 #define GPIO168_LCD_D39                PIN_CFG(168, ALT_B)
 #define GPIO168_NONE           PIN_CFG(168, ALT_C)
 
index 8440d952ba6dd1266628678f016bdf5f41a3002a..c493d7244d3d99bee236469940fbed42c10ce476 100644 (file)
@@ -89,13 +89,13 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
         * open-code the spin-locking.
         */
        ptl = pte_lockptr(vma->vm_mm, pmd);
-       pte = pte_offset_map_nested(pmd, address);
+       pte = pte_offset_map(pmd, address);
        spin_lock(ptl);
 
        ret = do_adjust_pte(vma, address, pfn, pte);
 
        spin_unlock(ptl);
-       pte_unmap_nested(pte);
+       pte_unmap(pte);
 
        return ret;
 }
index 1fbdb55bfd1bd34a480ea0e45b7f3a39a2934c6a..c00f119babbfe59a5d51a87fd5ba13f1e4c0f190 100644 (file)
@@ -36,18 +36,17 @@ void kunmap(struct page *page)
 }
 EXPORT_SYMBOL(kunmap);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
        unsigned int idx;
        unsigned long vaddr;
        void *kmap;
+       int type;
 
        pagefault_disable();
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic(type);
-
 #ifdef CONFIG_DEBUG_HIGHMEM
        /*
         * There is no cache coherency issue when non VIVT, so force the
@@ -61,6 +60,8 @@ void *kmap_atomic(struct page *page, enum km_type type)
        if (kmap)
                return kmap;
 
+       type = kmap_atomic_idx_push();
+
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -80,14 +81,17 @@ void *kmap_atomic(struct page *page, enum km_type type)
 
        return (void *)vaddr;
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
+       int idx, type;
 
        if (kvaddr >= (void *)FIXADDR_START) {
+               type = kmap_atomic_idx_pop();
+               idx = type + KM_TYPE_NR * smp_processor_id();
+
                if (cache_is_vivt())
                        __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -103,15 +107,16 @@ void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
        }
        pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-       unsigned int idx;
        unsigned long vaddr;
+       int idx, type;
 
        pagefault_disable();
 
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
index be5f58e153bf180d4df1da5037f26652cc7ca2cb..69bbfc6645a673853ed6f8171e08e3a4f9f22585 100644 (file)
@@ -57,9 +57,9 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
                        goto no_pte;
 
                init_pmd = pmd_offset(init_pgd, 0);
-               init_pte = pte_offset_map_nested(init_pmd, 0);
+               init_pte = pte_offset_map(init_pmd, 0);
                set_pte_ext(new_pte, *init_pte, 0);
-               pte_unmap_nested(init_pte);
+               pte_unmap(init_pte);
                pte_unmap(new_pte);
        }
 
diff --git a/arch/arm/plat-nomadik/include/plat/ske.h b/arch/arm/plat-nomadik/include/plat/ske.h
new file mode 100644 (file)
index 0000000..31382fb
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
+ *
+ * ux500 Scroll key and Keypad Encoder (SKE) header
+ */
+
+#ifndef __SKE_H
+#define __SKE_H
+
+#include <linux/input/matrix_keypad.h>
+
+/* register definitions for SKE peripheral */
+#define SKE_CR         0x00
+#define SKE_VAL0       0x04
+#define SKE_VAL1       0x08
+#define SKE_DBCR       0x0C
+#define SKE_IMSC       0x10
+#define SKE_RIS                0x14
+#define SKE_MIS                0x18
+#define SKE_ICR                0x1C
+
+/*
+ * Keypad module
+ */
+
+/**
+ * struct keypad_platform_data - structure for platform specific data
+ * @init:      pointer to keypad init function
+ * @exit:      pointer to keypad deinitialisation function
+ * @keymap_data: matrix scan code table for keycodes
+ * @krow:      maximum number of rows
+ * @kcol:      maximum number of columns
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ * @wakeup_enable: allow waking up the system
+ */
+struct ske_keypad_platform_data {
+       int (*init)(void);
+       int (*exit)(void);
+       const struct matrix_keymap_data *keymap_data;
+       u8 krow;
+       u8 kcol;
+       u8 debounce_ms;
+       bool no_autorepeat;
+       bool wakeup_enable;
+};
+#endif /*__SKE_KPD_H*/
index a92cb499313fdc9583890ebcc182ecae280cdc09..92c5bb7909f5632c6d0132813292e655a1d16161 100644 (file)
@@ -19,7 +19,7 @@ config ARCH_OMAP2PLUS
        bool "TI OMAP2/3/4"
        select COMMON_CLKDEV
        help
-         "Systems based on omap24xx, omap34xx or omap44xx"
+         "Systems based on OMAP2, OMAP3 or OMAP4"
 
 endchoice
 
index 9405831b746a5e63dd4dc3a2a6220afce032713c..a4a12859fdd57c6bc4a65870ac57682c6f92f28d 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
-        usb.o fb.o io.o
+        usb.o fb.o io.o counter_32k.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -31,4 +31,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
 # OMAP mailbox framework
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
\ No newline at end of file
+obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
index 7190cbd92620910dd806f021dbe75faa92fe2e97..fc62fb5fc20bc44b5a76cb9e56d1344c7b4841e8 100644 (file)
@@ -60,7 +60,7 @@ void clk_disable(struct clk *clk)
 
        spin_lock_irqsave(&clockfw_lock, flags);
        if (clk->usecount == 0) {
-               printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+               pr_err("Trying disable clock %s with 0 usecount\n",
                       clk->name);
                WARN_ON(1);
                goto out;
@@ -397,6 +397,7 @@ static int __init clk_disable_unused(void)
        struct clk *ck;
        unsigned long flags;
 
+       pr_info("clock: disabling unused clocks to save power\n");
        list_for_each_entry(ck, &clocks, node) {
                if (ck->ops == &clkops_null)
                        continue;
@@ -418,7 +419,7 @@ late_initcall(clk_disable_unused);
 int __init clk_init(struct clk_functions * custom_clocks)
 {
        if (!custom_clocks) {
-               printk(KERN_ERR "No custom clock functions registered\n");
+               pr_err("No custom clock functions registered\n");
                BUG();
        }
 
index 3008e71044876bf9007428b8020351b797902094..221a675ebbaedb4b14d08d354103ced49a402e90 100644 (file)
  * 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/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-
 #include <plat/common.h>
 #include <plat/board.h>
-#include <plat/control.h>
-#include <plat/mux.h>
-#include <plat/fpga.h>
-#include <plat/serial.h>
 #include <plat/vram.h>
 
-#include <plat/clock.h>
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-# include "../mach-omap2/sdrc.h"
-#endif
 
 #define NO_LENGTH_CHECK 0xffffffff
 
@@ -88,270 +65,3 @@ void __init omap_reserve(void)
        omapfb_reserve_sdram_memblock();
        omap_vram_reserve_sdram_memblock();
 }
-
-/*
- * 32KHz clocksource ... always available, on pretty most chips except
- * OMAP 730 and 1510.  Other timers could be used as clocksources, with
- * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
- * but systems won't necessarily want to spend resources that way.
- */
-
-#define OMAP16XX_TIMER_32K_SYNCHRONIZED                0xfffbc410
-
-#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
-
-#include <linux/clocksource.h>
-
-/*
- * offset_32k holds the init time counter value. It is then subtracted
- * from every counter read to achieve a counter that counts time from the
- * kernel boot (needed for sched_clock()).
- */
-static u32 offset_32k __read_mostly;
-
-#ifdef CONFIG_ARCH_OMAP16XX
-static cycle_t omap16xx_32k_read(struct clocksource *cs)
-{
-       return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
-}
-#else
-#define omap16xx_32k_read      NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2420
-static cycle_t omap2420_32k_read(struct clocksource *cs)
-{
-       return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2420_32k_read      NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-static cycle_t omap2430_32k_read(struct clocksource *cs)
-{
-       return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2430_32k_read      NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP3
-static cycle_t omap34xx_32k_read(struct clocksource *cs)
-{
-       return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap34xx_32k_read      NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-static cycle_t omap44xx_32k_read(struct clocksource *cs)
-{
-       return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap44xx_32k_read      NULL
-#endif
-
-/*
- * Kernel assumes that sched_clock can be called early but may not have
- * things ready yet.
- */
-static cycle_t omap_32k_read_dummy(struct clocksource *cs)
-{
-       return 0;
-}
-
-static struct clocksource clocksource_32k = {
-       .name           = "32k_counter",
-       .rating         = 250,
-       .read           = omap_32k_read_dummy,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 10,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
- * Returns current time from boot in nsecs. It's OK for this to wrap
- * around for now, as it's just a relative time stamp.
- */
-unsigned long long sched_clock(void)
-{
-       return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
-                                 clocksource_32k.mult, clocksource_32k.shift);
-}
-
-/**
- * read_persistent_clock -  Return time from a persistent clock.
- *
- * Reads the time from a source which isn't disabled during PM, the
- * 32k sync timer.  Convert the cycles elapsed since last read into
- * nsecs and adds to a monotonically increasing timespec.
- */
-static struct timespec persistent_ts;
-static cycles_t cycles, last_cycles;
-void read_persistent_clock(struct timespec *ts)
-{
-       unsigned long long nsecs;
-       cycles_t delta;
-       struct timespec *tsp = &persistent_ts;
-
-       last_cycles = cycles;
-       cycles = clocksource_32k.read(&clocksource_32k);
-       delta = cycles - last_cycles;
-
-       nsecs = clocksource_cyc2ns(delta,
-                                  clocksource_32k.mult, clocksource_32k.shift);
-
-       timespec_add_ns(tsp, nsecs);
-       *ts = *tsp;
-}
-
-static int __init omap_init_clocksource_32k(void)
-{
-       static char err[] __initdata = KERN_ERR
-                       "%s: can't register clocksource!\n";
-
-       if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
-               struct clk *sync_32k_ick;
-
-               if (cpu_is_omap16xx())
-                       clocksource_32k.read = omap16xx_32k_read;
-               else if (cpu_is_omap2420())
-                       clocksource_32k.read = omap2420_32k_read;
-               else if (cpu_is_omap2430())
-                       clocksource_32k.read = omap2430_32k_read;
-               else if (cpu_is_omap34xx())
-                       clocksource_32k.read = omap34xx_32k_read;
-               else if (cpu_is_omap44xx())
-                       clocksource_32k.read = omap44xx_32k_read;
-               else
-                       return -ENODEV;
-
-               sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
-               if (sync_32k_ick)
-                       clk_enable(sync_32k_ick);
-
-               clocksource_32k.mult = clocksource_hz2mult(32768,
-                                           clocksource_32k.shift);
-
-               offset_32k = clocksource_32k.read(&clocksource_32k);
-
-               if (clocksource_register(&clocksource_32k))
-                       printk(err, clocksource_32k.name);
-       }
-       return 0;
-}
-arch_initcall(omap_init_clocksource_32k);
-
-#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
-
-/* Global address base setup code */
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-
-static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
-{
-       omap2_set_globals_tap(omap2_globals);
-       omap2_set_globals_sdrc(omap2_globals);
-       omap2_set_globals_control(omap2_globals);
-       omap2_set_globals_prcm(omap2_globals);
-       omap2_set_globals_uart(omap2_globals);
-}
-
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2420)
-
-static struct omap_globals omap242x_globals = {
-       .class  = OMAP242X_CLASS,
-       .tap    = OMAP2_L4_IO_ADDRESS(0x48014000),
-       .sdrc   = OMAP2420_SDRC_BASE,
-       .sms    = OMAP2420_SMS_BASE,
-       .ctrl   = OMAP2420_CTRL_BASE,
-       .prm    = OMAP2420_PRM_BASE,
-       .cm     = OMAP2420_CM_BASE,
-       .uart1_phys     = OMAP2_UART1_BASE,
-       .uart2_phys     = OMAP2_UART2_BASE,
-       .uart3_phys     = OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_242x(void)
-{
-       __omap2_set_globals(&omap242x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2430)
-
-static struct omap_globals omap243x_globals = {
-       .class  = OMAP243X_CLASS,
-       .tap    = OMAP2_L4_IO_ADDRESS(0x4900a000),
-       .sdrc   = OMAP243X_SDRC_BASE,
-       .sms    = OMAP243X_SMS_BASE,
-       .ctrl   = OMAP243X_CTRL_BASE,
-       .prm    = OMAP2430_PRM_BASE,
-       .cm     = OMAP2430_CM_BASE,
-       .uart1_phys     = OMAP2_UART1_BASE,
-       .uart2_phys     = OMAP2_UART2_BASE,
-       .uart3_phys     = OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_243x(void)
-{
-       __omap2_set_globals(&omap243x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3)
-
-static struct omap_globals omap3_globals = {
-       .class  = OMAP343X_CLASS,
-       .tap    = OMAP2_L4_IO_ADDRESS(0x4830A000),
-       .sdrc   = OMAP343X_SDRC_BASE,
-       .sms    = OMAP343X_SMS_BASE,
-       .ctrl   = OMAP343X_CTRL_BASE,
-       .prm    = OMAP3430_PRM_BASE,
-       .cm     = OMAP3430_CM_BASE,
-       .uart1_phys     = OMAP3_UART1_BASE,
-       .uart2_phys     = OMAP3_UART2_BASE,
-       .uart3_phys     = OMAP3_UART3_BASE,
-       .uart4_phys     = OMAP3_UART4_BASE,     /* Only on 3630 */
-};
-
-void __init omap2_set_globals_3xxx(void)
-{
-       __omap2_set_globals(&omap3_globals);
-}
-
-void __init omap3_map_io(void)
-{
-       omap2_set_globals_3xxx();
-       omap34xx_map_common_io();
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4)
-static struct omap_globals omap4_globals = {
-       .class  = OMAP443X_CLASS,
-       .tap    = OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
-       .ctrl   = OMAP443X_CTRL_BASE,
-       .prm    = OMAP4430_PRM_BASE,
-       .cm     = OMAP4430_CM_BASE,
-       .cm2    = OMAP4430_CM2_BASE,
-       .uart1_phys     = OMAP4_UART1_BASE,
-       .uart2_phys     = OMAP4_UART2_BASE,
-       .uart3_phys     = OMAP4_UART3_BASE,
-       .uart4_phys     = OMAP4_UART4_BASE,
-};
-
-void __init omap2_set_globals_443x(void)
-{
-       omap2_set_globals_tap(&omap4_globals);
-       omap2_set_globals_control(&omap4_globals);
-       omap2_set_globals_prcm(&omap4_globals);
-       omap2_set_globals_uart(&omap4_globals);
-}
-#endif
-
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
new file mode 100644 (file)
index 0000000..155fe43
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * OMAP 32ksynctimer/counter_32k-related code
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * NOTE: This timer is not the same timer as the old OMAP1 MPU timer.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+
+#include <plat/clock.h>
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510.  Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#define OMAP16XX_TIMER_32K_SYNCHRONIZED                0xfffbc410
+
+#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
+
+#include <linux/clocksource.h>
+
+/*
+ * offset_32k holds the init time counter value. It is then subtracted
+ * from every counter read to achieve a counter that counts time from the
+ * kernel boot (needed for sched_clock()).
+ */
+static u32 offset_32k __read_mostly;
+
+#ifdef CONFIG_ARCH_OMAP16XX
+static cycle_t omap16xx_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
+}
+#else
+#define omap16xx_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+static cycle_t omap2420_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2420_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static cycle_t omap2430_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2430_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static cycle_t omap34xx_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap34xx_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static cycle_t omap44xx_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap44xx_32k_read      NULL
+#endif
+
+/*
+ * Kernel assumes that sched_clock can be called early but may not have
+ * things ready yet.
+ */
+static cycle_t omap_32k_read_dummy(struct clocksource *cs)
+{
+       return 0;
+}
+
+static struct clocksource clocksource_32k = {
+       .name           = "32k_counter",
+       .rating         = 250,
+       .read           = omap_32k_read_dummy,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 10,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+       return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
+                                 clocksource_32k.mult, clocksource_32k.shift);
+}
+
+/**
+ * read_persistent_clock -  Return time from a persistent clock.
+ *
+ * Reads the time from a source which isn't disabled during PM, the
+ * 32k sync timer.  Convert the cycles elapsed since last read into
+ * nsecs and adds to a monotonically increasing timespec.
+ */
+static struct timespec persistent_ts;
+static cycles_t cycles, last_cycles;
+void read_persistent_clock(struct timespec *ts)
+{
+       unsigned long long nsecs;
+       cycles_t delta;
+       struct timespec *tsp = &persistent_ts;
+
+       last_cycles = cycles;
+       cycles = clocksource_32k.read(&clocksource_32k);
+       delta = cycles - last_cycles;
+
+       nsecs = clocksource_cyc2ns(delta,
+                                  clocksource_32k.mult, clocksource_32k.shift);
+
+       timespec_add_ns(tsp, nsecs);
+       *ts = *tsp;
+}
+
+static int __init omap_init_clocksource_32k(void)
+{
+       static char err[] __initdata = KERN_ERR
+                       "%s: can't register clocksource!\n";
+
+       if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
+               struct clk *sync_32k_ick;
+
+               if (cpu_is_omap16xx())
+                       clocksource_32k.read = omap16xx_32k_read;
+               else if (cpu_is_omap2420())
+                       clocksource_32k.read = omap2420_32k_read;
+               else if (cpu_is_omap2430())
+                       clocksource_32k.read = omap2430_32k_read;
+               else if (cpu_is_omap34xx())
+                       clocksource_32k.read = omap34xx_32k_read;
+               else if (cpu_is_omap44xx())
+                       clocksource_32k.read = omap44xx_32k_read;
+               else
+                       return -ENODEV;
+
+               sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
+               if (sync_32k_ick)
+                       clk_enable(sync_32k_ick);
+
+               clocksource_32k.mult = clocksource_hz2mult(32768,
+                                           clocksource_32k.shift);
+
+               offset_32k = clocksource_32k.read(&clocksource_32k);
+
+               if (clocksource_register(&clocksource_32k))
+                       printk(err, clocksource_32k.name);
+       }
+       return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
+
index 6d3d3336005600a301dc78220b91b2bfd37ce17b..11c54ec8d47f94bae13c63154c9db0cf39029c43 100644 (file)
@@ -40,7 +40,7 @@ static struct clk *mpu_clk;
 
 /* TODO: Add support for SDRAM timing changes */
 
-int omap_verify_speed(struct cpufreq_policy *policy)
+static int omap_verify_speed(struct cpufreq_policy *policy)
 {
        if (freq_table)
                return cpufreq_frequency_table_verify(policy, freq_table);
@@ -58,7 +58,7 @@ int omap_verify_speed(struct cpufreq_policy *policy)
        return 0;
 }
 
-unsigned int omap_getspeed(unsigned int cpu)
+static unsigned int omap_getspeed(unsigned int cpu)
 {
        unsigned long rate;
 
index d1920be7833bfe8d8336483928b616c6aa73f8d2..1e2383eae6383fd862dce6f5228763308c0cf30e 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/mach/map.h>
 
 #include <plat/tc.h>
-#include <plat/control.h>
 #include <plat/board.h>
 #include <plat/mmc.h>
 #include <mach/gpio.h>
@@ -232,46 +231,6 @@ static void omap_init_uwire(void)
 static inline void omap_init_uwire(void) {}
 #endif
 
-/*-------------------------------------------------------------------------*/
-
-#if    defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-
-static struct resource wdt_resources[] = {
-       {
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device omap_wdt_device = {
-       .name      = "omap_wdt",
-       .id          = -1,
-       .num_resources  = ARRAY_SIZE(wdt_resources),
-       .resource       = wdt_resources,
-};
-
-static void omap_init_wdt(void)
-{
-       if (cpu_is_omap16xx())
-               wdt_resources[0].start = 0xfffeb000;
-       else if (cpu_is_omap2420())
-               wdt_resources[0].start = 0x48022000; /* WDT2 */
-       else if (cpu_is_omap2430())
-               wdt_resources[0].start = 0x49016000; /* WDT2 */
-       else if (cpu_is_omap343x())
-               wdt_resources[0].start = 0x48314000; /* WDT2 */
-       else if (cpu_is_omap44xx())
-               wdt_resources[0].start = 0x4a314000;
-       else
-               return;
-
-       wdt_resources[0].end = wdt_resources[0].start + 0x4f;
-
-       (void) platform_device_register(&omap_wdt_device);
-}
-#else
-static inline void omap_init_wdt(void) {}
-#endif
-
 /*
  * This gets called after board-specific INIT_MACHINE, and initializes most
  * on-chip peripherals accessible on this board (except for few like USB):
@@ -300,7 +259,6 @@ static int __init omap_init_devices(void)
        omap_init_rng();
        omap_init_mcpdm();
        omap_init_uwire();
-       omap_init_wdt();
        return 0;
 }
 arch_initcall(omap_init_devices);
index ec7eddf9e525e4dc5a9d09a4b23ee3d635d6c14b..f5c5b8da9a87f194683afa8b51ebecb39e53f302 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
@@ -996,11 +997,17 @@ void omap_start_dma(int lch)
        l = dma_read(CCR(lch));
 
        /*
-        * Errata: On ES2.0 BUFFERING disable must be set.
-        * This will always fail on ES1.0
+        * Errata: Inter Frame DMA buffering issue (All OMAP2420 and
+        * OMAP2430ES1.0): DMA will wrongly buffer elements if packing and
+        * bursting is enabled. This might result in data gets stalled in
+        * FIFO at the end of the block.
+        * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
+        * guarantee no data will stay in the DMA FIFO in case inter frame
+        * buffering occurs.
         */
-       if (cpu_is_omap24xx())
-               l |= OMAP_DMA_CCR_EN;
+       if (cpu_is_omap2420() ||
+           (cpu_is_omap2430() && (omap_type() == OMAP2430_REV_ES1_0)))
+               l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
 
        l |= OMAP_DMA_CCR_EN;
        dma_write(l, CCR(lch));
@@ -1018,8 +1025,39 @@ void omap_stop_dma(int lch)
                dma_write(0, CICR(lch));
 
        l = dma_read(CCR(lch));
-       l &= ~OMAP_DMA_CCR_EN;
-       dma_write(l, CCR(lch));
+       /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+       if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+               int i = 0;
+               u32 sys_cf;
+
+               /* Configure No-Standby */
+               l = dma_read(OCP_SYSCONFIG);
+               sys_cf = l;
+               l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+               l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+               dma_write(l , OCP_SYSCONFIG);
+
+               l = dma_read(CCR(lch));
+               l &= ~OMAP_DMA_CCR_EN;
+               dma_write(l, CCR(lch));
+
+               /* Wait for sDMA FIFO drain */
+               l = dma_read(CCR(lch));
+               while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+                                       OMAP_DMA_CCR_WR_ACTIVE))) {
+                       udelay(5);
+                       i++;
+                       l = dma_read(CCR(lch));
+               }
+               if (i >= 100)
+                       printk(KERN_ERR "DMA drain did not complete on "
+                                       "lch %d\n", lch);
+               /* Restore OCP_SYSCONFIG */
+               dma_write(sys_cf, OCP_SYSCONFIG);
+       } else {
+               l &= ~OMAP_DMA_CCR_EN;
+               dma_write(l, CCR(lch));
+       }
 
        if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
                int next_lch, cur_lch = lch;
index 44bafdab2dceaa94d7d6facbcfd422b2f65b660c..1d706cf63ca0e697521d38ab814d9889a1b70435 100644 (file)
@@ -581,7 +581,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
         * When the functional clock disappears, too quick writes seem
         * to cause an abort. XXX Is this still necessary?
         */
-       __delay(150000);
+       __delay(300000);
 
        return ret;
 }
index 71934817e17228ffb01cfffc6a5fe2b872009964..c9e5d7298c408cf26391c4d3370001c571707e82 100644 (file)
@@ -36,6 +36,8 @@
 #include <plat/board.h>
 #include <plat/sram.h>
 
+#include "fb.h"
+
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
 static struct omapfb_platform_data omapfb_config;
@@ -94,7 +96,7 @@ static int fbmem_region_reserved(unsigned long start, size_t size)
  * Get the region_idx`th region from board config/ATAG and convert it to
  * our internal format.
  */
-static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
 {
        const struct omap_fbmem_config  *conf;
        u32                             paddr;
@@ -126,7 +128,7 @@ static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
         * type = 0 && paddr = 0, a default don't care case maps to
         * the SDRAM type.
         */
-       if (rg->type || (!rg->type && !rg->paddr))
+       if (rg->type || !rg->paddr)
                return 0;
        if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
                rg->type = mem_type;
@@ -258,7 +260,7 @@ void __init omapfb_reserve_sdram_memblock(void)
  * this point, since the driver built as a module would have problem with
  * freeing / reallocating the regions.
  */
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
                                  unsigned long sram_vstart,
                                  unsigned long sram_size,
                                  unsigned long pstart_avail,
@@ -332,7 +334,7 @@ void omapfb_set_ctrl_platform_data(void *data)
        omapfb_config.ctrl_platform_data = data;
 }
 
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
 {
        const struct omap_lcd_config *conf;
 
@@ -377,7 +379,7 @@ void omapfb_set_platform_data(struct omapfb_platform_data *data)
        omapfb_config = *data;
 }
 
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
 {
        return platform_device_register(&omap_fb_device);
 }
@@ -388,7 +390,7 @@ void omapfb_reserve_sdram_memblock(void)
 {
 }
 
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
                                  unsigned long sram_vstart,
                                  unsigned long sram_size,
                                  unsigned long start_avail,
@@ -407,7 +409,7 @@ void omapfb_reserve_sdram_memblock(void)
 {
 }
 
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
                                  unsigned long sram_vstart,
                                  unsigned long sram_size,
                                  unsigned long start_avail,
diff --git a/arch/arm/plat-omap/fb.h b/arch/arm/plat-omap/fb.h
new file mode 100644 (file)
index 0000000..d765d0b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __PLAT_OMAP_FB_H__
+#define __PLAT_OMAP_FB_H__
+
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+                                        unsigned long sram_vstart,
+                                        unsigned long sram_size,
+                                        unsigned long pstart_avail,
+                                        unsigned long size_avail);
+
+#endif /* __PLAT_OMAP_FB_H__ */
index 7951eefe1a0e90d634c315882427f94fc9c32faa..c05c653d1674e1e8945835b64471893135702c11 100644 (file)
@@ -2084,9 +2084,10 @@ void omap2_gpio_prepare_for_idle(int power_state)
 
        for (i = min; i < gpio_bank_count; i++) {
                struct gpio_bank *bank = &gpio_bank[i];
-               u32 l1, l2;
+               u32 l1 = 0, l2 = 0;
+               int j;
 
-               if (bank->dbck_enable_mask)
+               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
                        clk_disable(bank->dbck);
 
                if (power_state > PWRDM_POWER_OFF)
@@ -2151,9 +2152,10 @@ void omap2_gpio_resume_after_idle(void)
                min = 1;
        for (i = min; i < gpio_bank_count; i++) {
                struct gpio_bank *bank = &gpio_bank[i];
-               u32 l, gen, gen0, gen1;
+               u32 l = 0, gen, gen0, gen1;
+               int j;
 
-               if (bank->dbck_enable_mask)
+               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
                        clk_enable(bank->dbck);
 
                if (!workaround_enabled)
index 9776b41ad76f57a9f63bd3be3e1044f2f58481af..a9d69a09920d968029ca2e581dec013487213696 100644 (file)
@@ -47,6 +47,7 @@ struct omap_globals {
        unsigned long   sdrc;           /* SDRAM Controller */
        unsigned long   sms;            /* SDRAM Memory Scheduler */
        unsigned long   ctrl;           /* System Control Module */
+       unsigned long   ctrl_pad;       /* PAD Control Module */
        unsigned long   prm;            /* Power and Reset Management */
        unsigned long   cm;             /* Clock Management */
        unsigned long   cm2;
@@ -66,7 +67,6 @@ void omap2_set_globals_tap(struct omap_globals *);
 void omap2_set_globals_sdrc(struct omap_globals *);
 void omap2_set_globals_control(struct omap_globals *);
 void omap2_set_globals_prcm(struct omap_globals *);
-void omap2_set_globals_uart(struct omap_globals *);
 
 void omap3_map_io(void);
 
@@ -91,7 +91,8 @@ void omap3_map_io(void);
 })
 
 extern struct device *omap2_get_mpuss_device(void);
-extern struct device *omap2_get_dsp_device(void);
+extern struct device *omap2_get_iva_device(void);
 extern struct device *omap2_get_l3_device(void);
+extern struct device *omap4_get_dsp_device(void);
 
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h
deleted file mode 100644 (file)
index 131bf40..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/control.h
- *
- * OMAP2/3/4 System Control Module definitions
- *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2007-2008 Nokia Corporation
- *
- * Written by Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_CONTROL_H
-#define __ASM_ARCH_CONTROL_H
-
-#include <mach/io.h>
-
-#ifndef __ASSEMBLY__
-#define OMAP242X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
-#else
-#define OMAP242X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg)                                     \
-               OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
-#endif /* __ASSEMBLY__ */
-
-/*
- * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
- * OMAP24XX and OMAP34XX.
- */
-
-/* Control submodule offsets */
-
-#define OMAP2_CONTROL_INTERFACE                0x000
-#define OMAP2_CONTROL_PADCONFS         0x030
-#define OMAP2_CONTROL_GENERAL          0x270
-#define OMAP343X_CONTROL_MEM_WKUP      0x600
-#define OMAP343X_CONTROL_PADCONFS_WKUP 0xa00
-#define OMAP343X_CONTROL_GENERAL_WKUP  0xa60
-
-/* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
-
-#define OMAP2_CONTROL_SYSCONFIG                (OMAP2_CONTROL_INTERFACE + 0x10)
-
-/* CONTROL_GENERAL register offsets common to OMAP2 & 3 */
-#define OMAP2_CONTROL_DEVCONF0         (OMAP2_CONTROL_GENERAL + 0x0004)
-#define OMAP2_CONTROL_MSUSPENDMUX_0    (OMAP2_CONTROL_GENERAL + 0x0020)
-#define OMAP2_CONTROL_MSUSPENDMUX_1    (OMAP2_CONTROL_GENERAL + 0x0024)
-#define OMAP2_CONTROL_MSUSPENDMUX_2    (OMAP2_CONTROL_GENERAL + 0x0028)
-#define OMAP2_CONTROL_MSUSPENDMUX_3    (OMAP2_CONTROL_GENERAL + 0x002c)
-#define OMAP2_CONTROL_MSUSPENDMUX_4    (OMAP2_CONTROL_GENERAL + 0x0030)
-#define OMAP2_CONTROL_MSUSPENDMUX_5    (OMAP2_CONTROL_GENERAL + 0x0034)
-#define OMAP2_CONTROL_SEC_CTRL         (OMAP2_CONTROL_GENERAL + 0x0040)
-#define OMAP2_CONTROL_RPUB_KEY_H_0     (OMAP2_CONTROL_GENERAL + 0x0090)
-#define OMAP2_CONTROL_RPUB_KEY_H_1     (OMAP2_CONTROL_GENERAL + 0x0094)
-#define OMAP2_CONTROL_RPUB_KEY_H_2     (OMAP2_CONTROL_GENERAL + 0x0098)
-#define OMAP2_CONTROL_RPUB_KEY_H_3     (OMAP2_CONTROL_GENERAL + 0x009c)
-
-/* 242x-only CONTROL_GENERAL register offsets */
-#define OMAP242X_CONTROL_DEVCONF       OMAP2_CONTROL_DEVCONF0 /* match TRM */
-#define OMAP242X_CONTROL_OCM_RAM_PERM  (OMAP2_CONTROL_GENERAL + 0x0068)
-
-/* 243x-only CONTROL_GENERAL register offsets */
-/* CONTROL_IVA2_BOOT{ADDR,MOD} are at the same place on 343x - noted below */
-#define OMAP243X_CONTROL_DEVCONF1      (OMAP2_CONTROL_GENERAL + 0x0078)
-#define OMAP243X_CONTROL_CSIRXFE       (OMAP2_CONTROL_GENERAL + 0x007c)
-#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 OMAP24XX_CONTROL_EMU_SUPPORT   (OMAP2_CONTROL_GENERAL + 0x0008)
-#define OMAP24XX_CONTROL_SEC_TEST      (OMAP2_CONTROL_GENERAL + 0x0044)
-#define OMAP24XX_CONTROL_PSA_CTRL      (OMAP2_CONTROL_GENERAL + 0x0048)
-#define OMAP24XX_CONTROL_PSA_CMD       (OMAP2_CONTROL_GENERAL + 0x004c)
-#define OMAP24XX_CONTROL_PSA_VALUE     (OMAP2_CONTROL_GENERAL + 0x0050)
-#define OMAP24XX_CONTROL_SEC_EMU       (OMAP2_CONTROL_GENERAL + 0x0060)
-#define OMAP24XX_CONTROL_SEC_TAP       (OMAP2_CONTROL_GENERAL + 0x0064)
-#define OMAP24XX_CONTROL_OCM_PUB_RAM_ADD       (OMAP2_CONTROL_GENERAL + 0x006c)
-#define OMAP24XX_CONTROL_EXT_SEC_RAM_START_ADD (OMAP2_CONTROL_GENERAL + 0x0070)
-#define OMAP24XX_CONTROL_EXT_SEC_RAM_STOP_ADD  (OMAP2_CONTROL_GENERAL + 0x0074)
-#define OMAP24XX_CONTROL_SEC_STATUS            (OMAP2_CONTROL_GENERAL + 0x0080)
-#define OMAP24XX_CONTROL_SEC_ERR_STATUS                (OMAP2_CONTROL_GENERAL + 0x0084)
-#define OMAP24XX_CONTROL_STATUS                        (OMAP2_CONTROL_GENERAL + 0x0088)
-#define OMAP24XX_CONTROL_GENERAL_PURPOSE_STATUS        (OMAP2_CONTROL_GENERAL + 0x008c)
-#define OMAP24XX_CONTROL_RAND_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00a0)
-#define OMAP24XX_CONTROL_RAND_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00a4)
-#define OMAP24XX_CONTROL_RAND_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00a8)
-#define OMAP24XX_CONTROL_RAND_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00ac)
-#define OMAP24XX_CONTROL_CUST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00b0)
-#define OMAP24XX_CONTROL_CUST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00b4)
-#define OMAP24XX_CONTROL_TEST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00c0)
-#define OMAP24XX_CONTROL_TEST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00c4)
-#define OMAP24XX_CONTROL_TEST_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00c8)
-#define OMAP24XX_CONTROL_TEST_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00cc)
-#define OMAP24XX_CONTROL_TEST_KEY_4    (OMAP2_CONTROL_GENERAL + 0x00d0)
-#define OMAP24XX_CONTROL_TEST_KEY_5    (OMAP2_CONTROL_GENERAL + 0x00d4)
-#define OMAP24XX_CONTROL_TEST_KEY_6    (OMAP2_CONTROL_GENERAL + 0x00d8)
-#define OMAP24XX_CONTROL_TEST_KEY_7    (OMAP2_CONTROL_GENERAL + 0x00dc)
-#define OMAP24XX_CONTROL_TEST_KEY_8    (OMAP2_CONTROL_GENERAL + 0x00e0)
-#define OMAP24XX_CONTROL_TEST_KEY_9    (OMAP2_CONTROL_GENERAL + 0x00e4)
-
-#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0)
-
-/* 34xx-only CONTROL_GENERAL register offsets */
-#define OMAP343X_CONTROL_PADCONF_OFF   (OMAP2_CONTROL_GENERAL + 0x0000)
-#define OMAP343X_CONTROL_MEM_DFTRW0    (OMAP2_CONTROL_GENERAL + 0x0008)
-#define OMAP343X_CONTROL_MEM_DFTRW1    (OMAP2_CONTROL_GENERAL + 0x000c)
-#define OMAP343X_CONTROL_DEVCONF1      (OMAP2_CONTROL_GENERAL + 0x0068)
-#define OMAP343X_CONTROL_CSIRXFE               (OMAP2_CONTROL_GENERAL + 0x006c)
-#define OMAP343X_CONTROL_SEC_STATUS            (OMAP2_CONTROL_GENERAL + 0x0070)
-#define OMAP343X_CONTROL_SEC_ERR_STATUS                (OMAP2_CONTROL_GENERAL + 0x0074)
-#define OMAP343X_CONTROL_SEC_ERR_STATUS_DEBUG  (OMAP2_CONTROL_GENERAL + 0x0078)
-#define OMAP343X_CONTROL_STATUS                        (OMAP2_CONTROL_GENERAL + 0x0080)
-#define OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS        (OMAP2_CONTROL_GENERAL + 0x0084)
-#define OMAP343X_CONTROL_RPUB_KEY_H_4  (OMAP2_CONTROL_GENERAL + 0x00a0)
-#define OMAP343X_CONTROL_RAND_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00a8)
-#define OMAP343X_CONTROL_RAND_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00ac)
-#define OMAP343X_CONTROL_RAND_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00b0)
-#define OMAP343X_CONTROL_RAND_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00b4)
-#define OMAP343X_CONTROL_TEST_KEY_0    (OMAP2_CONTROL_GENERAL + 0x00c8)
-#define OMAP343X_CONTROL_TEST_KEY_1    (OMAP2_CONTROL_GENERAL + 0x00cc)
-#define OMAP343X_CONTROL_TEST_KEY_2    (OMAP2_CONTROL_GENERAL + 0x00d0)
-#define OMAP343X_CONTROL_TEST_KEY_3    (OMAP2_CONTROL_GENERAL + 0x00d4)
-#define OMAP343X_CONTROL_TEST_KEY_4    (OMAP2_CONTROL_GENERAL + 0x00d8)
-#define OMAP343X_CONTROL_TEST_KEY_5    (OMAP2_CONTROL_GENERAL + 0x00dc)
-#define OMAP343X_CONTROL_TEST_KEY_6    (OMAP2_CONTROL_GENERAL + 0x00e0)
-#define OMAP343X_CONTROL_TEST_KEY_7    (OMAP2_CONTROL_GENERAL + 0x00e4)
-#define OMAP343X_CONTROL_TEST_KEY_8    (OMAP2_CONTROL_GENERAL + 0x00e8)
-#define OMAP343X_CONTROL_TEST_KEY_9    (OMAP2_CONTROL_GENERAL + 0x00ec)
-#define OMAP343X_CONTROL_TEST_KEY_10   (OMAP2_CONTROL_GENERAL + 0x00f0)
-#define OMAP343X_CONTROL_TEST_KEY_11   (OMAP2_CONTROL_GENERAL + 0x00f4)
-#define OMAP343X_CONTROL_TEST_KEY_12   (OMAP2_CONTROL_GENERAL + 0x00f8)
-#define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
-#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
-#define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
-#define OMAP343X_CONTROL_DEBOBS(i)     (OMAP2_CONTROL_GENERAL + 0x01B0 \
-                                       + ((i) >> 1) * 4 + (!((i) & 1)) * 2)
-#define OMAP343X_CONTROL_PROG_IO0      (OMAP2_CONTROL_GENERAL + 0x01D4)
-#define OMAP343X_CONTROL_PROG_IO1      (OMAP2_CONTROL_GENERAL + 0x01D8)
-#define OMAP343X_CONTROL_DSS_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E0)
-#define OMAP343X_CONTROL_CORE_DPLL_SPREADING   (OMAP2_CONTROL_GENERAL + 0x01E4)
-#define OMAP343X_CONTROL_PER_DPLL_SPREADING    (OMAP2_CONTROL_GENERAL + 0x01E8)
-#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING        (OMAP2_CONTROL_GENERAL + 0x01EC)
-#define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02B0)
-#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02B4)
-#define OMAP343X_CONTROL_SRAMLDO4      (OMAP2_CONTROL_GENERAL + 0x02B8)
-#define OMAP343X_CONTROL_SRAMLDO5      (OMAP2_CONTROL_GENERAL + 0x02C0)
-#define OMAP343X_CONTROL_CSI           (OMAP2_CONTROL_GENERAL + 0x02C4)
-
-/* AM35XX only CONTROL_GENERAL register offsets */
-#define AM35XX_CONTROL_MSUSPENDMUX_6    (OMAP2_CONTROL_GENERAL + 0x0038)
-#define AM35XX_CONTROL_DEVCONF2         (OMAP2_CONTROL_GENERAL + 0x0310)
-#define AM35XX_CONTROL_DEVCONF3         (OMAP2_CONTROL_GENERAL + 0x0314)
-#define AM35XX_CONTROL_CBA_PRIORITY     (OMAP2_CONTROL_GENERAL + 0x0320)
-#define AM35XX_CONTROL_LVL_INTR_CLEAR   (OMAP2_CONTROL_GENERAL + 0x0324)
-#define AM35XX_CONTROL_IP_SW_RESET      (OMAP2_CONTROL_GENERAL + 0x0328)
-#define AM35XX_CONTROL_IPSS_CLK_CTRL    (OMAP2_CONTROL_GENERAL + 0x032C)
-
-/* 34xx PADCONF register offsets */
-#define OMAP343X_PADCONF_ETK(i)                (OMAP2_CONTROL_PADCONFS + 0x5a8 + \
-                                               (i)*2)
-#define OMAP343X_PADCONF_ETK_CLK       OMAP343X_PADCONF_ETK(0)
-#define OMAP343X_PADCONF_ETK_CTL       OMAP343X_PADCONF_ETK(1)
-#define OMAP343X_PADCONF_ETK_D0                OMAP343X_PADCONF_ETK(2)
-#define OMAP343X_PADCONF_ETK_D1                OMAP343X_PADCONF_ETK(3)
-#define OMAP343X_PADCONF_ETK_D2                OMAP343X_PADCONF_ETK(4)
-#define OMAP343X_PADCONF_ETK_D3                OMAP343X_PADCONF_ETK(5)
-#define OMAP343X_PADCONF_ETK_D4                OMAP343X_PADCONF_ETK(6)
-#define OMAP343X_PADCONF_ETK_D5                OMAP343X_PADCONF_ETK(7)
-#define OMAP343X_PADCONF_ETK_D6                OMAP343X_PADCONF_ETK(8)
-#define OMAP343X_PADCONF_ETK_D7                OMAP343X_PADCONF_ETK(9)
-#define OMAP343X_PADCONF_ETK_D8                OMAP343X_PADCONF_ETK(10)
-#define OMAP343X_PADCONF_ETK_D9                OMAP343X_PADCONF_ETK(11)
-#define OMAP343X_PADCONF_ETK_D10       OMAP343X_PADCONF_ETK(12)
-#define OMAP343X_PADCONF_ETK_D11       OMAP343X_PADCONF_ETK(13)
-#define OMAP343X_PADCONF_ETK_D12       OMAP343X_PADCONF_ETK(14)
-#define OMAP343X_PADCONF_ETK_D13       OMAP343X_PADCONF_ETK(15)
-#define OMAP343X_PADCONF_ETK_D14       OMAP343X_PADCONF_ETK(16)
-#define OMAP343X_PADCONF_ETK_D15       OMAP343X_PADCONF_ETK(17)
-
-/* 34xx GENERAL_WKUP regist offsets */
-#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
-                                               0x008 + (i))
-#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
-#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C)
-#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010)
-#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
-#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
-
-/* 34xx D2D idle-related pins, handled by PM core */
-#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
-#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
-
-/* 44xx control status register offset */
-#define OMAP44XX_CONTROL_STATUS                0x2c4
-
-/* 44xx-only CONTROL_GENERAL register offsets */
-#define OMAP44XX_CONTROL_MMC1                  0x628
-#define OMAP44XX_CONTROL_PBIAS_LITE            0x600
-/*
- * REVISIT: This list of registers is not comprehensive - there are more
- * that should be added.
- */
-
-/*
- * Control module register bit defines - these should eventually go into
- * their own regbits file.  Some of these will be complicated, depending
- * on the device type (general-purpose, emulator, test, secure, bad, other)
- * 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 */
-
-/* CONTROL_STATUS bits */
-#define OMAP2_DEVICETYPE_MASK          (0x7 << 8)
-#define OMAP2_SYSBOOT_5_MASK           (1 << 5)
-#define OMAP2_SYSBOOT_4_MASK           (1 << 4)
-#define OMAP2_SYSBOOT_3_MASK           (1 << 3)
-#define OMAP2_SYSBOOT_2_MASK           (1 << 2)
-#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)
-
-/* CONTROL_PBIAS_LITE bits for OMAP4 */
-#define OMAP4_MMC1_PWRDNZ                      (1 << 26)
-#define OMAP4_MMC1_PBIASLITE_HIZ_MODE          (1 << 25)
-#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT     (1 << 24)
-#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR       (1 << 23)
-#define OMAP4_MMC1_PBIASLITE_PWRDNZ            (1 << 22)
-#define OMAP4_MMC1_PBIASLITE_VMODE             (1 << 21)
-#define OMAP4_USBC1_ICUSB_PWRDNZ               (1 << 20)
-
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0    (1 << 31)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1    (1 << 30)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2    (1 << 29)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3    (1 << 28)
-#define OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL     (1 << 27)
-#define OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL     (1 << 26)
-#define OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL     (1 << 25)
-
-/* CONTROL_PROG_IO1 bits */
-#define OMAP3630_PRG_SDMMC1_SPEEDCTRL  (1 << 20)
-
-/* CONTROL_IVA2_BOOTMOD bits */
-#define OMAP3_IVA2_BOOTMOD_SHIFT       0
-#define OMAP3_IVA2_BOOTMOD_MASK                (0xf << 0)
-#define OMAP3_IVA2_BOOTMOD_IDLE                (0x1 << 0)
-
-/* CONTROL_PADCONF_X bits */
-#define OMAP3_PADCONF_WAKEUPEVENT0     (1 << 15)
-#define OMAP3_PADCONF_WAKEUPENABLE0    (1 << 14)
-
-#define OMAP343X_SCRATCHPAD_ROM                (OMAP343X_CTRL_BASE + 0x860)
-#define OMAP343X_SCRATCHPAD            (OMAP343X_CTRL_BASE + 0x910)
-#define OMAP343X_SCRATCHPAD_ROM_OFFSET 0x19C
-
-/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */
-#define AM35XX_USBOTG_VBUSP_CLK_SHIFT   0
-#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT   1
-#define AM35XX_VPFE_VBUSP_CLK_SHIFT     2
-#define AM35XX_HECC_VBUSP_CLK_SHIFT     3
-#define AM35XX_USBOTG_FCLK_SHIFT        8
-#define AM35XX_CPGMAC_FCLK_SHIFT        9
-#define AM35XX_VPFE_FCLK_SHIFT          10
-
-/*AM35XX CONTROL_LVL_INTR_CLEAR bits*/
-#define AM35XX_CPGMAC_C0_MISC_PULSE_CLR        BIT(0)
-#define AM35XX_CPGMAC_C0_RX_PULSE_CLR  BIT(1)
-#define AM35XX_CPGMAC_C0_RX_THRESH_CLR BIT(2)
-#define AM35XX_CPGMAC_C0_TX_PULSE_CLR  BIT(3)
-#define AM35XX_USBOTGSS_INT_CLR                BIT(4)
-#define AM35XX_VPFE_CCDC_VD0_INT_CLR   BIT(5)
-#define AM35XX_VPFE_CCDC_VD1_INT_CLR   BIT(6)
-#define AM35XX_VPFE_CCDC_VD2_INT_CLR   BIT(7)
-
-/*AM35XX CONTROL_IP_SW_RESET bits*/
-#define AM35XX_USBOTGSS_SW_RST         BIT(0)
-#define AM35XX_CPGMACSS_SW_RST         BIT(1)
-#define AM35XX_VPFE_VBUSP_SW_RST       BIT(2)
-#define AM35XX_HECC_SW_RST             BIT(3)
-#define AM35XX_VPFE_PCLK_SW_RST                BIT(4)
-
-/*
- * CONTROL OMAP STATUS register to identify OMAP3 features
- */
-#define OMAP3_CONTROL_OMAP_STATUS      0x044c
-
-#define OMAP3_SGX_SHIFT                        13
-#define OMAP3_SGX_MASK                 (3 << OMAP3_SGX_SHIFT)
-#define                FEAT_SGX_FULL           0
-#define                FEAT_SGX_HALF           1
-#define                FEAT_SGX_NONE           2
-
-#define OMAP3_IVA_SHIFT                        12
-#define OMAP3_IVA_MASK                 (1 << OMAP3_SGX_SHIFT)
-#define                FEAT_IVA                0
-#define                FEAT_IVA_NONE           1
-
-#define OMAP3_L2CACHE_SHIFT            10
-#define OMAP3_L2CACHE_MASK             (3 << OMAP3_L2CACHE_SHIFT)
-#define                FEAT_L2CACHE_NONE       0
-#define                FEAT_L2CACHE_64KB       1
-#define                FEAT_L2CACHE_128KB      2
-#define                FEAT_L2CACHE_256KB      3
-
-#define OMAP3_ISP_SHIFT                        5
-#define OMAP3_ISP_MASK                 (1<< OMAP3_ISP_SHIFT)
-#define                FEAT_ISP                0
-#define                FEAT_ISP_NONE           1
-
-#define OMAP3_NEON_SHIFT               4
-#define OMAP3_NEON_MASK                        (1<< OMAP3_NEON_SHIFT)
-#define                FEAT_NEON               0
-#define                FEAT_NEON_NONE          1
-
-
-#ifndef __ASSEMBLY__
-#ifdef CONFIG_ARCH_OMAP2PLUS
-extern void __iomem *omap_ctrl_base_get(void);
-extern u8 omap_ctrl_readb(u16 offset);
-extern u16 omap_ctrl_readw(u16 offset);
-extern u32 omap_ctrl_readl(u16 offset);
-extern void omap_ctrl_writeb(u8 val, u16 offset);
-extern void omap_ctrl_writew(u16 val, u16 offset);
-extern void omap_ctrl_writel(u32 val, u16 offset);
-
-extern void omap3_save_scratchpad_contents(void);
-extern void omap3_clear_scratchpad_contents(void);
-extern u32 *get_restore_pointer(void);
-extern u32 *get_es3_restore_pointer(void);
-extern u32 omap3_arm_context[128];
-extern void omap3_control_save_context(void);
-extern void omap3_control_restore_context(void);
-
-#else
-#define omap_ctrl_base_get()           0
-#define omap_ctrl_readb(x)             0
-#define omap_ctrl_readw(x)             0
-#define omap_ctrl_readl(x)             0
-#define omap_ctrl_writeb(x, y)         WARN_ON(1)
-#define omap_ctrl_writew(x, y)         WARN_ON(1)
-#define omap_ctrl_writel(x, y)         WARN_ON(1)
-#endif
-#endif /* __ASSEMBLY__ */
-
-#endif /* __ASM_ARCH_CONTROL_H */
-
index 2e2ae530fced338a7b08fe16bc715582cd27cb44..3fd8b4055727e1e7e0aaf006322b8905aa925f0c 100644 (file)
@@ -68,10 +68,9 @@ unsigned int omap_rev(void);
 #define OMAP_REVBITS_00                0x00
 #define OMAP_REVBITS_01                0x01
 #define OMAP_REVBITS_02                0x02
-#define OMAP_REVBITS_10                0x10
-#define OMAP_REVBITS_20                0x20
-#define OMAP_REVBITS_30                0x30
-#define OMAP_REVBITS_40                0x40
+#define OMAP_REVBITS_03                0x03
+#define OMAP_REVBITS_04                0x04
+#define OMAP_REVBITS_05                0x05
 
 /*
  * Get the CPU revision for OMAP devices
@@ -363,23 +362,24 @@ IS_OMAP_TYPE(3517, 0x3517)
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS         0x24200024
-#define OMAP2420_REV_ES1_0     0x24200024
-#define OMAP2420_REV_ES2_0     0x24201024
+#define OMAP2420_REV_ES1_0     OMAP242X_CLASS
+#define OMAP2420_REV_ES2_0     (OMAP242X_CLASS | (OMAP_REVBITS_01 << 8))
 
 #define OMAP243X_CLASS         0x24300024
-#define OMAP2430_REV_ES1_0     0x24300024
+#define OMAP2430_REV_ES1_0     OMAP243X_CLASS
 
 #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
-#define OMAP3430_REV_ES3_1     0x34304034
-#define OMAP3430_REV_ES3_1_2   0x34305034
-
-#define OMAP3630_REV_ES1_0     0x36300034
-#define OMAP3630_REV_ES1_1     0x36300134
-#define OMAP3630_REV_ES1_2     0x36300234
+#define OMAP3430_REV_ES1_0     OMAP343X_CLASS
+#define OMAP3430_REV_ES2_0     (OMAP343X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3430_REV_ES2_1     (OMAP343X_CLASS | (OMAP_REVBITS_02 << 8))
+#define OMAP3430_REV_ES3_0     (OMAP343X_CLASS | (OMAP_REVBITS_03 << 8))
+#define OMAP3430_REV_ES3_1     (OMAP343X_CLASS | (OMAP_REVBITS_04 << 8))
+#define OMAP3430_REV_ES3_1_2   (OMAP343X_CLASS | (OMAP_REVBITS_05 << 8))
+
+#define OMAP363X_CLASS         0x36300034
+#define OMAP3630_REV_ES1_0     OMAP363X_CLASS
+#define OMAP3630_REV_ES1_1     (OMAP363X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3630_REV_ES1_2     (OMAP363X_CLASS | (OMAP_REVBITS_02 << 8))
 
 #define OMAP35XX_CLASS         0x35000034
 #define OMAP3503_REV(v)                (OMAP35XX_CLASS | (0x3503 << 16) | (v << 8))
@@ -390,7 +390,8 @@ IS_OMAP_TYPE(3517, 0x3517)
 #define OMAP3517_REV(v)                (OMAP35XX_CLASS | (0x3517 << 16) | (v << 8))
 
 #define OMAP443X_CLASS         0x44300044
-#define OMAP4430_REV_ES1_0     0x44300044
+#define OMAP4430_REV_ES1_0     OMAP443X_CLASS
+#define OMAP4430_REV_ES2_0     0x44301044
 
 /*
  * omap_chip bits
@@ -417,10 +418,12 @@ IS_OMAP_TYPE(3517, 0x3517)
 #define CHIP_IS_OMAP4430ES1            (1 << 8)
 #define CHIP_IS_OMAP3630ES1_1           (1 << 9)
 #define CHIP_IS_OMAP3630ES1_2           (1 << 10)
+#define CHIP_IS_OMAP4430ES2            (1 << 11)
 
 #define CHIP_IS_OMAP24XX               (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
 
-#define CHIP_IS_OMAP4430               (CHIP_IS_OMAP4430ES1)
+#define CHIP_IS_OMAP4430               (CHIP_IS_OMAP4430ES1 | \
+                                                CHIP_IS_OMAP4430ES2)
 
 /*
  * "GE" here represents "greater than or equal to" in terms of ES
index 8bd15bdb4132c1532fdd0704c88af5206b7f6e15..c915a661f1f5668a6aa7f0b9b50cbf664507f2d4 100644 (file)
@@ -81,37 +81,6 @@ enum omap_color_mode {
        OMAP_DSS_COLOR_ARGB32   = 1 << 11, /* ARGB32 */
        OMAP_DSS_COLOR_RGBA32   = 1 << 12, /* RGBA32 */
        OMAP_DSS_COLOR_RGBX32   = 1 << 13, /* RGBx32 */
-
-       OMAP_DSS_COLOR_GFX_OMAP2 =
-               OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
-               OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
-               OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
-               OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
-
-       OMAP_DSS_COLOR_VID_OMAP2 =
-               OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-               OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
-               OMAP_DSS_COLOR_UYVY,
-
-       OMAP_DSS_COLOR_GFX_OMAP3 =
-               OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
-               OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
-               OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
-               OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-               OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
-               OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
-
-       OMAP_DSS_COLOR_VID1_OMAP3 =
-               OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
-               OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
-               OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
-
-       OMAP_DSS_COLOR_VID2_OMAP3 =
-               OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
-               OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-               OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
-               OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
-               OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
 enum omap_lcd_display_type {
index af3a03941addfd810a24452b2af25c749f3a8632..0cce4ca83aa0c70217fadd03ea07856665436ef0 100644 (file)
 #define OMAP34XX_DMA_USIM_TX           79      /* S_DMA_78 */
 #define OMAP34XX_DMA_USIM_RX           80      /* S_DMA_79 */
 
+#define OMAP36XX_DMA_UART4_TX          81      /* S_DMA_80 */
+#define OMAP36XX_DMA_UART4_RX          82      /* S_DMA_81 */
 /*----------------------------------------------------------------------------*/
 
 #define OMAP1_DMA_TOUT_IRQ             (1 << 0)
 #define OMAP2_DMA_MISALIGNED_ERR_IRQ   (1 << 11)
 
 #define OMAP_DMA_CCR_EN                        (1 << 7)
+#define OMAP_DMA_CCR_RD_ACTIVE         (1 << 9)
+#define OMAP_DMA_CCR_WR_ACTIVE         (1 << 10)
+#define OMAP_DMA_CCR_SEL_SRC_DST_SYNC  (1 << 24)
+#define OMAP_DMA_CCR_BUFFERING_DISABLE (1 << 25)
 
 #define OMAP_DMA_DATA_TYPE_S8          0x00
 #define OMAP_DMA_DATA_TYPE_S16         0x01
index 20f1054c0a804bf541fb313b27f896a45b6fbaa3..dfa3aff9761bc0cf814c73c5da2d484817bdbbb1 100644 (file)
@@ -45,6 +45,8 @@
 #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE        0x02
 
 struct omap_dm_timer;
+extern struct omap_dm_timer *gptimer_wakeup;
+extern struct sys_timer omap_timer;
 struct clk;
 
 int omap_dm_timer_init(void);
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
new file mode 100644 (file)
index 0000000..872de0b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from arch/arm/plat-omap/include/plat/gpmc-smc91x.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.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPMC_SMSC911X_H__
+
+struct omap_smsc911x_platform_data {
+       int     cs;
+       int     gpio_irq;
+       int     gpio_reset;
+       u32     flags;
+};
+
+#if defined(CONFIG_SMSC911X) || \
+       defined(CONFIG_SMSC911X_MODULE)
+
+extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
+
+#else
+
+static inline void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d)
+{
+}
+
+#endif
+#endif
index 87f6bf2ea4fafbf2864a9f72f630cc5ec56da9a9..36a0befd6168e82c5acc3f7cc75602d0158a40ea 100644 (file)
@@ -18,6 +18,8 @@
  * 02110-1301 USA
  *
  */
+#ifndef __ASM__ARCH_OMAP_I2C_H
+#define __ASM__ARCH_OMAP_I2C_H
 
 #include <linux/i2c.h>
 
@@ -36,3 +38,5 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
 
 void __init omap1_i2c_mux_pins(int bus_id);
 void __init omap2_i2c_mux_pins(int bus_id);
+
+#endif /* __ASM__ARCH_OMAP_I2C_H */
index c01d9f08a19874d78777309693b8ac1a6274b419..65e20a686713731be41d9eb9285cb6aa592e0fd6 100644 (file)
 #define INT_34XX_MMC3_IRQ      94
 #define INT_34XX_GPT12_IRQ     95
 
+#define INT_36XX_UART4_IRQ     80
+
 #define INT_35XX_HECC0_IRQ             24
 #define INT_35XX_HECC1_IRQ             28
 #define INT_35XX_EMAC_C0_RXTHRESH_IRQ  67
index b4ff6a11a8f2862dbc2f0daf1c70167b50284145..b87d83ccd545e5ea889d9111a48f13a0d3098644 100644 (file)
 #include <mach/hardware.h>
 #include <plat/clock.h>
 
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)            \
+static struct platform_device omap_mcbsp##port_nr = {  \
+       .name   = "omap-mcbsp-dai",                     \
+       .id     = OMAP_MCBSP##port_nr,                  \
+}
+
 #define OMAP7XX_MCBSP1_BASE    0xfffb1000
 #define OMAP7XX_MCBSP2_BASE    0xfffb1800
 
 #define RFSREN                 0x0002
 #define RSYNCERREN             0x0001
 
+/* CLKR signal muxing options */
+#define CLKR_SRC_CLKR          0
+#define CLKR_SRC_CLKX          1
+
+/* FSR signal muxing options */
+#define FSR_SRC_FSR            0
+#define FSR_SRC_FSX            1
+
+/* McBSP functional clock sources */
+#define MCBSP_CLKS_PRCM_SRC    0
+#define MCBSP_CLKS_PAD_SRC     1
+
 /* we don't do multichannel for now */
 struct omap_mcbsp_reg_cfg {
        u16 spcr2;
@@ -398,6 +417,7 @@ struct omap_mcbsp_spi_cfg {
 struct omap_mcbsp_ops {
        void (*request)(unsigned int);
        void (*free)(unsigned int);
+       int (*set_clks_src)(u8, u8);
 };
 
 struct omap_mcbsp_platform_data {
@@ -464,6 +484,9 @@ struct omap_mcbsp {
 extern struct omap_mcbsp **mcbsp_ptr;
 extern int omap_mcbsp_count, omap_mcbsp_cache_size;
 
+#define omap_mcbsp_check_valid_id(id)  (id < omap_mcbsp_count)
+#define id_to_mcbsp_ptr(id)            mcbsp_ptr[id];
+
 int omap_mcbsp_init(void);
 void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
                                        int size);
@@ -502,6 +525,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
 int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
 
 
+/* McBSP functional clock source changing function */
+extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id);
 /* SPI specific API */
 void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
 
@@ -510,6 +535,10 @@ int omap_mcbsp_pollread(unsigned int id, u16 * buf);
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
 int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
 
+/* McBSP signal muxing API */
+void omap2_mcbsp1_mux_clkr_src(u8 mux);
+void omap2_mcbsp1_mux_fsr_src(u8 mux);
+
 #ifdef CONFIG_ARCH_OMAP3
 /* Sidetone specific API */
 int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
index 9b89ec601ee2788535c75f8fa572b149d85af957..f57f36abb07edf7695bdb8dd8013f1255e3589b0 100644 (file)
@@ -71,12 +71,17 @@ struct omap_mmc_platform_data {
 
        u64 dma_mask;
 
+       /* Register offset deviation */
+       u16 reg_offset;
+
        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
+               /*
+                * 4/8 wires and any additional host capabilities
+                * need to OR'd all capabilities (ref. linux/mmc/host.h)
                 */
-               u8 wires;
+               u8  wires;      /* Used for the MMC driver on omap1 and 2420 */
+               u32 caps;       /* Used for the MMC driver on 2430 and later */
 
                /*
                 * nomux means "standard" muxing is wrong on this board, and
@@ -104,6 +109,7 @@ struct omap_mmc_platform_data {
 
                /* we can put the features above into this variable */
 #define HSMMC_HAS_PBIAS                (1 << 0)
+#define HSMMC_HAS_UPDATED_RESET        (1 << 1)
                unsigned features;
 
                int switch_pin;                 /* gpio (card detect) */
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
new file mode 100644 (file)
index 0000000..c8dae02
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *     Govindraj R     <govindraj.raja@ti.com>
+ *     Thara Gopinath  <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __OMAP_SERIAL_H__
+#define __OMAP_SERIAL_H__
+
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <plat/mux.h>
+
+#define DRIVER_NAME    "omap-hsuart"
+
+/*
+ * Use tty device name as ttyO, [O -> OMAP]
+ * in bootargs we specify as console=ttyO0 if uart1
+ * is used as console uart.
+ */
+#define OMAP_SERIAL_NAME       "ttyO"
+
+#define OMAP_MDR1_DISABLE      0x07
+#define OMAP_MDR1_MODE13X      0x03
+#define OMAP_MDR1_MODE16X      0x00
+#define OMAP_MODE13X_SPEED     230400
+
+/*
+ * LCR = 0XBF: Switch to Configuration Mode B.
+ * In configuration mode b allow access
+ * to EFR,DLL,DLH.
+ * Reference OMAP TRM Chapter 17
+ * Section: 1.4.3 Mode Selection
+ */
+#define OMAP_UART_LCR_CONF_MDB 0XBF
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP 0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX                0x04
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX                0x04
+
+#define OMAP_UART_SYSC_RESET   0X07
+#define OMAP_UART_TCR_TRIG     0X0F
+#define OMAP_UART_SW_CLR       0XF0
+#define OMAP_UART_FIFO_CLR     0X06
+
+#define OMAP_UART_DMA_CH_FREE  -1
+
+#define RX_TIMEOUT             (3 * HZ)
+#define OMAP_MAX_HSUART_PORTS  4
+
+#define MSR_SAVE_FLAGS         UART_MSR_ANY_DELTA
+
+struct omap_uart_port_info {
+       bool                    dma_enabled;    /* To specify DMA Mode */
+       unsigned int            uartclk;        /* UART clock rate */
+       void __iomem            *membase;       /* ioremap cookie or NULL */
+       resource_size_t         mapbase;        /* resource base */
+       unsigned long           irqflags;       /* request_irq flags */
+       upf_t                   flags;          /* UPF_* flags */
+};
+
+struct uart_omap_dma {
+       u8                      uart_dma_tx;
+       u8                      uart_dma_rx;
+       int                     rx_dma_channel;
+       int                     tx_dma_channel;
+       dma_addr_t              rx_buf_dma_phys;
+       dma_addr_t              tx_buf_dma_phys;
+       unsigned int            uart_base;
+       /*
+        * Buffer for rx dma.It is not required for tx because the buffer
+        * comes from port structure.
+        */
+       unsigned char           *rx_buf;
+       unsigned int            prev_rx_dma_pos;
+       int                     tx_buf_size;
+       int                     tx_dma_used;
+       int                     rx_dma_used;
+       spinlock_t              tx_lock;
+       spinlock_t              rx_lock;
+       /* timer to poll activity on rx dma */
+       struct timer_list       rx_timer;
+       int                     rx_buf_size;
+       int                     rx_timeout;
+};
+
+struct uart_omap_port {
+       struct uart_port        port;
+       struct uart_omap_dma    uart_dma;
+       struct platform_device  *pdev;
+
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           fcr;
+       unsigned char           efr;
+
+       int                     use_dma;
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+       unsigned int            lsr_break_flag;
+       unsigned char           msr_saved_flags;
+       char                    name[20];
+       unsigned long           port_activity;
+};
+
+#endif /* __OMAP_SERIAL_H__ */
index 7055672a8c68932dc6a41a528bede03c07a813be..92df9e27cc5cc1b690836cd3a825bf9c4adf9cbe 100644 (file)
@@ -40,7 +40,7 @@
 #define OMAP24XX_IC_BASE       (L4_24XX_BASE + 0xfe000)
 #define OMAP24XX_IVA_INTC_BASE 0x40000000
 
-#define OMAP2420_CTRL_BASE     L4_24XX_BASE
+#define OMAP242X_CTRL_BASE     L4_24XX_BASE
 #define OMAP2420_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
 #define OMAP2420_PRCM_BASE     (L4_24XX_BASE + 0x8000)
 #define OMAP2420_CM_BASE       (L4_24XX_BASE + 0x8000)
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h
new file mode 100644 (file)
index 0000000..2b1d9bc
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+struct omap4_keypad_platform_data {
+       const struct matrix_keymap_data *keymap_data;
+
+       u8 rows;
+       u8 cols;
+};
+
+extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
+#endif
index 25cd9ac3b0958eb1a61d166b485731be2a480dab..28e2d1a78433b6d57c94e40b4050bb8ab521717c 100644 (file)
@@ -36,6 +36,8 @@
 
 #include <plat/omap_hwmod.h>
 
+extern struct device omap_device_parent;
+
 /* omap_device._state values */
 #define OMAP_DEVICE_STATE_UNKNOWN      0
 #define OMAP_DEVICE_STATE_ENABLED      1
@@ -62,7 +64,6 @@
  *
  */
 struct omap_device {
-       u32                             magic;
        struct platform_device          pdev;
        struct omap_hwmod               **hwmods;
        struct omap_device_pm_latency   *pm_lats;
@@ -82,7 +83,6 @@ int omap_device_shutdown(struct platform_device *pdev);
 
 /* Core code interface */
 
-bool omap_device_is_valid(struct omap_device *od);
 int omap_device_count_resources(struct omap_device *od);
 int omap_device_fill_resources(struct omap_device *od, struct resource *res);
 
index a4e508dfaba2716a46a9d20d1ac59337dce1fae2..7eaa8edf3b142eb3779385df916df80d1e055bf8 100644 (file)
  *
  * These headers and macros are used to define OMAP on-chip module
  * data and their integration with other OMAP modules and Linux.
- *
- * References:
- * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
- * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
- * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
- * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
- * - Open Core Protocol Specification 2.2
+ * Copious documentation and references can also be found in the
+ * omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this
+ * writing).
  *
  * To do:
  * - add interconnect error log structures
  * - add pinmuxing
  * - init_conn_id_bit (CONNID_BIT_VECTOR)
  * - implement default hwmod SMS/SDRC flags?
+ * - remove unused fields
  *
  */
 #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
@@ -35,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
+#include <linux/mutex.h>
 #include <plat/cpu.h>
 
 struct omap_device;
@@ -96,7 +94,7 @@ struct omap_hwmod_irq_info {
 /**
  * struct omap_hwmod_dma_info - DMA channels used by the hwmod
  * @name: name of the DMA channel (module local name)
- * @dma_ch: DMA channel ID
+ * @dma_req: DMA request ID
  *
  * @name should be something short, e.g., "tx" or "rx".  It is for use
  * by platform_get_resource_byname().  It is defined locally to the
@@ -104,7 +102,20 @@ struct omap_hwmod_irq_info {
  */
 struct omap_hwmod_dma_info {
        const char      *name;
-       u16             dma_ch;
+       u16             dma_req;
+};
+
+/**
+ * struct omap_hwmod_rst_info - IPs reset lines use by hwmod
+ * @name: name of the reset line (module local name)
+ * @rst_shift: Offset of the reset bit
+ *
+ * @name should be something short, e.g., "cpu0" or "rst". It is defined
+ * locally to the hwmod.
+ */
+struct omap_hwmod_rst_info {
+       const char      *name;
+       u8              rst_shift;
 };
 
 /**
@@ -237,8 +248,9 @@ struct omap_hwmod_ocp_if {
 #define SYSC_HAS_CLOCKACTIVITY (1 << 4)
 #define SYSC_HAS_SIDLEMODE     (1 << 5)
 #define SYSC_HAS_MIDLEMODE     (1 << 6)
-#define SYSS_MISSING           (1 << 7)
+#define SYSS_HAS_RESET_STATUS  (1 << 7)
 #define SYSC_NO_CACHE          (1 << 8)  /* XXX SW flag, belongs elsewhere */
+#define SYSC_HAS_RESET_STATUS  (1 << 9)
 
 /* omap_hwmod_sysconfig.clockact flags */
 #define CLOCKACT_TEST_BOTH     0x0
@@ -327,10 +339,12 @@ struct omap_hwmod_omap2_prcm {
 /**
  * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
  * @clkctrl_reg: PRCM address of the clock control register
+ * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
  * @submodule_wkdep_bit: bit shift of the WKDEP range
  */
 struct omap_hwmod_omap4_prcm {
        void __iomem    *clkctrl_reg;
+       void __iomem    *rstctrl_reg;
        u8              submodule_wkdep_bit;
 };
 
@@ -352,6 +366,11 @@ struct omap_hwmod_omap4_prcm {
  * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
  * HWMOD_NO_IDLEST : this module does not have idle status - this is the case
  *     only for few initiator modules on OMAP2 & 3.
+ * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset.
+ *     This is needed for devices like DSS that require optional clocks enabled
+ *     in order to complete the reset. Optional clocks will be disabled
+ *     again after the reset.
+ * HWMOD_16BIT_REG: Module has 16bit registers
  */
 #define HWMOD_SWSUP_SIDLE                      (1 << 0)
 #define HWMOD_SWSUP_MSTANDBY                   (1 << 1)
@@ -360,6 +379,8 @@ struct omap_hwmod_omap4_prcm {
 #define HWMOD_NO_OCP_AUTOIDLE                  (1 << 4)
 #define HWMOD_SET_DEFAULT_CLOCKACT             (1 << 5)
 #define HWMOD_NO_IDLEST                                (1 << 6)
+#define HWMOD_CONTROL_OPT_CLKS_IN_RESET                (1 << 7)
+#define HWMOD_16BIT_REG                                (1 << 8)
 
 /*
  * omap_hwmod._int_flags definitions
@@ -410,7 +431,7 @@ struct omap_hwmod_class {
  * @class: struct omap_hwmod_class * to the class of this hwmod
  * @od: struct omap_device currently associated with this hwmod (internal use)
  * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt)
- * @sdma_chs: ptr to an array of SDMA channel IDs (see also sdma_chs_cnt)
+ * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt)
  * @prcm: PRCM data pertaining to this hwmod
  * @main_clk: main clock: OMAP clock name
  * @_clk: pointer to the main struct clk (filled in at runtime)
@@ -424,7 +445,7 @@ struct omap_hwmod_class {
  * @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6)
  * @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift
  * @mpu_irqs_cnt: number of @mpu_irqs
- * @sdma_chs_cnt: number of @sdma_chs
+ * @sdma_reqs_cnt: number of @sdma_reqs
  * @opt_clks_cnt: number of @opt_clks
  * @master_cnt: number of @master entries
  * @slaves_cnt: number of @slave entries
@@ -433,6 +454,7 @@ struct omap_hwmod_class {
  * @_state: internal-use hwmod state
  * @flags: hwmod flags (documented below)
  * @omap_chip: OMAP chips this hwmod is present on
+ * @_mutex: mutex serializing operations on this hwmod
  * @node: list node for hwmod list (internal use)
  *
  * @main_clk refers to this module's "main clock," which for our
@@ -448,7 +470,8 @@ struct omap_hwmod {
        struct omap_hwmod_class         *class;
        struct omap_device              *od;
        struct omap_hwmod_irq_info      *mpu_irqs;
-       struct omap_hwmod_dma_info      *sdma_chs;
+       struct omap_hwmod_dma_info      *sdma_reqs;
+       struct omap_hwmod_rst_info      *rst_lines;
        union {
                struct omap_hwmod_omap2_prcm omap2;
                struct omap_hwmod_omap4_prcm omap4;
@@ -461,6 +484,7 @@ struct omap_hwmod {
        void                            *dev_attr;
        u32                             _sysc_cache;
        void __iomem                    *_mpu_rt_va;
+       struct mutex                    _mutex;
        struct list_head                node;
        u16                             flags;
        u8                              _mpu_port_index;
@@ -468,7 +492,8 @@ struct omap_hwmod {
        u8                              msuspendmux_shift;
        u8                              response_lat;
        u8                              mpu_irqs_cnt;
-       u8                              sdma_chs_cnt;
+       u8                              sdma_reqs_cnt;
+       u8                              rst_lines_cnt;
        u8                              opt_clks_cnt;
        u8                              masters_cnt;
        u8                              slaves_cnt;
@@ -492,6 +517,10 @@ int omap_hwmod_idle(struct omap_hwmod *oh);
 int _omap_hwmod_idle(struct omap_hwmod *oh);
 int omap_hwmod_shutdown(struct omap_hwmod *oh);
 
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name);
+
 int omap_hwmod_enable_clocks(struct omap_hwmod *oh);
 int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 
@@ -500,8 +529,8 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs);
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs);
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs);
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs);
 
 int omap_hwmod_count_resources(struct omap_hwmod *oh);
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);
@@ -534,5 +563,6 @@ int omap_hwmod_for_each_by_class(const char *classname,
 extern int omap2420_hwmod_init(void);
 extern int omap2430_hwmod_init(void);
 extern int omap3xxx_hwmod_init(void);
+extern int omap44xx_hwmod_init(void);
 
 #endif
index fb6ec74fe39e342736e7b0163541777a96012469..9ca420dcd2f86da87c0979e6b596b74d6a9b259b 100644 (file)
@@ -32,6 +32,7 @@
 
 /* Powerdomain allowable state bitfields */
 #define PWRSTS_ON              (1 << PWRDM_POWER_ON)
+#define PWRSTS_OFF             (1 << PWRDM_POWER_OFF)
 #define PWRSTS_OFF_ON          ((1 << PWRDM_POWER_OFF) | \
                                 (1 << PWRDM_POWER_ON))
 
@@ -161,5 +162,6 @@ int pwrdm_state_switch(struct powerdomain *pwrdm);
 int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
 int pwrdm_pre_transition(void);
 int pwrdm_post_transition(void);
+int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
 
 #endif
index 9fbd91419cd15b2849460eed590165e47b820c2a..ab77442e42ab1649cb1b0363f4a95af46c9470f3 100644 (file)
@@ -38,6 +38,8 @@ u32 prm_read_mod_reg(s16 module, u16 idx);
 void prm_write_mod_reg(u32 val, s16 module, u16 idx);
 u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
 u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask);
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask);
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg);
 u32 cm_read_mod_reg(s16 module, u16 idx);
 void cm_write_mod_reg(u32 val, s16 module, u16 idx);
 u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
index 7b76f50564ba543c1626df470383c3b58c55afa9..efd87c8dda69bb0f9d5dd82bf1b473bac21e9459 100644 (file)
@@ -147,6 +147,7 @@ struct memory_timings {
 };
 
 extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
+struct omap_sdrc_params *rx51_get_sdram_timings(void);
 
 u32 omap2xxx_sdrc_dll_is_unlocked(void);
 u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);
index 16a1b458d53c9b54513205eaceaea0a96b90e972..5905100b29a1391078a9239e01c6d28b22f5f5be 100644 (file)
@@ -11,7 +11,6 @@
 #ifndef __ARCH_ARM_OMAP_SRAM_H
 #define __ARCH_ARM_OMAP_SRAM_H
 
-extern int __init omap_sram_init(void);
 extern void * omap_sram_push(void * start, unsigned long size);
 extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
 
diff --git a/arch/arm/plat-omap/include/plat/timer-gp.h b/arch/arm/plat-omap/include/plat/timer-gp.h
deleted file mode 100644 (file)
index c88d346..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * OMAP2/3 GPTIMER support.headers
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
-#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
-
-int __init omap2_gp_clockevent_set_gptimer(u8 id);
-
-#endif
-
index ddf723be48dc997c867226ec5838dd27fe55db05..9036e374e0ac3b32d7f27e484514d27a91d6a776 100644 (file)
@@ -139,10 +139,14 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
                DEBUG_LL_OMAP2(1, omap3evm);
                DEBUG_LL_OMAP3(1, omap_3430sdp);
                DEBUG_LL_OMAP3(1, omap_3630sdp);
+               DEBUG_LL_OMAP3(1, omap3530_lv_som);
+               DEBUG_LL_OMAP3(1, omap3_torpedo);
 
                /* omap3 based boards using UART3 */
                DEBUG_LL_OMAP3(3, cm_t35);
+               DEBUG_LL_OMAP3(3, cm_t3517);
                DEBUG_LL_OMAP3(3, igep0020);
+               DEBUG_LL_OMAP3(3, igep0030);
                DEBUG_LL_OMAP3(3, nokia_rx51);
                DEBUG_LL_OMAP3(3, omap3517evm);
                DEBUG_LL_OMAP3(3, omap3_beagle);
@@ -153,6 +157,7 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
 
                /* omap4 based boards using UART3 */
                DEBUG_LL_OMAP4(3, omap_4430sdp);
+               DEBUG_LL_OMAP4(3, omap4_panda);
 
                /* zoom2/3 external uart */
                DEBUG_LL_ZOOM(omap_zoom2);
index 9feddacfe8503268c8e92949cc22804bb87f0b6c..59c7fe731f28779944202463137234d000b997e2 100644 (file)
@@ -105,7 +105,7 @@ static inline void omap1_usb_init(struct omap_usb_config *pdata)
 #if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP_OTG_MODULE)
 void omap2_usbfs_init(struct omap_usb_config *pdata);
 #else
-static inline omap2_usbfs_init(struct omap_usb_config *pdata)
+static inline void omap2_usbfs_init(struct omap_usb_config *pdata)
 {
 }
 #endif
index d8a03ced3b108cbd78c494a364e9c98e1215ca50..3792bdea2f6dcbb0be40fe8de0387e49efaf1be7 100644 (file)
@@ -35,6 +35,7 @@ struct vrfb {
        bool yuv_mode;
 };
 
+#ifdef CONFIG_OMAP2_VRFB
 extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
 extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
 extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
@@ -47,4 +48,19 @@ extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
 extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
 extern void omap_vrfb_restore_context(void);
 
+#else
+static inline int omap_vrfb_request_ctx(struct vrfb *vrfb) { return 0; }
+static inline void omap_vrfb_release_ctx(struct vrfb *vrfb) {}
+static inline void omap_vrfb_adjust_size(u16 *width, u16 *height,
+               u8 bytespp) {}
+static inline u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
+               { return 0; }
+static inline u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
+               { return 0; }
+static inline void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
+               u16 width, u16 height, unsigned bytespp, bool yuv_mode) {}
+static inline int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
+               { return 0; }
+static inline void omap_vrfb_restore_context(void) {}
+#endif
 #endif /* __VRFB_H */
index 0c8612fd831237164968b1f2120a1134618557e3..eac4b978e9fd2feb4c692d8f10567b853ca53398 100644 (file)
@@ -33,7 +33,7 @@
 struct omap_mcbsp **mcbsp_ptr;
 int omap_mcbsp_count, omap_mcbsp_cache_size;
 
-void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 {
        if (cpu_class_is_omap1()) {
                ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val;
@@ -47,7 +47,7 @@ void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
        }
 }
 
-int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
+static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
 {
        if (cpu_class_is_omap1()) {
                return !from_cache ? __raw_readw(mcbsp->io_base + reg) :
@@ -62,12 +62,12 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
 }
 
 #ifdef CONFIG_ARCH_OMAP3
-void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 {
        __raw_writel(val, mcbsp->st_data->io_base_st + reg);
 }
 
-int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
 {
        return __raw_readl(mcbsp->st_data->io_base_st + reg);
 }
@@ -80,9 +80,6 @@ int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
 #define MCBSP_READ_CACHE(mcbsp, reg) \
                omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
 
-#define omap_mcbsp_check_valid_id(id)  (id < omap_mcbsp_count)
-#define id_to_mcbsp_ptr(id)            mcbsp_ptr[id];
-
 #define MCBSP_ST_READ(mcbsp, reg) \
                        omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
 #define MCBSP_ST_WRITE(mcbsp, reg, val) \
@@ -878,7 +875,7 @@ EXPORT_SYMBOL(omap_mcbsp_free);
 void omap_mcbsp_start(unsigned int id, int tx, int rx)
 {
        struct omap_mcbsp *mcbsp;
-       int idle;
+       int enable_srg = 0;
        u16 w;
 
        if (!omap_mcbsp_check_valid_id(id)) {
@@ -893,10 +890,13 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
        mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7;
        mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7;
 
-       idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-                       MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+       /* Only enable SRG, if McBSP is master */
+       w = MCBSP_READ_CACHE(mcbsp, PCR0);
+       if (w & (FSXM | FSRM | CLKXM | CLKRM))
+               enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+                               MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
 
-       if (idle) {
+       if (enable_srg) {
                /* Start the sample generator */
                w = MCBSP_READ_CACHE(mcbsp, SPCR2);
                MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
@@ -919,7 +919,7 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
         */
        udelay(500);
 
-       if (idle) {
+       if (enable_srg) {
                /* Start frame sync */
                w = MCBSP_READ_CACHE(mcbsp, SPCR2);
                MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
@@ -1645,7 +1645,7 @@ static const struct attribute_group sidetone_attr_group = {
        .attrs = (struct attribute **)sidetone_attrs,
 };
 
-int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
+static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
 {
        struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
        struct omap_mcbsp_st_data *st_data;
index d2b160942ccc5ec0a2e0fb2efe3e7e288da9cb12..abe933cd8f0926c99b059d2a214bda900e5326eb 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 
 #include <plat/omap_device.h>
 #include <plat/omap_hwmod.h>
 #define USE_WAKEUP_LAT                 0
 #define IGNORE_WAKEUP_LAT              1
 
-/*
- * OMAP_DEVICE_MAGIC: used to determine whether a struct omap_device
- * obtained via container_of() is in fact a struct omap_device
- */
-#define OMAP_DEVICE_MAGIC               0xf00dcafe
-
 /* Private functions */
 
 /**
@@ -243,6 +238,44 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
        return container_of(pdev, struct omap_device, pdev);
 }
 
+/**
+ * _add_optional_clock_alias - Add clock alias for hwmod optional clocks
+ * @od: struct omap_device *od
+ *
+ * For every optional clock present per hwmod per omap_device, this function
+ * adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role>
+ * if an entry is already present in it with the form <dev-id=NULL, con-id=role>
+ *
+ * The function is called from inside omap_device_build_ss(), after
+ * omap_device_register.
+ *
+ * This allows drivers to get a pointer to its optional clocks based on its role
+ * by calling clk_get(<dev*>, <role>).
+ *
+ * No return value.
+ */
+static void _add_optional_clock_alias(struct omap_device *od,
+                                     struct omap_hwmod *oh)
+{
+       int i;
+
+       for (i = 0; i < oh->opt_clks_cnt; i++) {
+               struct omap_hwmod_opt_clk *oc;
+               int r;
+
+               oc = &oh->opt_clks[i];
+
+               if (!oc->_clk)
+                       continue;
+
+               r = clk_add_alias(oc->role, dev_name(&od->pdev.dev),
+                                 (char *)oc->clk, &od->pdev.dev);
+               if (r)
+                       pr_err("omap_device: %s: clk_add_alias for %s failed\n",
+                              dev_name(&od->pdev.dev), oc->role);
+       }
+}
+
 
 /* Public functions for use by core code */
 
@@ -257,12 +290,11 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
  */
 int omap_device_count_resources(struct omap_device *od)
 {
-       struct omap_hwmod *oh;
        int c = 0;
        int i;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               c += omap_hwmod_count_resources(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               c += omap_hwmod_count_resources(od->hwmods[i]);
 
        pr_debug("omap_device: %s: counted %d total resources across %d "
                 "hwmods\n", od->pdev.name, c, od->hwmods_cnt);
@@ -289,12 +321,11 @@ int omap_device_count_resources(struct omap_device *od)
  */
 int omap_device_fill_resources(struct omap_device *od, struct resource *res)
 {
-       struct omap_hwmod *oh;
        int c = 0;
        int i, r;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++) {
-               r = omap_hwmod_fill_resources(oh, res);
+       for (i = 0; i < od->hwmods_cnt; i++) {
+               r = omap_hwmod_fill_resources(od->hwmods[i], res);
                res += r;
                c += r;
        }
@@ -414,15 +445,15 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
        od->pm_lats = pm_lats;
        od->pm_lats_cnt = pm_lats_cnt;
 
-       od->magic = OMAP_DEVICE_MAGIC;
-
        if (is_early_device)
                ret = omap_early_device_register(od);
        else
                ret = omap_device_register(od);
 
-       for (i = 0; i < oh_cnt; i++)
+       for (i = 0; i < oh_cnt; i++) {
                hwmods[i]->od = od;
+               _add_optional_clock_alias(od, hwmods[i]);
+       }
 
        if (ret)
                goto odbs_exit4;
@@ -473,6 +504,7 @@ int omap_device_register(struct omap_device *od)
 {
        pr_debug("omap_device: %s: registering\n", od->pdev.name);
 
+       od->pdev.dev.parent = &omap_device_parent;
        return platform_device_register(&od->pdev);
 }
 
@@ -566,7 +598,6 @@ int omap_device_shutdown(struct platform_device *pdev)
 {
        int ret, i;
        struct omap_device *od;
-       struct omap_hwmod *oh;
 
        od = _find_by_pdev(pdev);
 
@@ -579,8 +610,8 @@ int omap_device_shutdown(struct platform_device *pdev)
 
        ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               omap_hwmod_shutdown(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               omap_hwmod_shutdown(od->hwmods[i]);
 
        od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
 
@@ -626,18 +657,6 @@ int omap_device_align_pm_lat(struct platform_device *pdev,
        return ret;
 }
 
-/**
- * omap_device_is_valid - Check if pointer is a valid omap_device
- * @od: struct omap_device *
- *
- * Return whether struct omap_device pointer @od points to a valid
- * omap_device.
- */
-bool omap_device_is_valid(struct omap_device *od)
-{
-       return (od && od->magic == OMAP_DEVICE_MAGIC);
-}
-
 /**
  * omap_device_get_pwrdm - return the powerdomain * associated with @od
  * @od: struct omap_device *
@@ -692,11 +711,10 @@ void __iomem *omap_device_get_rt_va(struct omap_device *od)
  */
 int omap_device_enable_hwmods(struct omap_device *od)
 {
-       struct omap_hwmod *oh;
        int i;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               omap_hwmod_enable(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               omap_hwmod_enable(od->hwmods[i]);
 
        /* XXX pass along return value here? */
        return 0;
@@ -710,11 +728,10 @@ int omap_device_enable_hwmods(struct omap_device *od)
  */
 int omap_device_idle_hwmods(struct omap_device *od)
 {
-       struct omap_hwmod *oh;
        int i;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               omap_hwmod_idle(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               omap_hwmod_idle(od->hwmods[i]);
 
        /* XXX pass along return value here? */
        return 0;
@@ -729,11 +746,10 @@ int omap_device_idle_hwmods(struct omap_device *od)
  */
 int omap_device_disable_clocks(struct omap_device *od)
 {
-       struct omap_hwmod *oh;
        int i;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               omap_hwmod_disable_clocks(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               omap_hwmod_disable_clocks(od->hwmods[i]);
 
        /* XXX pass along return value here? */
        return 0;
@@ -748,12 +764,22 @@ int omap_device_disable_clocks(struct omap_device *od)
  */
 int omap_device_enable_clocks(struct omap_device *od)
 {
-       struct omap_hwmod *oh;
        int i;
 
-       for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-               omap_hwmod_enable_clocks(oh);
+       for (i = 0; i < od->hwmods_cnt; i++)
+               omap_hwmod_enable_clocks(od->hwmods[i]);
 
        /* XXX pass along return value here? */
        return 0;
 }
+
+struct device omap_device_parent = {
+       .init_name      = "omap",
+       .parent         = &platform_bus,
+};
+
+static int __init omap_device_init(void)
+{
+       return device_register(&omap_device_parent);
+}
+core_initcall(omap_device_init);
index 10b3b4c63372f406e6ee206ce691977753017e56..e2c8eebe6b3a54a1ab7c0a9ffa25f280117ceb04 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/omapfb.h>
 
 #include <asm/tlb.h>
 #include <asm/cacheflush.h>
@@ -30,8 +31,8 @@
 #include <plat/cpu.h>
 #include <plat/vram.h>
 
-#include <plat/control.h>
-
+#include "sram.h"
+#include "fb.h"
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 # include "../mach-omap2/prm.h"
 # include "../mach-omap2/cm.h"
@@ -53,7 +54,7 @@
 #define OMAP4_SRAM_PUB_PA      (OMAP4_SRAM_PA + 0x4000)
 #define OMAP4_SRAM_PUB_VA      (OMAP4_SRAM_VA + 0x4000)
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2PLUS)
 #define SRAM_BOOTLOADER_SZ     0x00
 #else
 #define SRAM_BOOTLOADER_SZ     0x80
@@ -68,7 +69,6 @@
 #define OMAP34XX_VA_WRITEPERM0         OMAP2_L3_IO_ADDRESS(0x68012858)
 #define OMAP34XX_VA_ADDR_MATCH2                OMAP2_L3_IO_ADDRESS(0x68012880)
 #define OMAP34XX_VA_SMS_RG_ATT0                OMAP2_L3_IO_ADDRESS(0x6C000048)
-#define OMAP34XX_VA_CONTROL_STAT       OMAP2_L4_IO_ADDRESS(0x480022F0)
 
 #define GP_DEVICE              0x300
 
@@ -79,12 +79,6 @@ static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
-                                        unsigned long sram_vstart,
-                                        unsigned long sram_size,
-                                        unsigned long pstart_avail,
-                                        unsigned long size_avail);
-
 /*
  * Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessible size for all device types is 2k. A GP
@@ -93,16 +87,7 @@ extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
  */
 static int is_sram_locked(void)
 {
-       int type = 0;
-
-       if (cpu_is_omap44xx())
-               /* Not yet supported */
-               return 0;
-
-       if (cpu_is_omap242x())
-               type = omap_rev() & OMAP2_DEVICETYPE_MASK;
-
-       if (type == GP_DEVICE) {
+       if (OMAP2_DEVICE_TYPE_GP == omap_type()) {
                /* RAMFW: R/W access to all initiators for all qualifier sets */
                if (cpu_is_omap242x()) {
                        __raw_writel(0xFF, OMAP24XX_VA_REQINFOPERM0); /* all q-vects */
@@ -127,7 +112,7 @@ static int is_sram_locked(void)
  * to secure SRAM will hang the system. Also the SRAM is not
  * yet mapped at this point.
  */
-void __init omap_detect_sram(void)
+static void __init omap_detect_sram(void)
 {
        unsigned long reserved;
 
@@ -213,7 +198,7 @@ static struct map_desc omap_sram_io_desc[] __initdata = {
 /*
  * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
  */
-void __init omap_map_sram(void)
+static void __init omap_map_sram(void)
 {
        unsigned long base;
 
@@ -330,7 +315,7 @@ u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2420
-int __init omap242x_sram_init(void)
+static int __init omap242x_sram_init(void)
 {
        _omap2_sram_ddr_init = omap_sram_push(omap242x_sram_ddr_init,
                                        omap242x_sram_ddr_init_sz);
@@ -351,7 +336,7 @@ static inline int omap242x_sram_init(void)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2430
-int __init omap243x_sram_init(void)
+static int __init omap243x_sram_init(void)
 {
        _omap2_sram_ddr_init = omap_sram_push(omap243x_sram_ddr_init,
                                        omap243x_sram_ddr_init_sz);
@@ -407,7 +392,7 @@ void omap3_sram_restore_context(void)
 }
 #endif /* CONFIG_PM */
 
-int __init omap34xx_sram_init(void)
+static int __init omap34xx_sram_init(void)
 {
        _omap3_sram_configure_core_dpll =
                omap_sram_push(omap3_sram_configure_core_dpll,
@@ -423,7 +408,7 @@ static inline int omap34xx_sram_init(void)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
-int __init omap44xx_sram_init(void)
+static int __init omap44xx_sram_init(void)
 {
        printk(KERN_ERR "FIXME: %s not implemented\n", __func__);
 
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h
new file mode 100644 (file)
index 0000000..29b43ef
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __PLAT_OMAP_SRAM_H__
+#define __PLAT_OMAP_SRAM_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /* __PLAT_OMAP_SRAM_H__ */
index 452e18438b41b21546e5ae52c7b0b25e74078032..2f91057a0c02380841db092f087ea9f6731efca6 100644 (file)
@@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 
 struct platform_device s3c_device_iis = {
-       .name             = "s3c2410-iis",
+       .name             = "s3c24xx-iis",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_iis_resource),
        .resource         = s3c_iis_resource,
@@ -259,6 +259,21 @@ struct platform_device s3c_device_iis = {
 
 EXPORT_SYMBOL(s3c_device_iis);
 
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+       .name             = "s3c24xx-pcm-audio",
+       .id               = -1,
+       .dev              = {
+               .dma_mask = &s3c_device_audio_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
 /* RTC */
 
 static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
        },
 };
 
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
 struct platform_device s3c_device_ac97 = {
        .name             = "s3c-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_ac97_resource),
        .resource         = s3c_ac97_resource,
        .dev              = {
-               .dma_mask = &s3c_device_ac97_dmamask,
+               .dma_mask = &s3c_device_audio_dmamask,
                .coherent_dma_mask = 0xffffffffUL
        }
 };
 
 EXPORT_SYMBOL(s3c_device_ac97);
 
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+       .name             = "s3c2412-iis",
+       .id               = -1,
+       .dev              = {
+               .dma_mask = &s3c_device_audio_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
 #endif // CONFIG_CPU_S32440
index 7d448e13879241c8a62da6f26604ea00ecc1a3d1..c8b94279bad101037553659e73a4886aa44148bb 100644 (file)
@@ -32,6 +32,8 @@ extern struct platform_device s3c64xx_device_iisv4;
 extern struct platform_device s3c64xx_device_spi0;
 extern struct platform_device s3c64xx_device_spi1;
 
+extern struct platform_device s3c_device_pcm;
+
 extern struct platform_device s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm1;
 
index a9ae30c41e746d53e25281d3c8132c5aeba9f09d..6fbfea61f7bb7315d7c19f15db0df6ae8f8bd697 100644 (file)
@@ -319,9 +319,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_offset_kernel(dir, address)                                        \
        ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte)         do { } while (0)
-#define pte_unmap_nested(pte)  do { } while (0)
 
 struct vm_area_struct;
 extern void update_mmu_cache(struct vm_area_struct * vma,
index d1825cb247685dacb6175f58829bec48edb6c03f..acb83799a215f89ce870493ab90976ea79cadf46 100644 (file)
@@ -102,17 +102,6 @@ config DEBUG_DOUBLEFAULT_RESET
 
 endchoice
 
-config DEBUG_ICACHE_CHECK
-       bool "Check Instruction cache coherency"
-       depends on DEBUG_KERNEL
-       depends on DEBUG_HWERR
-       help
-         Say Y here if you are getting weird unexplained errors. This will
-         ensure that icache is what SDRAM says it should be by doing a
-         byte wise comparison between SDRAM and instruction cache. This
-         also relocates the irq_panic() function to L1 memory, (which is
-         un-cached).
-
 config DEBUG_HUNT_FOR_ZERO
        bool "Catch NULL pointer reads/writes"
        default y
index 46fac1bf0605cbab71f2629e24c011bc9f50a596..c0b988ee30df44a33127a3cd33bf8204f237bf9d 100644 (file)
@@ -35,6 +35,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -114,7 +115,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 80240806cf9ea76a34b4804969c5f4fab12f88b2..864af5b68874387e088b612a86a3121351ded238 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -152,7 +153,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 08c55f6b8b7a1c0e814597792733bae0bab6da3f..7b6a3370dbe23d573eb6080d3e815fb21530e747 100644 (file)
@@ -9,6 +9,7 @@ CONFIG_EMBEDDED=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_AIO is not set
 CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -101,5 +102,4 @@ CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
index 4a9125558fcf13b80480bcb9a00ebcf615effe75..4faa6b46a352d665a266f57f83d1fb226fa7e83f 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF527=y
 CONFIG_BF_REV_0_2=y
@@ -38,6 +39,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -181,6 +183,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 8ccf3cec75342f0a91cc0c46dee49cbede118bd1..9d893eb68243d28cad56767b8e6733efd35a69fa 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF527=y
 CONFIG_BF_REV_0_1=y
@@ -37,6 +38,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -173,6 +175,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 92ded5edc86c6fee819e657232f8814c1f85e300..97a2767c80f8ea8239eb987409133b9e345ba97f 100644 (file)
@@ -174,7 +174,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC7=m
index c40e0f1c7eac3d9e9a283d40335c514f1f023af4..f84774360c5bb17316a99365930eaf0df275a0c0 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BFIN533_EZKIT=y
 CONFIG_TIMER0=11
@@ -107,6 +108,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index aa8c1d7453bac30558c045806ae51dabc7face5a..0e7262c04cc2fe5ccf567d92826239d6304b1949 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_TIMER0=11
 CONFIG_HIGH_RES_TIMERS=y
@@ -121,6 +122,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index f245c0b427e4574c5bc4eeda8879fb1122df6010..4d14a002e7bd721d146ee0e18a5a94733b317a2b 100644 (file)
@@ -20,9 +20,9 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF537=y
-CONFIG_IRQ_ERROR=11
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
 CONFIG_BFIN_GPTIMERS=m
@@ -133,6 +133,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 74a330cca9b424d61d4a9866e900b1be850e74f0..fbee9d776f564b46aaca9ccb2337afca07b18c19 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF538=y
 CONFIG_IRQ_TIMER0=12
@@ -31,6 +32,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -129,6 +131,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 29373cbba2274bbc96dad61f4ad2f66a38c051c7..05dd11db2f7d6b4809db3198b3d033833fbff992 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_EBIU_MODEVAL=0x1
 CONFIG_EBIU_FCTLVAL=0x6
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -62,7 +63,7 @@ CONFIG_IRCOMM=m
 CONFIG_IRTTY_SIR=m
 CONFIG_BFIN_SIR=m
 CONFIG_BFIN_SIR3=y
-CONFIG_LIB80211=m
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
@@ -92,6 +93,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
index 1f12034f56106eff9767943b3e55d5f88aba9b42..bcb14d1c56647639bca47adff02bce380c341038 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_EMBEDDED=y
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
@@ -44,6 +45,7 @@ CONFIG_IP_PNP=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -71,6 +73,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -147,5 +150,4 @@ CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 8913d997fa47b63c9074e2ba3d932cae32d805bc..843aaa54a9e3c241a510d3934575ac180a5a8e84 100644 (file)
@@ -35,6 +35,7 @@ CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 0242917b69c988ac4a69b89509033009ce0c3e32..dae7adf3b2a2ae731d003e0a049eacbc7cd61af4 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_INET=y
 CONFIG_IP_PNP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -63,6 +64,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
@@ -104,5 +106,4 @@ CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
index 0512fef3d55a3c41c96a964cc824c404be4cfa8c..f3414244bfed479a6ef5a000bedaeae42d60a1ab 100644 (file)
@@ -50,6 +50,7 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -70,9 +71,9 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_BFIN_MAC=y
-CONFIG_BFIN_MAC_RMII=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -124,7 +125,6 @@ CONFIG_DEBUG_FS=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 05e09be8b4c5642e2eaccab7229b906792492bc8..8c7e08f173d446084a28d1084193f772d5d873ee 100644 (file)
@@ -33,6 +33,7 @@ CONFIG_BINFMT_SHARED_FLAT=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -47,6 +48,7 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -72,7 +74,6 @@ CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=y
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
index d2eb5325b9c3d7d04f5286381a023f0492e3c53d..bd3cb766d07803e0ebd6b0af2c2c26d7459c8b48 100644 (file)
@@ -48,6 +48,7 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -65,6 +66,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_BFIN_MAC=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -99,7 +101,6 @@ CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 9d52c443eb099b1cad8cacb45483f04e376fd1ab..82224f37c04e4d49a5ee4728b58b4ef505681a3f 100644 (file)
@@ -44,6 +44,7 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -59,6 +60,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -90,7 +92,6 @@ CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
index 9de13cf2cddae7c4aa5bd56a1faade4aeb096103..433598c6e7736d7b7ede1eaf19dd4c768238c987 100644 (file)
@@ -49,6 +49,7 @@ CONFIG_INET_XFRM_MODE_BEET=m
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -71,6 +72,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 CONFIG_INPUT_EVBUG=m
@@ -167,7 +169,6 @@ CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=m
index 238353a53bf03b5311e3987ba5bb3a731d699981..ded7d845cb399aa3bd1feaff7119c960497a4ba3 100644 (file)
@@ -48,6 +48,7 @@ CONFIG_INET=y
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -67,6 +68,7 @@ CONFIG_MII=y
 CONFIG_SMSC911X=m
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -99,7 +101,6 @@ CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
index 0cb524e8947f0ce2fef6e6d45a5d101a0fa3d2c3..700fb701c121affa69c937ae5376df45ff60808e 100644 (file)
@@ -33,6 +33,7 @@ CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -50,6 +51,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -84,4 +86,3 @@ CONFIG_NFS_V3=y
 CONFIG_NLS=m
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
index 2a3411ef19fd7966d0ce800fd131fd3f568a5771..b40156d217e376ff5a1584a6f36f0fef9f3f6373 100644 (file)
@@ -41,6 +41,7 @@ CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
 CONFIG_IP_NF_MANGLE=y
+# CONFIG_WIRELESS is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
@@ -60,6 +61,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -89,5 +91,4 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=y
index fea303386548f8b10c3b8c9ae43a921fbc7f99d7..be866d95ed760a3054de1de9889566e69fd2a442 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF537=y
 CONFIG_IRQ_TIMER0=12
@@ -107,7 +108,6 @@ CONFIG_SMB_FS=m
 # CONFIG_DEBUG_HUNT_FOR_ZERO is not set
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 # CONFIG_ACCESS_CHECK is not set
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 9811b31868475da1b64ece65e5266b9c1ae7198b..b64bdf759b82c19fdb5fdcebde86b836d3377d2f 100644 (file)
@@ -35,6 +35,7 @@ CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -51,6 +52,7 @@ CONFIG_EEPROM_AT25=m
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
@@ -85,4 +87,3 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
index 412bf79b9724bcf056cefe8722d9cb273f002344..1bccd9a50986e2f359d1151e673df809194b6794 100644 (file)
@@ -128,7 +128,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 04bf52c4cf124db378bb4cde7502fdc76ba33afc..00ce899e9e5d367b947164dc91e3c2815051a116 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -57,6 +58,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_BFIN_MAC=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
index 0b5136e334b599c382fc6bbe2f7245e8abe128aa..5392583d02531fc2e3d2feb20127bf730e575610 100644 (file)
@@ -60,6 +60,8 @@ struct bfin_spi_regs {
        __BFP(shadow);
 };
 
+#undef __BFP
+
 #define MAX_CTRL_CS          8  /* cs in spi controller */
 
 /* device.platform_data for SSP controller devices */
index 003900886f972cebf19dfc1bb9a47f408343106f..3be05faa2c65ad14fa73dcf8ef44f85da4cc97cd 100644 (file)
@@ -48,4 +48,6 @@ struct bfin_eppi_regs {
        u32 clip;
 };
 
+#undef __BFP
+
 #endif
diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h
new file mode 100644 (file)
index 0000000..e767d64
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * bfin_twi.h - interface to Blackfin TWIs
+ *
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_TWI_H__
+#define __ASM_BFIN_TWI_H__
+
+#include <linux/types.h>
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin twi registers layout
+ */
+struct bfin_twi_regs {
+       __BFP(clkdiv);
+       __BFP(control);
+       __BFP(slave_ctl);
+       __BFP(slave_stat);
+       __BFP(slave_addr);
+       __BFP(master_ctl);
+       __BFP(master_stat);
+       __BFP(master_addr);
+       __BFP(int_stat);
+       __BFP(int_mask);
+       __BFP(fifo_ctl);
+       __BFP(fifo_stat);
+       u32 __pad[20];
+       __BFP(xmt_data8);
+       __BFP(xmt_data16);
+       __BFP(rcv_data8);
+       __BFP(rcv_data16);
+};
+
+#undef __BFP
+
+#endif
index a1f6817687e8fc13388e6223159eb8e7b400009a..59af63c0c2bea9122959ee8061d74489932dbaec 100644 (file)
 #define bfin_write_ITEST_DATA0(val)          bfin_write32(ITEST_DATA0,val)
 #define bfin_write_ITEST_DATA1(val)          bfin_write32(ITEST_DATA1,val)
 
-#if ANOMALY_05000481
+#if !ANOMALY_05000481
 #define bfin_read_ITEST_COMMAND()            bfin_read32(ITEST_COMMAND)
 #define bfin_read_ITEST_DATA0()              bfin_read32(ITEST_DATA0)
 #define bfin_read_ITEST_DATA1()              bfin_read32(ITEST_DATA1)
index a6886f6e48194027f529a0380feb618eb1f2abcd..4104d5783e2c1a4ad80b633f123e7c1dc219c459 100644 (file)
 #define        LFLUSH_I_AND_D  0x00000808
 #define        LSIGTRAP        5
 
-/* process bits for task_struct.flags */
-#define        PF_TRACESYS_OFF 3
-#define        PF_TRACESYS_BIT 5
-#define        PF_PTRACED_OFF  3
-#define        PF_PTRACED_BIT  4
-#define        PF_DTRACE_OFF   1
-#define        PF_DTRACE_BIT   5
-
 /*
  * NOTE!  The single-stepping code assumes that all interrupt handlers
  * start by saving SYSCFG on the stack with their first instruction.
index f95e6096719b61de64c4eba04bfaa57de5d9f3a1..b894c8abe7ecaa8734a1fca6e8d643054bd9dfab 100644 (file)
@@ -87,13 +87,55 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = {
+       P_MII0_ETxD0,
+       P_MII0_ETxD1,
+       P_MII0_ETxEN,
+       P_MII0_ERxD0,
+       P_MII0_ERxD1,
+       P_MII0_TxCLK,
+       P_MII0_PHYINT,
+       P_MII0_CRS,
+       P_MII0_MDC,
+       P_MII0_MDIO,
+       0
+};
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+       {
+               .addr = 2,
+               .irq = IRQ_MAC_PHYINT,
+       },
+       {
+               .addr = 3,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 3,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 
 #if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
index bead810a6546d1172270a5988e7494788246a3fa..e6ce1d7c523a4ef6d222f88e9646645ea44f9446 100644 (file)
@@ -81,13 +81,35 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 38037c7e125a7554edb588b11359f6390c2eabe2..2c31af7a320a7bd767749fc06f974db27db8c281 100644 (file)
@@ -273,13 +273,35 @@ static struct platform_device dm9000_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_RMII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 6cc64a1e78b963009df363e3254703a909d0d019..9a736a850c5c64cc76807ccbf7f3e33076773fca 100644 (file)
@@ -193,13 +193,35 @@ static struct platform_device rtc_device = {
 
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_RMII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index df82723fb504fa221df05b18f56ca5e1200aee12..9222bc00bbd3bce1ce5706b17564d1bd6e6f84d3 100644 (file)
@@ -366,13 +366,35 @@ static struct platform_device dm9000_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_RMII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index ae4130e97c01a3cb90ef626001bb93fe71b908e9..9ec575729e2c4f00d726cc1e96889d7225898165 100644 (file)
@@ -257,13 +257,35 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_RMII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index e2e7be40ef44cca5c6c160c48ca38e64f80aa74b..836698c4ee54fc70cbe12fb8cdc2b899888f3036 100644 (file)
@@ -597,13 +597,35 @@ static struct platform_device bfin_sport1_uart_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 752c833f7ca8f93bd195565ec2e45f8c71e210e5..2a85670273cb977e4c34b8dfab93c62981a4543a 100644 (file)
@@ -562,13 +562,35 @@ static struct platform_device bfin_sport1_uart_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 05d45994480eaf8b2dae60ae59aeb439b2ebb05b..49800518412c44dc07ef9e9f7a7f26032f3d87e3 100644 (file)
@@ -68,13 +68,35 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 6b03808800a6bc36ea5d974f1ec9800efb4084ae..b95807894e256bfab6a22ef0e39eb59747b096ba 100644 (file)
@@ -99,13 +99,35 @@ static struct platform_device smc91x_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_RMII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index cd2c797c8c9f24b4fa291b52ee87e665f7f9ca32..3aa344ce8e5252d2cf14d0c75a3c75b2509a31f1 100644 (file)
@@ -327,13 +327,35 @@ static struct platform_device bfin_can_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = PHY_POLL, /* IRQ_MAC_PHYINT */
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index a4d62b5fc7ba11390e358665b06d65bea854e4e2..31498add1a42ebd3af3842136e523ea2b70ce0e2 100644 (file)
@@ -564,13 +564,35 @@ static struct platform_device bfin_sport1_uart_device = {
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+       {
+               .addr = 1,
+               .irq = IRQ_MAC_PHYINT,
+       },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+       .phydev_number = 1,
+       .phydev_data = bfin_phydev_data,
+       .phy_mode = PHY_INTERFACE_MODE_MII,
+       .mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
+       .dev = {
+               .platform_data = &bfin_mii_bus_data,
+       }
 };
 
 static struct platform_device bfin_mac_device = {
        .name = "bfin_mac",
-       .dev.platform_data = &bfin_mii_bus,
+       .dev = {
+               .platform_data = &bfin_mii_bus,
+       }
 };
 #endif
 
index 814cb483853bba6ea743285e65bbcabb161dd554..ff299f24aba0703fe8751004de6ed7345ee8777a 100644 (file)
@@ -11,4 +11,3 @@ obj-$(CONFIG_CPU_FREQ)    += cpufreq.o
 obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
 obj-$(CONFIG_SMP)         += smp.o
 obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
-obj-$(CONFIG_DEBUG_ICACHE_CHECK) += irqpanic.o
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
deleted file mode 100644 (file)
index c649624..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * panic kernel with dump information
- *
- * Copyright 2005-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <asm/blackfin.h>
-
-#define L1_ICACHE_START 0xffa10000
-#define L1_ICACHE_END   0xffa13fff
-
-/*
- * irq_panic - calls panic with string setup
- */
-__attribute__ ((l1_text))
-asmlinkage void irq_panic(int reason, struct pt_regs *regs)
-{
-       unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
-       unsigned short i, j, die;
-       unsigned int bad[10][6];
-
-       /* check entire cache for coherency
-        * Since printk is in cacheable memory,
-        * don't call it until you have checked everything
-       */
-
-       die = 0;
-       i = 0;
-
-       /* check icache */
-
-       for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
-
-               /* Grab various address bits for the itest_cmd fields                      */
-               cmd = (((ca & 0x3000) << 4) |   /* ca[13:12] for SBNK[1:0]             */
-                      ((ca & 0x0c00) << 16) |  /* ca[11:10] for WAYSEL[1:0]           */
-                      ((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0]  */
-                      0);      /* Access Tag, Read access             */
-
-               SSYNC();
-               bfin_write_ITEST_COMMAND(cmd);
-               SSYNC();
-               tag = bfin_read_ITEST_DATA0();
-               SSYNC();
-
-               /* if tag is marked as valid, check it */
-               if (tag & 1) {
-                       /* The icache is arranged in 4 groups of 64-bits */
-                       for (j = 0; j < 32; j += 8) {
-                               cmd = ((((ca + j) & 0x3000) << 4) |     /* ca[13:12] for SBNK[1:0]             */
-                                      (((ca + j) & 0x0c00) << 16) |    /* ca[11:10] for WAYSEL[1:0]           */
-                                      (((ca + j) & 0x3f8)) |   /* ca[09:03] for SET[4:0] and DW[1:0]  */
-                                      4);      /* Access Data, Read access             */
-
-                               SSYNC();
-                               bfin_write_ITEST_COMMAND(cmd);
-                               SSYNC();
-
-                               cache_hi = bfin_read_ITEST_DATA1();
-                               cache_lo = bfin_read_ITEST_DATA0();
-
-                               pa = ((unsigned int *)((tag & 0xffffcc00) |
-                                                      ((ca + j) & ~(0xffffcc00))));
-
-                               /*
-                                * Debugging this, enable
-                                *
-                                * printk("addr: %08x %08x%08x | %08x%08x\n",
-                                *  ((unsigned int *)((tag & 0xffffcc00)  | ((ca+j) & ~(0xffffcc00)))),
-                                *   cache_hi, cache_lo, *(pa+1), *pa);
-                                */
-
-                               if (cache_hi != *(pa + 1) || cache_lo != *pa) {
-                                       /* Since icache is not working, stay out of it, by not printing */
-                                       die = 1;
-                                       bad[i][0] = (ca + j);
-                                       bad[i][1] = cache_hi;
-                                       bad[i][2] = cache_lo;
-                                       bad[i][3] = ((tag & 0xffffcc00) |
-                                               ((ca + j) & ~(0xffffcc00)));
-                                       bad[i][4] = *(pa + 1);
-                                       bad[i][5] = *(pa);
-                                       i++;
-                               }
-                       }
-               }
-       }
-       if (die) {
-               printk(KERN_EMERG "icache coherency error\n");
-               for (j = 0; j <= i; j++) {
-                       printk(KERN_EMERG
-                           "cache address   : %08x  cache value : %08x%08x\n",
-                            bad[j][0], bad[j][1], bad[j][2]);
-                       printk(KERN_EMERG
-                           "physical address: %08x  SDRAM value : %08x%08x\n",
-                            bad[j][3], bad[j][4], bad[j][5]);
-               }
-               panic("icache coherency error");
-       } else
-               printk(KERN_EMERG "icache checked, and OK\n");
-}
index f63d6fccbc6caf18906fa06c99d72e44e3b17792..9eaae217b21b755298809150cca419904bd5c944 100644 (file)
@@ -248,10 +248,8 @@ static inline pgd_t * pgd_offset(const struct mm_struct *mm, unsigned long addre
        ((pte_t *) pmd_page_vaddr(*(dir)) +  __pte_offset(address))
 #define pte_offset_map(dir, address) \
        ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #define pte_pfn(x)             ((unsigned long)(__va((x).pte)) >> PAGE_SHIFT)
 #define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
index cb4c317eaecc8db55074398fa8d593a2f37a9da3..a8d6565d415d611a030d658a8ce2270be0f8eff6 100644 (file)
@@ -112,12 +112,11 @@ extern struct page *kmap_atomic_to_page(void *ptr);
        (void *) damlr;                                                                           \
 })
 
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic_primary(struct page *page, enum km_type type)
 {
        unsigned long paddr;
 
        pagefault_disable();
-       debug_kmap_atomic(type);
        paddr = page_to_phys(page);
 
        switch (type) {
@@ -125,14 +124,6 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
         case 1:                return __kmap_atomic_primary(1, paddr, 3);
         case 2:                return __kmap_atomic_primary(2, paddr, 4);
         case 3:                return __kmap_atomic_primary(3, paddr, 5);
-        case 4:                return __kmap_atomic_primary(4, paddr, 6);
-        case 5:                return __kmap_atomic_primary(5, paddr, 7);
-        case 6:                return __kmap_atomic_primary(6, paddr, 8);
-        case 7:                return __kmap_atomic_primary(7, paddr, 9);
-        case 8:                return __kmap_atomic_primary(8, paddr, 10);
-
-       case 9 ... 9 + NR_TLB_LINES - 1:
-               return __kmap_atomic_secondary(type - 9, paddr);
 
        default:
                BUG();
@@ -152,22 +143,13 @@ do {                                                                      \
        asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory");   \
 } while(0)
 
-static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+static inline void kunmap_atomic_primary(void *kvaddr, enum km_type type)
 {
        switch (type) {
         case 0:                __kunmap_atomic_primary(0, 2);  break;
         case 1:                __kunmap_atomic_primary(1, 3);  break;
         case 2:                __kunmap_atomic_primary(2, 4);  break;
         case 3:                __kunmap_atomic_primary(3, 5);  break;
-        case 4:                __kunmap_atomic_primary(4, 6);  break;
-        case 5:                __kunmap_atomic_primary(5, 7);  break;
-        case 6:                __kunmap_atomic_primary(6, 8);  break;
-        case 7:                __kunmap_atomic_primary(7, 9);  break;
-        case 8:                __kunmap_atomic_primary(8, 10); break;
-
-       case 9 ... 9 + NR_TLB_LINES - 1:
-               __kunmap_atomic_secondary(type - 9, kvaddr);
-               break;
 
        default:
                BUG();
@@ -175,6 +157,9 @@ static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
        pagefault_enable();
 }
 
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index c18b0d32e63655ed7dc7d26b5ce0c44c5f990c36..6bc241e4b4f8212b386758586693d58e32e3a426 100644 (file)
@@ -451,17 +451,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
-       ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
-#define pte_offset_map_nested(dir, address) \
-       ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+       ((pte_t *)kmap_atomic(pmd_page(*(dir))) + pte_index(address))
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) \
        ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /*
index 85d110b71cf735166a31d3d2872e46fc597bbc6d..41098a3803a22db4fa787d4ab5129dfe1da8456d 100644 (file)
@@ -61,14 +61,14 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        dampr2 = __get_DAMPR(2);
 
        for (i = 0; i < nents; i++) {
-               vaddr = kmap_atomic(sg_page(&sg[i]), __KM_CACHE);
+               vaddr = kmap_atomic_primary(sg_page(&sg[i]), __KM_CACHE);
 
                frv_dcache_writeback((unsigned long) vaddr,
                                     (unsigned long) vaddr + PAGE_SIZE);
 
        }
 
-       kunmap_atomic(vaddr, __KM_CACHE);
+       kunmap_atomic_primary(vaddr, __KM_CACHE);
        if (dampr2) {
                __set_DAMPR(2, dampr2);
                __set_IAMPR(2, dampr2);
index 0261cbe153b5ecf4ff427a6a4d806b280a6a3930..b24ade27a0f09210002916bf0c164aed73777abc 100644 (file)
@@ -26,11 +26,11 @@ void flush_dcache_page(struct page *page)
 
        dampr2 = __get_DAMPR(2);
 
-       vaddr = kmap_atomic(page, __KM_CACHE);
+       vaddr = kmap_atomic_primary(page, __KM_CACHE);
 
        frv_dcache_writeback((unsigned long) vaddr, (unsigned long) vaddr + PAGE_SIZE);
 
-       kunmap_atomic(vaddr, __KM_CACHE);
+       kunmap_atomic_primary(vaddr, __KM_CACHE);
 
        if (dampr2) {
                __set_DAMPR(2, dampr2);
@@ -54,12 +54,12 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
 
        dampr2 = __get_DAMPR(2);
 
-       vaddr = kmap_atomic(page, __KM_CACHE);
+       vaddr = kmap_atomic_primary(page, __KM_CACHE);
 
        start = (start & ~PAGE_MASK) | (unsigned long) vaddr;
        frv_cache_wback_inv(start, start + len);
 
-       kunmap_atomic(vaddr, __KM_CACHE);
+       kunmap_atomic_primary(vaddr, __KM_CACHE);
 
        if (dampr2) {
                __set_DAMPR(2, dampr2);
index eadd07658075c3bc942ead2ee3d4d77f0b0803ec..61088dcc159432ad6063d60aee452d7866a2ef4f 100644 (file)
@@ -36,3 +36,53 @@ struct page *kmap_atomic_to_page(void *ptr)
 {
        return virt_to_page(ptr);
 }
+
+void *__kmap_atomic(struct page *page)
+{
+       unsigned long paddr;
+       int type;
+
+       pagefault_disable();
+       type = kmap_atomic_idx_push();
+       paddr = page_to_phys(page);
+
+       switch (type) {
+       /*
+        * The first 4 primary maps are reserved for architecture code
+        */
+       case 0:         return __kmap_atomic_primary(4, paddr, 6);
+       case 1:         return __kmap_atomic_primary(5, paddr, 7);
+       case 2:         return __kmap_atomic_primary(6, paddr, 8);
+       case 3:         return __kmap_atomic_primary(7, paddr, 9);
+       case 4:         return __kmap_atomic_primary(8, paddr, 10);
+
+       case 5 ... 5 + NR_TLB_LINES - 1:
+               return __kmap_atomic_secondary(type - 5, paddr);
+
+       default:
+               BUG();
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(__kmap_atomic);
+
+void __kunmap_atomic(void *kvaddr)
+{
+       int type = kmap_atomic_idx_pop();
+       switch (type) {
+       case 0:         __kunmap_atomic_primary(4, 6);  break;
+       case 1:         __kunmap_atomic_primary(5, 7);  break;
+       case 2:         __kunmap_atomic_primary(6, 8);  break;
+       case 3:         __kunmap_atomic_primary(7, 9);  break;
+       case 4:         __kunmap_atomic_primary(8, 10); break;
+
+       case 5 ... 5 + NR_TLB_LINES - 1:
+               __kunmap_atomic_secondary(type - 5, kvaddr);
+               break;
+
+       default:
+               BUG();
+       }
+       pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
index c3286f42e501477722bdec7373112e92efc8a40d..1a97af31ef176e71d8138250c03c52b7ab0adf3f 100644 (file)
@@ -406,9 +406,7 @@ pgd_offset (const struct mm_struct *mm, unsigned long address)
 #define pte_index(addr)                (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir,addr)    ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir,addr)       pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr)        pte_offset_map(dir, addr)
 #define pte_unmap(pte)                 do { } while (0)
-#define pte_unmap_nested(pte)          do { } while (0)
 
 /* atomic versions of the some PTE manipulations: */
 
index 118d4297900319df2d97840fc7149cce0ad8610c..c8fcaa2ac48f88f13bd93e1d25fd3fd5d2031c6a 100644 (file)
@@ -62,6 +62,7 @@ typedef struct siginfo {
                        int _imm;               /* immediate value for "break" */
                        unsigned int _flags;    /* see below */
                        unsigned long _isr;     /* isr */
+                       short _addr_lsb;        /* lsb of faulting address */
                } _sigfault;
 
                /* SIGPOLL */
index e6359c566b504f50ae462cc9c917b2126603052d..8a28cfea27297694aa12328e579dd6f44a385d3e 100644 (file)
@@ -332,9 +332,7 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
        ((pte_t *)pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address)   \
        ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address)    pte_offset_map(dir, address)
 #define pte_unmap(pte)         do { } while (0)
-#define pte_unmap_nested(pte)  do { } while (0)
 
 /* Encode and de-code a swap entry */
 #define __swp_type(x)                  (((x).val >> 2) & 0x1f)
index 89f195656be74e8888e2c9d28389034408511775..7085bd51668b96d101c44b2506cf730812a23eaa 100644 (file)
@@ -29,7 +29,7 @@
 
 static inline void __flush_cache_all(void)
 {
-#ifdef CONFIG_M5407
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
        /*
         *      Use cpushl to push and invalidate all cache lines.
         *      Gas doesn't seem to know how to generate the ColdFire
index 83a9fa4e618accaef823f556a9492ba2f614b5d8..3b0a34d0fe33400c66e68462375ead78b2a1cb5f 100644 (file)
@@ -32,7 +32,9 @@
  */
 #define        MCF_MBAR        0x10000000
 #define        MCF_MBAR2       0x80000000
-#if defined(CONFIG_M520x)
+#if defined(CONFIG_M548x)
+#define        MCF_IPSBAR      MCF_MBAR
+#elif defined(CONFIG_M520x)
 #define        MCF_IPSBAR      0xFC000000
 #else
 #define        MCF_IPSBAR      0x40000000
index e41fea399bfe1c94c03e4a0fcab662ee7a67fbcf..73b8c8fbed9cdbad94c505db43e98a3972d72d5d 100644 (file)
 
 LFLUSH_I_AND_D = 0x00000808
 
-/* process bits for task_struct.ptrace */
-PT_TRACESYS_OFF = 3
-PT_TRACESYS_BIT = 1
-PT_PTRACED_OFF = 3
-PT_PTRACED_BIT = 0
-PT_DTRACE_OFF = 3
-PT_DTRACE_BIT = 2
-
 #define SAVE_ALL_INT save_all_int
 #define SAVE_ALL_SYS save_all_sys
 #define RESTORE_ALL restore_all
index 80e41492aa2a0750018620d73c1387a36bbe265a..26be277394f9fc647931f2145e67173d648c20f2 100644 (file)
 
 #ifdef __ASSEMBLY__
 
-/* process bits for task_struct.flags */
-PF_TRACESYS_OFF = 3
-PF_TRACESYS_BIT = 5
-PF_PTRACED_OFF = 3
-PF_PTRACED_BIT = 4
-PF_DTRACE_OFF = 1
-PF_DTRACE_BIT = 5
-
-LENOSYS = 38
-
 #define SWITCH_STACK_SIZE (6*4+4)      /* Includes return address */
 
 /*
index 283214dc65a7b6d051ab20fbeb592bd28749174e..1b57adbafad54b14ef1b651a5b82fdf295bf8d47 100644 (file)
@@ -36,7 +36,8 @@
  */
 #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
     defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-    defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+    defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+    defined(CONFIG_M532x) || defined(CONFIG_M548x)
 
 /* These parts have GPIO organized by 8 bit ports */
 
@@ -136,6 +137,8 @@ static inline u32 __mcf_gpio_ppdr(unsigned gpio)
 #endif
        else
                return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+       return 0;
 #endif
 }
 
@@ -173,6 +176,8 @@ static inline u32 __mcf_gpio_podr(unsigned gpio)
 #endif
        else
                return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+       return 0;
 #endif
 }
 
diff --git a/arch/m68k/include/asm/m548xgpt.h b/arch/m68k/include/asm/m548xgpt.h
new file mode 100644 (file)
index 0000000..c8ef158
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * File:       m548xgpt.h
+ * Purpose:    Register and bit definitions for the MCF548X
+ *
+ * Notes:
+ *
+ */
+
+#ifndef m548xgpt_h
+#define m548xgpt_h
+
+/*********************************************************************
+*
+* General Purpose Timers (GPT)
+*
+*********************************************************************/
+
+/* Register read/write macros */
+#define MCF_GPT_GMS0       0x000800
+#define MCF_GPT_GCIR0      0x000804
+#define MCF_GPT_GPWM0      0x000808
+#define MCF_GPT_GSR0       0x00080C
+#define MCF_GPT_GMS1       0x000810
+#define MCF_GPT_GCIR1      0x000814
+#define MCF_GPT_GPWM1      0x000818
+#define MCF_GPT_GSR1       0x00081C
+#define MCF_GPT_GMS2       0x000820
+#define MCF_GPT_GCIR2      0x000824
+#define MCF_GPT_GPWM2      0x000828
+#define MCF_GPT_GSR2       0x00082C
+#define MCF_GPT_GMS3       0x000830
+#define MCF_GPT_GCIR3      0x000834
+#define MCF_GPT_GPWM3      0x000838
+#define MCF_GPT_GSR3       0x00083C
+#define MCF_GPT_GMS(x)     (0x000800+((x)*0x010))
+#define MCF_GPT_GCIR(x)    (0x000804+((x)*0x010))
+#define MCF_GPT_GPWM(x)    (0x000808+((x)*0x010))
+#define MCF_GPT_GSR(x)     (0x00080C+((x)*0x010))
+
+/* Bit definitions and macros for MCF_GPT_GMS */
+#define MCF_GPT_GMS_TMS(x)         (((x)&0x00000007)<<0)
+#define MCF_GPT_GMS_GPIO(x)        (((x)&0x00000003)<<4)
+#define MCF_GPT_GMS_IEN            (0x00000100)
+#define MCF_GPT_GMS_OD             (0x00000200)
+#define MCF_GPT_GMS_SC             (0x00000400)
+#define MCF_GPT_GMS_CE             (0x00001000)
+#define MCF_GPT_GMS_WDEN           (0x00008000)
+#define MCF_GPT_GMS_ICT(x)         (((x)&0x00000003)<<16)
+#define MCF_GPT_GMS_OCT(x)         (((x)&0x00000003)<<20)
+#define MCF_GPT_GMS_OCPW(x)        (((x)&0x000000FF)<<24)
+#define MCF_GPT_GMS_OCT_FRCLOW     (0x00000000)
+#define MCF_GPT_GMS_OCT_PULSEHI    (0x00100000)
+#define MCF_GPT_GMS_OCT_PULSELO    (0x00200000)
+#define MCF_GPT_GMS_OCT_TOGGLE     (0x00300000)
+#define MCF_GPT_GMS_ICT_ANY        (0x00000000)
+#define MCF_GPT_GMS_ICT_RISE       (0x00010000)
+#define MCF_GPT_GMS_ICT_FALL       (0x00020000)
+#define MCF_GPT_GMS_ICT_PULSE      (0x00030000)
+#define MCF_GPT_GMS_GPIO_INPUT     (0x00000000)
+#define MCF_GPT_GMS_GPIO_OUTLO     (0x00000020)
+#define MCF_GPT_GMS_GPIO_OUTHI     (0x00000030)
+#define MCF_GPT_GMS_TMS_DISABLE    (0x00000000)
+#define MCF_GPT_GMS_TMS_INCAPT     (0x00000001)
+#define MCF_GPT_GMS_TMS_OUTCAPT    (0x00000002)
+#define MCF_GPT_GMS_TMS_PWM        (0x00000003)
+#define MCF_GPT_GMS_TMS_GPIO       (0x00000004)
+
+/* Bit definitions and macros for MCF_GPT_GCIR */
+#define MCF_GPT_GCIR_CNT(x)        (((x)&0x0000FFFF)<<0)
+#define MCF_GPT_GCIR_PRE(x)        (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GPWM */
+#define MCF_GPT_GPWM_LOAD          (0x00000001)
+#define MCF_GPT_GPWM_PWMOP         (0x00000100)
+#define MCF_GPT_GPWM_WIDTH(x)      (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GSR */
+#define MCF_GPT_GSR_CAPT           (0x00000001)
+#define MCF_GPT_GSR_COMP           (0x00000002)
+#define MCF_GPT_GSR_PWMP           (0x00000004)
+#define MCF_GPT_GSR_TEXP           (0x00000008)
+#define MCF_GPT_GSR_PIN            (0x00000100)
+#define MCF_GPT_GSR_OVF(x)         (((x)&0x00000007)<<12)
+#define MCF_GPT_GSR_CAPTURE(x)     (((x)&0x0000FFFF)<<16)
+
+/********************************************************************/
+
+#endif /* m548xgpt_h */
diff --git a/arch/m68k/include/asm/m548xsim.h b/arch/m68k/include/asm/m548xsim.h
new file mode 100644 (file)
index 0000000..149135e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *     m548xsim.h -- ColdFire 547x/548x System Integration Unit support.
+ */
+
+#ifndef        m548xsim_h
+#define m548xsim_h
+
+#define MCFINT_VECBASE      64
+
+/*
+ *      Interrupt Controller Registers
+ */
+#define MCFICM_INTC0           0x0700          /* Base for Interrupt Ctrl 0 */
+#define MCFINTC_IPRH           0x00            /* Interrupt pending 32-63 */
+#define MCFINTC_IPRL           0x04            /* Interrupt pending 1-31 */
+#define MCFINTC_IMRH           0x08            /* Interrupt mask 32-63 */
+#define MCFINTC_IMRL           0x0c            /* Interrupt mask 1-31 */
+#define MCFINTC_INTFRCH                0x10            /* Interrupt force 32-63 */
+#define MCFINTC_INTFRCL                0x14            /* Interrupt force 1-31 */
+#define MCFINTC_IRLR           0x18            /* */
+#define MCFINTC_IACKL          0x19            /* */
+#define MCFINTC_ICR0           0x40            /* Base ICR register */
+
+/*
+ *     Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER          (64 + 54)       /* Slice Timer 0 */
+#define MCF_IRQ_PROFILER       (64 + 53)       /* Slice Timer 1 */
+
+/*
+ *     Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX                0       /* I am too lazy to count */
+#define MCFGPIO_IRQ_MAX                -1
+#define MCFGPIO_IRQ_VECBASE    -1
+
+/*
+ *     Some PSC related definitions
+ */
+#define MCF_PAR_PSC(x)         (0x000A4F-((x)&0x3))
+#define MCF_PAR_SDA            (0x0008)
+#define MCF_PAR_SCL            (0x0004)
+#define MCF_PAR_PSC_TXD                (0x04)
+#define MCF_PAR_PSC_RXD                (0x08)
+#define MCF_PAR_PSC_RTS(x)     (((x)&0x03)<<4)
+#define MCF_PAR_PSC_CTS(x)     (((x)&0x03)<<6)
+#define MCF_PAR_PSC_CTS_GPIO   (0x00)
+#define MCF_PAR_PSC_CTS_BCLK   (0x80)
+#define MCF_PAR_PSC_CTS_CTS    (0xC0)
+#define MCF_PAR_PSC_RTS_GPIO    (0x00)
+#define MCF_PAR_PSC_RTS_FSYNC  (0x20)
+#define MCF_PAR_PSC_RTS_RTS    (0x30)
+#define MCF_PAR_PSC_CANRX      (0x40)
+
+#endif /* m548xsim_h */
index c042634fadaa0cecb2c83d0ea9e3feac3ecc91d5..f49dfc09f70a6949375cd9c2d628373762fc4b49 100644 (file)
 .endm
 #endif /* CONFIG_M532x */
 
-#if defined(CONFIG_M5407)
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
 /*
  *     Version 4 cores have a true harvard style separate instruction
  *     and data cache. Invalidate and enable cache, also enable write
index 9c70a67bf85f7c90f12be85c9aaef73ac55dec17..6901fd68165bd333b79b3dc1dc113b7a15275f72 100644 (file)
@@ -41,6 +41,8 @@
 #elif defined(CONFIG_M5407)
 #include <asm/m5407sim.h>
 #include <asm/mcfintc.h>
+#elif defined(CONFIG_M548x)
+#include <asm/m548xsim.h>
 #endif
 
 /****************************************************************************/
diff --git a/arch/m68k/include/asm/mcfslt.h b/arch/m68k/include/asm/mcfslt.h
new file mode 100644 (file)
index 0000000..d0d0ecb
--- /dev/null
@@ -0,0 +1,44 @@
+/****************************************************************************/
+
+/*
+ *     mcfslt.h -- ColdFire internal Slice (SLT) timer support defines.
+ *
+ *     (C) Copyright 2004, Greg Ungerer (gerg@snapgear.com)
+ *     (C) Copyright 2009, Philippe De Muyter (phdm@macqel.be)
+ */
+
+/****************************************************************************/
+#ifndef mcfslt_h
+#define mcfslt_h
+/****************************************************************************/
+
+/*
+ *     Get address specific defines for the 547x.
+ */
+#define MCFSLT_TIMER0          0x900   /* Base address of TIMER0 */
+#define MCFSLT_TIMER1          0x910   /* Base address of TIMER1 */
+
+
+/*
+ *     Define the SLT timer register set addresses.
+ */
+#define MCFSLT_STCNT           0x00    /* Terminal count */
+#define MCFSLT_SCR             0x04    /* Control */
+#define MCFSLT_SCNT            0x08    /* Current count */
+#define MCFSLT_SSR             0x0C    /* Status */
+
+/*
+ *     Bit definitions for the SCR control register.
+ */
+#define MCFSLT_SCR_RUN         0x04000000      /* Run mode (continuous) */
+#define MCFSLT_SCR_IEN         0x02000000      /* Interrupt enable */
+#define MCFSLT_SCR_TEN         0x01000000      /* Timer enable */
+
+/*
+ *     Bit definitions for the SSR status register.
+ */
+#define MCFSLT_SSR_BE          0x02000000      /* Bus error condition */
+#define MCFSLT_SSR_TE          0x01000000      /* Timeout condition */
+
+/****************************************************************************/
+#endif /* mcfslt_h */
index 01a8716c5fc558253538b9cbea14a923b8b889be..db72e2b889ca0aca736f226f392819bdb60d650e 100644 (file)
 #define MCFUART_BASE1          0xfc060000      /* Base address of UART1 */
 #define MCFUART_BASE2          0xfc064000      /* Base address of UART2 */
 #define MCFUART_BASE3          0xfc068000      /* Base address of UART3 */
+#elif defined(CONFIG_M548x)
+#define MCFUART_BASE1          0x8600          /* on M548x */
+#define MCFUART_BASE2          0x8700          /* on M548x */
+#define MCFUART_BASE3          0x8800          /* on M548x */
+#define MCFUART_BASE4          0x8900          /* on M548x */
 #endif
 
 
@@ -212,7 +217,9 @@ struct mcf_platform_uart {
 #define        MCFUART_URF_RXS         0xc0            /* Receiver status */
 #endif
 
-#if defined(CONFIG_M5272)
+#if defined(CONFIG_M548x)
+#define MCFUART_TXFIFOSIZE     512
+#elif defined(CONFIG_M5272)
 #define MCFUART_TXFIFOSIZE     25
 #else
 #define MCFUART_TXFIFOSIZE     1
index 8e9a8a754dde0007377d1f59cfc0ed121f56f248..45bd3f589bf0d62baeac34692aa7b6582cd3ae9f 100644 (file)
@@ -221,9 +221,7 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmdp, unsigned long address)
 }
 
 #define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-#define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address)
 #define pte_unmap(pte)         ((void)0)
-#define pte_unmap_nested(pte)  ((void)0)
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
index f847ec732d62d290a11ba2c464c2185a8d040f89..cf5fad9b525041f20518bb5e776d728e911af007 100644 (file)
@@ -219,9 +219,7 @@ static inline pte_t pgoff_to_pte(unsigned off)
 #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address))
 /* FIXME: should we bother with kmap() here? */
 #define pte_offset_map(pmd, address) ((pte_t *)kmap(pmd_page(*pmd)) + pte_index(address))
-#define pte_offset_map_nested(pmd, address) pte_offset_map(pmd, address)
 #define pte_unmap(pte) kunmap(pte)
-#define pte_unmap_nested(pte) kunmap(pte)
 
 /* Macros to (de)construct the fake PTEs representing swap pages. */
 #define __swp_type(x)          ((x).val & 0x7F)
index 73e5e581245b11dc121e28f3c5c83cbdb894a21b..78e59b82ebc397ca8f1f4f0df0878aaeb3083be2 100644 (file)
 int main(void)
 {
        /* offsets into the task struct */
-       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
-       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-       DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
        DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
        DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-       DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 #ifdef CONFIG_MMU
        DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
 #endif
@@ -64,14 +60,6 @@ int main(void)
        /* bitfields are a bit difficult */
        DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
 
-       /* offsets into the irq_handler struct */
-       DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
-       DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
-       DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
-
-       /* offsets into the kernel_stat struct */
-       DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-
        /* offsets into the irq_cpustat_t struct */
        DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
 
index 2609c394e1dfd11f6ea78c16c109cfac03c66836..9287150e5fb0604419aca81ee1a34e82fb75882e 100644 (file)
@@ -59,6 +59,10 @@ config GENERIC_HARDIRQS
        bool
        default y
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       bool
+       default y
+
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
@@ -171,6 +175,11 @@ config M5407
        help
          Motorola ColdFire 5407 processor support.
 
+config M548x
+       bool "MCF548x"
+       help
+         Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
 endchoice
 
 config M527x
@@ -181,7 +190,7 @@ config M527x
 
 config COLDFIRE
        bool
-       depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
+       depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x)
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
        default y
index 14042574ac217550db926fd24e308b7c5620f756..026ef16fa68e6c0054ff479af392822db7de9075 100644 (file)
@@ -25,6 +25,7 @@ platform-$(CONFIG_M528x)      := 528x
 platform-$(CONFIG_M5307)       := 5307
 platform-$(CONFIG_M532x)       := 532x
 platform-$(CONFIG_M5407)       := 5407
+platform-$(CONFIG_M548x)       := 548x
 PLATFORM := $(platform-y)
 
 board-$(CONFIG_PILOT)          := pilot
@@ -73,6 +74,7 @@ cpuclass-$(CONFIG_M528x)      := coldfire
 cpuclass-$(CONFIG_M5307)       := coldfire
 cpuclass-$(CONFIG_M532x)       := coldfire
 cpuclass-$(CONFIG_M5407)       := coldfire
+cpuclass-$(CONFIG_M548x)       := coldfire
 cpuclass-$(CONFIG_M68328)      := 68328
 cpuclass-$(CONFIG_M68EZ328)    := 68328
 cpuclass-$(CONFIG_M68VZ328)    := 68328
@@ -100,6 +102,7 @@ cflags-$(CONFIG_M528x)              := $(call cc-option,-m528x,-m5307)
 cflags-$(CONFIG_M5307)         := $(call cc-option,-m5307,-m5200)
 cflags-$(CONFIG_M532x)         := $(call cc-option,-mcpu=532x,-m5307)
 cflags-$(CONFIG_M5407)         := $(call cc-option,-m5407,-m5200)
+cflags-$(CONFIG_M548x)         := $(call cc-option,-m5407,-m5200)
 cflags-$(CONFIG_M68328)                := -m68000
 cflags-$(CONFIG_M68EZ328)      := -m68000
 cflags-$(CONFIG_M68VZ328)      := -m68000
diff --git a/arch/m68knommu/kernel/.gitignore b/arch/m68knommu/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 24335022fa2c74893b695d041b330c4810680087..ffe02f41ad4683467db62e922b9efba6d0955c08 100644 (file)
 int main(void)
 {
        /* offsets into the task struct */
-       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
-       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-       DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-       DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-       DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
        /* offsets into the irq_cpustat_t struct */
        DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
@@ -63,7 +57,7 @@ int main(void)
        DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
 #else
        /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
 #endif
 
        /* signal defines */
@@ -75,11 +69,8 @@ int main(void)
        DEFINE(PT_PTRACED, PT_PTRACED);
 
        /* Offsets in thread_info structure */
-       DEFINE(TI_TASK, offsetof(struct thread_info, task));
-       DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
        DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-       DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 
        return 0;
 }
index f6be1248d2164e8f55a8d4d34942424369975df6..6fe7c38cd5569de6c7eb8750f1f69be59422888f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/signal.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -134,14 +135,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                        tmp >>= 16;
                        } else if (addr >= 21 && addr < 49) {
                                tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
-                               /* Convert internal fpu reg representation
-                                * into long double format
-                                */
-                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
-                                       tmp = ((tmp & 0xffff0000) << 15) |
-                                             ((tmp & 0x0000ffff) << 16);
-#endif
                        } else if (addr == 49) {
                                tmp = child->mm->start_code;
                        } else if (addr == 50) {
@@ -175,16 +168,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        }
                        if (addr >= 21 && addr < 48)
                        {
-#ifdef CONFIG_M68KFPU_EMU
-                               /* Convert long double format
-                                * into internal fpu reg representation
-                                */
-                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
-                                       data = (unsigned long)data << 15;
-                                       data = (data & 0xffff0000) |
-                                              ((data & 0x0000ffff) >> 1);
-                               }
-#endif
                                child->thread.fp[addr - 21] = data;
                                ret = 0;
                        }
@@ -259,21 +242,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        return ret;
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(void)
 {
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-       if (!(current->ptrace & PT_PTRACED))
-               return;
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                ? 0x80 : 0));
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+       int ret = 0;
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(task_pt_regs(current));
+       return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(task_pt_regs(current), 0);
 }
index ba92b90d5fbc81e7fd7f8cb3fad54b13461ac1f0..c684adf5dc40dfb8f4d4ce4d519d35e7023a4ff8 100644 (file)
@@ -54,9 +54,6 @@ void (*mach_reset)(void);
 void (*mach_halt)(void);
 void (*mach_power_off)(void);
 
-#ifdef CONFIG_M68000
-       #define CPU "MC68000"
-#endif
 #ifdef CONFIG_M68328
        #define CPU "MC68328"
 #endif
index 7089dd9d843b3fd65d39be90060f612e7deddd77..d6ac2a43453ce5be5808a0fa6aeacd4666cf8da6 100644 (file)
@@ -60,13 +60,16 @@ static unsigned long read_rtc_mmss(void)
 {
        unsigned int year, mon, day, hour, min, sec;
 
-       if (mach_gettod)
+       if (mach_gettod) {
                mach_gettod(&year, &mon, &day, &hour, &min, &sec);
-       else
-               year = mon = day = hour = min = sec = 0;
+               if ((year += 1900) < 1970)
+                       year += 100;
+       } else {
+               year = 1970;
+               mon = day = 1;
+               hour = min = sec = 0;
+       }
 
-       if ((year += 1900) < 1970)
-               year += 100;
 
        return  mktime(year, mon, day, hour, min, sec);
 }
index 3739c8f657d75f12d94c92e2e1665a6f927c2e7d..a768008dfd06fbafa47f29778754f0d464564371 100644 (file)
@@ -179,14 +179,16 @@ static void __show_stack(struct task_struct *task, unsigned long *stack)
 
 void bad_super_trap(struct frame *fp)
 {
+       int vector = (fp->ptregs.vector >> 2) & 0xff;
+
        console_verbose();
-       if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
+       if (vector < ARRAY_SIZE(vec_names))
                printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
-                       vec_names[(fp->ptregs.vector) >> 2],
+                       vec_names[vector],
                        fp->ptregs.format);
        else
                printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
-                       (fp->ptregs.vector) >> 2, 
+                       vector,
                        fp->ptregs.format);
        printk (KERN_WARNING "Current process id is %d\n", current->pid);
        die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
@@ -195,10 +197,11 @@ void bad_super_trap(struct frame *fp)
 asmlinkage void trap_c(struct frame *fp)
 {
        int sig;
+       int vector = (fp->ptregs.vector >> 2) & 0xff;
        siginfo_t info;
 
        if (fp->ptregs.sr & PS_S) {
-               if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+               if (vector == VEC_TRACE) {
                        /* traced a trapping instruction */
                } else
                        bad_super_trap(fp);
@@ -206,7 +209,7 @@ asmlinkage void trap_c(struct frame *fp)
        }
 
        /* send the appropriate signal to the user program */
-       switch ((fp->ptregs.vector) >> 2) {
+       switch (vector) {
            case VEC_ADDRERR:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
@@ -360,16 +363,3 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        else
                __show_stack(task, stack);
 }
-
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpemu_signal(int signal, int code, void *addr)
-{
-       siginfo_t info;
-
-       info.si_signo = signal;
-       info.si_errno = 0;
-       info.si_code = code;
-       info.si_addr = addr;
-       force_sig_info(signal, &info, current);
-}
-#endif
index 113c333900648dcc9edfaa974a63084e07844816..b5db05625cfabac5dc3fc5259e044da13b7a2376 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 113c333900648dcc9edfaa974a63084e07844816..b5db05625cfabac5dc3fc5259e044da13b7a2376 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 435ab3483dc1dd9f89c4599ce6ba96b5994e8fa5..ad3f4e5a57cee62ace23d1d3770bbe1f48175cc5 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index b8f9b45440c203bed369b4cd195a5d82ca70b874..c04b8f71c88c1c521e3fec975e88117fce76e134 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index f56225d1582fe559a81026e2f8bbb32408a19ee2..4bed30fd0073037d4c708900575e2fce28139247 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 93673ef8e2c13de6355fe4c2a3979c22cb2e5f7d..34110fc143015a6d90210bf33502f16845111f48 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 59278c0887d04de431d46049924f920170328d6a..65bb582734e1faea91d2a707e4107a55bbd90145 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -148,9 +150,23 @@ void __init config_BSP(char *commandp, int size)
 
 /***************************************************************************/
 
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+       .link   = 1,
+       .speed  = 100,
+       .duplex = 0,
+};
+
+/***************************************************************************/
+
 static int __init init_BSP(void)
 {
        m5272_uarts_init();
+       fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
        platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
        return 0;
 }
index 7081e0a9720e6fbbec92f2c0fb423daef9f769cb..3cf681c177aaa5e51d13a8a93504b05bf91522af 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <asm/coldfire.h>
  * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
  * loose mapping of vector number to register and internal bits, but
  * a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledgeing via acknowledge bits.
  */
 struct irqmap {
        unsigned char   icr;
@@ -68,6 +73,11 @@ static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
        /*MCF_IRQ_SWTO*/        { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
 };
 
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
 static void intc_irq_mask(unsigned int irq)
 {
        if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
@@ -95,7 +105,9 @@ static void intc_irq_ack(unsigned int irq)
                irq -= MCFINT_VECBASE;
                if (intc_irqmap[irq].ack) {
                        u32 v;
-                       v = 0xd << intc_irqmap[irq].index;
+                       v = readl(MCF_MBAR + intc_irqmap[irq].icr);
+                       v &= (0x7 << intc_irqmap[irq].index);
+                       v |= (0x8 << intc_irqmap[irq].index);
                        writel(v, MCF_MBAR + intc_irqmap[irq].icr);
                }
        }
@@ -103,21 +115,47 @@ static void intc_irq_ack(unsigned int irq)
 
 static int intc_irq_set_type(unsigned int irq, unsigned int type)
 {
-       /* We can set the edge type here for external interrupts */
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               irq -= MCFINT_VECBASE;
+               if (intc_irqmap[irq].ack) {
+                       u32 v;
+                       v = readl(MCF_MBAR + MCFSIM_PITR);
+                       if (type == IRQ_TYPE_EDGE_FALLING)
+                               v &= ~(0x1 << (32 - irq));
+                       else
+                               v |= (0x1 << (32 - irq));
+                       writel(v, MCF_MBAR + MCFSIM_PITR);
+               }
+       }
        return 0;
 }
 
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+       kstat_incr_irqs_this_cpu(irq, desc);
+       desc->status |= IRQ_INPROGRESS;
+       desc->chip->ack(irq);
+       handle_IRQ_event(irq, desc->action);
+       desc->status &= ~IRQ_INPROGRESS;
+}
+
 static struct irq_chip intc_irq_chip = {
        .name           = "CF-INTC",
        .mask           = intc_irq_mask,
        .unmask         = intc_irq_unmask,
+       .mask_ack       = intc_irq_mask,
        .ack            = intc_irq_ack,
        .set_type       = intc_irq_set_type,
 };
 
 void __init init_IRQ(void)
 {
-       int irq;
+       int irq, edge;
 
        init_vectors();
 
@@ -128,11 +166,17 @@ void __init init_IRQ(void)
        writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
 
        for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_desc[irq].status = IRQ_DISABLED;
-               irq_desc[irq].action = NULL;
-               irq_desc[irq].depth = 1;
-               irq_desc[irq].chip = &intc_irq_chip;
-               intc_irq_set_type(irq, 0);
+               set_irq_chip(irq, &intc_irq_chip);
+               edge = 0;
+               if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+                       edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+               if (edge) {
+                       set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+                       set_irq_handler(irq, intc_external_irq);
+               } else {
+                       set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+                       set_irq_handler(irq, handle_level_irq);
+               }
        }
 }
 
index 3d90e6d92459bc0e4adcecffa84488032833ff8f..6ac4b57370ea1b2c718bda98129ac867eea047c3 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 3d90e6d92459bc0e4adcecffa84488032833ff8f..6ac4b57370ea1b2c718bda98129ac867eea047c3 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 6de52697682829562a94bfd4577dc40b7e55e390..d4293b791f2eeeaaed03278cb6562520c57f2a6a 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index 4cc23245bcd1e1192236a06032d5f1fe62d20fef..ce01669399c64b45000bceef184185a7e27b4835 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
index dee62c5dbaa6890e4a7d51923907fab46fb2cb72..e83fe148eddc85743f449bddf87bdd6ee8838bb7 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/548x/Makefile b/arch/m68knommu/platform/548x/Makefile
new file mode 100644 (file)
index 0000000..e6035e7
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o
+
diff --git a/arch/m68knommu/platform/548x/config.c b/arch/m68knommu/platform/548x/config.c
new file mode 100644 (file)
index 0000000..9888846
--- /dev/null
@@ -0,0 +1,115 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/548x/config.c
+ *
+ *     Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m548xsim.h>
+#include <asm/mcfuart.h>
+#include <asm/m548xgpt.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m548x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 64 + 35,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 64 + 34,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = 64 + 33,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE4,
+               .irq            = 64 + 32,
+       },
+};
+
+static struct platform_device m548x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m548x_uart_platform,
+};
+
+static struct platform_device *m548x_devices[] __initdata = {
+       &m548x_uart,
+};
+
+
+/***************************************************************************/
+
+static void __init m548x_uart_init_line(int line, int irq)
+{
+       int rts_cts;
+
+       /* enable io pins */
+       switch (line) {
+       case 0:
+               rts_cts = 0; break;
+       case 1:
+               rts_cts = MCF_PAR_PSC_RTS_RTS; break;
+       case 2:
+               rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
+       case 3:
+               rts_cts = 0; break;
+       }
+       __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
+                                               MCF_MBAR + MCF_PAR_PSC(line));
+}
+
+static void __init m548x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m548x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m548x_uart_init_line(line, m548x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void mcf548x_reset(void)
+{
+       /* disable interrupts and enable the watchdog */
+       asm("movew #0x2700, %sr\n");
+       __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
+       __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
+       __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+                                               MCF_MBAR + MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = mcf548x_reset;
+       m548x_uarts_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+
+       platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index 9d80d2c4286668f2715d64a5026026e5f98cfae7..27241e16a5265b2d1d17536203025df9787108aa 100644 (file)
@@ -43,10 +43,10 @@ badsys:
        jra     ret_from_exception
 
 do_trace:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)        /* needed for strace*/
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
        subql   #4,%sp
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_enter
        RESTORE_SWITCH_STACK
        addql   #4,%sp
        movel   %sp@(PT_OFF_ORIG_D0),%d1
@@ -57,10 +57,10 @@ do_trace:
        lea     sys_call_table, %a0
        jbsr    %a0@(%d1)
 
-1:     movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_leave
 
 ret_from_signal:
        RESTORE_SWITCH_STACK
@@ -71,16 +71,16 @@ ENTRY(system_call)
        SAVE_ALL
 
        /* save top of frame*/
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
 
        movel   %sp@(PT_OFF_ORIG_D0),%d0
 
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
-       btst    #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -88,10 +88,10 @@ ENTRY(system_call)
        lea     sys_call_table,%a0
        movel   %a0@(%d0), %a0
        jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value*/
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
 
 ret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)              /* check if returning to kernel*/
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
        jeq     Luser_return            /* if so, skip resched, signals*/
 
 Lkernel_return:
@@ -133,7 +133,7 @@ Lreturn:
  */
 inthandler1:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -144,7 +144,7 @@ inthandler1:
 
 inthandler2:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -155,7 +155,7 @@ inthandler2:
 
 inthandler3:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -166,7 +166,7 @@ inthandler3:
 
 inthandler4:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -177,7 +177,7 @@ inthandler4:
 
 inthandler5:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -188,7 +188,7 @@ inthandler5:
 
 inthandler6:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -199,7 +199,7 @@ inthandler6:
 
 inthandler7:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -210,7 +210,7 @@ inthandler7:
 
 inthandler:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
index 92d96456d3635c9118d8041fb04d948e57839227..f632fdcb93e913b218b7e5a7743d089ac0f8172f 100644 (file)
@@ -1,11 +1,5 @@
 
-#if defined(CONFIG_RAM32MB)
-#define        MEM_END 0x02000000      /* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define        MEM_END 0x01000000      /* Memory size 16Mb */
-#else
 #define        MEM_END 0x00800000      /* Memory size 8Mb */
-#endif
 
 #undef CRT_DEBUG
 
index 252b80b020380b422e1fdec6afdcb56e31dea6a5..7f1aeeacb219a7525f3b142f4e27fefa5cb99ba5 100644 (file)
@@ -67,33 +67,6 @@ pclp1:
        beq     pclp1
 #endif /* DEBUG */
 
-#ifdef CONFIG_RELOCATE
-       /* Copy me to RAM */
-       moveal  #__rom_start, %a0
-       moveal  #_stext, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       movel   %a0@+, %d0
-       movel   %d0, %a1@+
-       cmpal   %a1, %a2
-       bhi     LD1
-       
-#ifdef DEBUG
-       moveq   #74, %d7                /* 'J' */
-       moveb   %d7,0xfffff907          /* No absolute addresses */
-pclp2:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     pclp2
-#endif /* DEBUG */
-       /* jump into the RAM copy */
-       jmp     ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
 #ifdef DEBUG
        moveq   #82, %d7                /* 'R' */
        moveb   %d7,0xfffff907          /* No absolute addresses */
index b91ee85d4b5dbf7de464a6ab46350025f5cf78fb..865852806a1719311936ab2dcf973cf99790f92f 100644 (file)
@@ -179,10 +179,8 @@ void __init init_IRQ(void)
        IMR = ~0;
 
        for (i = 0; (i < NR_IRQS); i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].chip = &intc_irq_chip;
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
index 6d3460a39cacf1383a16f2e66146c60aeecf6509..c131c6e1d92dddfa749ea3db232c61bf98ef0ce2 100644 (file)
@@ -42,7 +42,7 @@ do_trace:
        movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
        subql   #4,%sp
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_enter
        RESTORE_SWITCH_STACK
        addql   #4,%sp
        movel   %sp@(PT_OFF_ORIG_D0),%d1
@@ -56,7 +56,7 @@ do_trace:
 1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_leave
 
 ret_from_signal:
        RESTORE_SWITCH_STACK
@@ -71,7 +71,12 @@ ENTRY(system_call)
        jbsr    set_esp0
        addql   #4,%sp
 
-       btst    #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF)
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -124,7 +129,7 @@ Lreturn:
  */
 inthandler:
        SAVE_ALL
-       movew   %sp@(PT_OFF_VECTOR), %d0
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
        and.l   #0x3ff, %d0
        lsr.l   #0x02,  %d0
 
index 6f22970d8c2037380e4342e7e88a7dbab9c74dc3..ad96ab1051f002314fc839bd84b64c26d87e7d6f 100644 (file)
@@ -132,10 +132,8 @@ void init_IRQ(void)
        pquicc->intr_cimr = 0x00000000;
 
        for (i = 0; (i < NR_IRQS); i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].chip = &intc_irq_chip;
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
index fc5c63054e98f09a2cff9d955709d3267212707c..eabaabe8af3605e9dbb09519b5391f2a33a76b0d 100644 (file)
@@ -90,11 +90,6 @@ static void init_hardware(char *command, int size)
        PDIQEG &= ~PD(1);
        PDIRQEN |= PD(1);                       /* IRQ enabled */
 
-#ifdef CONFIG_68328_SERIAL_UART2
-       /* Enable RXD TXD port bits to enable UART2 */
-       PJSEL &= ~(PJ(5) | PJ(4));
-#endif
-
 #ifdef CONFIG_INIT_LCD
        /* initialize LCD controller */
        LSSA = (long) screen_bits;
index f72a0e5d9996a9a5104ca1d81171c2a701252dd9..45f501fa452526f8221d8a2cb47c82b60ed4b5c7 100644 (file)
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
@@ -26,6 +26,7 @@ obj-$(CONFIG_M528x)   += pit.o intc-2.o
 obj-$(CONFIG_M5307)    += timers.o intc.o
 obj-$(CONFIG_M532x)    += timers.o intc-simr.o
 obj-$(CONFIG_M5407)    += timers.o intc.o
+obj-$(CONFIG_M548x)    += sltimers.o intc-2.o
 
 obj-y                  += pinmux.o gpio.o
 extra-y := head.o
index cd79d7e92ce64ee61c1d1c9e08c10f978ad6c87a..5e92bed94b7e56c9f4e543bed2897e18128a8b3e 100644 (file)
@@ -88,7 +88,7 @@ ENTRY(system_call)
        movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
        subql   #4,%sp
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_enter
        RESTORE_SWITCH_STACK
        addql   #4,%sp
        movel   %d3,%a0
@@ -96,7 +96,7 @@ ENTRY(system_call)
        movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
-       jbsr    syscall_trace
+       jbsr    syscall_trace_leave
 
 ret_from_signal:
        RESTORE_SWITCH_STACK
index 5598c8b8661f9dae4ce6ad9f25a2adc9fee6348f..85daa2b3001ad0fecbacaa71dcd4d737c9810e4d 100644 (file)
@@ -1,5 +1,11 @@
 /*
- * intc-1.c
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
  *
  * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
  *
 #include <asm/traps.h>
 
 /*
- *     Each vector needs a unique priority and level asscoiated with it.
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l)    ((l)<<3)        /* Level l intr */
+#define MCFSIM_ICR_PRI(p)      (p)             /* Priority p intr */
+
+/*
+ *     Each vector needs a unique priority and level associated with it.
  *     We don't really care so much what they are, we don't rely on the
- *     tranditional priority interrupt scheme of the m68k/ColdFire.
+ *     traditional priority interrupt scheme of the m68k/ColdFire.
  */
-static u8 intc_intpri = 0x36;
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+#ifdef MCFICM_INTC1
+#define NR_VECS        128
+#else
+#define NR_VECS        64
+#endif
 
 static void intc_irq_mask(unsigned int irq)
 {
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
                unsigned long imraddr;
                u32 val, imrbit;
 
                irq -= MCFINT_VECBASE;
                imraddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
                imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+               imraddr += MCFICM_INTC0;
+#endif
                imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
                imrbit = 0x1 << (irq & 0x1f);
 
@@ -44,13 +66,17 @@ static void intc_irq_mask(unsigned int irq)
 
 static void intc_irq_unmask(unsigned int irq)
 {
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
                unsigned long intaddr, imraddr, icraddr;
                u32 val, imrbit;
 
                irq -= MCFINT_VECBASE;
                intaddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
                intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+               intaddr += MCFICM_INTC0;
+#endif
                imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
                icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
                imrbit = 0x1 << (irq & 0x1f);
@@ -67,10 +93,16 @@ static void intc_irq_unmask(unsigned int irq)
        }
 }
 
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+       return 0;
+}
+
 static struct irq_chip intc_irq_chip = {
        .name           = "CF-INTC",
        .mask           = intc_irq_mask,
        .unmask         = intc_irq_unmask,
+       .set_type       = intc_irq_set_type,
 };
 
 void __init init_IRQ(void)
@@ -81,13 +113,14 @@ void __init init_IRQ(void)
 
        /* Mask all interrupt sources */
        __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
        __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
 
        for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_desc[irq].status = IRQ_DISABLED;
-               irq_desc[irq].action = NULL;
-               irq_desc[irq].depth = 1;
-               irq_desc[irq].chip = &intc_irq_chip;
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
index 1b01e79c2f633a75540457a7d1d10f066f26002e..bb7048636140384b96ac754132a5a88836c71565 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * intc-simr.c
  *
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
  * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -68,11 +70,9 @@ void __init init_IRQ(void)
                __raw_writeb(0xff, MCFINTC1_SIMR);
 
        for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_desc[irq].status = IRQ_DISABLED;
-               irq_desc[irq].action = NULL;
-               irq_desc[irq].depth = 1;
-               irq_desc[irq].chip = &intc_irq_chip;
-               intc_irq_set_type(irq, 0);
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
index a4560c86db714f121074c7543ae300ed7bad8a41..60d2fcbe182b37efb906ebccbce79f5a62a1d1a9 100644 (file)
@@ -143,11 +143,9 @@ void __init init_IRQ(void)
        mcf_maskimr(0xffffffff);
 
        for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_desc[irq].status = IRQ_DISABLED;
-               irq_desc[irq].action = NULL;
-               irq_desc[irq].depth = 1;
-               irq_desc[irq].chip = &intc_irq_chip;
-               intc_irq_set_type(irq, 0);
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68knommu/platform/coldfire/sltimers.c
new file mode 100644 (file)
index 0000000..0a1b937
--- /dev/null
@@ -0,0 +1,145 @@
+/***************************************************************************/
+
+/*
+ *     sltimers.c -- generic ColdFire slice timer support.
+ *
+ *     Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ *     based on
+ *     timers.c -- generic ColdFire hardware timer support.
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ *     By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define        PA(a)   (MCF_MBAR + MCFSLT_TIMER1 + (a))
+
+/*
+ *     Choose a reasonably fast profile timer. Make it an odd value to
+ *     try and get good coverage of kernel operations.
+ */
+#define        PROFILEHZ       1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 1 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+       .name    = "profile timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+       printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+              PROFILEHZ);
+
+       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+       /* Set up TIMER 2 as high speed profile clock */
+       __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               PA(MCFSLT_SCR));
+
+}
+
+#endif /* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ *     By default use Slice Timer 0 as the system clock timer.
+ */
+#define        TA(a)   (MCF_MBAR + MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 0 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+       mcfslt_cnt += mcfslt_cycles_per_jiffy;
+       return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 scnt;
+
+       local_irq_save(flags);
+       scnt = __raw_readl(TA(MCFSLT_SCNT));
+       cycles = mcfslt_cnt;
+       local_irq_restore(flags);
+
+       /* substract because slice timers count down */
+       return cycles - scnt;
+}
+
+static struct clocksource mcfslt_clk = {
+       .name   = "slt",
+       .rating = 250,
+       .read   = mcfslt_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(void)
+{
+       mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+       /*
+        *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
+        *      then STCNT again and so on.  It counts thus actually
+        *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
+        *      n cycles, initialize STCNT with n - 1.
+        */
+       __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               TA(MCFSLT_SCR));
+       /* initialize mcfslt_cnt knowing that slice timers count down */
+       mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+       mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
+       clocksource_register(&mcfslt_clk);
+
+#ifdef CONFIG_HIGHPROFILE
+       mcfslt_profile_init();
+#endif
+}
index 692fdfce2a2357122119429ceb36779f13640560..dad40fc2bef80d1ca73bff62e5b60a6dc1af1dc8 100644 (file)
@@ -121,6 +121,23 @@ config CMDLINE_FORCE
          Set this to have arguments from the default kernel command string
          override those passed by the boot loader.
 
+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.
+
 endmenu
 
 menu "Advanced setup"
index e6e5e0da28c3c06dad4463d4fb110c0d1a19ecf9..e66e25c4b0b2d0c812b471baca0deb95faf6be51 100644 (file)
@@ -10,7 +10,7 @@ source "lib/Kconfig.debug"
 
 config EARLY_PRINTK
        bool "Early printk function for kernel"
-       depends on SERIAL_UARTLITE_CONSOLE
+       depends on SERIAL_UARTLITE_CONSOLE || SERIAL_8250_CONSOLE
        default n
        help
          This option turns on/off early printk messages to console.
index 592c7079de889a435d96850f357fff666328fe5e..15f1f1d1840d065c14233d43e43b6dcf230bae5d 100644 (file)
@@ -42,11 +42,8 @@ KBUILD_CFLAGS += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
 LDFLAGS                :=
 LDFLAGS_vmlinux        :=
 
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
 head-y := arch/microblaze/kernel/head.o
 libs-y += arch/microblaze/lib/
-libs-y += $(LIBGCC)
 core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
@@ -72,12 +69,16 @@ export MMU DTB
 
 all: linux.bin
 
-BOOT_TARGETS = linux.bin linux.bin.gz simpleImage.%
+# With make 3.82 we cannot mix normal and wildcard targets
+BOOT_TARGETS1 = linux.bin linux.bin.gz
+BOOT_TARGETS2 = simpleImage.%
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
-$(BOOT_TARGETS): vmlinux
+$(BOOT_TARGETS1): vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+$(BOOT_TARGETS2): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 define archhelp
index ce9c58732ffcdec6888854e4f33a7c81a75b12da..31902762a42699079fd1d40d0a3416a0e4d4d1c0 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _ASM_MICROBLAZE_BYTEORDER_H
 #define _ASM_MICROBLAZE_BYTEORDER_H
 
+#ifdef __MICROBLAZEEL__
+#include <linux/byteorder/little_endian.h>
+#else
 #include <linux/byteorder/big_endian.h>
+#endif
 
 #endif /* _ASM_MICROBLAZE_BYTEORDER_H */
index 128bf03b54b7e9435abe99f8af19ef4eae91b611..0185cbefdda48a2770703709ed1d9701208362a0 100644 (file)
@@ -24,8 +24,13 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
                "addc %0, %0, %3\n\t"
                "addc %0, %0, r0\n\t"
                : "+&d" (sum)
-               : "d" (saddr), "d" (daddr), "d" (len + proto));
-
+               : "d" (saddr), "d" (daddr),
+#ifdef __MICROBLAZEEL__
+       "d" ((len + proto) << 8)
+#else
+       "d" (len + proto)
+#endif
+);
        return sum;
 }
 
index b4f5ca33aebf09a831226022ae0b9513c8344322..cd257537ae5445a4fcd1cbf0defa4d5407b08102 100644 (file)
@@ -38,6 +38,7 @@ struct cpuinfo {
        u32 use_exc;
        u32 ver_code;
        u32 mmu;
+       u32 endian;
 
        /* CPU caches */
        u32 use_icache;
@@ -76,7 +77,6 @@ struct cpuinfo {
        u32 num_rd_brk;
        u32 num_wr_brk;
        u32 cpu_clock_freq; /* store real freq of cpu */
-       u32 freq_div_hz; /* store freq/HZ */
 
        /* FPGA family */
        u32 fpga_family_code;
@@ -97,7 +97,8 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu);
 static inline unsigned int fcpu(struct device_node *cpu, char *n)
 {
        int *val;
-       return (val = (int *) of_get_property(cpu, n, NULL)) ? *val : 0;
+       return (val = (int *) of_get_property(cpu, n, NULL)) ?
+                                                       be32_to_cpup(val) : 0;
 }
 
 #endif /* _ASM_MICROBLAZE_CPUINFO_H */
index 732caf1be741fc1ede77bbfe14972a19c3044eb0..098dfdde4b061e067c56ad2a5ce0016a98fa8ff1 100644 (file)
@@ -71,7 +71,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #define ELF_ET_DYN_BASE         (0x08000000)
 
-#ifdef __LITTLE_ENDIAN__
+#ifdef __MICROBLAZEEL__
 #define ELF_DATA       ELFDATA2LSB
 #else
 #define ELF_DATA       ELFDATA2MSB
index 2345ac354d9be3b865e0477c206b46630bca50a1..2b2c18be71c6512e84ea0007bfb994941f399c7c 100644 (file)
@@ -38,12 +38,9 @@ static inline int gpio_cansleep(unsigned int gpio)
        return __gpio_cansleep(gpio);
 }
 
-/*
- * Not implemented, yet.
- */
 static inline int gpio_to_irq(unsigned int gpio)
 {
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
index 00b5398d08c79336761eaaf9954d1c260597459a..eae32220f44782d089a6a5bd1d0ca687442f49de 100644 (file)
@@ -243,6 +243,8 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
 #define out_8(a, v) __raw_writeb((v), (a))
 #define in_8(a) __raw_readb(a)
 
+#define mmiowb()
+
 #define ioport_map(port, nr)   ((void __iomem *)(port))
 #define ioport_unmap(addr)
 
index cf377d91da7132a7c084abea14aab85e35f79179..ed9d0f6e2cdb2be99cda93a20eb8987faf393a9c 100644 (file)
@@ -205,9 +205,6 @@ extern int page_is_ram(unsigned long pfn);
 #define TOPHYS(addr)  __virt_to_phys(addr)
 
 #ifdef CONFIG_MMU
-#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
-#define WANT_PAGE_VIRTUAL 1 /* page alloc 2 relies on this */
-#endif
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
index 5a388eeeb28fa3735912e741efb6389de28877c2..2232ff942ba9e58b2b0d657d3e92260cc9875fe8 100644 (file)
@@ -165,5 +165,7 @@ extern void __init xilinx_pci_init(void);
 static inline void __init xilinx_pci_init(void) { return; }
 #endif
 
+#include <asm-generic/pci-dma-compat.h>
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_MICROBLAZE_PCI_H */
index c614a893f8a3d40179be89d162a2879bfff19db9..ebd35792482c104678dabdab9324002dc7ae2a31 100644 (file)
@@ -165,7 +165,8 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
 
 #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
 
-#define pmd_populate(mm, pmd, pte)     (pmd_val(*(pmd)) = page_address(pte))
+#define pmd_populate(mm, pmd, pte) \
+                       (pmd_val(*(pmd)) = (unsigned long)page_address(pte))
 
 #define pmd_populate_kernel(mm, pmd, pte) \
                (pmd_val(*(pmd)) = (unsigned long) (pte))
index ca2d92871545821affe833848788e976b8c2f09a..cae268c22ba283513f967461a0e3132be739a6b9 100644 (file)
@@ -57,6 +57,13 @@ static inline int pte_file(pte_t pte) { return 0; }
 
 #define pgprot_noncached_wc(prot)      prot
 
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define        VMALLOC_START   0
+#define        VMALLOC_END     0xffffffff
+
 #else /* CONFIG_MMU */
 
 #include <asm-generic/4level-fixup.h>
@@ -497,12 +504,9 @@ static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
 #define pte_offset_kernel(dir, addr)   \
        ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir, addr)              \
-       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr)       \
-       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+       ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
 
-#define pte_unmap(pte)         kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte)  kunmap_atomic(pte, KM_PTE1)
+#define pte_unmap(pte)         kunmap_atomic(pte)
 
 /* Encode and decode a nonlinear file mapping entry */
 #define PTE_FILE_MAX_BITS      29
index 101fa098f62af7576f05b694a346e80349ae2c2d..bdc38312ae4ae00b677328c1eab1524f3cfd75a8 100644 (file)
@@ -27,6 +27,7 @@
 
 /* Other Prototypes */
 extern int early_uartlite_console(void);
+extern int early_uart16550_console(void);
 
 #ifdef CONFIG_PCI
 /*
index 9578666e98baff8f3051a694101d07bb0732eb39..37db96a15b4544fdf7c08e869d440a698340a6ad 100644 (file)
@@ -30,7 +30,9 @@ struct pvr_s {
 #define PVR0_USE_EXC_MASK              0x04000000
 #define PVR0_USE_ICACHE_MASK           0x02000000
 #define PVR0_USE_DCACHE_MASK           0x01000000
-#define PVR0_USE_MMU                   0x00800000      /* new */
+#define PVR0_USE_MMU                   0x00800000
+#define PVR0_USE_BTC                   0x00400000
+#define PVR0_ENDI                      0x00200000
 #define PVR0_VERSION_MASK              0x0000FF00
 #define PVR0_USER1_MASK                        0x000000FF
 
@@ -38,9 +40,9 @@ struct pvr_s {
 #define PVR1_USER2_MASK                        0xFFFFFFFF
 
 /* Configuration PVR masks */
-#define PVR2_D_OPB_MASK                        0x80000000
+#define PVR2_D_OPB_MASK                        0x80000000 /* or AXI */
 #define PVR2_D_LMB_MASK                        0x40000000
-#define PVR2_I_OPB_MASK                        0x20000000
+#define PVR2_I_OPB_MASK                        0x20000000 /* or AXI */
 #define PVR2_I_LMB_MASK                        0x10000000
 #define PVR2_INTERRUPT_IS_EDGE_MASK    0x08000000
 #define PVR2_EDGE_IS_POSITIVE_MASK     0x04000000
@@ -63,8 +65,8 @@ struct pvr_s {
 #define PVR2_OPCODE_0x0_ILL_MASK       0x00000040
 #define PVR2_UNALIGNED_EXC_MASK                0x00000020
 #define PVR2_ILL_OPCODE_EXC_MASK       0x00000010
-#define PVR2_IOPB_BUS_EXC_MASK         0x00000008
-#define PVR2_DOPB_BUS_EXC_MASK         0x00000004
+#define PVR2_IOPB_BUS_EXC_MASK         0x00000008 /* or AXI */
+#define PVR2_DOPB_BUS_EXC_MASK         0x00000004 /* or AXI */
 #define PVR2_DIV_ZERO_EXC_MASK         0x00000002
 #define PVR2_FPU_EXC_MASK              0x00000001
 
@@ -208,6 +210,8 @@ struct pvr_s {
 #define PVR_MMU_TLB_ACCESS(pvr)        (pvr.pvr[11] & PVR11_MMU_TLB_ACCESS)
 #define PVR_MMU_ZONES(pvr)     (pvr.pvr[11] & PVR11_MMU_ZONES)
 
+/* endian */
+#define PVR_ENDIAN(pvr)        (pvr.pvr[0] & PVR0_ENDI)
 
 int cpu_has_pvr(void);
 void get_pvr(struct pvr_s *pvr);
diff --git a/arch/microblaze/include/asm/seccomp.h b/arch/microblaze/include/asm/seccomp.h
new file mode 100644 (file)
index 0000000..0d91275
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _ASM_MICROBLAZE_SECCOMP_H
+#define _ASM_MICROBLAZE_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read              __NR_read
+#define __NR_seccomp_write             __NR_write
+#define __NR_seccomp_exit              __NR_exit
+#define __NR_seccomp_sigreturn         __NR_sigreturn
+
+#define __NR_seccomp_read_32           __NR_read
+#define __NR_seccomp_write_32          __NR_write
+#define __NR_seccomp_exit_32           __NR_exit
+#define __NR_seccomp_sigreturn_32      __NR_sigreturn
+
+#endif /* _ASM_MICROBLAZE_SECCOMP_H */
index 782b5c89248e1f5222a83192f1608ce110adedcc..8f3968971e4eef6334b5f014fd1d0aef1cf27537 100644 (file)
@@ -25,6 +25,12 @@ void early_printk(const char *fmt, ...);
 int setup_early_printk(char *opt);
 void disable_early_printk(void);
 
+#if defined(CONFIG_EARLY_PRINTK)
+#define eprintk early_printk
+#else
+#define eprintk printk
+#endif
+
 void heartbeat(void);
 void setup_heartbeat(void);
 
index 8a8e9fc6e0c04ad7f87db735cc08a23e2fe6d7e9..b73da2ac21b34e350439b2ec4359ba5454a5cf16 100644 (file)
@@ -127,23 +127,19 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SECCOMP            10      /* secure computing */
 #define TIF_FREEZE             14      /* Freezing for suspend */
 
-/* FIXME change in entry.S */
-#define TIF_KERNEL_TRACE       8       /* kernel trace active */
-
 /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_POLLING_NRFLAG     16
 
-#define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
-#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
-#define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
-#define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
-#define _TIF_IRET              (1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE            (1<<TIF_FREEZE)
+#define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
+#define _TIF_IRET              (1 << TIF_IRET)
+#define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE            (1 << TIF_FREEZE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
-#define _TIF_KERNEL_TRACE      (1 << TIF_KERNEL_TRACE)
 
 /* work to do in syscall trace */
 #define _TIF_WORK_SYSCALL_MASK  (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
index 3658d91ac0fb95ead00dbc3bca4fd9e0b8d36457..2b97cbe500e9a4e92dc6f556129dc7d8b630d8fe 100644 (file)
 
 # ifdef __KERNEL__
 
-# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/be_byteshift.h>
 # include <linux/unaligned/le_byteshift.h>
 # include <linux/unaligned/generic.h>
 
-# define get_unaligned __get_unaligned_be
-# define put_unaligned __put_unaligned_be
+
+#  ifdef __MICROBLAZEEL__
+#   define get_unaligned       __get_unaligned_le
+#   define put_unaligned       __put_unaligned_le
+#  else
+#   define get_unaligned       __get_unaligned_be
+#   define put_unaligned       __put_unaligned_be
+#  endif
 
 # endif        /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_UNALIGNED_H */
index 2b67e92a773c25ae4864fa2d30310d4647da3c13..d770b00ec6b1d6137699298cc36580912995b63a 100644 (file)
 #define __NR_rt_tgsigqueueinfo 365 /* new */
 #define __NR_perf_event_open   366 /* new */
 #define __NR_recvmmsg          367 /* new */
+#define __NR_fanotify_init     368
+#define __NR_fanotify_mark     369
+#define __NR_prlimit64         370
 
-#define __NR_syscalls          368
+#define __NR_syscalls          371
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
index f72dbd66c84411041c59705f72d253ee896af574..f70a6047f08e3e581b32dd65866ad4ebf45e5423 100644 (file)
@@ -72,6 +72,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
        CI(pvr_user2, USER2);
 
        CI(mmu, USE_MMU);
+       CI(endian, ENDIAN);
 
        CI(use_icache, USE_ICACHE);
        CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
index 6095aa6b5c88ef17d6cdab7d7393d49dfd0ee286..b16b994ca3d25b81165b1d95492e0c550cc9d14e 100644 (file)
@@ -119,6 +119,7 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
        ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
 
        ci->mmu = fcpu(cpu, "xlnx,use-mmu");
+       ci->endian = fcpu(cpu, "xlnx,endianness");
 
        ci->ver_code = 0;
        ci->fpga_family_code = 0;
index 255ef880351e793b38ef9b3e853c8c30f6ed40be..87c79fa275c38b79ec0674fdd488ad7887d6b11c 100644 (file)
@@ -30,6 +30,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"7.20.c", 0x0e},
        {"7.20.d", 0x0f},
        {"7.30.a", 0x10},
+       {"7.30.b", 0x11},
+       {"8.00.a", 0x12},
        {NULL, 0},
 };
 
index 7086e356428163bc77d9ddaee75b2f7565249a12..b4048af026158e79c1422b0553d540d30f53da13 100644 (file)
@@ -51,11 +51,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        count = seq_printf(m,
                        "CPU-Family:    MicroBlaze\n"
                        "FPGA-Arch:     %s\n"
-                       "CPU-Ver:       %s\n"
+                       "CPU-Ver:       %s, %s endian\n"
                        "CPU-MHz:       %d.%02d\n"
                        "BogoMips:      %lu.%02lu\n",
                        fpga_family,
                        cpu_ver,
+                       cpuinfo.endian ? "little" : "big",
                        cpuinfo.cpu_clock_freq /
                        1000000,
                        cpuinfo.cpu_clock_freq %
index 9bee9382bf74587031e01fde8e828f243683d147..e01afa68273ede2302d7cd6da97f0c63430f7eaa 100644 (file)
@@ -27,7 +27,7 @@
        register unsigned tmp __asm__("r3");                    \
        tmp = 0x0;      /* Prevent warning about unused */      \
        __asm__ __volatile__ (                                  \
-                       ".byte 0x94,0x60,0xa0, " #pvrid "\n\t"  \
+                       "mfs    %0, rpvr" #pvrid ";"    \
                        : "=r" (tmp) : : "memory");             \
        val = tmp;                                              \
 }
index 7de84923ba07d90b60406c05a777030c1204b5a6..c3616a080ebfcad71bbc9b950b40ba64e6da8218 100644 (file)
@@ -24,7 +24,8 @@
 static u32 early_console_initialized;
 static u32 base_addr;
 
-static void early_printk_putc(char c)
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void early_printk_uartlite_putc(char c)
 {
        /*
         * Limit how many times we'll spin waiting for TX FIFO status.
@@ -45,25 +46,70 @@ static void early_printk_putc(char c)
                out_be32(base_addr + 4, c & 0xff);
 }
 
-static void early_printk_write(struct console *unused,
+static void early_printk_uartlite_write(struct console *unused,
                                        const char *s, unsigned n)
 {
        while (*s && n-- > 0) {
-               early_printk_putc(*s);
+               early_printk_uartlite_putc(*s);
                if (*s == '\n')
-                       early_printk_putc('\r');
+                       early_printk_uartlite_putc('\r');
                s++;
        }
 }
 
-static struct console early_serial_console = {
+static struct console early_serial_uartlite_console = {
        .name = "earlyser",
-       .write = early_printk_write,
+       .write = early_printk_uartlite_write,
        .flags = CON_PRINTBUFFER,
        .index = -1,
 };
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
 
-static struct console *early_console = &early_serial_console;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static void early_printk_uart16550_putc(char c)
+{
+       /*
+        * Limit how many times we'll spin waiting for TX FIFO status.
+        * This will prevent lockups if the base address is incorrectly
+        * set, or any other issue on the UARTLITE.
+        * This limit is pretty arbitrary, unless we are at about 10 baud
+        * we'll never timeout on a working UART.
+        */
+
+       #define UART_LSR_TEMT   0x40 /* Transmitter empty */
+       #define UART_LSR_THRE   0x20 /* Transmit-hold-register empty */
+       #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+       unsigned retries = 10000;
+
+       while (--retries &&
+               !((in_be32(base_addr + 0x14) & BOTH_EMPTY) == BOTH_EMPTY))
+               ;
+
+       if (retries)
+               out_be32(base_addr, c & 0xff);
+}
+
+static void early_printk_uart16550_write(struct console *unused,
+                                       const char *s, unsigned n)
+{
+       while (*s && n-- > 0) {
+               early_printk_uart16550_putc(*s);
+               if (*s == '\n')
+                       early_printk_uart16550_putc('\r');
+               s++;
+       }
+}
+
+static struct console early_serial_uart16550_console = {
+       .name = "earlyser",
+       .write = early_printk_uart16550_write,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+};
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+static struct console *early_console;
 
 void early_printk(const char *fmt, ...)
 {
@@ -84,20 +130,43 @@ int __init setup_early_printk(char *opt)
        if (early_console_initialized)
                return 1;
 
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
        base_addr = early_uartlite_console();
        if (base_addr) {
                early_console_initialized = 1;
 #ifdef CONFIG_MMU
                early_console_reg_tlb_alloc(base_addr);
 #endif
+               early_console = &early_serial_uartlite_console;
                early_printk("early_printk_console is enabled at 0x%08x\n",
                                                        base_addr);
 
                /* register_console(early_console); */
 
                return 0;
-       } else
-               return 1;
+       }
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       base_addr = early_uart16550_console();
+       base_addr &= ~3; /* clear register offset */
+       if (base_addr) {
+               early_console_initialized = 1;
+#ifdef CONFIG_MMU
+               early_console_reg_tlb_alloc(base_addr);
+#endif
+               early_console = &early_serial_uart16550_console;
+
+               early_printk("early_printk_console is enabled at 0x%08x\n",
+                                                       base_addr);
+
+               /* register_console(early_console); */
+
+               return 0;
+       }
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+       return 1;
 }
 
 void __init disable_early_printk(void)
index 304882e56459b70d90b661622b54066452a38d74..819238b8a429c6ce55567fa762fb8b12ca11644c 100644 (file)
        swi     r13, r1, PTO+PT_R13;    /* Save SDA2 */                 \
        swi     r14, r1, PTO+PT_PC;     /* PC, before IRQ/trap */       \
        swi     r15, r1, PTO+PT_R15;    /* Save LP */                   \
+       swi     r16, r1, PTO+PT_R16;                                    \
+       swi     r17, r1, PTO+PT_R17;                                    \
        swi     r18, r1, PTO+PT_R18;    /* Save asm scratch reg */      \
        swi     r19, r1, PTO+PT_R19;                                    \
        swi     r20, r1, PTO+PT_R20;                                    \
        lwi     r13, r1, PTO+PT_R13;    /* restore SDA2 */              \
        lwi     r14, r1, PTO+PT_PC;     /* RESTORE_LINK PC, before IRQ/trap */\
        lwi     r15, r1, PTO+PT_R15;    /* restore LP */                \
+       lwi     r16, r1, PTO+PT_R16;                                    \
+       lwi     r17, r1, PTO+PT_R17;                                    \
        lwi     r18, r1, PTO+PT_R18;    /* restore asm scratch reg */   \
        lwi     r19, r1, PTO+PT_R19;                                    \
        lwi     r20, r1, PTO+PT_R20;                                    \
@@ -295,6 +299,8 @@ C_ENTRY(_user_exception):
        /* addik        r1, r1, -STATE_SAVE_SIZE; */
        addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
        SAVE_REGS
+       swi     r0, r1, PTO + PT_R3
+       swi     r0, r1, PTO + PT_R4
 
        lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
        swi     r11, r1, PTO+PT_R1;             /* Store user SP.  */
@@ -458,14 +464,8 @@ C_ENTRY(sys_execve):
        addik   r8, r1, PTO;            /* add user context as 4th arg */
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       brlid   r15, sys_rt_sigreturn   /* Do real work */
+       brid    sys_rt_sigreturn        /* Do real work */
        addik   r5, r1, PTO;            /* add user context as 1st arg */
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
-       nop;
 
 /*
  * HW EXCEPTION rutine start
@@ -765,9 +765,7 @@ C_ENTRY(_debug_exception):
        /* save all regs to pt_reg structure */
        swi     r0, r1, PTO+PT_R0;      /* R0 must be saved too */
        swi     r14, r1, PTO+PT_R14     /* rewrite saved R14 value */
-       swi     r16, r1, PTO+PT_R16
        swi     r16, r1, PTO+PT_PC; /* PC and r16 are the same */
-       swi     r17, r1, PTO+PT_R17
        /* save special purpose registers to pt_regs */
        mfs     r11, rear;
        swi     r11, r1, PTO+PT_EAR;
@@ -801,8 +799,6 @@ C_ENTRY(_debug_exception):
 
        addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
        SAVE_REGS;
-       swi     r17, r1, PTO+PT_R17;
-       swi     r16, r1, PTO+PT_R16;
        swi     r16, r1, PTO+PT_PC;     /* Save LP */
        swi     r0, r1, PTO + PT_MODE; /* Was in user-mode.  */
        lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
@@ -848,8 +844,6 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
        tophys(r1,r1);
        /* MS: Restore all regs */
        RESTORE_REGS
-       lwi     r17, r1, PTO+PT_R17;
-       lwi     r16, r1, PTO+PT_R16;
        addik   r1, r1, STATE_SAVE_SIZE  /* Clean up stack space */
        lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
 DBTRAP_return_user: /* MS: Make global symbol for debugging */
@@ -863,7 +857,6 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */
        RESTORE_REGS
        lwi     r14, r1, PTO+PT_R14;
        lwi     r16, r1, PTO+PT_PC;
-       lwi     r17, r1, PTO+PT_R17;
        addik   r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
        tovirt(r1,r1);
 DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
index b98ee8d0c1cdcdf96f4e4f4a394dcde6adb7c3bb..478f2943ede77d3e5b6a507e6bec662dd7f1424c 100644 (file)
@@ -72,7 +72,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                                                        int fsr, int addr)
 {
 #ifdef CONFIG_MMU
-       int code;
        addr = regs->pc;
 #endif
 
@@ -86,8 +85,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
        switch (type & 0x1F) {
        case MICROBLAZE_ILL_OPCODE_EXCEPTION:
                if (user_mode(regs)) {
-                       pr_debug(KERN_WARNING "Illegal opcode exception " \
-                                                       "in user mode.\n");
+                       pr_debug("Illegal opcode exception in user mode\n");
                        _exception(SIGILL, regs, ILL_ILLOPC, addr);
                        return;
                }
@@ -97,8 +95,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                break;
        case MICROBLAZE_IBUS_EXCEPTION:
                if (user_mode(regs)) {
-                       pr_debug(KERN_WARNING "Instruction bus error " \
-                                               "exception in user mode.\n");
+                       pr_debug("Instruction bus error exception in user mode\n");
                        _exception(SIGBUS, regs, BUS_ADRERR, addr);
                        return;
                }
@@ -108,8 +105,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                break;
        case MICROBLAZE_DBUS_EXCEPTION:
                if (user_mode(regs)) {
-                       pr_debug(KERN_WARNING "Data bus error exception " \
-                                                       "in user mode.\n");
+                       pr_debug("Data bus error exception in user mode\n");
                        _exception(SIGBUS, regs, BUS_ADRERR, addr);
                        return;
                }
@@ -119,8 +115,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                break;
        case MICROBLAZE_DIV_ZERO_EXCEPTION:
                if (user_mode(regs)) {
-                       pr_debug(KERN_WARNING "Divide by zero exception " \
-                                                       "in user mode\n");
+                       pr_debug("Divide by zero exception in user mode\n");
                        _exception(SIGILL, regs, FPE_INTDIV, addr);
                        return;
                }
@@ -129,7 +124,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                die("Divide by zero exception", regs, SIGBUS);
                break;
        case MICROBLAZE_FPU_EXCEPTION:
-               pr_debug(KERN_WARNING "FPU exception\n");
+               pr_debug("FPU exception\n");
                /* IEEE FP exception */
                /* I removed fsr variable and use code var for storing fsr */
                if (fsr & FSR_IO)
@@ -147,14 +142,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
 
 #ifdef CONFIG_MMU
        case MICROBLAZE_PRIVILEGED_EXCEPTION:
-               pr_debug(KERN_WARNING "Privileged exception\n");
-               /* "brk r0,r0" - used as debug breakpoint - old toolchain */
-               if (get_user(code, (unsigned long *)regs->pc) == 0
-                       && code == 0x980c0000) {
-                       _exception(SIGTRAP, regs, TRAP_BRKPT, addr);
-               } else {
-                       _exception(SIGILL, regs, ILL_PRVOPC, addr);
-               }
+               pr_debug("Privileged exception\n");
+               _exception(SIGILL, regs, ILL_PRVOPC, addr);
                break;
 #endif
        default:
index 522751737cfad936fe5193a93fd0105c874c04cc..154756f3c6945a51eee059ec1b7349c9e326c129 100644 (file)
@@ -47,11 +47,10 @@ void setup_heartbeat(void)
        struct device_node *gpio = NULL;
        int *prop;
        int j;
-       char *gpio_list[] = {
-                               "xlnx,xps-gpio-1.00.a",
-                               "xlnx,opb-gpio-1.00.a",
-                               NULL
-                       };
+       const char * const gpio_list[] = {
+               "xlnx,xps-gpio-1.00.a",
+               NULL
+       };
 
        for (j = 0; gpio_list[j] != NULL; j++) {
                gpio = of_find_compatible_node(NULL, NULL, gpio_list[j]);
@@ -60,7 +59,7 @@ void setup_heartbeat(void)
        }
 
        if (gpio) {
-               base_addr = *(int *) of_get_property(gpio, "reg", NULL);
+               base_addr = be32_to_cpup(of_get_property(gpio, "reg", NULL));
                base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
                printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
 
index 03172c1da770c69eda75e8c72aca7a648c7ada53..d61ea33aff7cd3a9de120710a89cd51e8c03b40d 100644 (file)
@@ -126,11 +126,8 @@ void __init init_IRQ(void)
                                0
                        };
 #endif
-       static char *intc_list[] = {
+       const char * const intc_list[] = {
                                "xlnx,xps-intc-1.00.a",
-                               "xlnx,opb-intc-1.00.c",
-                               "xlnx,opb-intc-1.00.b",
-                               "xlnx,opb-intc-1.00.a",
                                NULL
                        };
 
@@ -141,12 +138,15 @@ void __init init_IRQ(void)
        }
        BUG_ON(!intc);
 
-       intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL);
+       intc_baseaddr = be32_to_cpup(of_get_property(intc,
+                                                               "reg", NULL));
        intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
-       nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL);
+       nr_irq = be32_to_cpup(of_get_property(intc,
+                                               "xlnx,num-intr-inputs", NULL));
 
        intr_type =
-               *(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL);
+               be32_to_cpup(of_get_property(intc,
+                                               "xlnx,kind-of-intr", NULL));
        if (intr_type >= (1 << (nr_irq + 1)))
                printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
 
index bfc006b7f2d8b74e0ce0196a1226549435fced23..09a5e82861371ef35e3589ab89b534575ee162be 100644 (file)
@@ -80,7 +80,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 void microblaze_kgdb_break(struct pt_regs *regs)
 {
        if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
-               return 0;
+               return;
 
        /* Jump over the first arch_kgdb_breakpoint which is barrier to
         * get kgdb work. The same solution is used for powerpc */
@@ -114,7 +114,6 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
 {
        char *ptr;
        unsigned long address;
-       int cpu = smp_processor_id();
 
        switch (remcom_in_buffer[0]) {
        case 'c':
@@ -143,5 +142,9 @@ void kgdb_arch_exit(void)
  * Global data
  */
 struct kgdb_arch arch_kgdb_ops = {
+#ifdef __MICROBLAZEEL__
+       .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
+#else
        .gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
+#endif
 };
index ff85f77180355fe6ba8a6c5c1cdeecfa25b5fa75..5cb034174005a4be062b188cb6f358a0c1f095a9 100644 (file)
 #include <linux/syscalls.h>
 
 #include <asm/checksum.h>
+#include <asm/cacheflush.h>
 #include <linux/io.h>
 #include <asm/page.h>
 #include <asm/system.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
-/*
- * libgcc functions - functions that are used internally by the
- * compiler... (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-EXPORT_SYMBOL(__ashldi3);
-extern void __ashrdi3(void);
-EXPORT_SYMBOL(__ashrdi3);
-extern void __divsi3(void);
-EXPORT_SYMBOL(__divsi3);
-extern void __lshrdi3(void);
-EXPORT_SYMBOL(__lshrdi3);
-extern void __modsi3(void);
-EXPORT_SYMBOL(__modsi3);
-extern void __mulsi3(void);
-EXPORT_SYMBOL(__mulsi3);
-extern void __muldi3(void);
-EXPORT_SYMBOL(__muldi3);
-extern void __ucmpdi2(void);
-EXPORT_SYMBOL(__ucmpdi2);
-extern void __udivsi3(void);
-EXPORT_SYMBOL(__udivsi3);
-extern void __umodsi3(void);
-EXPORT_SYMBOL(__umodsi3);
 extern char *_ebss;
 EXPORT_SYMBOL_GPL(_ebss);
 #ifdef CONFIG_FUNCTION_TRACER
@@ -63,3 +39,9 @@ EXPORT_SYMBOL(__strncpy_user);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 #endif
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(empty_zero_page);
+#endif
+
+EXPORT_SYMBOL(mbc);
index 427b13b4740f822c95362f10a2510359e75fbd0a..a105301e2b7fec6465daa9ac89c06a20b65cd59f 100644 (file)
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
 
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
-{
-       /* No Microblaze specific code here */
-}
-
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
        memblock_add(base, size);
@@ -77,11 +72,12 @@ static int __init early_init_dt_scan_serial(unsigned long node,
 /* find compatible node with uartlite */
        p = of_get_flat_dt_prop(node, "compatible", &l);
        if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
-                       (strncmp(p, "xlnx,opb-uartlite", 17) != 0))
+                       (strncmp(p, "xlnx,opb-uartlite", 17) != 0) &&
+                       (strncmp(p, "xlnx,axi-uartlite", 17) != 0))
                return 0;
 
        addr = of_get_flat_dt_prop(node, "reg", &l);
-       return *addr; /* return address */
+       return be32_to_cpup(addr); /* return address */
 }
 
 /* this function is looking for early uartlite console - Microblaze specific */
@@ -89,6 +85,40 @@ int __init early_uartlite_console(void)
 {
        return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
 }
+
+/* MS this is Microblaze specifig function */
+static int __init early_init_dt_scan_serial_full(unsigned long node,
+                               const char *uname, int depth, void *data)
+{
+       unsigned long l;
+       char *p;
+       unsigned int addr;
+
+       pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+/* find all serial nodes */
+       if (strncmp(uname, "serial", 6) != 0)
+               return 0;
+
+       early_init_dt_check_for_initrd(node);
+
+/* find compatible node with uartlite */
+       p = of_get_flat_dt_prop(node, "compatible", &l);
+
+       if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) &&
+               (strncmp(p, "xlnx,axi-uart16550", 18) != 0))
+               return 0;
+
+       addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
+       addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l);
+       return be32_to_cpu(addr); /* return address */
+}
+
+/* this function is looking for early uartlite console - Microblaze specific */
+int __init early_uart16550_console(void)
+{
+       return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL);
+}
 #endif
 
 void __init early_init_devtree(void *params)
index f5f768842354201266bf0dce0e7209484f49a4fa..bb1558e4b283f0d59f2a00bb2976427c521c845d 100644 (file)
@@ -92,12 +92,6 @@ inline unsigned get_romfs_len(unsigned *addr)
 }
 #endif /* CONFIG_MTD_UCLINUX_EBSS */
 
-#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
-#define eprintk early_printk
-#else
-#define eprintk printk
-#endif
-
 void __init machine_early_init(const char *cmdline, unsigned int ram,
                unsigned int fdt, unsigned int msr)
 {
index 03376dc814c9b406d16f12346d135e08039b2e90..e88a930fd1e393cad4847035918098072adb1d36 100644 (file)
@@ -372,3 +372,6 @@ ENTRY(sys_call_table)
        .long sys_rt_tgsigqueueinfo     /* 365 */
        .long sys_perf_event_open
        .long sys_recvmmsg
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64     /* 370 */
index b1380ae93ae13ae8bf43f4993cdd18351d5de505..a5aa33db1df3c934cfef3691d0fe494409c47642 100644 (file)
@@ -38,6 +38,9 @@ static unsigned int timer_baseaddr;
 #define TIMER_BASE     timer_baseaddr
 #endif
 
+unsigned int freq_div_hz;
+unsigned int timer_clock_freq;
+
 #define TCSR0  (0x00)
 #define TLR0   (0x04)
 #define TCR0   (0x08)
@@ -115,7 +118,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                printk(KERN_INFO "%s: periodic\n", __func__);
-               microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
+               microblaze_timer0_start_periodic(freq_div_hz);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                printk(KERN_INFO "%s: oneshot\n", __func__);
@@ -168,7 +171,7 @@ static struct irqaction timer_irqaction = {
 static __init void microblaze_clockevent_init(void)
 {
        clockevent_microblaze_timer.mult =
-               div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+               div_sc(timer_clock_freq, NSEC_PER_SEC,
                                clockevent_microblaze_timer.shift);
        clockevent_microblaze_timer.max_delta_ns =
                clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
@@ -201,7 +204,7 @@ static struct cyclecounter microblaze_cc = {
 
 int __init init_microblaze_timecounter(void)
 {
-       microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+       microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
                                microblaze_cc.shift);
 
        timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
@@ -221,7 +224,7 @@ static struct clocksource clocksource_microblaze = {
 static int __init microblaze_clocksource_init(void)
 {
        clocksource_microblaze.mult =
-                       clocksource_hz2mult(cpuinfo.cpu_clock_freq,
+                       clocksource_hz2mult(timer_clock_freq,
                                                clocksource_microblaze.shift);
        if (clocksource_register(&clocksource_microblaze))
                panic("failed to register clocksource");
@@ -247,6 +250,7 @@ void __init time_init(void)
        u32 irq, i = 0;
        u32 timer_num = 1;
        struct device_node *timer = NULL;
+       const void *prop;
 #ifdef CONFIG_SELFMOD_TIMER
        unsigned int timer_baseaddr = 0;
        int arr_func[] = {
@@ -258,12 +262,10 @@ void __init time_init(void)
                                0
                        };
 #endif
-       char *timer_list[] = {
-                               "xlnx,xps-timer-1.00.a",
-                               "xlnx,opb-timer-1.00.b",
-                               "xlnx,opb-timer-1.00.a",
-                               NULL
-                       };
+       const char * const timer_list[] = {
+               "xlnx,xps-timer-1.00.a",
+               NULL
+       };
 
        for (i = 0; timer_list[i] != NULL; i++) {
                timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
@@ -272,13 +274,13 @@ void __init time_init(void)
        }
        BUG_ON(!timer);
 
-       timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
+       timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
        timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
-       irq = *(int *) of_get_property(timer, "interrupts", NULL);
-       timer_num =
-               *(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
+       irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL));
+       timer_num = be32_to_cpup(of_get_property(timer,
+                                               "xlnx,one-timer-only", NULL));
        if (timer_num) {
-               printk(KERN_EMERG "Please enable two timers in HW\n");
+               eprintk(KERN_EMERG "Please enable two timers in HW\n");
                BUG();
        }
 
@@ -288,7 +290,14 @@ void __init time_init(void)
        printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
                timer_list[i], timer_baseaddr, irq);
 
-       cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
+       /* If there is clock-frequency property than use it */
+       prop = of_get_property(timer, "clock-frequency", NULL);
+       if (prop)
+               timer_clock_freq = be32_to_cpup(prop);
+       else
+               timer_clock_freq = cpuinfo.cpu_clock_freq;
+
+       freq_div_hz = timer_clock_freq / HZ;
 
        setup_irq(irq, &timer_irqaction);
 #ifdef CONFIG_HEART_BEAT
index a09f2962fbec7b8db901fe50c1b91ab98bb43097..96a88c31fe48f412106a7f16780c964fbf0b4e01 100644 (file)
@@ -8,7 +8,6 @@
  * for more details.
  */
 
-OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
 OUTPUT_ARCH(microblaze)
 ENTRY(microblaze_start)
 
@@ -16,7 +15,11 @@ ENTRY(microblaze_start)
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
 
+#ifdef __MICROBLAZEEL__
+jiffies = jiffies_64;
+#else
 jiffies = jiffies_64 + 4;
+#endif
 
 SECTIONS {
        . = CONFIG_KERNEL_START;
index 4dfe47d3cd916e51ad21e25eb674afea71ff8551..f1fcbff3da257af9569d577c97b6aabbb8fc94dc 100644 (file)
@@ -11,3 +11,13 @@ lib-y += memcpy.o memmove.o
 endif
 
 lib-y += uaccess_old.o
+
+lib-y += ashldi3.o
+lib-y += ashrdi3.o
+lib-y += divsi3.o
+lib-y += lshrdi3.o
+lib-y += modsi3.o
+lib-y += muldi3.o
+lib-y += mulsi3.o
+lib-y += udivsi3.o
+lib-y += umodsi3.o
diff --git a/arch/microblaze/lib/ashldi3.c b/arch/microblaze/lib/ashldi3.c
new file mode 100644 (file)
index 0000000..beb80f3
--- /dev/null
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashldi3(long long u, word_type b)
+{
+       DWunion uu, w;
+       word_type bm;
+
+       if (b == 0)
+               return u;
+
+       uu.ll = u;
+       bm = 32 - b;
+
+       if (bm <= 0) {
+               w.s.low = 0;
+               w.s.high = (unsigned int) uu.s.low << -bm;
+       } else {
+               const unsigned int carries = (unsigned int) uu.s.low >> bm;
+
+               w.s.low = (unsigned int) uu.s.low << b;
+               w.s.high = ((unsigned int) uu.s.high << b) | carries;
+       }
+
+       return w.ll;
+}
+
+EXPORT_SYMBOL(__ashldi3);
diff --git a/arch/microblaze/lib/ashrdi3.c b/arch/microblaze/lib/ashrdi3.c
new file mode 100644 (file)
index 0000000..c884a91
--- /dev/null
@@ -0,0 +1,31 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashrdi3(long long u, word_type b)
+{
+       DWunion uu, w;
+       word_type bm;
+
+       if (b == 0)
+               return u;
+
+       uu.ll = u;
+       bm = 32 - b;
+
+       if (bm <= 0) {
+               /* w.s.high = 1..1 or 0..0 */
+               w.s.high =
+                   uu.s.high >> 31;
+               w.s.low = uu.s.high >> -bm;
+       } else {
+               const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+               w.s.high = uu.s.high >> b;
+               w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+       }
+
+       return w.ll;
+}
+
+EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/microblaze/lib/divsi3.S b/arch/microblaze/lib/divsi3.S
new file mode 100644 (file)
index 0000000..595b02d
--- /dev/null
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* Divide operation for 32 bit integers.
+*      Input : Dividend in Reg r5
+*              Divisor in Reg r6
+*      Output: Result in Reg r3
+*/
+       .text
+       .globl  __divsi3
+       .type __divsi3, @function
+       .ent __divsi3
+__divsi3:
+       .frame  r1, 0, r15
+
+       addik   r1, r1, -16
+       swi     r28, r1, 0
+       swi     r29, r1, 4
+       swi     r30, r1, 8
+       swi     r31, r1, 12
+
+       beqi    r6, div_by_zero /* div_by_zero - division error */
+       beqi    r5, result_is_zero /* result is zero */
+       bgeid   r5, r5_pos
+       xor     r28, r5, r6 /* get the sign of the result */
+       rsubi   r5, r5, 0 /* make r5 positive */
+r5_pos:
+       bgei    r6, r6_pos
+       rsubi   r6, r6, 0 /* make r6 positive */
+r6_pos:
+       addik   r30, r0, 0 /* clear mod */
+       addik   r3, r0, 0 /* clear div */
+       addik   r29, r0, 32 /* initialize the loop count */
+
+       /* first part try to find the first '1' in the r5 */
+div0:
+       blti    r5, div2 /* this traps r5 == 0x80000000 */
+div1:
+       add     r5, r5, r5 /* left shift logical r5 */
+       bgtid   r5, div1
+       addik   r29, r29, -1
+div2:
+       /* left shift logical r5 get the '1' into the carry */
+       add     r5, r5, r5
+       addc    r30, r30, r30 /* move that bit into the mod register */
+       rsub    r31, r6, r30 /* try to subtract (r30 a r6) */
+       blti    r31, mod_too_small
+       /* move the r31 to mod since the result was positive */
+       or      r30, r0, r31
+       addik   r3, r3, 1
+mod_too_small:
+       addik   r29, r29, -1
+       beqi    r29, loop_end
+       add     r3, r3, r3 /* shift in the '1' into div */
+       bri     div2 /* div2 */
+loop_end:
+       bgei    r28, return_here
+       brid    return_here
+       rsubi   r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+       or      r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+       lwi     r28, r1, 0
+       lwi     r29, r1, 4
+       lwi     r30, r1, 8
+       lwi     r31, r1, 12
+       rtsd    r15, 8
+       addik   r1, r1, 16
+
+.size __divsi3, . - __divsi3
+.end __divsi3
diff --git a/arch/microblaze/lib/libgcc.h b/arch/microblaze/lib/libgcc.h
new file mode 100644 (file)
index 0000000..05909d5
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __ASM_LIBGCC_H
+#define __ASM_LIBGCC_H
+
+#include <asm/byteorder.h>
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#ifdef __BIG_ENDIAN
+struct DWstruct {
+       int high, low;
+};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct {
+       int low, high;
+};
+#else
+#error I feel sick.
+#endif
+
+typedef union {
+       struct DWstruct s;
+       long long ll;
+} DWunion;
+
+#endif /* __ASM_LIBGCC_H */
diff --git a/arch/microblaze/lib/lshrdi3.c b/arch/microblaze/lib/lshrdi3.c
new file mode 100644 (file)
index 0000000..dcf8d68
--- /dev/null
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __lshrdi3(long long u, word_type b)
+{
+       DWunion uu, w;
+       word_type bm;
+
+       if (b == 0)
+               return u;
+
+       uu.ll = u;
+       bm = 32 - b;
+
+       if (bm <= 0) {
+               w.s.high = 0;
+               w.s.low = (unsigned int) uu.s.high >> -bm;
+       } else {
+               const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+               w.s.high = (unsigned int) uu.s.high >> b;
+               w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+       }
+
+       return w.ll;
+}
+
+EXPORT_SYMBOL(__lshrdi3);
index 014bac92bdff74553595280c0be125a7b17cfcfb..cc495d7d99cc7ab142c5d9a9c950982e28d52b30 100644 (file)
 #include <asm/system.h>
 
 #ifdef __HAVE_ARCH_MEMCPY
+#ifndef CONFIG_OPT_LIB_FUNCTION
 void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
 {
        const char *src = v_src;
        char *dst = v_dst;
-#ifndef CONFIG_OPT_LIB_FUNCTION
+
        /* Simple, byte oriented memcpy. */
        while (c--)
                *dst++ = *src++;
 
        return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+       const char *src = v_src;
+       char *dst = v_dst;
+
        /* The following code tries to optimize the copy by using unsigned
         * alignment. This will work fine if both source and destination are
         * aligned on the same boundary. However, if they are aligned on
@@ -86,7 +93,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x1:       /* Unaligned - Off by 1 */
                        /* Word align the source */
                        i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *i_src++ << 8;
 
@@ -95,7 +102,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                                *i_dst++ = buf_hold | value >> 24;
                                buf_hold = value << 8;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *i_src++;
+                               *i_dst++ = buf_hold | ((value & 0xFF) << 24);
+                               buf_hold = (value & 0xFFFFFF00) >>8;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src -= 3;
@@ -103,7 +119,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x2:       /* Unaligned - Off by 2 */
                        /* Word align the source */
                        i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *i_src++ << 16;
 
@@ -112,7 +128,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                                *i_dst++ = buf_hold | value >> 16;
                                buf_hold = value << 16;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *i_src++;
+                               *i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
+                               buf_hold = (value & 0xFFFF0000) >>16;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src -= 2;
@@ -120,7 +145,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x3:       /* Unaligned - Off by 3 */
                        /* Word align the source */
                        i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *i_src++ << 24;
 
@@ -129,7 +154,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
                                *i_dst++ = buf_hold | value >> 8;
                                buf_hold = value << 24;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*i_src++ & 0xFF000000) >> 24;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *i_src++;
+                               *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
+                               buf_hold = (value & 0xFF000000) >> 24;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src -= 1;
@@ -150,7 +184,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
        }
 
        return v_dst;
-#endif
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memcpy);
 #endif /* __HAVE_ARCH_MEMCPY */
index 0929198c5e686b737a5e1bbe232652760328a403..123e3616f2dd44213b75a5471e95c810d26488ea 100644 (file)
 #include <linux/string.h>
 
 #ifdef __HAVE_ARCH_MEMMOVE
+#ifndef CONFIG_OPT_LIB_FUNCTION
 void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
 {
        const char *src = v_src;
        char *dst = v_dst;
 
-#ifdef CONFIG_OPT_LIB_FUNCTION
-       const uint32_t *i_src;
-       uint32_t *i_dst;
-#endif
-
        if (!c)
                return v_dst;
 
@@ -48,7 +44,6 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
        if (v_dst <= v_src)
                return memcpy(v_dst, v_src, c);
 
-#ifndef CONFIG_OPT_LIB_FUNCTION
        /* copy backwards, from end to beginning */
        src += c;
        dst += c;
@@ -58,7 +53,22 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                *--dst = *--src;
 
        return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+       const char *src = v_src;
+       char *dst = v_dst;
+       const uint32_t *i_src;
+       uint32_t *i_dst;
+
+       if (!c)
+               return v_dst;
+
+       /* Use memcpy when source is higher than dest */
+       if (v_dst <= v_src)
+               return memcpy(v_dst, v_src, c);
+
        /* The following code tries to optimize the copy by using unsigned
         * alignment. This will work fine if both source and destination are
         * aligned on the same boundary. However, if they are aligned on
@@ -104,7 +114,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x1:       /* Unaligned - Off by 1 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 24;
 
@@ -113,7 +123,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 8 | value;
                                buf_hold = value >> 24;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFF) << 24;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
+                               buf_hold = (value  & 0xFF) << 24;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 1;
@@ -121,7 +140,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x2:       /* Unaligned - Off by 2 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 16;
 
@@ -130,7 +149,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 16 | value;
                                buf_hold = value >> 16;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFFFF) << 16;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
+                               buf_hold = (value & 0xFFFF) << 16;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 2;
@@ -138,7 +166,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x3:       /* Unaligned - Off by 3 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 8;
 
@@ -147,7 +175,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 24 | value;
                                buf_hold = value >> 8;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFFFFFF) << 8;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
+                               buf_hold = (value & 0xFFFFFF) << 8;;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 3;
@@ -169,7 +206,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                *--dst = *--src;
        }
        return v_dst;
-#endif
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memmove);
 #endif /* __HAVE_ARCH_MEMMOVE */
index ecfb663e1fc159dc33a922b894910f4912d6ed09..834565d1607e8670cd1c6fb9e21499d224f1fb1e 100644 (file)
 #include <linux/string.h>
 
 #ifdef __HAVE_ARCH_MEMSET
+#ifndef CONFIG_OPT_LIB_FUNCTION
+void *memset(void *v_src, int c, __kernel_size_t n)
+{
+       char *src = v_src;
+
+       /* Truncate c to 8 bits */
+       c = (c & 0xFF);
+
+       /* Simple, byte oriented memset or the rest of count. */
+       while (n--)
+               *src++ = c;
+
+       return v_src;
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
 void *memset(void *v_src, int c, __kernel_size_t n)
 {
        char *src = v_src;
-#ifdef CONFIG_OPT_LIB_FUNCTION
        uint32_t *i_src;
        uint32_t w32 = 0;
-#endif
+
        /* Truncate c to 8 bits */
        c = (c & 0xFF);
 
-#ifdef CONFIG_OPT_LIB_FUNCTION
        if (unlikely(c)) {
                /* Make a repeating word out of it */
                w32 = c;
@@ -72,12 +85,13 @@ void *memset(void *v_src, int c, __kernel_size_t n)
 
                src  = (void *)i_src;
        }
-#endif
+
        /* Simple, byte oriented memset or the rest of count. */
        while (n--)
                *src++ = c;
 
        return v_src;
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memset);
 #endif /* __HAVE_ARCH_MEMSET */
diff --git a/arch/microblaze/lib/modsi3.S b/arch/microblaze/lib/modsi3.S
new file mode 100644 (file)
index 0000000..84e0bee
--- /dev/null
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* modulo operation for 32 bit integers.
+*      Input : op1 in Reg r5
+*              op2 in Reg r6
+*      Output: op1 mod op2 in Reg r3
+*/
+
+       .text
+       .globl  __modsi3
+       .type __modsi3,  @function
+       .ent __modsi3
+
+__modsi3:
+       .frame  r1, 0, r15
+
+       addik   r1, r1, -16
+       swi     r28, r1, 0
+       swi     r29, r1, 4
+       swi     r30, r1, 8
+       swi     r31, r1, 12
+
+       beqi    r6, div_by_zero /* div_by_zero division error */
+       beqi    r5, result_is_zero /* result is zero */
+       bgeid   r5, r5_pos
+       /* get the sign of the result [ depends only on the first arg] */
+       add     r28, r5, r0
+       rsubi   r5, r5, 0        /* make r5 positive */
+r5_pos:
+       bgei    r6, r6_pos
+       rsubi   r6, r6, 0        /* make r6 positive */
+r6_pos:
+       addik   r3, r0, 0 /* clear mod */
+       addik   r30, r0, 0 /* clear div */
+       addik   r29, r0, 32 /* initialize the loop count */
+/* first part try to find the first '1' in the r5 */
+div1:
+       add     r5, r5, r5 /* left shift logical r5 */
+       bgeid   r5, div1
+       addik   r29, r29, -1
+div2:
+       /* left shift logical r5 get the '1' into the carry */
+       add     r5, r5, r5
+       addc    r3, r3, r3 /* move that bit into the mod register */
+       rsub    r31, r6, r3 /* try to subtract (r30 a r6) */
+       blti    r31, mod_too_small
+       /* move the r31 to mod since the result was positive */
+       or      r3, r0, r31
+       addik   r30, r30, 1
+mod_too_small:
+       addik   r29, r29, -1
+       beqi    r29, loop_end
+       add     r30, r30, r30 /* shift in the '1' into div */
+       bri     div2 /* div2 */
+loop_end:
+       bgei    r28, return_here
+       brid    return_here
+       rsubi   r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+       or      r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+       lwi     r28, r1, 0
+       lwi     r29, r1, 4
+       lwi     r30, r1, 8
+       lwi     r31, r1, 12
+       rtsd    r15, 8
+       addik   r1, r1, 16
+
+.size __modsi3,  . - __modsi3
+.end __modsi3
diff --git a/arch/microblaze/lib/muldi3.S b/arch/microblaze/lib/muldi3.S
new file mode 100644 (file)
index 0000000..ceeaa8c
--- /dev/null
@@ -0,0 +1,121 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 64 bit integers, for devices with hard multiply
+ *     Input : Operand1[H] in Reg r5
+ *             Operand1[L] in Reg r6
+ *             Operand2[H] in Reg r7
+ *             Operand2[L] in Reg r8
+ *     Output: Result[H] in Reg r3
+ *             Result[L] in Reg r4
+ *
+ * Explaination:
+ *
+ *     Both the input numbers are divided into 16 bit number as follows
+ *             op1 = A B C D
+ *             op2 = E F G H
+ *     result = D * H
+ *              + (C * H + D * G) << 16
+ *              + (B * H + C * G + D * F) << 32
+ *              + (A * H + B * G + C * F + D * E) << 48
+ *
+ *     Only 64 bits of the output are considered
+ */
+
+       .text
+       .globl  __muldi3
+       .type __muldi3, @function
+       .ent __muldi3
+
+__muldi3:
+       addi    r1, r1, -40
+
+/* Save the input operands on the caller's stack */
+       swi     r5, r1, 44
+       swi     r6, r1, 48
+       swi     r7, r1, 52
+       swi     r8, r1, 56
+
+/* Store all the callee saved registers */
+       sw      r20, r1, r0
+       swi     r21, r1, 4
+       swi     r22, r1, 8
+       swi     r23, r1, 12
+       swi     r24, r1, 16
+       swi     r25, r1, 20
+       swi     r26, r1, 24
+       swi     r27, r1, 28
+
+/* Load all the 16 bit values for A thru H */
+       lhui    r20, r1, 44 /* A */
+       lhui    r21, r1, 46 /* B */
+       lhui    r22, r1, 48 /* C */
+       lhui    r23, r1, 50 /* D */
+       lhui    r24, r1, 52 /* E */
+       lhui    r25, r1, 54 /* F */
+       lhui    r26, r1, 56 /* G */
+       lhui    r27, r1, 58 /* H */
+
+/* D * H ==> LSB of the result on stack ==> Store1 */
+       mul     r9, r23, r27
+       swi     r9, r1, 36 /* Pos2 and Pos3 */
+
+/* Hi (Store1) + C * H + D * G ==> Store2 ==> Pos1 and Pos2 */
+/* Store the carry generated in position 2 for Pos 3 */
+       lhui    r11, r1, 36 /* Pos2 */
+       mul     r9, r22, r27 /* C * H */
+       mul     r10, r23, r26 /* D * G */
+       add     r9, r9, r10
+       addc    r12, r0, r0
+       add     r9, r9, r11
+       addc    r12, r12, r0 /* Store the Carry */
+       shi     r9, r1, 36 /* Store Pos2 */
+       swi     r9, r1, 32
+       lhui    r11, r1, 32
+       shi     r11, r1, 34 /* Store Pos1 */
+
+/* Hi (Store2) + B * H + C * G + D * F ==> Store3 ==> Pos0 and Pos1 */
+       mul     r9, r21, r27 /* B * H */
+       mul     r10, r22, r26 /* C * G */
+       mul     r7, r23, r25 /* D * F */
+       add     r9, r9, r11
+       add     r9, r9, r10
+       add     r9, r9, r7
+       swi     r9, r1, 32 /* Pos0 and Pos1 */
+
+/* Hi (Store3) + A * H + B * G + C * F + D * E ==> Store3 ==> Pos0 */
+       lhui    r11, r1, 32 /* Pos0 */
+       mul     r9, r20, r27 /* A * H */
+       mul     r10, r21, r26 /* B * G */
+       mul     r7, r22, r25 /* C * F */
+       mul     r8, r23, r24 /* D * E */
+       add     r9, r9, r11
+       add     r9, r9, r10
+       add     r9, r9, r7
+       add     r9, r9, r8
+       sext16  r9, r9 /* Sign extend the MSB */
+       shi     r9, r1, 32
+
+/* Move results to r3 and r4 */
+       lhui    r3, r1, 32
+       add     r3, r3, r12
+       shi     r3, r1, 32
+       lwi     r3, r1, 32 /* Hi Part */
+       lwi     r4, r1, 36 /* Lo Part */
+
+/* Restore Callee saved registers */
+       lw      r20, r1, r0
+       lwi     r21, r1, 4
+       lwi     r22, r1, 8
+       lwi     r23, r1, 12
+       lwi     r24, r1, 16
+       lwi     r25, r1, 20
+       lwi     r26, r1, 24
+       lwi     r27, r1, 28
+
+/* Restore Frame and return */
+       rtsd    r15, 8
+       addi    r1, r1, 40
+
+.size __muldi3, . - __muldi3
+.end __muldi3
diff --git a/arch/microblaze/lib/mulsi3.S b/arch/microblaze/lib/mulsi3.S
new file mode 100644 (file)
index 0000000..90bd7b9
--- /dev/null
@@ -0,0 +1,46 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 32 bit integers.
+ *     Input : Operand1 in Reg r5
+ *             Operand2 in Reg r6
+ *     Output: Result [op1 * op2] in Reg r3
+ */
+       .text
+       .globl  __mulsi3
+       .type __mulsi3,  @function
+       .ent __mulsi3
+
+__mulsi3:
+       .frame  r1, 0, r15
+       add     r3, r0, r0
+       beqi    r5, result_is_zero /* multiply by zero */
+       beqi    r6, result_is_zero /* multiply by zero */
+       bgeid   r5, r5_pos
+       xor     r4, r5, r6 /* get the sign of the result */
+       rsubi   r5, r5, 0 /* make r5 positive */
+r5_pos:
+       bgei    r6, r6_pos
+       rsubi   r6, r6, 0 /* make r6 positive */
+r6_pos:
+       bri     l1
+l2:
+       add     r5, r5, r5
+l1:
+       srl     r6, r6
+       addc    r7, r0, r0
+       beqi    r7, l2
+       bneid   r6, l2
+       add     r3, r3, r5
+       blti    r4, negateresult
+       rtsd    r15, 8
+       nop
+negateresult:
+       rtsd    r15, 8
+       rsub    r3, r3, r0
+result_is_zero:
+       rtsd    r15, 8
+       addi    r3, r0, 0
+
+.size __mulsi3,  . - __mulsi3
+.end __mulsi3
diff --git a/arch/microblaze/lib/udivsi3.S b/arch/microblaze/lib/udivsi3.S
new file mode 100644 (file)
index 0000000..64cf57e
--- /dev/null
@@ -0,0 +1,84 @@
+#include <linux/linkage.h>
+
+/*
+* Unsigned divide operation.
+*      Input : Divisor in Reg r5
+*              Dividend in Reg r6
+*      Output: Result in Reg r3
+*/
+
+       .text
+       .globl  __udivsi3
+       .type __udivsi3, @function
+       .ent __udivsi3
+
+__udivsi3:
+
+       .frame  r1, 0, r15
+
+       addik   r1, r1, -12
+       swi     r29, r1, 0
+       swi     r30, r1, 4
+       swi     r31, r1, 8
+
+       beqi    r6, div_by_zero /* div_by_zero /* division error */
+       beqid   r5, result_is_zero /* result is zero */
+       addik   r30, r0, 0 /* clear mod */
+       addik   r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal - if yes, return 1 */
+       rsub    r18, r5, r6
+       beqid   r18, return_here
+       addik   r3, r0, 1
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return 0 */
+       xor     r18, r5, r6
+       bgeid   r18, 16
+       add     r3, r0, r0 /* we would anyways clear r3 */
+       blti    r6, return_here /* r6[bit 31 = 1] hence is greater */
+       bri     checkr6
+       rsub    r18, r6, r5 /* microblazecmp */
+       blti    r18, return_here
+
+/* if r6 [bit 31] is set, then return result as 1 */
+checkr6:
+       bgti    r6, div0
+       brid    return_here
+       addik   r3, r0, 1
+
+/* first part try to find the first '1' in the r5 */
+div0:
+       blti    r5, div2
+div1:
+       add     r5, r5, r5 /* left shift logical r5 */
+       bgtid   r5, div1
+       addik   r29, r29, -1
+div2:
+/* left shift logical r5 get the '1' into the carry */
+       add     r5, r5, r5
+       addc    r30, r30, r30 /* move that bit into the mod register */
+       rsub    r31, r6, r30 /* try to subtract (r30 a r6) */
+       blti    r31, mod_too_small
+/* move the r31 to mod since the result was positive */
+       or      r30, r0, r31
+       addik   r3, r3, 1
+mod_too_small:
+       addik   r29, r29, -1
+       beqi    r29, loop_end
+       add     r3, r3, r3 /* shift in the '1' into div */
+       bri     div2 /* div2 */
+loop_end:
+       bri     return_here
+div_by_zero:
+result_is_zero:
+       or      r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+       lwi     r29, r1, 0
+       lwi     r30, r1, 4
+       lwi     r31, r1, 8
+       rtsd    r15, 8
+       addik   r1, r1, 12
+
+.size __udivsi3, . - __udivsi3
+.end __udivsi3
diff --git a/arch/microblaze/lib/umodsi3.S b/arch/microblaze/lib/umodsi3.S
new file mode 100644 (file)
index 0000000..17d16ba
--- /dev/null
@@ -0,0 +1,86 @@
+#include <linux/linkage.h>
+
+/*
+ * Unsigned modulo operation for 32 bit integers.
+ *     Input : op1 in Reg r5
+ *             op2 in Reg r6
+ *     Output: op1 mod op2 in Reg r3
+ */
+
+       .text
+       .globl  __umodsi3
+       .type __umodsi3, @function
+       .ent __umodsi3
+
+__umodsi3:
+       .frame  r1, 0, r15
+
+       addik   r1, r1, -12
+       swi     r29, r1, 0
+       swi     r30, r1, 4
+       swi     r31, r1, 8
+
+       beqi    r6, div_by_zero /* div_by_zero - division error */
+       beqid   r5, result_is_zero /* result is zero */
+       addik   r3, r0, 0 /* clear div */
+       addik   r30, r0, 0 /* clear mod */
+       addik   r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal /* if yes, return 0 */
+       rsub    r18, r5, r6
+       beqi    r18, return_here
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return r5 */
+       xor     r18, r5, r6
+       bgeid   r18, 16
+       addik   r3, r5, 0
+       blti    r6, return_here
+       bri     $lcheckr6
+       rsub    r18, r5, r6 /* microblazecmp */
+       bgti    r18, return_here
+
+/* if r6 [bit 31] is set, then return result as r5-r6 */
+$lcheckr6:
+       bgtid   r6, div0
+       addik   r3, r0, 0
+       addik   r18, r0, 0x7fffffff
+       and     r5, r5, r18
+       and     r6, r6, r18
+       brid    return_here
+       rsub    r3, r6, r5
+/* first part: try to find the first '1' in the r5 */
+div0:
+       blti    r5, div2
+div1:
+       add     r5, r5, r5 /* left shift logical r5 */
+       bgeid   r5, div1
+       addik   r29, r29, -1
+div2:
+       /* left shift logical r5 get the '1' into the carry */
+       add     r5, r5, r5
+       addc    r3, r3, r3 /* move that bit into the mod register */
+       rsub    r31, r6, r3 /* try to subtract (r3 a r6) */
+       blti    r31, mod_too_small
+       /* move the r31 to mod since the result was positive */
+       or      r3, r0, r31
+       addik   r30, r30, 1
+mod_too_small:
+       addik   r29, r29, -1
+       beqi    r29, loop_end
+       add     r30, r30, r30 /* shift in the '1' into div */
+       bri     div2 /* div2 */
+loop_end:
+       bri     return_here
+div_by_zero:
+result_is_zero:
+       or      r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+       lwi     r29, r1, 0
+       lwi     r30, r1, 4
+       lwi     r31, r1, 8
+       rtsd    r15, 8
+       addik   r1, r1, 12
+
+.size __umodsi3, . - __umodsi3
+.end __umodsi3
index 55ef532f32be6fc3c174e1280a7971ffc5329406..e363615d67989da66ca3d8d2e981bddbb34edc47 100644 (file)
@@ -60,21 +60,6 @@ struct dma_map_ops *get_pci_dma_ops(void)
 }
 EXPORT_SYMBOL(get_pci_dma_ops);
 
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       return dma_set_mask(&dev->dev, mask);
-}
-
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       int rc;
-
-       rc = dma_set_mask(&dev->dev, mask);
-       dev->dev.coherent_dma_mask = dev->dma_mask;
-
-       return rc;
-}
-
 struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
 {
        struct pci_controller *phb;
@@ -1075,8 +1060,6 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                 bus->number, bus->self ? pci_name(bus->self) : "PHB");
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
-               struct dev_archdata *sd = &dev->dev.archdata;
-
                /* Setup OF node pointer in archdata */
                dev->dev.of_node = pci_device_to_OF_node(dev);
 
@@ -1086,8 +1069,8 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
 
                /* Hook up default DMA ops */
-               sd->dma_ops = pci_dma_ops;
-               sd->dma_data = (void *)PCI_DRAM_OFFSET;
+               set_dma_ops(&dev->dev, pci_dma_ops);
+               dev->dev.archdata.dma_data = (void *)PCI_DRAM_OFFSET;
 
                /* Read default IRQs and fixup if necessary */
                pci_read_irq_line(dev);
index 2d5c41767cd06ca146e0192df79e9fd9f06ef441..3f85df2b73b3ecd21fb4a0d4d118544e4fc290f0 100644 (file)
@@ -85,6 +85,7 @@
                        xlnx,dynamic-bus-sizing = <0x1>;
                        xlnx,edge-is-positive = <0x1>;
                        xlnx,family = "virtex5";
+                       xlnx,endianness = <0x1>;
                        xlnx,fpu-exception = <0x1>;
                        xlnx,fsl-data-size = <0x20>;
                        xlnx,fsl-exception = <0x0>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        compatible = "xlnx,compound";
+                       ranges ;
                        ethernet@81c00000 {
                                compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
                                device_type = "network";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        compatible = "xlnx,mpmc-4.02.a";
+                       ranges ;
                        PIM3: sdma@84600180 {
                                compatible = "xlnx,ll-dma-1.00.a";
                                interrupt-parent = <&xps_intc_0>;
index 5b89b58c5aedbc9d9f12aa5d6b2e541134101f6f..b9529caa507af30d38f3a9f58dea81241b73fe25 100644 (file)
@@ -17,9 +17,6 @@
 
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
        { .compatible = "simple-bus", },
-       { .compatible = "xlnx,plb-v46-1.00.a", },
-       { .compatible = "xlnx,opb-v20-1.10.c", },
-       { .compatible = "xlnx,opb-v20-1.10.b", },
        { .compatible = "xlnx,compound", },
        {}
 };
index 784cf822963afbee48cfafbaf0d799143aa3972b..46cae2b163e4a1e6286584e28496f59d7e41d844 100644 (file)
@@ -2128,6 +2128,13 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+config USE_OF
+       bool "Flattened Device Tree support"
+       select OF
+       select OF_FLATTREE
+       help
+         Include support for flattened device tree machine descriptions.
+
 endmenu
 
 config LOCKDEP_SUPPORT
index 3fa34c3abc0408a04d668c262e03360506b4d861..fbb55935b99e71ee3be1475657ca8fdfdf981ee5 100644 (file)
@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
        .resource       = au1200_psc1_res,
 };
 
+static struct platform_device db1200_stac_dev = {
+       .name           = "ac97-codec",
+       .id             = 1,    /* on PSC1 */
+};
+
 static struct platform_device *db1200_devs[] __initdata = {
        NULL,           /* PSC0, selected by S6.8 */
        &db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
        &db1200_rtc_dev,
        &db1200_nand_dev,
        &db1200_audio_dev,
+       &db1200_stac_dev,
 };
 
 static int __init db1200_dev_init(void)
index 75753ca73bfd1c9e0d6ad82681ef15e4f2783897..77e644082a3b84547e0375241026ae1430f57ad4 100644 (file)
@@ -45,18 +45,12 @@ extern pte_t *pkmap_page_table;
 extern void * kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
 
-extern void *__kmap(struct page *page);
-extern void __kunmap(struct page *page);
-extern void *__kmap_atomic(struct page *page, enum km_type type);
-extern void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-extern struct page *__kmap_atomic_to_page(void *ptr);
-
-#define kmap                   __kmap
-#define kunmap                 __kunmap
-#define kmap_atomic            __kmap_atomic
-#define kunmap_atomic_notypecheck              __kunmap_atomic_notypecheck
-#define kmap_atomic_to_page    __kmap_atomic_to_page
+extern void *kmap(struct page *page);
+extern void kunmap(struct page *page);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
+extern struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()    flush_cache_all()
 
index dea4aed6478f7de6652c8b5491ebfc165cf52d53..b003ed52ed1725221ca6ac510251f46e7cb7d443 100644 (file)
 
 #include <irq.h>
 
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+       return;
+}
+
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
index ae90412556d026fc58d5a97bc9e2761c76080e49..8a153d2fa62af5aa1d3666f232e850e985e2b0ef 100644 (file)
@@ -154,10 +154,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
 
 #define pte_offset_map(dir, address)                                    \
        ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)                             \
-       ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
 
index 1be4b0fa30da7dc30d269c8057acb1f659d650c9..f00896087ddab34b861ac6770e8166d9f2fa764a 100644 (file)
@@ -257,10 +257,7 @@ static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address)
        ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
 #define pte_offset_map(dir, address)                                   \
        ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)                            \
-       ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 /*
  * Initialize a new pgd / pmd table with invalid pointers.
diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h
new file mode 100644 (file)
index 0000000..f29b862
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  arch/mips/include/asm/prom.h
+ *
+ *  Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.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 __ASM_MIPS_PROM_H
+#define __ASM_MIPS_PROM_H
+
+#ifdef CONFIG_OF
+#include <asm/bootinfo.h>
+
+/* which is compatible with the flattened device tree (FDT) */
+#define cmd_line arcs_cmdline
+
+extern int early_init_dt_scan_memory_arch(unsigned long node,
+       const char *uname, int depth, void *data);
+
+extern int reserve_mem_mach(unsigned long addr, unsigned long size);
+extern void free_mem_mach(unsigned long addr, unsigned long size);
+
+extern void device_tree_init(void);
+#else /* CONFIG_OF */
+static inline void device_tree_init(void) { }
+#endif /* CONFIG_OF */
+
+#endif /* _ASM_MIPS_PROM_H */
index 06f848299785c1785fc914da5b57a189c517b103..80884983270de35d19253287e4a12deec60ebb06 100644 (file)
@@ -96,6 +96,8 @@ obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 obj-$(CONFIG_SPINLOCK_TEST)    += spinlock_test.o
 
+obj-$(CONFIG_OF)               += prom.o
+
 CFLAGS_cpu-bugs64.o    = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
 
 obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT)  += 8250-platform.o
index 9a526ba6f25766f3ab6b58bc70b7f792c4011ff9..802e6160f37e987802ac60b2e1cec193b4c832af 100644 (file)
@@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
        if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
                goto out_unlock;
 
-       retval = security_task_setscheduler(p)
+       retval = security_task_setscheduler(p);
        if (retval)
                goto out_unlock;
 
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
new file mode 100644 (file)
index 0000000..e000b27
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * MIPS support for CONFIG_OF device tree support
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.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/errno.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+
+int __init early_init_dt_scan_memory_arch(unsigned long node,
+                                         const char *uname, int depth,
+                                         void *data)
+{
+       return early_init_dt_scan_memory(node, uname, depth, data);
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       return add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init reserve_mem_mach(unsigned long addr, unsigned long size)
+{
+       return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
+}
+
+void __init free_mem_mach(unsigned long addr, unsigned long size)
+{
+       return free_bootmem(addr, size);
+}
+
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return virt_to_phys(
+               __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS))
+               );
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+                                           unsigned long end)
+{
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
+}
+#endif
+
+/*
+ * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
+ * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
+ * supported.
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+void __init early_init_devtree(void *params)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* Retrieve various informations from the /chosen node of the
+        * device-tree, including the platform type, initrd location and
+        * size, and more ...
+        */
+       of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+       /* Scan memory nodes */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL);
+}
+
+void __init device_tree_init(void)
+{
+       unsigned long base, size;
+
+       if (!initial_boot_params)
+               return;
+
+       base = virt_to_phys((void *)initial_boot_params);
+       size = initial_boot_params->totalsize;
+
+       /* Before we do anything, lets reserve the dt blob */
+       reserve_mem_mach(base, size);
+
+       unflatten_device_tree();
+
+       /* free the space reserved for the dt blob */
+       free_mem_mach(base, size);
+}
index 85aef3fc6716f8bc123ed614c454ad3f6dc2f07a..a6b900f2962bb2dff92f93a4f53206a2c52bc812 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/setup.h>
 #include <asm/smp-ops.h>
 #include <asm/system.h>
+#include <asm/prom.h>
 
 struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
 
@@ -487,6 +488,7 @@ static void __init arch_mem_init(char **cmdline_p)
        }
 
        bootmem_init();
+       device_tree_init();
        sparse_init();
        paging_init();
 }
index 6a2b1bf9ef112571ef771e1ba039ec0992d18311..1e69b1fb4b85c16e1a1c5f07bc6f0e054e5196cc 100644 (file)
@@ -9,7 +9,7 @@ static pte_t *kmap_pte;
 
 unsigned long highstart_pfn, highend_pfn;
 
-void *__kmap(struct page *page)
+void *kmap(struct page *page)
 {
        void *addr;
 
@@ -21,16 +21,16 @@ void *__kmap(struct page *page)
 
        return addr;
 }
-EXPORT_SYMBOL(__kmap);
+EXPORT_SYMBOL(kmap);
 
-void __kunmap(struct page *page)
+void kunmap(struct page *page)
 {
        BUG_ON(in_interrupt());
        if (!PageHighMem(page))
                return;
        kunmap_high(page);
 }
-EXPORT_SYMBOL(__kunmap);
+EXPORT_SYMBOL(kunmap);
 
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -41,17 +41,17 @@ EXPORT_SYMBOL(__kunmap);
  * kmaps are appropriate for short, tight code paths only.
  */
 
-void *__kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
 
        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
        pagefault_disable();
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -64,43 +64,47 @@ void *__kmap_atomic(struct page *page, enum km_type type)
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
-void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+       int type;
 
        if (vaddr < FIXADDR_START) { // FIXME
                pagefault_enable();
                return;
        }
 
-       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+       type = kmap_atomic_idx_pop();
+#ifdef CONFIG_DEBUG_HIGHMEM
+       {
+               int idx = type + KM_TYPE_NR * smp_processor_id();
 
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(&init_mm, vaddr, kmap_pte-idx);
-       local_flush_tlb_one(vaddr);
-#endif
+               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
 
+               /*
+                * force other mappings to Oops if they'll try to access
+                * this pte without first remap it
+                */
+               pte_clear(&init_mm, vaddr, kmap_pte-idx);
+               local_flush_tlb_one(vaddr);
+       }
+#endif
        pagefault_enable();
 }
-EXPORT_SYMBOL(__kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /*
  * This is the same as kmap_atomic() but can map memory that doesn't
  * have a struct page associated with it.
  */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
 
        pagefault_disable();
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
@@ -109,7 +113,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
        return (void*) vaddr;
 }
 
-struct page *__kmap_atomic_to_page(void *ptr)
+struct page *kmap_atomic_to_page(void *ptr)
 {
        unsigned long idx, vaddr = (unsigned long)ptr;
        pte_t *pte;
index b0b187a29b8862a9a99e1c98404c90bb3eb74225..f577ba2268caadc554d2cb34c5163394a83f901f 100644 (file)
@@ -70,15 +70,16 @@ static inline void kunmap(struct page *page)
  * be used in IRQ contexts, so in some (very limited) cases we need
  * it.
  */
-static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline unsigned long __kmap_atomic(struct page *page)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
 
+       pagefault_disable();
        if (page < highmem_start_page)
                return page_address(page);
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #if HIGHMEM_DEBUG
@@ -91,26 +92,35 @@ static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
        return vaddr;
 }
 
-static inline void kunmap_atomic_notypecheck(unsigned long vaddr, enum km_type type)
+static inline void __kunmap_atomic(unsigned long vaddr)
 {
-#if HIGHMEM_DEBUG
-       enum fixed_addresses idx = type + KM_TYPE_NR * smp_processor_id();
+       int type;
 
-       if (vaddr < FIXADDR_START) /* FIXME */
+       if (vaddr < FIXADDR_START) { /* FIXME */
+               pagefault_enable();
                return;
+       }
 
-       if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
-               BUG();
+       type = kmap_atomic_idx_pop();
 
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(kmap_pte - idx);
-       __flush_tlb_one(vaddr);
+#if HIGHMEM_DEBUG
+       {
+               unsigned int idx;
+               idx = type + KM_TYPE_NR * smp_processor_id();
+
+               if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
+                       BUG();
+
+               /*
+                * force other mappings to Oops if they'll try to access
+                * this pte without first remap it
+                */
+               pte_clear(kmap_pte - idx);
+               __flush_tlb_one(vaddr);
+       }
 #endif
+       pagefault_enable();
 }
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
index 16d88577f3e08510b543452ac322d6cd7e970e77..b049a8bd157774fd9c3f20d208913d04a8761c70 100644 (file)
@@ -457,9 +457,7 @@ static inline int set_kernel_exec(unsigned long vaddr, int enable)
 
 #define pte_offset_map(dir, address) \
        ((pte_t *) page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte)         do {} while (0)
-#define pte_unmap_nested(pte)  do {} while (0)
 
 /*
  * The MN10300 has external MMU info in the form of a TLB: this is adapted from
index 10549dcfb610fca868a0e623a367d2ea5be55ed9..febbeee7f2f54ba99bf429b72d9ea74aab80be62 100644 (file)
@@ -70,7 +70,7 @@ SECTIONS
        .exit.text : { EXIT_TEXT; }
        .exit.data : { EXIT_DATA; }
 
-  PERCPU(32)
+  PERCPU(PAGE_SIZE)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index 01c15035e783d47ec944f7d47b30ee90202cd9a2..865f37a8a88167306d6469e2bce9c11880022146 100644 (file)
@@ -397,9 +397,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_offset_kernel(pmd, address) \
        ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 #define pte_unmap(pte)                 do { } while (0)
 #define pte_unmap_nested(pte)          do { } while (0)
index 9535ce68caaee41331554d2a330a783b503e6eb1..83c3218cb4da2717b9a375ab904ddc8879e9b038 100644 (file)
 
                ssi@16100 {
                        compatible = "fsl,mpc8610-ssi";
+                       status = "disabled";
                        cell-index = <1>;
                        reg = <0x16100 0x100>;
                        interrupt-parent = <&mpic>;
index c3b113b2ca318ce8c25badd717d9f122b6157398..3aeb5949cfef6da423f675b4a2bb9249fd0e6bb4 100644 (file)
@@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
index a075da2ea3fbdbffb06623234a92493269dbe901..d62c8016f4bcaf7cd603856a917dac4382a64901 100644 (file)
@@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
new file mode 100644 (file)
index 0000000..bebd124
--- /dev/null
@@ -0,0 +1,197 @@
+/**
+ * Freecale 85xx and 86xx Global Utilties register set
+ *
+ * Authors: Jeff Brown
+ *          Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2004,2007 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
+#ifdef __KERNEL__
+
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names.  In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
+       __be32  porpllsr;       /* 0x.0000 - POR PLL Ratio Status Register */
+       __be32  porbmsr;        /* 0x.0004 - POR Boot Mode Status Register */
+       __be32  porimpscr;      /* 0x.0008 - POR I/O Impedance Status and Control Register */
+       __be32  pordevsr;       /* 0x.000c - POR I/O Device Status Register */
+       __be32  pordbgmsr;      /* 0x.0010 - POR Debug Mode Status Register */
+       __be32  pordevsr2;      /* 0x.0014 - POR device status register 2 */
+       u8      res018[0x20 - 0x18];
+       __be32  porcir;         /* 0x.0020 - POR Configuration Information Register */
+       u8      res024[0x30 - 0x24];
+       __be32  gpiocr;         /* 0x.0030 - GPIO Control Register */
+       u8      res034[0x40 - 0x34];
+       __be32  gpoutdr;        /* 0x.0040 - General-Purpose Output Data Register */
+       u8      res044[0x50 - 0x44];
+       __be32  gpindr;         /* 0x.0050 - General-Purpose Input Data Register */
+       u8      res054[0x60 - 0x54];
+       __be32  pmuxcr;         /* 0x.0060 - Alternate Function Signal Multiplex Control */
+        __be32  pmuxcr2;       /* 0x.0064 - Alternate function signal multiplex control 2 */
+        __be32  dmuxcr;                /* 0x.0068 - DMA Mux Control Register */
+        u8     res06c[0x70 - 0x6c];
+       __be32  devdisr;        /* 0x.0070 - Device Disable Control */
+       __be32  devdisr2;       /* 0x.0074 - Device Disable Control 2 */
+       u8      res078[0x7c - 0x78];
+       __be32  pmjcr;          /* 0x.007c - 4 Power Management Jog Control Register */
+       __be32  powmgtcsr;      /* 0x.0080 - Power Management Status and Control Register */
+       __be32  pmrccr;         /* 0x.0084 - Power Management Reset Counter Configuration Register */
+       __be32  pmpdccr;        /* 0x.0088 - Power Management Power Down Counter Configuration Register */
+       __be32  pmcdr;          /* 0x.008c - 4Power management clock disable register */
+       __be32  mcpsumr;        /* 0x.0090 - Machine Check Summary Register */
+       __be32  rstrscr;        /* 0x.0094 - Reset Request Status and Control Register */
+       __be32  ectrstcr;       /* 0x.0098 - Exception reset control register */
+       __be32  autorstsr;      /* 0x.009c - Automatic reset status register */
+       __be32  pvr;            /* 0x.00a0 - Processor Version Register */
+       __be32  svr;            /* 0x.00a4 - System Version Register */
+       u8      res0a8[0xb0 - 0xa8];
+       __be32  rstcr;          /* 0x.00b0 - Reset Control Register */
+       u8      res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+       __be32  iovselsr;       /* 0x.00c0 - I/O voltage select status register */
+#else
+       __be32  elbcvselcr;     /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
+#endif
+       u8      res0c4[0x224 - 0xc4];
+       __be32  iodelay1;       /* 0x.0224 - IO delay control register 1 */
+       __be32  iodelay2;       /* 0x.0228 - IO delay control register 2 */
+       u8      res22c[0x800 - 0x22c];
+       __be32  clkdvdr;        /* 0x.0800 - Clock Divide Register */
+       u8      res804[0x900 - 0x804];
+       __be32  ircr;           /* 0x.0900 - Infrared Control Register */
+       u8      res904[0x908 - 0x904];
+       __be32  dmacr;          /* 0x.0908 - DMA Control Register */
+       u8      res90c[0x914 - 0x90c];
+       __be32  elbccr;         /* 0x.0914 - eLBC Control Register */
+       u8      res918[0xb20 - 0x918];
+       __be32  ddr1clkdr;      /* 0x.0b20 - DDR1 Clock Disable Register */
+       __be32  ddr2clkdr;      /* 0x.0b24 - DDR2 Clock Disable Register */
+       __be32  ddrclkdr;       /* 0x.0b28 - DDR Clock Disable Register */
+       u8      resb2c[0xe00 - 0xb2c];
+       __be32  clkocr;         /* 0x.0e00 - Clock Out Select Register */
+       u8      rese04[0xe10 - 0xe04];
+       __be32  ddrdllcr;       /* 0x.0e10 - DDR DLL Control Register */
+       u8      rese14[0xe20 - 0xe14];
+       __be32  lbcdllcr;       /* 0x.0e20 - LBC DLL Control Register */
+       __be32  cpfor;          /* 0x.0e24 - L2 charge pump fuse override register */
+       u8      rese28[0xf04 - 0xe28];
+       __be32  srds1cr0;       /* 0x.0f04 - SerDes1 Control Register 0 */
+       __be32  srds1cr1;       /* 0x.0f08 - SerDes1 Control Register 0 */
+       u8      resf0c[0xf2c - 0xf0c];
+       __be32  itcr;           /* 0x.0f2c - Internal transaction control register */
+       u8      resf30[0xf40 - 0xf30];
+       __be32  srds2cr0;       /* 0x.0f40 - SerDes2 Control Register 0 */
+       __be32  srds2cr1;       /* 0x.0f44 - SerDes2 Control Register 0 */
+} __attribute__ ((packed));
+
+#ifdef CONFIG_PPC_86xx
+
+#define CCSR_GUTS_DMACR_DEV_SSI        0       /* DMA controller/channel set to SSI */
+#define CCSR_GUTS_DMACR_DEV_IR 1       /* DMA controller/channel set to IR */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller.  Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
+ */
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
+       unsigned int co, unsigned int ch, unsigned int device)
+{
+       unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+       clrsetbits_be32(&guts->dmacr, 3 << shift, device << shift);
+}
+
+#define CCSR_GUTS_PMUXCR_LDPSEL                0x00010000
+#define CCSR_GUTS_PMUXCR_SSI1_MASK     0x0000C000      /* Bitmask for SSI1 */
+#define CCSR_GUTS_PMUXCR_SSI1_LA       0x00000000      /* Latched address */
+#define CCSR_GUTS_PMUXCR_SSI1_HI       0x00004000      /* High impedance */
+#define CCSR_GUTS_PMUXCR_SSI1_SSI      0x00008000      /* Used for SSI1 */
+#define CCSR_GUTS_PMUXCR_SSI2_MASK     0x00003000      /* Bitmask for SSI2 */
+#define CCSR_GUTS_PMUXCR_SSI2_LA       0x00000000      /* Latched address */
+#define CCSR_GUTS_PMUXCR_SSI2_HI       0x00001000      /* High impedance */
+#define CCSR_GUTS_PMUXCR_SSI2_SSI      0x00002000      /* Used for SSI2 */
+#define CCSR_GUTS_PMUXCR_LA_22_25_LA   0x00000000      /* Latched Address */
+#define CCSR_GUTS_PMUXCR_LA_22_25_HI   0x00000400      /* High impedance */
+#define CCSR_GUTS_PMUXCR_DBGDRV                0x00000200      /* Signals not driven */
+#define CCSR_GUTS_PMUXCR_DMA2_0                0x00000008
+#define CCSR_GUTS_PMUXCR_DMA2_3                0x00000004
+#define CCSR_GUTS_PMUXCR_DMA1_0                0x00000002
+#define CCSR_GUTS_PMUXCR_DMA1_3                0x00000001
+
+/*
+ * Set the DMA external control bits in the GUTS
+ *
+ * The DMA external control bits in the PMUXCR are only meaningful for
+ * channels 0 and 3.  Any other channels are ignored.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * value: the new value for the bit (0 or 1)
+ */
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
+       unsigned int co, unsigned int ch, unsigned int value)
+{
+       if ((ch == 0) || (ch == 3)) {
+               unsigned int shift = 2 * (co + 1) - (ch & 1) - 1;
+
+               clrsetbits_be32(&guts->pmuxcr, 1 << shift, value << shift);
+       }
+}
+
+#define CCSR_GUTS_CLKDVDR_PXCKEN       0x80000000
+#define CCSR_GUTS_CLKDVDR_SSICKEN      0x20000000
+#define CCSR_GUTS_CLKDVDR_PXCKINV      0x10000000
+#define CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT 25
+#define CCSR_GUTS_CLKDVDR_PXCKDLY_MASK 0x06000000
+#define CCSR_GUTS_CLKDVDR_PXCKDLY(x) \
+       (((x) & 3) << CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT)
+#define CCSR_GUTS_CLKDVDR_PXCLK_SHIFT  16
+#define CCSR_GUTS_CLKDVDR_PXCLK_MASK   0x001F0000
+#define CCSR_GUTS_CLKDVDR_PXCLK(x) (((x) & 31) << CCSR_GUTS_CLKDVDR_PXCLK_SHIFT)
+#define CCSR_GUTS_CLKDVDR_SSICLK_MASK  0x000000FF
+#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
+
+#endif
+
+#endif
+#endif
index d10d64a4be38c2c5725a853498007406e211f817..dbc264010d0b9f5b5182d56c02e8730c2025242f 100644 (file)
@@ -60,9 +60,8 @@ extern pte_t *pkmap_page_table;
 
 extern void *kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
-extern void *kmap_atomic_prot(struct page *page, enum km_type type,
-                             pgprot_t prot);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
 
 static inline void *kmap(struct page *page)
 {
@@ -80,9 +79,9 @@ static inline void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *__kmap_atomic(struct page *page)
 {
-       return kmap_atomic_prot(page, type, kmap_prot);
+       return kmap_atomic_prot(page, kmap_prot);
 }
 
 static inline struct page *kmap_atomic_to_page(void *ptr)
diff --git a/arch/powerpc/include/asm/immap_86xx.h b/arch/powerpc/include/asm/immap_86xx.h
deleted file mode 100644 (file)
index 0f165e5..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * MPC86xx Internal Memory Map
- *
- * Authors: Jeff Brown
- *          Timur Tabi <timur@freescale.com>
- *
- * Copyright 2004,2007 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
- */
-
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
-#ifdef __KERNEL__
-
-/* Global Utility Registers */
-struct ccsr_guts {
-       __be32  porpllsr;       /* 0x.0000 - POR PLL Ratio Status Register */
-       __be32  porbmsr;        /* 0x.0004 - POR Boot Mode Status Register */
-       __be32  porimpscr;      /* 0x.0008 - POR I/O Impedance Status and Control Register */
-       __be32  pordevsr;       /* 0x.000c - POR I/O Device Status Register */
-       __be32  pordbgmsr;      /* 0x.0010 - POR Debug Mode Status Register */
-       u8      res1[0x20 - 0x14];
-       __be32  porcir;         /* 0x.0020 - POR Configuration Information Register */
-       u8      res2[0x30 - 0x24];
-       __be32  gpiocr;         /* 0x.0030 - GPIO Control Register */
-       u8      res3[0x40 - 0x34];
-       __be32  gpoutdr;        /* 0x.0040 - General-Purpose Output Data Register */
-       u8      res4[0x50 - 0x44];
-       __be32  gpindr;         /* 0x.0050 - General-Purpose Input Data Register */
-       u8      res5[0x60 - 0x54];
-       __be32  pmuxcr;         /* 0x.0060 - Alternate Function Signal Multiplex Control */
-       u8      res6[0x70 - 0x64];
-       __be32  devdisr;        /* 0x.0070 - Device Disable Control */
-       __be32  devdisr2;       /* 0x.0074 - Device Disable Control 2 */
-       u8      res7[0x80 - 0x78];
-       __be32  powmgtcsr;      /* 0x.0080 - Power Management Status and Control Register */
-       u8      res8[0x90 - 0x84];
-       __be32  mcpsumr;        /* 0x.0090 - Machine Check Summary Register */
-       __be32  rstrscr;        /* 0x.0094 - Reset Request Status and Control Register */
-       u8      res9[0xA0 - 0x98];
-       __be32  pvr;            /* 0x.00a0 - Processor Version Register */
-       __be32  svr;            /* 0x.00a4 - System Version Register */
-       u8      res10[0xB0 - 0xA8];
-       __be32  rstcr;          /* 0x.00b0 - Reset Control Register */
-       u8      res11[0xC0 - 0xB4];
-       __be32  elbcvselcr;     /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-       u8      res12[0x800 - 0xC4];
-       __be32  clkdvdr;        /* 0x.0800 - Clock Divide Register */
-       u8      res13[0x900 - 0x804];
-       __be32  ircr;           /* 0x.0900 - Infrared Control Register */
-       u8      res14[0x908 - 0x904];
-       __be32  dmacr;          /* 0x.0908 - DMA Control Register */
-       u8      res15[0x914 - 0x90C];
-       __be32  elbccr;         /* 0x.0914 - eLBC Control Register */
-       u8      res16[0xB20 - 0x918];
-       __be32  ddr1clkdr;      /* 0x.0b20 - DDR1 Clock Disable Register */
-       __be32  ddr2clkdr;      /* 0x.0b24 - DDR2 Clock Disable Register */
-       __be32  ddrclkdr;       /* 0x.0b28 - DDR Clock Disable Register */
-       u8      res17[0xE00 - 0xB2C];
-       __be32  clkocr;         /* 0x.0e00 - Clock Out Select Register */
-       u8      res18[0xE10 - 0xE04];
-       __be32  ddrdllcr;       /* 0x.0e10 - DDR DLL Control Register */
-       u8      res19[0xE20 - 0xE14];
-       __be32  lbcdllcr;       /* 0x.0e20 - LBC DLL Control Register */
-       u8      res20[0xF04 - 0xE24];
-       __be32  srds1cr0;       /* 0x.0f04 - SerDes1 Control Register 0 */
-       __be32  srds1cr1;       /* 0x.0f08 - SerDes1 Control Register 0 */
-       u8      res21[0xF40 - 0xF0C];
-       __be32  srds2cr0;       /* 0x.0f40 - SerDes1 Control Register 0 */
-       __be32  srds2cr1;       /* 0x.0f44 - SerDes1 Control Register 0 */
-} __attribute__ ((packed));
-
-#define CCSR_GUTS_DMACR_DEV_SSI        0       /* DMA controller/channel set to SSI */
-#define CCSR_GUTS_DMACR_DEV_IR 1       /* DMA controller/channel set to IR */
-
-/*
- * Set the DMACR register in the GUTS
- *
- * The DMACR register determines the source of initiated transfers for each
- * channel on each DMA controller.  Rather than have a bunch of repetitive
- * macros for the bit patterns, we just have a function that calculates
- * them.
- *
- * guts: Pointer to GUTS structure
- * co: The DMA controller (0 or 1)
- * ch: The channel on the DMA controller (0, 1, 2, or 3)
- * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
- */
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
-       unsigned int co, unsigned int ch, unsigned int device)
-{
-       unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
-
-       clrsetbits_be32(&guts->dmacr, 3 << shift, device << shift);
-}
-
-#define CCSR_GUTS_PMUXCR_LDPSEL                0x00010000
-#define CCSR_GUTS_PMUXCR_SSI1_MASK     0x0000C000      /* Bitmask for SSI1 */
-#define CCSR_GUTS_PMUXCR_SSI1_LA       0x00000000      /* Latched address */
-#define CCSR_GUTS_PMUXCR_SSI1_HI       0x00004000      /* High impedance */
-#define CCSR_GUTS_PMUXCR_SSI1_SSI      0x00008000      /* Used for SSI1 */
-#define CCSR_GUTS_PMUXCR_SSI2_MASK     0x00003000      /* Bitmask for SSI2 */
-#define CCSR_GUTS_PMUXCR_SSI2_LA       0x00000000      /* Latched address */
-#define CCSR_GUTS_PMUXCR_SSI2_HI       0x00001000      /* High impedance */
-#define CCSR_GUTS_PMUXCR_SSI2_SSI      0x00002000      /* Used for SSI2 */
-#define CCSR_GUTS_PMUXCR_LA_22_25_LA   0x00000000      /* Latched Address */
-#define CCSR_GUTS_PMUXCR_LA_22_25_HI   0x00000400      /* High impedance */
-#define CCSR_GUTS_PMUXCR_DBGDRV                0x00000200      /* Signals not driven */
-#define CCSR_GUTS_PMUXCR_DMA2_0                0x00000008
-#define CCSR_GUTS_PMUXCR_DMA2_3                0x00000004
-#define CCSR_GUTS_PMUXCR_DMA1_0                0x00000002
-#define CCSR_GUTS_PMUXCR_DMA1_3                0x00000001
-
-/*
- * Set the DMA external control bits in the GUTS
- *
- * The DMA external control bits in the PMUXCR are only meaningful for
- * channels 0 and 3.  Any other channels are ignored.
- *
- * guts: Pointer to GUTS structure
- * co: The DMA controller (0 or 1)
- * ch: The channel on the DMA controller (0, 1, 2, or 3)
- * value: the new value for the bit (0 or 1)
- */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
-       unsigned int co, unsigned int ch, unsigned int value)
-{
-       if ((ch == 0) || (ch == 3)) {
-               unsigned int shift = 2 * (co + 1) - (ch & 1) - 1;
-
-               clrsetbits_be32(&guts->pmuxcr, 1 << shift, value << shift);
-       }
-}
-
-#define CCSR_GUTS_CLKDVDR_PXCKEN       0x80000000
-#define CCSR_GUTS_CLKDVDR_SSICKEN      0x20000000
-#define CCSR_GUTS_CLKDVDR_PXCKINV      0x10000000
-#define CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT 25
-#define CCSR_GUTS_CLKDVDR_PXCKDLY_MASK 0x06000000
-#define CCSR_GUTS_CLKDVDR_PXCKDLY(x) \
-       (((x) & 3) << CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT)
-#define CCSR_GUTS_CLKDVDR_PXCLK_SHIFT  16
-#define CCSR_GUTS_CLKDVDR_PXCLK_MASK   0x001F0000
-#define CCSR_GUTS_CLKDVDR_PXCLK(x) (((x) & 31) << CCSR_GUTS_CLKDVDR_PXCLK_SHIFT)
-#define CCSR_GUTS_CLKDVDR_SSICLK_MASK  0x000000FF
-#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
-
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
index a7db96f2b5c38dfb4257974aace3739aa11361c7..47edde8c3556221b7371b225f32e1065b4b2fdb8 100644 (file)
@@ -308,12 +308,8 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
 #define pte_offset_kernel(dir, addr)   \
        ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir, addr)              \
-       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr)       \
-       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
-
-#define pte_unmap(pte)         kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte)  kunmap_atomic(pte, KM_PTE1)
+       ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
+#define pte_unmap(pte)         kunmap_atomic(pte)
 
 /*
  * Encode and decode a swap entry.
index 49865045d56f2559377a62c3938cb9656f76f360..2b09cd522d333d120ad97e1870bb63f12304e81b 100644 (file)
   (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 
 #define pte_offset_map(dir,addr)       pte_offset_kernel((dir), (addr))
-#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir), (addr))
 #define pte_unmap(pte)                 do { } while(0)
-#define pte_unmap_nested(pte)          do { } while(0)
 
 /* to find an entry in a kernel page-table-directory */
 /* This now only contains the vmalloc pages */
index 9b626cfffce17d2a8c487c15f50bdd5bc229695f..f62efdfd176989c142019351fe691b52edc5260f 100644 (file)
@@ -162,13 +162,10 @@ static int ibmebus_create_device(struct device_node *dn)
        dev->dev.bus = &ibmebus_bus_type;
        dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
 
-       ret = of_device_register(dev);
-       if (ret) {
-               of_device_free(dev);
-               return ret;
-       }
-
-       return 0;
+       ret = of_device_add(dev);
+       if (ret)
+               platform_device_put(dev);
+       return ret;
 }
 
 static int ibmebus_create_devices(const struct of_device_id *matches)
index c1fd0f9658fd715536b3b2a7ce57ca34de67eee4..c834757bebc07663ba44f2c779f210a4f308637d 100644 (file)
@@ -52,14 +52,14 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
                                  phys_addr_t taddr, unsigned long irq,
                                  upf_t flags, int irq_check_parent)
 {
-       const u32 *clk, *spd;
+       const __be32 *clk, *spd;
        u32 clock = BASE_BAUD * 16;
        int index;
 
        /* get clock freq. if present */
        clk = of_get_property(np, "clock-frequency", NULL);
        if (clk && *clk)
-               clock = *clk;
+               clock = be32_to_cpup(clk);
 
        /* get default speed if present */
        spd = of_get_property(np, "current-speed", NULL);
@@ -109,7 +109,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        legacy_serial_infos[index].taddr = taddr;
        legacy_serial_infos[index].np = of_node_get(np);
        legacy_serial_infos[index].clock = clock;
-       legacy_serial_infos[index].speed = spd ? *spd : 0;
+       legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0;
        legacy_serial_infos[index].irq_check_parent = irq_check_parent;
 
        printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
@@ -168,7 +168,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
 static int __init add_legacy_isa_port(struct device_node *np,
                                      struct device_node *isa_brg)
 {
-       const u32 *reg;
+       const __be32 *reg;
        const char *typep;
        int index = -1;
        u64 taddr;
@@ -181,7 +181,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
                return -1;
 
        /* Verify it's an IO port, we don't support anything else */
-       if (!(reg[0] & 0x00000001))
+       if (!(be32_to_cpu(reg[0]) & 0x00000001))
                return -1;
 
        /* Now look for an "ibm,aix-loc" property that gives us ordering
@@ -202,7 +202,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
                taddr = 0;
 
        /* Add port, irq will be dealt with later */
-       return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+       return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), taddr,
                               NO_IRQ, UPF_BOOT_AUTOCONF, 0);
 
 }
@@ -251,9 +251,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * we get to their "reg" property
         */
        if (np != pci_dev) {
-               const u32 *reg = of_get_property(np, "reg", NULL);
-               if (reg && (*reg < 4))
-                       index = lindex = *reg;
+               const __be32 *reg = of_get_property(np, "reg", NULL);
+               if (reg && (be32_to_cpup(reg) < 4))
+                       index = lindex = be32_to_cpup(reg);
        }
 
        /* Local index means it's the Nth port in the PCI chip. Unfortunately
@@ -507,7 +507,7 @@ static int __init check_legacy_serial_console(void)
        struct device_node *prom_stdout = NULL;
        int i, speed = 0, offset = 0;
        const char *name;
-       const u32 *spd;
+       const __be32 *spd;
 
        DBG(" -> check_legacy_serial_console()\n");
 
@@ -547,7 +547,7 @@ static int __init check_legacy_serial_console(void)
        }
        spd = of_get_property(prom_stdout, "current-speed", NULL);
        if (spd)
-               speed = *spd;
+               speed = be32_to_cpup(spd);
 
        if (strcmp(name, "serial") != 0)
                goto not_found;
index c3c6a88575441a5d68c75705a1ac68e0d130a5f7..9e3132db718b10115a076b0f3db09094afdb3d38 100644 (file)
@@ -364,10 +364,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
        return 0;
 }
 
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
+int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
+                                        int depth, void *data)
 {
        unsigned long *lprop;
 
+       /* Use common scan routine to determine if this is the chosen node */
+       if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
+               return 0;
+
 #ifdef CONFIG_PPC64
        /* check if iommu is forced on or off */
        if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -399,6 +404,9 @@ void __init early_init_dt_scan_chosen_arch(unsigned long node)
        if (lprop)
                crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
+
+       /* break now */
+       return 1;
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -683,7 +691,7 @@ void __init early_init_devtree(void *params)
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
         */
-       of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+       of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
 
        /* Scan memory nodes and rebuild MEMBLOCKs */
        memblock_init();
index d692989a4318273c06fc1fdc024448afd15d322d..441d2a722f0655b540b993c422c7f433585e1060 100644 (file)
@@ -238,9 +238,7 @@ static inline void vio_cmo_dealloc(struct vio_dev *viodev, size_t size)
         * memory in this pool does not change.
         */
        if (spare_needed && reserve_freed) {
-               tmp = min(spare_needed, min(reserve_freed,
-                                           (viodev->cmo.entitled -
-                                            VIO_CMO_MIN_ENT)));
+               tmp = min3(spare_needed, reserve_freed, (viodev->cmo.entitled - VIO_CMO_MIN_ENT));
 
                vio_cmo.spare += tmp;
                viodev->cmo.entitled -= tmp;
index 857d4173f9c69358209eaf8793b6b64f4f0cfd89..b0848b462bbceb6678a071889cc774e40f77cafd 100644 (file)
  * be used in IRQ contexts, so in some (very limited) cases we need
  * it.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-       unsigned int idx;
        unsigned long vaddr;
+       int idx, type;
 
        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
        pagefault_disable();
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -52,26 +52,33 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
 }
 EXPORT_SYMBOL(kmap_atomic_prot);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+       int type;
 
        if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
                pagefault_enable();
                return;
        }
 
-       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+       type = kmap_atomic_idx_pop();
 
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(&init_mm, vaddr, kmap_pte-idx);
-       local_flush_tlb_page(NULL, vaddr);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       {
+               unsigned int idx;
+
+               idx = type + KM_TYPE_NR * smp_processor_id();
+               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+               /*
+                * force other mappings to Oops if they'll try to access
+                * this pte without first remap it
+                */
+               pte_clear(&init_mm, vaddr, kmap_pte-idx);
+               local_flush_tlb_page(NULL, vaddr);
+       }
 #endif
        pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
index 2b390d19a1d179bfd1d1c0d58498f693ed1f4c27..7eb5c40c069fafb296b436c99241b721be33895f 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright 2010 Freescale Semiconductor, Inc.
  *
  * This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
  * 2) No AMP support
  * 3) No PCI endpoint support
  *
 #include <linux/pci.h>
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
-
+#include <asm/div64.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU.  This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN         0x80000000
+#define CLKDVDR_PXCKINV                0x10000000
+#define CLKDVDR_PXCKDLY                0x06000000
+#define CLKDVDR_PXCLK_MASK     0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN       0x80
+#define PX_BRDCFG1_DFPEN       0x40
+#define PX_BRDCFG1_BACKLIGHT   0x20
+#define PX_BRDCFG1_DDCEN       0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register.  So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F              0x10000000
+#define AD_ALPHA_C_MASK                0x0E000000
+#define AD_ALPHA_C_SHIFT       25
+#define AD_BLUE_C_MASK         0x01800000
+#define AD_BLUE_C_SHIFT                23
+#define AD_GREEN_C_MASK                0x00600000
+#define AD_GREEN_C_SHIFT       21
+#define AD_RED_C_MASK          0x00180000
+#define AD_RED_C_SHIFT         19
+#define AD_PALETTE             0x00040000
+#define AD_PIXEL_S_MASK                0x00030000
+#define AD_PIXEL_S_SHIFT       16
+#define AD_COMP_3_MASK         0x0000F000
+#define AD_COMP_3_SHIFT                12
+#define AD_COMP_2_MASK         0x00000F00
+#define AD_COMP_2_SHIFT                8
+#define AD_COMP_1_MASK         0x000000F0
+#define AD_COMP_1_SHIFT                4
+#define AD_COMP_0_MASK         0x0000000F
+#define AD_COMP_0_SHIFT                0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+       cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+       (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+       (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+       (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+       (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+       int monitor_port)
+{
+       switch (bits_per_pixel) {
+       case 32:
+               /* 0x88883316 */
+               return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+       case 24:
+               /* 0x88082219 */
+               return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+       case 16:
+               /* 0x65053118 */
+               return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+       default:
+               pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+               return 0;
+       }
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+       struct device_node *pixis_node;
+       u8 __iomem *brdcfg1;
+
+       pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+       if (!pixis_node) {
+               pr_err("p1022ds: missing ngPIXIS node\n");
+               return;
+       }
+
+       brdcfg1 = of_iomap(pixis_node, 0);
+       if (!brdcfg1) {
+               pr_err("p1022ds: could not map ngPIXIS registers\n");
+               return;
+       }
+       brdcfg1 += 9;   /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+       switch (monitor_port) {
+       case 0: /* DVI */
+               /* Enable the DVI port, disable the DFP and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DVIEN);
+               break;
+       case 1: /* Single link LVDS */
+               /* Enable the DFP port, disable the DVI and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DFPEN);
+               break;
+       default:
+               pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+       }
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+       struct device_node *guts_np = NULL;
+       struct ccsr_guts_85xx __iomem *guts;
+       unsigned long freq;
+       u64 temp;
+       u32 pxclk;
+
+       /* Map the global utilities registers. */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_np) {
+               pr_err("p1022ds: missing global utilties device node\n");
+               return;
+       }
+
+       guts = of_iomap(guts_np, 0);
+       of_node_put(guts_np);
+       if (!guts) {
+               pr_err("p1022ds: could not map global utilties device\n");
+               return;
+       }
+
+       /* Convert pixclock from a wavelength to a frequency */
+       temp = 1000000000000ULL;
+       do_div(temp, pixclock);
+       freq = temp;
+
+       /* pixclk is the ratio of the platform clock to the pixel clock */
+       pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+       /* Disable the pixel clock, and set it to non-inverted and no delay */
+       clrbits32(&guts->clkdvdr,
+                 CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+       /* Enable the clock and set the pxclk */
+       setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+       return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+               monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+       return val < 2 ? val : 0;
+}
+
+#endif
 
 void __init p1022_ds_pic_init(void)
 {
@@ -92,6 +290,15 @@ static void __init p1022_ds_setup_arch(void)
        }
 #endif
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+       diu_ops.get_pixel_format        = p1022ds_get_pixel_format;
+       diu_ops.set_gamma_table         = p1022ds_set_gamma_table;
+       diu_ops.set_monitor_port        = p1022ds_set_monitor_port;
+       diu_ops.set_pixel_clock         = p1022ds_set_pixel_clock;
+       diu_ops.show_monitor_port       = p1022ds_show_monitor_port;
+       diu_ops.set_sysfs_monitor_port  = p1022ds_set_sysfs_monitor_port;
+#endif
+
 #ifdef CONFIG_SMP
        mpc85xx_smp_init();
 #endif
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild
new file mode 100644 (file)
index 0000000..ae4b010
--- /dev/null
@@ -0,0 +1,6 @@
+obj-y += kernel/
+obj-y += mm/
+obj-y += crypto/
+obj-y += appldata/
+obj-y += hypfs/
+obj-y += kvm/
index 75976a14194770390154ca124d9e94f95eedecf4..068e55d1bba8ec9e5ce790f80fc25a73c48db624 100644 (file)
@@ -60,6 +60,9 @@ config NO_IOMEM
 config NO_DMA
        def_bool y
 
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool 64BIT
+
 config GENERIC_LOCKBREAK
        bool
        default y
@@ -101,6 +104,7 @@ config S390
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
+       select HAVE_GET_USER_PAGES_FAST
        select ARCH_INLINE_SPIN_TRYLOCK
        select ARCH_INLINE_SPIN_TRYLOCK_BH
        select ARCH_INLINE_SPIN_LOCK
@@ -286,6 +290,14 @@ config MARCH_Z10
          machines such as the z990, z890, z900, z800, z9-109, z9-ec
          and z9-bc.
 
+config MARCH_Z196
+       bool "IBM zEnterprise 196"
+       help
+         Select this to enable optimizations for IBM zEnterprise 196.
+         The kernel will be slightly faster but will not work on older
+         machines such as the z990, z890, z900, z800, z9-109, z9-ec,
+         z9-bc, z10-ec and z10-bc.
+
 endchoice
 
 config PACK_STACK
index 0c9e6c6d2a645f7df5f2f4f7f9f07824a327c0d1..d5b8a6ade525ca9327f8101c299afbeb12de2e11 100644 (file)
@@ -40,6 +40,7 @@ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
 cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
 cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
 cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10)
+cflags-$(CONFIG_MARCH_Z196) += $(call cc-option,-march=z196)
 
 #KBUILD_IMAGE is necessary for make rpm
 KBUILD_IMAGE   :=arch/s390/boot/image
@@ -94,8 +95,8 @@ head-y                := arch/s390/kernel/head.o
 head-y         += arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o)
 head-y         += arch/s390/kernel/init_task.o
 
-core-y         += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
-                  arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
+# See arch/s390/Kbuild for content of core part of the kernel
+core-y         += arch/s390/
 
 libs-y         += arch/s390/lib/
 drivers-y      += drivers/s390/
index 0ef9829f2ad69e2e15b743ac1582858a48124067..7ee9a1b4ad9f380a719efc27c5540c4c9b19f63e 100644 (file)
@@ -297,7 +297,7 @@ static inline int crypt_s390_func_available(int func)
        int ret;
 
        /* check if CPACF facility (bit 17) is available */
-       if (!(stfl() & 1ULL << (31 - 17)))
+       if (!test_facility(17))
                return 0;
 
        switch (func & CRYPT_S390_OP_MASK) {
index f3ba0fa98de6ce31647e67a6213a708ba1883ffb..e8501115eca85c7edb4dd8fa9c1d925cd7fee05d 100644 (file)
@@ -91,6 +91,16 @@ struct ccw_device {
        void (*handler) (struct ccw_device *, unsigned long, struct irb *);
 };
 
+/*
+ * Possible events used by the path_event notifier.
+ */
+#define PE_NONE                                0x0
+#define PE_PATH_GONE                   0x1 /* A path is no longer available. */
+#define PE_PATH_AVAILABLE              0x2 /* A path has become available and
+                                              was successfully verified. */
+#define PE_PATHGROUP_ESTABLISHED       0x4 /* A pathgroup was reset and had
+                                              to be established again. */
+
 /*
  * Possible CIO actions triggered by the unit check handler.
  */
@@ -109,6 +119,7 @@ enum uc_todo {
  * @set_online: called when setting device online
  * @set_offline: called when setting device offline
  * @notify: notify driver of device state changes
+ * @path_event: notify driver of channel path events
  * @shutdown: called at device shutdown
  * @prepare: prepare for pm state transition
  * @complete: undo work done in @prepare
@@ -127,6 +138,7 @@ struct ccw_driver {
        int (*set_online) (struct ccw_device *);
        int (*set_offline) (struct ccw_device *);
        int (*notify) (struct ccw_device *, int);
+       void (*path_event) (struct ccw_device *, int *);
        void (*shutdown) (struct ccw_device *);
        int (*prepare) (struct ccw_device *);
        void (*complete) (struct ccw_device *);
index 471234b905743d60768e2f893c517f53b1d07c13..e0b69540216f0839818fc4cfc3a18d98ee211415 100644 (file)
@@ -20,7 +20,7 @@ struct cpuid
        unsigned int ident   : 24;
        unsigned int machine : 16;
        unsigned int unused  : 16;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_S390_CPU_H */
index bb8343d157bc18b6117d02aa4ef164039b06f108..b56403c2df281d098aa67dc89d3ca9511b6ea5ea 100644 (file)
@@ -37,32 +37,6 @@ static inline int prepare_hugepage_range(struct file *file,
 int arch_prepare_hugepage(struct page *page);
 void arch_release_hugepage(struct page *page);
 
-static inline pte_t pte_mkhuge(pte_t pte)
-{
-       /*
-        * PROT_NONE needs to be remapped from the pte type to the ste type.
-        * The HW invalid bit is also different for pte and ste. The pte
-        * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
-        * bit, so we don't have to clear it.
-        */
-       if (pte_val(pte) & _PAGE_INVALID) {
-               if (pte_val(pte) & _PAGE_SWT)
-                       pte_val(pte) |= _HPAGE_TYPE_NONE;
-               pte_val(pte) |= _SEGMENT_ENTRY_INV;
-       }
-       /*
-        * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
-        * table entry.
-        */
-       pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
-       /*
-        * Also set the change-override bit because we don't need dirty bit
-        * tracking for hugetlbfs pages.
-        */
-       pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
-       return pte;
-}
-
 static inline pte_t huge_pte_wrprotect(pte_t pte)
 {
        pte_val(pte) |= _PAGE_RO;
index 0f97ef2d92acd8324aa3ee342c874a2ad071771b..65e172f8209d902798e05a884bc3c5ce8ef7f80c 100644 (file)
@@ -150,9 +150,10 @@ struct _lowcore {
         */
        __u32   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e04 */
+       __u8    pad_0x0e08[0x0f00-0x0e08];      /* 0x0e08 */
 
-       /* Align to the top 1k of prefix area */
-       __u8    pad_0x0e08[0x1000-0x0e08];      /* 0x0e08 */
+       /* Extended facility list */
+       __u64   stfle_fac_list[32];             /* 0x0f00 */
 } __packed;
 
 #else /* CONFIG_32BIT */
@@ -285,7 +286,11 @@ struct _lowcore {
         */
        __u64   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e08 */
-       __u8    pad_0x0e0c[0x11b8-0x0e0c];      /* 0x0e0c */
+       __u8    pad_0x0e0c[0x0f00-0x0e0c];      /* 0x0e0c */
+
+       /* Extended facility list */
+       __u64   stfle_fac_list[32];             /* 0x0f00 */
+       __u8    pad_0x1000[0x11b8-0x1000];      /* 0x1000 */
 
        /* 64 bit extparam used for pfault/diag 250: defined by architecture */
        __u64   ext_params2;                    /* 0x11B8 */
index af650fb472064a82c09ab508cab7ccd341412c79..a8729ea7e9ac1d12826fb4a0e76923a19af307fa 100644 (file)
@@ -108,9 +108,13 @@ typedef pte_t *pgtable_t;
 #define __pgprot(x)     ((pgprot_t) { (x) } )
 
 static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey)
+page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
 {
-       asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
+       if (!mapped)
+               asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
+                            : : "d" (skey), "a" (addr));
+       else
+               asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
 }
 
 static inline unsigned int
index 68940d0bad910912ecbfbb67dfb6364466dfc253..082eb4e50e8b3f53a59cc8343e619bfc6a60b6cc 100644 (file)
 
 unsigned long *crst_table_alloc(struct mm_struct *, int);
 void crst_table_free(struct mm_struct *, unsigned long *);
+void crst_table_free_rcu(struct mm_struct *, unsigned long *);
 
 unsigned long *page_table_alloc(struct mm_struct *);
 void page_table_free(struct mm_struct *, unsigned long *);
+void page_table_free_rcu(struct mm_struct *, unsigned long *);
 void disable_noexec(struct mm_struct *, struct task_struct *);
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
@@ -176,4 +178,6 @@ static inline void pmd_populate(struct mm_struct *mm,
 #define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte)
 #define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte)
 
+extern void rcu_table_freelist_finish(void);
+
 #endif /* _S390_PGALLOC_H */
index 3157441ee1da287345a1f1a6bfe79769939bd7d7..02ace3491c51cca92625f2a39f30fe9aa9741ddb 100644 (file)
@@ -38,6 +38,7 @@
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
 extern void vmem_map_init(void);
+extern void fault_init(void);
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
@@ -46,11 +47,27 @@ extern void vmem_map_init(void);
 #define update_mmu_cache(vma, address, ptep)     do { } while (0)
 
 /*
- * ZERO_PAGE is a global shared page that is always zero: used
+ * ZERO_PAGE is a global shared page that is always zero; used
  * for zero-mapped memory areas etc..
  */
-extern char empty_zero_page[PAGE_SIZE];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern unsigned long empty_zero_page;
+extern unsigned long zero_page_mask;
+
+#define ZERO_PAGE(vaddr) \
+       (virt_to_page((void *)(empty_zero_page + \
+        (((unsigned long)(vaddr)) &zero_page_mask))))
+
+#define is_zero_pfn is_zero_pfn
+static inline int is_zero_pfn(unsigned long pfn)
+{
+       extern unsigned long zero_pfn;
+       unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+       return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+#define my_zero_pfn(addr)      page_to_pfn(ZERO_PAGE(addr))
+
 #endif /* !__ASSEMBLY__ */
 
 /*
@@ -300,6 +317,7 @@ extern unsigned long VMALLOC_START;
 
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_ORIGIN  0x7fffffc0UL    /* page table origin        */
+#define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
 #define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
 #define _SEGMENT_ENTRY_COMMON  0x10    /* common segment bit               */
 #define _SEGMENT_ENTRY_PTL     0x0f    /* page table length                */
@@ -572,7 +590,7 @@ static inline void rcp_unlock(pte_t *ptep)
 }
 
 /* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page);
+static inline void page_clear_dirty(struct page *page, int mapped);
 #include <linux/page-flags.h>
 
 static inline void ptep_rcp_copy(pte_t *ptep)
@@ -754,6 +772,34 @@ static inline pte_t pte_mkspecial(pte_t pte)
        return pte;
 }
 
+#ifdef CONFIG_HUGETLB_PAGE
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+       /*
+        * PROT_NONE needs to be remapped from the pte type to the ste type.
+        * The HW invalid bit is also different for pte and ste. The pte
+        * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
+        * bit, so we don't have to clear it.
+        */
+       if (pte_val(pte) & _PAGE_INVALID) {
+               if (pte_val(pte) & _PAGE_SWT)
+                       pte_val(pte) |= _HPAGE_TYPE_NONE;
+               pte_val(pte) |= _SEGMENT_ENTRY_INV;
+       }
+       /*
+        * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
+        * table entry.
+        */
+       pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
+       /*
+        * Also set the change-override bit because we don't need dirty bit
+        * tracking for hugetlbfs pages.
+        */
+       pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+       return pte;
+}
+#endif
+
 #ifdef CONFIG_PGSTE
 /*
  * Get (and clear) the user dirty bit for a PTE.
@@ -782,7 +828,7 @@ static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
        }
        dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
        if (skey & _PAGE_CHANGED)
-               page_clear_dirty(page);
+               page_clear_dirty(page, 1);
        rcp_unlock(ptep);
        return dirty;
 }
@@ -957,9 +1003,9 @@ static inline int page_test_dirty(struct page *page)
 }
 
 #define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page)
+static inline void page_clear_dirty(struct page *page, int mapped)
 {
-       page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY);
+       page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
 }
 
 /*
@@ -1048,9 +1094,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
 #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr))
 #define pte_offset_kernel(pmd, address) pte_offset(pmd,address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 /*
  * 31 bit swap entry format:
index 73e259834e10d9bc3ecc5cced06860f6b3dd0b86..8d6f871695776ccbe0e483c6d12c9a3d0a656a48 100644 (file)
@@ -82,8 +82,6 @@ struct thread_struct {
         unsigned long prot_addr;        /* address of protection-excep.     */
         unsigned int trap_no;
         per_struct per_info;
-       /* Used to give failing instruction back to user for ieee exceptions */
-       unsigned long ieee_instruction_pointer; 
         /* pfault_wait is used to block the process on a pfault event */
        unsigned long pfault_wait;
 };
index e2c218dc68a6f91624acc5df7c2ddfb256d4b0fc..d9d42b1e46faedbd688aef69060fd847bcdc08a9 100644 (file)
@@ -481,8 +481,7 @@ struct user_regs_struct
         * watchpoints. This is the way intel does it.
         */
        per_struct per_info;
-       unsigned long ieee_instruction_pointer; 
-       /* Used to give failing instruction back to user for ieee exceptions */
+       unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
 };
 
 #ifdef __KERNEL__
index 2afc060266a2f4468d074174f8b9dd931f58255b..1a9307e7084253ba15963338fdf90bc12eecb977 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/types.h>
 
-typedef void (*ext_int_handler_t)(__u16 code);
+typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
 
 typedef struct ext_int_info_t {
        struct ext_int_info_t *next;
index 35d786fe93ae0dcba7e1cf434606e9e61d1b05c2..6d45ef6c12a73e23f2930bbbb816c30fa7f16a6f 100644 (file)
@@ -1 +1,3 @@
 #include <asm-generic/scatterlist.h>
+
+#define ARCH_HAS_SG_CHAIN
index 25e831d58e1ecde6a3dba239a6befcd7a6bfd808..d5e2ef10537d9a93882e3bc38b857cb2edf4f764 100644 (file)
@@ -73,6 +73,7 @@ extern unsigned int user_mode;
 #define MACHINE_FLAG_PFMF      (1UL << 11)
 #define MACHINE_FLAG_LPAR      (1UL << 12)
 #define MACHINE_FLAG_SPP       (1UL << 13)
+#define MACHINE_FLAG_TOPOLOGY  (1UL << 14)
 
 #define MACHINE_IS_VM          (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM         (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -90,6 +91,7 @@ extern unsigned int user_mode;
 #define MACHINE_HAS_HPAGE      (0)
 #define MACHINE_HAS_PFMF       (0)
 #define MACHINE_HAS_SPP                (0)
+#define MACHINE_HAS_TOPOLOGY   (0)
 #else /* __s390x__ */
 #define MACHINE_HAS_IEEE       (1)
 #define MACHINE_HAS_CSP                (1)
@@ -100,6 +102,7 @@ extern unsigned int user_mode;
 #define MACHINE_HAS_HPAGE      (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
 #define MACHINE_HAS_PFMF       (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
 #define MACHINE_HAS_SPP                (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
+#define MACHINE_HAS_TOPOLOGY   (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
 #endif /* __s390x__ */
 
 #define ZFCPDUMP_HSA_SIZE      (32UL<<20)
index 8429686951f94f7ffeff1fafdb9ea2f5bba6a7d6..5c0246b955d80e411250623c400c3387f23568b7 100644 (file)
@@ -65,8 +65,6 @@ static inline void syscall_get_arguments(struct task_struct *task,
        if (test_tsk_thread_flag(task, TIF_31BIT))
                mask = 0xffffffff;
 #endif
-       if (i + n == 6)
-               args[--n] = regs->args[0] & mask;
        while (n-- > 0)
                if (i + n > 0)
                        args[n] = regs->gprs[2 + i + n] & mask;
@@ -80,8 +78,6 @@ static inline void syscall_set_arguments(struct task_struct *task,
                                         const unsigned long *args)
 {
        BUG_ON(i + n > 6);
-       if (i + n == 6)
-               regs->args[0] = args[--n];
        while (n-- > 0)
                if (i + n > 0)
                        regs->gprs[2 + i + n] = args[n];
index 22bdb2a0ee5f00724d02e67e814c41f4aa115e49..79d3d6e2e9c5681787ca1c8064c35b6a87992668 100644 (file)
 #ifndef __ASM_S390_SYSINFO_H
 #define __ASM_S390_SYSINFO_H
 
+#include <asm/bitsperlong.h>
+
 struct sysinfo_1_1_1 {
-       char reserved_0[32];
+       unsigned short :16;
+       unsigned char ccr;
+       unsigned char cai;
+       char reserved_0[28];
        char manufacturer[16];
        char type[4];
        char reserved_1[12];
@@ -104,6 +109,39 @@ struct sysinfo_3_2_2 {
        char reserved_544[3552];
 };
 
+#define TOPOLOGY_CPU_BITS      64
+#define TOPOLOGY_NR_MAG                6
+
+struct topology_cpu {
+       unsigned char reserved0[4];
+       unsigned char :6;
+       unsigned char pp:2;
+       unsigned char reserved1;
+       unsigned short origin;
+       unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
+};
+
+struct topology_container {
+       unsigned char reserved[7];
+       unsigned char id;
+};
+
+union topology_entry {
+       unsigned char nl;
+       struct topology_cpu cpu;
+       struct topology_container container;
+};
+
+struct sysinfo_15_1_x {
+       unsigned char reserved0[2];
+       unsigned short length;
+       unsigned char mag[TOPOLOGY_NR_MAG];
+       unsigned char reserved1;
+       unsigned char mnest;
+       unsigned char reserved2[4];
+       union topology_entry tle[0];
+};
+
 static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
 {
        register int r0 asm("0") = (fc << 28) | sel1;
index 1f2ebc4afd828f47da56d6763be4a16ba713263c..3ad16dbf622eebea0529250dac2b8487b9c48427 100644 (file)
@@ -85,14 +85,16 @@ static inline void restore_access_regs(unsigned int *acrs)
        asm volatile("lam 0,15,%0" : : "Q" (*acrs));
 }
 
-#define switch_to(prev,next,last) do {                                      \
-       if (prev == next)                                                    \
-               break;                                                       \
-       save_fp_regs(&prev->thread.fp_regs);                                 \
-       restore_fp_regs(&next->thread.fp_regs);                              \
-       save_access_regs(&prev->thread.acrs[0]);                             \
-       restore_access_regs(&next->thread.acrs[0]);                          \
-       prev = __switch_to(prev,next);                                       \
+#define switch_to(prev,next,last) do {                                 \
+       if (prev->mm) {                                                 \
+               save_fp_regs(&prev->thread.fp_regs);                    \
+               save_access_regs(&prev->thread.acrs[0]);                \
+       }                                                               \
+       if (next->mm) {                                                 \
+               restore_fp_regs(&next->thread.fp_regs);                 \
+               restore_access_regs(&next->thread.acrs[0]);             \
+       }                                                               \
+       prev = __switch_to(prev,next);                                  \
 } while (0)
 
 extern void account_vtime(struct task_struct *, struct task_struct *);
@@ -418,30 +420,21 @@ extern void smp_ctl_clear_bit(int cr, int bit);
 
 #endif /* CONFIG_SMP */
 
-static inline unsigned int stfl(void)
-{
-       asm volatile(
-               "       .insn   s,0xb2b10000,0(0)\n" /* stfl */
-               "0:\n"
-               EX_TABLE(0b,0b));
-       return S390_lowcore.stfl_fac_list;
-}
+#define MAX_FACILITY_BIT (256*8)       /* stfle_fac_list has 256 bytes */
 
-static inline int __stfle(unsigned long long *list, int doublewords)
+/*
+ * The test_facility function uses the bit odering where the MSB is bit 0.
+ * That makes it easier to query facility bits with the bit number as
+ * documented in the Principles of Operation.
+ */
+static inline int test_facility(unsigned long nr)
 {
-       typedef struct { unsigned long long _[doublewords]; } addrtype;
-       register unsigned long __nr asm("0") = doublewords - 1;
-
-       asm volatile(".insn s,0xb2b00000,%0" /* stfle */
-                    : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
-       return __nr + 1;
-}
+       unsigned char *ptr;
 
-static inline int stfle(unsigned long long *list, int doublewords)
-{
-       if (!(stfl() & (1UL << 24)))
-               return -EOPNOTSUPP;
-       return __stfle(list, doublewords);
+       if (nr >= MAX_FACILITY_BIT)
+               return 0;
+       ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
+       return (*ptr & (0x80 >> (nr & 7))) != 0;
 }
 
 static inline unsigned short stap(void)
index fd1c00d08bf57ca1ead5095746ba082847f52752..f1f644f2240a5cd377042a7dfe63bf546fde6da5 100644 (file)
@@ -64,10 +64,9 @@ static inline void tlb_flush_mmu(struct mmu_gather *tlb,
        if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
                __tlb_flush_mm(tlb->mm);
        while (tlb->nr_ptes > 0)
-               pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
+               page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
        while (tlb->nr_pxds < TLB_NR_PTRS)
-               /* pgd_free frees the pointer as region or segment table */
-               pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]);
+               crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -75,6 +74,8 @@ static inline void tlb_finish_mmu(struct mmu_gather *tlb,
 {
        tlb_flush_mmu(tlb, start, end);
 
+       rcu_table_freelist_finish();
+
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
@@ -103,7 +104,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                if (tlb->nr_ptes >= tlb->nr_pxds)
                        tlb_flush_mmu(tlb, 0, 0);
        } else
-               pte_free(tlb->mm, pte);
+               page_table_free(tlb->mm, (unsigned long *) pte);
 }
 
 /*
@@ -124,7 +125,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
                if (tlb->nr_ptes >= tlb->nr_pxds)
                        tlb_flush_mmu(tlb, 0, 0);
        } else
-               pmd_free(tlb->mm, pmd);
+               crst_table_free(tlb->mm, (unsigned long *) pmd);
 #endif
 }
 
@@ -146,7 +147,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
                if (tlb->nr_ptes >= tlb->nr_pxds)
                        tlb_flush_mmu(tlb, 0, 0);
        } else
-               pud_free(tlb->mm, pud);
+               crst_table_free(tlb->mm, (unsigned long *) pud);
 #endif
 }
 
index 051107a2c5e249397f71163544ae105dbde6d302..c5338834ddbdfb6614be4d8079afcef4deda1ca2 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_S390_TOPOLOGY_H
 
 #include <linux/cpumask.h>
+#include <asm/sysinfo.h>
 
 extern unsigned char cpu_core_id[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
@@ -32,6 +33,7 @@ static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
 
 int topology_set_cpu_management(int fc);
 void topology_schedule_update(void);
+void store_topology(struct sysinfo_15_1_x *info);
 
 #define POLARIZATION_UNKNWN    (-1)
 #define POLARIZATION_HRZ       (0)
index 5232278d79adc289cae995a78d51fd04c90b096f..f3c1b823c9a83b3a4ed4a0c4a4359e11b5934af1 100644 (file)
@@ -84,6 +84,7 @@ int main(void)
        DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
        DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
        DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
+       DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
        DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
        DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
        DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
@@ -142,10 +143,8 @@ int main(void)
        DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
        DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
 #ifdef CONFIG_32BIT
-       DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
        DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
 #else /* CONFIG_32BIT */
-       DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2));
        DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
        DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
        DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
index 123dd660d7fbed3793ed34a6dee6add2bc25c05a..3141025724f418e51d4420cc07aa340efb89d6e9 100644 (file)
@@ -51,8 +51,7 @@ struct user_regs_struct32
         * watchpoints. This is the way intel does it.
         */
        per_struct32 per_info;
-       u32  ieee_instruction_pointer; 
-       /* Used to give failing instruction back to user for ieee exceptions */
+       u32  ieee_instruction_pointer;  /* obsolete, always 0 */
 };
 
 struct user32 {
index b39b27d68b456bf04c0b8eca232c027d900d8117..c83726c9fe033d9f74ed9524c5a12e0722386142 100644 (file)
@@ -113,7 +113,7 @@ enum {
        INSTR_INVALID,
        INSTR_E,
        INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU,
-       INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU,
+       INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, INSTR_RIE_RRI0,
        INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP,
        INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU,
        INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
@@ -122,13 +122,14 @@ enum {
        INSTR_RRE_RR, INSTR_RRE_RR_OPT,
        INSTR_RRF_0UFF, INSTR_RRF_F0FF, INSTR_RRF_F0FF2, INSTR_RRF_F0FR,
        INSTR_RRF_FFRU, INSTR_RRF_FUFF, INSTR_RRF_M0RR, INSTR_RRF_R0RR,
-       INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, INSTR_RRF_U0RR,
-       INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
+       INSTR_RRF_R0RR2, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF,
+       INSTR_RRF_U0RR, INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
        INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
        INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD,
        INSTR_RSI_RRP,
        INSTR_RSL_R0RD,
        INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
+       INSTR_RSY_RDRM,
        INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
        INSTR_RS_RURD,
        INSTR_RXE_FRRD, INSTR_RXE_RRRD,
@@ -139,7 +140,7 @@ enum {
        INSTR_SIY_IRD, INSTR_SIY_URD,
        INSTR_SI_URD,
        INSTR_SSE_RDRD,
-       INSTR_SSF_RRDRD,
+       INSTR_SSF_RRDRD, INSTR_SSF_RRDRD2,
        INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD,
        INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
        INSTR_S_00, INSTR_S_RD,
@@ -152,7 +153,7 @@ struct operand {
 };
 
 struct insn {
-       const char name[6];
+       const char name[5];
        unsigned char opfrag;
        unsigned char format;
 };
@@ -217,6 +218,7 @@ static const unsigned char formats[][7] = {
        [INSTR_RIE_RRP]   = { 0xff, R_8,R_12,J16_16,0,0,0 },
        [INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 },
        [INSTR_RIE_RUPI]  = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 },
+       [INSTR_RIE_RRI0]  = { 0xff, R_8,R_12,I16_16,0,0,0 },
        [INSTR_RIL_RI]    = { 0x0f, R_8,I32_16,0,0,0,0 },
        [INSTR_RIL_RP]    = { 0x0f, R_8,J32_16,0,0,0,0 },
        [INSTR_RIL_RU]    = { 0x0f, R_8,U32_16,0,0,0,0 },
@@ -248,6 +250,7 @@ static const unsigned char formats[][7] = {
        [INSTR_RRF_FUFF]  = { 0xff, F_24,F_16,F_28,U4_20,0,0 },
        [INSTR_RRF_M0RR]  = { 0xff, R_24,R_28,M_16,0,0,0 },
        [INSTR_RRF_R0RR]  = { 0xff, R_24,R_16,R_28,0,0,0 },
+       [INSTR_RRF_R0RR2] = { 0xff, R_24,R_28,R_16,0,0,0 },
        [INSTR_RRF_RURR]  = { 0xff, R_24,R_28,R_16,U4_20,0,0 },
        [INSTR_RRF_U0FF]  = { 0xff, F_24,U4_16,F_28,0,0,0 },
        [INSTR_RRF_U0RF]  = { 0xff, R_24,U4_16,F_28,0,0,0 },
@@ -269,6 +272,7 @@ static const unsigned char formats[][7] = {
        [INSTR_RSY_CCRD]  = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
        [INSTR_RSY_RRRD]  = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
        [INSTR_RSY_RURD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
+       [INSTR_RSY_RDRM]  = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
        [INSTR_RS_AARD]   = { 0xff, A_8,A_12,D_20,B_16,0,0 },
        [INSTR_RS_CCRD]   = { 0xff, C_8,C_12,D_20,B_16,0,0 },
        [INSTR_RS_R0RD]   = { 0xff, R_8,D_20,B_16,0,0,0 },
@@ -290,6 +294,7 @@ static const unsigned char formats[][7] = {
        [INSTR_SI_URD]    = { 0xff, D_20,B_16,U8_8,0,0,0 },
        [INSTR_SSE_RDRD]  = { 0xff, D_20,B_16,D_36,B_32,0,0 },
        [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 },
+       [INSTR_SSF_RRDRD2]= { 0x00, R_8,D_20,B_16,D_36,B_32,0 },
        [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
        [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
        [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
@@ -300,6 +305,36 @@ static const unsigned char formats[][7] = {
        [INSTR_S_RD]      = { 0xff, D_20,B_16,0,0,0,0 },
 };
 
+enum {
+       LONG_INSN_ALGHSIK,
+       LONG_INSN_ALHSIK,
+       LONG_INSN_CLFHSI,
+       LONG_INSN_CLGFRL,
+       LONG_INSN_CLGHRL,
+       LONG_INSN_CLGHSI,
+       LONG_INSN_CLHHSI,
+       LONG_INSN_LLGFRL,
+       LONG_INSN_LLGHRL,
+       LONG_INSN_POPCNT,
+       LONG_INSN_RISBHG,
+       LONG_INSN_RISBLG,
+};
+
+static char *long_insn_name[] = {
+       [LONG_INSN_ALGHSIK] = "alghsik",
+       [LONG_INSN_ALHSIK] = "alhsik",
+       [LONG_INSN_CLFHSI] = "clfhsi",
+       [LONG_INSN_CLGFRL] = "clgfrl",
+       [LONG_INSN_CLGHRL] = "clghrl",
+       [LONG_INSN_CLGHSI] = "clghsi",
+       [LONG_INSN_CLHHSI] = "clhhsi",
+       [LONG_INSN_LLGFRL] = "llgfrl",
+       [LONG_INSN_LLGHRL] = "llghrl",
+       [LONG_INSN_POPCNT] = "popcnt",
+       [LONG_INSN_RISBHG] = "risbhg",
+       [LONG_INSN_RISBLG] = "risblk",
+};
+
 static struct insn opcode[] = {
 #ifdef CONFIG_64BIT
        { "lmd", 0xef, INSTR_SS_RRRDRD3 },
@@ -881,6 +916,35 @@ static struct insn opcode_b9[] = {
        { "pfmf", 0xaf, INSTR_RRE_RR },
        { "trte", 0xbf, INSTR_RRF_M0RR },
        { "trtre", 0xbd, INSTR_RRF_M0RR },
+       { "ahhhr", 0xc8, INSTR_RRF_R0RR2 },
+       { "shhhr", 0xc9, INSTR_RRF_R0RR2 },
+       { "alhhh", 0xca, INSTR_RRF_R0RR2 },
+       { "alhhl", 0xca, INSTR_RRF_R0RR2 },
+       { "slhhh", 0xcb, INSTR_RRF_R0RR2 },
+       { "chhr ", 0xcd, INSTR_RRE_RR },
+       { "clhhr", 0xcf, INSTR_RRE_RR },
+       { "ahhlr", 0xd8, INSTR_RRF_R0RR2 },
+       { "shhlr", 0xd9, INSTR_RRF_R0RR2 },
+       { "slhhl", 0xdb, INSTR_RRF_R0RR2 },
+       { "chlr", 0xdd, INSTR_RRE_RR },
+       { "clhlr", 0xdf, INSTR_RRE_RR },
+       { { 0, LONG_INSN_POPCNT }, 0xe1, INSTR_RRE_RR },
+       { "locgr", 0xe2, INSTR_RRF_M0RR },
+       { "ngrk", 0xe4, INSTR_RRF_R0RR2 },
+       { "ogrk", 0xe6, INSTR_RRF_R0RR2 },
+       { "xgrk", 0xe7, INSTR_RRF_R0RR2 },
+       { "agrk", 0xe8, INSTR_RRF_R0RR2 },
+       { "sgrk", 0xe9, INSTR_RRF_R0RR2 },
+       { "algrk", 0xea, INSTR_RRF_R0RR2 },
+       { "slgrk", 0xeb, INSTR_RRF_R0RR2 },
+       { "locr", 0xf2, INSTR_RRF_M0RR },
+       { "nrk", 0xf4, INSTR_RRF_R0RR2 },
+       { "ork", 0xf6, INSTR_RRF_R0RR2 },
+       { "xrk", 0xf7, INSTR_RRF_R0RR2 },
+       { "ark", 0xf8, INSTR_RRF_R0RR2 },
+       { "srk", 0xf9, INSTR_RRF_R0RR2 },
+       { "alrk", 0xfa, INSTR_RRF_R0RR2 },
+       { "slrk", 0xfb, INSTR_RRF_R0RR2 },
 #endif
        { "kmac", 0x1e, INSTR_RRE_RR },
        { "lrvr", 0x1f, INSTR_RRE_RR },
@@ -949,9 +1013,9 @@ static struct insn opcode_c4[] = {
        { "lgfrl", 0x0c, INSTR_RIL_RP },
        { "lhrl", 0x05, INSTR_RIL_RP },
        { "lghrl", 0x04, INSTR_RIL_RP },
-       { "llgfrl", 0x0e, INSTR_RIL_RP },
+       { { 0, LONG_INSN_LLGFRL }, 0x0e, INSTR_RIL_RP },
        { "llhrl", 0x02, INSTR_RIL_RP },
-       { "llghrl", 0x06, INSTR_RIL_RP },
+       { { 0, LONG_INSN_LLGHRL }, 0x06, INSTR_RIL_RP },
        { "strl", 0x0f, INSTR_RIL_RP },
        { "stgrl", 0x0b, INSTR_RIL_RP },
        { "sthrl", 0x07, INSTR_RIL_RP },
@@ -968,9 +1032,9 @@ static struct insn opcode_c6[] = {
        { "cghrl", 0x04, INSTR_RIL_RP },
        { "clrl", 0x0f, INSTR_RIL_RP },
        { "clgrl", 0x0a, INSTR_RIL_RP },
-       { "clgfrl", 0x0e, INSTR_RIL_RP },
+       { { 0, LONG_INSN_CLGFRL }, 0x0e, INSTR_RIL_RP },
        { "clhrl", 0x07, INSTR_RIL_RP },
-       { "clghrl", 0x06, INSTR_RIL_RP },
+       { { 0, LONG_INSN_CLGHRL }, 0x06, INSTR_RIL_RP },
        { "pfdrl", 0x02, INSTR_RIL_UP },
        { "exrl", 0x00, INSTR_RIL_RP },
 #endif
@@ -982,6 +1046,20 @@ static struct insn opcode_c8[] = {
        { "mvcos", 0x00, INSTR_SSF_RRDRD },
        { "ectg", 0x01, INSTR_SSF_RRDRD },
        { "csst", 0x02, INSTR_SSF_RRDRD },
+       { "lpd", 0x04, INSTR_SSF_RRDRD2 },
+       { "lpdg ", 0x05, INSTR_SSF_RRDRD2 },
+#endif
+       { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_cc[] = {
+#ifdef CONFIG_64BIT
+       { "brcth", 0x06, INSTR_RIL_RP },
+       { "aih", 0x08, INSTR_RIL_RI },
+       { "alsih", 0x0a, INSTR_RIL_RI },
+       { "alsih", 0x0b, INSTR_RIL_RI },
+       { "cih", 0x0d, INSTR_RIL_RI },
+       { "clih ", 0x0f, INSTR_RIL_RI },
 #endif
        { "", 0, INSTR_INVALID }
 };
@@ -1063,6 +1141,16 @@ static struct insn opcode_e3[] = {
        { "mfy", 0x5c, INSTR_RXY_RRRD },
        { "mhy", 0x7c, INSTR_RXY_RRRD },
        { "pfd", 0x36, INSTR_RXY_URRD },
+       { "lbh", 0xc0, INSTR_RXY_RRRD },
+       { "llch", 0xc2, INSTR_RXY_RRRD },
+       { "stch", 0xc3, INSTR_RXY_RRRD },
+       { "lhh", 0xc4, INSTR_RXY_RRRD },
+       { "llhh", 0xc6, INSTR_RXY_RRRD },
+       { "sthh", 0xc7, INSTR_RXY_RRRD },
+       { "lfh", 0xca, INSTR_RXY_RRRD },
+       { "stfh", 0xcb, INSTR_RXY_RRRD },
+       { "chf", 0xcd, INSTR_RXY_RRRD },
+       { "clhf", 0xcf, INSTR_RXY_RRRD },
 #endif
        { "lrv", 0x1e, INSTR_RXY_RRRD },
        { "lrvh", 0x1f, INSTR_RXY_RRRD },
@@ -1080,9 +1168,9 @@ static struct insn opcode_e5[] = {
        { "chhsi", 0x54, INSTR_SIL_RDI },
        { "chsi", 0x5c, INSTR_SIL_RDI },
        { "cghsi", 0x58, INSTR_SIL_RDI },
-       { "clhhsi", 0x55, INSTR_SIL_RDU },
-       { "clfhsi", 0x5d, INSTR_SIL_RDU },
-       { "clghsi", 0x59, INSTR_SIL_RDU },
+       { { 0, LONG_INSN_CLHHSI }, 0x55, INSTR_SIL_RDU },
+       { { 0, LONG_INSN_CLFHSI }, 0x5d, INSTR_SIL_RDU },
+       { { 0, LONG_INSN_CLGHSI }, 0x59, INSTR_SIL_RDU },
        { "mvhhi", 0x44, INSTR_SIL_RDI },
        { "mvhi", 0x4c, INSTR_SIL_RDI },
        { "mvghi", 0x48, INSTR_SIL_RDI },
@@ -1137,6 +1225,24 @@ static struct insn opcode_eb[] = {
        { "alsi", 0x6e, INSTR_SIY_IRD },
        { "algsi", 0x7e, INSTR_SIY_IRD },
        { "ecag", 0x4c, INSTR_RSY_RRRD },
+       { "srak", 0xdc, INSTR_RSY_RRRD },
+       { "slak", 0xdd, INSTR_RSY_RRRD },
+       { "srlk", 0xde, INSTR_RSY_RRRD },
+       { "sllk", 0xdf, INSTR_RSY_RRRD },
+       { "locg", 0xe2, INSTR_RSY_RDRM },
+       { "stocg", 0xe3, INSTR_RSY_RDRM },
+       { "lang", 0xe4, INSTR_RSY_RRRD },
+       { "laog", 0xe6, INSTR_RSY_RRRD },
+       { "laxg", 0xe7, INSTR_RSY_RRRD },
+       { "laag", 0xe8, INSTR_RSY_RRRD },
+       { "laalg", 0xea, INSTR_RSY_RRRD },
+       { "loc", 0xf2, INSTR_RSY_RDRM },
+       { "stoc", 0xf3, INSTR_RSY_RDRM },
+       { "lan", 0xf4, INSTR_RSY_RRRD },
+       { "lao", 0xf6, INSTR_RSY_RRRD },
+       { "lax", 0xf7, INSTR_RSY_RRRD },
+       { "laa", 0xf8, INSTR_RSY_RRRD },
+       { "laal", 0xfa, INSTR_RSY_RRRD },
 #endif
        { "rll", 0x1d, INSTR_RSY_RRRD },
        { "mvclu", 0x8e, INSTR_RSY_RRRD },
@@ -1172,6 +1278,12 @@ static struct insn opcode_ec[] = {
        { "rxsbg", 0x57, INSTR_RIE_RRUUU },
        { "rosbg", 0x56, INSTR_RIE_RRUUU },
        { "risbg", 0x55, INSTR_RIE_RRUUU },
+       { { 0, LONG_INSN_RISBLG }, 0x51, INSTR_RIE_RRUUU },
+       { { 0, LONG_INSN_RISBHG }, 0x5D, INSTR_RIE_RRUUU },
+       { "ahik", 0xd8, INSTR_RIE_RRI0 },
+       { "aghik", 0xd9, INSTR_RIE_RRI0 },
+       { { 0, LONG_INSN_ALHSIK }, 0xda, INSTR_RIE_RRI0 },
+       { { 0, LONG_INSN_ALGHSIK }, 0xdb, INSTR_RIE_RRI0 },
 #endif
        { "", 0, INSTR_INVALID }
 };
@@ -1321,6 +1433,9 @@ static struct insn *find_insn(unsigned char *code)
        case 0xc8:
                table = opcode_c8;
                break;
+       case 0xcc:
+               table = opcode_cc;
+               break;
        case 0xe3:
                table = opcode_e3;
                opfrag = code[5];
@@ -1367,7 +1482,11 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
        ptr = buffer;
        insn = find_insn(code);
        if (insn) {
-               ptr += sprintf(ptr, "%.5s\t", insn->name);
+               if (insn->name[0] == '\0')
+                       ptr += sprintf(ptr, "%s\t",
+                                      long_insn_name[(int) insn->name[1]]);
+               else
+                       ptr += sprintf(ptr, "%.5s\t", insn->name);
                /* Extract the operands. */
                separator = 0;
                for (ops = formats[insn->format] + 1, i = 0;
index c00856ad4e5a15b00450322053914964122f7cf7..d149609e46e63c0ebc518140fd9983a7d70a95ce 100644 (file)
@@ -208,7 +208,8 @@ static noinline __init void init_kernel_storage_key(void)
        end_pfn = PFN_UP(__pa(&_end));
 
        for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
-               page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+               page_set_storage_key(init_pfn << PAGE_SHIFT,
+                                    PAGE_DEFAULT_KEY, 0);
 }
 
 static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
@@ -255,13 +256,35 @@ static noinline __init void setup_lowcore_early(void)
        s390_base_pgm_handler_fn = early_pgm_check_handler;
 }
 
+static noinline __init void setup_facility_list(void)
+{
+       unsigned long nr;
+
+       S390_lowcore.stfl_fac_list = 0;
+       asm volatile(
+               "       .insn   s,0xb2b10000,0(0)\n" /* stfl */
+               "0:\n"
+               EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
+       memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
+       nr = 4;                         /* # bytes stored by stfl */
+       if (test_facility(7)) {
+               /* More facility bits available with stfle */
+               register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
+               asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+                            : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
+                            : : "cc");
+               nr = (reg0 + 1) * 8;    /* # bytes stored by stfle */
+       }
+       memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
+              MAX_FACILITY_BIT/8 - nr);
+}
+
 static noinline __init void setup_hpage(void)
 {
 #ifndef CONFIG_DEBUG_PAGEALLOC
        unsigned int facilities;
 
-       facilities = stfl();
-       if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
+       if (!test_facility(2) || !test_facility(8))
                return;
        S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
        __ctl_set_bit(0, 23);
@@ -355,18 +378,15 @@ static __init void detect_diag44(void)
 static __init void detect_machine_facilities(void)
 {
 #ifdef CONFIG_64BIT
-       unsigned int facilities;
-       unsigned long long facility_bits;
-
-       facilities = stfl();
-       if (facilities & (1 << 28))
+       if (test_facility(3))
                S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
-       if (facilities & (1 << 23))
+       if (test_facility(8))
                S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
-       if (facilities & (1 << 4))
+       if (test_facility(11))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
+       if (test_facility(27))
                S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
-       if ((stfle(&facility_bits, 1) > 0) &&
-           (facility_bits & (1ULL << (63 - 40))))
+       if (test_facility(40))
                S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
 #endif
 }
@@ -447,6 +467,7 @@ void __init startup_init(void)
        lockdep_off();
        sort_main_extable();
        setup_lowcore_early();
+       setup_facility_list();
        detect_machine_type();
        ipl_update_parameters();
        setup_boot_command_line();
index bea9ee37ac9d2fc78cb9c5c7da4454bf529cb955..5efce7202984ad969031922a21a39531014782de 100644 (file)
@@ -72,25 +72,9 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r1,BASED(.Ltrace_irq_off_caller)
        basr    %r14,%r1
        .endm
-
-       .macro  TRACE_IRQS_CHECK_ON
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       bz      BASED(0f)
-       TRACE_IRQS_ON
-0:
-       .endm
-
-       .macro  TRACE_IRQS_CHECK_OFF
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       bz      BASED(0f)
-       TRACE_IRQS_OFF
-0:
-       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@ STACK_SIZE  = 1 << STACK_SHIFT
        lpsw    \psworg                 # back to caller
        .endm
 
+       .macro REENABLE_IRQS
+       mvc     __SF_EMPTY(1,%r15),SP_PSW(%r15)
+       ni      __SF_EMPTY(%r15),0xbf
+       ssm     __SF_EMPTY(%r15)
+       .endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -264,12 +254,11 @@ sysc_do_svc:
        bnl     BASED(sysc_nr_ok)
        lr      %r7,%r1           # copy svc number to %r7
 sysc_nr_ok:
-       mvc     SP_ARGS(4,%r15),SP_R7(%r15)
-sysc_do_restart:
        sth     %r7,SP_SVCNR(%r15)
        sll     %r7,2             # svc number *4
        l       %r8,BASED(.Lsysc_table)
        tm      __TI_flags+2(%r9),_TIF_SYSCALL
+       mvc     SP_ARGS(4,%r15),SP_R7(%r15)
        l       %r8,0(%r7,%r8)    # get system call addr.
        bnz     BASED(sysc_tracesys)
        basr    %r14,%r8          # call sys_xxxx
@@ -357,7 +346,7 @@ sysc_restart:
        l       %r7,SP_R2(%r15)         # load new svc number
        mvc     SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
        lm      %r2,%r6,SP_R2(%r15)     # load svc arguments
-       b       BASED(sysc_do_restart)  # restart svc
+       b       BASED(sysc_nr_ok)       # restart svc
 
 #
 # _TIF_SINGLE_STEP is set, call do_single_step
@@ -390,6 +379,7 @@ sysc_tracesys:
        l       %r8,0(%r7,%r8)
 sysc_tracego:
        lm      %r3,%r6,SP_R3(%r15)
+       mvc     SP_ARGS(4,%r15),SP_R7(%r15)
        l       %r2,SP_ORIG_R2(%r15)
        basr    %r14,%r8                # call sys_xxx
        st      %r2,SP_R2(%r15)         # store return value
@@ -440,13 +430,11 @@ kernel_execve:
        br      %r14
        # execve succeeded.
 0:     stnsm   __SF_EMPTY(%r15),0xfc   # disable interrupts
-       TRACE_IRQS_OFF
        l       %r15,__LC_KERNEL_STACK  # load ksp
        s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
        l       %r9,__LC_THREAD_INFO
        mvc     SP_PTREGS(__PT_SIZE,%r15),0(%r12)       # copy pt_regs
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        l       %r1,BASED(.Lexecve_tail)
        basr    %r14,%r1
@@ -483,9 +471,10 @@ pgm_check_handler:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
-       TRACE_IRQS_CHECK_OFF
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        l       %r3,__LC_PGM_ILC        # load program interruption code
+       l       %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        la      %r8,0x7f
        nr      %r8,%r3
 pgm_do_call:
@@ -495,7 +484,6 @@ pgm_do_call:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r7                # branch to interrupt-handler
 pgm_exit:
-       TRACE_IRQS_CHECK_ON
        b       BASED(sysc_return)
 
 #
@@ -523,7 +511,6 @@ pgm_per_std:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
-       TRACE_IRQS_CHECK_OFF
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        l       %r1,__TI_task(%r9)
        tm      SP_PSW+1(%r15),0x01     # kernel per event ?
@@ -533,6 +520,8 @@ pgm_no_vtime2:
        mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
        oi      __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        l       %r3,__LC_PGM_ILC        # load program interruption code
+       l       %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        la      %r8,0x7f
        nr      %r8,%r3                 # clear per-event-bit and ilc
        be      BASED(pgm_exit2)        # only per or per+check ?
@@ -542,8 +531,6 @@ pgm_no_vtime2:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r7                # branch to interrupt-handler
 pgm_exit2:
-       TRACE_IRQS_ON
-       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        b       BASED(sysc_return)
 
 #
@@ -557,13 +544,11 @@ pgm_svcper:
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        lh      %r7,0x8a                # get svc number from lowcore
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
-       TRACE_IRQS_OFF
        l       %r8,__TI_task(%r9)
        mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
        mvc     __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
        mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        lm      %r2,%r6,SP_R2(%r15)     # load svc arguments
        b       BASED(sysc_do_svc)
@@ -737,7 +722,8 @@ ext_no_vtime:
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        TRACE_IRQS_OFF
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
-       lh      %r3,__LC_EXT_INT_CODE   # get interruption code
+       l       %r3,__LC_CPU_ADDRESS    # get cpu address + interruption code
+       l       %r4,__LC_EXT_PARAMS     # get external parameters
        l       %r1,BASED(.Ldo_extint)
        basr    %r14,%r1
        b       BASED(io_return)
index ff579b6bde066e35b306669039773733d61509ef..95c1dfc4ef315678fbabdc53a437109c5833f310 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/signal.h>
 #include <asm/ptrace.h>
 
-typedef void pgm_check_handler_t(struct pt_regs *, long);
+typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
 extern pgm_check_handler_t *pgm_check_table[128];
 pgm_check_handler_t do_protection_exception;
 pgm_check_handler_t do_dat_exception;
@@ -19,7 +19,7 @@ void do_signal(struct pt_regs *regs);
 int handle_signal32(unsigned long sig, struct k_sigaction *ka,
                    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
 
-void do_extint(struct pt_regs *regs, unsigned short code);
+void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
 int __cpuinit start_secondary(void *cpuvoid);
 void __init startup_init(void);
 void die(const char * str, struct pt_regs * regs, long err);
index 8bccec15ea90086a557de590f90977d1e018cb4f..a2be23922f4339849b97551e67f1c67fc0cbfbe7 100644 (file)
@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
        basr    %r2,%r0
        brasl   %r14,trace_hardirqs_off_caller
        .endm
-
-       .macro TRACE_IRQS_CHECK_ON
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       jz      0f
-       TRACE_IRQS_ON
-0:
-       .endm
-
-       .macro TRACE_IRQS_CHECK_OFF
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       jz      0f
-       TRACE_IRQS_OFF
-0:
-       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
 0:
        .endm
 
+       .macro REENABLE_IRQS
+       mvc     __SF_EMPTY(1,%r15),SP_PSW(%r15)
+       ni      __SF_EMPTY(%r15),0xbf
+       ssm     __SF_EMPTY(%r15)
+       .endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -256,7 +246,6 @@ sysc_saveall:
        CREATE_STACK_FRAME __LC_SAVE_AREA
        mvc     SP_PSW(16,%r15),__LC_SVC_OLD_PSW
        mvc     SP_ILC(4,%r15),__LC_SVC_ILC
-       stg     %r7,SP_ARGS(%r15)
        lg      %r12,__LC_THREAD_INFO   # load pointer to thread_info struct
 sysc_vtime:
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -284,6 +273,7 @@ sysc_nr_ok:
 sysc_noemu:
 #endif
        tm      __TI_flags+6(%r12),_TIF_SYSCALL
+       mvc     SP_ARGS(8,%r15),SP_R7(%r15)
        lgf     %r8,0(%r7,%r10) # load address of system call routine
        jnz     sysc_tracesys
        basr    %r14,%r8        # call sys_xxxx
@@ -397,6 +387,7 @@ sysc_tracesys:
        lgf     %r8,0(%r7,%r10)
 sysc_tracego:
        lmg     %r3,%r6,SP_R3(%r15)
+       mvc     SP_ARGS(8,%r15),SP_R7(%r15)
        lg      %r2,SP_ORIG_R2(%r15)
        basr    %r14,%r8                # call sys_xxx
        stg     %r2,SP_R2(%r15)         # store return value
@@ -443,14 +434,12 @@ kernel_execve:
        br      %r14
        # execve succeeded.
 0:     stnsm   __SF_EMPTY(%r15),0xfc   # disable interrupts
-#      TRACE_IRQS_OFF
        lg      %r15,__LC_KERNEL_STACK  # load ksp
        aghi    %r15,-SP_SIZE           # make room for registers & psw
        lg      %r13,__LC_SVC_NEW_PSW+8
        mvc     SP_PTREGS(__PT_SIZE,%r15),0(%r12)       # copy pt_regs
        lg      %r12,__LC_THREAD_INFO
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-#      TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        brasl   %r14,execve_tail
        j       sysc_return
@@ -490,19 +479,18 @@ pgm_check_handler:
        LAST_BREAK
 pgm_no_vtime:
        HANDLE_SIE_INTERCEPT
-       TRACE_IRQS_CHECK_OFF
        stg     %r11,SP_ARGS(%r15)
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
+       lg      %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        lghi    %r8,0x7f
        ngr     %r8,%r3
-pgm_do_call:
        sll     %r8,3
        larl    %r1,pgm_check_table
        lg      %r1,0(%r8,%r1)          # load address of handler routine
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r1                # branch to interrupt-handler
 pgm_exit:
-       TRACE_IRQS_CHECK_ON
        j       sysc_return
 
 #
@@ -533,7 +521,6 @@ pgm_per_std:
        LAST_BREAK
 pgm_no_vtime2:
        HANDLE_SIE_INTERCEPT
-       TRACE_IRQS_CHECK_OFF
        lg      %r1,__TI_task(%r12)
        tm      SP_PSW+1(%r15),0x01     # kernel per event ?
        jz      kernel_per
@@ -542,6 +529,8 @@ pgm_no_vtime2:
        mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
        oi      __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
+       lg      %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        lghi    %r8,0x7f
        ngr     %r8,%r3                 # clear per-event-bit and ilc
        je      pgm_exit2
@@ -551,8 +540,6 @@ pgm_no_vtime2:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r1                # branch to interrupt-handler
 pgm_exit2:
-       TRACE_IRQS_ON
-       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        j       sysc_return
 
 #
@@ -568,13 +555,11 @@ pgm_svcper:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        LAST_BREAK
-       TRACE_IRQS_OFF
        lg      %r8,__TI_task(%r12)
        mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
        mvc     __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
        mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        lmg     %r2,%r6,SP_R2(%r15)     # load svc arguments
        j       sysc_do_svc
@@ -743,8 +728,11 @@ ext_int_handler:
 ext_no_vtime:
        HANDLE_SIE_INTERCEPT
        TRACE_IRQS_OFF
+       lghi    %r1,4096
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
-       llgh    %r3,__LC_EXT_INT_CODE   # get interruption code
+       llgf    %r3,__LC_CPU_ADDRESS    # get cpu address + interruption code
+       llgf    %r4,__LC_EXT_PARAMS     # get external parameter
+       lg      %r5,__LC_EXT_PARAMS2-4096(%r1)  # get 64 bit external parameter
        brasl   %r14,do_extint
        j       io_return
 
@@ -966,7 +954,6 @@ cleanup_system_call:
        CREATE_STACK_FRAME __LC_SAVE_AREA
        mvc     SP_PSW(16,%r15),__LC_SVC_OLD_PSW
        mvc     SP_ILC(4,%r15),__LC_SVC_ILC
-       stg     %r7,SP_ARGS(%r15)
        mvc     8(8,%r12),__LC_THREAD_INFO
 cleanup_vtime:
        clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
index db1696e210af496d0cd9a807b53dfdd7bebcf5d9..7061398341d59ac21ffab3affb29216ca973460e 100644 (file)
@@ -488,7 +488,9 @@ startup:
        .align 16
 2:     .long   0x000a0000,0x8badcccc
 #if defined(CONFIG_64BIT)
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+       .long 0xc100efe3, 0xf46c0000
+#elif defined(CONFIG_MARCH_Z10)
        .long 0xc100efe3, 0xf0680000
 #elif defined(CONFIG_MARCH_Z9_109)
        .long 0xc100efc3, 0x00000000
@@ -498,7 +500,9 @@ startup:
        .long 0xc0000000, 0x00000000
 #endif
 #else
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+       .long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z10)
        .long 0x8100c880, 0x00000000
 #elif defined(CONFIG_MARCH_Z9_109)
        .long 0x8100c880, 0x00000000
index d3a2d1c6438ee08c1216353c8fefec7f2ee0dc31..ec2e03b22ead24c57210d09df9c514c9dcbe5816 100644 (file)
@@ -76,17 +76,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 static void default_idle(void)
 {
        /* CPU is going idle. */
-       local_irq_disable();
-       if (need_resched()) {
-               local_irq_enable();
-               return;
-       }
 #ifdef CONFIG_HOTPLUG_CPU
        if (cpu_is_offline(smp_processor_id())) {
                preempt_enable_no_resched();
                cpu_die();
        }
 #endif
+       local_irq_disable();
+       if (need_resched()) {
+               local_irq_enable();
+               return;
+       }
        local_mcck_disable();
        if (test_thread_flag(TIF_MCCK_PENDING)) {
                local_mcck_enable();
index ecb2d02b02e44257a3aa834c0de800520a04a306..644548e615c6c8c6d2384b66f367ce9b46b3d5c8 100644 (file)
@@ -42,7 +42,7 @@ void __cpuinit print_cpu_info(void)
        struct cpuid *id = &per_cpu(cpu_id, smp_processor_id());
 
        pr_info("Processor %d started, address %d, identification %06X\n",
-               S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident);
+               S390_lowcore.cpu_nr, stap(), id->ident);
 }
 
 /*
index 9ce641b5291f8f5c9188ac3e886103fe256ba647..bd1db508e8afa1768ff1333e379ae89ed88587ed 100644 (file)
@@ -113,12 +113,15 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
        return 0;
 }
 
-void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
+void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+                          unsigned int param32, unsigned long param64)
 {
+       struct pt_regs *old_regs;
+       unsigned short code;
         ext_int_info_t *p;
         int index;
-       struct pt_regs *old_regs;
 
+       code = (unsigned short) ext_int_code;
        old_regs = set_irq_regs(regs);
        s390_idle_check(regs, S390_lowcore.int_clock,
                        S390_lowcore.async_enter_timer);
@@ -132,7 +135,7 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
         index = ext_hash(code);
        for (p = ext_int_hash[index]; p; p = p->next) {
                if (likely(p->code == code))
-                       p->handler(code);
+                       p->handler(ext_int_code, param32, param64);
        }
        irq_exit();
        set_irq_regs(old_regs);
index c8e8e1354e1dd403d6bcbb56e5c0d6f8ac3a0b33..e3ceb911dc75806c9acee85dfbd980502acf5563 100644 (file)
@@ -409,6 +409,9 @@ setup_lowcore(void)
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
        lc->machine_flags = S390_lowcore.machine_flags;
+       lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
+       memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
+              MAX_FACILITY_BIT/8);
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
                lc->extended_save_area_addr = (__u32)
@@ -627,7 +630,8 @@ setup_memory(void)
                add_active_range(0, start_chunk, end_chunk);
                pfn = max(start_chunk, start_pfn);
                for (; pfn < end_chunk; pfn++)
-                       page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
+                       page_set_storage_key(PFN_PHYS(pfn),
+                                            PAGE_DEFAULT_KEY, 0);
        }
 
        psw_set_key(PAGE_DEFAULT_KEY);
@@ -674,12 +678,9 @@ setup_memory(void)
 static void __init setup_hwcaps(void)
 {
        static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
-       unsigned long long facility_list_extended;
-       unsigned int facility_list;
        struct cpuid cpu_id;
        int i;
 
-       facility_list = stfl();
        /*
         * The store facility list bits numbers as found in the principles
         * of operation are numbered with bit 1UL<<31 as number 0 to
@@ -699,11 +700,10 @@ static void __init setup_hwcaps(void)
         *   HWCAP_S390_ETF3EH bit 8 (22 && 30).
         */
        for (i = 0; i < 6; i++)
-               if (facility_list & (1UL << (31 - stfl_bits[i])))
+               if (test_facility(stfl_bits[i]))
                        elf_hwcap |= 1UL << i;
 
-       if ((facility_list & (1UL << (31 - 22)))
-           && (facility_list & (1UL << (31 - 30))))
+       if (test_facility(22) && test_facility(30))
                elf_hwcap |= HWCAP_S390_ETF3EH;
 
        /*
@@ -719,12 +719,8 @@ static void __init setup_hwcaps(void)
         * translated to:
         *   HWCAP_S390_DFP bit 6 (42 && 44).
         */
-       if ((elf_hwcap & (1UL << 2)) &&
-           __stfle(&facility_list_extended, 1) > 0) {
-               if ((facility_list_extended & (1ULL << (63 - 42)))
-                   && (facility_list_extended & (1ULL << (63 - 44))))
-                       elf_hwcap |= HWCAP_S390_DFP;
-       }
+       if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
+               elf_hwcap |= HWCAP_S390_DFP;
 
        /*
         * Huge page support HWCAP_S390_HPAGE is bit 7.
index 8127ebd59c4d81f4e8368e7728ad49bf3a173900..94cf510b8fe181850e36acdeaa8a9fa65b1397b7 100644 (file)
@@ -156,7 +156,8 @@ void smp_send_stop(void)
  * cpus are handled.
  */
 
-static void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(unsigned int ext_int_code,
+                                 unsigned int param32, unsigned long param64)
 {
        unsigned long bits;
 
@@ -593,6 +594,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
        cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
        cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
        cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
+       memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
+              MAX_FACILITY_BIT/8);
        eieio();
 
        while (sigp(cpu, sigp_restart) == sigp_busy)
index a0ffc7717ed62994609a66b22202982b1c867dba..f04d93aa48ec927f54f9f032ccedd5fa1f6e8d7a 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
 #include <asm/cpcmd.h>
+#include <asm/topology.h>
 
 /* Sigh, math-emu. Don't ask. */
 #include <asm/sfp-util.h>
@@ -74,6 +75,42 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
                               "Model Temp. Capacity: %-16.16s %08u\n",
                               info->model_temp_cap,
                               *(u32 *) info->model_temp_cap_rating);
+       if (info->cai) {
+               len += sprintf(page + len,
+                              "Capacity Adj. Ind.:   %d\n",
+                              info->cai);
+               len += sprintf(page + len, "Capacity Ch. Reason:  %d\n",
+                              info->ccr);
+       }
+       return len;
+}
+
+static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
+{
+       static int max_mnest;
+       int i, rc;
+
+       len += sprintf(page + len, "\n");
+       if (!MACHINE_HAS_TOPOLOGY)
+               return len;
+       if (max_mnest) {
+               stsi(info, 15, 1, max_mnest);
+       } else {
+               for (max_mnest = 6; max_mnest > 1; max_mnest--) {
+                       rc = stsi(info, 15, 1, max_mnest);
+                       if (rc != -ENOSYS)
+                               break;
+               }
+       }
+       len += sprintf(page + len, "CPU Topology HW:     ");
+       for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+               len += sprintf(page + len, " %d", info->mag[i]);
+       len += sprintf(page + len, "\n");
+       store_topology(info);
+       len += sprintf(page + len, "CPU Topology SW:     ");
+       for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+               len += sprintf(page + len, " %d", info->mag[i]);
+       len += sprintf(page + len, "\n");
        return len;
 }
 
@@ -87,7 +124,6 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
        ext = (struct sysinfo_1_2_2_extension *)
                ((unsigned long) info + info->acc_offset);
 
-       len += sprintf(page + len, "\n");
        len += sprintf(page + len, "CPUs Total:           %d\n",
                       info->cpus_total);
        len += sprintf(page + len, "CPUs Configured:      %d\n",
@@ -216,6 +252,9 @@ static int proc_read_sysinfo(char *page, char **start,
        if (level >= 1)
                len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
 
+       if (level >= 1)
+               len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len);
+
        if (level >= 1)
                len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
 
index 2896cac9c14a9cd5501067e36f254c308b27cee8..f754a6dc4f944104d09fdb8d21acdd12e4f28161 100644 (file)
@@ -155,7 +155,9 @@ void init_cpu_timer(void)
        __ctl_set_bit(0, 4);
 }
 
-static void clock_comparator_interrupt(__u16 code)
+static void clock_comparator_interrupt(unsigned int ext_int_code,
+                                      unsigned int param32,
+                                      unsigned long param64)
 {
        if (S390_lowcore.clock_comparator == -1ULL)
                set_clock_comparator(S390_lowcore.clock_comparator);
@@ -164,14 +166,13 @@ static void clock_comparator_interrupt(__u16 code)
 static void etr_timing_alert(struct etr_irq_parm *);
 static void stp_timing_alert(struct stp_irq_parm *);
 
-static void timing_alert_interrupt(__u16 code)
+static void timing_alert_interrupt(unsigned int ext_int_code,
+                                  unsigned int param32, unsigned long param64)
 {
-       if (S390_lowcore.ext_params & 0x00c40000)
-               etr_timing_alert((struct etr_irq_parm *)
-                                &S390_lowcore.ext_params);
-       if (S390_lowcore.ext_params & 0x00038000)
-               stp_timing_alert((struct stp_irq_parm *)
-                                &S390_lowcore.ext_params);
+       if (param32 & 0x00c40000)
+               etr_timing_alert((struct etr_irq_parm *) &param32);
+       if (param32 & 0x00038000)
+               stp_timing_alert((struct stp_irq_parm *) &param32);
 }
 
 static void etr_reset(void);
index 13559c9938470b9d7d0c2597f6418e518d865c78..a9dee9048ee58017bbd6cf03ac9377047dc09f8a 100644 (file)
 #include <linux/cpuset.h>
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
-#include <asm/sysinfo.h>
-
-#define CPU_BITS 64
-#define NR_MAG 6
 
 #define PTF_HORIZONTAL (0UL)
 #define PTF_VERTICAL   (1UL)
 #define PTF_CHECK      (2UL)
 
-struct tl_cpu {
-       unsigned char reserved0[4];
-       unsigned char :6;
-       unsigned char pp:2;
-       unsigned char reserved1;
-       unsigned short origin;
-       unsigned long mask[CPU_BITS / BITS_PER_LONG];
-};
-
-struct tl_container {
-       unsigned char reserved[7];
-       unsigned char id;
-};
-
-union tl_entry {
-       unsigned char nl;
-       struct tl_cpu cpu;
-       struct tl_container container;
-};
-
-struct tl_info {
-       unsigned char reserved0[2];
-       unsigned short length;
-       unsigned char mag[NR_MAG];
-       unsigned char reserved1;
-       unsigned char mnest;
-       unsigned char reserved2[4];
-       union tl_entry tle[0];
-};
-
 struct mask_info {
        struct mask_info *next;
        unsigned char id;
        cpumask_t mask;
 };
 
-static int topology_enabled;
+static int topology_enabled = 1;
 static void topology_work_fn(struct work_struct *work);
-static struct tl_info *tl_info;
-static int machine_has_topology;
+static struct sysinfo_15_1_x *tl_info;
 static struct timer_list topology_timer;
 static void set_topology_timer(void);
 static DECLARE_WORK(topology_work, topology_work_fn);
@@ -88,7 +53,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
        cpumask_t mask;
 
        cpus_clear(mask);
-       if (!topology_enabled || !machine_has_topology)
+       if (!topology_enabled || !MACHINE_HAS_TOPOLOGY)
                return cpu_possible_map;
        while (info) {
                if (cpu_isset(cpu, info->mask)) {
@@ -102,18 +67,18 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
        return mask;
 }
 
-static void add_cpus_to_mask(struct tl_cpu *tl_cpu, struct mask_info *book,
-                            struct mask_info *core)
+static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
+                            struct mask_info *book, struct mask_info *core)
 {
        unsigned int cpu;
 
-       for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS);
-            cpu < CPU_BITS;
-            cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1))
+       for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS);
+            cpu < TOPOLOGY_CPU_BITS;
+            cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1))
        {
                unsigned int rcpu, lcpu;
 
-               rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
+               rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
                for_each_present_cpu(lcpu) {
                        if (cpu_logical_map(lcpu) != rcpu)
                                continue;
@@ -146,15 +111,14 @@ static void clear_masks(void)
 #endif
 }
 
-static union tl_entry *next_tle(union tl_entry *tle)
+static union topology_entry *next_tle(union topology_entry *tle)
 {
-       if (tle->nl)
-               return (union tl_entry *)((struct tl_container *)tle + 1);
-       else
-               return (union tl_entry *)((struct tl_cpu *)tle + 1);
+       if (!tle->nl)
+               return (union topology_entry *)((struct topology_cpu *)tle + 1);
+       return (union topology_entry *)((struct topology_container *)tle + 1);
 }
 
-static void tl_to_cores(struct tl_info *info)
+static void tl_to_cores(struct sysinfo_15_1_x *info)
 {
 #ifdef CONFIG_SCHED_BOOK
        struct mask_info *book = &book_info;
@@ -162,13 +126,13 @@ static void tl_to_cores(struct tl_info *info)
        struct mask_info *book = NULL;
 #endif
        struct mask_info *core = &core_info;
-       union tl_entry *tle, *end;
+       union topology_entry *tle, *end;
 
 
        spin_lock_irq(&topology_lock);
        clear_masks();
        tle = info->tle;
-       end = (union tl_entry *)((unsigned long)info + info->length);
+       end = (union topology_entry *)((unsigned long)info + info->length);
        while (tle < end) {
                switch (tle->nl) {
 #ifdef CONFIG_SCHED_BOOK
@@ -186,7 +150,6 @@ static void tl_to_cores(struct tl_info *info)
                        break;
                default:
                        clear_masks();
-                       machine_has_topology = 0;
                        goto out;
                }
                tle = next_tle(tle);
@@ -223,7 +186,7 @@ int topology_set_cpu_management(int fc)
        int cpu;
        int rc;
 
-       if (!machine_has_topology)
+       if (!MACHINE_HAS_TOPOLOGY)
                return -EOPNOTSUPP;
        if (fc)
                rc = ptf(PTF_VERTICAL);
@@ -251,7 +214,7 @@ static void update_cpu_core_map(void)
        spin_unlock_irqrestore(&topology_lock, flags);
 }
 
-static void store_topology(struct tl_info *info)
+void store_topology(struct sysinfo_15_1_x *info)
 {
 #ifdef CONFIG_SCHED_BOOK
        int rc;
@@ -265,11 +228,11 @@ static void store_topology(struct tl_info *info)
 
 int arch_update_cpu_topology(void)
 {
-       struct tl_info *info = tl_info;
+       struct sysinfo_15_1_x *info = tl_info;
        struct sys_device *sysdev;
        int cpu;
 
-       if (!machine_has_topology) {
+       if (!MACHINE_HAS_TOPOLOGY) {
                update_cpu_core_map();
                topology_update_polarization_simple();
                return 0;
@@ -311,9 +274,9 @@ static void set_topology_timer(void)
 
 static int __init early_parse_topology(char *p)
 {
-       if (strncmp(p, "on", 2))
+       if (strncmp(p, "off", 3))
                return 0;
-       topology_enabled = 1;
+       topology_enabled = 0;
        return 0;
 }
 early_param("topology", early_parse_topology);
@@ -323,7 +286,7 @@ static int __init init_topology_update(void)
        int rc;
 
        rc = 0;
-       if (!machine_has_topology) {
+       if (!MACHINE_HAS_TOPOLOGY) {
                topology_update_polarization_simple();
                goto out;
        }
@@ -335,13 +298,14 @@ out:
 }
 __initcall(init_topology_update);
 
-static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset)
+static void alloc_masks(struct sysinfo_15_1_x *info, struct mask_info *mask,
+                       int offset)
 {
        int i, nr_masks;
 
-       nr_masks = info->mag[NR_MAG - offset];
+       nr_masks = info->mag[TOPOLOGY_NR_MAG - offset];
        for (i = 0; i < info->mnest - offset; i++)
-               nr_masks *= info->mag[NR_MAG - offset - 1 - i];
+               nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
        nr_masks = max(nr_masks, 1);
        for (i = 0; i < nr_masks; i++) {
                mask->next = alloc_bootmem(sizeof(struct mask_info));
@@ -351,21 +315,16 @@ static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset
 
 void __init s390_init_cpu_topology(void)
 {
-       unsigned long long facility_bits;
-       struct tl_info *info;
+       struct sysinfo_15_1_x *info;
        int i;
 
-       if (stfle(&facility_bits, 1) <= 0)
-               return;
-       if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
+       if (!MACHINE_HAS_TOPOLOGY)
                return;
-       machine_has_topology = 1;
-
        tl_info = alloc_bootmem_pages(PAGE_SIZE);
        info = tl_info;
        store_topology(info);
        pr_info("The CPU configuration topology of the machine is:");
-       for (i = 0; i < NR_MAG; i++)
+       for (i = 0; i < TOPOLOGY_NR_MAG; i++)
                printk(" %d", info->mag[i]);
        printk(" / %d\n", info->mnest);
        alloc_masks(info, &core_info, 2);
index 5d8f0f3d025008a11614500fc1908e8cf7de1658..70640822621a364b042af25babe7285c2a0f11f3 100644 (file)
@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
        return 1;
 }
 
-static void __kprobes inline do_trap(long interruption_code, int signr,
-                                       char *str, struct pt_regs *regs,
-                                       siginfo_t *info)
+static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
+                                    struct pt_regs *regs, siginfo_t *info)
 {
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
-
-       if (notify_die(DIE_TRAP, str, regs, interruption_code,
-                               interruption_code, signr) == NOTIFY_STOP)
+       if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
+                      pgm_int_code, signr) == NOTIFY_STOP)
                return;
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code & 0xffff;
+               tsk->thread.trap_no = pgm_int_code & 0xffff;
                force_sig_info(signr, info, tsk);
-               report_user_fault(regs, interruption_code, signr);
+               report_user_fault(regs, pgm_int_code, signr);
         } else {
                 const struct exception_table_entry *fixup;
                 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
                        btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
                        if (btt == BUG_TRAP_TYPE_WARN)
                                return;
-                       die(str, regs, interruption_code);
+                       die(str, regs, pgm_int_code);
                }
         }
 }
 
-static inline void __user *get_check_address(struct pt_regs *regs)
+static inline void __user *get_psw_address(struct pt_regs *regs,
+                                          long pgm_int_code)
 {
-       return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+       return (void __user *)
+               ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
 }
 
 void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
                force_sig(SIGTRAP, current);
 }
 
-static void default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
+                                unsigned long trans_exc_code)
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
-               local_irq_enable();
-               report_user_fault(regs, interruption_code, SIGSEGV);
+               report_user_fault(regs, pgm_int_code, SIGSEGV);
                do_exit(SIGSEGV);
        } else
-               die("Unknown program exception", regs, interruption_code);
+               die("Unknown program exception", regs, pgm_int_code);
 }
 
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-static void name(struct pt_regs * regs, long interruption_code) \
+#define DO_ERROR_INFO(name, signr, sicode, str) \
+static void name(struct pt_regs *regs, long pgm_int_code, \
+                unsigned long trans_exc_code) \
 { \
         siginfo_t info; \
         info.si_signo = signr; \
         info.si_errno = 0; \
         info.si_code = sicode; \
-       info.si_addr = siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
+       info.si_addr = get_psw_address(regs, pgm_int_code); \
+       do_trap(pgm_int_code, signr, str, regs, &info);     \
 }
 
-DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
-             ILL_ILLADR, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
-             ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
-             FPE_INTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "fixpoint overflow exception", overflow_exception,
-             FPE_INTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP overflow exception", hfp_overflow_exception,
-             FPE_FLTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP underflow exception", hfp_underflow_exception,
-             FPE_FLTUND, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP significance exception", hfp_significance_exception,
-             FPE_FLTRES, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP divide exception", hfp_divide_exception,
-             FPE_FLTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP square root exception", hfp_sqrt_exception,
-             FPE_FLTINV, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
-             ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
-             ILL_PRVOPC, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
-             ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
-             ILL_ILLOPN, get_check_address(regs))
-
-static inline void
-do_fp_trap(struct pt_regs *regs, void __user *location,
-           int fpc, long interruption_code)
+DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
+             "addressing exception")
+DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
+             "execute exception")
+DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
+             "fixpoint divide exception")
+DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
+             "fixpoint overflow exception")
+DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
+             "HFP overflow exception")
+DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
+             "HFP underflow exception")
+DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
+             "HFP significance exception")
+DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
+             "HFP divide exception")
+DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
+             "HFP square root exception")
+DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
+             "operand exception")
+DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
+             "privileged operation")
+DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
+             "special operation exception")
+DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
+             "translation exception")
+
+static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
+                             int fpc, long pgm_int_code)
 {
        siginfo_t si;
 
@@ -453,26 +447,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
                else if (fpc & 0x0800) /* inexact */
                        si.si_code = FPE_FLTRES;
        }
-       current->thread.ieee_instruction_pointer = (addr_t) location;
-       do_trap(interruption_code, SIGFPE,
+       do_trap(pgm_int_code, SIGFPE,
                "floating point exception", regs, &si);
 }
 
-static void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs *regs, long pgm_int_code,
+                      unsigned long trans_exc_code)
 {
        siginfo_t info;
         __u8 opcode[6];
        __u16 __user *location;
        int signal = 0;
 
-       location = get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-       if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = get_psw_address(regs, pgm_int_code);
 
        if (regs->psw.mask & PSW_MASK_PSTATE) {
                if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +499,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
                 * If we get an illegal op in kernel mode, send it through the
                 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
                 */
-               if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+               if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
                               3, SIGTRAP) != NOTIFY_STOP)
                        signal = SIGILL;
        }
@@ -520,13 +507,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal == SIGSEGV) {
                info.si_signo = signal;
                info.si_errno = 0;
                info.si_code = SEGV_MAPERR;
                info.si_addr = (void __user *) location;
-               do_trap(interruption_code, signal,
+               do_trap(pgm_int_code, signal,
                        "user address fault", regs, &info);
        } else
 #endif
@@ -535,28 +522,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
                info.si_errno = 0;
                info.si_code = ILL_ILLOPC;
                info.si_addr = (void __user *) location;
-               do_trap(interruption_code, signal,
+               do_trap(pgm_int_code, signal,
                        "illegal operation", regs, &info);
        }
 }
 
 
 #ifdef CONFIG_MATHEMU
-asmlinkage void 
-specification_exception(struct pt_regs * regs, long interruption_code)
+asmlinkage void specification_exception(struct pt_regs *regs,
+                                       long pgm_int_code,
+                                       unsigned long trans_exc_code)
 {
         __u8 opcode[6];
        __u16 __user *location = NULL;
        int signal = 0;
 
-       location = (__u16 __user *) get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                get_user(*((__u16 *) opcode), location);
@@ -592,35 +573,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
 
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal) {
                siginfo_t info;
                info.si_signo = signal;
                info.si_errno = 0;
                info.si_code = ILL_ILLOPN;
                info.si_addr = location;
-               do_trap(interruption_code, signal, 
+               do_trap(pgm_int_code, signal,
                        "specification exception", regs, &info);
        }
 }
 #else
-DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
-             ILL_ILLOPN, get_check_address(regs));
+DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
+             "specification exception");
 #endif
 
-static void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs *regs, long pgm_int_code,
+                          unsigned long trans_exc_code)
 {
        __u16 __user *location;
        int signal = 0;
 
-       location = get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-       if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = get_psw_address(regs, pgm_int_code);
 
        if (MACHINE_HAS_IEEE)
                asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +661,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
                signal = SIGILL;
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal) {
                siginfo_t info;
                info.si_signo = signal;
                info.si_errno = 0;
                info.si_code = ILL_ILLOPN;
                info.si_addr = location;
-               do_trap(interruption_code, signal, 
-                       "data exception", regs, &info);
+               do_trap(pgm_int_code, signal, "data exception", regs, &info);
        }
 }
 
-static void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
+                                  unsigned long trans_exc_code)
 {
         siginfo_t info;
 
@@ -709,8 +684,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
         info.si_signo = SIGILL;
         info.si_errno = 0;
         info.si_code = ILL_PRVOPC;
-        info.si_addr = get_check_address(regs);
-        do_trap(int_code, SIGILL, "space switch event", regs, &info);
+       info.si_addr = get_psw_address(regs, pgm_int_code);
+       do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
 }
 
 asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
index 6b83870507d5b0f518e68024433db240e41b8fe3..e3150dd2fe7457604a9e041a9a274dee6861addd 100644 (file)
@@ -84,11 +84,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
  */
 static void vdso_init_data(struct vdso_data *vd)
 {
-       unsigned int facility_list;
-
-       facility_list = stfl();
-       vd->ectg_available =
-               user_mode != HOME_SPACE_MODE && (facility_list & 1);
+       vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
 }
 
 #ifdef CONFIG_64BIT
index 3479f1b0d4e0d86f90ca5bb974bf09814dc1c987..56c8687b29b3a48b9487921d2b0fdaea5767ec5b 100644 (file)
@@ -314,7 +314,8 @@ static void do_callbacks(struct list_head *cb_list)
 /*
  * Handler for the virtual CPU timer.
  */
-static void do_cpu_timer_interrupt(__u16 error_code)
+static void do_cpu_timer_interrupt(unsigned int ext_int_code,
+                                  unsigned int param32, unsigned long param64)
 {
        struct vtimer_queue *vq;
        struct vtimer_list *event, *tmp;
index 4fe68650535cf2acc4d3e968b839a1e750a00529..985d825494f10cd5f7827c5ba8438b763b55aa67 100644 (file)
@@ -740,8 +740,8 @@ static int __init kvm_s390_init(void)
                kvm_exit();
                return -ENOMEM;
        }
-       stfle(facilities, 1);
-       facilities[0] &= 0xff00fff3f0700000ULL;
+       memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
+       facilities[0] &= 0xff00fff3f47c0000ULL;
        return 0;
 }
 
index 44205507717cc673e1906d557f8d8bbe4e77f863..9194a4b52b22a84d3ada8dce7f46ab7f411e5576 100644 (file)
@@ -154,12 +154,12 @@ static int handle_chsc(struct kvm_vcpu *vcpu)
 
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
-       unsigned int facility_list = stfl();
+       unsigned int facility_list;
        int rc;
 
        vcpu->stat.instruction_stfl++;
        /* only pass the facility bits, which we can handle */
-       facility_list &= 0xff00fff3;
+       facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
 
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                           &facility_list, sizeof(facility_list));
index eec05448441922adf4c081b719f7cd5672e402d6..6fbc6f3fbdf276f90b21cf9b15e200086171b737 100644 (file)
@@ -3,6 +3,6 @@
 #
 
 obj-y   := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
-           page-states.o
+           page-states.o gup.o
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
index a9550dca3e4b2fed74fc7472dbfd3da95d4526fc..c66ffd8dbbb732416ad3d803d00ec02da6125555 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm/diag.h>
 
-static char *sender = "VMRMSVM";
+#ifdef CONFIG_CMM_IUCV
+static char *cmm_default_sender = "VMRMSVM";
+#endif
+static char *sender;
 module_param(sender, charp, 0400);
 MODULE_PARM_DESC(sender,
                 "Guest name that may send SMSG messages (default VMRMSVM)");
@@ -440,6 +443,8 @@ static int __init cmm_init(void)
                int len = strlen(sender);
                while (len--)
                        sender[len] = toupper(sender[len]);
+       } else {
+               sender = cmm_default_sender;
        }
 
        rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
index 2505b2ea0ef187803033c096bab3cff8eac45f02..fe5701e9efbfb95392328a389b1baae49e897844 100644 (file)
 #define VM_FAULT_BADMAP                0x020000
 #define VM_FAULT_BADACCESS     0x040000
 
+static unsigned long store_indication;
+
+void fault_init(void)
+{
+       if (test_facility(2) && test_facility(75))
+               store_indication = 0xc00;
+}
+
 static inline int notify_page_fault(struct pt_regs *regs)
 {
        int ret = 0;
@@ -199,14 +207,21 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
                               unsigned long trans_exc_code)
 {
        struct task_struct *tsk = current;
+       unsigned long address;
+       struct siginfo si;
 
        /*
         * Send a sigbus, regardless of whether we were in kernel
         * or user mode.
         */
-       tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+       address = trans_exc_code & __FAIL_ADDR_MASK;
+       tsk->thread.prot_addr = address;
        tsk->thread.trap_no = int_code;
-       force_sig(SIGBUS, tsk);
+       si.si_signo = SIGBUS;
+       si.si_errno = 0;
+       si.si_code = BUS_ADRERR;
+       si.si_addr = (void __user *) address;
+       force_sig_info(SIGBUS, &si, tsk);
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
@@ -266,10 +281,11 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                if (fault & VM_FAULT_OOM)
                        pagefault_out_of_memory();
                else if (fault & VM_FAULT_SIGBUS) {
-                       do_sigbus(regs, int_code, trans_exc_code);
                        /* Kernel mode? Handle exceptions or die */
                        if (!(regs->psw.mask & PSW_MASK_PSTATE))
                                do_no_context(regs, int_code, trans_exc_code);
+                       else
+                               do_sigbus(regs, int_code, trans_exc_code);
                } else
                        BUG();
                break;
@@ -294,7 +310,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
        struct mm_struct *mm;
        struct vm_area_struct *vma;
        unsigned long address;
-       int fault;
+       int fault, write;
 
        if (notify_page_fault(regs))
                return 0;
@@ -312,12 +328,6 @@ static inline int do_exception(struct pt_regs *regs, int access,
                goto out;
 
        address = trans_exc_code & __FAIL_ADDR_MASK;
-       /*
-        * When we get here, the fault happened in the current
-        * task's user address space, so we can switch on the
-        * interrupts again and then search the VMAs
-        */
-       local_irq_enable();
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
        down_read(&mm->mmap_sem);
 
@@ -348,8 +358,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       fault = handle_mm_fault(mm, vma, address,
-                               (access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+       write = (access == VM_WRITE ||
+                (trans_exc_code & store_indication) == 0x400) ?
+               FAULT_FLAG_WRITE : 0;
+       fault = handle_mm_fault(mm, vma, address, write);
        if (unlikely(fault & VM_FAULT_ERROR))
                goto out_up;
 
@@ -374,20 +386,20 @@ out:
        return fault;
 }
 
-void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
+                                      unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        int fault;
 
        /* Protection exception is supressing, decrement psw address. */
-       regs->psw.addr -= (int_code >> 16);
+       regs->psw.addr -= (pgm_int_code >> 16);
        /*
         * Check for low-address protection.  This needs to be treated
         * as a special case because the translation exception code
         * field is not guaranteed to contain valid data in this case.
         */
        if (unlikely(!(trans_exc_code & 4))) {
-               do_low_address(regs, int_code, trans_exc_code);
+               do_low_address(regs, pgm_int_code, trans_exc_code);
                return;
        }
        fault = do_exception(regs, VM_WRITE, trans_exc_code);
@@ -395,9 +407,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
                do_fault_error(regs, 4, trans_exc_code, fault);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
+                               unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        int access, fault;
 
        access = VM_READ | VM_EXEC | VM_WRITE;
@@ -408,21 +420,19 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
 #endif
        fault = do_exception(regs, access, trans_exc_code);
        if (unlikely(fault))
-               do_fault_error(regs, int_code & 255, trans_exc_code, fault);
+               do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
 }
 
 #ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
+                                unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
 
        if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
                goto no_context;
 
-       local_irq_enable();
-
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
        up_read(&mm->mmap_sem);
@@ -434,16 +444,16 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
 
        /* User mode accesses just cause a SIGSEGV */
        if (regs->psw.mask & PSW_MASK_PSTATE) {
-               do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
+               do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
                return;
        }
 
 no_context:
-       do_no_context(regs, int_code, trans_exc_code);
+       do_no_context(regs, pgm_int_code, trans_exc_code);
 }
 #endif
 
-int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
 {
        struct pt_regs regs;
        int access, fault;
@@ -454,14 +464,14 @@ int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
        regs.psw.addr = (unsigned long) __builtin_return_address(0);
        regs.psw.addr |= PSW_ADDR_AMODE;
        uaddr &= PAGE_MASK;
-       access = write_user ? VM_WRITE : VM_READ;
+       access = write ? VM_WRITE : VM_READ;
        fault = do_exception(&regs, access, uaddr | 2);
        if (unlikely(fault)) {
                if (fault & VM_FAULT_OOM) {
                        pagefault_out_of_memory();
                        fault = 0;
                } else if (fault & VM_FAULT_SIGBUS)
-                       do_sigbus(&regs, int_code, uaddr);
+                       do_sigbus(&regs, pgm_int_code, uaddr);
        }
        return fault ? -EFAULT : 0;
 }
@@ -527,7 +537,8 @@ void pfault_fini(void)
                : : "a" (&refbk), "m" (refbk) : "cc");
 }
 
-static void pfault_interrupt(__u16 int_code)
+static void pfault_interrupt(unsigned int ext_int_code,
+                            unsigned int param32, unsigned long param64)
 {
        struct task_struct *tsk;
        __u16 subcode;
@@ -538,14 +549,18 @@ static void pfault_interrupt(__u16 int_code)
         * in the 'cpu address' field associated with the
          * external interrupt. 
         */
-       subcode = S390_lowcore.cpu_addr;
+       subcode = ext_int_code >> 16;
        if ((subcode & 0xff00) != __SUBCODE_MASK)
                return;
 
        /*
         * Get the token (= address of the task structure of the affected task).
         */
-       tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
+#ifdef CONFIG_64BIT
+       tsk = *(struct task_struct **) param64;
+#else
+       tsk = *(struct task_struct **) param32;
+#endif
 
        if (subcode & 0x0080) {
                /* signal bit is set -> a page has been swapped in by VM */
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
new file mode 100644 (file)
index 0000000..38e641c
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *  Lockless get_user_pages_fast for s390
+ *
+ *  Copyright IBM Corp. 2010
+ *  Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/vmstat.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <asm/pgtable.h>
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+               unsigned long end, int write, struct page **pages, int *nr)
+{
+       unsigned long mask, result;
+       pte_t *ptep, pte;
+       struct page *page;
+
+       result = write ? 0 : _PAGE_RO;
+       mask = result | _PAGE_INVALID | _PAGE_SPECIAL;
+
+       ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
+       do {
+               pte = *ptep;
+               barrier();
+               if ((pte_val(pte) & mask) != result)
+                       return 0;
+               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+               page = pte_page(pte);
+               if (!page_cache_get_speculative(page))
+                       return 0;
+               if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+                       put_page(page);
+                       return 0;
+               }
+               pages[*nr] = page;
+               (*nr)++;
+
+       } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+       return 1;
+}
+
+static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+               unsigned long end, int write, struct page **pages, int *nr)
+{
+       unsigned long mask, result;
+       struct page *head, *page;
+       int refs;
+
+       result = write ? 0 : _SEGMENT_ENTRY_RO;
+       mask = result | _SEGMENT_ENTRY_INV;
+       if ((pmd_val(pmd) & mask) != result)
+               return 0;
+       VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
+
+       refs = 0;
+       head = pmd_page(pmd);
+       page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       if (!page_cache_add_speculative(head, refs)) {
+               *nr -= refs;
+               return 0;
+       }
+
+       if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
+               *nr -= refs;
+               while (refs--)
+                       put_page(head);
+       }
+
+       return 1;
+}
+
+
+static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
+               unsigned long end, int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pmd_t *pmdp, pmd;
+
+       pmdp = (pmd_t *) pudp;
+#ifdef CONFIG_64BIT
+       if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+               pmdp = (pmd_t *) pud_deref(pud);
+       pmdp += pmd_index(addr);
+#endif
+       do {
+               pmd = *pmdp;
+               barrier();
+               next = pmd_addr_end(addr, end);
+               if (pmd_none(pmd))
+                       return 0;
+               if (unlikely(pmd_huge(pmd))) {
+                       if (!gup_huge_pmd(pmdp, pmd, addr, next,
+                                         write, pages, nr))
+                               return 0;
+               } else if (!gup_pte_range(pmdp, pmd, addr, next,
+                                         write, pages, nr))
+                       return 0;
+       } while (pmdp++, addr = next, addr != end);
+
+       return 1;
+}
+
+static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr,
+               unsigned long end, int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pud_t *pudp, pud;
+
+       pudp = (pud_t *) pgdp;
+#ifdef CONFIG_64BIT
+       if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
+               pudp = (pud_t *) pgd_deref(pgd);
+       pudp += pud_index(addr);
+#endif
+       do {
+               pud = *pudp;
+               barrier();
+               next = pud_addr_end(addr, end);
+               if (pud_none(pud))
+                       return 0;
+               if (!gup_pmd_range(pudp, pud, addr, next, write, pages, nr))
+                       return 0;
+       } while (pudp++, addr = next, addr != end);
+
+       return 1;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:     starting user address
+ * @nr_pages:  number of pages from start to pin
+ * @write:     whether pages will be written to
+ * @pages:     array that receives pointers to the pages pinned.
+ *             Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                       struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       pgd_t *pgdp, pgd;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       if (end < start)
+               goto slow_irqon;
+
+       /*
+        * local_irq_disable() doesn't prevent pagetable teardown, but does
+        * prevent the pagetables from being freed on s390.
+        *
+        * So long as we atomically load page table pointers versus teardown,
+        * we can follow the address down to the the page and take a ref on it.
+        */
+       local_irq_disable();
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd = *pgdp;
+               barrier();
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       goto slow;
+               if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr))
+                       goto slow;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_enable();
+
+       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+       return nr;
+
+       {
+               int ret;
+slow:
+               local_irq_enable();
+slow_irqon:
+               /* Try to get the remaining pages with get_user_pages */
+               start += nr << PAGE_SHIFT;
+               pages += nr;
+
+               down_read(&mm->mmap_sem);
+               ret = get_user_pages(current, mm, start,
+                       (end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+               up_read(&mm->mmap_sem);
+
+               /* Have to be a bit careful with return values */
+               if (nr > 0) {
+                       if (ret < 0)
+                               ret = nr;
+                       else
+                               ret += nr;
+               }
+
+               return ret;
+       }
+}
index f28c43d2f61dd6b679b8cc8afb14c12e57e33273..639cd21f2218d6431030472a03509acb2ba8a41b 100644 (file)
@@ -68,7 +68,7 @@ void arch_release_hugepage(struct page *page)
        ptep = (pte_t *) page[1].index;
        if (!ptep)
                return;
-       pte_free(&init_mm, ptep);
+       page_table_free(&init_mm, (unsigned long *) ptep);
        page[1].index = 0;
 }
 
index 94b8ba2ec8575d814613bab79fa191ba5a2564ca..bb409332a484add0f68a1c20734d81968273f0e6 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 
-char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned long empty_zero_page, zero_page_mask;
 EXPORT_SYMBOL(empty_zero_page);
 
+static unsigned long setup_zero_pages(void)
+{
+       struct cpuid cpu_id;
+       unsigned int order;
+       unsigned long size;
+       struct page *page;
+       int i;
+
+       get_cpu_id(&cpu_id);
+       switch (cpu_id.machine) {
+       case 0x9672:    /* g5 */
+       case 0x2064:    /* z900 */
+       case 0x2066:    /* z900 */
+       case 0x2084:    /* z990 */
+       case 0x2086:    /* z990 */
+       case 0x2094:    /* z9-109 */
+       case 0x2096:    /* z9-109 */
+               order = 0;
+               break;
+       case 0x2097:    /* z10 */
+       case 0x2098:    /* z10 */
+       default:
+               order = 2;
+               break;
+       }
+
+       empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+       if (!empty_zero_page)
+               panic("Out of memory in setup_zero_pages");
+
+       page = virt_to_page((void *) empty_zero_page);
+       split_page(page, order);
+       for (i = 1 << order; i > 0; i--) {
+               SetPageReserved(page);
+               page++;
+       }
+
+       size = PAGE_SIZE << order;
+       zero_page_mask = (size - 1) & PAGE_MASK;
+
+       return 1UL << order;
+}
+
 /*
  * paging_init() sets up the page tables
  */
@@ -83,6 +124,7 @@ void __init paging_init(void)
 #endif
        max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
        free_area_init_nodes(max_zone_pfns);
+       fault_init();
 }
 
 void __init mem_init(void)
@@ -92,14 +134,12 @@ void __init mem_init(void)
         max_mapnr = num_physpages = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
-        /* clear the zero-page */
-        memset(empty_zero_page, 0, PAGE_SIZE);
-
        /* Setup guest page hinting */
        cmma_init();
 
        /* this will put all low memory onto the freelists */
        totalram_pages += free_all_bootmem();
+       totalram_pages -= setup_zero_pages();   /* Setup zeroed pages. */
 
        reservedpages = 0;
 
index 8d999249d3574fb880da55af3fb5ff40d7f32fe8..0c719c61972e5d95d52e4151b298659b57239845 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/quicklist.h>
+#include <linux/rcupdate.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 
+struct rcu_table_freelist {
+       struct rcu_head rcu;
+       struct mm_struct *mm;
+       unsigned int pgt_index;
+       unsigned int crst_index;
+       unsigned long *table[0];
+};
+
+#define RCU_FREELIST_SIZE \
+       ((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
+         / sizeof(unsigned long))
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
+
+static void __page_table_free(struct mm_struct *mm, unsigned long *table);
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
+
+static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
+{
+       struct rcu_table_freelist **batchp = &__get_cpu_var(rcu_table_freelist);
+       struct rcu_table_freelist *batch = *batchp;
+
+       if (batch)
+               return batch;
+       batch = (struct rcu_table_freelist *) __get_free_page(GFP_ATOMIC);
+       if (batch) {
+               batch->mm = mm;
+               batch->pgt_index = 0;
+               batch->crst_index = RCU_FREELIST_SIZE;
+               *batchp = batch;
+       }
+       return batch;
+}
+
+static void rcu_table_freelist_callback(struct rcu_head *head)
+{
+       struct rcu_table_freelist *batch =
+               container_of(head, struct rcu_table_freelist, rcu);
+
+       while (batch->pgt_index > 0)
+               __page_table_free(batch->mm, batch->table[--batch->pgt_index]);
+       while (batch->crst_index < RCU_FREELIST_SIZE)
+               __crst_table_free(batch->mm, batch->table[batch->crst_index++]);
+       free_page((unsigned long) batch);
+}
+
+void rcu_table_freelist_finish(void)
+{
+       struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist);
+
+       if (!batch)
+               return;
+       call_rcu(&batch->rcu, rcu_table_freelist_callback);
+       __get_cpu_var(rcu_table_freelist) = NULL;
+}
+
+static void smp_sync(void *arg)
+{
+}
+
 #ifndef CONFIG_64BIT
 #define ALLOC_ORDER    1
 #define TABLES_PER_PAGE        4
@@ -78,25 +140,55 @@ unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
                }
                page->index = page_to_phys(shadow);
        }
-       spin_lock(&mm->context.list_lock);
+       spin_lock_bh(&mm->context.list_lock);
        list_add(&page->lru, &mm->context.crst_list);
-       spin_unlock(&mm->context.list_lock);
+       spin_unlock_bh(&mm->context.list_lock);
        return (unsigned long *) page_to_phys(page);
 }
 
-void crst_table_free(struct mm_struct *mm, unsigned long *table)
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
 {
        unsigned long *shadow = get_shadow_table(table);
-       struct page *page = virt_to_page(table);
 
-       spin_lock(&mm->context.list_lock);
-       list_del(&page->lru);
-       spin_unlock(&mm->context.list_lock);
        if (shadow)
                free_pages((unsigned long) shadow, ALLOC_ORDER);
        free_pages((unsigned long) table, ALLOC_ORDER);
 }
 
+void crst_table_free(struct mm_struct *mm, unsigned long *table)
+{
+       struct page *page = virt_to_page(table);
+
+       spin_lock_bh(&mm->context.list_lock);
+       list_del(&page->lru);
+       spin_unlock_bh(&mm->context.list_lock);
+       __crst_table_free(mm, table);
+}
+
+void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+       struct rcu_table_freelist *batch;
+       struct page *page = virt_to_page(table);
+
+       spin_lock_bh(&mm->context.list_lock);
+       list_del(&page->lru);
+       spin_unlock_bh(&mm->context.list_lock);
+       if (atomic_read(&mm->mm_users) < 2 &&
+           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+               __crst_table_free(mm, table);
+               return;
+       }
+       batch = rcu_table_freelist_get(mm);
+       if (!batch) {
+               smp_call_function(smp_sync, NULL, 1);
+               __crst_table_free(mm, table);
+               return;
+       }
+       batch->table[--batch->crst_index] = table;
+       if (batch->pgt_index >= batch->crst_index)
+               rcu_table_freelist_finish();
+}
+
 #ifdef CONFIG_64BIT
 int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
 {
@@ -108,7 +200,7 @@ repeat:
        table = crst_table_alloc(mm, mm->context.noexec);
        if (!table)
                return -ENOMEM;
-       spin_lock(&mm->page_table_lock);
+       spin_lock_bh(&mm->page_table_lock);
        if (mm->context.asce_limit < limit) {
                pgd = (unsigned long *) mm->pgd;
                if (mm->context.asce_limit <= (1UL << 31)) {
@@ -130,7 +222,7 @@ repeat:
                mm->task_size = mm->context.asce_limit;
                table = NULL;
        }
-       spin_unlock(&mm->page_table_lock);
+       spin_unlock_bh(&mm->page_table_lock);
        if (table)
                crst_table_free(mm, table);
        if (mm->context.asce_limit < limit)
@@ -182,7 +274,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        unsigned long bits;
 
        bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
-       spin_lock(&mm->context.list_lock);
+       spin_lock_bh(&mm->context.list_lock);
        page = NULL;
        if (!list_empty(&mm->context.pgtable_list)) {
                page = list_first_entry(&mm->context.pgtable_list,
@@ -191,7 +283,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
                        page = NULL;
        }
        if (!page) {
-               spin_unlock(&mm->context.list_lock);
+               spin_unlock_bh(&mm->context.list_lock);
                page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
                if (!page)
                        return NULL;
@@ -202,7 +294,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
                        clear_table_pgstes(table);
                else
                        clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
-               spin_lock(&mm->context.list_lock);
+               spin_lock_bh(&mm->context.list_lock);
                list_add(&page->lru, &mm->context.pgtable_list);
        }
        table = (unsigned long *) page_to_phys(page);
@@ -213,10 +305,25 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        page->flags |= bits;
        if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
                list_move_tail(&page->lru, &mm->context.pgtable_list);
-       spin_unlock(&mm->context.list_lock);
+       spin_unlock_bh(&mm->context.list_lock);
        return table;
 }
 
+static void __page_table_free(struct mm_struct *mm, unsigned long *table)
+{
+       struct page *page;
+       unsigned long bits;
+
+       bits = ((unsigned long) table) & 15;
+       table = (unsigned long *)(((unsigned long) table) ^ bits);
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       page->flags ^= bits;
+       if (!(page->flags & FRAG_MASK)) {
+               pgtable_page_dtor(page);
+               __free_page(page);
+       }
+}
+
 void page_table_free(struct mm_struct *mm, unsigned long *table)
 {
        struct page *page;
@@ -225,7 +332,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
        bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-       spin_lock(&mm->context.list_lock);
+       spin_lock_bh(&mm->context.list_lock);
        page->flags ^= bits;
        if (page->flags & FRAG_MASK) {
                /* Page now has some free pgtable fragments. */
@@ -234,18 +341,48 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        } else
                /* All fragments of the 4K page have been freed. */
                list_del(&page->lru);
-       spin_unlock(&mm->context.list_lock);
+       spin_unlock_bh(&mm->context.list_lock);
        if (page) {
                pgtable_page_dtor(page);
                __free_page(page);
        }
 }
 
+void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+       struct rcu_table_freelist *batch;
+       struct page *page;
+       unsigned long bits;
+
+       if (atomic_read(&mm->mm_users) < 2 &&
+           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+               page_table_free(mm, table);
+               return;
+       }
+       batch = rcu_table_freelist_get(mm);
+       if (!batch) {
+               smp_call_function(smp_sync, NULL, 1);
+               page_table_free(mm, table);
+               return;
+       }
+       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+       bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       spin_lock_bh(&mm->context.list_lock);
+       /* Delayed freeing with rcu prevents reuse of pgtable fragments */
+       list_del_init(&page->lru);
+       spin_unlock_bh(&mm->context.list_lock);
+       table = (unsigned long *)(((unsigned long) table) | bits);
+       batch->table[batch->pgt_index++] = table;
+       if (batch->pgt_index >= batch->crst_index)
+               rcu_table_freelist_finish();
+}
+
 void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
 {
        struct page *page;
 
-       spin_lock(&mm->context.list_lock);
+       spin_lock_bh(&mm->context.list_lock);
        /* Free shadow region and segment tables. */
        list_for_each_entry(page, &mm->context.crst_list, lru)
                if (page->index) {
@@ -255,7 +392,7 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
        /* "Free" second halves of page tables. */
        list_for_each_entry(page, &mm->context.pgtable_list, lru)
                page->flags &= ~SECOND_HALVES;
-       spin_unlock(&mm->context.list_lock);
+       spin_unlock_bh(&mm->context.list_lock);
        mm->context.noexec = 0;
        update_mm(mm, tsk);
 }
@@ -312,6 +449,8 @@ int s390_enable_sie(void)
        tsk->mm = tsk->active_mm = mm;
        preempt_disable();
        update_mm(mm, tsk);
+       atomic_inc(&mm->context.attach_count);
+       atomic_dec(&old_mm->context.attach_count);
        cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
        preempt_enable();
        task_unlock(tsk);
index ccf38f06c57d78110e14cd21a0e3984c3c52b52d..2fd469807683fadfe15449e2474ec1f35f2fb921 100644 (file)
@@ -88,10 +88,7 @@ static inline void pmd_clear(pmd_t *pmdp)
 
 #define pte_offset_map(dir, address)   \
        ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)    \
-       ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 /*
  * Bits 9(_PAGE_PRESENT) and 10(_PAGE_FILE)are taken,
index 35b6879628a04feccd1dd2071846cb92563f5586..0f40fc35d0a2f7fecb83795792343c0fa4dbf39a 100644 (file)
@@ -24,6 +24,7 @@ config SUPERH
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
        select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_REGS_AND_STACK_ACCESS_API
        select RTC_LIB
        select GENERIC_ATOMIC64
        help
@@ -46,7 +47,7 @@ config SUPERH32
        select HAVE_ARCH_KGDB
        select HAVE_HW_BREAKPOINT
        select HAVE_MIXED_BREAKPOINTS_REGS
-       select PERF_EVENTS if HAVE_HW_BREAKPOINT
+       select PERF_EVENTS
        select ARCH_HIBERNATION_POSSIBLE if MMU
 
 config SUPERH64
@@ -471,6 +472,7 @@ config CPU_SUBTYPE_SHX3
        select CPU_SH4A
        select CPU_SHX3
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select ARCH_REQUIRE_GPIOLIB
 
 # SH4AL-DSP Processor Support
 
@@ -575,7 +577,7 @@ config SH_CLK_CPG
 config SH_CLK_CPG_LEGACY
        depends on SH_CLK_CPG
        def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
-                     !CPU_SUBTYPE_SH7786
+                     !CPU_SHX3 && !CPU_SUBTYPE_SH7757
 
 config SH_CLK_MD
        int "CPU Mode Pin Setting"
index 07b35ca2f64449fee151ad7176d8d58a2795f7a7..9c94711aa6caee785b152ba7be282b98a6b6d285 100644 (file)
@@ -155,6 +155,8 @@ config SH_SDK7786
        depends on CPU_SUBTYPE_SH7786
        select SYS_SUPPORTS_PCI
        select NO_IOPORT if !PCI
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select HAVE_SRAM_POOL
        help
          Select SDK7786 if configuring for a Renesas Technology Europe
          SH7786-65nm board.
@@ -165,6 +167,11 @@ config SH_HIGHLANDER
        select SYS_SUPPORTS_PCI
        select IO_TRAPPED if MMU
 
+config SH_SH7757LCR
+       bool "SH7757LCR"
+       depends on CPU_SUBTYPE_SH7757
+       select ARCH_REQUIRE_GPIOLIB
+
 config SH_SH7785LCR
        bool "SH7785LCR"
        depends on CPU_SUBTYPE_SH7785
@@ -309,6 +316,17 @@ config SH_POLARIS
        help
          Select if configuring for an SMSC Polaris development board
 
+config SH_SH2007
+       bool "SH-2007 board"
+       select NO_IOPORT
+       depends on CPU_SUBTYPE_SH7780
+       help
+         SH-2007 is a single-board computer based around SH7780 chip
+         intended for embedded applications.
+         It has an Ethernet interface (SMC9118), direct connected
+         Compact Flash socket, two serial ports and PC-104 bus.
+         More information at <http://sh2000.sh-linux.org>.
+
 endmenu
 
 source "arch/sh/boards/mach-r2d/Kconfig"
index 4f90f9b7a9228e3991e900a04190b5f88c01dd10..38ef655cc0f08cfe0f881b053f421e9861412556 100644 (file)
@@ -2,6 +2,7 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
+obj-$(CONFIG_SH_SH2007)                += board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
@@ -9,3 +10,4 @@ obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)          += board-espt.o
 obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
 obj-$(CONFIG_SH_TITAN)         += board-titan.o
+obj-$(CONFIG_SH_SH7757LCR)     += board-sh7757lcr.o
diff --git a/arch/sh/boards/board-sh2007.c b/arch/sh/boards/board-sh2007.c
new file mode 100644 (file)
index 0000000..b90b78f
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SH-2007 board support.
+ *
+ * Copyright (C) 2003, 2004  SUGIOKA Toshinobu
+ * Copyright (C) 2010  Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/io.h>
+#include <asm/machvec.h>
+#include <mach/sh2007.h>
+
+struct smsc911x_platform_config smc911x_info = {
+       .flags          = SMSC911X_USE_32BIT,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct resource smsc9118_0_resources[] = {
+       [0] = {
+               .start  = SMC0_BASE,
+               .end    = SMC0_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x240),
+               .end    = evt2irq(0x240),
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource smsc9118_1_resources[] = {
+       [0] = {
+               .start  = SMC1_BASE,
+               .end    = SMC1_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x280),
+               .end    = evt2irq(0x280),
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device smsc9118_0_device = {
+       .name           = "smsc911x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smsc9118_0_resources),
+       .resource       = smsc9118_0_resources,
+       .dev = {
+               .platform_data = &smc911x_info,
+       },
+};
+
+static struct platform_device smsc9118_1_device = {
+       .name           = "smsc911x",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(smsc9118_1_resources),
+       .resource       = smsc9118_1_resources,
+       .dev = {
+               .platform_data = &smc911x_info,
+       },
+};
+
+static struct resource cf_resources[] = {
+       [0] = {
+               .start  = CF_BASE + CF_OFFSET,
+               .end    = CF_BASE + CF_OFFSET + 0x0f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = CF_BASE + CF_OFFSET + 0x206,
+               .end    = CF_BASE + CF_OFFSET + 0x20f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = evt2irq(0x2c0),
+               .end    = evt2irq(0x2c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cf_device  = {
+       .name           = "pata_platform",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(cf_resources),
+       .resource       = cf_resources,
+};
+
+static struct platform_device *sh2007_devices[] __initdata = {
+       &smsc9118_0_device,
+       &smsc9118_1_device,
+       &cf_device,
+};
+
+static int __init sh2007_io_init(void)
+{
+       platform_add_devices(sh2007_devices, ARRAY_SIZE(sh2007_devices));
+       return 0;
+}
+subsys_initcall(sh2007_io_init);
+
+static void __init sh2007_init_irq(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * Initialize the board
+ */
+static void __init sh2007_setup(char **cmdline_p)
+{
+       printk(KERN_INFO "SH-2007 Setup...");
+
+       /* setup wait control registers for area 5 */
+       __raw_writel(CS5BCR_D, CS5BCR);
+       __raw_writel(CS5WCR_D, CS5WCR);
+       __raw_writel(CS5PCR_D, CS5PCR);
+
+       printk(KERN_INFO " done.\n");
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh2007 __initmv = {
+       .mv_setup               = sh2007_setup,
+       .mv_name                = "sh2007",
+       .mv_init_irq            = sh2007_init_irq,
+};
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
new file mode 100644 (file)
index 0000000..c475f10
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Renesas R0P7757LC0012RL Support.
+ *
+ * Copyright (C) 2009 - 2010  Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/io.h>
+#include <cpu/sh7757.h>
+#include <asm/sh_eth.h>
+#include <asm/heartbeat.h>
+
+static struct resource heartbeat_resource = {
+       .start  = 0xffec005c,   /* PUDR */
+       .end    = 0xffec005c,
+       .flags  = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
+};
+
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 };
+
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+       .flags          = HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .dev    = {
+               .platform_data  = &heartbeat_data,
+       },
+       .num_resources  = 1,
+       .resource       = &heartbeat_resource,
+};
+
+/* Fast Ethernet */
+static struct resource sh_eth0_resources[] = {
+       {
+               .start  = 0xfef00000,
+               .end    = 0xfef001ff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = 84,
+               .end    = 84,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_eth_plat_data sh7757_eth0_pdata = {
+       .phy = 1,
+       .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth0_device = {
+       .name           = "sh-eth",
+       .resource       = sh_eth0_resources,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(sh_eth0_resources),
+       .dev            = {
+               .platform_data = &sh7757_eth0_pdata,
+       },
+};
+
+static struct resource sh_eth1_resources[] = {
+       {
+               .start  = 0xfef00800,
+               .end    = 0xfef009ff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = 84,
+               .end    = 84,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_eth_plat_data sh7757_eth1_pdata = {
+       .phy = 1,
+       .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth1_device = {
+       .name           = "sh-eth",
+       .resource       = sh_eth1_resources,
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(sh_eth1_resources),
+       .dev            = {
+               .platform_data = &sh7757_eth1_pdata,
+       },
+};
+
+static struct platform_device *sh7757lcr_devices[] __initdata = {
+       &heartbeat_device,
+       &sh7757_eth0_device,
+       &sh7757_eth1_device,
+};
+
+static int __init sh7757lcr_devices_setup(void)
+{
+       /* RGMII (PTA) */
+       gpio_request(GPIO_FN_ET0_MDC, NULL);
+       gpio_request(GPIO_FN_ET0_MDIO, NULL);
+       gpio_request(GPIO_FN_ET1_MDC, NULL);
+       gpio_request(GPIO_FN_ET1_MDIO, NULL);
+
+       /* ONFI (PTB, PTZ) */
+       gpio_request(GPIO_FN_ON_NRE, NULL);
+       gpio_request(GPIO_FN_ON_NWE, NULL);
+       gpio_request(GPIO_FN_ON_NWP, NULL);
+       gpio_request(GPIO_FN_ON_NCE0, NULL);
+       gpio_request(GPIO_FN_ON_R_B0, NULL);
+       gpio_request(GPIO_FN_ON_ALE, NULL);
+       gpio_request(GPIO_FN_ON_CLE, NULL);
+
+       gpio_request(GPIO_FN_ON_DQ7, NULL);
+       gpio_request(GPIO_FN_ON_DQ6, NULL);
+       gpio_request(GPIO_FN_ON_DQ5, NULL);
+       gpio_request(GPIO_FN_ON_DQ4, NULL);
+       gpio_request(GPIO_FN_ON_DQ3, NULL);
+       gpio_request(GPIO_FN_ON_DQ2, NULL);
+       gpio_request(GPIO_FN_ON_DQ1, NULL);
+       gpio_request(GPIO_FN_ON_DQ0, NULL);
+
+       /* IRQ8 to 0 (PTB, PTC) */
+       gpio_request(GPIO_FN_IRQ8, NULL);
+       gpio_request(GPIO_FN_IRQ7, NULL);
+       gpio_request(GPIO_FN_IRQ6, NULL);
+       gpio_request(GPIO_FN_IRQ5, NULL);
+       gpio_request(GPIO_FN_IRQ4, NULL);
+       gpio_request(GPIO_FN_IRQ3, NULL);
+       gpio_request(GPIO_FN_IRQ2, NULL);
+       gpio_request(GPIO_FN_IRQ1, NULL);
+       gpio_request(GPIO_FN_IRQ0, NULL);
+
+       /* SPI0 (PTD) */
+       gpio_request(GPIO_FN_SP0_MOSI, NULL);
+       gpio_request(GPIO_FN_SP0_MISO, NULL);
+       gpio_request(GPIO_FN_SP0_SCK, NULL);
+       gpio_request(GPIO_FN_SP0_SCK_FB, NULL);
+       gpio_request(GPIO_FN_SP0_SS0, NULL);
+       gpio_request(GPIO_FN_SP0_SS1, NULL);
+       gpio_request(GPIO_FN_SP0_SS2, NULL);
+       gpio_request(GPIO_FN_SP0_SS3, NULL);
+
+       /* RMII 0/1 (PTE, PTF) */
+       gpio_request(GPIO_FN_RMII0_CRS_DV, NULL);
+       gpio_request(GPIO_FN_RMII0_TXD1, NULL);
+       gpio_request(GPIO_FN_RMII0_TXD0, NULL);
+       gpio_request(GPIO_FN_RMII0_TXEN, NULL);
+       gpio_request(GPIO_FN_RMII0_REFCLK, NULL);
+       gpio_request(GPIO_FN_RMII0_RXD1, NULL);
+       gpio_request(GPIO_FN_RMII0_RXD0, NULL);
+       gpio_request(GPIO_FN_RMII0_RX_ER, NULL);
+       gpio_request(GPIO_FN_RMII1_CRS_DV, NULL);
+       gpio_request(GPIO_FN_RMII1_TXD1, NULL);
+       gpio_request(GPIO_FN_RMII1_TXD0, NULL);
+       gpio_request(GPIO_FN_RMII1_TXEN, NULL);
+       gpio_request(GPIO_FN_RMII1_REFCLK, NULL);
+       gpio_request(GPIO_FN_RMII1_RXD1, NULL);
+       gpio_request(GPIO_FN_RMII1_RXD0, NULL);
+       gpio_request(GPIO_FN_RMII1_RX_ER, NULL);
+
+       /* eMMC (PTG) */
+       gpio_request(GPIO_FN_MMCCLK, NULL);
+       gpio_request(GPIO_FN_MMCCMD, NULL);
+       gpio_request(GPIO_FN_MMCDAT7, NULL);
+       gpio_request(GPIO_FN_MMCDAT6, NULL);
+       gpio_request(GPIO_FN_MMCDAT5, NULL);
+       gpio_request(GPIO_FN_MMCDAT4, NULL);
+       gpio_request(GPIO_FN_MMCDAT3, NULL);
+       gpio_request(GPIO_FN_MMCDAT2, NULL);
+       gpio_request(GPIO_FN_MMCDAT1, NULL);
+       gpio_request(GPIO_FN_MMCDAT0, NULL);
+
+       /* LPC (PTG, PTH, PTQ, PTU) */
+       gpio_request(GPIO_FN_SERIRQ, NULL);
+       gpio_request(GPIO_FN_LPCPD, NULL);
+       gpio_request(GPIO_FN_LDRQ, NULL);
+       gpio_request(GPIO_FN_WP, NULL);
+       gpio_request(GPIO_FN_FMS0, NULL);
+       gpio_request(GPIO_FN_LAD3, NULL);
+       gpio_request(GPIO_FN_LAD2, NULL);
+       gpio_request(GPIO_FN_LAD1, NULL);
+       gpio_request(GPIO_FN_LAD0, NULL);
+       gpio_request(GPIO_FN_LFRAME, NULL);
+       gpio_request(GPIO_FN_LRESET, NULL);
+       gpio_request(GPIO_FN_LCLK, NULL);
+       gpio_request(GPIO_FN_LGPIO7, NULL);
+       gpio_request(GPIO_FN_LGPIO6, NULL);
+       gpio_request(GPIO_FN_LGPIO5, NULL);
+       gpio_request(GPIO_FN_LGPIO4, NULL);
+
+       /* SPI1 (PTH) */
+       gpio_request(GPIO_FN_SP1_MOSI, NULL);
+       gpio_request(GPIO_FN_SP1_MISO, NULL);
+       gpio_request(GPIO_FN_SP1_SCK, NULL);
+       gpio_request(GPIO_FN_SP1_SCK_FB, NULL);
+       gpio_request(GPIO_FN_SP1_SS0, NULL);
+       gpio_request(GPIO_FN_SP1_SS1, NULL);
+
+       /* SDHI (PTI) */
+       gpio_request(GPIO_FN_SD_WP, NULL);
+       gpio_request(GPIO_FN_SD_CD, NULL);
+       gpio_request(GPIO_FN_SD_CLK, NULL);
+       gpio_request(GPIO_FN_SD_CMD, NULL);
+       gpio_request(GPIO_FN_SD_D3, NULL);
+       gpio_request(GPIO_FN_SD_D2, NULL);
+       gpio_request(GPIO_FN_SD_D1, NULL);
+       gpio_request(GPIO_FN_SD_D0, NULL);
+
+       /* SCIF3/4 (PTJ, PTW) */
+       gpio_request(GPIO_FN_RTS3, NULL);
+       gpio_request(GPIO_FN_CTS3, NULL);
+       gpio_request(GPIO_FN_TXD3, NULL);
+       gpio_request(GPIO_FN_RXD3, NULL);
+       gpio_request(GPIO_FN_RTS4, NULL);
+       gpio_request(GPIO_FN_RXD4, NULL);
+       gpio_request(GPIO_FN_TXD4, NULL);
+       gpio_request(GPIO_FN_CTS4, NULL);
+
+       /* SERMUX (PTK, PTL, PTO, PTV) */
+       gpio_request(GPIO_FN_COM2_TXD, NULL);
+       gpio_request(GPIO_FN_COM2_RXD, NULL);
+       gpio_request(GPIO_FN_COM2_RTS, NULL);
+       gpio_request(GPIO_FN_COM2_CTS, NULL);
+       gpio_request(GPIO_FN_COM2_DTR, NULL);
+       gpio_request(GPIO_FN_COM2_DSR, NULL);
+       gpio_request(GPIO_FN_COM2_DCD, NULL);
+       gpio_request(GPIO_FN_COM2_RI, NULL);
+       gpio_request(GPIO_FN_RAC_RXD, NULL);
+       gpio_request(GPIO_FN_RAC_RTS, NULL);
+       gpio_request(GPIO_FN_RAC_CTS, NULL);
+       gpio_request(GPIO_FN_RAC_DTR, NULL);
+       gpio_request(GPIO_FN_RAC_DSR, NULL);
+       gpio_request(GPIO_FN_RAC_DCD, NULL);
+       gpio_request(GPIO_FN_RAC_TXD, NULL);
+       gpio_request(GPIO_FN_COM1_TXD, NULL);
+       gpio_request(GPIO_FN_COM1_RXD, NULL);
+       gpio_request(GPIO_FN_COM1_RTS, NULL);
+       gpio_request(GPIO_FN_COM1_CTS, NULL);
+
+       writeb(0x10, 0xfe470000);       /* SMR0: SerMux mode 0 */
+
+       /* IIC (PTM, PTR, PTS) */
+       gpio_request(GPIO_FN_SDA7, NULL);
+       gpio_request(GPIO_FN_SCL7, NULL);
+       gpio_request(GPIO_FN_SDA6, NULL);
+       gpio_request(GPIO_FN_SCL6, NULL);
+       gpio_request(GPIO_FN_SDA5, NULL);
+       gpio_request(GPIO_FN_SCL5, NULL);
+       gpio_request(GPIO_FN_SDA4, NULL);
+       gpio_request(GPIO_FN_SCL4, NULL);
+       gpio_request(GPIO_FN_SDA3, NULL);
+       gpio_request(GPIO_FN_SCL3, NULL);
+       gpio_request(GPIO_FN_SDA2, NULL);
+       gpio_request(GPIO_FN_SCL2, NULL);
+       gpio_request(GPIO_FN_SDA1, NULL);
+       gpio_request(GPIO_FN_SCL1, NULL);
+       gpio_request(GPIO_FN_SDA0, NULL);
+       gpio_request(GPIO_FN_SCL0, NULL);
+
+       /* USB (PTN) */
+       gpio_request(GPIO_FN_VBUS_EN, NULL);
+       gpio_request(GPIO_FN_VBUS_OC, NULL);
+
+       /* SGPIO1/0 (PTN, PTO) */
+       gpio_request(GPIO_FN_SGPIO1_CLK, NULL);
+       gpio_request(GPIO_FN_SGPIO1_LOAD, NULL);
+       gpio_request(GPIO_FN_SGPIO1_DI, NULL);
+       gpio_request(GPIO_FN_SGPIO1_DO, NULL);
+       gpio_request(GPIO_FN_SGPIO0_CLK, NULL);
+       gpio_request(GPIO_FN_SGPIO0_LOAD, NULL);
+       gpio_request(GPIO_FN_SGPIO0_DI, NULL);
+       gpio_request(GPIO_FN_SGPIO0_DO, NULL);
+
+       /* WDT (PTN) */
+       gpio_request(GPIO_FN_SUB_CLKIN, NULL);
+
+       /* System (PTT) */
+       gpio_request(GPIO_FN_STATUS1, NULL);
+       gpio_request(GPIO_FN_STATUS0, NULL);
+
+       /* PWMX (PTT) */
+       gpio_request(GPIO_FN_PWMX1, NULL);
+       gpio_request(GPIO_FN_PWMX0, NULL);
+
+       /* R-SPI (PTV) */
+       gpio_request(GPIO_FN_R_SPI_MOSI, NULL);
+       gpio_request(GPIO_FN_R_SPI_MISO, NULL);
+       gpio_request(GPIO_FN_R_SPI_RSPCK, NULL);
+       gpio_request(GPIO_FN_R_SPI_SSL0, NULL);
+       gpio_request(GPIO_FN_R_SPI_SSL1, NULL);
+
+       /* EVC (PTV, PTW) */
+       gpio_request(GPIO_FN_EVENT7, NULL);
+       gpio_request(GPIO_FN_EVENT6, NULL);
+       gpio_request(GPIO_FN_EVENT5, NULL);
+       gpio_request(GPIO_FN_EVENT4, NULL);
+       gpio_request(GPIO_FN_EVENT3, NULL);
+       gpio_request(GPIO_FN_EVENT2, NULL);
+       gpio_request(GPIO_FN_EVENT1, NULL);
+       gpio_request(GPIO_FN_EVENT0, NULL);
+
+       /* LED for heartbeat */
+       gpio_request(GPIO_PTU3, NULL);
+       gpio_direction_output(GPIO_PTU3, 1);
+       gpio_request(GPIO_PTU2, NULL);
+       gpio_direction_output(GPIO_PTU2, 1);
+       gpio_request(GPIO_PTU1, NULL);
+       gpio_direction_output(GPIO_PTU1, 1);
+       gpio_request(GPIO_PTU0, NULL);
+       gpio_direction_output(GPIO_PTU0, 1);
+
+       /* control for MDIO of Gigabit Ethernet */
+       gpio_request(GPIO_PTT4, NULL);
+       gpio_direction_output(GPIO_PTT4, 1);
+
+       /* control for eMMC */
+       gpio_request(GPIO_PTT7, NULL);          /* eMMC_RST# */
+       gpio_direction_output(GPIO_PTT7, 0);
+       gpio_request(GPIO_PTT6, NULL);          /* eMMC_INDEX# */
+       gpio_direction_output(GPIO_PTT6, 0);
+       gpio_request(GPIO_PTT5, NULL);          /* eMMC_PRST# */
+       gpio_direction_output(GPIO_PTT5, 1);
+
+       /* General platform */
+       return platform_add_devices(sh7757lcr_devices,
+                                   ARRAY_SIZE(sh7757lcr_devices));
+}
+arch_initcall(sh7757lcr_devices_setup);
+
+/* Initialize IRQ setting */
+void __init init_sh7757lcr_IRQ(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRQ7654);
+       plat_irq_setup_pins(IRQ_MODE_IRQ3210);
+}
+
+/* Initialize the board */
+static void __init sh7757lcr_setup(char **cmdline_p)
+{
+       printk(KERN_INFO "Renesas R0P7757LC0012RL support.\n");
+}
+
+static int sh7757lcr_mode_pins(void)
+{
+       int value = 0;
+
+       /* These are the factory default settings of S3 (Low active).
+        * If you change these dip switches then you will need to
+        * adjust the values below as well.
+        */
+       value |= MODE_PIN0;     /* Clock Mode: 1 */
+
+       return value;
+}
+
+/* The Machine Vector */
+static struct sh_machine_vector mv_sh7757lcr __initmv = {
+       .mv_name                = "SH7757LCR",
+       .mv_setup               = sh7757lcr_setup,
+       .mv_init_irq            = init_sh7757lcr_IRQ,
+       .mv_mode_pins           = sh7757lcr_mode_pins,
+};
+
index 1d7b495a7db485bf77952295117535d6ab9ce7df..71a3368ab1fc00837ab9161298637f999fb8bed5 100644 (file)
@@ -1248,14 +1248,14 @@ static int __init arch_setup(void)
 
        /* set SPU2 clock to 83.4 MHz */
        clk = clk_get(NULL, "spu_clk");
-       if (clk) {
+       if (!IS_ERR(clk)) {
                clk_set_rate(clk, clk_round_rate(clk, 83333333));
                clk_put(clk);
        }
 
        /* change parent of FSI B */
        clk = clk_get(NULL, "fsib_clk");
-       if (clk) {
+       if (!IS_ERR(clk)) {
                clk_register(&fsimckb_clk);
                clk_set_parent(clk, &fsimckb_clk);
                clk_set_rate(clk, 11000);
@@ -1273,7 +1273,7 @@ static int __init arch_setup(void)
 
        /* set VPU clock to 166 MHz */
        clk = clk_get(NULL, "vpu_clk");
-       if (clk) {
+       if (!IS_ERR(clk)) {
                clk_set_rate(clk, clk_round_rate(clk, 166000000));
                clk_put(clk);
        }
index a29f19e85b63f7b0ea64aafe870540df6153d8ee..23ff7d4ac491fc2e47cf334700e3133f01684b9c 100644 (file)
@@ -1 +1,4 @@
-obj-y  := setup.o fpga.o irq.o
+obj-y  := fpga.o irq.o setup.o
+
+obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
+obj-$(CONFIG_HAVE_SRAM_POOL)   += sram.o
diff --git a/arch/sh/boards/mach-sdk7786/gpio.c b/arch/sh/boards/mach-sdk7786/gpio.c
new file mode 100644 (file)
index 0000000..f71ce09
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SDK7786 FPGA USRGPIR Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/fpga.h>
+
+#define NR_FPGA_GPIOS  8
+
+static const char *usrgpir_gpio_names[NR_FPGA_GPIOS] = {
+       "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7",
+};
+
+static int usrgpir_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+       /* always in */
+       return 0;
+}
+
+static int usrgpir_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+       return !!(fpga_read_reg(USRGPIR) & (1 << gpio));
+}
+
+static struct gpio_chip usrgpir_gpio_chip = {
+       .label                  = "sdk7786-fpga",
+       .names                  = usrgpir_gpio_names,
+       .direction_input        = usrgpir_gpio_direction_input,
+       .get                    = usrgpir_gpio_get,
+       .base                   = -1, /* don't care */
+       .ngpio                  = NR_FPGA_GPIOS,
+};
+
+static int __init usrgpir_gpio_setup(void)
+{
+       return gpiochip_add(&usrgpir_gpio_chip);
+}
+device_initcall(usrgpir_gpio_setup);
index 2ec1ea5cf8efcbb0b23306ca32b0202e4343fc0c..7e0c4e3878e062dd292b591c9706a3ff3127fbd7 100644 (file)
@@ -20,6 +20,8 @@
 #include <asm/machvec.h>
 #include <asm/heartbeat.h>
 #include <asm/sizes.h>
+#include <asm/clock.h>
+#include <asm/clkdev.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
 
@@ -140,6 +142,45 @@ static int sdk7786_mode_pins(void)
        return fpga_read_reg(MODSWR);
 }
 
+/*
+ * FPGA-driven PCIe clocks
+ *
+ * Historically these include the oscillator, clock B (slots 2/3/4) and
+ * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove
+ * everything under a single PCIe clocks enable bit that happens to map
+ * to the same bit position as the oscillator bit for earlier FPGA
+ * versions.
+ *
+ * Given that the legacy clocks have the side-effect of shutting the CPU
+ * off through the FPGA along with the PCI slots, we simply leave them in
+ * their initial state and don't bother registering them with the clock
+ * framework.
+ */
+static int sdk7786_pcie_clk_enable(struct clk *clk)
+{
+       fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR);
+       return 0;
+}
+
+static void sdk7786_pcie_clk_disable(struct clk *clk)
+{
+       fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
+}
+
+static struct clk_ops sdk7786_pcie_clk_ops = {
+       .enable         = sdk7786_pcie_clk_enable,
+       .disable        = sdk7786_pcie_clk_disable,
+};
+
+static struct clk sdk7786_pcie_clk = {
+       .ops            = &sdk7786_pcie_clk_ops,
+};
+
+static struct clk_lookup sdk7786_pcie_cl = {
+       .con_id         = "pcie_plat_clk",
+       .clk            = &sdk7786_pcie_clk,
+};
+
 static int sdk7786_clk_init(void)
 {
        struct clk *clk;
@@ -158,7 +199,18 @@ static int sdk7786_clk_init(void)
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
 
-       return ret;
+       /*
+        * Setup the FPGA clocks.
+        */
+       ret = clk_register(&sdk7786_pcie_clk);
+       if (unlikely(ret)) {
+               pr_err("FPGA clock registration failed\n");
+               return ret;
+       }
+
+       clkdev_add(&sdk7786_pcie_cl);
+
+       return 0;
 }
 
 static void sdk7786_restart(char *cmd)
diff --git a/arch/sh/boards/mach-sdk7786/sram.c b/arch/sh/boards/mach-sdk7786/sram.c
new file mode 100644 (file)
index 0000000..c81c3ab
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SDK7786 FPGA SRAM Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <mach/fpga.h>
+#include <asm/sram.h>
+#include <asm/sizes.h>
+
+static int __init fpga_sram_init(void)
+{
+       unsigned long phys;
+       unsigned int area;
+       void __iomem *vaddr;
+       int ret;
+       u16 data;
+
+       /* Enable FPGA SRAM */
+       data = fpga_read_reg(LCLASR);
+       data |= LCLASR_FRAMEN;
+       fpga_write_reg(data, LCLASR);
+
+       /*
+        * FPGA_SEL determines the area mapping
+        */
+       area = (data & LCLASR_FPGA_SEL_MASK) >> LCLASR_FPGA_SEL_SHIFT;
+       if (unlikely(area == LCLASR_AREA_MASK)) {
+               pr_err("FPGA memory unmapped.\n");
+               return -ENXIO;
+       }
+
+       /*
+        * The memory itself occupies a 2KiB range at the top of the area
+        * immediately below the system registers.
+        */
+       phys = (area << 26) + SZ_64M - SZ_4K;
+
+       /*
+        * The FPGA SRAM resides in translatable physical space, so set
+        * up a mapping prior to inserting it in to the pool.
+        */
+       vaddr = ioremap(phys, SZ_2K);
+       if (unlikely(!vaddr)) {
+               pr_err("Failed remapping FPGA memory.\n");
+               return -ENXIO;
+       }
+
+       pr_info("Adding %dKiB of FPGA memory at 0x%08lx-0x%08lx "
+               "(area %d) to pool.\n",
+               SZ_2K >> 10, phys, phys + SZ_2K - 1, area);
+
+       ret = gen_pool_add(sram_pool, (unsigned long)vaddr, SZ_2K, -1);
+       if (unlikely(ret < 0)) {
+               pr_err("Failed adding memory\n");
+               iounmap(vaddr);
+               return ret;
+       }
+
+       return 0;
+}
+postcore_initcall(fpga_sram_init);
index 983e4551fecff8c39656b1993c696abbb764933d..708c21c919ff8c46dc71222afaf668d11b31738c 100644 (file)
@@ -1 +1,3 @@
 obj-y += setup.o ilsel.o
+
+obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
new file mode 100644 (file)
index 0000000..594adf7
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * arch/sh/boards/mach-x3proto/gpio.c
+ *
+ * Renesas SH-X3 Prototype Baseboard GPIO Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
+
+#define KEYCTLR        0xb81c0000
+#define KEYOUTR        0xb81c0002
+#define KEYDETR 0xb81c0004
+
+static DEFINE_SPINLOCK(x3proto_gpio_lock);
+static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
+
+static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+       unsigned long flags;
+       unsigned int data;
+
+       spin_lock_irqsave(&x3proto_gpio_lock, flags);
+       data = __raw_readw(KEYCTLR);
+       data |= (1 << gpio);
+       __raw_writew(data, KEYCTLR);
+       spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+
+       return 0;
+}
+
+static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+       return !!(__raw_readw(KEYDETR) & (1 << gpio));
+}
+
+static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+       return x3proto_gpio_irq_map[gpio];
+}
+
+static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = get_irq_desc_chip(desc);
+       unsigned long mask;
+       int pin;
+
+       chip->mask_ack(irq);
+
+       mask = __raw_readw(KEYDETR);
+
+       for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
+               generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
+
+       chip->unmask(irq);
+}
+
+struct gpio_chip x3proto_gpio_chip = {
+       .label                  = "x3proto-gpio",
+       .direction_input        = x3proto_gpio_direction_input,
+       .get                    = x3proto_gpio_get,
+       .to_irq                 = x3proto_gpio_to_irq,
+       .base                   = -1,
+       .ngpio                  = NR_BASEBOARD_GPIOS,
+};
+
+int __init x3proto_gpio_setup(void)
+{
+       int ilsel;
+       int ret, i;
+
+       ilsel = ilsel_enable(ILSEL_KEY);
+       if (unlikely(ilsel < 0))
+               return ilsel;
+
+       ret = gpiochip_add(&x3proto_gpio_chip);
+       if (unlikely(ret))
+               goto err_gpio;
+
+       for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
+               unsigned long flags;
+               int irq = create_irq();
+
+               if (unlikely(irq < 0)) {
+                       ret = -EINVAL;
+                       goto err_irq;
+               }
+
+               spin_lock_irqsave(&x3proto_gpio_lock, flags);
+               x3proto_gpio_irq_map[i] = irq;
+               set_irq_chip_and_handler_name(irq, &dummy_irq_chip,
+                                       handle_simple_irq, "gpio");
+               spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+       }
+
+       pr_info("registering '%s' support, handling GPIOs %u -> %u, "
+               "bound to IRQ %u\n",
+               x3proto_gpio_chip.label, x3proto_gpio_chip.base,
+               x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
+               ilsel);
+
+       set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler);
+       set_irq_wake(ilsel, 1);
+
+       return 0;
+
+err_irq:
+       for (; i >= 0; --i)
+               if (x3proto_gpio_irq_map[i])
+                       destroy_irq(x3proto_gpio_irq_map[i]);
+
+       ret = gpiochip_remove(&x3proto_gpio_chip);
+       if (unlikely(ret))
+               pr_err("Failed deregistering GPIO\n");
+
+err_gpio:
+       synchronize_irq(ilsel);
+
+       ilsel_disable(ILSEL_KEY);
+
+       return ret;
+}
index 5c9842704c60f39cc1039f8c5cc8180ad67f91fb..95e34613951550d6a66c5d47164505bc093c3420 100644 (file)
@@ -1,20 +1,22 @@
 /*
- * arch/sh/boards/renesas/x3proto/ilsel.c
+ * arch/sh/boards/mach-x3proto/ilsel.c
  *
  * Helper routines for SH-X3 proto board ILSEL.
  *
- * Copyright (C) 2007 Paul Mundt
+ * Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/bitmap.h>
 #include <linux/io.h>
-#include <asm/ilsel.h>
+#include <mach/ilsel.h>
 
 /*
  * ILSEL is split across:
@@ -64,6 +66,8 @@ static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
        unsigned int tmp, shift;
        unsigned long addr;
 
+       pr_notice("enabling ILSEL set %d\n", set);
+
        addr = mk_ilsel_addr(bit);
        shift = mk_ilsel_shift(bit);
 
@@ -92,8 +96,10 @@ int ilsel_enable(ilsel_source_t set)
 {
        unsigned int bit;
 
-       /* Aliased sources must use ilsel_enable_fixed() */
-       BUG_ON(set > ILSEL_KEY);
+       if (unlikely(set > ILSEL_KEY)) {
+               pr_err("Aliased sources must use ilsel_enable_fixed()\n");
+               return -EINVAL;
+       }
 
        do {
                bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
@@ -140,6 +146,8 @@ void ilsel_disable(unsigned int irq)
        unsigned long addr;
        unsigned int tmp;
 
+       pr_notice("disabling ILSEL set %d\n", irq);
+
        addr = mk_ilsel_addr(irq);
 
        tmp = __raw_readw(addr);
index 102bf56befb41f394eeebf500d1fa1a953ed4bf3..d682e2b6a856c42854e8b43bed314f9fb918f8e8 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * arch/sh/boards/renesas/x3proto/setup.c
+ * arch/sh/boards/mach-x3proto/setup.c
  *
  * Renesas SH-X3 Prototype Board Support.
  *
- * Copyright (C) 2007 - 2008 Paul Mundt
+ * Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
 #include <linux/smc91x.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/input.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/usb/m66592.h>
-#include <asm/ilsel.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
 #include <asm/smp-ops.h>
 
 static struct resource heartbeat_resources[] = {
@@ -122,15 +126,128 @@ static struct platform_device m66592_usb_peripheral_device = {
        .resource       = m66592_usb_peripheral_resources,
 };
 
+static struct gpio_keys_button baseboard_buttons[NR_BASEBOARD_GPIOS] = {
+       {
+               .desc           = "key44",
+               .code           = KEY_POWER,
+               .active_low     = 1,
+               .wakeup         = 1,
+       }, {
+               .desc           = "key43",
+               .code           = KEY_SUSPEND,
+               .active_low     = 1,
+               .wakeup         = 1,
+       }, {
+               .desc           = "key42",
+               .code           = KEY_KATAKANAHIRAGANA,
+               .active_low     = 1,
+       }, {
+               .desc           = "key41",
+               .code           = KEY_SWITCHVIDEOMODE,
+               .active_low     = 1,
+       }, {
+               .desc           = "key34",
+               .code           = KEY_F12,
+               .active_low     = 1,
+       }, {
+               .desc           = "key33",
+               .code           = KEY_F11,
+               .active_low     = 1,
+       }, {
+               .desc           = "key32",
+               .code           = KEY_F10,
+               .active_low     = 1,
+       }, {
+               .desc           = "key31",
+               .code           = KEY_F9,
+               .active_low     = 1,
+       }, {
+               .desc           = "key24",
+               .code           = KEY_F8,
+               .active_low     = 1,
+       }, {
+               .desc           = "key23",
+               .code           = KEY_F7,
+               .active_low     = 1,
+       }, {
+               .desc           = "key22",
+               .code           = KEY_F6,
+               .active_low     = 1,
+       }, {
+               .desc           = "key21",
+               .code           = KEY_F5,
+               .active_low     = 1,
+       }, {
+               .desc           = "key14",
+               .code           = KEY_F4,
+               .active_low     = 1,
+       }, {
+               .desc           = "key13",
+               .code           = KEY_F3,
+               .active_low     = 1,
+       }, {
+               .desc           = "key12",
+               .code           = KEY_F2,
+               .active_low     = 1,
+       }, {
+               .desc           = "key11",
+               .code           = KEY_F1,
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data baseboard_buttons_data = {
+       .buttons        = baseboard_buttons,
+       .nbuttons       = ARRAY_SIZE(baseboard_buttons),
+};
+
+static struct platform_device baseboard_buttons_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &baseboard_buttons_data,
+       },
+};
+
 static struct platform_device *x3proto_devices[] __initdata = {
        &heartbeat_device,
        &smc91x_device,
        &r8a66597_usb_host_device,
        &m66592_usb_peripheral_device,
+       &baseboard_buttons_device,
 };
 
+static void __init x3proto_init_irq(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+       /* Set ICR0.LVLMODE */
+       __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
 static int __init x3proto_devices_setup(void)
 {
+       int ret, i;
+
+       /*
+        * IRLs are only needed for ILSEL mappings, so flip over the INTC
+        * pins at a later point to enable the GPIOs to settle.
+        */
+       x3proto_init_irq();
+
+       /*
+        * Now that ILSELs are available, set up the baseboard GPIOs.
+        */
+       ret = x3proto_gpio_setup();
+       if (unlikely(ret))
+               return ret;
+
+       /*
+        * Propagate dynamic GPIOs for the baseboard button device.
+        */
+       for (i = 0; i < ARRAY_SIZE(baseboard_buttons); i++)
+               baseboard_buttons[i].gpio = x3proto_gpio_chip.base + i;
+
        r8a66597_usb_host_resources[1].start =
                r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
 
@@ -145,14 +262,6 @@ static int __init x3proto_devices_setup(void)
 }
 device_initcall(x3proto_devices_setup);
 
-static void __init x3proto_init_irq(void)
-{
-       plat_irq_setup_pins(IRQ_MODE_IRL3210);
-
-       /* Set ICR0.LVLMODE */
-       __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
-}
-
 static void __init x3proto_setup(char **cmdline_p)
 {
        register_smp_ops(&shx3_smp_ops);
@@ -161,5 +270,4 @@ static void __init x3proto_setup(char **cmdline_p)
 static struct sh_machine_vector mv_x3proto __initmv = {
        .mv_name                = "x3proto",
        .mv_setup               = x3proto_setup,
-       .mv_init_irq            = x3proto_init_irq,
 };
index 200c1d4f1efe4c518a6470993603d748550d4eae..3e150326f1fd8a16a6161d6ce796c5ba63094c15 100644 (file)
@@ -91,7 +91,9 @@ bss_start_addr:
 end_addr:
        .long   _end
 init_sr:
-       .long   0x400000F0      /* Privileged mode, Bank=0, Block=0, IMASK=0xF */
+       .long   0x500000F0      /* Privileged mode, Bank=0, Block=1, IMASK=0xF */
+kexec_magic:
+       .long   0x400000F0      /* magic used by kexec to parse zImage format */
 init_stack_addr:
        .long   stack_start
 decompress_kernel_addr:
index 9682e3ab668fd338d92e633f327319a39679d0f9..59c348337bb86199fcbe4571a85db9feb019ea0a 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_HD64461)  += hd64461.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index 238d6833ac70d8d54395adf6b345ca4cc0e17b44..e5335123b5e99c098f15d2a284e1d28c605277c3 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index b3bf11bcf02589c8ead27a6c2b07e1c002ac2fc4..67e150631ea514b72dc14e1b0f03b46ef11d550e 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 3cdee4f0c184abcbd2ab0eaf69cfa5faa588ade7..ec243ca295292f2a2da487735551048996b741d1 100644 (file)
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
index 021633b02835ed91abd7deff23f7cc1e8d0f2fe4..5fcb17bff24a3d8ec19e023e647045ee554aa098 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
index 365f2318e9b5b545da60e9146a0c6e114d7c9165..e1077a041ac3a453ea6381ce573f2d508144118f 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
index ca7fc1b3d567dc5474a87bfc22b53d6146465d82..67cb1094a03333dfc84a2f2214d75bfc6450e342 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
 CONFIG_IPC_NS=y
index 45c18a3830d2a59f94f656936361710740bf86e7..496edcdf95a3e8f246113757a99b791dbd15cdd2 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
index d4268b1953bcf29b3f7541ece6be90050ed1e7ca..029a506ca3258da0bb7bd957548859061cbe6487 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
index ad5d296b375f935752d812aa99e2ca5d8eb9e616..fac13ded07b2bd71c6bbac7e0e48dc28bf86112d 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
index 14e658e9318fba8ec2b61099f3bf8ac66fabf1ef..3670e937f2b769fc9a9bb6e60f6b00bce45a55ec 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
index 6be7eaaa8bb6176e1db21f20088d88e835d37be9..e3c0894b1bb4abc5a55eeaabfa74caa369d0f675 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
index 4d61b7711b40a6a951f722c5f993fae2e8dd7bd9..9479872b1ae6b0332a97b6d5d53adb93831d6ee6 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_AUDIT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
index 0e32a24fed53f542c92beefb64f156d52a8d31b6..f1d2e1b5ee419eaad55cadab5f230c6ace448c92 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
index c19fcdfdee37ed3d7cb564859635358566f1c9bf..9ad904a110de750c0df7e18dbc58be52352addff 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
index 984e3fe1ce5d7f5e2d68aa630aaf84c6943ef2b4..f3d5d9f76310612d42a69c457835875b57f4e81b 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_AUDIT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index e8b5472e6d841bb74bc8b254a2ceec90d57853ba..920b8471ceb766ff35ed309bd2e5435e860822e1 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index fd884806098291dfe3a242b6d70a39723dc527bb..c77da6be06b8975ed68a992bb96ae6fab3bc9d24 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_RCU_TRACE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
index a42f7c22ca1a1e2525085a9b820986c65f11940f..a3d081095ce23a293dedf7e4aeee44a27e67e90a 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
index 742aa61f2427147a99135e5e47934a7200e74478..b1a04f3c598bb1088bf2f363c0a84ab8f431c909 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
index aed394d89346f8b4b6bf733515636bba374de18b..ae1115849dda4bd22d657fd0076eaa6f14d1529b 100644 (file)
@@ -6,7 +6,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
index 7a7e13853cfda5c6e3596c8e19dee2392028837c..be9c474197b3de65df7ebf59b6e8f16543d8c522 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 3620a7f4c821ac57a0e114250ff347cc9ff89602..1248635e4f888a4a248f4efa7236243fb4ee0deb 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_BUG is not set
index fe22f599c0cbd381af9486c43767e6db6b2cacdc..c3ba6e8a981810542ecd702cf8ca2d9240496d74 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_BUG is not set
index b9b64c38810e1564f47203c54a44ff85ad50d2e0..ae998c7e2ee0f5aa59a4e524ed2f6ba06305d78a 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
index 03e736781c2e3042c01c6be9ae367b83919fa952..ed35093e375892701300277b1f2072cdefba01ad 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 1a686b6d5cd437e1c50c71f6efac79d906d5cf84..912c98590e2215c69dde022f9698862f93fb4da5 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
index 7e03451a9fad96a434462b24882f966dfb7d3375..75c92fc1876b79c629b44d418be27c309862ab8c 100644 (file)
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
index 4cfc4deff13507d7978c2f6418ccd0f84bd2e01c..c8c5e7f7a68d1476b9c0a51575ddfe000d7e9a76 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index b95dc76b04c1b69840b949cccd1e40c3d03c2184..2051821724c6db6d33ac89b333bc5214b61b68ea 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
diff --git a/arch/sh/configs/sh2007_defconfig b/arch/sh/configs/sh2007_defconfig
new file mode 100644 (file)
index 0000000..0d2f414
--- /dev/null
@@ -0,0 +1,212 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+CONFIG_MEMORY_SIZE=0x08000000
+# CONFIG_VSYSCALL is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH2007=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_NR_DMA_CHANNELS_BOOL=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC1,115200 ip=dhcp root=/dev/nfs rw nfsroot=/nfs/rootfs,rsize=1024,wsize=1024 earlyprintk=sh-sci.1"
+CONFIG_PCCARD=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_NET_IPIP=y
+# 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_IPV6 is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PKTGEN=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_RAID_ATTRS=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_EQUALIZER=y
+CONFIG_TUN=y
+CONFIG_VETH=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SH_WDT=y
+CONFIG_SSB=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_DMADEVICES=y
+CONFIG_TIMB_DMA=y
+CONFIG_EXT3_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=932
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_CAMELLIA=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
index b804641c8dd2aa89c17fef54cb9328bcf4ac38ee..f92ad17cd629ffa93eae80be7dac2315e7f6e468 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/sh7757lcr_defconfig b/arch/sh/configs/sh7757lcr_defconfig
new file mode 100644 (file)
index 0000000..273f3fa
--- /dev/null
@@ -0,0 +1,85 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7757=y
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x0f000000
+CONFIG_PMB=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH7757LCR=y
+CONFIG_HEARTBEAT=y
+CONFIG_SECCOMP=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC2,115200 root=/dev/nfs ip=dhcp"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_PHYLIB=y
+CONFIG_VITESSE_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_INOTIFY=y
+CONFIG_ISO9660_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_SQUASHFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
index 361876786932639a73983847e9ef59753406a439..4795364402643eb80c4cf919f72d4a03c267ca81 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
 CONFIG_IPC_NS=y
index ee6b81f7539e45fe2e2d01feb7316b0d3aa2ac9f..51561f5677d8163863b3691708ffac2ec74ab898 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
index bb4f60c0f866c93d9eaddd2b1e09a7287f47d664..3f92d37c6374e7dfde027bc5933eb40c07115d5d 100644 (file)
@@ -15,7 +15,6 @@ CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_MEM_RES_CTLR=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
index f38c98341f15b1640a5ace26023697a38a7c97ab..7eae4e59d7f0437d399ae6a3ff92b00bf100ec13 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
index 7007d00c67e02efce94872ae7d1a40db6d5f29e9..b58dfc505efe482c476b153053b926d84e1121d5 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
index 45c309ff447e9202ce2204613c546b419438c2eb..0f558914e7604cc56a6822eeb2a2dec09c510abc 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
index e107d424acf08739fa7824b6cc3f631d860b22ee..2d288b887fbdd8c56bb45c6a6d67273abc8fac77 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
index 4a277224a871f9d846210916d48eab26f80ab489..f46848f088e47c2eb900b890cbe656580f5f3a37 100644 (file)
@@ -412,8 +412,8 @@ EXPORT_SYMBOL(unregister_dmac);
 static int __init dma_api_init(void)
 {
        printk(KERN_NOTICE "DMA: Registering DMA API.\n");
-       create_proc_read_entry("dma", 0, 0, dma_read_proc, 0);
-       return 0;
+       return create_proc_read_entry("dma", 0, 0, dma_read_proc, 0)
+                   ? 0 : -ENOMEM;
 }
 subsys_initcall(dma_api_init);
 
index 4a59e6890876cd2d1546e991011c887c4a230983..82f0a335fd19f2e144603c740a616e2b467295d5 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SH_RTS7751R2D)           += fixups-rts7751r2d.o
 obj-$(CONFIG_SH_SH03)                  += fixups-sh03.o
 obj-$(CONFIG_SH_HIGHLANDER)            += fixups-r7780rp.o
 obj-$(CONFIG_SH_SH7785LCR)             += fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7786)               += fixups-sdk7786.o
 obj-$(CONFIG_SH_SDK7780)               += fixups-sdk7780.o
 obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)  += fixups-sdk7780.o
 obj-$(CONFIG_SH_TITAN)                 += fixups-titan.o
diff --git a/arch/sh/drivers/pci/fixups-sdk7786.c b/arch/sh/drivers/pci/fixups-sdk7786.c
new file mode 100644 (file)
index 0000000..0e18ee3
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SDK7786 FPGA PCIe mux handling
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "PCI: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <mach/fpga.h>
+
+/*
+ * The SDK7786 FPGA supports mangling of most of the slots in some way or
+ * another. Slots 3/4 are special in that only one can be supported at a
+ * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
+ * (the horizontal edge connector) will disable slot 3 entirely.
+ *
+ * Misconfigurations can be detected through the FPGA via the slot
+ * resistors to determine card presence. Hotplug remains unsupported.
+ */
+static unsigned int slot4en __devinitdata;
+
+char *__devinit pcibios_setup(char *str)
+{
+       if (strcmp(str, "slot4en") == 0) {
+               slot4en = 1;
+               return NULL;
+       }
+
+       return str;
+}
+
+static int __init sdk7786_pci_init(void)
+{
+       u16 data = fpga_read_reg(PCIECR);
+
+       /*
+        * Enable slot #4 if it's been specified on the command line.
+        *
+        * Optionally reroute if slot #4 has a card present while slot #3
+        * does not, regardless of command line value.
+        *
+        * Card presence is logically inverted.
+        */
+       slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
+       if (slot4en) {
+               pr_info("Activating PCIe slot#4 (disabling slot#3)\n");
+
+               data &= ~PCIECR_PCIEMUX1;
+               fpga_write_reg(data, PCIECR);
+
+               /* Warn about forced rerouting if slot#3 is occupied */
+               if ((data & PCIECR_PRST3) == 0) {
+                       pr_warning("Unreachable card detected in slot#3\n");
+                       return -EBUSY;
+               }
+       } else
+               pr_info("PCIe slot#4 disabled\n");
+
+       return 0;
+}
+postcore_initcall(sdk7786_pci_init);
index 0b81999fb88ba96c15de7606fe80fa02956ae37e..b6234203e0ac19404ed2943d5e0c808953907dc6 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 #include <asm/addrspace.h>
 #include "pci-sh4.h"
 
@@ -18,8 +19,6 @@
 #define CONFIG_CMD(bus, devfn, where) \
        (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
 
-static DEFINE_SPINLOCK(sh4_pci_lock);
-
 /*
  * Functions for accessing PCI configuration space with type 1 accesses
  */
@@ -34,10 +33,10 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
         * PCIPDR may only be accessed as 32 bit words,
         * so we must do byte alignment by hand
         */
-       spin_lock_irqsave(&sh4_pci_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
        pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
        data = pci_read_reg(chan, SH4_PCIPDR);
-       spin_unlock_irqrestore(&sh4_pci_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        switch (size) {
        case 1:
@@ -69,10 +68,10 @@ static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
        int shift;
        u32 data;
 
-       spin_lock_irqsave(&sh4_pci_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
        pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
        data = pci_read_reg(chan, SH4_PCIPDR);
-       spin_unlock_irqrestore(&sh4_pci_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        switch (size) {
        case 1:
index 48f594b9582b88880ff733d2d7a39a4d5ba23358..128421009e3f2fbbf56ec01d2a13728d675eb0a1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic SH7786 PCI-Express operations.
  *
- *  Copyright (C) 2009  Paul Mundt
+ *  Copyright (C) 2009 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License v2. See the file "COPYING" in the main directory of this archive
@@ -19,37 +19,72 @@ enum {
        PCI_ACCESS_WRITE,
 };
 
-static DEFINE_SPINLOCK(sh7786_pcie_lock);
-
 static int sh7786_pcie_config_access(unsigned char access_type,
                struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
 {
        struct pci_channel *chan = bus->sysdata;
-       int dev, func;
+       int dev, func, type, reg;
 
        dev = PCI_SLOT(devfn);
        func = PCI_FUNC(devfn);
+       type = !!bus->parent;
+       reg = where & ~3;
 
        if (bus->number > 255 || dev > 31 || func > 7)
                return PCIBIOS_FUNC_NOT_SUPPORTED;
-       if (devfn)
-               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * While each channel has its own memory-mapped extended config
+        * space, it's generally only accessible when in endpoint mode.
+        * When in root complex mode, the controller is unable to target
+        * itself with either type 0 or type 1 accesses, and indeed, any
+        * controller initiated target transfer to its own config space
+        * result in a completer abort.
+        *
+        * Each channel effectively only supports a single device, but as
+        * the same channel <-> device access works for any PCI_SLOT()
+        * value, we cheat a bit here and bind the controller's config
+        * space to devfn 0 in order to enable self-enumeration. In this
+        * case the regular PAR/PDR path is sidelined and the mangled
+        * config access itself is initiated as a SuperHyway transaction.
+        */
+       if (pci_is_root_bus(bus)) {
+               if (dev == 0) {
+                       if (access_type == PCI_ACCESS_READ)
+                               *data = pci_read_reg(chan, PCI_REG(reg));
+                       else
+                               pci_write_reg(chan, *data, PCI_REG(reg));
+
+                       return PCIBIOS_SUCCESSFUL;
+               } else if (dev > 1)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       /* Clear errors */
+       pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
 
        /* Set the PIO address */
        pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
-                               (func << 16) | (where & ~3), SH4A_PCIEPAR);
+                               (func << 16) | reg, SH4A_PCIEPAR);
 
        /* Enable the configuration access */
-       pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
+       pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
+
+       /* Check for errors */
+       if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /* Check for master and target aborts */
+       if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
+               return PCIBIOS_DEVICE_NOT_FOUND;
 
        if (access_type == PCI_ACCESS_READ)
                *data = pci_read_reg(chan, SH4A_PCIEPDR);
        else
                pci_write_reg(chan, *data, SH4A_PCIEPDR);
 
-       /* Check for master and target aborts */
-       if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
-               return PCIBIOS_DEVICE_NOT_FOUND;
+       /* Disable the configuration access */
+       pci_write_reg(chan, 0, SH4A_PCIEPCTLR);
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -66,11 +101,13 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
        else if ((size == 4) && (where & 3))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
-       spin_lock_irqsave(&sh7786_pcie_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
        ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
                                        devfn, where, &data);
-       if (ret != PCIBIOS_SUCCESSFUL)
+       if (ret != PCIBIOS_SUCCESSFUL) {
+               *val = 0xffffffff;
                goto out;
+       }
 
        if (size == 1)
                *val = (data >> ((where & 3) << 3)) & 0xff;
@@ -84,7 +121,7 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
                devfn, where, size, (unsigned long)*val);
 
 out:
-       spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
        return ret;
 }
 
@@ -100,7 +137,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
        else if ((size == 4) && (where & 3))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
-       spin_lock_irqsave(&sh7786_pcie_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
        ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
                                        devfn, where, &data);
        if (ret != PCIBIOS_SUCCESSFUL)
@@ -124,7 +161,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
        ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
                                        devfn, where, &data);
 out:
-       spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
        return ret;
 }
 
index f98141b3b7d7283ba82d04e00064231f0715b4a2..86adb1e235cdd6bf105e4e35c501045873ea2b67 100644 (file)
@@ -81,7 +81,7 @@ static int __init sh7751_pci_init(void)
        unsigned int id;
        u32 word, reg;
 
-       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+       printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
        chan->reg_base = 0xfe200000;
 
index ffdcbf10b95e08b6f8b40ce860b2a21539ca63b1..edb7cca148825f7324c37ecaf215b9f56c540751 100644 (file)
@@ -246,7 +246,7 @@ static int __init sh7780_pci_init(void)
        const char *type;
        int ret, i;
 
-       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+       printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
        chan->reg_base = 0xfe040000;
 
index 205dcbefe2756270f239c8ec7ea499aa0051ac92..1742e2c9db7a0ed3c90d38478bd32553b31485d8 100644 (file)
 #ifndef _PCI_SH7780_H_
 #define _PCI_SH7780_H_
 
-#define PCI_VENDOR_ID_RENESAS          0x1912
-#define PCI_DEVICE_ID_RENESAS_SH7781   0x0001
-#define PCI_DEVICE_ID_RENESAS_SH7780   0x0002
-#define PCI_DEVICE_ID_RENESAS_SH7763   0x0004
-#define PCI_DEVICE_ID_RENESAS_SH7785   0x0007
-
 /* SH7780 Control Registers */
 #define        PCIECR                  0xFE000008
 #define PCIECR_ENBL            0x01
index 1e9598d2bbf4832e69e43ba49eff659adcad46c8..60ee09a4e1215d14225c9280e5e5f79f0e68a3af 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/dma-debug.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 
 unsigned long PCIBIOS_MIN_IO = 0x0000;
 unsigned long PCIBIOS_MIN_MEM = 0;
@@ -56,6 +57,11 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
        }
 }
 
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+DEFINE_RAW_SPINLOCK(pci_config_lock);
 static DEFINE_MUTEX(pci_scan_mutex);
 
 int __devinit register_pci_controller(struct pci_channel *hose)
@@ -233,40 +239,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for (idx=0; idx < PCI_NUM_RESOURCES; idx++) {
-               /* Only set up the requested stuff */
-               if (!(mask & (1<<idx)))
-                       continue;
-
-               r = &dev->resource[idx];
-               if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
-                       continue;
-               if ((idx == PCI_ROM_RESOURCE) &&
-                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
-                       continue;
-               if (!r->start && r->end) {
-                       printk(KERN_ERR "PCI: Device %s not available "
-                              "because of resource collisions\n",
-                              pci_name(dev));
-                       return -EINVAL;
-               }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       if (cmd != old_cmd) {
-               printk("PCI: Enabling device %s (%04x -> %04x)\n",
-                      pci_name(dev), old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-       return 0;
+       return pci_enable_resources(dev, mask);
 }
 
 /*
@@ -295,7 +268,7 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-char * __devinit pcibios_setup(char *str)
+char * __devinit __weak pcibios_setup(char *str)
 {
        return str;
 }
index 68cb9b0ac9d28294d00c8cb63a9ece18a5ad7bfd..96e9b058aa1d9afb0245004fc8843a279b30a0eb 100644 (file)
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
 #include "pcie-sh7786.h"
 #include <asm/sizes.h>
 
 struct sh7786_pcie_port {
        struct pci_channel      *hose;
+       struct clk              *fclk, phy_clk;
        unsigned int            index;
        int                     endpoint;
        int                     link;
@@ -51,6 +54,7 @@ static struct resource sh7786_pci0_resources[] = {
                .name   = "PCIe0 MEM 2",
                .start  = 0xfe100000,
                .end    = 0xfe100000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -74,6 +78,7 @@ static struct resource sh7786_pci1_resources[] = {
                .name   = "PCIe1 MEM 2",
                .start  = 0xfe300000,
                .end    = 0xfe300000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -82,6 +87,7 @@ static struct resource sh7786_pci2_resources[] = {
                .name   = "PCIe2 IO",
                .start  = 0xfc800000,
                .end    = 0xfc800000 + SZ_4M - 1,
+               .flags  = IORESOURCE_IO,
        }, {
                .name   = "PCIe2 MEM 0",
                .start  = 0x80000000,
@@ -96,6 +102,7 @@ static struct resource sh7786_pci2_resources[] = {
                .name   = "PCIe2 MEM 2",
                .start  = 0xfcd00000,
                .end    = 0xfcd00000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -117,7 +124,29 @@ static struct pci_channel sh7786_pci_channels[] = {
        DEFINE_CONTROLLER(0xfcc00000, 2),
 };
 
-static int phy_wait_for_ack(struct pci_channel *chan)
+static struct clk fixed_pciexclkp = {
+       .rate = 100000000,      /* 100 MHz reference clock */
+};
+
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+       /*
+        * Prevent enumeration of root complex resources.
+        */
+       if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+               int i;
+
+               for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+                       dev->resource[i].start  = 0;
+                       dev->resource[i].end    = 0;
+                       dev->resource[i].flags  = 0;
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+                        sh7786_pci_fixup);
+
+static int __init phy_wait_for_ack(struct pci_channel *chan)
 {
        unsigned int timeout = 100;
 
@@ -131,7 +160,7 @@ static int phy_wait_for_ack(struct pci_channel *chan)
        return -ETIMEDOUT;
 }
 
-static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
+static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
 {
        unsigned int timeout = 100;
 
@@ -145,19 +174,14 @@ static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
        return -ETIMEDOUT;
 }
 
-static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
-                         unsigned int lane, unsigned int data)
+static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
+                                unsigned int lane, unsigned int data)
 {
-       unsigned long phyaddr, ctrl;
+       unsigned long phyaddr;
 
        phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
                        ((addr & 0xff) << BITS_ADR);
 
-       /* Enable clock */
-       ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-       ctrl |= (1 << BITS_CKE);
-       pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
-
        /* Set write data */
        pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
        pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
@@ -165,20 +189,74 @@ static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
        phy_wait_for_ack(chan);
 
        /* Clear command */
+       pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
        pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
 
        phy_wait_for_ack(chan);
+}
 
-       /* Disable clock */
-       ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-       ctrl &= ~(1 << BITS_CKE);
-       pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
+static int __init pcie_clk_init(struct sh7786_pcie_port *port)
+{
+       struct pci_channel *chan = port->hose;
+       struct clk *clk;
+       char fclk_name[16];
+       int ret;
+
+       /*
+        * First register the fixed clock
+        */
+       ret = clk_register(&fixed_pciexclkp);
+       if (unlikely(ret != 0))
+               return ret;
+
+       /*
+        * Grab the port's function clock, which the PHY clock depends
+        * on. clock lookups don't help us much at this point, since no
+        * dev_id is available this early. Lame.
+        */
+       snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
+
+       port->fclk = clk_get(NULL, fclk_name);
+       if (IS_ERR(port->fclk)) {
+               ret = PTR_ERR(port->fclk);
+               goto err_fclk;
+       }
+
+       clk_enable(port->fclk);
+
+       /*
+        * And now, set up the PHY clock
+        */
+       clk = &port->phy_clk;
+
+       memset(clk, 0, sizeof(struct clk));
+
+       clk->parent = &fixed_pciexclkp;
+       clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
+       clk->enable_bit = BITS_CKE;
+
+       ret = sh_clk_mstp32_register(clk, 1);
+       if (unlikely(ret < 0))
+               goto err_phy;
+
+       return 0;
+
+err_phy:
+       clk_disable(port->fclk);
+       clk_put(port->fclk);
+err_fclk:
+       clk_unregister(&fixed_pciexclkp);
+
+       return ret;
 }
 
-static int phy_init(struct pci_channel *chan)
+static int __init phy_init(struct sh7786_pcie_port *port)
 {
+       struct pci_channel *chan = port->hose;
        unsigned int timeout = 100;
 
+       clk_enable(&port->phy_clk);
+
        /* Initialize the phy */
        phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
        phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
@@ -187,9 +265,13 @@ static int phy_init(struct pci_channel *chan)
        phy_write_reg(chan, 0x66, 0xf, 0x00000010);
        phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
        phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
+       phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
 
        /* Deassert Standby */
-       phy_write_reg(chan, 0x67, 0xf, 0x00000400);
+       phy_write_reg(chan, 0x67, 0x1, 0x00000400);
+
+       /* Disable clock */
+       clk_disable(&port->phy_clk);
 
        while (timeout--) {
                if (pci_read_reg(chan, SH4A_PCIEPHYSR))
@@ -201,22 +283,33 @@ static int phy_init(struct pci_channel *chan)
        return -ETIMEDOUT;
 }
 
-static int pcie_init(struct sh7786_pcie_port *port)
+static void __init pcie_reset(struct sh7786_pcie_port *port)
+{
+       struct pci_channel *chan = port->hose;
+
+       pci_write_reg(chan, 1, SH4A_PCIESRSTR);
+       pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+       pci_write_reg(chan, 0, SH4A_PCIESRSTR);
+       pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
+}
+
+static int __init pcie_init(struct sh7786_pcie_port *port)
 {
        struct pci_channel *chan = port->hose;
        unsigned int data;
        phys_addr_t memphys;
        size_t memsize;
-       int ret, i;
+       int ret, i, win;
 
        /* Begin initialization */
-       pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+       pcie_reset(port);
 
-       /* Initialize as type1. */
-       data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
-       data &= ~(0x7f << 16);
-       data |= PCI_HEADER_TYPE_BRIDGE << 16;
-       pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+       /*
+        * Initial header for port config space is type 1, set the device
+        * class to match. Hardware takes care of propagating the IDSETR
+        * settings, so there is no need to bother with a quirk.
+        */
+       pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
 
        /* Initialize default capabilities. */
        data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
@@ -268,30 +361,33 @@ static int pcie_init(struct sh7786_pcie_port *port)
         * LAR1/LAMR1.
         */
        if (memsize > SZ_512M) {
-               __raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1);
-               __raw_writel(((memsize - SZ_512M) - SZ_256) | 1,
-                            chan->reg_base + SH4A_PCIELAMR1);
+               pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
+               pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
+                             SH4A_PCIELAMR1);
                memsize = SZ_512M;
        } else {
                /*
                 * Otherwise just zero it out and disable it.
                 */
-               __raw_writel(0, chan->reg_base + SH4A_PCIELAR1);
-               __raw_writel(0, chan->reg_base + SH4A_PCIELAMR1);
+               pci_write_reg(chan, 0, SH4A_PCIELAR1);
+               pci_write_reg(chan, 0, SH4A_PCIELAMR1);
        }
 
        /*
         * LAR0/LAMR0 covers up to the first 512MB, which is enough to
         * cover all of lowmem on most platforms.
         */
-       __raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0);
-       __raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0);
+       pci_write_reg(chan, memphys, SH4A_PCIELAR0);
+       pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
 
        /* Finish initialization */
        data = pci_read_reg(chan, SH4A_PCIETCTLR);
        data |= 0x1;
        pci_write_reg(chan, data, SH4A_PCIETCTLR);
 
+       /* Let things settle down a bit.. */
+       mdelay(100);
+
        /* Enable DL_Active Interrupt generation */
        data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
        data |= PCIEDLINTENR_DLL_ACT_ENABLE;
@@ -302,9 +398,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
        data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
        pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
 
+       /*
+        * This will timeout if we don't have a link, but we permit the
+        * port to register anyways in order to support hotplug on future
+        * hardware.
+        */
        ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
-       if (unlikely(ret != 0))
-               return -ENODEV;
 
        data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
        data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
@@ -317,35 +416,48 @@ static int pcie_init(struct sh7786_pcie_port *port)
 
        wmb();
 
-       data = pci_read_reg(chan, SH4A_PCIEMACSR);
-       printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
-              port->index, (data >> 20) & 0x3f);
-
+       if (ret == 0) {
+               data = pci_read_reg(chan, SH4A_PCIEMACSR);
+               printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
+                      port->index, (data >> 20) & 0x3f);
+       } else
+               printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
+                      port->index);
 
-       for (i = 0; i < chan->nr_resources; i++) {
+       for (i = win = 0; i < chan->nr_resources; i++) {
                struct resource *res = chan->resources + i;
                resource_size_t size;
-               u32 enable_mask;
+               u32 mask;
 
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i));
+               /*
+                * We can't use the 32-bit mode windows in legacy 29-bit
+                * mode, so just skip them entirely.
+                */
+               if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
+                       continue;
 
-               size = resource_size(res);
+               pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
 
                /*
                 * The PAMR mask is calculated in units of 256kB, which
                 * keeps things pretty simple.
                 */
-               __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
-                            chan->reg_base + SH4A_PCIEPAMR(i));
+               size = resource_size(res);
+               mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
+               pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
 
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i));
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i));
+               pci_write_reg(chan, upper_32_bits(res->start),
+                             SH4A_PCIEPARH(win));
+               pci_write_reg(chan, lower_32_bits(res->start),
+                             SH4A_PCIEPARL(win));
 
-               enable_mask = MASK_PARE;
+               mask = MASK_PARE;
                if (res->flags & IORESOURCE_IO)
-                       enable_mask |= MASK_SPC;
+                       mask |= MASK_SPC;
+
+               pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
 
-               pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i));
+               win++;
        }
 
        return 0;
@@ -356,26 +468,33 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
         return 71;
 }
 
-static int sh7786_pcie_core_init(void)
+static int __init sh7786_pcie_core_init(void)
 {
        /* Return the number of ports */
        return test_mode_pin(MODE_PIN12) ? 3 : 2;
 }
 
-static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
+static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
 {
        int ret;
 
-       ret = phy_init(port->hose);
-       if (unlikely(ret < 0))
-               return ret;
-
        /*
         * Check if we are configured in endpoint or root complex mode,
         * this is a fixed pin setting that applies to all PCIe ports.
         */
        port->endpoint = test_mode_pin(MODE_PIN11);
 
+       /*
+        * Setup clocks, needed both for PHY and PCIe registers.
+        */
+       ret = pcie_clk_init(port);
+       if (unlikely(ret < 0))
+               return ret;
+
+       ret = phy_init(port);
+       if (unlikely(ret < 0))
+               return ret;
+
        ret = pcie_init(port);
        if (unlikely(ret < 0))
                return ret;
@@ -390,9 +509,10 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
 
 static int __init sh7786_pcie_init(void)
 {
+       struct clk *platclk;
        int ret = 0, i;
 
-       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+       printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
        sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
 
@@ -407,6 +527,22 @@ static int __init sh7786_pcie_init(void)
        if (unlikely(!sh7786_pcie_ports))
                return -ENOMEM;
 
+       /*
+        * Fetch any optional platform clock associated with this block.
+        *
+        * This is a rather nasty hack for boards with spec-mocking FPGAs
+        * that have a secondary set of clocks outside of the on-chip
+        * ones that need to be accounted for before there is any chance
+        * of touching the existing MSTP bits or CPG clocks.
+        */
+       platclk = clk_get(NULL, "pcie_plat_clk");
+       if (IS_ERR(platclk)) {
+               /* Sane hardware should probably get a WARN_ON.. */
+               platclk = NULL;
+       }
+
+       clk_enable(platclk);
+
        printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
 
        for (i = 0; i < nr_ports; i++) {
@@ -419,8 +555,11 @@ static int __init sh7786_pcie_init(void)
                ret |= sh7786_pcie_hwops->port_init_hw(port);
        }
 
-       if (unlikely(ret))
+       if (unlikely(ret)) {
+               clk_disable(platclk);
+               clk_put(platclk);
                return ret;
+       }
 
        return 0;
 }
index 90a6992576b0bb479828bd0d88acd711d9762128..1ee054e47eae5ffcf289bd03fa5b06ee74c73626 100644 (file)
 #define                BITS_ERRRCV     (0)             /* 0 ERRRCV 0 */
 #define                MASK_ERRRCV     (1<<BITS_ERRRCV)
 
+/*     PCIEENBLR        */
+#define        SH4A_PCIEENBLR          (0x000008)      /* R/W - 0x0000 0001 32 */
+
 /*     PCIEECR         */
-#define        SH4A_PCIEECR            (0x000008)      /* R/W - 0x0000 0000 32 */
+#define        SH4A_PCIEECR            (0x00000C)      /* R/W - 0x0000 0000 32 */
 #define                BITS_ENBL       (0)     /* 0 ENBL 0 R/W */
 #define                MASK_ENBL       (1<<BITS_ENBL)
 
 #define                BITS_MDATA      (0)
 #define                MASK_MDATA      (0xffffffff<<BITS_MDATA)
 
+/*     PCIEUNLOCKCR    */
+#define        SH4A_PCIEUNLOCKCR       (0x000048)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIEIDR         */
+#define        SH4A_PCIEIDR            (0x000060)      /* R/W - 0x0101 1101 32 */
+
+/*     PCIEDBGCTLR     */
+#define        SH4A_PCIEDBGCTLR        (0x000100)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIEINTXR       */
+#define        SH4A_PCIEINTXR          (0x004000)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIERMSGR       */
+#define        SH4A_PCIERMSGR          (0x004010)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIERSTR        */
+#define SH4A_PCIERSTR(x)       (0x008000 + ((x) * 0x4)) /* R/W - 0x0000 0000 32 */
+
+/*     PCIESRSTR        */
+#define SH4A_PCIESRSTR         (0x008040)      /* R/W - 0x0000 0000 32 */
+
 /*     PCIEPHYCTLR     */
 #define        SH4A_PCIEPHYCTLR        (0x010000)      /* R/W - 0x0000 0000 32 */
 #define                BITS_CKE        (0)
 /*     PCIERMSGIER     */
 #define        SH4A_PCIERMSGIER        (0x004040)      /* R/W - 0x0000 0000 32 */
 
+/*     PCIEPHYCTLR     */
+#define SH4A_PCIEPHYCTLR       (0x010000)      /* R/W - 0x0000 0000 32 */
+
 /*     PCIEPHYADRR     */
 #define        SH4A_PCIEPHYADRR        (0x010004)      /* R/W - 0x0000 0000 32 */
 #define                BITS_ACK        (24)                    // Rev1.171
 #define                MASK_CFINT      (1<<BITS_CFINT)
 
 /*     PCIETSTR        */
-#define        SH4A_PCIETSTR           (0x020004)      /* R/W R/W 0x0000 0000 32  */
+#define        SH4A_PCIETSTR           (0x020004)      /* R 0x0000 0000 32  */
 
 /*     PCIEINTR        */
 #define        SH4A_PCIEINTR           (0x020008)      /* R/W R/W 0x0000 0000 32  */
 #define                BITS_INTPM                      (8)
 #define                MASK_INTPM                      (1<<BITS_INTPM)
 
+/*     PCIEEH0R        */
+#define SH4A_PCIEEHR(x)                (0x020010 + ((x) * 0x4)) /* R - 0x0000 0000 32 */
+
 /*     PCIEAIR  */
 #define        SH4A_PCIEAIR            (SH4A_PCIE_BASE + 0x020010)     /* R/W R/W 0xxxxx xxxx 32 */
 
 
 /*      PCIEERRFR       */                                                             // Rev1.18
 #define        SH4A_PCIEERRFR          (0x020020)              /* R/W R/W 0xxxxx xxxx 32 */    // Rev1.18
+
+/*     PCIEERRFER      */
+#define SH4A_PCIEERRFER                (0x020024)              /* R/W R/W 0x0000 0000 32 */
+
+/*     PCIEERRFR2      */
+#define SH4A_PCIEERRFR2                (0x020028)              /* R/W R/W 0x0000 0000 32 */
+
+/*     PCIEMSIR        */
+#define SH4A_PCIEMSIR          (0x020040)              /* R/W - 0x0000 0000 32 */
+
+/*     PCIEMSIFR       */
+#define SH4A_PCIEMSIFR         (0x020044)              /* R/W R/W 0x0000 0000 32 */
+
+/*     PCIEPWRCTLR     */
+#define SH4A_PCIEPWRCTLR       (0x020100)              /* R/W - 0x0000 0000 32 */
+
+/*     PCIEPCCTLR      */
+#define SH4A_PCIEPCCTLR                (0x020180)              /* R/W - 0x0000 0000 32 */
+
                                                                                        // Rev1.18
 /*     PCIELAR0        */
 #define        SH4A_PCIELAR0           (0x020200)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCCR0         (0x021120)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCC2R0        (0x021124)      /* R/W R/W 0x0000 0000 - */
 #define        SH4A_PCIEDMCCCR0        (0x021128)      /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR0       (0x02112C)      /* R/W - 0x0000 0000 32 */
 #define        SH4A_PCIEDMSAR1         (0x021140)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMSAHR1        (0x021144)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMDAR1         (0x021148)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCCR1         (0x021160)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCC2R1        (0x021164)      /* R/W R/W 0x0000 0000 - */
 #define        SH4A_PCIEDMCCCR1        (0x021168)      /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR1       (0x02116C)      /* R/W - 0x0000 0000 32 */
 #define        SH4A_PCIEDMSAR2         (0x021180)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMSAHR2        (0x021184)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMDAR2         (0x021188)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCCR3         (0x0211E0)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEDMCC2R3        (0x0211E4)      /* R/W R/W 0x0000 0000 -  */
 #define        SH4A_PCIEDMCCCR3        (0x0211E8)      /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR3       (0x0211EC)      /* R/W R/W 0x0000 0000 32 */
 #define        SH4A_PCIEPCICONF0       (0x040000)      /* R R - 8/16/32 */
 #define        SH4A_PCIEPCICONF1       (0x040004)      /* R/W R/W 0x0008 0000 8/16/32 */
 #define        SH4A_PCIEPCICONF2       (0x040008)      /* R/W R/W 0xFF00 0000 8/16/32 */
index 0eed47b236abfc09c79e19254424fcaf36f26856..7beb42322f60059368590c80439617a6be614460 100644 (file)
@@ -5,5 +5,7 @@ header-y += cpu-features.h
 header-y += hw_breakpoint.h
 header-y += posix_types_32.h
 header-y += posix_types_64.h
+header-y += ptrace_32.h
+header-y += ptrace_64.h
 header-y += unistd_32.h
 header-y += unistd_64.h
index ce830faeebbf50705e1ba1126b240ea274bbd77c..f38112be67d29555eb76042c57598e34c2b2e8a4 100644 (file)
 #define        R_SH_GOTPC              167
 
 /* FDPIC relocs */
-#define R_SH_GOT20             70
-#define R_SH_GOTOFF20          71
-#define R_SH_GOTFUNCDESC       72
-#define R_SH_GOTFUNCDESC20     73
-#define R_SH_GOTOFFFUNCDESC    74
-#define R_SH_GOTOFFFUNCDESC20  75
-#define R_SH_FUNCDESC          76
-#define R_SH_FUNCDESC_VALUE    77
-
-#if 0 /* XXX - later .. */
-#define R_SH_GOT20             198
-#define R_SH_GOTOFF20          199
-#define R_SH_GOTFUNCDESC       200
-#define R_SH_GOTFUNCDESC20     201
-#define R_SH_GOTOFFFUNCDESC    202
-#define R_SH_GOTOFFFUNCDESC20  203
-#define R_SH_FUNCDESC          204
-#define R_SH_FUNCDESC_VALUE    205
-#endif
+#define R_SH_GOT20             201
+#define R_SH_GOTOFF20          202
+#define R_SH_GOTFUNCDESC       203
+#define R_SH_GOTFUNCDESC20     204
+#define R_SH_GOTOFFFUNCDESC    205
+#define R_SH_GOTOFFFUNCDESC20  206
+#define R_SH_FUNCDESC          207
+#define R_SH_FUNCDESC_VALUE    208
 
 /* SHmedia relocs */
 #define R_SH_IMM_LOW16         246
index 6e7cea453895a7bcd020a1c70e8d95f8cd218796..bd7e79a1265345691caf54cc4e1d21198e7e0adf 100644 (file)
@@ -58,7 +58,7 @@ enum fixed_addresses {
 
 #ifdef CONFIG_HIGHMEM
        FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
-       FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+       FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
 #endif
 
 #ifdef CONFIG_IOREMAP_FIXED
@@ -69,7 +69,7 @@ enum fixed_addresses {
         */
 #define FIX_N_IOREMAPS 32
        FIX_IOREMAP_BEGIN,
-       FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
+       FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
 #endif
 
        __end_of_fixed_addresses
index f8d9a731e9033f9561dc088bc00b1d32cbb5bdf7..04f53d31489f2cc142f804bd444593305db27c01 100644 (file)
@@ -41,14 +41,12 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       WARN_ON(1);
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-       WARN_ON(1);
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
diff --git a/arch/sh/include/asm/ilsel.h b/arch/sh/include/asm/ilsel.h
deleted file mode 100644 (file)
index e3d304b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __ASM_SH_ILSEL_H
-#define __ASM_SH_ILSEL_H
-
-typedef enum {
-       ILSEL_NONE,
-       ILSEL_LAN,
-       ILSEL_USBH_I,
-       ILSEL_USBH_S,
-       ILSEL_USBH_V,
-       ILSEL_RTC,
-       ILSEL_USBP_I,
-       ILSEL_USBP_S,
-       ILSEL_USBP_V,
-       ILSEL_KEY,
-
-       /*
-        * ILSEL Aliases - corner cases for interleaved level tables.
-        *
-        * Someone thought this was a good idea and less hassle than
-        * demuxing a shared vector, really.
-        */
-
-       /* ILSEL0 and 2 */
-       ILSEL_FPGA0,
-       ILSEL_FPGA1,
-       ILSEL_EX1,
-       ILSEL_EX2,
-       ILSEL_EX3,
-       ILSEL_EX4,
-
-       /* ILSEL1 and 3 */
-       ILSEL_FPGA2 = ILSEL_FPGA0,
-       ILSEL_FPGA3 = ILSEL_FPGA1,
-       ILSEL_EX5 = ILSEL_EX1,
-       ILSEL_EX6 = ILSEL_EX2,
-       ILSEL_EX7 = ILSEL_EX3,
-       ILSEL_EX8 = ILSEL_EX4,
-} ilsel_source_t;
-
-/* arch/sh/boards/renesas/x3proto/ilsel.c */
-int ilsel_enable(ilsel_source_t set);
-int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
-void ilsel_disable(unsigned int irq);
-
-#endif /* __ASM_SH_ILSEL_H */
index 02c2f0102cfaf8305d4510cd7ce591a8ec734b3d..45d08b6a5ef71de204578bb0569f4fba3c836cbd 100644 (file)
@@ -9,7 +9,7 @@
  * advised to cap this at the hard limit that they're interested in
  * through the machvec.
  */
-#define NR_IRQS                        256
+#define NR_IRQS                        512
 #define NR_IRQS_LEGACY         8       /* Legacy external IRQ0-7 */
 
 /*
index 036c3311233cd088d1349c2f9dd1699692153026..134f3980e44a60ab9caf41796ad031f6bc966748 100644 (file)
@@ -16,7 +16,6 @@ typedef insn_size_t kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define regs_return_value(_regs)               ((_regs)->regs[0])
 #define flush_insn_slot(p)             do { } while (0)
 #define kretprobe_blacklist_size       0
 
index 8bd952fcf3ba6cbc0ee826d306c5f9b209aee178..f0efe97f17506394f03255d30784bd061c8913ac 100644 (file)
@@ -37,6 +37,8 @@ struct pci_channel {
 };
 
 /* arch/sh/drivers/pci/pci.c */
+extern raw_spinlock_t pci_config_lock;
+
 extern int register_pci_controller(struct pci_channel *hose);
 extern void pcibios_report_status(unsigned int status_mask, int warn);
 
index e172d696e52bbfaa9e21e6017f343cea7e32d3fd..69fdfbf14ea5b00e5dc8ed29cd65b30333a1ee82 100644 (file)
@@ -429,10 +429,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_offset_kernel(dir, address) \
        ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address)           pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address)    pte_offset_kernel(dir, address)
-
 #define pte_unmap(pte)         do { } while (0)
-#define pte_unmap_nested(pte)  do { } while (0)
 
 #ifdef CONFIG_X2TLB
 #define pte_ERROR(e) \
index 0ee46776dad6d9c7032a45856710e357d9fb90d1..10a48111226dbd319315105ed48709d6b3189721 100644 (file)
@@ -84,9 +84,7 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
                ((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
 
 #define pte_offset_map(dir,addr)       pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr)        pte_offset_kernel(dir, addr)
 #define pte_unmap(pte)         do { } while (0)
-#define pte_unmap_nested(pte)  do { } while (0)
 
 #ifndef __ASSEMBLY__
 #define IOBASE_VADDR   0xff000000
index 61a445d2d02a84fed1ac5bf1b4effa5d4ddee924..46d5179c9f4902fef3b797a8772e6a65652c7aeb 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/page.h>
 #include <asm/types.h>
-#include <asm/ptrace.h>
 #include <asm/hw_breakpoint.h>
 
 /*
@@ -194,8 +193,6 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
 
-#define user_stack_pointer(_regs)      ((_regs)->regs[15])
-
 #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
 #define PREFETCH_STRIDE                L1_CACHE_BYTES
 #define ARCH_HAS_PREFETCH
index 621bc4618c6b2ed168dfb4c90d911bc2c6d423f7..2a541ddb5a1b2f907a00b6e4764a6f2ecc3bfafa 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/compiler.h>
 #include <asm/page.h>
 #include <asm/types.h>
-#include <asm/ptrace.h>
 #include <cpu/registers.h>
 
 /*
@@ -231,7 +230,5 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
 
-#define user_stack_pointer(_regs)      ((_regs)->regs[15])
-
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SH_PROCESSOR_64_H */
index 2168fde25611787e48401f8cd3769518b7b7f3b5..f6edc10aa0d338e2041de62d4359f03c85662596 100644 (file)
@@ -3,90 +3,7 @@
 
 /*
  * Copyright (C) 1999, 2000  Niibe Yutaka
- *
- */
-#if defined(__SH5__)
-struct pt_regs {
-       unsigned long long pc;
-       unsigned long long sr;
-       long long syscall_nr;
-       unsigned long long regs[63];
-       unsigned long long tregs[8];
-       unsigned long long pad[2];
-};
-#else
-/*
- * GCC defines register number like this:
- * -----------------------------
- *      0 - 15 are integer registers
- *     17 - 22 are control/special registers
- *     24 - 39 fp registers
- *     40 - 47 xd registers
- *     48 -    fpscr register
- * -----------------------------
- *
- * We follows above, except:
- *     16 --- program counter (PC)
- *     22 --- syscall #
- *     23 --- floating point communication register
  */
-#define REG_REG0        0
-#define REG_REG15      15
-
-#define REG_PC         16
-
-#define REG_PR         17
-#define REG_SR         18
-#define REG_GBR                19
-#define REG_MACH       20
-#define REG_MACL       21
-
-#define REG_SYSCALL    22
-
-#define REG_FPREG0     23
-#define REG_FPREG15    38
-#define REG_XFREG0     39
-#define REG_XFREG15    54
-
-#define REG_FPSCR      55
-#define REG_FPUL       56
-
-/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_regs {
-       unsigned long regs[16];
-       unsigned long pc;
-       unsigned long pr;
-       unsigned long sr;
-       unsigned long gbr;
-       unsigned long mach;
-       unsigned long macl;
-       long tra;
-};
-
-/*
- * This struct defines the way the DSP registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_dspregs {
-       unsigned long   a1;
-       unsigned long   a0g;
-       unsigned long   a1g;
-       unsigned long   m0;
-       unsigned long   m1;
-       unsigned long   a0;
-       unsigned long   x0;
-       unsigned long   x1;
-       unsigned long   y0;
-       unsigned long   y1;
-       unsigned long   dsr;
-       unsigned long   rs;
-       unsigned long   re;
-       unsigned long   mod;
-};
-#endif
 
 #define PTRACE_GETREGS         12      /* General registers */
 #define PTRACE_SETREGS         13
@@ -107,22 +24,102 @@ struct pt_dspregs {
 #define PT_DATA_ADDR           248     /* &(struct user)->start_data */
 #define PT_TEXT_LEN            252
 
+#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
+#include "ptrace_64.h"
+#else
+#include "ptrace_32.h"
+#endif
+
 #ifdef __KERNEL__
+
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
 #include <asm/addrspace.h>
 #include <asm/page.h>
 #include <asm/system.h>
 
 #define user_mode(regs)                        (((regs)->sr & 0x40000000)==0)
+#define user_stack_pointer(regs)       ((unsigned long)(regs)->regs[15])
+#define kernel_stack_pointer(regs)     ((unsigned long)(regs)->regs[15])
 #define instruction_pointer(regs)      ((unsigned long)(regs)->pc)
 
 extern void show_regs(struct pt_regs *);
 
+#define arch_has_single_step() (1)
+
 /*
- * These are defined as per linux/ptrace.h.
+ * kprobe-based event tracer support
  */
-struct task_struct;
+struct pt_regs_offset {
+       const char *name;
+       int offset;
+};
 
-#define arch_has_single_step() (1)
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REGS_OFFSET_NAME(num)  \
+       {.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])}
+#define TREGS_OFFSET_NAME(num) \
+       {.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+
+extern const struct pt_regs_offset regoffset_table[];
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:      pt_regs from which register value is gotten.
+ * @offset:    offset number of the register.
+ *
+ * regs_get_register returns the value of a register. The @offset is the
+ * offset of the register in struct pt_regs address which specified by @regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+                                             unsigned int offset)
+{
+       if (unlikely(offset > MAX_REG_OFFSET))
+               return 0;
+       return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static inline int regs_within_kernel_stack(struct pt_regs *regs,
+                                          unsigned long addr)
+{
+       return ((addr & ~(THREAD_SIZE - 1))  ==
+               (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @n:         stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+                                                     unsigned int n)
+{
+       unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+       addr += n;
+       if (regs_within_kernel_stack(regs, (unsigned long)addr))
+               return *addr;
+       else
+               return 0;
+}
 
 struct perf_event;
 struct perf_sample_data;
diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h
new file mode 100644 (file)
index 0000000..35d9e25
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __ASM_SH_PTRACE_32_H
+#define __ASM_SH_PTRACE_32_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ *      0 - 15 are integer registers
+ *     17 - 22 are control/special registers
+ *     24 - 39 fp registers
+ *     40 - 47 xd registers
+ *     48 -    fpscr register
+ * -----------------------------
+ *
+ * We follows above, except:
+ *     16 --- program counter (PC)
+ *     22 --- syscall #
+ *     23 --- floating point communication register
+ */
+#define REG_REG0        0
+#define REG_REG15      15
+
+#define REG_PC         16
+
+#define REG_PR         17
+#define REG_SR         18
+#define REG_GBR                19
+#define REG_MACH       20
+#define REG_MACL       21
+
+#define REG_SYSCALL    22
+
+#define REG_FPREG0     23
+#define REG_FPREG15    38
+#define REG_XFREG0     39
+#define REG_XFREG15    54
+
+#define REG_FPSCR      55
+#define REG_FPUL       56
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+       unsigned long regs[16];
+       unsigned long pc;
+       unsigned long pr;
+       unsigned long sr;
+       unsigned long gbr;
+       unsigned long mach;
+       unsigned long macl;
+       long tra;
+};
+
+/*
+ * This struct defines the way the DSP registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_dspregs {
+       unsigned long   a1;
+       unsigned long   a0g;
+       unsigned long   a1g;
+       unsigned long   m0;
+       unsigned long   m1;
+       unsigned long   a0;
+       unsigned long   x0;
+       unsigned long   x1;
+       unsigned long   y0;
+       unsigned long   y1;
+       unsigned long   dsr;
+       unsigned long   rs;
+       unsigned long   re;
+       unsigned long   mod;
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET         offsetof(struct pt_regs, tra)
+#define regs_return_value(regs)        ((regs)->regs[0])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_32_H */
diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h
new file mode 100644 (file)
index 0000000..d43c1cb
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __ASM_SH_PTRACE_64_H
+#define __ASM_SH_PTRACE_64_H
+
+struct pt_regs {
+       unsigned long long pc;
+       unsigned long long sr;
+       long long syscall_nr;
+       unsigned long long regs[63];
+       unsigned long long tregs[8];
+       unsigned long long pad[2];
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET         offsetof(struct pt_regs, tregs[7])
+#define regs_return_value(regs)        ((regs)->regs[3])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_64_H */
index 3a1fb97770f1f507b3f0d58cba278d2860b9bb7a..0b9fe2d5c36d9d4ac05621d50b8e6725ce6f3d13 100644 (file)
@@ -32,6 +32,7 @@
 #define SZ_512                         0x00000200
 
 #define SZ_1K                           0x00000400
+#define SZ_2K                           0x00000800
 #define SZ_4K                           0x00001000
 #define SZ_8K                           0x00002000
 #define SZ_16K                          0x00004000
diff --git a/arch/sh/include/asm/sram.h b/arch/sh/include/asm/sram.h
new file mode 100644 (file)
index 0000000..a2808ce
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __ASM_SRAM_H
+#define __ASM_SRAM_H
+
+#ifdef CONFIG_HAVE_SRAM_POOL
+
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+/* arch/sh/mm/sram.c */
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+       if (!sram_pool)
+               return 0UL;
+
+       return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+       return gen_pool_free(sram_pool, addr, len);
+}
+
+#else
+
+static inline unsigned long sram_alloc(size_t len)
+{
+       return 0;
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+}
+
+#endif /* CONFIG_HAVE_SRAM_POOL */
+
+#endif /* __ASM_SRAM_H */
index 0bd7a17d5e1a0162a7968a8c11ee18d99b493a9d..1f1af5afff0374537f989911d4e98f51078a9c1e 100644 (file)
@@ -140,8 +140,6 @@ extern unsigned int instruction_size(unsigned int insn);
 extern unsigned long cached_to_uncached;
 extern unsigned long uncached_size;
 
-extern struct dentry *sh_debugfs_root;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
index 51296b36770e3b1be77acefedd2476f2fd8206f3..c941b273940581bc4221458a8cabf639829e1500 100644 (file)
@@ -212,17 +212,16 @@ static inline reg_size_t register_align(void *val)
 }
 
 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
-                           struct mem_access *ma, int);
+                           struct mem_access *ma, int, unsigned long address);
 
 static inline void trigger_address_error(void)
 {
-       if (__in_29bit_mode())
-               __asm__ __volatile__ (
-                       "ldc %0, sr\n\t"
-                       "mov.l @%1, %0"
-                       :
-                       : "r" (0x10000000), "r" (0x80000001)
-               );
+       __asm__ __volatile__ (
+               "ldc %0, sr\n\t"
+               "mov.l @%1, %0"
+               :
+               : "r" (0x10000000), "r" (0x80000001)
+       );
 }
 
 asmlinkage void do_address_error(struct pt_regs *regs,
index e0ac97221ae6bb6a6351331ce72b884fc229ecd1..0df66f0c72847c37a9598f33126237a442ec4366 100644 (file)
@@ -21,6 +21,8 @@ extern void local_flush_tlb_kernel_range(unsigned long start,
                                         unsigned long end);
 extern void local_flush_tlb_one(unsigned long asid, unsigned long page);
 
+extern void __flush_tlb_global(void);
+
 #ifdef CONFIG_SMP
 
 extern void flush_tlb_all(void);
index 0e7f0fc8f0864f11b7108d36674b90ad5c508b74..903cd618eb740606853662d23765a694044e586c 100644 (file)
 #define __NR_pwritev           334
 #define __NR_rt_tgsigqueueinfo 335
 #define __NR_perf_event_open   336
+#define __NR_fanotify_init     337
+#define __NR_fanotify_mark     338
+#define __NR_prlimit64         339
 
-#define NR_syscalls 337
+/* Non-multiplexed socket family */
+#define __NR_socket            340
+#define __NR_bind              341
+#define __NR_connect           342
+#define __NR_listen            343
+#define __NR_accept            344
+#define __NR_getsockname       345
+#define __NR_getpeername       346
+#define __NR_socketpair                347
+#define __NR_send              348
+#define __NR_sendto            349
+#define __NR_recv              350
+#define __NR_recvfrom          351
+#define __NR_shutdown          352
+#define __NR_setsockopt                353
+#define __NR_getsockopt                354
+#define __NR_sendmsg           355
+#define __NR_recvmsg           356
+#define __NR_recvmmsg          357
 
-#ifdef __KERNEL__
+#define NR_syscalls 358
 
-#define __IGNORE_recvmmsg
+#ifdef __KERNEL__
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 0580c33a1e04725811ebcc2cfe13caa1a3a11362..09aa93f9eb70d8bc62432a395bec21623f8628c8 100644 (file)
 #define __NR_perf_event_open   364
 #define __NR_recvmmsg          365
 #define __NR_accept4           366
+#define __NR_fanotify_init     367
+#define __NR_fanotify_mark     368
+#define __NR_prlimit64         369
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 367
+#define NR_syscalls 370
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index ab09da73ce770b5601c4a4c85a02235491450f88..0c7c735ea82ad4fdeb186ccb72b373493f82c3e2 100644 (file)
@@ -16,6 +16,7 @@
 #define MMU_TEA                0xFFFFFFFC      /* TLB Exception Address */
 
 #define MMUCR          0xFFFFFFE0      /* MMU Control Register */
+#define MMUCR_TI       (1 << 2)        /* TLB flush bit */
 
 #define MMU_TLB_ADDRESS_ARRAY  0xF2000000
 #define MMU_PAGE_ASSOC_BIT     0x80
index e1e90960ee9a41ee73032f1167cb85f8b6dfa83a..cffd25ed02400fb472fe8e56bcc5067ae373d7f0 100644 (file)
@@ -56,7 +56,9 @@
 #define FRQCR1                 0xffc40004
 #define FRQMR1                 0xffc40014
 #elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define FRQCR                  0xffc00014
+#define FRQCR0                 0xffc00000
+#define FRQCR1                 0xffc00004
+#define FRQMR1                 0xffc00014
 #else
 #define FRQCR                  0xffc00000
 #define FRQCR_PSTBY            0x0200
index f4d267efad712186793cf3735eaebd8fe2f55df8..15f3de11c55a973e3b6e8d2f8586455f225e14ff 100644 (file)
 
 enum {
        /* PTA */
-       GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
-       GPIO_PTA3, GPIO_PTA2, GPIO_PTA1, GPIO_PTA0,
+       GPIO_PTA0, GPIO_PTA1, GPIO_PTA2, GPIO_PTA3,
+       GPIO_PTA4, GPIO_PTA5, GPIO_PTA6, GPIO_PTA7,
 
        /* PTB */
-       GPIO_PTB7, GPIO_PTB6, GPIO_PTB5, GPIO_PTB4,
-       GPIO_PTB3, GPIO_PTB2, GPIO_PTB1, GPIO_PTB0,
+       GPIO_PTB0, GPIO_PTB1, GPIO_PTB2, GPIO_PTB3,
+       GPIO_PTB4, GPIO_PTB5, GPIO_PTB6, GPIO_PTB7,
 
        /* PTC */
-       GPIO_PTC7, GPIO_PTC6, GPIO_PTC5, GPIO_PTC4,
-       GPIO_PTC3, GPIO_PTC2, GPIO_PTC1, GPIO_PTC0,
+       GPIO_PTC0, GPIO_PTC1, GPIO_PTC2, GPIO_PTC3,
+       GPIO_PTC4, GPIO_PTC5, GPIO_PTC6, GPIO_PTC7,
 
        /* PTD */
-       GPIO_PTD7, GPIO_PTD6, GPIO_PTD5, GPIO_PTD4,
-       GPIO_PTD3, GPIO_PTD2, GPIO_PTD1, GPIO_PTD0,
+       GPIO_PTD0, GPIO_PTD1, GPIO_PTD2, GPIO_PTD3,
+       GPIO_PTD4, GPIO_PTD5, GPIO_PTD6, GPIO_PTD7,
 
        /* PTE */
-       GPIO_PTE7, GPIO_PTE6, GPIO_PTE5, GPIO_PTE4,
-       GPIO_PTE3, GPIO_PTE2, GPIO_PTE1, GPIO_PTE0,
+       GPIO_PTE0, GPIO_PTE1, GPIO_PTE2, GPIO_PTE3,
+       GPIO_PTE4, GPIO_PTE5, GPIO_PTE6, GPIO_PTE7,
 
        /* PTF */
-       GPIO_PTF7, GPIO_PTF6, GPIO_PTF5, GPIO_PTF4,
-       GPIO_PTF3, GPIO_PTF2, GPIO_PTF1, GPIO_PTF0,
+       GPIO_PTF0, GPIO_PTF1, GPIO_PTF2, GPIO_PTF3,
+       GPIO_PTF4, GPIO_PTF5, GPIO_PTF6, GPIO_PTF7,
 
        /* PTG */
-       GPIO_PTG7, GPIO_PTG6, GPIO_PTG5, GPIO_PTG4,
-       GPIO_PTG3, GPIO_PTG2, GPIO_PTG1, GPIO_PTG0,
+       GPIO_PTG0, GPIO_PTG1, GPIO_PTG2, GPIO_PTG3,
+       GPIO_PTG4, GPIO_PTG5, GPIO_PTG6, GPIO_PTG7,
 
        /* PTH */
-       GPIO_PTH7, GPIO_PTH6, GPIO_PTH5, GPIO_PTH4,
-       GPIO_PTH3, GPIO_PTH2, GPIO_PTH1, GPIO_PTH0,
+       GPIO_PTH0, GPIO_PTH1, GPIO_PTH2, GPIO_PTH3,
+       GPIO_PTH4, GPIO_PTH5, GPIO_PTH6, GPIO_PTH7,
 
        /* PTI */
-       GPIO_PTI7, GPIO_PTI6, GPIO_PTI5, GPIO_PTI4,
-       GPIO_PTI3, GPIO_PTI2, GPIO_PTI1, GPIO_PTI0,
+       GPIO_PTI0, GPIO_PTI1, GPIO_PTI2, GPIO_PTI3,
+       GPIO_PTI4, GPIO_PTI5, GPIO_PTI6, GPIO_PTI7,
 
        /* PTJ */
-       GPIO_PTJ7, GPIO_PTJ6, GPIO_PTJ5, GPIO_PTJ4,
-       GPIO_PTJ3, GPIO_PTJ2, GPIO_PTJ1, GPIO_PTJ0,
+       GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
+       GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
 
        /* PTK */
-       GPIO_PTK7, GPIO_PTK6, GPIO_PTK5, GPIO_PTK4,
-       GPIO_PTK3, GPIO_PTK2, GPIO_PTK1, GPIO_PTK0,
+       GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
+       GPIO_PTK4, GPIO_PTK5, GPIO_PTK6, GPIO_PTK7,
 
        /* PTL */
-       GPIO_PTL7, GPIO_PTL6, GPIO_PTL5, GPIO_PTL4,
-       GPIO_PTL3, GPIO_PTL2, GPIO_PTL1, GPIO_PTL0,
+       GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
+       GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
 
        /* PTM */
-                  GPIO_PTM6, GPIO_PTM5, GPIO_PTM4,
-       GPIO_PTM3, GPIO_PTM2, GPIO_PTM1, GPIO_PTM0,
+       GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
+       GPIO_PTM4, GPIO_PTM5, GPIO_PTM6, GPIO_PTM7,
 
        /* PTN */
-       GPIO_PTN7, GPIO_PTN6, GPIO_PTN5, GPIO_PTN4,
-       GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
+       GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
+       GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
 
        /* PTO */
-       GPIO_PTO7, GPIO_PTO6, GPIO_PTO5, GPIO_PTO4,
-       GPIO_PTO3, GPIO_PTO2, GPIO_PTO1, GPIO_PTO0,
+       GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
+       GPIO_PTO4, GPIO_PTO5, GPIO_PTO6, GPIO_PTO7,
 
        /* PTP */
-                  GPIO_PTP6, GPIO_PTP5, GPIO_PTP4,
-       GPIO_PTP3, GPIO_PTP2, GPIO_PTP1, GPIO_PTP0,
+       GPIO_PTP0, GPIO_PTP1, GPIO_PTP2, GPIO_PTP3,
+       GPIO_PTP4, GPIO_PTP5, GPIO_PTP6, GPIO_PTP7,
 
        /* PTQ */
-                  GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
-       GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
+       GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
+       GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
 
        /* PTR */
-       GPIO_PTR7, GPIO_PTR6, GPIO_PTR5, GPIO_PTR4,
-       GPIO_PTR3, GPIO_PTR2, GPIO_PTR1, GPIO_PTR0,
+       GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
+       GPIO_PTR4, GPIO_PTR5, GPIO_PTR6, GPIO_PTR7,
 
        /* PTS */
-       GPIO_PTS7, GPIO_PTS6, GPIO_PTS5, GPIO_PTS4,
-       GPIO_PTS3, GPIO_PTS2, GPIO_PTS1, GPIO_PTS0,
+       GPIO_PTS0, GPIO_PTS1, GPIO_PTS2, GPIO_PTS3,
+       GPIO_PTS4, GPIO_PTS5, GPIO_PTS6, GPIO_PTS7,
 
        /* PTT */
-                             GPIO_PTT5, GPIO_PTT4,
-       GPIO_PTT3, GPIO_PTT2, GPIO_PTT1, GPIO_PTT0,
+       GPIO_PTT0, GPIO_PTT1, GPIO_PTT2, GPIO_PTT3,
+       GPIO_PTT4, GPIO_PTT5, GPIO_PTT6, GPIO_PTT7,
 
        /* PTU */
-       GPIO_PTU7, GPIO_PTU6, GPIO_PTU5, GPIO_PTU4,
-       GPIO_PTU3, GPIO_PTU2, GPIO_PTU1, GPIO_PTU0,
+       GPIO_PTU0, GPIO_PTU1, GPIO_PTU2, GPIO_PTU3,
+       GPIO_PTU4, GPIO_PTU5, GPIO_PTU6, GPIO_PTU7,
 
        /* PTV */
-       GPIO_PTV7, GPIO_PTV6, GPIO_PTV5, GPIO_PTV4,
-       GPIO_PTV3, GPIO_PTV2, GPIO_PTV1, GPIO_PTV0,
+       GPIO_PTV0, GPIO_PTV1, GPIO_PTV2, GPIO_PTV3,
+       GPIO_PTV4, GPIO_PTV5, GPIO_PTV6, GPIO_PTV7,
 
        /* PTW */
-       GPIO_PTW7, GPIO_PTW6, GPIO_PTW5, GPIO_PTW4,
-       GPIO_PTW3, GPIO_PTW2, GPIO_PTW1, GPIO_PTW0,
+       GPIO_PTW0, GPIO_PTW1, GPIO_PTW2, GPIO_PTW3,
+       GPIO_PTW4, GPIO_PTW5, GPIO_PTW6, GPIO_PTW7,
 
        /* PTX */
-       GPIO_PTX7, GPIO_PTX6, GPIO_PTX5, GPIO_PTX4,
-       GPIO_PTX3, GPIO_PTX2, GPIO_PTX1, GPIO_PTX0,
+       GPIO_PTX0, GPIO_PTX1, GPIO_PTX2, GPIO_PTX3,
+       GPIO_PTX4, GPIO_PTX5, GPIO_PTX6, GPIO_PTX7,
 
        /* PTY */
-       GPIO_PTY7, GPIO_PTY6, GPIO_PTY5, GPIO_PTY4,
-       GPIO_PTY3, GPIO_PTY2, GPIO_PTY1, GPIO_PTY0,
+       GPIO_PTY0, GPIO_PTY1, GPIO_PTY2, GPIO_PTY3,
+       GPIO_PTY4, GPIO_PTY5, GPIO_PTY6, GPIO_PTY7,
 
        /* PTZ */
-       GPIO_PTZ7, GPIO_PTZ6, GPIO_PTZ5, GPIO_PTZ4,
-       GPIO_PTZ3, GPIO_PTZ2, GPIO_PTZ1, GPIO_PTZ0,
+       GPIO_PTZ0, GPIO_PTZ1, GPIO_PTZ2, GPIO_PTZ3,
+       GPIO_PTZ4, GPIO_PTZ5, GPIO_PTZ6, GPIO_PTZ7,
 
 
-       /* PTA (mobule: LBSC, CPG, LPC) */
+       /* PTA (mobule: LBSC, RGMII) */
        GPIO_FN_BS,     GPIO_FN_RDWR,   GPIO_FN_WE1,    GPIO_FN_RDY,
-       GPIO_FN_MD10,   GPIO_FN_MD9,    GPIO_FN_MD8,
-       GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
-       GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
-
-       /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-       GPIO_FN_D15,    GPIO_FN_D14,    GPIO_FN_D13,    GPIO_FN_D12,
-       GPIO_FN_D11,    GPIO_FN_D10,    GPIO_FN_D9,     GPIO_FN_D8,
-       GPIO_FN_ET0_MDC,                GPIO_FN_ET0_MDIO,
-       GPIO_FN_ET1_MDC,                GPIO_FN_ET1_MDIO,
-       GPIO_FN_SIM_D,  GPIO_FN_SIM_CLK,                GPIO_FN_SIM_RST,
-       GPIO_FN_WPSZ1,  GPIO_FN_WPSZ0,  GPIO_FN_FWID,   GPIO_FN_FLSHSZ,
-       GPIO_FN_LPC_SPIEN,              GPIO_FN_BASEL,
+       GPIO_FN_ET0_MDC,        GPIO_FN_ET0_MDIO,
+       GPIO_FN_ET1_MDC,        GPIO_FN_ET1_MDIO,
 
-       /* PTC (mobule: SD) */
-       GPIO_FN_SD_WP,  GPIO_FN_SD_CD,  GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
-       GPIO_FN_SD_D3,  GPIO_FN_SD_D2,  GPIO_FN_SD_D1,  GPIO_FN_SD_D0,
+       /* PTB (mobule: INTC, ONFI, TMU) */
+       GPIO_FN_IRQ15,  GPIO_FN_IRQ14,  GPIO_FN_IRQ13,  GPIO_FN_IRQ12,
+       GPIO_FN_IRQ11,  GPIO_FN_IRQ10,  GPIO_FN_IRQ9,   GPIO_FN_IRQ8,
+       GPIO_FN_ON_NRE, GPIO_FN_ON_NWE, GPIO_FN_ON_NWP, GPIO_FN_ON_NCE0,
+       GPIO_FN_ON_R_B0,        GPIO_FN_ON_ALE, GPIO_FN_ON_CLE,
+       GPIO_FN_TCLK,
 
-       /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+       /* PTC (mobule: IRQ, PWMU) */
        GPIO_FN_IRQ7,   GPIO_FN_IRQ6,   GPIO_FN_IRQ5,   GPIO_FN_IRQ4,
        GPIO_FN_IRQ3,   GPIO_FN_IRQ2,   GPIO_FN_IRQ1,   GPIO_FN_IRQ0,
-       GPIO_FN_MD6,    GPIO_FN_MD5,    GPIO_FN_MD3,    GPIO_FN_MD2,
-       GPIO_FN_MD1,    GPIO_FN_MD0,    GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
-
-       /* PTE (mobule: EtherC) */
-       GPIO_FN_ET0_CRS_DV,             GPIO_FN_ET0_TXD1,
-       GPIO_FN_ET0_TXD0,               GPIO_FN_ET0_TX_EN,
-       GPIO_FN_ET0_REF_CLK,            GPIO_FN_ET0_RXD1,
-       GPIO_FN_ET0_RXD0,               GPIO_FN_ET0_RX_ER,
-
-       /* PTF (mobule: EtherC) */
-       GPIO_FN_ET1_CRS_DV,             GPIO_FN_ET1_TXD1,
-       GPIO_FN_ET1_TXD0,               GPIO_FN_ET1_TX_EN,
-       GPIO_FN_ET1_REF_CLK,            GPIO_FN_ET1_RXD1,
-       GPIO_FN_ET1_RXD0,               GPIO_FN_ET1_RX_ER,
-
-       /* PTG (mobule: SYSTEM, PWMX, LPC) */
-       GPIO_FN_STATUS0,                GPIO_FN_STATUS1,
-       GPIO_FN_PWX0,   GPIO_FN_PWX1,   GPIO_FN_PWX2,   GPIO_FN_PWX3,
-       GPIO_FN_SERIRQ, GPIO_FN_CLKRUN, GPIO_FN_LPCPD,  GPIO_FN_LDRQ,
-
-       /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-       GPIO_FN_TCLK,   GPIO_FN_RXD4,   GPIO_FN_TXD4,
+       GPIO_FN_PWMU0,  GPIO_FN_PWMU1,  GPIO_FN_PWMU2,  GPIO_FN_PWMU3,
+       GPIO_FN_PWMU4,  GPIO_FN_PWMU5,
+
+       /* PTD (mobule: SPI0, DMAC) */
+       GPIO_FN_SP0_MOSI,       GPIO_FN_SP0_MISO,       GPIO_FN_SP0_SCK,
+       GPIO_FN_SP0_SCK_FB,     GPIO_FN_SP0_SS0,        GPIO_FN_SP0_SS1,
+       GPIO_FN_SP0_SS2,        GPIO_FN_SP0_SS3,        GPIO_FN_DREQ0,
+       GPIO_FN_DACK0,          GPIO_FN_TEND0,
+
+       /* PTE (mobule: RMII) */
+       GPIO_FN_RMII0_CRS_DV,   GPIO_FN_RMII0_TXD1,     GPIO_FN_RMII0_TXD0,
+       GPIO_FN_RMII0_TXEN,     GPIO_FN_RMII0_REFCLK,   GPIO_FN_RMII0_RXD1,
+       GPIO_FN_RMII0_RXD0,     GPIO_FN_RMII0_RX_ER,
+
+       /* PTF (mobule: RMII, SerMux) */
+       GPIO_FN_RMII1_CRS_DV,   GPIO_FN_RMII1_TXD1,     GPIO_FN_RMII1_TXD0,
+       GPIO_FN_RMII1_TXEN,     GPIO_FN_RMII1_REFCLK,   GPIO_FN_RMII1_RXD1,
+       GPIO_FN_RMII1_RXD0,     GPIO_FN_RMII1_RX_ER,    GPIO_FN_RAC_RI,
+
+       /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+       GPIO_FN_BOOTFMS,                GPIO_FN_BOOTWP,
+       GPIO_FN_A25,    GPIO_FN_A24,    GPIO_FN_SERIRQ, GPIO_FN_WDTOVF,
+       GPIO_FN_LPCPD,  GPIO_FN_LDRQ,   GPIO_FN_MMCCLK, GPIO_FN_MMCCMD,
+
+       /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
        GPIO_FN_SP1_MOSI,               GPIO_FN_SP1_MISO,
        GPIO_FN_SP1_SCK,                GPIO_FN_SP1_SCK_FB,
        GPIO_FN_SP1_SS0,                GPIO_FN_SP1_SS1,
-       GPIO_FN_SP0_SS1,
-
-       /* PTI (mobule: INTC) */
-       GPIO_FN_IRQ15,  GPIO_FN_IRQ14,  GPIO_FN_IRQ13,  GPIO_FN_IRQ12,
-       GPIO_FN_IRQ11,  GPIO_FN_IRQ10,  GPIO_FN_IRQ9,   GPIO_FN_IRQ8,
-
-       /* PTJ (mobule: SCIF234, SERMUX) */
-       GPIO_FN_RXD3,   GPIO_FN_TXD3,   GPIO_FN_RXD2,   GPIO_FN_TXD2,
-       GPIO_FN_COM1_TXD,               GPIO_FN_COM1_RXD,
-       GPIO_FN_COM1_RTS,               GPIO_FN_COM1_CTS,
-
-       /* PTK (mobule: SERMUX) */
-       GPIO_FN_COM2_TXD,               GPIO_FN_COM2_RXD,
-       GPIO_FN_COM2_RTS,               GPIO_FN_COM2_CTS,
-       GPIO_FN_COM2_DTR,               GPIO_FN_COM2_DSR,
-       GPIO_FN_COM2_DCD,               GPIO_FN_COM2_RI,
+       GPIO_FN_WP,     GPIO_FN_FMS0,   GPIO_FN_TEND1,  GPIO_FN_DREQ1,
+       GPIO_FN_DACK1,  GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
 
-       /* PTL (mobule: SERMUX) */
-       GPIO_FN_RAC_TXD,                GPIO_FN_RAC_RXD,
-       GPIO_FN_RAC_RTS,                GPIO_FN_RAC_CTS,
-       GPIO_FN_RAC_DTR,                GPIO_FN_RAC_DSR,
-       GPIO_FN_RAC_DCD,                GPIO_FN_RAC_RI,
+       /* PTI (mobule: LBSC, SDHI) */
+       GPIO_FN_D15,    GPIO_FN_D14,    GPIO_FN_D13,    GPIO_FN_D12,
+       GPIO_FN_D11,    GPIO_FN_D10,    GPIO_FN_D9,     GPIO_FN_D8,
+       GPIO_FN_SD_WP,  GPIO_FN_SD_CD,  GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
+       GPIO_FN_SD_D3,  GPIO_FN_SD_D2,  GPIO_FN_SD_D1,  GPIO_FN_SD_D0,
 
-       /* PTM (mobule: IIC, LPC) */
+       /* PTJ (mobule: SCIF234) */
+       GPIO_FN_RTS3,   GPIO_FN_CTS3,   GPIO_FN_TXD3,   GPIO_FN_RXD3,
+       GPIO_FN_RTS4,   GPIO_FN_RXD4,   GPIO_FN_TXD4,
+
+       /* PTK (mobule: SERMUX, LBSC, SCIF) */
+       GPIO_FN_COM2_TXD,       GPIO_FN_COM2_RXD,       GPIO_FN_COM2_RTS,
+       GPIO_FN_COM2_CTS,       GPIO_FN_COM2_DTR,       GPIO_FN_COM2_DSR,
+       GPIO_FN_COM2_DCD,       GPIO_FN_CLKOUT,
+       GPIO_FN_SCK2,           GPIO_FN_SCK4,   GPIO_FN_SCK3,
+
+       /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+       GPIO_FN_RAC_RXD,        GPIO_FN_RAC_RTS,        GPIO_FN_RAC_CTS,
+       GPIO_FN_RAC_DTR,        GPIO_FN_RAC_DSR,        GPIO_FN_RAC_DCD,
+       GPIO_FN_RAC_TXD,        GPIO_FN_RXD2,           GPIO_FN_CS5,
+       GPIO_FN_CS6,            GPIO_FN_AUDSYNC,        GPIO_FN_AUDCK,
+       GPIO_FN_TXD2,
+
+       /* PTM (mobule: LBSC, IIC) */
+       GPIO_FN_CS4,    GPIO_FN_RD,     GPIO_FN_WE0,    GPIO_FN_CS0,
        GPIO_FN_SDA6,   GPIO_FN_SCL6,   GPIO_FN_SDA7,   GPIO_FN_SCL7,
-       GPIO_FN_WP,     GPIO_FN_FMS0,   GPIO_FN_FMS1,
-
-       /* PTN (mobule: SCIF234, EVC) */
-       GPIO_FN_SCK2,   GPIO_FN_RTS4,   GPIO_FN_RTS3,   GPIO_FN_RTS2,
-       GPIO_FN_CTS4,   GPIO_FN_CTS3,   GPIO_FN_CTS2,
-       GPIO_FN_EVENT7, GPIO_FN_EVENT6, GPIO_FN_EVENT5, GPIO_FN_EVENT4,
-       GPIO_FN_EVENT3, GPIO_FN_EVENT2, GPIO_FN_EVENT1, GPIO_FN_EVENT0,
 
-       /* PTO (mobule: SGPIO) */
-       GPIO_FN_SGPIO0_CLK,             GPIO_FN_SGPIO0_LOAD,
-       GPIO_FN_SGPIO0_DI,              GPIO_FN_SGPIO0_DO,
-       GPIO_FN_SGPIO1_CLK,             GPIO_FN_SGPIO1_LOAD,
-       GPIO_FN_SGPIO1_DI,              GPIO_FN_SGPIO1_DO,
+       /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+       GPIO_FN_VBUS_EN,        GPIO_FN_VBUS_OC,        GPIO_FN_JMCTCK,
+       GPIO_FN_JMCTMS,         GPIO_FN_JMCTDO,         GPIO_FN_JMCTDI,
+       GPIO_FN_JMCTRST,
+       GPIO_FN_SGPIO1_CLK,     GPIO_FN_SGPIO1_LOAD,    GPIO_FN_SGPIO1_DI,
+       GPIO_FN_SGPIO1_DO,      GPIO_FN_SUB_CLKIN,
 
-       /* PTP (mobule: JMC, SCIF234) */
-       GPIO_FN_JMCTCK, GPIO_FN_JMCTMS, GPIO_FN_JMCTDO, GPIO_FN_JMCTDI,
-       GPIO_FN_JMCRST, GPIO_FN_SCK4,   GPIO_FN_SCK3,
+       /* PTO (mobule: SGPIO, SerMux) */
+       GPIO_FN_SGPIO0_CLK,     GPIO_FN_SGPIO0_LOAD,    GPIO_FN_SGPIO0_DI,
+       GPIO_FN_SGPIO0_DO,      GPIO_FN_SGPIO2_CLK,     GPIO_FN_SGPIO2_LOAD,
+       GPIO_FN_SGPIO2_DI,      GPIO_FN_SGPIO2_DO,      GPIO_FN_COM1_TXD,
+       GPIO_FN_COM1_RXD,       GPIO_FN_COM1_RTS,       GPIO_FN_COM1_CTS,
 
        /* PTQ (mobule: LPC) */
        GPIO_FN_LAD3,   GPIO_FN_LAD2,   GPIO_FN_LAD1,   GPIO_FN_LAD0,
        GPIO_FN_LFRAME, GPIO_FN_LRESET, GPIO_FN_LCLK,
 
        /* PTR (mobule: GRA, IIC) */
-       GPIO_FN_DDC3,   GPIO_FN_DDC2,
-       GPIO_FN_SDA8,   GPIO_FN_SCL8,   GPIO_FN_SDA2,   GPIO_FN_SCL2,
+       GPIO_FN_DDC3,   GPIO_FN_DDC2,   GPIO_FN_SDA2,   GPIO_FN_SCL2,
        GPIO_FN_SDA1,   GPIO_FN_SCL1,   GPIO_FN_SDA0,   GPIO_FN_SCL0,
+       GPIO_FN_SDA8,   GPIO_FN_SCL8,
 
        /* PTS (mobule: GRA, IIC) */
-       GPIO_FN_DDC1,   GPIO_FN_DDC0,
-       GPIO_FN_SDA9,   GPIO_FN_SCL9,   GPIO_FN_SDA5,   GPIO_FN_SCL5,
+       GPIO_FN_DDC1,   GPIO_FN_DDC0,   GPIO_FN_SDA5,   GPIO_FN_SCL5,
        GPIO_FN_SDA4,   GPIO_FN_SCL4,   GPIO_FN_SDA3,   GPIO_FN_SCL3,
+       GPIO_FN_SDA9,   GPIO_FN_SCL9,
 
-       /* PTT (mobule: SYSTEM, PWMX) */
-       GPIO_FN_AUDSYNC,                GPIO_FN_AUDCK,
-       GPIO_FN_AUDATA3,                GPIO_FN_AUDATA2,
-       GPIO_FN_AUDATA1,                GPIO_FN_AUDATA0,
-       GPIO_FN_PWX7,   GPIO_FN_PWX6,   GPIO_FN_PWX5,   GPIO_FN_PWX4,
+       /* PTT (mobule: PWMX, AUD) */
+       GPIO_FN_PWMX7,  GPIO_FN_PWMX6,  GPIO_FN_PWMX5,  GPIO_FN_PWMX4,
+       GPIO_FN_PWMX3,  GPIO_FN_PWMX2,  GPIO_FN_PWMX1,  GPIO_FN_PWMX0,
+       GPIO_FN_AUDATA3,        GPIO_FN_AUDATA2,        GPIO_FN_AUDATA1,
+       GPIO_FN_AUDATA0,        GPIO_FN_STATUS1,        GPIO_FN_STATUS0,
 
-       /* PTU (mobule: LBSC, DMAC) */
-       GPIO_FN_CS6,    GPIO_FN_CS5,    GPIO_FN_CS4,    GPIO_FN_CS0,
-       GPIO_FN_RD,     GPIO_FN_WE0,    GPIO_FN_A25,    GPIO_FN_A24,
-       GPIO_FN_DREQ0,  GPIO_FN_DACK0,
+       /* PTU (mobule: LPC, APM) */
+       GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
+       GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
+       GPIO_FN_APMONCTL_O,     GPIO_FN_APMPWBTOUT_O,   GPIO_FN_APMSCI_O,
+       GPIO_FN_APMVDDON,       GPIO_FN_APMSLPBTN,      GPIO_FN_APMPWRBTN,
+       GPIO_FN_APMS5N,         GPIO_FN_APMS3N,
 
-       /* PTV (mobule: LBSC, DMAC) */
+       /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
        GPIO_FN_A23,    GPIO_FN_A22,    GPIO_FN_A21,    GPIO_FN_A20,
        GPIO_FN_A19,    GPIO_FN_A18,    GPIO_FN_A17,    GPIO_FN_A16,
-       GPIO_FN_TEND0,  GPIO_FN_DREQ1,  GPIO_FN_DACK1,  GPIO_FN_TEND1,
+       GPIO_FN_COM2_RI,        GPIO_FN_R_SPI_MOSI,     GPIO_FN_R_SPI_MISO,
+       GPIO_FN_R_SPI_RSPCK,    GPIO_FN_R_SPI_SSL0,     GPIO_FN_R_SPI_SSL1,
+       GPIO_FN_EVENT7,         GPIO_FN_EVENT6,         GPIO_FN_VBIOS_DI,
+       GPIO_FN_VBIOS_DO,       GPIO_FN_VBIOS_CLK,      GPIO_FN_VBIOS_CS,
 
-       /* PTW (mobule: LBSC) */
+       /* PTW (mobule: LBSC, EVC, SCIF) */
        GPIO_FN_A15,    GPIO_FN_A14,    GPIO_FN_A13,    GPIO_FN_A12,
        GPIO_FN_A11,    GPIO_FN_A10,    GPIO_FN_A9,     GPIO_FN_A8,
+       GPIO_FN_EVENT5, GPIO_FN_EVENT4, GPIO_FN_EVENT3, GPIO_FN_EVENT2,
+       GPIO_FN_EVENT1, GPIO_FN_EVENT0, GPIO_FN_CTS4,   GPIO_FN_CTS2,
 
-       /* PTX (mobule: LBSC) */
+       /* PTX (mobule: LBSC, SCIF, SIM) */
        GPIO_FN_A7,     GPIO_FN_A6,     GPIO_FN_A5,     GPIO_FN_A4,
        GPIO_FN_A3,     GPIO_FN_A2,     GPIO_FN_A1,     GPIO_FN_A0,
+       GPIO_FN_RTS2,   GPIO_FN_SIM_D,  GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
 
        /* PTY (mobule: LBSC) */
        GPIO_FN_D7,     GPIO_FN_D6,     GPIO_FN_D5,     GPIO_FN_D4,
        GPIO_FN_D3,     GPIO_FN_D2,     GPIO_FN_D1,     GPIO_FN_D0,
+
+       /* PTZ (mobule: eMMC, ONFI) */
+       GPIO_FN_MMCDAT7,        GPIO_FN_MMCDAT6,        GPIO_FN_MMCDAT5,
+       GPIO_FN_MMCDAT4,        GPIO_FN_MMCDAT3,        GPIO_FN_MMCDAT2,
+       GPIO_FN_MMCDAT1,        GPIO_FN_MMCDAT0,
+       GPIO_FN_ON_DQ7, GPIO_FN_ON_DQ6, GPIO_FN_ON_DQ5, GPIO_FN_ON_DQ4,
+       GPIO_FN_ON_DQ3, GPIO_FN_ON_DQ2, GPIO_FN_ON_DQ1, GPIO_FN_ON_DQ0,
 };
 
 #endif /* __ASM_SH7757_H__ */
diff --git a/arch/sh/include/cpu-sh4/cpu/shx3.h b/arch/sh/include/cpu-sh4/cpu/shx3.h
new file mode 100644 (file)
index 0000000..68d9080
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __CPU_SHX3_H
+#define __CPU_SHX3_H
+
+enum {
+       /* PA */
+       GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
+       GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+       /* PB */
+       GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+       GPIO_PB3, GPIO_PB2, GPIO_PB1, GPIO_PB0,
+
+       /* PC */
+       GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+       GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+       /* PD */
+       GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+       GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+       /* PE */
+       GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+       GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+       /* PF */
+       GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+       GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+       /* PG */
+       GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+       GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+       /* PH */
+       GPIO_PH5, GPIO_PH4,
+       GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+       /* SCIF */
+       GPIO_FN_SCK3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+       GPIO_FN_SCK2, GPIO_FN_TXD2, GPIO_FN_RXD2,
+       GPIO_FN_SCK1, GPIO_FN_TXD1, GPIO_FN_RXD1,
+       GPIO_FN_SCK0, GPIO_FN_TXD0, GPIO_FN_RXD0,
+
+       /* LBSC */
+       GPIO_FN_D31, GPIO_FN_D30, GPIO_FN_D29, GPIO_FN_D28,
+       GPIO_FN_D27, GPIO_FN_D26, GPIO_FN_D25, GPIO_FN_D24,
+       GPIO_FN_D23, GPIO_FN_D22, GPIO_FN_D21, GPIO_FN_D20,
+       GPIO_FN_D19, GPIO_FN_D18, GPIO_FN_D17, GPIO_FN_D16,
+       GPIO_FN_WE3, GPIO_FN_WE2, GPIO_FN_CS6, GPIO_FN_CS5,
+       GPIO_FN_CS4, GPIO_FN_CLKOUTENB, GPIO_FN_BREQ,
+       GPIO_FN_IOIS16, GPIO_FN_CE2B, GPIO_FN_CE2A, GPIO_FN_BACK,
+
+       /* DMAC */
+       GPIO_FN_DACK0, GPIO_FN_DREQ0, GPIO_FN_DRAK0,
+       GPIO_FN_DACK1, GPIO_FN_DREQ1, GPIO_FN_DRAK1,
+       GPIO_FN_DACK2, GPIO_FN_DREQ2, GPIO_FN_DRAK2,
+       GPIO_FN_DACK3, GPIO_FN_DREQ3, GPIO_FN_DRAK3,
+
+       /* INTC */
+       GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
+       GPIO_FN_IRL3, GPIO_FN_IRL2, GPIO_FN_IRL1, GPIO_FN_IRL0,
+       GPIO_FN_IRQOUT, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
+};
+
+#endif /* __CPU_SHX3_H */
diff --git a/arch/sh/include/mach-common/mach/sh2007.h b/arch/sh/include/mach-common/mach/sh2007.h
new file mode 100644 (file)
index 0000000..48180b9
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef __MACH_SH2007_H
+#define __MACH_SH2007_H
+
+#define CS5BCR         0xff802050
+#define CS5WCR         0xff802058
+#define CS5PCR         0xff802070
+
+#define BUS_SZ8                1
+#define BUS_SZ16       2
+#define BUS_SZ32       3
+
+#define PCMCIA_IODYN   1
+#define PCMCIA_ATA     0
+#define PCMCIA_IO8     2
+#define PCMCIA_IO16    3
+#define PCMCIA_COMM8   4
+#define PCMCIA_COMM16  5
+#define PCMCIA_ATTR8   6
+#define PCMCIA_ATTR16  7
+
+#define TYPE_SRAM      0
+#define TYPE_PCMCIA    4
+
+/* write-read/write-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWW5           0
+#define IWW6           3
+/* different area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWD5         2
+#define IWRWD6         2
+/* same area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWS5         2
+#define IWRWS6         2
+/* different area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRD5         2
+#define IWRRD6         2
+/* same area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRS5         0
+#define IWRRS6         2
+/* burst count (0-3:4,8,16,32) */
+#define BST5           0
+#define BST6           0
+/* bus size */
+#define SZ5            BUS_SZ16
+#define SZ6            BUS_SZ16
+/* RD hold for SRAM (0-1:0,1) */
+#define RDSPL5         0
+#define RDSPL6         0
+/* Burst pitch (0-7:0,1,2,3,4,5,6,7) */
+#define BW5            0
+#define BW6            0
+/* Multiplex (0-1:0,1) */
+#define MPX5           0
+#define MPX6           0
+/* device type */
+#define TYPE5          TYPE_PCMCIA
+#define TYPE6          TYPE_PCMCIA
+/* address setup before assert CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADS5           0
+#define ADS6           0
+/* address hold after negate CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADH5           0
+#define ADH6           0
+/* CSn assert to RD assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDS5           0
+#define RDS6           0
+/* RD negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDH5           0
+#define RDH6           0
+/* CSn assert to WE assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTS5           0
+#define WTS6           0
+/* WE negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTH5           0
+#define WTH6           0
+/* BS hold (0-1:1,2) */
+#define BSH5           0
+#define BSH6           0
+/* wait cycle (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define IW5            6       /* 60ns PIO mode 4 */
+#define IW6            15      /* 250ns */
+
+#define SAA5           PCMCIA_IODYN    /* IDE area b4000000-b5ffffff */
+#define SAB5           PCMCIA_IODYN    /* CF  area b6000000-b7ffffff */
+#define PCWA5          0       /* additional wait A (0-3:0,15,30,50) */
+#define PCWB5          0       /* additional wait B (0-3:0,15,30,50) */
+/* wait B (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define PCIW5          12
+/* Address->OE/WE assert delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEDA5          2
+/* Address->OE/WE assert delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEDB5          4
+/* OE/WE negate->Address delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEHA5          2
+/* OE/WE negate->Address delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEHB5          3
+
+#define CS5BCR_D       ((IWW5<<28)|(IWRWD5<<24)|(IWRWS5<<20)|          \
+                       (IWRRD5<<16)|(IWRRS5<<12)|(BST5<<10)|           \
+                       (SZ5<<8)|(RDSPL5<<7)|(BW5<<4)|(MPX5<<3)|TYPE5)
+#define CS5WCR_D       ((ADS5<<28)|(ADH5<<24)|(RDS5<<20)|      \
+                       (RDH5<<16)|(WTS5<<12)|(WTH5<<8)|(BSH5<<4)|IW5)
+#define CS5PCR_D       ((SAA5<<28)|(SAB5<<24)|(PCWA5<<22)|             \
+                       (PCWB5<<20)|(PCIW5<<16)|(TEDA5<<12)|            \
+                       (TEDB5<<8)|(TEHA5<<4)|TEHB5)
+
+#define SMC0_BASE       0xb0800000      /* eth0 */
+#define SMC1_BASE       0xb0900000      /* eth1 */
+#define CF_BASE         0xb6100000      /* Compact Flash (I/O area) */
+#define IDE_BASE        0xb4000000      /* IDE */
+#define PC104_IO_BASE   0xb8000000
+#define PC104_MEM_BASE  0xba000000
+#define SMC_IO_SIZE     0x100
+
+#define CF_OFFSET       0x1f0
+#define IDE_OFFSET      0x170
+
+#endif /* __MACH_SH2007_H */
index 416b621d94d145eaab47299f837ff0073190ac2f..40f0c2d3690c5a3c6744f2bdff6c4eed8eb1c027 100644 (file)
 #define EXTASR         0x110
 #define SPCAR          0x120
 #define INTMSR         0x130
+
 #define PCIECR         0x140
+#define  PCIECR_PCIEMUX1       BIT(15)
+#define  PCIECR_PCIEMUX0       BIT(14)
+#define  PCIECR_PRST4          BIT(12) /* slot 4 card present */
+#define  PCIECR_PRST3          BIT(11) /* slot 3 card present */
+#define  PCIECR_PRST2          BIT(10) /* slot 2 card present */
+#define  PCIECR_PRST1          BIT(9)  /* slot 1 card present */
+#define  PCIECR_CLKEN          BIT(4)  /* oscillator enable */
+
 #define FAER           0x150
 #define USRGPIR                0x160
+
 /* 0x170 reserved */
-#define LCLASR         0x180
+
+#define LCLASR                 0x180
+#define  LCLASR_FRAMEN         BIT(15)
+
+#define  LCLASR_FPGA_SEL_SHIFT 12
+#define  LCLASR_NAND_SEL_SHIFT 8
+#define  LCLASR_NORB_SEL_SHIFT 4
+#define  LCLASR_NORA_SEL_SHIFT 0
+
+#define  LCLASR_AREA_MASK      0x7
+
+#define  LCLASR_FPGA_SEL_MASK  (LCLASR_AREA_MASK << LCLASR_FPGA_SEL_SHIFT)
+#define  LCLASR_NAND_SEL_MASK  (LCLASR_AREA_MASK << LCLASR_NAND_SEL_SHIFT)
+#define  LCLASR_NORB_SEL_MASK  (LCLASR_AREA_MASK << LCLASR_NORB_SEL_SHIFT)
+#define  LCLASR_NORA_SEL_MASK  (LCLASR_AREA_MASK << LCLASR_NORA_SEL_SHIFT)
 
 #define SBCR           0x190
 #define  SCBR_I2CMEN   BIT(0)  /* FPGA I2C master enable */
diff --git a/arch/sh/include/mach-x3proto/mach/hardware.h b/arch/sh/include/mach-x3proto/mach/hardware.h
new file mode 100644 (file)
index 0000000..52bca57
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __MACH_X3PROTO_HARDWARE_H
+#define __MACH_X3PROTO_HARDWARE_H
+
+struct gpio_chip;
+
+/* arch/sh/boards/mach-x3proto/gpio.c */
+int x3proto_gpio_setup(void);
+extern struct gpio_chip x3proto_gpio_chip;
+
+#define NR_BASEBOARD_GPIOS     16
+
+#endif /* __MACH_X3PROTO_HARDWARE_H */
diff --git a/arch/sh/include/mach-x3proto/mach/ilsel.h b/arch/sh/include/mach-x3proto/mach/ilsel.h
new file mode 100644 (file)
index 0000000..e3d304b
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __ASM_SH_ILSEL_H
+#define __ASM_SH_ILSEL_H
+
+typedef enum {
+       ILSEL_NONE,
+       ILSEL_LAN,
+       ILSEL_USBH_I,
+       ILSEL_USBH_S,
+       ILSEL_USBH_V,
+       ILSEL_RTC,
+       ILSEL_USBP_I,
+       ILSEL_USBP_S,
+       ILSEL_USBP_V,
+       ILSEL_KEY,
+
+       /*
+        * ILSEL Aliases - corner cases for interleaved level tables.
+        *
+        * Someone thought this was a good idea and less hassle than
+        * demuxing a shared vector, really.
+        */
+
+       /* ILSEL0 and 2 */
+       ILSEL_FPGA0,
+       ILSEL_FPGA1,
+       ILSEL_EX1,
+       ILSEL_EX2,
+       ILSEL_EX3,
+       ILSEL_EX4,
+
+       /* ILSEL1 and 3 */
+       ILSEL_FPGA2 = ILSEL_FPGA0,
+       ILSEL_FPGA3 = ILSEL_FPGA1,
+       ILSEL_EX5 = ILSEL_EX1,
+       ILSEL_EX6 = ILSEL_EX2,
+       ILSEL_EX7 = ILSEL_EX3,
+       ILSEL_EX8 = ILSEL_EX4,
+} ilsel_source_t;
+
+/* arch/sh/boards/renesas/x3proto/ilsel.c */
+int ilsel_enable(ilsel_source_t set);
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
+void ilsel_disable(unsigned int irq);
+
+#endif /* __ASM_SH_ILSEL_H */
index e25f3c69525d4eeb4aaed3fc9a5d724efb797124..8eed6a4854463418c26dfd7410874481706e5adf 100644 (file)
@@ -12,9 +12,9 @@ endif
 CFLAGS_REMOVE_return_address.o = -pg
 
 obj-y  := clkdev.o debugtraps.o dma-nommu.o dumpstack.o                \
-          idle.o io.o irq.o                                            \
-          irq_$(BITS).o machvec.o nmi_debug.o process.o                \
-          process_$(BITS).o ptrace_$(BITS).o                           \
+          idle.o io.o irq.o irq_$(BITS).o kdebugfs.o                   \
+          machvec.o nmi_debug.o process.o                              \
+          process_$(BITS).o ptrace.o ptrace_$(BITS).o                  \
           reboot.o return_address.o                                    \
           setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o            \
           syscalls_$(BITS).o time.o topology.o traps.o                 \
@@ -44,4 +44,4 @@ obj-$(CONFIG_HAS_IOPORT)      += io_generic.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)               += hw_breakpoint.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += localtimer.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index befc255830a4c1b30874ed44034d81680e13fbfd..1f800ef4a7356045d18bae9dbcd788d07872ce50 100644 (file)
@@ -161,9 +161,11 @@ EXPORT_SYMBOL(clk_add_alias);
  */
 void clkdev_drop(struct clk_lookup *cl)
 {
+       struct clk_lookup_alloc *cla = container_of(cl, struct clk_lookup_alloc, cl);
+
        mutex_lock(&clocks_mutex);
        list_del(&cl->node);
        mutex_unlock(&clocks_mutex);
-       kfree(cl);
+       kfree(cla);
 }
 EXPORT_SYMBOL(clkdev_drop);
index d180f16281ed9f824df155f5cdb1fb872b6a223b..b93458f33b74bad99e7a29721a0f2c25e78194a5 100644 (file)
@@ -150,7 +150,7 @@ void __cpuinit cpu_probe(void)
                        boot_cpu_data.type = CPU_SH7724;
                        boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
                        break;
-               case 0x50:
+               case 0x10:
                        boot_cpu_data.type = CPU_SH7757;
                        break;
                }
index b144e8af89dc696b8285bbb5e60fbb032a1d2bb6..cc122b1d303540ea6fcf13182c6d5f834901481b 100644 (file)
@@ -8,13 +8,13 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7763)      += setup-sh7763.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7770)       += setup-sh7770.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += setup-sh7780.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += setup-sh7785.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += setup-sh7786.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += setup-sh7786.o intc-shx3.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)       += setup-sh7724.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)       += setup-sh7366.o
-obj-$(CONFIG_CPU_SUBTYPE_SHX3)         += setup-shx3.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3)         += setup-shx3.o intc-shx3.o
 
 # SMP setup
 smp-$(CONFIG_CPU_SHX3)                 := smp-shx3.o
@@ -40,6 +40,7 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7724)   := pinmux-sh7724.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7757)    := pinmux-sh7757.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)    := pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)    := pinmux-sh7786.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SHX3)      := pinmux-shx3.o
 
 obj-y                                  += $(clock-y)
 obj-$(CONFIG_SMP)                      += $(smp-y)
index 0a752bd324ac74b7c9a8b004c822fce522456806..ce39a2ae8c6cd8a8140a9bd8a09a977b75a48a27 100644 (file)
@@ -3,7 +3,7 @@
  *
  * SH7757 support for the clock framework
  *
- *  Copyright (C) 2009  Renesas Solutions Corp.
+ *  Copyright (C) 2009-2010  Renesas Solutions Corp.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
 #include <asm/clock.h>
 #include <asm/freq.h>
 
-static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-                             16, 1, 1, 32, 1, 1, 1, 1 };
-static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-                             16, 1, 1, 32, 1, 1, 1, 1 };
-static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-                             16, 1, 1, 32, 1, 1, 1, 1 };
-static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-                              16, 1, 1, 32, 1, 1, 1, 1 };
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+       .rate           = 48000000,
+};
 
-static void master_clk_init(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
 {
-       clk->rate = CONFIG_SH_PCLK_FREQ * 16;
-}
+       int multiplier;
 
-static struct clk_ops sh7757_master_clk_ops = {
-       .init           = master_clk_init,
-};
+       multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16;
 
-static void module_clk_recalc(struct clk *clk)
-{
-       int idx = __raw_readl(FRQCR) & 0x0000000f;
-       clk->rate = clk->parent->rate / p1fc_divisors[idx];
+       return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops sh7757_module_clk_ops = {
-       .recalc         = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
-{
-       int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f;
-       clk->rate = clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+       .ops            = &pll_clk_ops,
+       .parent         = &extal_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
 
-static struct clk_ops sh7757_bus_clk_ops = {
-       .recalc         = bus_clk_recalc,
+static struct clk *clks[] = {
+       &extal_clk,
+       &pll_clk,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-       int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f;
-       clk->rate = clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6,
+                              1, 1, 1, 16, 1, 24, 1, 1 };
 
-static struct clk_ops sh7757_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = div2,
+       .nr_divisors = ARRAY_SIZE(div2),
 };
 
-static struct clk_ops *sh7757_clk_ops[] = {
-       &sh7757_master_clk_ops,
-       &sh7757_module_clk_ops,
-       &sh7757_bus_clk_ops,
-       &sh7757_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
-       if (idx < ARRAY_SIZE(sh7757_clk_ops))
-               *ops = sh7757_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR };
 
-static void shyway_clk_recalc(struct clk *clk)
-{
-       int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f;
-       clk->rate = clk->parent->rate / sfc_divisors[idx];
-}
-
-static struct clk_ops sh7757_shyway_clk_ops = {
-       .recalc         = shyway_clk_recalc,
-};
+#define DIV4(_bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags)
 
-static struct clk sh7757_shyway_clk = {
-       .flags          = CLK_ENABLE_ON_INIT,
-       .ops            = &sh7757_shyway_clk_ops,
+struct clk div4_clks[DIV4_NR] = {
+       /*
+        * P clock is always enable, because some P clock modules is used
+        * by Host PC.
+        */
+       [DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT),
+       [DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT),
 };
 
-/*
- * Additional sh7757-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *sh7757_onchip_clocks[] = {
-       &sh7757_shyway_clk,
+#define MSTPCR0                0xffc80030
+#define MSTPCR1                0xffc80034
+
+enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+       MSTP111, MSTP110, MSTP103, MSTP102,
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       /* MSTPCR0 */
+       [MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
+       [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+       /* MSTPCR1 */
+       [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+       [MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
+       [MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
+       [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+       [MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0),
+       [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+       [MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0),
 };
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
        /* main clocks */
-       CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk),
+       CLKDEV_CON_ID("extal", &extal_clk),
+       CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+       CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+       CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+       /* MSTP32 clocks */
+       CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
+       CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
+       {
+               /* TMU0 */
+               .dev_id         = "sh_tmu.0",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP113],
+       }, {
+               /* TMU1 */
+               .dev_id         = "sh_tmu.1",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP114],
+       },
+       {
+               /* SCIF4 (But, ID is 2) */
+               .dev_id         = "sh-sci.2",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP112],
+       }, {
+               /* SCIF3 */
+               .dev_id         = "sh-sci.1",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP111],
+       }, {
+               /* SCIF2 */
+               .dev_id         = "sh-sci.0",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP110],
+       },
+       CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
 };
 
-static int __init sh7757_clk_init(void)
+int __init arch_clk_init(void)
 {
-       struct clk *clk = clk_get(NULL, "master_clk");
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) {
-               struct clk *clkp = sh7757_onchip_clocks[i];
+       int i, ret = 0;
 
-               clkp->parent = clk;
-               clk_register(clkp);
-               clk_enable(clkp);
-       }
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               ret |= clk_register(clks[i]);
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
 
-       /*
-        * Now that we have the rest of the clocks registered, we need to
-        * force the parent clock to propagate so that these clocks will
-        * automatically figure out their rate. We cheat by handing the
-        * parent clock its current rate and forcing child propagation.
-        */
-       clk_set_rate(clk, clk_get_rate(clk));
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+                                          &div4_table);
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
-       clk_put(clk);
-
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
-       return 0;
+       return ret;
 }
 
-arch_initcall(sh7757_clk_init);
-
index 236a6282d7789aad27380d7fa9723aeed694f84c..4f70df6b6169cb5170261f60f28cdf4b66b4107a 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  Copyright (C) 2006-2007  Renesas Technology Corp.
  *  Copyright (C) 2006-2007  Renesas Solutions Corp.
- *  Copyright (C) 2006-2007  Paul Mundt
+ *  Copyright (C) 2006-2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
 #include <asm/clock.h>
 #include <asm/freq.h>
 
-static int ifc_divisors[] = { 1, 2, 4 ,6 };
-static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
-static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
-static int cfc_divisors[] = { 1, 1, 4, 6 };
-
-#define IFC_POS                28
-#define IFC_MSK                0x0003
-#define BFC_MSK                0x000f
-#define PFC_MSK                0x000f
-#define CFC_MSK                0x0003
-#define BFC_POS                16
-#define PFC_POS                0
-#define CFC_POS                20
-
-static void master_clk_init(struct clk *clk)
-{
-       clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK];
-}
-
-static struct clk_ops shx3_master_clk_ops = {
-       .init           = master_clk_init,
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+       .rate           = 16666666,
 };
 
-static unsigned long module_clk_recalc(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
 {
-       int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK);
-       return clk->parent->rate / pfc_divisors[idx];
+       /* PLL1 has a fixed x72 multiplier.  */
+       return clk->parent->rate * 72;
 }
 
-static struct clk_ops shx3_module_clk_ops = {
-       .recalc         = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
 };
 
-static unsigned long bus_clk_recalc(struct clk *clk)
-{
-       int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK);
-       return clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+       .ops            = &pll_clk_ops,
+       .parent         = &extal_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
 
-static struct clk_ops shx3_bus_clk_ops = {
-       .recalc         = bus_clk_recalc,
+static struct clk *clks[] = {
+       &extal_clk,
+       &pll_clk,
 };
 
-static unsigned long cpu_clk_recalc(struct clk *clk)
-{
-       int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK);
-       return clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
+                              24, 32, 36, 48 };
 
-static struct clk_ops shx3_cpu_clk_ops = {
-       .recalc         = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = div2,
+       .nr_divisors = ARRAY_SIZE(div2),
 };
 
-static struct clk_ops *shx3_clk_ops[] = {
-       &shx3_master_clk_ops,
-       &shx3_module_clk_ops,
-       &shx3_bus_clk_ops,
-       &shx3_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
-       if (idx < ARRAY_SIZE(shx3_clk_ops))
-               *ops = shx3_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR };
 
-static unsigned long shyway_clk_recalc(struct clk *clk)
-{
-       int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK);
-       return clk->parent->rate / cfc_divisors[idx];
-}
+#define DIV4(_bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
 
-static struct clk_ops shx3_shyway_clk_ops = {
-       .recalc         = shyway_clk_recalc,
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_P] = DIV4(0, 0x0f80, 0),
+       [DIV4_SHA] = DIV4(4, 0x0ff0, 0),
+       [DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
+       [DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
+       [DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
 };
 
-static struct clk shx3_shyway_clk = {
-       .flags          = CLK_ENABLE_ON_INIT,
-       .ops            = &shx3_shyway_clk_ops,
-};
-
-/*
- * Additional SHx3-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *shx3_onchip_clocks[] = {
-       &shx3_shyway_clk,
+#define MSTPCR0                0xffc00030
+#define MSTPCR1                0xffc00034
+
+enum { MSTP027, MSTP026, MSTP025, MSTP024,
+       MSTP009, MSTP008, MSTP003, MSTP002,
+       MSTP001, MSTP000, MSTP119, MSTP105,
+       MSTP104, MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       /* MSTPCR0 */
+       [MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
+       [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+       [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+       [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+       [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+       [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+       [MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
+       [MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
+       [MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
+       [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+       /* MSTPCR1 */
+       [MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
+       [MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
+       [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
 };
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
        /* main clocks */
-       CLKDEV_CON_ID("shyway_clk", &shx3_shyway_clk),
+       CLKDEV_CON_ID("extal", &extal_clk),
+       CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+       CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]),
+       CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
+       CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+       CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+       CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+       /* MSTP32 clocks */
+       {
+               /* SCIF3 */
+               .dev_id         = "sh-sci.3",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP027],
+       }, {
+               /* SCIF2 */
+               .dev_id         = "sh-sci.2",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP026],
+       }, {
+               /* SCIF1 */
+               .dev_id         = "sh-sci.1",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP025],
+       }, {
+               /* SCIF0 */
+               .dev_id         = "sh-sci.0",
+               .con_id         = "sci_fck",
+               .clk            = &mstp_clks[MSTP024],
+       },
+       CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
+       CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
+       CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
+       CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
+       {
+               /* TMU0 */
+               .dev_id         = "sh_tmu.0",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP008],
+       }, {
+               /* TMU1 */
+               .dev_id         = "sh_tmu.1",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP008],
+       }, {
+               /* TMU2 */
+               .dev_id         = "sh_tmu.2",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP008],
+       }, {
+               /* TMU3 */
+               .dev_id         = "sh_tmu.3",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP009],
+       }, {
+               /* TMU4 */
+               .dev_id         = "sh_tmu.4",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP009],
+       }, {
+               /* TMU5 */
+               .dev_id         = "sh_tmu.5",
+               .con_id         = "tmu_fck",
+               .clk            = &mstp_clks[MSTP009],
+       },
+       CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
+       CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
+       CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
 };
 
 int __init arch_clk_init(void)
 {
-       struct clk *clk;
        int i, ret = 0;
 
-       cpg_clk_init();
-
-       clk = clk_get(NULL, "master_clk");
-       for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
-               struct clk *clkp = shx3_onchip_clocks[i];
-
-               clkp->parent = clk;
-               ret |= clk_register(clkp);
-       }
-
-       clk_put(clk);
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               ret |= clk_register(clks[i]);
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
 
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+                                          &div4_table);
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
        return ret;
 }
diff --git a/arch/sh/kernel/cpu/sh4a/intc-shx3.c b/arch/sh/kernel/cpu/sh4a/intc-shx3.c
new file mode 100644 (file)
index 0000000..78c9714
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Shared support for SH-X3 interrupt controllers.
+ *
+ *  Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/init.h>
+
+#define INTACK         0xfe4100b8
+#define INTACKCLR      0xfe4100bc
+#define INTC_USERIMASK 0xfe411000
+
+#ifdef CONFIG_INTC_BALANCING
+unsigned int irq_lookup(unsigned int irq)
+{
+       return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
+}
+
+void irq_finish(unsigned int irq)
+{
+       __raw_writel(irq2evt(irq), INTACKCLR);
+}
+#endif
+
+static int __init shx3_irq_setup(void)
+{
+       return register_intc_userimask(INTC_USERIMASK);
+}
+arch_initcall(shx3_irq_setup);
index eddc21973fa1e4f4f5600d217503924c6ce0d88b..b8b873d8d6b515e49c46cb015f1f079241bcc73a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Performance events support for SH-4A performance counters
  *
- *  Copyright (C) 2009  Paul Mundt
+ *  Copyright (C) 2009, 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
 #define CCBR_CMDS      (1 << 1)
 #define CCBR_PPCE      (1 << 0)
 
+#ifdef CONFIG_CPU_SHX3
+/*
+ * The PMCAT location for SH-X3 CPUs was quietly moved, while the CCBR
+ * and PMCTR locations remains tentatively constant. This change remains
+ * wholly undocumented, and was simply found through trial and error.
+ *
+ * Early cuts of SH-X3 still appear to use the SH-X/SH-X2 locations, and
+ * it's unclear when this ceased to be the case. For now we always use
+ * the new location (if future parts keep up with this trend then
+ * scanning for them at runtime also remains a viable option.)
+ *
+ * The gap in the register space also suggests that there are other
+ * undocumented counters, so this will need to be revisited at a later
+ * point in time.
+ */
+#define PPC_PMCAT      0xfc100240
+#else
 #define PPC_PMCAT      0xfc100080
+#endif
 
 #define PMCAT_OVF3     (1 << 27)
 #define PMCAT_CNN3     (1 << 26)
index ed23b155c097c409a416c777c239ce6d9759f7bf..4c74bd04bba43b505ab967316a5a5e7a7d3f014a 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * SH7757 (A0 step) Pinmux
+ * SH7757 (B0 step) Pinmux
  *
- *  Copyright (C) 2009  Renesas Solutions Corp.
+ *  Copyright (C) 2009-2010  Renesas Solutions Corp.
  *
  *  Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * Based on SH7757 Pinmux
+ * Based on SH7723 Pinmux
  *  Copyright (C) 2008  Magnus Damm
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -40,27 +40,27 @@ enum {
        PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
        PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
        PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
-       PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+                  PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
        PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
        PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
        PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
-       PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+                  PTL6_DATA, PTL5_DATA, PTL4_DATA,
        PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
-       PTM6_DATA, PTM5_DATA, PTM4_DATA,
+       PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
        PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
-       PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+                  PTN6_DATA, PTN5_DATA, PTN4_DATA,
        PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
        PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
        PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
-       PTP6_DATA, PTP5_DATA, PTP4_DATA,
+       PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
        PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
-       PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+                  PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
        PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
        PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
        PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
        PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
        PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
-       PTT5_DATA, PTT4_DATA,
+       PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
        PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
        PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
        PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
@@ -95,27 +95,27 @@ enum {
        PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
        PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
        PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
-       PTJ7_IN, PTJ6_IN, PTJ5_IN, PTJ4_IN,
+                PTJ6_IN, PTJ5_IN, PTJ4_IN,
        PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
        PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
        PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
-       PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+                PTL6_IN, PTL5_IN, PTL4_IN,
        PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
-       PTM6_IN, PTM5_IN, PTM4_IN,
+       PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
        PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
-       PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+                PTN6_IN, PTN5_IN, PTN4_IN,
        PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
        PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
        PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
-       PTP6_IN, PTP5_IN, PTP4_IN,
+       PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
        PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
-       PTQ6_IN, PTQ5_IN, PTQ4_IN,
+                PTQ6_IN, PTQ5_IN, PTQ4_IN,
        PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
        PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
        PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
        PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
        PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
-       PTT5_IN, PTT4_IN,
+       PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
        PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
        PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
        PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
@@ -132,16 +132,43 @@ enum {
        PINMUX_INPUT_END,
 
        PINMUX_INPUT_PULLUP_BEGIN,
+       PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+       PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+       PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+       PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+       PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+       PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+       PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+       PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+       PTG7_IN_PU, PTG6_IN_PU,             PTG4_IN_PU,
+       PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+       PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+       PTI7_IN_PU, PTI6_IN_PU,             PTI4_IN_PU,
+       PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
+                   PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+       PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+       PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+       PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+                   PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+       PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+       PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+                                           PTN4_IN_PU,
+       PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+       PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
+       PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
+       PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+       PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
        PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
        PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
        PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
-       PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
-       PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
-       PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+       PTV3_IN_PU, PTV2_IN_PU,
+                               PTW1_IN_PU, PTW0_IN_PU,
        PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
        PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
        PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
        PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+       PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+       PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
        PINMUX_INPUT_PULLUP_END,
 
        PINMUX_OUTPUT_BEGIN,
@@ -163,27 +190,27 @@ enum {
        PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
        PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
        PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
-       PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+                 PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
        PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
        PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
        PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
-       PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+                 PTL6_OUT, PTL5_OUT, PTL4_OUT,
        PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
-       PTM6_OUT, PTM5_OUT, PTM4_OUT,
+       PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
        PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
-       PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+                 PTN6_OUT, PTN5_OUT, PTN4_OUT,
        PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
        PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
        PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
-       PTP6_OUT, PTP5_OUT, PTP4_OUT,
+       PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
        PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
-       PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+                 PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
        PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
        PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
        PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
        PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
        PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
-       PTT5_OUT, PTT4_OUT,
+       PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
        PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
        PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
        PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
@@ -218,27 +245,27 @@ enum {
        PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
        PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
        PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
-       PTJ7_FN, PTJ6_FN, PTJ5_FN, PTJ4_FN,
+                PTJ6_FN, PTJ5_FN, PTJ4_FN,
        PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
        PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
        PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
-       PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+                PTL6_FN, PTL5_FN, PTL4_FN,
        PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
-       PTM6_FN, PTM5_FN, PTM4_FN,
+       PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
        PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
-       PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+                PTN6_FN, PTN5_FN, PTN4_FN,
        PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
        PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
        PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
-       PTP6_FN, PTP5_FN, PTP4_FN,
+       PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
        PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
-       PTQ6_FN, PTQ5_FN, PTQ4_FN,
+                PTQ6_FN, PTQ5_FN, PTQ4_FN,
        PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
        PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
        PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
        PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
        PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
-       PTT5_FN, PTT4_FN,
+       PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
        PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
        PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
        PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
@@ -253,181 +280,248 @@ enum {
        PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
        PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
 
-       PS0_15_FN1, PS0_15_FN3,
-       PS0_14_FN1, PS0_14_FN3,
-       PS0_13_FN1, PS0_13_FN3,
-       PS0_12_FN1, PS0_12_FN3,
+       PS0_15_FN1, PS0_15_FN2,
+       PS0_14_FN1, PS0_14_FN2,
+       PS0_13_FN1, PS0_13_FN2,
+       PS0_12_FN1, PS0_12_FN2,
+       PS0_11_FN1, PS0_11_FN2,
+       PS0_10_FN1, PS0_10_FN2,
+       PS0_9_FN1, PS0_9_FN2,
+       PS0_8_FN1, PS0_8_FN2,
        PS0_7_FN1, PS0_7_FN2,
        PS0_6_FN1, PS0_6_FN2,
        PS0_5_FN1, PS0_5_FN2,
        PS0_4_FN1, PS0_4_FN2,
        PS0_3_FN1, PS0_3_FN2,
        PS0_2_FN1, PS0_2_FN2,
-       PS0_1_FN1, PS0_1_FN2,
 
-       PS1_7_FN1, PS1_7_FN3,
-       PS1_6_FN1, PS1_6_FN3,
+       PS1_10_FN1, PS1_10_FN2,
+       PS1_9_FN1, PS1_9_FN2,
+       PS1_8_FN1, PS1_8_FN2,
+       PS1_2_FN1, PS1_2_FN2,
+
+       PS2_13_FN1, PS2_13_FN2,
+       PS2_12_FN1, PS2_12_FN2,
+       PS2_7_FN1, PS2_7_FN2,
+       PS2_6_FN1, PS2_6_FN2,
+       PS2_5_FN1, PS2_5_FN2,
+       PS2_4_FN1, PS2_4_FN2,
+       PS2_2_FN1, PS2_2_FN2,
+
+       PS3_15_FN1, PS3_15_FN2,
+       PS3_14_FN1, PS3_14_FN2,
+       PS3_13_FN1, PS3_13_FN2,
+       PS3_12_FN1, PS3_12_FN2,
+       PS3_11_FN1, PS3_11_FN2,
+       PS3_10_FN1, PS3_10_FN2,
+       PS3_9_FN1, PS3_9_FN2,
+       PS3_8_FN1, PS3_8_FN2,
+       PS3_7_FN1, PS3_7_FN2,
+       PS3_2_FN1, PS3_2_FN2,
+       PS3_1_FN1, PS3_1_FN2,
 
-       PS2_13_FN1, PS2_13_FN3,
-       PS2_12_FN1, PS2_12_FN3,
-       PS2_1_FN1, PS2_1_FN2,
-       PS2_0_FN1, PS2_0_FN2,
-
-       PS4_15_FN1, PS4_15_FN2,
        PS4_14_FN1, PS4_14_FN2,
        PS4_13_FN1, PS4_13_FN2,
        PS4_12_FN1, PS4_12_FN2,
-       PS4_11_FN1, PS4_11_FN2,
        PS4_10_FN1, PS4_10_FN2,
        PS4_9_FN1, PS4_9_FN2,
+       PS4_8_FN1, PS4_8_FN2,
+       PS4_4_FN1, PS4_4_FN2,
        PS4_3_FN1, PS4_3_FN2,
        PS4_2_FN1, PS4_2_FN2,
        PS4_1_FN1, PS4_1_FN2,
        PS4_0_FN1, PS4_0_FN2,
 
+       PS5_11_FN1, PS5_11_FN2,
+       PS5_10_FN1, PS5_10_FN2,
        PS5_9_FN1, PS5_9_FN2,
        PS5_8_FN1, PS5_8_FN2,
        PS5_7_FN1, PS5_7_FN2,
        PS5_6_FN1, PS5_6_FN2,
        PS5_5_FN1, PS5_5_FN2,
        PS5_4_FN1, PS5_4_FN2,
-
-       /* AN15 to 8 : EVENT15 to 8 */
-       PS6_7_FN_AN, PS6_7_FN_EV,
-       PS6_6_FN_AN, PS6_6_FN_EV,
-       PS6_5_FN_AN, PS6_5_FN_EV,
-       PS6_4_FN_AN, PS6_4_FN_EV,
-       PS6_3_FN_AN, PS6_3_FN_EV,
-       PS6_2_FN_AN, PS6_2_FN_EV,
-       PS6_1_FN_AN, PS6_1_FN_EV,
-       PS6_0_FN_AN, PS6_0_FN_EV,
-
+       PS5_3_FN1, PS5_3_FN2,
+       PS5_2_FN1, PS5_2_FN2,
+
+       PS6_15_FN1, PS6_15_FN2,
+       PS6_14_FN1, PS6_14_FN2,
+       PS6_13_FN1, PS6_13_FN2,
+       PS6_12_FN1, PS6_12_FN2,
+       PS6_11_FN1, PS6_11_FN2,
+       PS6_10_FN1, PS6_10_FN2,
+       PS6_9_FN1, PS6_9_FN2,
+       PS6_8_FN1, PS6_8_FN2,
+       PS6_7_FN1, PS6_7_FN2,
+       PS6_6_FN1, PS6_6_FN2,
+       PS6_5_FN1, PS6_5_FN2,
+       PS6_4_FN1, PS6_4_FN2,
+       PS6_3_FN1, PS6_3_FN2,
+       PS6_2_FN1, PS6_2_FN2,
+       PS6_1_FN1, PS6_1_FN2,
+       PS6_0_FN1, PS6_0_FN2,
+
+       PS7_15_FN1, PS7_15_FN2,
+       PS7_14_FN1, PS7_14_FN2,
+       PS7_13_FN1, PS7_13_FN2,
+       PS7_12_FN1, PS7_12_FN2,
+       PS7_11_FN1, PS7_11_FN2,
+       PS7_10_FN1, PS7_10_FN2,
+       PS7_9_FN1, PS7_9_FN2,
+       PS7_8_FN1, PS7_8_FN2,
+       PS7_7_FN1, PS7_7_FN2,
+       PS7_6_FN1, PS7_6_FN2,
+       PS7_5_FN1, PS7_5_FN2,
+       PS7_4_FN1, PS7_4_FN2,
+
+       PS8_15_FN1, PS8_15_FN2,
+       PS8_14_FN1, PS8_14_FN2,
+       PS8_13_FN1, PS8_13_FN2,
+       PS8_12_FN1, PS8_12_FN2,
+       PS8_11_FN1, PS8_11_FN2,
+       PS8_10_FN1, PS8_10_FN2,
+       PS8_9_FN1, PS8_9_FN2,
+       PS8_8_FN1, PS8_8_FN2,
        PINMUX_FUNCTION_END,
 
        PINMUX_MARK_BEGIN,
-       /* PTA (mobule: LBSC, CPG, LPC) */
+       /* PTA (mobule: LBSC, RGMII) */
        BS_MARK,        RDWR_MARK,      WE1_MARK,       RDY_MARK,
-       MD10_MARK,      MD9_MARK,       MD8_MARK,
-       LGPIO7_MARK,    LGPIO6_MARK,    LGPIO5_MARK,    LGPIO4_MARK,
-       LGPIO3_MARK,    LGPIO2_MARK,    LGPIO1_MARK,    LGPIO0_MARK,
-
-       /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-       D15_MARK,       D14_MARK,       D13_MARK,       D12_MARK,
-       D11_MARK,       D10_MARK,       D9_MARK,        D8_MARK,
        ET0_MDC_MARK,   ET0_MDIO_MARK,  ET1_MDC_MARK,   ET1_MDIO_MARK,
-       SIM_D_MARK,     SIM_CLK_MARK,   SIM_RST_MARK,
-       WPSZ1_MARK,     WPSZ0_MARK,     FWID_MARK,      FLSHSZ_MARK,
-       LPC_SPIEN_MARK, BASEL_MARK,
 
-       /* PTC (mobule: SD) */
-       SD_WP_MARK,     SD_CD_MARK,     SD_CLK_MARK,    SD_CMD_MARK,
-       SD_D3_MARK,     SD_D2_MARK,     SD_D1_MARK,     SD_D0_MARK,
+       /* PTB (mobule: INTC, ONFI, TMU) */
+       IRQ15_MARK,     IRQ14_MARK,     IRQ13_MARK,     IRQ12_MARK,
+       IRQ11_MARK,     IRQ10_MARK,     IRQ9_MARK,      IRQ8_MARK,
+       ON_NRE_MARK,    ON_NWE_MARK,    ON_NWP_MARK,    ON_NCE0_MARK,
+       ON_R_B0_MARK,   ON_ALE_MARK,    ON_CLE_MARK,    TCLK_MARK,
 
-       /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+       /* PTC (mobule: IRQ, PWMU) */
        IRQ7_MARK,      IRQ6_MARK,      IRQ5_MARK,      IRQ4_MARK,
        IRQ3_MARK,      IRQ2_MARK,      IRQ1_MARK,      IRQ0_MARK,
-       MD6_MARK,       MD5_MARK,       MD3_MARK,       MD2_MARK,
-       MD1_MARK,       MD0_MARK,       ADTRG1_MARK,    ADTRG0_MARK,
-
-       /* PTE (mobule: EtherC) */
-       ET0_CRS_DV_MARK,        ET0_TXD1_MARK,
-       ET0_TXD0_MARK,          ET0_TX_EN_MARK,
-       ET0_REF_CLK_MARK,       ET0_RXD1_MARK,
-       ET0_RXD0_MARK,          ET0_RX_ER_MARK,
-
-       /* PTF (mobule: EtherC) */
-       ET1_CRS_DV_MARK,        ET1_TXD1_MARK,
-       ET1_TXD0_MARK,          ET1_TX_EN_MARK,
-       ET1_REF_CLK_MARK,       ET1_RXD1_MARK,
-       ET1_RXD0_MARK,          ET1_RX_ER_MARK,
-
-       /* PTG (mobule: SYSTEM, PWMX, LPC) */
-       STATUS0_MARK,   STATUS1_MARK,
-       PWX0_MARK,      PWX1_MARK,      PWX2_MARK,      PWX3_MARK,
-       SERIRQ_MARK,    CLKRUN_MARK,    LPCPD_MARK,     LDRQ_MARK,
-
-       /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-       TCLK_MARK,      RXD4_MARK,      TXD4_MARK,
+       PWMU0_MARK,     PWMU1_MARK,     PWMU2_MARK,     PWMU3_MARK,
+       PWMU4_MARK,     PWMU5_MARK,
+
+       /* PTD (mobule: SPI0, DMAC) */
+       SP0_MOSI_MARK,  SP0_MISO_MARK,  SP0_SCK_MARK,   SP0_SCK_FB_MARK,
+       SP0_SS0_MARK,   SP0_SS1_MARK,   SP0_SS2_MARK,   SP0_SS3_MARK,
+       DREQ0_MARK,     DACK0_MARK,     TEND0_MARK,
+
+       /* PTE (mobule: RMII) */
+       RMII0_CRS_DV_MARK,      RMII0_TXD1_MARK,
+       RMII0_TXD0_MARK,        RMII0_TXEN_MARK,
+       RMII0_REFCLK_MARK,      RMII0_RXD1_MARK,
+       RMII0_RXD0_MARK,        RMII0_RX_ER_MARK,
+
+       /* PTF (mobule: RMII, SerMux) */
+       RMII1_CRS_DV_MARK,      RMII1_TXD1_MARK,
+       RMII1_TXD0_MARK,        RMII1_TXEN_MARK,
+       RMII1_REFCLK_MARK,      RMII1_RXD1_MARK,
+       RMII1_RXD0_MARK,        RMII1_RX_ER_MARK,
+       RAC_RI_MARK,
+
+       /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+       BOOTFMS_MARK,   BOOTWP_MARK,    A25_MARK,       A24_MARK,
+       SERIRQ_MARK,    WDTOVF_MARK,    LPCPD_MARK,     LDRQ_MARK,
+       MMCCLK_MARK,    MMCCMD_MARK,
+
+       /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
        SP1_MOSI_MARK,  SP1_MISO_MARK,  SP1_SCK_MARK,   SP1_SCK_FB_MARK,
-       SP1_SS0_MARK,   SP1_SS1_MARK,   SP0_SS1_MARK,
+       SP1_SS0_MARK,   SP1_SS1_MARK,   WP_MARK,        FMS0_MARK,
+       TEND1_MARK,     DREQ1_MARK,     DACK1_MARK,     ADTRG1_MARK,
+       ADTRG0_MARK,
 
-       /* PTI (mobule: INTC) */
-       IRQ15_MARK,     IRQ14_MARK,     IRQ13_MARK,     IRQ12_MARK,
-       IRQ11_MARK,     IRQ10_MARK,     IRQ9_MARK,      IRQ8_MARK,
+       /* PTI (mobule: LBSC, SDHI) */
+       D15_MARK,       D14_MARK,       D13_MARK,       D12_MARK,
+       D11_MARK,       D10_MARK,       D9_MARK,        D8_MARK,
+       SD_WP_MARK,     SD_CD_MARK,     SD_CLK_MARK,    SD_CMD_MARK,
+       SD_D3_MARK,     SD_D2_MARK,     SD_D1_MARK,     SD_D0_MARK,
 
-       /* PTJ (mobule: SCIF234, SERMUX) */
-       RXD3_MARK,      TXD3_MARK,      RXD2_MARK,      TXD2_MARK,
-       COM1_TXD_MARK,  COM1_RXD_MARK,  COM1_RTS_MARK,  COM1_CTS_MARK,
+       /* PTJ (mobule: SCIF234) */
+       RTS3_MARK,      CTS3_MARK,      TXD3_MARK,      RXD3_MARK,
+       RTS4_MARK,      RXD4_MARK,      TXD4_MARK,
 
-       /* PTK (mobule: SERMUX) */
+       /* PTK (mobule: SERMUX, LBSC, SCIF) */
        COM2_TXD_MARK,  COM2_RXD_MARK,  COM2_RTS_MARK,  COM2_CTS_MARK,
-       COM2_DTR_MARK,  COM2_DSR_MARK,  COM2_DCD_MARK,  COM2_RI_MARK,
+       COM2_DTR_MARK,  COM2_DSR_MARK,  COM2_DCD_MARK,  CLKOUT_MARK,
+       SCK2_MARK,      SCK4_MARK,      SCK3_MARK,
 
-       /* PTL (mobule: SERMUX) */
-       RAC_TXD_MARK,   RAC_RXD_MARK,   RAC_RTS_MARK,   RAC_CTS_MARK,
-       RAC_DTR_MARK,   RAC_DSR_MARK,   RAC_DCD_MARK,   RAC_RI_MARK,
+       /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+       RAC_RXD_MARK,   RAC_RTS_MARK,   RAC_CTS_MARK,   RAC_DTR_MARK,
+       RAC_DSR_MARK,   RAC_DCD_MARK,   RAC_TXD_MARK,   RXD2_MARK,
+       CS5_MARK,       CS6_MARK,       AUDSYNC_MARK,   AUDCK_MARK,
+       TXD2_MARK,
 
-       /* PTM (mobule: IIC, LPC) */
+       /* PTM (mobule: LBSC, IIC) */
+       CS4_MARK,       RD_MARK,        WE0_MARK,       CS0_MARK,
        SDA6_MARK,      SCL6_MARK,      SDA7_MARK,      SCL7_MARK,
-       WP_MARK,        FMS0_MARK,      FMS1_MARK,
 
-       /* PTN (mobule: SCIF234, EVC) */
-       SCK2_MARK,      RTS4_MARK,      RTS3_MARK,      RTS2_MARK,
-       CTS4_MARK,      CTS3_MARK,      CTS2_MARK,
-       EVENT7_MARK,    EVENT6_MARK,    EVENT5_MARK,    EVENT4_MARK,
-       EVENT3_MARK,    EVENT2_MARK,    EVENT1_MARK,    EVENT0_MARK,
+       /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+       VBUS_EN_MARK,   VBUS_OC_MARK,   JMCTCK_MARK,    JMCTMS_MARK,
+       JMCTDO_MARK,    JMCTDI_MARK,    JMCTRST_MARK,
+       SGPIO1_CLK_MARK,        SGPIO1_LOAD_MARK,       SGPIO1_DI_MARK,
+       SGPIO1_DO_MARK,         SUB_CLKIN_MARK,
 
-       /* PTO (mobule: SGPIO) */
-       SGPIO0_CLK_MARK,        SGPIO0_LOAD_MARK,
-       SGPIO0_DI_MARK,         SGPIO0_DO_MARK,
-       SGPIO1_CLK_MARK,        SGPIO1_LOAD_MARK,
-       SGPIO1_DI_MARK,         SGPIO1_DO_MARK,
-
-       /* PTP (mobule: JMC, SCIF234) */
-       JMCTCK_MARK,    JMCTMS_MARK,    JMCTDO_MARK,    JMCTDI_MARK,
-       JMCRST_MARK,    SCK4_MARK,      SCK3_MARK,
+       /* PTO (mobule: SGPIO, SerMux) */
+       SGPIO0_CLK_MARK,        SGPIO0_LOAD_MARK,       SGPIO0_DI_MARK,
+       SGPIO0_DO_MARK,         SGPIO2_CLK_MARK,        SGPIO2_LOAD_MARK,
+       SGPIO2_DI_MARK,         SGPIO2_DO_MARK,
+       COM1_TXD_MARK,  COM1_RXD_MARK,  COM1_RTS_MARK,  COM1_CTS_MARK,
 
        /* PTQ (mobule: LPC) */
        LAD3_MARK,      LAD2_MARK,      LAD1_MARK,      LAD0_MARK,
        LFRAME_MARK,    LRESET_MARK,    LCLK_MARK,
 
        /* PTR (mobule: GRA, IIC) */
-       DDC3_MARK,      DDC2_MARK,
-       SDA8_MARK,      SCL8_MARK,      SDA2_MARK,      SCL2_MARK,
+       DDC3_MARK,      DDC2_MARK,      SDA2_MARK,      SCL2_MARK,
        SDA1_MARK,      SCL1_MARK,      SDA0_MARK,      SCL0_MARK,
+       SDA8_MARK,      SCL8_MARK,
 
        /* PTS (mobule: GRA, IIC) */
-       DDC1_MARK,      DDC0_MARK,
-       SDA9_MARK,      SCL9_MARK,      SDA5_MARK,      SCL5_MARK,
+       DDC1_MARK,      DDC0_MARK,      SDA5_MARK,      SCL5_MARK,
        SDA4_MARK,      SCL4_MARK,      SDA3_MARK,      SCL3_MARK,
+       SDA9_MARK,      SCL9_MARK,
 
-       /* PTT (mobule: SYSTEM, PWMX) */
-       AUDSYNC_MARK,           AUDCK_MARK,
-       AUDATA3_MARK,           AUDATA2_MARK,
-       AUDATA1_MARK,           AUDATA0_MARK,
-       PWX7_MARK,      PWX6_MARK,      PWX5_MARK,      PWX4_MARK,
+       /* PTT (mobule: PWMX, AUD) */
+       PWMX7_MARK,     PWMX6_MARK,     PWMX5_MARK,     PWMX4_MARK,
+       PWMX3_MARK,     PWMX2_MARK,     PWMX1_MARK,     PWMX0_MARK,
+       AUDATA3_MARK,   AUDATA2_MARK,   AUDATA1_MARK,   AUDATA0_MARK,
+       STATUS1_MARK,   STATUS0_MARK,
 
-       /* PTU (mobule: LBSC, DMAC) */
-       CS6_MARK,       CS5_MARK,       CS4_MARK,       CS0_MARK,
-       RD_MARK,        WE0_MARK,       A25_MARK,       A24_MARK,
-       DREQ0_MARK,     DACK0_MARK,
+       /* PTU (mobule: LPC, APM) */
+       LGPIO7_MARK,    LGPIO6_MARK,    LGPIO5_MARK,    LGPIO4_MARK,
+       LGPIO3_MARK,    LGPIO2_MARK,    LGPIO1_MARK,    LGPIO0_MARK,
+       APMONCTL_O_MARK,        APMPWBTOUT_O_MARK,      APMSCI_O_MARK,
+       APMVDDON_MARK,  APMSLPBTN_MARK, APMPWRBTN_MARK, APMS5N_MARK,
+       APMS3N_MARK,
 
-       /* PTV (mobule: LBSC, DMAC) */
+       /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
        A23_MARK,       A22_MARK,       A21_MARK,       A20_MARK,
        A19_MARK,       A18_MARK,       A17_MARK,       A16_MARK,
-       TEND0_MARK,     DREQ1_MARK,     DACK1_MARK,     TEND1_MARK,
+       COM2_RI_MARK,           R_SPI_MOSI_MARK,        R_SPI_MISO_MARK,
+       R_SPI_RSPCK_MARK,       R_SPI_SSL0_MARK,        R_SPI_SSL1_MARK,
+       EVENT7_MARK,    EVENT6_MARK,    VBIOS_DI_MARK,  VBIOS_DO_MARK,
+       VBIOS_CLK_MARK, VBIOS_CS_MARK,
 
-       /* PTW (mobule: LBSC) */
+       /* PTW (mobule: LBSC, EVC, SCIF) */
        A15_MARK,       A14_MARK,       A13_MARK,       A12_MARK,
        A11_MARK,       A10_MARK,       A9_MARK,        A8_MARK,
+       EVENT5_MARK,    EVENT4_MARK,    EVENT3_MARK,    EVENT2_MARK,
+       EVENT1_MARK,    EVENT0_MARK,    CTS4_MARK,      CTS2_MARK,
 
-       /* PTX (mobule: LBSC) */
+       /* PTX (mobule: LBSC, SCIF, SIM) */
        A7_MARK,        A6_MARK,        A5_MARK,        A4_MARK,
        A3_MARK,        A2_MARK,        A1_MARK,        A0_MARK,
+       RTS2_MARK,      SIM_D_MARK,     SIM_CLK_MARK,   SIM_RST_MARK,
 
        /* PTY (mobule: LBSC) */
        D7_MARK,        D6_MARK,        D5_MARK,        D4_MARK,
        D3_MARK,        D2_MARK,        D1_MARK,        D0_MARK,
+
+       /* PTZ (mobule: eMMC, ONFI) */
+       MMCDAT7_MARK,   MMCDAT6_MARK,   MMCDAT5_MARK,   MMCDAT4_MARK,
+       MMCDAT3_MARK,   MMCDAT2_MARK,   MMCDAT1_MARK,   MMCDAT0_MARK,
+       ON_DQ7_MARK,    ON_DQ6_MARK,    ON_DQ5_MARK,    ON_DQ4_MARK,
+       ON_DQ3_MARK,    ON_DQ2_MARK,    ON_DQ1_MARK,    ON_DQ0_MARK,
+
        PINMUX_MARK_END,
 };
 
@@ -473,6 +567,8 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
 
        /* PTE GPIO */
+       PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+       PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
        PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
        PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
        PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
@@ -521,7 +617,6 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
 
        /* PTJ GPIO */
-       PINMUX_DATA(PTJ7_DATA, PTJ7_IN, PTJ7_OUT),
        PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
        PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
        PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
@@ -541,7 +636,6 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
 
        /* PTL GPIO */
-       PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
        PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
        PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
        PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
@@ -560,7 +654,6 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
 
        /* PTN GPIO */
-       PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
        PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
        PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
        PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
@@ -609,6 +702,8 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
 
        /* PTT GPIO */
+       PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+       PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
        PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
        PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
        PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
@@ -677,186 +772,204 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
 
        /* PTA FN */
-       PINMUX_DATA(BS_MARK, PS0_15_FN1, PTA7_FN),
-       PINMUX_DATA(LGPIO7_MARK, PS0_15_FN3, PTA7_FN),
-       PINMUX_DATA(RDWR_MARK, PS0_14_FN1, PTA6_FN),
-       PINMUX_DATA(LGPIO6_MARK, PS0_14_FN3, PTA6_FN),
-       PINMUX_DATA(WE1_MARK, PS0_13_FN1, PTA5_FN),
-       PINMUX_DATA(LGPIO5_MARK, PS0_13_FN3, PTA5_FN),
-       PINMUX_DATA(RDY_MARK, PS0_12_FN1, PTA4_FN),
-       PINMUX_DATA(LGPIO4_MARK, PS0_12_FN3, PTA4_FN),
-       PINMUX_DATA(LGPIO3_MARK, PTA3_FN),
-       PINMUX_DATA(LGPIO2_MARK, PTA2_FN),
-       PINMUX_DATA(LGPIO1_MARK, PTA1_FN),
-       PINMUX_DATA(LGPIO0_MARK, PTA0_FN),
+       PINMUX_DATA(BS_MARK, PTA7_FN),
+       PINMUX_DATA(RDWR_MARK, PTA6_FN),
+       PINMUX_DATA(WE1_MARK, PTA5_FN),
+       PINMUX_DATA(RDY_MARK, PTA4_FN),
+       PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
+       PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
+       PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
+       PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
 
        /* PTB FN */
-       PINMUX_DATA(D15_MARK, PS0_7_FN1, PTB7_FN),
-       PINMUX_DATA(ET0_MDC_MARK, PS0_7_FN2, PTB7_FN),
-       PINMUX_DATA(D14_MARK, PS0_6_FN1, PTB6_FN),
-       PINMUX_DATA(ET0_MDIO_MARK, PS0_6_FN2, PTB6_FN),
-       PINMUX_DATA(D13_MARK, PS0_5_FN1, PTB5_FN),
-       PINMUX_DATA(ET1_MDC_MARK, PS0_5_FN2, PTB5_FN),
-       PINMUX_DATA(D12_MARK, PS0_4_FN1, PTB4_FN),
-       PINMUX_DATA(ET1_MDIO_MARK, PS0_4_FN2, PTB4_FN),
-       PINMUX_DATA(D11_MARK, PS0_3_FN1, PTB3_FN),
-       PINMUX_DATA(SIM_D_MARK, PS0_3_FN2, PTB3_FN),
-       PINMUX_DATA(D10_MARK, PS0_2_FN1, PTB2_FN),
-       PINMUX_DATA(SIM_CLK_MARK, PS0_2_FN2, PTB2_FN),
-       PINMUX_DATA(D9_MARK, PS0_1_FN1, PTB1_FN),
-       PINMUX_DATA(SIM_RST_MARK, PS0_1_FN2, PTB1_FN),
-       PINMUX_DATA(D8_MARK, PTB0_FN),
+       PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
+       PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
+       PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
+       PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
+       PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
+       PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
+       PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
+       PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
+       PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
+       PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
+       PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
+       PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
+       PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
+       PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
+       PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
+       PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
 
        /* PTC FN */
-       PINMUX_DATA(SD_WP_MARK, PTC7_FN),
-       PINMUX_DATA(SD_CD_MARK, PTC6_FN),
-       PINMUX_DATA(SD_CLK_MARK, PTC5_FN),
-       PINMUX_DATA(SD_CMD_MARK, PTC4_FN),
-       PINMUX_DATA(SD_D3_MARK, PTC3_FN),
-       PINMUX_DATA(SD_D2_MARK, PTC2_FN),
-       PINMUX_DATA(SD_D1_MARK, PTC1_FN),
-       PINMUX_DATA(SD_D0_MARK, PTC0_FN),
+       PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
+       PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
+       PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
+       PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
+       PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
+       PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
+       PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
+       PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
+       PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
+       PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
+       PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
+       PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
+       PINMUX_DATA(IRQ1_MARK, PTC1_FN),
+       PINMUX_DATA(IRQ0_MARK, PTC0_FN),
 
        /* PTD FN */
-       PINMUX_DATA(IRQ7_MARK, PS1_7_FN1, PTD7_FN),
-       PINMUX_DATA(ADTRG1_MARK, PS1_7_FN3, PTD7_FN),
-       PINMUX_DATA(IRQ6_MARK, PS1_6_FN1, PTD6_FN),
-       PINMUX_DATA(ADTRG0_MARK, PS1_6_FN3, PTD6_FN),
-       PINMUX_DATA(IRQ5_MARK, PTD5_FN),
-       PINMUX_DATA(IRQ4_MARK, PTD4_FN),
-       PINMUX_DATA(IRQ3_MARK, PTD3_FN),
-       PINMUX_DATA(IRQ2_MARK, PTD2_FN),
-       PINMUX_DATA(IRQ1_MARK, PTD1_FN),
-       PINMUX_DATA(IRQ0_MARK, PTD0_FN),
+       PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
+       PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
+       PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
+       PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
+       PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
+       PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
+       PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
+       PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
+       PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
+       PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
+       PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
 
        /* PTE FN */
-       PINMUX_DATA(ET0_CRS_DV_MARK, PTE7_FN),
-       PINMUX_DATA(ET0_TXD1_MARK, PTE6_FN),
-       PINMUX_DATA(ET0_TXD0_MARK, PTE5_FN),
-       PINMUX_DATA(ET0_TX_EN_MARK, PTE4_FN),
-       PINMUX_DATA(ET0_REF_CLK_MARK, PTE3_FN),
-       PINMUX_DATA(ET0_RXD1_MARK, PTE2_FN),
-       PINMUX_DATA(ET0_RXD0_MARK, PTE1_FN),
-       PINMUX_DATA(ET0_RX_ER_MARK, PTE0_FN),
+       PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
+       PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
+       PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
+       PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
+       PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
+       PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
+       PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
+       PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
 
        /* PTF FN */
-       PINMUX_DATA(ET1_CRS_DV_MARK, PTF7_FN),
-       PINMUX_DATA(ET1_TXD1_MARK, PTF6_FN),
-       PINMUX_DATA(ET1_TXD0_MARK, PTF5_FN),
-       PINMUX_DATA(ET1_TX_EN_MARK, PTF4_FN),
-       PINMUX_DATA(ET1_REF_CLK_MARK, PTF3_FN),
-       PINMUX_DATA(ET1_RXD1_MARK, PTF2_FN),
-       PINMUX_DATA(ET1_RXD0_MARK, PTF1_FN),
-       PINMUX_DATA(ET1_RX_ER_MARK, PTF0_FN),
+       PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
+       PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
+       PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
+       PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
+       PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
+       PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
+       PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
+       PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
+       PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
 
        /* PTG FN */
-       PINMUX_DATA(PWX0_MARK, PTG7_FN),
-       PINMUX_DATA(PWX1_MARK, PTG6_FN),
-       PINMUX_DATA(STATUS0_MARK, PS2_13_FN1, PTG5_FN),
-       PINMUX_DATA(PWX2_MARK, PS2_13_FN3, PTG5_FN),
-       PINMUX_DATA(STATUS1_MARK, PS2_12_FN1, PTG4_FN),
-       PINMUX_DATA(PWX3_MARK, PS2_12_FN3, PTG4_FN),
+       PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
+       PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
+       PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
+       PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
+       PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
+       PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
        PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
-       PINMUX_DATA(CLKRUN_MARK, PTG2_FN),
+       PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
        PINMUX_DATA(LPCPD_MARK, PTG1_FN),
        PINMUX_DATA(LDRQ_MARK, PTG0_FN),
 
        /* PTH FN */
-       PINMUX_DATA(SP1_MOSI_MARK, PTH7_FN),
-       PINMUX_DATA(SP1_MISO_MARK, PTH6_FN),
-       PINMUX_DATA(SP1_SCK_MARK, PTH5_FN),
-       PINMUX_DATA(SP1_SCK_FB_MARK, PTH4_FN),
+       PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
+       PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
+       PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
+       PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
+       PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
+       PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
+       PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
+       PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
        PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
-       PINMUX_DATA(TCLK_MARK, PTH2_FN),
-       PINMUX_DATA(RXD4_MARK, PS2_1_FN1, PTH1_FN),
-       PINMUX_DATA(SP1_SS1_MARK, PS2_1_FN2, PTH1_FN),
-       PINMUX_DATA(TXD4_MARK, PS2_0_FN1, PTH0_FN),
-       PINMUX_DATA(SP0_SS1_MARK, PS2_0_FN2, PTH0_FN),
+       PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
+       PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
+       PINMUX_DATA(WP_MARK, PTH1_FN),
+       PINMUX_DATA(FMS0_MARK, PTH0_FN),
 
        /* PTI FN */
-       PINMUX_DATA(IRQ15_MARK, PTI7_FN),
-       PINMUX_DATA(IRQ14_MARK, PTI6_FN),
-       PINMUX_DATA(IRQ13_MARK, PTI5_FN),
-       PINMUX_DATA(IRQ12_MARK, PTI4_FN),
-       PINMUX_DATA(IRQ11_MARK, PTI3_FN),
-       PINMUX_DATA(IRQ10_MARK, PTI2_FN),
-       PINMUX_DATA(IRQ9_MARK, PTI1_FN),
-       PINMUX_DATA(IRQ8_MARK, PTI0_FN),
+       PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
+       PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
+       PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
+       PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
+       PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
+       PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
+       PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
+       PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
+       PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
+       PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
+       PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
+       PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
+       PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
+       PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
+       PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
+       PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
 
        /* PTJ FN */
-       PINMUX_DATA(RXD3_MARK, PTJ7_FN),
-       PINMUX_DATA(TXD3_MARK, PTJ6_FN),
-       PINMUX_DATA(RXD2_MARK, PTJ5_FN),
-       PINMUX_DATA(TXD2_MARK, PTJ4_FN),
-       PINMUX_DATA(COM1_TXD_MARK, PTJ3_FN),
-       PINMUX_DATA(COM1_RXD_MARK, PTJ2_FN),
-       PINMUX_DATA(COM1_RTS_MARK, PTJ1_FN),
-       PINMUX_DATA(COM1_CTS_MARK, PTJ0_FN),
+       PINMUX_DATA(RTS3_MARK, PTJ6_FN),
+       PINMUX_DATA(CTS3_MARK, PTJ5_FN),
+       PINMUX_DATA(TXD3_MARK, PTJ4_FN),
+       PINMUX_DATA(RXD3_MARK, PTJ3_FN),
+       PINMUX_DATA(RTS4_MARK, PTJ2_FN),
+       PINMUX_DATA(RXD4_MARK, PTJ1_FN),
+       PINMUX_DATA(TXD4_MARK, PTJ0_FN),
 
        /* PTK FN */
-       PINMUX_DATA(COM2_TXD_MARK, PTK7_FN),
+       PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
+       PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
        PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
        PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
        PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
        PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
-       PINMUX_DATA(COM2_DSR_MARK, PTK2_FN),
-       PINMUX_DATA(COM2_DCD_MARK, PTK1_FN),
-       PINMUX_DATA(COM2_RI_MARK, PTK0_FN),
+       PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
+       PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
+       PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
+       PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
+       PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
 
        /* PTL FN */
-       PINMUX_DATA(RAC_TXD_MARK, PTL7_FN),
-       PINMUX_DATA(RAC_RXD_MARK, PTL6_FN),
-       PINMUX_DATA(RAC_RTS_MARK, PTL5_FN),
-       PINMUX_DATA(RAC_CTS_MARK, PTL4_FN),
+       PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
+       PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
+       PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
+       PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
+       PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
+       PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
        PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
-       PINMUX_DATA(RAC_DSR_MARK, PTL2_FN),
-       PINMUX_DATA(RAC_DCD_MARK, PTL1_FN),
-       PINMUX_DATA(RAC_RI_MARK, PTL0_FN),
+       PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
+       PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
+       PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
+       PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
+       PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
+       PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
 
        /* PTM FN */
-       PINMUX_DATA(WP_MARK, PTM6_FN),
-       PINMUX_DATA(FMS0_MARK, PTM5_FN),
-       PINMUX_DATA(FMS1_MARK, PTM4_FN),
+       PINMUX_DATA(CS4_MARK, PTM7_FN),
+       PINMUX_DATA(RD_MARK, PTM6_FN),
+       PINMUX_DATA(WE0_MARK, PTM7_FN),
+       PINMUX_DATA(CS0_MARK, PTM4_FN),
        PINMUX_DATA(SDA6_MARK, PTM3_FN),
        PINMUX_DATA(SCL6_MARK, PTM2_FN),
        PINMUX_DATA(SDA7_MARK, PTM1_FN),
        PINMUX_DATA(SCL7_MARK, PTM0_FN),
 
        /* PTN FN */
-       PINMUX_DATA(SCK2_MARK, PS4_15_FN1, PTN7_FN),
-       PINMUX_DATA(EVENT7_MARK, PS4_15_FN2, PTN7_FN),
-       PINMUX_DATA(RTS4_MARK, PS4_14_FN1, PTN6_FN),
-       PINMUX_DATA(EVENT6_MARK, PS4_14_FN2, PTN6_FN),
-       PINMUX_DATA(RTS3_MARK, PS4_13_FN1, PTN5_FN),
-       PINMUX_DATA(EVENT5_MARK, PS4_13_FN2, PTN5_FN),
-       PINMUX_DATA(RTS2_MARK, PS4_12_FN1, PTN4_FN),
-       PINMUX_DATA(EVENT4_MARK, PS4_12_FN2, PTN4_FN),
-       PINMUX_DATA(CTS4_MARK, PS4_11_FN1, PTN3_FN),
-       PINMUX_DATA(EVENT3_MARK, PS4_11_FN2, PTN3_FN),
-       PINMUX_DATA(CTS3_MARK, PS4_10_FN1, PTN2_FN),
-       PINMUX_DATA(EVENT2_MARK, PS4_10_FN2, PTN2_FN),
-       PINMUX_DATA(CTS2_MARK, PS4_9_FN1, PTN1_FN),
-       PINMUX_DATA(EVENT1_MARK, PS4_9_FN2, PTN1_FN),
-       PINMUX_DATA(EVENT0_MARK, PTN0_FN),
+       PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
+       PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
+       PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
+       PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
+       PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
+       PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
+       PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
+       PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
+       PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
+       PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
+       PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
+       PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
 
        /* PTO FN */
        PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
        PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
        PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
        PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
-       PINMUX_DATA(SGPIO1_CLK_MARK, PTO3_FN),
-       PINMUX_DATA(SGPIO1_LOAD_MARK, PTO2_FN),
-       PINMUX_DATA(SGPIO1_DI_MARK, PTO1_FN),
-       PINMUX_DATA(SGPIO1_DO_MARK, PTO0_FN),
+       PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
+       PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
+       PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
+       PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
+       PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
+       PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
+       PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
+       PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
 
        /* PTP FN */
-       PINMUX_DATA(JMCTCK_MARK, PTP6_FN),
-       PINMUX_DATA(JMCTMS_MARK, PTP5_FN),
-       PINMUX_DATA(JMCTDO_MARK, PTP4_FN),
-       PINMUX_DATA(JMCTDI_MARK, PTP3_FN),
-       PINMUX_DATA(JMCRST_MARK, PTP2_FN),
-       PINMUX_DATA(SCK4_MARK, PTP1_FN),
-       PINMUX_DATA(SCK3_MARK, PTP0_FN),
 
        /* PTQ FN */
        PINMUX_DATA(LAD3_MARK, PTQ6_FN),
@@ -864,8 +977,8 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(LAD1_MARK, PTQ4_FN),
        PINMUX_DATA(LAD0_MARK, PTQ3_FN),
        PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
-       PINMUX_DATA(SCK4_MARK, PTQ1_FN),
-       PINMUX_DATA(SCK3_MARK, PTQ0_FN),
+       PINMUX_DATA(LRESET_MARK, PTQ1_FN),
+       PINMUX_DATA(LCLK_MARK, PTQ0_FN),
 
        /* PTR FN */
        PINMUX_DATA(SDA8_MARK, PTR7_FN),        /* DDC3? */
@@ -888,58 +1001,84 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(SCL3_MARK, PTS0_FN),
 
        /* PTT FN */
-       PINMUX_DATA(AUDSYNC_MARK, PTS5_FN),
-       PINMUX_DATA(AUDCK_MARK, PTS4_FN),
-       PINMUX_DATA(AUDATA3_MARK, PS4_3_FN1, PTS3_FN),
-       PINMUX_DATA(PWX7_MARK, PS4_3_FN2, PTS3_FN),
-       PINMUX_DATA(AUDATA2_MARK, PS4_2_FN1, PTS2_FN),
-       PINMUX_DATA(PWX6_MARK, PS4_2_FN2, PTS2_FN),
-       PINMUX_DATA(AUDATA1_MARK, PS4_1_FN1, PTS1_FN),
-       PINMUX_DATA(PWX5_MARK, PS4_1_FN2, PTS1_FN),
-       PINMUX_DATA(AUDATA0_MARK, PS4_0_FN1, PTS0_FN),
-       PINMUX_DATA(PWX4_MARK, PS4_0_FN2, PTS0_FN),
+       PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
+       PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
+       PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
+       PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
+       PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
+       PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
+       PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
+       PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
+       PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
+       PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
+       PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
+       PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
+       PINMUX_DATA(PWMX1_MARK, PTT1_FN),
+       PINMUX_DATA(PWMX0_MARK, PTT0_FN),
 
        /* PTU FN */
-       PINMUX_DATA(CS6_MARK, PTU7_FN),
-       PINMUX_DATA(CS5_MARK, PTU6_FN),
-       PINMUX_DATA(CS4_MARK, PTU5_FN),
-       PINMUX_DATA(CS0_MARK, PTU4_FN),
-       PINMUX_DATA(RD_MARK, PTU3_FN),
-       PINMUX_DATA(WE0_MARK, PTU2_FN),
-       PINMUX_DATA(A25_MARK, PS5_9_FN1, PTU1_FN),
-       PINMUX_DATA(DREQ0_MARK, PS5_9_FN2, PTU1_FN),
-       PINMUX_DATA(A24_MARK, PS5_8_FN1, PTU0_FN),
-       PINMUX_DATA(DACK0_MARK, PS5_8_FN2, PTU0_FN),
+       PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
+       PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
+       PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
+       PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
+       PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
+       PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
+       PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
+       PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
+       PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
+       PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
+       PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
+       PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
+       PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
+       PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
+       PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
+       PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
 
        /* PTV FN */
-       PINMUX_DATA(A23_MARK, PS5_7_FN1, PTV7_FN),
-       PINMUX_DATA(TEND0_MARK, PS5_7_FN2, PTV7_FN),
-       PINMUX_DATA(A22_MARK, PS5_6_FN1, PTV6_FN),
-       PINMUX_DATA(DREQ1_MARK, PS5_6_FN2, PTV6_FN),
-       PINMUX_DATA(A21_MARK, PS5_5_FN1, PTV5_FN),
-       PINMUX_DATA(DACK1_MARK, PS5_5_FN2, PTV5_FN),
-       PINMUX_DATA(A20_MARK, PS5_4_FN1, PTV4_FN),
-       PINMUX_DATA(TEND1_MARK, PS5_4_FN2, PTV4_FN),
-       PINMUX_DATA(A19_MARK, PTV3_FN),
-       PINMUX_DATA(A18_MARK, PTV2_FN),
-       PINMUX_DATA(A17_MARK, PTV1_FN),
-       PINMUX_DATA(A16_MARK, PTV0_FN),
+       PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
+       PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
+       PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
+       PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
+       PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
+       PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
+       PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
+       PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
+       PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
+       PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
+       PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
+       PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
+       PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
+       PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
+       PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
+       PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
 
        /* PTW FN */
-       PINMUX_DATA(A15_MARK, PTW7_FN),
-       PINMUX_DATA(A14_MARK, PTW6_FN),
-       PINMUX_DATA(A13_MARK, PTW5_FN),
-       PINMUX_DATA(A12_MARK, PTW4_FN),
-       PINMUX_DATA(A11_MARK, PTW3_FN),
-       PINMUX_DATA(A10_MARK, PTW2_FN),
-       PINMUX_DATA(A9_MARK, PTW1_FN),
-       PINMUX_DATA(A8_MARK, PTW0_FN),
+       PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
+       PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
+       PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
+       PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
+       PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
+       PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
+       PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
+       PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
+       PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
+       PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
+       PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
+       PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
+       PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
+       PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
+       PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
+       PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
 
        /* PTX FN */
-       PINMUX_DATA(A7_MARK, PTX7_FN),
-       PINMUX_DATA(A6_MARK, PTX6_FN),
-       PINMUX_DATA(A5_MARK, PTX5_FN),
-       PINMUX_DATA(A4_MARK, PTX4_FN),
+       PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
+       PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
+       PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
+       PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
+       PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
+       PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
+       PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
+       PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
        PINMUX_DATA(A3_MARK, PTX3_FN),
        PINMUX_DATA(A2_MARK, PTX2_FN),
        PINMUX_DATA(A1_MARK, PTX1_FN),
@@ -954,6 +1093,24 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(D2_MARK, PTY2_FN),
        PINMUX_DATA(D1_MARK, PTY1_FN),
        PINMUX_DATA(D0_MARK, PTY0_FN),
+
+       /* PTZ FN */
+       PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
+       PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
+       PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
+       PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
+       PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
+       PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
+       PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
+       PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
+       PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
+       PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
+       PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
+       PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
+       PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
+       PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
+       PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
+       PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
 };
 
 static struct pinmux_gpio pinmux_gpios[] = {
@@ -1048,7 +1205,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
 
        /* PTJ */
-       PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
        PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
        PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
        PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
@@ -1068,7 +1224,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
 
        /* PTL */
-       PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
        PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
        PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
        PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
@@ -1078,6 +1233,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
 
        /* PTM */
+       PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
        PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
        PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
        PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
@@ -1087,7 +1243,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
 
        /* PTN */
-       PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
        PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
        PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
        PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
@@ -1107,6 +1262,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
 
        /* PTP */
+       PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
        PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
        PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
        PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
@@ -1145,6 +1301,8 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
 
        /* PTT */
+       PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+       PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
        PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
        PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
        PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
@@ -1212,54 +1370,35 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
        PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
 
-       /* PTA (mobule: LBSC, CPG, LPC) */
+       /* PTA (mobule: LBSC, RGMII) */
        PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
        PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
        PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
        PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
-       PINMUX_GPIO(GPIO_FN_MD10, MD10_MARK),
-       PINMUX_GPIO(GPIO_FN_MD9, MD9_MARK),
-       PINMUX_GPIO(GPIO_FN_MD8, MD8_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
-       PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
-
-       /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-       PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
-       PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
-       PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
-       PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
-       PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
-       PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
-       PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
-       PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
        PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDIO_MARK),
+       PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDC_MARK),
        PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDIO_MARK),
-       PINMUX_GPIO(GPIO_FN_WPSZ1, WPSZ1_MARK),
-       PINMUX_GPIO(GPIO_FN_WPSZ0, WPSZ0_MARK),
-       PINMUX_GPIO(GPIO_FN_FWID, FWID_MARK),
-       PINMUX_GPIO(GPIO_FN_FLSHSZ, FLSHSZ_MARK),
-       PINMUX_GPIO(GPIO_FN_LPC_SPIEN, LPC_SPIEN_MARK),
-       PINMUX_GPIO(GPIO_FN_BASEL, BASEL_MARK),
-
-       /* PTC (mobule: SD) */
-       PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
-       PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
+       PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDC_MARK),
 
-       /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+       /* PTB (mobule: INTC, ONFI, TMU) */
+       PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+
+       /* PTC (mobule: IRQ, PWMU) */
        PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
        PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
        PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
@@ -1268,80 +1407,102 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
        PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
        PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
-       PINMUX_GPIO(GPIO_FN_MD6, MD6_MARK),
-       PINMUX_GPIO(GPIO_FN_MD5, MD5_MARK),
-       PINMUX_GPIO(GPIO_FN_MD3, MD3_MARK),
-       PINMUX_GPIO(GPIO_FN_MD2, MD2_MARK),
-       PINMUX_GPIO(GPIO_FN_MD1, MD1_MARK),
-       PINMUX_GPIO(GPIO_FN_MD0, MD0_MARK),
-       PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
-       PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
+
+       /* PTD (mobule: SPI0, DMAC) */
+       PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
+       PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
 
-       /* PTE (mobule: EtherC) */
-       PINMUX_GPIO(GPIO_FN_ET0_CRS_DV, ET0_CRS_DV_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_TXD1, ET0_TXD1_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_TXD0, ET0_TXD0_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_TX_EN, ET0_TX_EN_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_REF_CLK, ET0_REF_CLK_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_RXD1, ET0_RXD1_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_RXD0, ET0_RXD0_MARK),
-       PINMUX_GPIO(GPIO_FN_ET0_RX_ER, ET0_RX_ER_MARK),
-
-       /* PTF (mobule: EtherC) */
-       PINMUX_GPIO(GPIO_FN_ET1_CRS_DV, ET1_CRS_DV_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_TXD1, ET1_TXD1_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_TXD0, ET1_TXD0_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_TX_EN, ET1_TX_EN_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_REF_CLK, ET1_REF_CLK_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_RXD1, ET1_RXD1_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_RXD0, ET1_RXD0_MARK),
-       PINMUX_GPIO(GPIO_FN_ET1_RX_ER, ET1_RX_ER_MARK),
-
-       /* PTG (mobule: SYSTEM, PWMX, LPC) */
-       PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
-       PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX0, PWX0_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX1, PWX1_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX2, PWX2_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX3, PWX3_MARK),
+       /* PTE (mobule: RMII) */
+       PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
+
+       /* PTF (mobule: RMII, SerMux) */
+       PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
+       PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+
+       /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+       PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
+       PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
+       PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+       PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
        PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
-       PINMUX_GPIO(GPIO_FN_CLKRUN, CLKRUN_MARK),
+       PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
        PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
        PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
 
-       /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-       PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
-       PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
-       PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+       /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
        PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
        PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
        PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
        PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
        PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
        PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
-       PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+       PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
+       PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
+       PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
+       PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
 
-       /* PTI (mobule: INTC) */
-       PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
-       PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+       /* PTI (mobule: LBSC, SDHI) */
+       PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+       PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+       PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+       PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+       PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+       PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+       PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+       PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
+       PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
 
        /* PTJ (mobule: SCIF234, SERMUX) */
-       PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
        PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
-       PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
-       PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
-       PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
-       PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
-       PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
-       PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
 
-       /* PTK (mobule: SERMUX) */
+       /* PTK (mobule: SERMUX, LBSC, SCIF) */
        PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
        PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
        PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
@@ -1349,62 +1510,65 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
        PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
        PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
-       PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+       PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
 
-       /* PTL (mobule: SERMUX) */
-       PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+       /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
        PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
        PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
        PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
        PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
        PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
        PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
-       PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+       PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+       PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
 
-       /* PTM (mobule: IIC, LPC) */
+       /* PTM (mobule: LBSC, IIC) */
+       PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+       PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+       PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
+       PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
        PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
        PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
        PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
        PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
-       PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
-       PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
-       PINMUX_GPIO(GPIO_FN_FMS1, FMS1_MARK),
 
-       /* PTN (mobule: SCIF234, EVC) */
-       PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
-       PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
-       PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
-       PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
-       PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
-       PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
-       PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
-       PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+       /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+       PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
+       PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
+       PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
+       PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
+       PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
+       PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
+       PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+       PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
 
-       /* PTO (mobule: SGPIO) */
+       /* PTO (mobule: SGPIO, SerMux) */
        PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
        PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
        PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
        PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
-       PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
-       PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
-       PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
-       PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
+       PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
+       PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
+       PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
 
-       /* PTP (mobule: JMC, SCIF234) */
-       PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
-       PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
-       PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
-       PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
-       PINMUX_GPIO(GPIO_FN_JMCRST, JMCRST_MARK),
-       PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
-       PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+       /* PTP (mobule: EVC, ADC) */
 
        /* PTQ (mobule: LPC) */
        PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
@@ -1439,31 +1603,41 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
        PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
 
-       /* PTT (mobule: SYSTEM, PWMX) */
-       PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
-       PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+       /* PTT (mobule: PWMX, AUD) */
+       PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
+       PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
        PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
        PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
        PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
        PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX7, PWX7_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX6, PWX6_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX5, PWX5_MARK),
-       PINMUX_GPIO(GPIO_FN_PWX4, PWX4_MARK),
-
-       /* PTU (mobule: LBSC, DMAC) */
-       PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
-       PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
-       PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
-       PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
-       PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
-       PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
-       PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
-       PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
-       PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
-       PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
 
-       /* PTV (mobule: LBSC, DMAC) */
+       /* PTU (mobule: LPC, APM) */
+       PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
+       PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
+       PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
+       PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
+       PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
+       PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
+       PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
+       PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
+       PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
+       PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
+
+       /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
        PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
        PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
        PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
@@ -1472,12 +1646,20 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
        PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
        PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
-       PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
-       PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
-       PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
-       PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+       PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+       PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
+       PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
+       PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
+       PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
+       PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
+       PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
+       PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
+       PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
 
-       /* PTW (mobule: LBSC) */
+       /* PTW (mobule: LBSC, EVC, SCIF) */
        PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
        PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
        PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
@@ -1487,6 +1669,14 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
        PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
        PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
+       PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
 
        /* PTX (mobule: LBSC) */
        PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
@@ -1497,6 +1687,10 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
        PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
        PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
+       PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+       PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
 
        /* PTY (mobule: LBSC) */
        PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
@@ -1507,18 +1701,36 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
        PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
        PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+       /* PTZ (mobule: eMMC, ONFI) */
+       PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
+       PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
  };
 
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
        { PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
-               PTA7_FN, PTA7_OUT, PTA7_IN, 0,
-               PTA6_FN, PTA6_OUT, PTA6_IN, 0,
-               PTA5_FN, PTA5_OUT, PTA5_IN, 0,
-               PTA4_FN, PTA4_OUT, PTA4_IN, 0,
-               PTA3_FN, PTA3_OUT, PTA3_IN, 0,
-               PTA2_FN, PTA2_OUT, PTA2_IN, 0,
-               PTA1_FN, PTA1_OUT, PTA1_IN, 0,
-               PTA0_FN, PTA0_OUT, PTA0_IN, 0 }
+               PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
+               PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
+               PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
+               PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
+               PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
+               PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
+               PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
+               PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
        },
        { PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
                PTB7_FN, PTB7_OUT, PTB7_IN, 0,
@@ -1541,125 +1753,126 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
        },
        { PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
-               PTD7_FN, PTD7_OUT, PTD7_IN, 0,
-               PTD6_FN, PTD6_OUT, PTD6_IN, 0,
-               PTD5_FN, PTD5_OUT, PTD5_IN, 0,
-               PTD4_FN, PTD4_OUT, PTD4_IN, 0,
-               PTD3_FN, PTD3_OUT, PTD3_IN, 0,
-               PTD2_FN, PTD2_OUT, PTD2_IN, 0,
-               PTD1_FN, PTD1_OUT, PTD1_IN, 0,
-               PTD0_FN, PTD0_OUT, PTD0_IN, 0 }
+               PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
+               PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
+               PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
+               PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
+               PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
+               PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
+               PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
+               PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
        },
        { PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
-               PTE7_FN, PTE7_OUT, PTE7_IN, 0,
-               PTE6_FN, PTE6_OUT, PTE6_IN, 0,
-               PTE5_FN, PTE5_OUT, PTE5_IN, 0,
-               PTE4_FN, PTE4_OUT, PTE4_IN, 0,
-               PTE3_FN, PTE3_OUT, PTE3_IN, 0,
-               PTE2_FN, PTE2_OUT, PTE2_IN, 0,
-               PTE1_FN, PTE1_OUT, PTE1_IN, 0,
-               PTE0_FN, PTE0_OUT, PTE0_IN, 0 }
+               PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
+               PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
+               PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
+               PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
+               PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
+               PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
+               PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
+               PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
        },
        { PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
-               PTF7_FN, PTF7_OUT, PTF7_IN, 0,
-               PTF6_FN, PTF6_OUT, PTF6_IN, 0,
-               PTF5_FN, PTF5_OUT, PTF5_IN, 0,
-               PTF4_FN, PTF4_OUT, PTF4_IN, 0,
-               PTF3_FN, PTF3_OUT, PTF3_IN, 0,
-               PTF2_FN, PTF2_OUT, PTF2_IN, 0,
-               PTF1_FN, PTF1_OUT, PTF1_IN, 0,
-               PTF0_FN, PTF0_OUT, PTF0_IN, 0 }
+               PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
+               PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
+               PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
+               PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
+               PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
+               PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
+               PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
+               PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
        },
        { PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
-               PTG7_FN, PTG7_OUT, PTG7_IN, 0,
-               PTG6_FN, PTG6_OUT, PTG6_IN, 0,
+               PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
+               PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
                PTG5_FN, PTG5_OUT, PTG5_IN, 0,
-               PTG4_FN, PTG4_OUT, PTG4_IN, 0,
+               PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
                PTG3_FN, PTG3_OUT, PTG3_IN, 0,
                PTG2_FN, PTG2_OUT, PTG2_IN, 0,
                PTG1_FN, PTG1_OUT, PTG1_IN, 0,
                PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
        },
        { PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
-               PTH7_FN, PTH7_OUT, PTH7_IN, 0,
-               PTH6_FN, PTH6_OUT, PTH6_IN, 0,
-               PTH5_FN, PTH5_OUT, PTH5_IN, 0,
-               PTH4_FN, PTH4_OUT, PTH4_IN, 0,
-               PTH3_FN, PTH3_OUT, PTH3_IN, 0,
-               PTH2_FN, PTH2_OUT, PTH2_IN, 0,
-               PTH1_FN, PTH1_OUT, PTH1_IN, 0,
-               PTH0_FN, PTH0_OUT, PTH0_IN, 0 }
+               PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
+               PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
+               PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
+               PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
+               PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
+               PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
+               PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
+               PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
        },
        { PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
-               PTI7_FN, PTI7_OUT, PTI7_IN, 0,
-               PTI6_FN, PTI6_OUT, PTI6_IN, 0,
+               PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
+               PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
                PTI5_FN, PTI5_OUT, PTI5_IN, 0,
-               PTI4_FN, PTI4_OUT, PTI4_IN, 0,
-               PTI3_FN, PTI3_OUT, PTI3_IN, 0,
-               PTI2_FN, PTI2_OUT, PTI2_IN, 0,
-               PTI1_FN, PTI1_OUT, PTI1_IN, 0,
-               PTI0_FN, PTI0_OUT, PTI0_IN, 0 }
+               PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
+               PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
+               PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
+               PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
+               PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
        },
        { PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
-               PTJ7_FN, PTJ7_OUT, PTJ7_IN, 0,
-               PTJ6_FN, PTJ6_OUT, PTJ6_IN, 0,
-               PTJ5_FN, PTJ5_OUT, PTJ5_IN, 0,
-               PTJ4_FN, PTJ4_OUT, PTJ4_IN, 0,
-               PTJ3_FN, PTJ3_OUT, PTJ3_IN, 0,
-               PTJ2_FN, PTJ2_OUT, PTJ2_IN, 0,
-               PTJ1_FN, PTJ1_OUT, PTJ1_IN, 0,
-               PTJ0_FN, PTJ0_OUT, PTJ0_IN, 0 }
+               0, 0, 0, 0,     /* reserved: always set 1 */
+               PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
+               PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
+               PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
+               PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
+               PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
+               PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
+               PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
        },
        { PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
-               PTK7_FN, PTK7_OUT, PTK7_IN, 0,
-               PTK6_FN, PTK6_OUT, PTK6_IN, 0,
-               PTK5_FN, PTK5_OUT, PTK5_IN, 0,
-               PTK4_FN, PTK4_OUT, PTK4_IN, 0,
-               PTK3_FN, PTK3_OUT, PTK3_IN, 0,
-               PTK2_FN, PTK2_OUT, PTK2_IN, 0,
-               PTK1_FN, PTK1_OUT, PTK1_IN, 0,
-               PTK0_FN, PTK0_OUT, PTK0_IN, 0 }
+               PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
+               PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
+               PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
+               PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
+               PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
+               PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
+               PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
+               PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
        },
        { PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
-               PTL7_FN, PTL7_OUT, PTL7_IN, 0,
-               PTL6_FN, PTL6_OUT, PTL6_IN, 0,
-               PTL5_FN, PTL5_OUT, PTL5_IN, 0,
-               PTL4_FN, PTL4_OUT, PTL4_IN, 0,
-               PTL3_FN, PTL3_OUT, PTL3_IN, 0,
-               PTL2_FN, PTL2_OUT, PTL2_IN, 0,
-               PTL1_FN, PTL1_OUT, PTL1_IN, 0,
-               PTL0_FN, PTL0_OUT, PTL0_IN, 0 }
+               0, 0, 0, 0,     /* reserved: always set 1 */
+               PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
+               PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
+               PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
+               PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
+               PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
+               PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
+               PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
        },
        { PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
-               0, 0, 0, 0,     /* reserved: always set 1 */
-               PTM6_FN, PTM6_OUT, PTM6_IN, 0,
-               PTM5_FN, PTM5_OUT, PTM5_IN, 0,
-               PTM4_FN, PTM4_OUT, PTM4_IN, 0,
+               PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
+               PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
+               PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
+               PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
                PTM3_FN, PTM3_OUT, PTM3_IN, 0,
                PTM2_FN, PTM2_OUT, PTM2_IN, 0,
                PTM1_FN, PTM1_OUT, PTM1_IN, 0,
                PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
        },
        { PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
-               PTN7_FN, PTN7_OUT, PTN7_IN, 0,
+               0, 0, 0, 0,     /* reserved: always set 1 */
                PTN6_FN, PTN6_OUT, PTN6_IN, 0,
                PTN5_FN, PTN5_OUT, PTN5_IN, 0,
-               PTN4_FN, PTN4_OUT, PTN4_IN, 0,
-               PTN3_FN, PTN3_OUT, PTN3_IN, 0,
-               PTN2_FN, PTN2_OUT, PTN2_IN, 0,
-               PTN1_FN, PTN1_OUT, PTN1_IN, 0,
-               PTN0_FN, PTN0_OUT, PTN0_IN, 0 }
+               PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
+               PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
+               PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
+               PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
+               PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
        },
        { PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
-               PTO7_FN, PTO7_OUT, PTO7_IN, 0,
-               PTO6_FN, PTO6_OUT, PTO6_IN, 0,
-               PTO5_FN, PTO5_OUT, PTO5_IN, 0,
-               PTO4_FN, PTO4_OUT, PTO4_IN, 0,
-               PTO3_FN, PTO3_OUT, PTO3_IN, 0,
-               PTO2_FN, PTO2_OUT, PTO2_IN, 0,
-               PTO1_FN, PTO1_OUT, PTO1_IN, 0,
-               PTO0_FN, PTO0_OUT, PTO0_IN, 0 }
+               PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
+               PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
+               PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
+               PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
+               PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
+               PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
+               PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
+               PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
        },
+#if 0  /* FIXME: Remove it? */
        { PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
                0, 0, 0, 0,     /* reserved: always set 1 */
                PTP6_FN, PTP6_OUT, PTP6_IN, 0,
@@ -1670,6 +1883,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                PTP1_FN, PTP1_OUT, PTP1_IN, 0,
                PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
        },
+#endif
        { PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
                0, 0, 0, 0,     /* reserved: always set 1 */
                PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
@@ -1701,14 +1915,14 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
        },
        { PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
-               0, 0, 0, 0,     /* reserved: always set 1 */
-               0, 0, 0, 0,     /* reserved: always set 1 */
-               PTT5_FN, PTT5_OUT, PTT5_IN, 0,
-               PTT4_FN, PTT4_OUT, PTT4_IN, 0,
-               PTT3_FN, PTT3_OUT, PTT3_IN, 0,
-               PTT2_FN, PTT2_OUT, PTT2_IN, 0,
-               PTT1_FN, PTT1_OUT, PTT1_IN, 0,
-               PTT0_FN, PTT0_OUT, PTT0_IN, 0 }
+               PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
+               PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
+               PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
+               PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
+               PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
+               PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
+               PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
+               PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
        },
        { PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
                PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
@@ -1727,16 +1941,16 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
                PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
                PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
-               PTV1_FN, PTV1_OUT, PTV1_IN, PTV1_IN_PU,
-               PTV0_FN, PTV0_OUT, PTV0_IN, PTV0_IN_PU }
+               PTV1_FN, PTV1_OUT, PTV1_IN, 0,
+               PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
        },
        { PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
-               PTW7_FN, PTW7_OUT, PTW7_IN, PTW7_IN_PU,
-               PTW6_FN, PTW6_OUT, PTW6_IN, PTW6_IN_PU,
-               PTW5_FN, PTW5_OUT, PTW5_IN, PTW5_IN_PU,
-               PTW4_FN, PTW4_OUT, PTW4_IN, PTW4_IN_PU,
-               PTW3_FN, PTW3_OUT, PTW3_IN, PTW3_IN_PU,
-               PTW2_FN, PTW2_OUT, PTW2_IN, PTW2_IN_PU,
+               PTW7_FN, PTW7_OUT, PTW7_IN, 0,
+               PTW6_FN, PTW6_OUT, PTW6_IN, 0,
+               PTW5_FN, PTW5_OUT, PTW5_IN, 0,
+               PTW4_FN, PTW4_OUT, PTW4_IN, 0,
+               PTW3_FN, PTW3_OUT, PTW3_IN, 0,
+               PTW2_FN, PTW2_OUT, PTW2_IN, 0,
                PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
                PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
        },
@@ -1761,32 +1975,32 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
        },
        { PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
-               0, PTZ7_OUT, PTZ7_IN, 0,
-               0, PTZ6_OUT, PTZ6_IN, 0,
-               0, PTZ5_OUT, PTZ5_IN, 0,
-               0, PTZ4_OUT, PTZ4_IN, 0,
-               0, PTZ3_OUT, PTZ3_IN, 0,
-               0, PTZ2_OUT, PTZ2_IN, 0,
-               0, PTZ1_OUT, PTZ1_IN, 0,
-               0, PTZ0_OUT, PTZ0_IN, 0 }
+               PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
+               PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
+               PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
+               PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
+               PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
+               PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
+               PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
+               PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
        },
 
        { PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
-               PS0_15_FN3, PS0_15_FN1,
-               PS0_14_FN3, PS0_14_FN1,
-               PS0_13_FN3, PS0_13_FN1,
-               PS0_12_FN3, PS0_12_FN1,
-               0, 0,
-               0, 0,
+               PS0_15_FN1, PS0_15_FN2,
+               PS0_14_FN1, PS0_14_FN2,
+               PS0_13_FN1, PS0_13_FN2,
+               PS0_12_FN1, PS0_12_FN2,
+               PS0_11_FN1, PS0_11_FN2,
+               PS0_10_FN1, PS0_10_FN2,
+               PS0_9_FN1, PS0_9_FN2,
+               PS0_8_FN1, PS0_8_FN2,
+               PS0_7_FN1, PS0_7_FN2,
+               PS0_6_FN1, PS0_6_FN2,
+               PS0_5_FN1, PS0_5_FN2,
+               PS0_4_FN1, PS0_4_FN2,
+               PS0_3_FN1, PS0_3_FN2,
+               PS0_2_FN1, PS0_2_FN2,
                0, 0,
-               0, 0,
-               PS0_7_FN2, PS0_7_FN1,
-               PS0_6_FN2, PS0_6_FN1,
-               PS0_5_FN2, PS0_5_FN1,
-               PS0_4_FN2, PS0_4_FN1,
-               PS0_3_FN2, PS0_3_FN1,
-               PS0_2_FN2, PS0_2_FN1,
-               PS0_1_FN2, PS0_1_FN1,
                0, 0, }
        },
        { PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
@@ -1795,73 +2009,136 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                0, 0,
                0, 0,
                0, 0,
+               PS1_10_FN1, PS1_10_FN2,
+               PS1_9_FN1, PS1_9_FN2,
+               PS1_8_FN1, PS1_8_FN2,
                0, 0,
                0, 0,
                0, 0,
-               PS1_7_FN1, PS1_7_FN3,
-               PS1_6_FN1, PS1_6_FN3,
-               0, 0,
-               0, 0,
                0, 0,
                0, 0,
+               PS1_2_FN1, PS1_2_FN2,
                0, 0,
                0, 0, }
        },
        { PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
                0, 0,
                0, 0,
-               PS2_13_FN3, PS2_13_FN1,
-               PS2_12_FN3, PS2_12_FN1,
+               PS2_13_FN1, PS2_13_FN2,
+               PS2_12_FN1, PS2_12_FN2,
                0, 0,
                0, 0,
                0, 0,
                0, 0,
+               PS2_7_FN1, PS2_7_FN2,
+               PS2_6_FN1, PS2_6_FN2,
+               PS2_5_FN1, PS2_5_FN2,
+               PS2_4_FN1, PS2_4_FN2,
                0, 0,
+               PS2_2_FN1, PS2_2_FN2,
                0, 0,
+               0, 0, }
+       },
+       { PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
+               PS3_15_FN1, PS3_15_FN2,
+               PS3_14_FN1, PS3_14_FN2,
+               PS3_13_FN1, PS3_13_FN2,
+               PS3_12_FN1, PS3_12_FN2,
+               PS3_11_FN1, PS3_11_FN2,
+               PS3_10_FN1, PS3_10_FN2,
+               PS3_9_FN1, PS3_9_FN2,
+               PS3_8_FN1, PS3_8_FN2,
+               PS3_7_FN1, PS3_7_FN2,
                0, 0,
                0, 0,
                0, 0,
                0, 0,
-               PS2_1_FN1, PS2_1_FN2,
-               PS2_0_FN1, PS2_0_FN2, }
+               PS3_2_FN1, PS3_2_FN2,
+               PS3_1_FN1, PS3_1_FN2,
+               0, 0, }
        },
+
        { PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
-               PS4_15_FN2, PS4_15_FN1,
-               PS4_14_FN2, PS4_14_FN1,
-               PS4_13_FN2, PS4_13_FN1,
-               PS4_12_FN2, PS4_12_FN1,
-               PS4_11_FN2, PS4_11_FN1,
-               PS4_10_FN2, PS4_10_FN1,
-               PS4_9_FN2, PS4_9_FN1,
                0, 0,
+               PS4_14_FN1, PS4_14_FN2,
+               PS4_13_FN1, PS4_13_FN2,
+               PS4_12_FN1, PS4_12_FN2,
                0, 0,
+               PS4_10_FN1, PS4_10_FN2,
+               PS4_9_FN1, PS4_9_FN2,
+               PS4_8_FN1, PS4_8_FN2,
                0, 0,
                0, 0,
                0, 0,
-               PS4_3_FN2, PS4_3_FN1,
-               PS4_2_FN2, PS4_2_FN1,
-               PS4_1_FN2, PS4_1_FN1,
-               PS4_0_FN2, PS4_0_FN1, }
+               PS4_4_FN1, PS4_4_FN2,
+               PS4_3_FN1, PS4_3_FN2,
+               PS4_2_FN1, PS4_2_FN2,
+               PS4_1_FN1, PS4_1_FN2,
+               PS4_0_FN1, PS4_0_FN2, }
        },
        { PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
                0, 0,
                0, 0,
                0, 0,
                0, 0,
-               0, 0,
-               0, 0,
+               PS5_11_FN1, PS5_11_FN2,
+               PS5_10_FN1, PS5_10_FN2,
                PS5_9_FN1, PS5_9_FN2,
                PS5_8_FN1, PS5_8_FN2,
                PS5_7_FN1, PS5_7_FN2,
                PS5_6_FN1, PS5_6_FN2,
                PS5_5_FN1, PS5_5_FN2,
+               PS5_4_FN1, PS5_4_FN2,
+               PS5_3_FN1, PS5_3_FN2,
+               PS5_2_FN1, PS5_2_FN2,
+               0, 0,
+               0, 0, }
+       },
+       { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+               PS6_15_FN1, PS6_15_FN2,
+               PS6_14_FN1, PS6_14_FN2,
+               PS6_13_FN1, PS6_13_FN2,
+               PS6_12_FN1, PS6_12_FN2,
+               PS6_11_FN1, PS6_11_FN2,
+               PS6_10_FN1, PS6_10_FN2,
+               PS6_9_FN1, PS6_9_FN2,
+               PS6_8_FN1, PS6_8_FN2,
+               PS6_7_FN1, PS6_7_FN2,
+               PS6_6_FN1, PS6_6_FN2,
+               PS6_5_FN1, PS6_5_FN2,
+               PS6_4_FN1, PS6_4_FN2,
+               PS6_3_FN1, PS6_3_FN2,
+               PS6_2_FN1, PS6_2_FN2,
+               PS6_1_FN1, PS6_1_FN2,
+               PS6_0_FN1, PS6_0_FN2, }
+       },
+       { PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
+               PS7_15_FN1, PS7_15_FN2,
+               PS7_14_FN1, PS7_14_FN2,
+               PS7_13_FN1, PS7_13_FN2,
+               PS7_12_FN1, PS7_12_FN2,
+               PS7_11_FN1, PS7_11_FN2,
+               PS7_10_FN1, PS7_10_FN2,
+               PS7_9_FN1, PS7_9_FN2,
+               PS7_8_FN1, PS7_8_FN2,
+               PS7_7_FN1, PS7_7_FN2,
+               PS7_6_FN1, PS7_6_FN2,
+               PS7_5_FN1, PS7_5_FN2,
                0, 0,
                0, 0,
                0, 0,
                0, 0,
                0, 0, }
        },
-       { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+       { PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
+               PS8_15_FN1, PS8_15_FN2,
+               PS8_14_FN1, PS8_14_FN2,
+               PS8_13_FN1, PS8_13_FN2,
+               PS8_12_FN1, PS8_12_FN2,
+               PS8_11_FN1, PS8_11_FN2,
+               PS8_10_FN1, PS8_10_FN2,
+               PS8_9_FN1, PS8_9_FN2,
+               PS8_8_FN1, PS8_8_FN2,
                0, 0,
                0, 0,
                0, 0,
@@ -1869,15 +2146,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
                0, 0,
                0, 0,
                0, 0,
-               0, 0,
-               PS6_7_FN_AN, PS6_7_FN_EV,
-               PS6_6_FN_AN, PS6_6_FN_EV,
-               PS6_5_FN_AN, PS6_5_FN_EV,
-               PS6_4_FN_AN, PS6_4_FN_EV,
-               PS6_3_FN_AN, PS6_3_FN_EV,
-               PS6_2_FN_AN, PS6_2_FN_EV,
-               PS6_1_FN_AN, PS6_1_FN_EV,
-               PS6_0_FN_AN, PS6_0_FN_EV, }
+               0, 0, }
        },
        {}
 };
@@ -1920,7 +2189,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
                PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
        },
        { PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
-               PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+               0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
                PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
        },
        { PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
@@ -1928,15 +2197,15 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
                PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
        },
        { PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
-               PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+               0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
                PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
        },
        { PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
-               0, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+               PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
                PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
        },
        { PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
-               PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+               0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
                PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
        },
        { PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
@@ -1944,7 +2213,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
                PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
        },
        { PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
-               0, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+               PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
                PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
        },
        { PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
@@ -1960,7 +2229,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
                PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
        },
        { PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
-               0, 0, PTT5_DATA, PTT4_DATA,
+               PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
                PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
        },
        { PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
@@ -2000,8 +2269,8 @@ static struct pinmux_info sh7757_pinmux_info = {
        .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
-       .first_gpio = GPIO_PTA7,
-       .last_gpio = GPIO_FN_D0,
+       .first_gpio = GPIO_PTA0,
+       .last_gpio = GPIO_FN_ON_DQ0,
 
        .gpios = pinmux_gpios,
        .cfg_regs = pinmux_config_regs,
@@ -2015,5 +2284,4 @@ static int __init plat_pinmux_setup(void)
 {
        return register_pinmux(&sh7757_pinmux_info);
 }
-
 arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
new file mode 100644 (file)
index 0000000..aaa5338
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * SH-X3 prototype CPU pinmux
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/shx3.h>
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+       PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+       PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+       PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+       PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+       PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+       PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+       PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+       PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+       PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+       PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+       PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+       PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+       PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+
+       PH5_DATA, PH4_DATA,
+       PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+       PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+       PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+       PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+       PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+       PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+       PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+       PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+       PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+       PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+       PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+       PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+       PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+       PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+
+       PH5_IN, PH4_IN,
+       PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+       PINMUX_INPUT_END,
+
+       PINMUX_INPUT_PULLUP_BEGIN,
+       PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+       PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+       PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+       PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+       PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+       PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+       PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+       PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+       PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
+       PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+       PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+       PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+       PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+       PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+
+       PH5_IN_PU, PH4_IN_PU,
+       PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+       PINMUX_INPUT_PULLUP_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+       PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+       PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+       PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+       PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+       PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+       PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+       PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+       PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+       PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+       PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+       PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+       PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+       PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+
+       PH5_OUT, PH4_OUT,
+       PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+       PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+       PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+       PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+       PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+       PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+       PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+       PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+       PE7_FN, PE6_FN, PE5_FN, PE4_FN,
+       PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+       PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+       PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+       PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+       PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+
+       PH5_FN, PH4_FN,
+       PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+
+       D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
+       D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+       D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+
+       BACK_MARK, BREQ_MARK,
+       WE3_MARK, WE2_MARK,
+       CS6_MARK, CS5_MARK, CS4_MARK,
+       CLKOUTENB_MARK,
+
+       DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
+       DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
+
+       IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+
+       DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
+
+       SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
+       IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
+       TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
+       RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
+
+       CE2B_MARK, CE2A_MARK, IOIS16_MARK,
+       STATUS1_MARK, STATUS0_MARK,
+
+       IRQOUT_MARK,
+
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t shx3_pinmux_data[] = {
+
+       /* PA GPIO */
+       PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+       PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+       PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+       PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+       PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+       PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+       PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+       PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+       /* PB GPIO */
+       PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+       PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+       PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+       PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+       PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+       PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+       PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+       PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+       /* PC GPIO */
+       PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+       PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+       PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+       PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+       PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+       PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+       PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+       PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+       /* PD GPIO */
+       PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+       PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+       PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+       PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+       PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+       PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+       PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+       PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+       /* PE GPIO */
+       PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+       PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+       PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+       PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+       PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+       PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+       PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+       PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+       /* PF GPIO */
+       PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+       PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+       PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+       PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+       PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+       PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+       PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+       PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+       /* PG GPIO */
+       PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+       PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+       PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+       PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+       PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+       PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+       PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+       PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+       /* PH GPIO */
+       PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+       PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+       PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+       PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+       PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+       PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+       /* PA FN */
+       PINMUX_DATA(D31_MARK, PA7_FN),
+       PINMUX_DATA(D30_MARK, PA6_FN),
+       PINMUX_DATA(D29_MARK, PA5_FN),
+       PINMUX_DATA(D28_MARK, PA4_FN),
+       PINMUX_DATA(D27_MARK, PA3_FN),
+       PINMUX_DATA(D26_MARK, PA2_FN),
+       PINMUX_DATA(D25_MARK, PA1_FN),
+       PINMUX_DATA(D24_MARK, PA0_FN),
+
+       /* PB FN */
+       PINMUX_DATA(D23_MARK, PB7_FN),
+       PINMUX_DATA(D22_MARK, PB6_FN),
+       PINMUX_DATA(D21_MARK, PB5_FN),
+       PINMUX_DATA(D20_MARK, PB4_FN),
+       PINMUX_DATA(D19_MARK, PB3_FN),
+       PINMUX_DATA(D18_MARK, PB2_FN),
+       PINMUX_DATA(D17_MARK, PB1_FN),
+       PINMUX_DATA(D16_MARK, PB0_FN),
+
+       /* PC FN */
+       PINMUX_DATA(BACK_MARK,          PC7_FN),
+       PINMUX_DATA(BREQ_MARK,          PC6_FN),
+       PINMUX_DATA(WE3_MARK,           PC5_FN),
+       PINMUX_DATA(WE2_MARK,           PC4_FN),
+       PINMUX_DATA(CS6_MARK,           PC3_FN),
+       PINMUX_DATA(CS5_MARK,           PC2_FN),
+       PINMUX_DATA(CS4_MARK,           PC1_FN),
+       PINMUX_DATA(CLKOUTENB_MARK,     PC0_FN),
+
+       /* PD FN */
+       PINMUX_DATA(DACK3_MARK, PD7_FN),
+       PINMUX_DATA(DACK2_MARK, PD6_FN),
+       PINMUX_DATA(DACK1_MARK, PD5_FN),
+       PINMUX_DATA(DACK0_MARK, PD4_FN),
+       PINMUX_DATA(DREQ3_MARK, PD3_FN),
+       PINMUX_DATA(DREQ2_MARK, PD2_FN),
+       PINMUX_DATA(DREQ1_MARK, PD1_FN),
+       PINMUX_DATA(DREQ0_MARK, PD0_FN),
+
+       /* PE FN */
+       PINMUX_DATA(IRQ3_MARK,  PE7_FN),
+       PINMUX_DATA(IRQ2_MARK,  PE6_FN),
+       PINMUX_DATA(IRQ1_MARK,  PE5_FN),
+       PINMUX_DATA(IRQ0_MARK,  PE4_FN),
+       PINMUX_DATA(DRAK3_MARK, PE3_FN),
+       PINMUX_DATA(DRAK2_MARK, PE2_FN),
+       PINMUX_DATA(DRAK1_MARK, PE1_FN),
+       PINMUX_DATA(DRAK0_MARK, PE0_FN),
+
+       /* PF FN */
+       PINMUX_DATA(SCK3_MARK, PF7_FN),
+       PINMUX_DATA(SCK2_MARK, PF6_FN),
+       PINMUX_DATA(SCK1_MARK, PF5_FN),
+       PINMUX_DATA(SCK0_MARK, PF4_FN),
+       PINMUX_DATA(IRL3_MARK, PF3_FN),
+       PINMUX_DATA(IRL2_MARK, PF2_FN),
+       PINMUX_DATA(IRL1_MARK, PF1_FN),
+       PINMUX_DATA(IRL0_MARK, PF0_FN),
+
+       /* PG FN */
+       PINMUX_DATA(TXD3_MARK, PG7_FN),
+       PINMUX_DATA(TXD2_MARK, PG6_FN),
+       PINMUX_DATA(TXD1_MARK, PG5_FN),
+       PINMUX_DATA(TXD0_MARK, PG4_FN),
+       PINMUX_DATA(RXD3_MARK, PG3_FN),
+       PINMUX_DATA(RXD2_MARK, PG2_FN),
+       PINMUX_DATA(RXD1_MARK, PG1_FN),
+       PINMUX_DATA(RXD0_MARK, PG0_FN),
+
+       /* PH FN */
+       PINMUX_DATA(CE2B_MARK,          PH5_FN),
+       PINMUX_DATA(CE2A_MARK,          PH4_FN),
+       PINMUX_DATA(IOIS16_MARK,        PH3_FN),
+       PINMUX_DATA(STATUS1_MARK,       PH2_FN),
+       PINMUX_DATA(STATUS0_MARK,       PH1_FN),
+       PINMUX_DATA(IRQOUT_MARK,        PH0_FN),
+};
+
+static struct pinmux_gpio shx3_pinmux_gpios[] = {
+       /* PA */
+       PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+       PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+       PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+       PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+       PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+       PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+       PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+       PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+       /* PB */
+       PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+       PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+       PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+       PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+       PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+       PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+       PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+       PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+       /* PC */
+       PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+       PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+       PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+       PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+       PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+       PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+       PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+       PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+       /* PD */
+       PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+       PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+       PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+       PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+       PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+       PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+       PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+       PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+       /* PE */
+       PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+       PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+       PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+       PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+       PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+       PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+       PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+       PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+       /* PF */
+       PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+       PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+       PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+       PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+       PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+       PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+       PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+       PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+       /* PG */
+       PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+       PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+       PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+       PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+       PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+       PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+       PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+       PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+       /* PH */
+       PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+       PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+       PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+       PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+       PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+       PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+       /* FN */
+       PINMUX_GPIO(GPIO_FN_D31,        D31_MARK),
+       PINMUX_GPIO(GPIO_FN_D30,        D30_MARK),
+       PINMUX_GPIO(GPIO_FN_D29,        D29_MARK),
+       PINMUX_GPIO(GPIO_FN_D28,        D28_MARK),
+       PINMUX_GPIO(GPIO_FN_D27,        D27_MARK),
+       PINMUX_GPIO(GPIO_FN_D26,        D26_MARK),
+       PINMUX_GPIO(GPIO_FN_D25,        D25_MARK),
+       PINMUX_GPIO(GPIO_FN_D24,        D24_MARK),
+       PINMUX_GPIO(GPIO_FN_D23,        D23_MARK),
+       PINMUX_GPIO(GPIO_FN_D22,        D22_MARK),
+       PINMUX_GPIO(GPIO_FN_D21,        D21_MARK),
+       PINMUX_GPIO(GPIO_FN_D20,        D20_MARK),
+       PINMUX_GPIO(GPIO_FN_D19,        D19_MARK),
+       PINMUX_GPIO(GPIO_FN_D18,        D18_MARK),
+       PINMUX_GPIO(GPIO_FN_D17,        D17_MARK),
+       PINMUX_GPIO(GPIO_FN_D16,        D16_MARK),
+       PINMUX_GPIO(GPIO_FN_BACK,       BACK_MARK),
+       PINMUX_GPIO(GPIO_FN_BREQ,       BREQ_MARK),
+       PINMUX_GPIO(GPIO_FN_WE3,        WE3_MARK),
+       PINMUX_GPIO(GPIO_FN_WE2,        WE2_MARK),
+       PINMUX_GPIO(GPIO_FN_CS6,        CS6_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5,        CS5_MARK),
+       PINMUX_GPIO(GPIO_FN_CS4,        CS4_MARK),
+       PINMUX_GPIO(GPIO_FN_CLKOUTENB,  CLKOUTENB_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK3,      DACK3_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK2,      DACK2_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK1,      DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK0,      DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ3,      DREQ3_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ2,      DREQ2_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ1,      DREQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ0,      DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ3,       IRQ3_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ2,       IRQ2_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1,       IRQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0,       IRQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK3,      DRAK3_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK2,      DRAK2_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK1,      DRAK1_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK0,      DRAK0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK3,       SCK3_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK2,       SCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK1,       SCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK0,       SCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL3,       IRL3_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL2,       IRL2_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL1,       IRL1_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL0,       IRL0_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD3,       TXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD2,       TXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD1,       TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD0,       TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD3,       RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD2,       RXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD1,       RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD0,       RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2B,       CE2B_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2A,       CE2A_MARK),
+       PINMUX_GPIO(GPIO_FN_IOIS16,     IOIS16_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS1,    STATUS1_MARK),
+       PINMUX_GPIO(GPIO_FN_STATUS0,    STATUS0_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQOUT,     IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
+               PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+               PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+               PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+               PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+               PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+               PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+               PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+               PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
+               PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+               PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+               PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+               PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+               PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+               PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+               PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+               PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+       },
+       { PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
+               PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+               PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+               PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+               PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+               PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+               PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+               PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+               PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
+               PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+               PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+               PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+               PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+               PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+               PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+               PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+               PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+       },
+       { PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
+               PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+               PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+               PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+               PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+               PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+               PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+               PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+               PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
+               PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+               PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+               PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+               PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+               PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+               PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+               PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+               PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+       },
+       { PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
+               PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+               PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+               PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+               PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+               PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+               PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+               PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+               PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+               PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+               PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+               PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+               PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+               PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+       },
+       { },
+};
+
+static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+               PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+               PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
+       },
+       { PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+               PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+               PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
+       },
+       { PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+               PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+               PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
+       },
+       { PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+               PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, PH5_DATA, PH4_DATA,
+               PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
+       },
+       { },
+};
+
+static struct pinmux_info shx3_pinmux_info = {
+       .name           = "shx3_pfc",
+       .reserved_id    = PINMUX_RESERVED,
+       .data           = { PINMUX_DATA_BEGIN,     PINMUX_DATA_END },
+       .input          = { PINMUX_INPUT_BEGIN,    PINMUX_INPUT_END },
+       .input_pu       = { PINMUX_INPUT_PULLUP_BEGIN,
+                           PINMUX_INPUT_PULLUP_END },
+       .output         = { PINMUX_OUTPUT_BEGIN,   PINMUX_OUTPUT_END },
+       .mark           = { PINMUX_MARK_BEGIN,     PINMUX_MARK_END },
+       .function       = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+       .first_gpio     = GPIO_PA7,
+       .last_gpio      = GPIO_FN_IRQOUT,
+       .gpios          = shx3_pinmux_gpios,
+       .gpio_data      = shx3_pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(shx3_pinmux_data),
+       .cfg_regs       = shx3_pinmux_config_regs,
+       .data_regs      = shx3_pinmux_data_regs,
+};
+
+static int __init shx3_pinmux_setup(void)
+{
+       return register_pinmux(&shx3_pinmux_info);
+}
+arch_initcall(shx3_pinmux_setup);
index 156ccc9600155f159c7f84baed82990e16ed6292..d551ed8dea954600216cc1d5ec418d389fd45a70 100644 (file)
@@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
 };
 
 static struct platform_device siu_device = {
-       .name           = "sh_siu",
+       .name           = "siu-pcm-audio",
        .id             = -1,
        .dev = {
                .platform_data  = &siu_platform_data,
index 79c556e5626213b16f44051242c8f93ac7389904..828c9657eb526956fcc6d2942b28091c1be5bab3 100644 (file)
@@ -524,6 +524,70 @@ static struct platform_device veu1_device = {
        },
 };
 
+/* BEU0 */
+static struct uio_info beu0_platform_data = {
+       .name = "BEU0",
+       .version = "0",
+       .irq = evt2irq(0x8A0),
+};
+
+static struct resource beu0_resources[] = {
+       [0] = {
+               .name   = "BEU0",
+               .start  = 0xfe930000,
+               .end    = 0xfe933400,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device beu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &beu0_platform_data,
+       },
+       .resource       = beu0_resources,
+       .num_resources  = ARRAY_SIZE(beu0_resources),
+       .archdata = {
+               .hwblk_id = HWBLK_BEU0,
+       },
+};
+
+/* BEU1 */
+static struct uio_info beu1_platform_data = {
+       .name = "BEU1",
+       .version = "0",
+       .irq = evt2irq(0xA00),
+};
+
+static struct resource beu1_resources[] = {
+       [0] = {
+               .name   = "BEU1",
+               .start  = 0xfe940000,
+               .end    = 0xfe943400,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device beu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &beu1_platform_data,
+       },
+       .resource       = beu1_resources,
+       .num_resources  = ARRAY_SIZE(beu1_resources),
+       .archdata = {
+               .hwblk_id = HWBLK_BEU1,
+       },
+};
+
 static struct sh_timer_config cmt_platform_data = {
        .channel_offset = 0x60,
        .timer_bit = 5,
@@ -857,6 +921,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
        &vpu_device,
        &veu0_device,
        &veu1_device,
+       &beu0_device,
+       &beu1_device,
        &jpu_device,
        &spu0_device,
        &spu1_device,
index 444aca95b20d60e6e3f469f2e9f9c0f63f8d2ac7..749c6388d5a5515cd5b0b889c8c06b2a0d65c408 100644 (file)
@@ -26,7 +26,7 @@ static struct plat_sci_port scif2_platform_data = {
 
 static struct platform_device scif2_device = {
        .name           = "sh-sci",
-       .id             = 2,
+       .id             = 0,
        .dev            = {
                .platform_data  = &scif2_platform_data,
        },
@@ -41,7 +41,7 @@ static struct plat_sci_port scif3_platform_data = {
 
 static struct platform_device scif3_device = {
        .name           = "sh-sci",
-       .id             = 3,
+       .id             = 1,
        .dev            = {
                .platform_data  = &scif3_platform_data,
        },
@@ -56,7 +56,7 @@ static struct plat_sci_port scif4_platform_data = {
 
 static struct platform_device scif4_device = {
        .name           = "sh-sci",
-       .id             = 4,
+       .id             = 2,
        .dev            = {
                .platform_data  = &scif4_platform_data,
        },
@@ -163,39 +163,23 @@ enum {
        IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
 
-       SDHI,
-       DVC,
-       IRQ8, IRQ9, IRQ10,
-       WDT0,
-       TMU0, TMU1, TMU2, TMU2_TICPI,
+       SDHI, DVC,
+       IRQ8, IRQ9, IRQ11, IRQ10, IRQ12, IRQ13, IRQ14, IRQ15,
+       TMU0, TMU1, TMU2, TMU2_TICPI, TMU3, TMU4, TMU5,
        HUDI,
-
        ARC4,
-       DMAC0,
-       IRQ11,
-       SCIF2,
-       DMAC1_6,
-       USB0,
-       IRQ12,
+       DMAC0_5, DMAC6_7, DMAC8_11,
+       SCIF0, SCIF1, SCIF2, SCIF3, SCIF4,
+       USB0, USB1,
        JMC,
-       SPI1,
-       IRQ13, IRQ14,
-       USB1,
+       SPI0, SPI1,
        TMR01, TMR23, TMR45,
-       WDT1,
        FRT,
-       LPC,
-       SCIF0, SCIF1, SCIF3,
-       PECI0I, PECI1I, PECI2I,
-       IRQ15,
+       LPC, LPC5, LPC6, LPC7, LPC8,
+       PECI0, PECI1, PECI2, PECI3, PECI4, PECI5,
        ETHERC,
-       SPI0,
-       ADC1,
-       DMAC1_8,
+       ADC0, ADC1,
        SIM,
-       TMU3, TMU4, TMU5,
-       ADC0,
-       SCIF4,
        IIC0_0, IIC0_1, IIC0_2, IIC0_3,
        IIC1_0, IIC1_1, IIC1_2, IIC1_3,
        IIC2_0, IIC2_1, IIC2_2, IIC2_3,
@@ -206,9 +190,23 @@ enum {
        IIC7_0, IIC7_1, IIC7_2, IIC7_3,
        IIC8_0, IIC8_1, IIC8_2, IIC8_3,
        IIC9_0, IIC9_1, IIC9_2, IIC9_3,
-       PCIINTA,
-       PCIE,
+       ONFICTL,
+       MMC1, MMC2,
+       ECCU,
+       PCIC,
+       G200,
+       RSPI,
        SGPIO,
+       DMINT12, DMINT13, DMINT14, DMINT15, DMINT16, DMINT17, DMINT18, DMINT19,
+       DMINT20, DMINT21, DMINT22, DMINT23,
+       DDRECC,
+       TSIP,
+       PCIE_BRIDGE,
+       WDT0B, WDT1B, WDT2B, WDT3B, WDT4B, WDT5B, WDT6B, WDT7B, WDT8B,
+       GETHER0, GETHER1, GETHER2,
+       PBIA, PBIB, PBIC,
+       DMAE2, DMAE3,
+       SERMUX2, SERMUX3,
 
        /* interrupt groups */
 
@@ -221,19 +219,18 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(DVC, 0x4e0),
        INTC_VECT(IRQ8, 0x500), INTC_VECT(IRQ9, 0x520),
        INTC_VECT(IRQ10, 0x540),
-       INTC_VECT(WDT0, 0x560),
        INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
        INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
        INTC_VECT(HUDI, 0x600),
        INTC_VECT(ARC4, 0x620),
-       INTC_VECT(DMAC0, 0x640), INTC_VECT(DMAC0, 0x660),
-       INTC_VECT(DMAC0, 0x680), INTC_VECT(DMAC0, 0x6a0),
-       INTC_VECT(DMAC0, 0x6c0),
+       INTC_VECT(DMAC0_5, 0x640), INTC_VECT(DMAC0_5, 0x660),
+       INTC_VECT(DMAC0_5, 0x680), INTC_VECT(DMAC0_5, 0x6a0),
+       INTC_VECT(DMAC0_5, 0x6c0),
        INTC_VECT(IRQ11, 0x6e0),
        INTC_VECT(SCIF2, 0x700), INTC_VECT(SCIF2, 0x720),
        INTC_VECT(SCIF2, 0x740), INTC_VECT(SCIF2, 0x760),
-       INTC_VECT(DMAC0, 0x780), INTC_VECT(DMAC0, 0x7a0),
-       INTC_VECT(DMAC1_6, 0x7c0), INTC_VECT(DMAC1_6, 0x7e0),
+       INTC_VECT(DMAC0_5, 0x780), INTC_VECT(DMAC0_5, 0x7a0),
+       INTC_VECT(DMAC6_7, 0x7c0), INTC_VECT(DMAC6_7, 0x7e0),
        INTC_VECT(USB0, 0x840),
        INTC_VECT(IRQ12, 0x880),
        INTC_VECT(JMC, 0x8a0),
@@ -242,7 +239,6 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(USB1, 0x920),
        INTC_VECT(TMR01, 0xa00), INTC_VECT(TMR23, 0xa20),
        INTC_VECT(TMR45, 0xa40),
-       INTC_VECT(WDT1, 0xa60),
        INTC_VECT(FRT, 0xa80),
        INTC_VECT(LPC, 0xaa0), INTC_VECT(LPC, 0xac0),
        INTC_VECT(LPC, 0xae0), INTC_VECT(LPC, 0xb00),
@@ -250,14 +246,14 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(SCIF0, 0xb40), INTC_VECT(SCIF1, 0xb60),
        INTC_VECT(SCIF3, 0xb80), INTC_VECT(SCIF3, 0xba0),
        INTC_VECT(SCIF3, 0xbc0), INTC_VECT(SCIF3, 0xbe0),
-       INTC_VECT(PECI0I, 0xc00), INTC_VECT(PECI1I, 0xc20),
-       INTC_VECT(PECI2I, 0xc40),
+       INTC_VECT(PECI0, 0xc00), INTC_VECT(PECI1, 0xc20),
+       INTC_VECT(PECI2, 0xc40),
        INTC_VECT(IRQ15, 0xc60),
        INTC_VECT(ETHERC, 0xc80), INTC_VECT(ETHERC, 0xca0),
        INTC_VECT(SPI0, 0xcc0),
        INTC_VECT(ADC1, 0xce0),
-       INTC_VECT(DMAC1_8, 0xd00), INTC_VECT(DMAC1_8, 0xd20),
-       INTC_VECT(DMAC1_8, 0xd40), INTC_VECT(DMAC1_8, 0xd60),
+       INTC_VECT(DMAC8_11, 0xd00), INTC_VECT(DMAC8_11, 0xd20),
+       INTC_VECT(DMAC8_11, 0xd40), INTC_VECT(DMAC8_11, 0xd60),
        INTC_VECT(SIM, 0xd80), INTC_VECT(SIM, 0xda0),
        INTC_VECT(SIM, 0xdc0), INTC_VECT(SIM, 0xde0),
        INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
@@ -278,17 +274,47 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(IIC5_0, 0x1860), INTC_VECT(IIC5_1, 0x1880),
        INTC_VECT(IIC5_2, 0x18a0), INTC_VECT(IIC5_3, 0x18c0),
        INTC_VECT(IIC6_0, 0x18e0), INTC_VECT(IIC6_1, 0x1900),
-       INTC_VECT(IIC6_2, 0x1920), INTC_VECT(IIC6_3, 0x1980),
+       INTC_VECT(IIC6_2, 0x1920),
+       INTC_VECT(ONFICTL, 0x1960),
+       INTC_VECT(IIC6_3, 0x1980),
        INTC_VECT(IIC7_0, 0x19a0), INTC_VECT(IIC7_1, 0x1a00),
        INTC_VECT(IIC7_2, 0x1a20), INTC_VECT(IIC7_3, 0x1a40),
        INTC_VECT(IIC8_0, 0x1a60), INTC_VECT(IIC8_1, 0x1a80),
        INTC_VECT(IIC8_2, 0x1aa0), INTC_VECT(IIC8_3, 0x1b40),
        INTC_VECT(IIC9_0, 0x1b60), INTC_VECT(IIC9_1, 0x1b80),
        INTC_VECT(IIC9_2, 0x1c00), INTC_VECT(IIC9_3, 0x1c20),
-       INTC_VECT(PCIINTA, 0x1ce0),
-       INTC_VECT(PCIE, 0x1e00),
-       INTC_VECT(SGPIO, 0x1f80),
-       INTC_VECT(SGPIO, 0x1fa0),
+       INTC_VECT(MMC1, 0x1c60), INTC_VECT(MMC2, 0x1c80),
+       INTC_VECT(ECCU, 0x1cc0),
+       INTC_VECT(PCIC, 0x1ce0),
+       INTC_VECT(G200, 0x1d00),
+       INTC_VECT(RSPI, 0x1d80), INTC_VECT(RSPI, 0x1da0),
+       INTC_VECT(RSPI, 0x1dc0), INTC_VECT(RSPI, 0x1de0),
+       INTC_VECT(PECI3, 0x1ec0), INTC_VECT(PECI4, 0x1ee0),
+       INTC_VECT(PECI5, 0x1f00),
+       INTC_VECT(SGPIO, 0x1f80), INTC_VECT(SGPIO, 0x1fa0),
+       INTC_VECT(SGPIO, 0x1fc0),
+       INTC_VECT(DMINT12, 0x2400), INTC_VECT(DMINT13, 0x2420),
+       INTC_VECT(DMINT14, 0x2440), INTC_VECT(DMINT15, 0x2460),
+       INTC_VECT(DMINT16, 0x2480), INTC_VECT(DMINT17, 0x24e0),
+       INTC_VECT(DMINT18, 0x2500), INTC_VECT(DMINT19, 0x2520),
+       INTC_VECT(DMINT20, 0x2540), INTC_VECT(DMINT21, 0x2560),
+       INTC_VECT(DMINT22, 0x2580), INTC_VECT(DMINT23, 0x2600),
+       INTC_VECT(DDRECC, 0x2620),
+       INTC_VECT(TSIP, 0x2640),
+       INTC_VECT(PCIE_BRIDGE, 0x27c0),
+       INTC_VECT(WDT0B, 0x2800), INTC_VECT(WDT1B, 0x2820),
+       INTC_VECT(WDT2B, 0x2840), INTC_VECT(WDT3B, 0x2860),
+       INTC_VECT(WDT4B, 0x2880), INTC_VECT(WDT5B, 0x28a0),
+       INTC_VECT(WDT6B, 0x28c0), INTC_VECT(WDT7B, 0x28e0),
+       INTC_VECT(WDT8B, 0x2900),
+       INTC_VECT(GETHER0, 0x2960), INTC_VECT(GETHER1, 0x2980),
+       INTC_VECT(GETHER2, 0x29a0),
+       INTC_VECT(PBIA, 0x2a00), INTC_VECT(PBIB, 0x2a20),
+       INTC_VECT(PBIC, 0x2a40),
+       INTC_VECT(DMAE2, 0x2a60), INTC_VECT(DMAE3, 0x2a80),
+       INTC_VECT(SERMUX2, 0x2aa0), INTC_VECT(SERMUX3, 0x2b40),
+       INTC_VECT(LPC5, 0x2b60), INTC_VECT(LPC6, 0x2b80),
+       INTC_VECT(LPC7, 0x2c00), INTC_VECT(LPC8, 0x2c20),
 };
 
 static struct intc_group groups[] __initdata = {
@@ -312,31 +338,45 @@ static struct intc_mask_reg mask_registers[] __initdata = {
 
        { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
          { 0, 0, 0, 0, 0, 0, 0, 0,
-           0, DMAC1_8, 0, PECI0I, LPC, FRT, WDT1, TMR45,
-           TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0,
-           HUDI, 0, WDT0, SCIF3, SCIF2, SDHI, TMU345, TMU012
+           0, DMAC8_11, 0, PECI0, LPC, FRT, 0, TMR45,
+           TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0_5,
+           HUDI, 0, 0, SCIF3, SCIF2, SDHI, TMU345, TMU012
             } },
 
        { 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
          { IRQ15, IRQ14, IRQ13, IRQ12, IRQ11, IRQ10, SCIF4, ETHERC,
            IRQ9, IRQ8, SCIF1, SCIF0, USB0, 0, 0, USB1,
-           ADC1, 0, DMAC1_6, ADC0, SPI0, SIM, PECI2I, PECI1I,
+           ADC1, 0, DMAC6_7, ADC0, SPI0, SIM, PECI2, PECI1,
            ARC4, 0, SPI1, JMC, 0, 0, 0, DVC
             } },
 
        { 0xffd10038, 0xffd1003c, 32, /* INT2MSKR2 / INT2MSKCR2 */
-         { IIC4_1, IIC4_2, IIC5_0, 0, 0, 0, SGPIO, 0,
-           0, 0, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
+         { IIC4_1, IIC4_2, IIC5_0, ONFICTL, 0, 0, SGPIO, 0,
+           0, G200, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
            IIC7_2, IIC7_1, IIC6_3, IIC0_0, IIC0_1, IIC0_2, IIC0_3, IIC3_1,
-           IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, PCIE, IIC2_2
+           IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, 0, IIC2_2
             } },
 
-       { 0xffd100d0, 0xff1400d4, 32, /* INT2MSKR3 / INT2MSKCR4 */
-         { 0, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, 0, 0,
+       { 0xffd100d0, 0xffd100d4, 32, /* INT2MSKR3 / INT2MSKCR3 */
+         { MMC1, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, PECI5, MMC2,
            IIC1_3, IIC1_2, IIC9_0, IIC8_3, IIC4_3, IIC7_0, 0, IIC6_2,
-           PCIINTA, 0, IIC4_0, 0, 0, 0, 0, IIC9_3,
+           PCIC, 0, IIC4_0, 0, ECCU, RSPI, 0, IIC9_3,
            IIC3_0, 0, IIC5_3, IIC5_2, 0, 0, 0, IIC1_1
             } },
+
+       { 0xffd20038, 0xffd2003c, 32, /* INT2MSKR4 / INT2MSKCR4 */
+         { WDT0B, WDT1B, WDT3B, GETHER0, 0, 0, 0, 0,
+           0, 0, 0, LPC7, SERMUX2, DMAE3, DMAE2, PBIC,
+           PBIB, PBIA, GETHER1, DMINT12, DMINT13, DMINT14, DMINT15, TSIP,
+           DMINT23, 0, DMINT21, LPC6, 0, DMINT16, 0, DMINT22
+            } },
+
+       { 0xffd200d0, 0xffd200d4, 32, /* INT2MSKR5 / INT2MSKCR5 */
+         { 0, WDT8B, WDT7B, WDT4B, 0, DMINT20, 0, 0,
+           DMINT19, DMINT18, LPC5, SERMUX3, WDT2B, GETHER2, 0, 0,
+           0, 0, PCIE_BRIDGE, 0, 0, 0, 0, LPC8,
+           DDRECC, 0, WDT6B, WDT5B, 0, 0, 0, DMINT17
+            } },
 };
 
 #define INTPRI         0xffd00010
@@ -372,6 +412,22 @@ static struct intc_mask_reg mask_registers[] __initdata = {
 #define INT2PRI29      0xffd100b4
 #define INT2PRI30      0xffd100b8
 #define INT2PRI31      0xffd100bc
+#define INT2PRI32      0xffd20000
+#define INT2PRI33      0xffd20004
+#define INT2PRI34      0xffd20008
+#define INT2PRI35      0xffd2000c
+#define INT2PRI36      0xffd20010
+#define INT2PRI37      0xffd20014
+#define INT2PRI38      0xffd20018
+#define INT2PRI39      0xffd2001c
+#define INT2PRI40      0xffd200a0
+#define INT2PRI41      0xffd200a4
+#define INT2PRI42      0xffd200a8
+#define INT2PRI43      0xffd200ac
+#define INT2PRI44      0xffd200b0
+#define INT2PRI45      0xffd200b4
+#define INT2PRI46      0xffd200b8
+#define INT2PRI47      0xffd200bc
 
 static struct intc_prio_reg prio_registers[] __initdata = {
        { INTPRI, 0, 32, 4, { IRQ0, IRQ1, IRQ2, IRQ3,
@@ -379,39 +435,61 @@ static struct intc_prio_reg prio_registers[] __initdata = {
 
        { INT2PRI0, 0, 32, 8, { TMU0, TMU1, TMU2, TMU2_TICPI } },
        { INT2PRI1, 0, 32, 8, { TMU3, TMU4, TMU5, SDHI } },
-       { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, WDT0, IRQ8 } },
-       { INT2PRI3, 0, 32, 8, { HUDI, DMAC0, ADC0, IRQ9 } },
+       { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, 0, IRQ8 } },
+       { INT2PRI3, 0, 32, 8, { HUDI, DMAC0_5, ADC0, IRQ9 } },
        { INT2PRI4, 0, 32, 8, { IRQ10, 0, TMR01, TMR23 } },
-       { INT2PRI5, 0, 32, 8, { TMR45, WDT1, FRT, LPC } },
-       { INT2PRI6, 0, 32, 8, { PECI0I, ETHERC, DMAC1_8, 0 } },
+       { INT2PRI5, 0, 32, 8, { TMR45, 0, FRT, LPC } },
+       { INT2PRI6, 0, 32, 8, { PECI0, ETHERC, DMAC8_11, 0 } },
        { INT2PRI7, 0, 32, 8, { SCIF4, 0, IRQ11, IRQ12 } },
        { INT2PRI8, 0, 32, 8, { 0, 0, 0, DVC } },
        { INT2PRI9, 0, 32, 8, { ARC4, 0, SPI1, JMC } },
-       { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2I, PECI1I } },
-       { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC1_6, IRQ14 } },
+       { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2, PECI1 } },
+       { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC6_7, IRQ14 } },
        { INT2PRI12, 0, 32, 8, { USB0, 0, IRQ15, USB1 } },
        { INT2PRI13, 0, 32, 8, { 0, 0, SCIF1, SCIF0 } },
 
        { INT2PRI16, 0, 32, 8, { IIC2_2, 0, 0, 0 } },
-       { INT2PRI17, 0, 32, 8, { PCIE, 0, 0, IIC1_0 } },
+       { INT2PRI17, 0, 32, 8, { 0, 0, 0, IIC1_0 } },
        { INT2PRI18, 0, 32, 8, { IIC3_3, IIC9_1, IIC2_1, IIC1_2 } },
        { INT2PRI19, 0, 32, 8, { IIC2_3, IIC3_1, 0, IIC1_3 } },
        { INT2PRI20, 0, 32, 8, { IIC2_0, IIC6_3, IIC7_1, IIC7_2 } },
        { INT2PRI21, 0, 32, 8, { IIC7_3, IIC8_0, IIC8_1, IIC8_2 } },
-       { INT2PRI22, 0, 32, 8, { IIC9_2, 0, 0, 0 } },
-       { INT2PRI23, 0, 32, 8, { 0, SGPIO, IIC3_2, IIC5_1 } },
-       { INT2PRI24, 0, 32, 8, { 0, 0, 0, IIC1_1 } },
+       { INT2PRI22, 0, 32, 8, { IIC9_2, MMC2, G200, 0 } },
+       { INT2PRI23, 0, 32, 8, { PECI5, SGPIO, IIC3_2, IIC5_1 } },
+       { INT2PRI24, 0, 32, 8, { PECI4, PECI3, 0, IIC1_1 } },
        { INT2PRI25, 0, 32, 8, { IIC3_0, 0, IIC5_3, IIC5_2 } },
-       { INT2PRI26, 0, 32, 8, { 0, 0, 0, IIC9_3 } },
-       { INT2PRI27, 0, 32, 8, { PCIINTA, IIC6_0, IIC4_0, IIC6_1 } },
-       { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, 0, IIC6_2 } },
+       { INT2PRI26, 0, 32, 8, { ECCU, RSPI, 0, IIC9_3 } },
+       { INT2PRI27, 0, 32, 8, { PCIC, IIC6_0, IIC4_0, IIC6_1 } },
+       { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, MMC1, IIC6_2 } },
        { INT2PRI29, 0, 32, 8, { 0, 0, IIC9_0, IIC8_3 } },
-       { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, 0 } },
+       { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, ONFICTL } },
        { INT2PRI31, 0, 32, 8, { IIC0_0, IIC0_1, IIC0_2, IIC0_3 } },
+       { INT2PRI32, 0, 32, 8, { DMINT22, 0, 0, 0 } },
+       { INT2PRI33, 0, 32, 8, { 0, 0, 0, DMINT16 } },
+       { INT2PRI34, 0, 32, 8, { 0, LPC6, DMINT21, DMINT18 } },
+       { INT2PRI35, 0, 32, 8, { DMINT23, TSIP, 0, DMINT19 } },
+       { INT2PRI36, 0, 32, 8, { DMINT20, GETHER1, PBIA, PBIB } },
+       { INT2PRI37, 0, 32, 8, { PBIC, DMAE2, DMAE3, SERMUX2 } },
+       { INT2PRI38, 0, 32, 8, { LPC7, 0, 0, 0 } },
+       { INT2PRI39, 0, 32, 8, { 0, 0, 0, WDT4B } },
+       { INT2PRI40, 0, 32, 8, { 0, 0, 0, DMINT17 } },
+       { INT2PRI41, 0, 32, 8, { DDRECC, 0, WDT6B, WDT5B } },
+       { INT2PRI42, 0, 32, 8, { 0, 0, 0, LPC8 } },
+       { INT2PRI43, 0, 32, 8, { 0, WDT7B, PCIE_BRIDGE, WDT8B } },
+       { INT2PRI44, 0, 32, 8, { WDT2B, GETHER2, 0, 0 } },
+       { INT2PRI45, 0, 32, 8, { 0, 0, LPC5, SERMUX3 } },
+       { INT2PRI46, 0, 32, 8, { WDT0B, WDT1B, WDT3B, GETHER0 } },
+       { INT2PRI47, 0, 32, 8, { DMINT12, DMINT13, DMINT14, DMINT15 } },
+};
+
+static struct intc_sense_reg sense_registers_irq8to15[] __initdata = {
+       { 0xffd100f8, 32, 2, /* ICR2 */   { IRQ15, IRQ14, IRQ13, IRQ12,
+                                           IRQ11, IRQ10, IRQ9, IRQ8 } },
 };
 
 static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
-                        mask_registers, prio_registers, NULL);
+                        mask_registers, prio_registers,
+                        sense_registers_irq8to15);
 
 /* Support for external interrupt pins in IRQ mode */
 static struct intc_vect vectors_irq0123[] __initdata = {
index 8797723231ea0dde8429778274fa4c7cc7670ad4..c016c0004714047fdb285224cc6f01bc4ce9b143 100644 (file)
@@ -629,33 +629,10 @@ static void __init sh7786_usb_setup(void)
        }
 }
 
-static int __init sh7786_devices_setup(void)
-{
-       int ret;
-
-       sh7786_usb_setup();
-
-       ret = platform_add_devices(sh7786_early_devices,
-                                  ARRAY_SIZE(sh7786_early_devices));
-       if (unlikely(ret != 0))
-               return ret;
-
-       return platform_add_devices(sh7786_devices,
-                                   ARRAY_SIZE(sh7786_devices));
-}
-arch_initcall(sh7786_devices_setup);
-
-void __init plat_early_device_setup(void)
-{
-       early_platform_add_devices(sh7786_early_devices,
-                                  ARRAY_SIZE(sh7786_early_devices));
-}
-
 enum {
        UNUSED = 0,
 
        /* interrupt sources */
-
        IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
        IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
        IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
@@ -693,9 +670,12 @@ enum {
        Thermal,
        INTICI0, INTICI1, INTICI2, INTICI3,
        INTICI4, INTICI5, INTICI6, INTICI7,
+
+       /* Muxed sub-events */
+       TXI1, BRI1, RXI1, ERI1,
 };
 
-static struct intc_vect vectors[] __initdata = {
+static struct intc_vect sh7786_vectors[] __initdata = {
        INTC_VECT(WDT, 0x3e0),
        INTC_VECT(TMU0_0, 0x400), INTC_VECT(TMU0_1, 0x420),
        INTC_VECT(TMU0_2, 0x440), INTC_VECT(TMU0_3, 0x460),
@@ -756,14 +736,12 @@ static struct intc_vect vectors[] __initdata = {
 
 #define INTDISTCR0     0xfe4100b0
 #define INTDISTCR1     0xfe4100b4
-#define INTACK         0xfe4100b8
-#define INTACKCLR      0xfe4100bc
 #define INT2DISTCR0    0xfe410900
 #define INT2DISTCR1    0xfe410904
 #define INT2DISTCR2    0xfe410908
 #define INT2DISTCR3    0xfe41090c
 
-static struct intc_mask_reg mask_registers[] __initdata = {
+static struct intc_mask_reg sh7786_mask_registers[] __initdata = {
        { CnINTMSK0, CnINTMSKCLR0, 32,
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 },
            INTC_SMP_BALANCING(INTDISTCR0) },
@@ -807,7 +785,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
            0, 0, 0, 0, 0, 0, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR3) },
 };
 
-static struct intc_prio_reg prio_registers[] __initdata = {
+static struct intc_prio_reg sh7786_prio_registers[] __initdata = {
        { 0xfe410010, 0, 32, 4, /* INTPRI */   { IRQ0, IRQ1, IRQ2, IRQ3,
                                                 IRQ4, IRQ5, IRQ6, IRQ7 } },
        { 0xfe410800, 0, 32, 8, /* INT2PRI0 */ { 0, 0, 0, WDT } },
@@ -851,11 +829,27 @@ static struct intc_prio_reg prio_registers[] __initdata = {
            INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 2) },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7786", vectors, NULL,
-                        mask_registers, prio_registers, NULL);
+static struct intc_subgroup sh7786_subgroups[] __initdata = {
+       { 0xfe410c20, 32, SCIF1,
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TXI1, BRI1, RXI1, ERI1 } },
+};
 
-/* Support for external interrupt pins in IRQ mode */
+static struct intc_desc sh7786_intc_desc __initdata = {
+       .name           = "sh7786",
+       .hw             = {
+               .vectors        = sh7786_vectors,
+               .nr_vectors     = ARRAY_SIZE(sh7786_vectors),
+               .mask_regs      = sh7786_mask_registers,
+               .nr_mask_regs   = ARRAY_SIZE(sh7786_mask_registers),
+               .subgroups      = sh7786_subgroups,
+               .nr_subgroups   = ARRAY_SIZE(sh7786_subgroups),
+               .prio_regs      = sh7786_prio_registers,
+               .nr_prio_regs   = ARRAY_SIZE(sh7786_prio_registers),
+       },
+};
 
+/* Support for external interrupt pins in IRQ mode */
 static struct intc_vect vectors_irq0123[] __initdata = {
        INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
        INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
@@ -866,23 +860,25 @@ static struct intc_vect vectors_irq4567[] __initdata = {
        INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
 };
 
-static struct intc_sense_reg sense_registers[] __initdata = {
+static struct intc_sense_reg sh7786_sense_registers[] __initdata = {
        { 0xfe41001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
                                            IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_mask_reg ack_registers[] __initdata = {
+static struct intc_mask_reg sh7786_ack_registers[] __initdata = {
        { 0xfe410024, 0, 32, /* INTREQ */
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
 static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh7786-irq0123",
-                            vectors_irq0123, NULL, mask_registers,
-                            prio_registers, sense_registers, ack_registers);
+                            vectors_irq0123, NULL, sh7786_mask_registers,
+                            sh7786_prio_registers, sh7786_sense_registers,
+                            sh7786_ack_registers);
 
 static DECLARE_INTC_DESC_ACK(intc_desc_irq4567, "sh7786-irq4567",
-                            vectors_irq4567, NULL, mask_registers,
-                            prio_registers, sense_registers, ack_registers);
+                            vectors_irq4567, NULL, sh7786_mask_registers,
+                            sh7786_prio_registers, sh7786_sense_registers,
+                            sh7786_ack_registers);
 
 /* External interrupt pins in IRL mode */
 
@@ -909,10 +905,10 @@ static struct intc_vect vectors_irl4567[] __initdata = {
 };
 
 static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7786-irl0123", vectors_irl0123,
-                        NULL, mask_registers, NULL, NULL);
+                        NULL, sh7786_mask_registers, NULL, NULL);
 
 static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
-                        NULL, mask_registers, NULL, NULL);
+                        NULL, sh7786_mask_registers, NULL, NULL);
 
 #define INTC_ICR0      0xfe410000
 #define INTC_INTMSK0   CnINTMSK0
@@ -920,19 +916,6 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
 #define INTC_INTMSK2   INTMSK2
 #define INTC_INTMSKCLR1        CnINTMSKCLR1
 #define INTC_INTMSKCLR2        INTMSKCLR2
-#define INTC_USERIMASK 0xfe411000
-
-#ifdef CONFIG_INTC_BALANCING
-unsigned int irq_lookup(unsigned int irq)
-{
-       return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
-}
-
-void irq_finish(unsigned int irq)
-{
-       __raw_writel(irq2evt(irq), INTACKCLR);
-}
-#endif
 
 void __init plat_irq_setup(void)
 {
@@ -946,8 +929,7 @@ void __init plat_irq_setup(void)
        /* select IRL mode for IRL3-0 + IRL7-4 */
        __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
 
-       register_intc_controller(&intc_desc);
-       register_intc_userimask(INTC_USERIMASK);
+       register_intc_controller(&sh7786_intc_desc);
 }
 
 void __init plat_irq_setup_pins(int mode)
@@ -991,3 +973,39 @@ void __init plat_irq_setup_pins(int mode)
 void __init plat_mem_setup(void)
 {
 }
+
+static int __init sh7786_devices_setup(void)
+{
+       int ret, irq;
+
+       sh7786_usb_setup();
+
+       /*
+        * De-mux SCIF1 IRQs if possible
+        */
+       irq = intc_irq_lookup(sh7786_intc_desc.name, TXI1);
+       if (irq > 0) {
+               scif1_platform_data.irqs[SCIx_TXI_IRQ] = irq;
+               scif1_platform_data.irqs[SCIx_ERI_IRQ] =
+                       intc_irq_lookup(sh7786_intc_desc.name, ERI1);
+               scif1_platform_data.irqs[SCIx_BRI_IRQ] =
+                       intc_irq_lookup(sh7786_intc_desc.name, BRI1);
+               scif1_platform_data.irqs[SCIx_RXI_IRQ] =
+                       intc_irq_lookup(sh7786_intc_desc.name, RXI1);
+       }
+
+       ret = platform_add_devices(sh7786_early_devices,
+                                  ARRAY_SIZE(sh7786_early_devices));
+       if (unlikely(ret != 0))
+               return ret;
+
+       return platform_add_devices(sh7786_devices,
+                                   ARRAY_SIZE(sh7786_devices));
+}
+arch_initcall(sh7786_devices_setup);
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7786_early_devices,
+                                  ARRAY_SIZE(sh7786_early_devices));
+}
index 9158bc5ea38beb9c8df4835563d89fac1a1430dd..013f0b1444896f434cb8af60914d68a26d0e964c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH-X3 Prototype Setup
  *
- *  Copyright (C) 2007 - 2009  Paul Mundt
+ *  Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -12,7 +12,9 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/sh_timer.h>
+#include <cpu/shx3.h>
 #include <asm/mmzone.h>
 
 /*
@@ -354,6 +356,10 @@ static struct intc_group groups[] __initdata = {
                   DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
 };
 
+#define INT2DISTCR0    0xfe4108a0
+#define INT2DISTCR1    0xfe4108a4
+#define INT2DISTCR2    0xfe4108a8
+
 static struct intc_mask_reg mask_registers[] __initdata = {
        { 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
          { IRQ0, IRQ1, IRQ2, IRQ3 } },
@@ -363,20 +369,23 @@ static struct intc_mask_reg mask_registers[] __initdata = {
          { FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
            DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
-           0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+           0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, },
+           INTC_SMP_BALANCING(INT2DISTCR0) },
        { 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
          { 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
            PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
            PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
            DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
            DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
-           DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+           DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 },
+           INTC_SMP_BALANCING(INT2DISTCR1) },
        { 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
          { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
            SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
            SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
-           SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+           SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI },
+           INTC_SMP_BALANCING(INT2DISTCR2) },
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -433,11 +442,33 @@ static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
 
 void __init plat_irq_setup_pins(int mode)
 {
+       int ret = 0;
+
        switch (mode) {
        case IRQ_MODE_IRQ:
+               ret |= gpio_request(GPIO_FN_IRQ3, intc_desc_irq.name);
+               ret |= gpio_request(GPIO_FN_IRQ2, intc_desc_irq.name);
+               ret |= gpio_request(GPIO_FN_IRQ1, intc_desc_irq.name);
+               ret |= gpio_request(GPIO_FN_IRQ0, intc_desc_irq.name);
+
+               if (unlikely(ret)) {
+                       pr_err("Failed to set IRQ mode\n");
+                       return;
+               }
+
                register_intc_controller(&intc_desc_irq);
                break;
        case IRQ_MODE_IRL3210:
+               ret |= gpio_request(GPIO_FN_IRL3, intc_desc_irl.name);
+               ret |= gpio_request(GPIO_FN_IRL2, intc_desc_irl.name);
+               ret |= gpio_request(GPIO_FN_IRL1, intc_desc_irl.name);
+               ret |= gpio_request(GPIO_FN_IRL0, intc_desc_irl.name);
+
+               if (unlikely(ret)) {
+                       pr_err("Failed to set IRL mode\n");
+                       return;
+               }
+
                register_intc_controller(&intc_desc_irl);
                break;
        default:
@@ -447,6 +478,9 @@ void __init plat_irq_setup_pins(int mode)
 
 void __init plat_irq_setup(void)
 {
+       reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
+       reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
+
        register_intc_controller(&intc_desc);
 }
 
index 6e35f012cc0361150804c9f6084ac176c0ba75f0..7db248936b60ef7ca6639fc3420612b0c22d06d3 100644 (file)
@@ -330,7 +330,7 @@ ENTRY(_stext)
 #if defined(CONFIG_CPU_SH2)
 1:     .long   0x000000F0              ! IMASK=0xF
 #else
-1:     .long   0x400080F0              ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+1:     .long   0x500080F0              ! MD=1, RB=0, BL=1, FD=1, IMASK=0xF
 #endif
 ENTRY(stack_start)
 2:     .long   init_thread_union+THREAD_SIZE
index 2947d2bd12919e5d19117839a9d180ff918a93f3..32c385ef1011778cb172ddd33392343418b939b5 100644 (file)
@@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address)
        }
 
        tmp = handle_unaligned_access(instruction, regs,
-                                     &trapped_io_access, 1);
+                                     &trapped_io_access, 1, address);
        set_fs(oldfs);
        return tmp == 0;
 }
index ae5bac39b896d052e0b3b1b663e3edb69a754339..9dc447db8a44475b9584146bf710778f24504084 100644 (file)
@@ -283,6 +283,8 @@ void __init init_IRQ(void)
        if (sh_mv.mv_init_irq)
                sh_mv.mv_init_irq();
 
+       intc_finalize();
+
        irq_ctx_init(smp_processor_id());
 }
 
diff --git a/arch/sh/kernel/kdebugfs.c b/arch/sh/kernel/kdebugfs.c
new file mode 100644 (file)
index 0000000..e11c30b
--- /dev/null
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+
+struct dentry *arch_debugfs_dir;
+EXPORT_SYMBOL(arch_debugfs_dir);
+
+static int __init arch_kdebugfs_init(void)
+{
+       arch_debugfs_dir = debugfs_create_dir("sh", NULL);
+       if (!arch_debugfs_dir)
+               return -ENOMEM;
+
+       return 0;
+}
+arch_initcall(arch_kdebugfs_init);
index 4049d99f76e13ff5983b4a840a0673ed7ca47d5e..1208b09e95c32c7d728ffb5a47ed87b3ee403f2d 100644 (file)
@@ -20,9 +20,9 @@
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
-static struct kprobe saved_current_opcode;
-static struct kprobe saved_next_opcode;
-static struct kprobe saved_next_opcode2;
+static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
 
 #define OPCODE_JMP(x)  (((x) & 0xF0FF) == 0x402b)
 #define OPCODE_JSR(x)  (((x) & 0xF0FF) == 0x400b)
@@ -102,16 +102,21 @@ int __kprobes kprobe_handle_illslot(unsigned long pc)
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
-       if (saved_next_opcode.addr != 0x0) {
+       struct kprobe *saved = &__get_cpu_var(saved_next_opcode);
+
+       if (saved->addr) {
                arch_disarm_kprobe(p);
-               arch_disarm_kprobe(&saved_next_opcode);
-               saved_next_opcode.addr = 0x0;
-               saved_next_opcode.opcode = 0x0;
-
-               if (saved_next_opcode2.addr != 0x0) {
-                       arch_disarm_kprobe(&saved_next_opcode2);
-                       saved_next_opcode2.addr = 0x0;
-                       saved_next_opcode2.opcode = 0x0;
+               arch_disarm_kprobe(saved);
+
+               saved->addr = NULL;
+               saved->opcode = 0;
+
+               saved = &__get_cpu_var(saved_next_opcode2);
+               if (saved->addr) {
+                       arch_disarm_kprobe(saved);
+
+                       saved->addr = NULL;
+                       saved->opcode = 0;
                }
        }
 }
@@ -141,57 +146,59 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
  */
 static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
-       kprobe_opcode_t *addr = NULL;
-       saved_current_opcode.addr = (kprobe_opcode_t *) (regs->pc);
-       addr = saved_current_opcode.addr;
+       __get_cpu_var(saved_current_opcode).addr = (kprobe_opcode_t *)regs->pc;
 
        if (p != NULL) {
+               struct kprobe *op1, *op2;
+
                arch_disarm_kprobe(p);
 
+               op1 = &__get_cpu_var(saved_next_opcode);
+               op2 = &__get_cpu_var(saved_next_opcode2);
+
                if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
                        unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
-                       saved_next_opcode.addr =
-                           (kprobe_opcode_t *) regs->regs[reg_nr];
+                       op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
                } else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
                        unsigned long disp = (p->opcode & 0x0FFF);
-                       saved_next_opcode.addr =
+                       op1->addr =
                            (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
 
                } else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
                        unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
-                       saved_next_opcode.addr =
+                       op1->addr =
                            (kprobe_opcode_t *) (regs->pc + 4 +
                                                 regs->regs[reg_nr]);
 
                } else if (OPCODE_RTS(p->opcode)) {
-                       saved_next_opcode.addr = (kprobe_opcode_t *) regs->pr;
+                       op1->addr = (kprobe_opcode_t *) regs->pr;
 
                } else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
                        unsigned long disp = (p->opcode & 0x00FF);
                        /* case 1 */
-                       saved_next_opcode.addr = p->addr + 1;
+                       op1->addr = p->addr + 1;
                        /* case 2 */
-                       saved_next_opcode2.addr =
+                       op2->addr =
                            (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
-                       saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
-                       arch_arm_kprobe(&saved_next_opcode2);
+                       op2->opcode = *(op2->addr);
+                       arch_arm_kprobe(op2);
 
                } else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
                        unsigned long disp = (p->opcode & 0x00FF);
                        /* case 1 */
-                       saved_next_opcode.addr = p->addr + 2;
+                       op1->addr = p->addr + 2;
                        /* case 2 */
-                       saved_next_opcode2.addr =
+                       op2->addr =
                            (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
-                       saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
-                       arch_arm_kprobe(&saved_next_opcode2);
+                       op2->opcode = *(op2->addr);
+                       arch_arm_kprobe(op2);
 
                } else {
-                       saved_next_opcode.addr = p->addr + 1;
+                       op1->addr = p->addr + 1;
                }
 
-               saved_next_opcode.opcode = *(saved_next_opcode.addr);
-               arch_arm_kprobe(&saved_next_opcode);
+               op1->opcode = *(op1->addr);
+               arch_arm_kprobe(op1);
        }
 }
 
@@ -376,21 +383,23 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
                cur->post_handler(cur, regs, 0);
        }
 
-       if (saved_next_opcode.addr != 0x0) {
-               arch_disarm_kprobe(&saved_next_opcode);
-               saved_next_opcode.addr = 0x0;
-               saved_next_opcode.opcode = 0x0;
+       p = &__get_cpu_var(saved_next_opcode);
+       if (p->addr) {
+               arch_disarm_kprobe(p);
+               p->addr = NULL;
+               p->opcode = 0;
 
-               addr = saved_current_opcode.addr;
-               saved_current_opcode.addr = 0x0;
+               addr = __get_cpu_var(saved_current_opcode).addr;
+               __get_cpu_var(saved_current_opcode).addr = NULL;
 
                p = get_kprobe(addr);
                arch_arm_kprobe(p);
 
-               if (saved_next_opcode2.addr != 0x0) {
-                       arch_disarm_kprobe(&saved_next_opcode2);
-                       saved_next_opcode2.addr = 0x0;
-                       saved_next_opcode2.opcode = 0x0;
+               p = &__get_cpu_var(saved_next_opcode2);
+               if (p->addr) {
+                       arch_disarm_kprobe(p);
+                       p->addr = NULL;
+                       p->opcode = 0;
                }
        }
 
@@ -572,14 +581,5 @@ static struct kprobe trampoline_p = {
 
 int __init arch_init_kprobes(void)
 {
-       saved_next_opcode.addr = 0x0;
-       saved_next_opcode.opcode = 0x0;
-
-       saved_current_opcode.addr = 0x0;
-       saved_current_opcode.opcode = 0x0;
-
-       saved_next_opcode2.addr = 0x0;
-       saved_next_opcode2.opcode = 0x0;
-
        return register_kprobe(&trampoline_p);
 }
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..0a05983
--- /dev/null
@@ -0,0 +1,33 @@
+#include <linux/ptrace.h>
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:      the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->offset;
+       return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:    the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (roff->offset == offset)
+                       return roff->name;
+       return NULL;
+}
index 6c4bbba2a67573e2d1a72d2362bc28b4af4e2428..2cd42b58cb204993a08b67d21266fcbf294db818 100644 (file)
@@ -274,6 +274,33 @@ static int dspregs_active(struct task_struct *target,
 }
 #endif
 
+const struct pt_regs_offset regoffset_table[] = {
+       REGS_OFFSET_NAME(0),
+       REGS_OFFSET_NAME(1),
+       REGS_OFFSET_NAME(2),
+       REGS_OFFSET_NAME(3),
+       REGS_OFFSET_NAME(4),
+       REGS_OFFSET_NAME(5),
+       REGS_OFFSET_NAME(6),
+       REGS_OFFSET_NAME(7),
+       REGS_OFFSET_NAME(8),
+       REGS_OFFSET_NAME(9),
+       REGS_OFFSET_NAME(10),
+       REGS_OFFSET_NAME(11),
+       REGS_OFFSET_NAME(12),
+       REGS_OFFSET_NAME(13),
+       REGS_OFFSET_NAME(14),
+       REGS_OFFSET_NAME(15),
+       REG_OFFSET_NAME(pc),
+       REG_OFFSET_NAME(pr),
+       REG_OFFSET_NAME(sr),
+       REG_OFFSET_NAME(gbr),
+       REG_OFFSET_NAME(mach),
+       REG_OFFSET_NAME(macl),
+       REG_OFFSET_NAME(tra),
+       REG_OFFSET_END,
+};
+
 /*
  * These are our native regset flavours.
  */
index 5fd644da7f022dc88380bb3422c215d578c8410d..e0fb065914aa18ce7fefcb38b54aa06f327a3431 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -252,6 +252,85 @@ static int fpregs_active(struct task_struct *target,
 }
 #endif
 
+const struct pt_regs_offset regoffset_table[] = {
+       REG_OFFSET_NAME(pc),
+       REG_OFFSET_NAME(sr),
+       REG_OFFSET_NAME(syscall_nr),
+       REGS_OFFSET_NAME(0),
+       REGS_OFFSET_NAME(1),
+       REGS_OFFSET_NAME(2),
+       REGS_OFFSET_NAME(3),
+       REGS_OFFSET_NAME(4),
+       REGS_OFFSET_NAME(5),
+       REGS_OFFSET_NAME(6),
+       REGS_OFFSET_NAME(7),
+       REGS_OFFSET_NAME(8),
+       REGS_OFFSET_NAME(9),
+       REGS_OFFSET_NAME(10),
+       REGS_OFFSET_NAME(11),
+       REGS_OFFSET_NAME(12),
+       REGS_OFFSET_NAME(13),
+       REGS_OFFSET_NAME(14),
+       REGS_OFFSET_NAME(15),
+       REGS_OFFSET_NAME(16),
+       REGS_OFFSET_NAME(17),
+       REGS_OFFSET_NAME(18),
+       REGS_OFFSET_NAME(19),
+       REGS_OFFSET_NAME(20),
+       REGS_OFFSET_NAME(21),
+       REGS_OFFSET_NAME(22),
+       REGS_OFFSET_NAME(23),
+       REGS_OFFSET_NAME(24),
+       REGS_OFFSET_NAME(25),
+       REGS_OFFSET_NAME(26),
+       REGS_OFFSET_NAME(27),
+       REGS_OFFSET_NAME(28),
+       REGS_OFFSET_NAME(29),
+       REGS_OFFSET_NAME(30),
+       REGS_OFFSET_NAME(31),
+       REGS_OFFSET_NAME(32),
+       REGS_OFFSET_NAME(33),
+       REGS_OFFSET_NAME(34),
+       REGS_OFFSET_NAME(35),
+       REGS_OFFSET_NAME(36),
+       REGS_OFFSET_NAME(37),
+       REGS_OFFSET_NAME(38),
+       REGS_OFFSET_NAME(39),
+       REGS_OFFSET_NAME(40),
+       REGS_OFFSET_NAME(41),
+       REGS_OFFSET_NAME(42),
+       REGS_OFFSET_NAME(43),
+       REGS_OFFSET_NAME(44),
+       REGS_OFFSET_NAME(45),
+       REGS_OFFSET_NAME(46),
+       REGS_OFFSET_NAME(47),
+       REGS_OFFSET_NAME(48),
+       REGS_OFFSET_NAME(49),
+       REGS_OFFSET_NAME(50),
+       REGS_OFFSET_NAME(51),
+       REGS_OFFSET_NAME(52),
+       REGS_OFFSET_NAME(53),
+       REGS_OFFSET_NAME(54),
+       REGS_OFFSET_NAME(55),
+       REGS_OFFSET_NAME(56),
+       REGS_OFFSET_NAME(57),
+       REGS_OFFSET_NAME(58),
+       REGS_OFFSET_NAME(59),
+       REGS_OFFSET_NAME(60),
+       REGS_OFFSET_NAME(61),
+       REGS_OFFSET_NAME(62),
+       REGS_OFFSET_NAME(63),
+       TREGS_OFFSET_NAME(0),
+       TREGS_OFFSET_NAME(1),
+       TREGS_OFFSET_NAME(2),
+       TREGS_OFFSET_NAME(3),
+       TREGS_OFFSET_NAME(4),
+       TREGS_OFFSET_NAME(5),
+       TREGS_OFFSET_NAME(6),
+       TREGS_OFFSET_NAME(7),
+       REG_OFFSET_END,
+};
+
 /*
  * These are our native regset flavours.
  */
@@ -395,10 +474,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
 {
 #define WPC_DBRMODE 0x0d104008
-       static int first_call = 1;
+       static unsigned long first_call;
 
-       lock_kernel();
-       if (first_call) {
+       if (!test_and_set_bit(0, &first_call)) {
                /* Set WPC.DBRMODE to 0.  This makes all debug events get
                 * delivered through RESVEC, i.e. into the handlers in entry.S.
                 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
@@ -408,9 +486,7 @@ asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
                 * the remote gdb.) */
                printk("DBRMODE set to 0 to permit native debugging\n");
                poke_real_address_q(WPC_DBRMODE, 0);
-               first_call = 0;
        }
-       unlock_kernel();
 
        return sys_ptrace(request, pid, addr, data);
 }
index b1fca66bb92eca13b57e2ed6f94cc4ae383cbebd..ca6a5ca64015bf223e64e1303e07bdfa17fd03e8 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/addrspace.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
 
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
@@ -25,6 +26,9 @@ static void native_machine_restart(char * __unused)
 {
        local_irq_disable();
 
+       /* Destroy all of the TLBs in preparation for reset by MMU */
+       __flush_tlb_global();
+
        /* Address error with SR.BL=1 first. */
        trigger_address_error();
 
index e769401a78ba3218946620d62ad2a83875448ea7..4e278467f76ce5f0fbc7cdbd90bd7d1eff0002e6 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/err.h>
-#include <linux/debugfs.h>
 #include <linux/crash_dump.h>
 #include <linux/mmzone.h>
 #include <linux/clk.h>
@@ -136,8 +135,9 @@ void __init check_for_initrd(void)
                goto disable;
        }
 
-       if (unlikely(start < PAGE_OFFSET)) {
-               pr_err("initrd start < PAGE_OFFSET\n");
+       if (unlikely(start < __MEMORY_START)) {
+               pr_err("initrd start (%08lx) < __MEMORY_START(%x)\n",
+                       start, __MEMORY_START);
                goto disable;
        }
 
@@ -158,7 +158,7 @@ void __init check_for_initrd(void)
        /*
         * Address sanitization
         */
-       initrd_start = (unsigned long)__va(__pa(start));
+       initrd_start = (unsigned long)__va(start);
        initrd_end = initrd_start + INITRD_SIZE;
 
        memblock_reserve(__pa(initrd_start), INITRD_SIZE);
@@ -458,17 +458,3 @@ const struct seq_operations cpuinfo_op = {
        .show   = show_cpuinfo,
 };
 #endif /* CONFIG_PROC_FS */
-
-struct dentry *sh_debugfs_root;
-
-static int __init sh_debugfs_init(void)
-{
-       sh_debugfs_root = debugfs_create_dir("sh", NULL);
-       if (!sh_debugfs_root)
-               return -ENOMEM;
-       if (IS_ERR(sh_debugfs_root))
-               return PTR_ERR(sh_debugfs_root);
-
-       return 0;
-}
-arch_initcall(sh_debugfs_init);
index 19fd11dd9871aadf7c6667eb9d97f473a5e813dc..e872e81add8a96ed12709964768a699f8a50306d 100644 (file)
@@ -353,3 +353,25 @@ ENTRY(sys_call_table)
        .long sys_pwritev
        .long sys_rt_tgsigqueueinfo     /* 335 */
        .long sys_perf_event_open
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
+       /* Broken-out socket family */
+       .long sys_socket                /* 340 */
+       .long sys_bind
+       .long sys_connect
+       .long sys_listen
+       .long sys_accept
+       .long sys_getsockname   /* 345 */
+       .long sys_getpeername
+       .long sys_socketpair
+       .long sys_send
+       .long sys_sendto
+       .long sys_recv                  /* 350 */
+       .long sys_recvfrom
+       .long sys_shutdown
+       .long sys_setsockopt
+       .long sys_getsockopt
+       .long sys_sendmsg               /* 355 */
+       .long sys_recvmsg
+       .long sys_recvmmsg
index 2048a20d7c80c4172b80f1bc3074290e935f42bd..66585708ce90d257333eb424851da9f1415ff646 100644 (file)
@@ -393,3 +393,6 @@ sys_call_table:
        .long sys_perf_event_open
        .long sys_recvmmsg              /* 365 */
        .long sys_accept4
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
index c3d86fa71ddfc9bbe2b98819fe9a2513becb5e8e..3484c2f65aba32874f40738ee9b78c401354349c 100644 (file)
@@ -5,7 +5,7 @@
  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  *                  Copyright (C) 2000 Philipp Rumpf
  *                  Copyright (C) 2000 David Howells
- *                  Copyright (C) 2002 - 2007 Paul Mundt
+ *                  Copyright (C) 2002 - 2010 Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -26,6 +26,7 @@
 #include <linux/limits.h>
 #include <linux/sysfs.h>
 #include <linux/uaccess.h>
+#include <linux/perf_event.h>
 #include <asm/system.h>
 #include <asm/alignment.h>
 #include <asm/fpu.h>
@@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs,
 #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
 
 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
-                           struct mem_access *ma, int expected)
+                           struct mem_access *ma, int expected,
+                           unsigned long address)
 {
        u_int rm;
        int ret, index;
@@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
        index = (instruction>>8)&15;    /* 0x0F00 */
        rm = regs->regs[index];
 
-       /* shout about fixups */
-       if (!expected)
+       /*
+        * Log the unexpected fixups, and then pass them on to perf.
+        *
+        * We intentionally don't report the expected cases to perf as
+        * otherwise the trapped I/O case will skew the results too much
+        * to be useful.
+        */
+       if (!expected) {
                unaligned_fixups_notify(current, instruction, regs);
+               perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
+                             regs, address);
+       }
 
        ret = -EFAULT;
        switch (instruction&0xF000) {
@@ -574,7 +585,8 @@ fixup:
 
                set_fs(USER_DS);
                tmp = handle_unaligned_access(instruction, regs,
-                                             &user_mem_access, 0);
+                                             &user_mem_access, 0,
+                                             address);
                set_fs(oldfs);
 
                if (tmp == 0)
@@ -607,8 +619,8 @@ uspace_segv:
 
                unaligned_fixups_notify(current, instruction, regs);
 
-               handle_unaligned_access(instruction, regs,
-                                       &user_mem_access, 0);
+               handle_unaligned_access(instruction, regs, &user_mem_access,
+                                       0, address);
                set_fs(oldfs);
        }
 }
@@ -802,6 +814,9 @@ void __cpuinit per_cpu_trap_init(void)
                     : /* no output */
                     : "r" (&vbr_base)
                     : "memory");
+
+       /* disable exception blocking now when the vbr has been setup */
+       clear_bl_bit();
 }
 
 void *set_exception_table_vec(unsigned int vec, void *handler)
index e67e140bf1f682f6c41edeececa7b2b4165e7496..6713ca97e553ea68a5743a4f3e2a373f9b23f822 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
 #include <linux/module.h>
+#include <linux/perf_event.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -50,7 +51,7 @@ asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
        do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
 }
 
-spinlock_t die_lock;
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
@@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs,
                return error;
        }
 
+       perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
        destreg = (opcode >> 4) & 0x3f;
        if (user_mode(regs)) {
                __u64 buffer;
@@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs,
                return error;
        }
 
+       perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
        srcreg = (opcode >> 4) & 0x3f;
        if (user_mode(regs)) {
                __u64 buffer;
@@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
                return error;
        }
 
+       perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
        destreg = (opcode >> 4) & 0x3f;
        if (user_mode(regs)) {
                __u64 buffer;
@@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
                return error;
        }
 
+       perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
        srcreg = (opcode >> 4) & 0x3f;
        if (user_mode(regs)) {
                __u64 buffer;
index dab4d2129812365deb1d64cf5975fa23efc8381b..7b95f29e31749ec180e67028424580fadda1c3af 100644 (file)
@@ -30,4 +30,4 @@ lib-$(CONFIG_MMU)             += copy_page.o __clear_user.o
 lib-$(CONFIG_MCOUNT)           += mcount.o
 lib-y                          += $(memcpy-y) $(memset-y) $(udivsi3-y)
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index 1fcdb12209754ed20fb92721ca7906a05b7d3bb9..f76a5090d5d1b51e78221432b5340c4a8eb8bbcd 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/perf_event.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
        struct task_struct *tsk = current;
        struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
 
+       perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
+
        if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
                /* initialize once. */
                fpu_init(fpu);
index 1445ca6257df65640b1fd9007ab66bee52fed924..09370392aff15d791d612ac57bcdf0c6031d8443 100644 (file)
@@ -168,6 +168,10 @@ config IOREMAP_FIXED
 config UNCACHED_MAPPING
        bool
 
+config HAVE_SRAM_POOL
+       bool
+       select GENERIC_ALLOCATOR
+
 choice
        prompt "Kernel page size"
        default PAGE_SIZE_4KB
index 53f7c684afb25b53515d03ddd3d784e18c5a45ff..ab89ea4f941492901d215893a4b1c1b56ebef2f4 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_PMB)             += pmb.o
 obj-$(CONFIG_NUMA)             += numa.o
 obj-$(CONFIG_IOREMAP_FIXED)    += ioremap_fixed.o
 obj-$(CONFIG_UNCACHED_MAPPING) += uncached.o
+obj-$(CONFIG_HAVE_SRAM_POOL)   += sram.o
 
 # Special flags for fault_64.o.  This puts restrictions on the number of
 # caller-save registers that the compiler can target when building this file.
@@ -66,4 +67,4 @@ CFLAGS_fault_64.o += -ffixed-r7 \
        -ffixed-r60 -ffixed-r61 -ffixed-r62 \
        -fomit-frame-pointer
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index cd8c3bf39b5a8390efbc22df4e8523af05714d99..74c03ecc48718c6e41abb7b59f50f715eb992681 100644 (file)
@@ -63,7 +63,7 @@ static int __init asids_debugfs_init(void)
 {
        struct dentry *asids_dentry;
 
-       asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root,
+       asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
                                           NULL, &asids_debugfs_fops);
        if (!asids_dentry)
                return -ENOMEM;
index 690ed010d00207251f8104ea119bda948849323c..52411462c4096f973243e5c05acc9ebfc357819a 100644 (file)
@@ -126,25 +126,19 @@ static int __init cache_debugfs_init(void)
 {
        struct dentry *dcache_dentry, *icache_dentry;
 
-       dcache_dentry = debugfs_create_file("dcache", S_IRUSR, sh_debugfs_root,
+       dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
                                            (unsigned int *)CACHE_TYPE_DCACHE,
                                            &cache_debugfs_fops);
        if (!dcache_dentry)
                return -ENOMEM;
-       if (IS_ERR(dcache_dentry))
-               return PTR_ERR(dcache_dentry);
 
-       icache_dentry = debugfs_create_file("icache", S_IRUSR, sh_debugfs_root,
+       icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
                                            (unsigned int *)CACHE_TYPE_ICACHE,
                                            &cache_debugfs_fops);
        if (!icache_dentry) {
                debugfs_remove(dcache_dentry);
                return -ENOMEM;
        }
-       if (IS_ERR(icache_dentry)) {
-               debugfs_remove(dcache_dentry);
-               return PTR_ERR(icache_dentry);
-       }
 
        return 0;
 }
index c86a08540258bf72ac09821f13a5c1c94fe9b41d..0387932869904a042472cca19b65141b5b8bdc9f 100644 (file)
@@ -38,11 +38,12 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
        void *ret, *ret_nocache;
        int order = get_order(size);
 
+       gfp |= __GFP_ZERO;
+
        ret = (void *)__get_free_pages(gfp, order);
        if (!ret)
                return NULL;
 
-       memset(ret, 0, size);
        /*
         * Pages from the page allocator may have data present in
         * cache. So flush the cache before using uncached memory.
index 552bea5113f550c415f2d9d70b86082e905b0814..3385b28acaac5f072b8b773c810b6ad5a4e7ae5b 100644 (file)
@@ -47,7 +47,6 @@ static pte_t *__get_pte_phys(unsigned long addr)
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte;
 
        pgd = pgd_offset_k(addr);
        if (pgd_none(*pgd)) {
@@ -67,8 +66,7 @@ static pte_t *__get_pte_phys(unsigned long addr)
                return NULL;
        }
 
-       pte = pte_offset_kernel(pmd, addr);
-       return pte;
+       return pte_offset_kernel(pmd, addr);
 }
 
 static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -125,13 +123,45 @@ void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
        clear_pte_phys(address, prot);
 }
 
+static pmd_t * __init one_md_table_init(pud_t *pud)
+{
+       if (pud_none(*pud)) {
+               pmd_t *pmd;
+
+               pmd = alloc_bootmem_pages(PAGE_SIZE);
+               pud_populate(&init_mm, pud, pmd);
+               BUG_ON(pmd != pmd_offset(pud, 0));
+       }
+
+       return pmd_offset(pud, 0);
+}
+
+static pte_t * __init one_page_table_init(pmd_t *pmd)
+{
+       if (pmd_none(*pmd)) {
+               pte_t *pte;
+
+               pte = alloc_bootmem_pages(PAGE_SIZE);
+               pmd_populate_kernel(&init_mm, pmd, pte);
+               BUG_ON(pte != pte_offset_kernel(pmd, 0));
+       }
+
+       return pte_offset_kernel(pmd, 0);
+}
+
+static pte_t * __init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
+                                           unsigned long vaddr, pte_t *lastpte)
+{
+       return pte;
+}
+
 void __init page_table_range_init(unsigned long start, unsigned long end,
                                         pgd_t *pgd_base)
 {
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte;
+       pte_t *pte = NULL;
        int i, j, k;
        unsigned long vaddr;
 
@@ -144,19 +174,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
        for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
                pud = (pud_t *)pgd;
                for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
-#ifdef __PAGETABLE_PMD_FOLDED
-                       pmd = (pmd_t *)pud;
-#else
-                       pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
-                       pud_populate(&init_mm, pud, pmd);
+                       pmd = one_md_table_init(pud);
+#ifndef __PAGETABLE_PMD_FOLDED
                        pmd += k;
 #endif
                        for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
-                               if (pmd_none(*pmd)) {
-                                       pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-                                       pmd_populate_kernel(&init_mm, pmd, pte);
-                                       BUG_ON(pte != pte_offset_kernel(pmd, 0));
-                               }
+                               pte = page_table_kmap_check(one_page_table_init(pmd),
+                                                           pmd, vaddr, pte);
                                vaddr += PMD_SIZE;
                        }
                        k = 0;
index 7694f50c90347d619ac1c5a77be8e5d636f2f5fb..36312d254faf3bb7714375b9e60c6844c754ab8e 100644 (file)
@@ -67,6 +67,10 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
        BUG();
 }
 
+void __flush_tlb_global(void)
+{
+}
+
 void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 }
index 6379091a164764040c57fce64b9a9dae521bff41..b20b1b3eee4b267778102e0420f9119a88cf959e 100644 (file)
@@ -40,7 +40,7 @@ struct pmb_entry {
        unsigned long flags;
        unsigned long size;
 
-       spinlock_t lock;
+       raw_spinlock_t lock;
 
        /*
         * 0 .. NR_PMB_ENTRIES for specific entry selection, or
@@ -265,7 +265,7 @@ static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
 
        memset(pmbe, 0, sizeof(struct pmb_entry));
 
-       spin_lock_init(&pmbe->lock);
+       raw_spin_lock_init(&pmbe->lock);
 
        pmbe->vpn       = vpn;
        pmbe->ppn       = ppn;
@@ -327,9 +327,9 @@ static void set_pmb_entry(struct pmb_entry *pmbe)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&pmbe->lock, flags);
+       raw_spin_lock_irqsave(&pmbe->lock, flags);
        __set_pmb_entry(pmbe);
-       spin_unlock_irqrestore(&pmbe->lock, flags);
+       raw_spin_unlock_irqrestore(&pmbe->lock, flags);
 }
 #endif /* CONFIG_PM */
 
@@ -368,7 +368,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
                                return PTR_ERR(pmbe);
                        }
 
-                       spin_lock_irqsave(&pmbe->lock, flags);
+                       raw_spin_lock_irqsave(&pmbe->lock, flags);
 
                        pmbe->size = pmb_sizes[i].size;
 
@@ -383,9 +383,10 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
                         * entries for easier tear-down.
                         */
                        if (likely(pmbp)) {
-                               spin_lock(&pmbp->lock);
+                               raw_spin_lock_nested(&pmbp->lock,
+                                                    SINGLE_DEPTH_NESTING);
                                pmbp->link = pmbe;
-                               spin_unlock(&pmbp->lock);
+                               raw_spin_unlock(&pmbp->lock);
                        }
 
                        pmbp = pmbe;
@@ -398,7 +399,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
                        i--;
                        mapped++;
 
-                       spin_unlock_irqrestore(&pmbe->lock, flags);
+                       raw_spin_unlock_irqrestore(&pmbe->lock, flags);
                }
        } while (size >= SZ_16M);
 
@@ -627,15 +628,14 @@ static void __init pmb_synchronize(void)
                        continue;
                }
 
-               spin_lock_irqsave(&pmbe->lock, irqflags);
+               raw_spin_lock_irqsave(&pmbe->lock, irqflags);
 
                for (j = 0; j < ARRAY_SIZE(pmb_sizes); j++)
                        if (pmb_sizes[j].flag == size)
                                pmbe->size = pmb_sizes[j].size;
 
                if (pmbp) {
-                       spin_lock(&pmbp->lock);
-
+                       raw_spin_lock_nested(&pmbp->lock, SINGLE_DEPTH_NESTING);
                        /*
                         * Compare the previous entry against the current one to
                         * see if the entries span a contiguous mapping. If so,
@@ -644,13 +644,12 @@ static void __init pmb_synchronize(void)
                         */
                        if (pmb_can_merge(pmbp, pmbe))
                                pmbp->link = pmbe;
-
-                       spin_unlock(&pmbp->lock);
+                       raw_spin_unlock(&pmbp->lock);
                }
 
                pmbp = pmbe;
 
-               spin_unlock_irqrestore(&pmbe->lock, irqflags);
+               raw_spin_unlock_irqrestore(&pmbe->lock, irqflags);
        }
 }
 
@@ -757,7 +756,7 @@ static void __init pmb_resize(void)
                /*
                 * Found it, now resize it.
                 */
-               spin_lock_irqsave(&pmbe->lock, flags);
+               raw_spin_lock_irqsave(&pmbe->lock, flags);
 
                pmbe->size = SZ_16M;
                pmbe->flags &= ~PMB_SZ_MASK;
@@ -767,7 +766,7 @@ static void __init pmb_resize(void)
 
                __set_pmb_entry(pmbe);
 
-               spin_unlock_irqrestore(&pmbe->lock, flags);
+               raw_spin_unlock_irqrestore(&pmbe->lock, flags);
        }
 
        read_unlock(&pmb_rwlock);
@@ -866,11 +865,9 @@ static int __init pmb_debugfs_init(void)
        struct dentry *dentry;
 
        dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
-                                    sh_debugfs_root, NULL, &pmb_debugfs_fops);
+                                    arch_debugfs_dir, NULL, &pmb_debugfs_fops);
        if (!dentry)
                return -ENOMEM;
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
 
        return 0;
 }
diff --git a/arch/sh/mm/sram.c b/arch/sh/mm/sram.c
new file mode 100644 (file)
index 0000000..bc156ec
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SRAM pool for tiny memories not otherwise managed.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sram.h>
+
+/*
+ * This provides a standard SRAM pool for tiny memories that can be
+ * added either by the CPU or the platform code. Typical SRAM sizes
+ * to be inserted in to the pool will generally be less than the page
+ * size, with anything more reasonably sized handled as a NUMA memory
+ * node.
+ */
+struct gen_pool *sram_pool;
+
+static int __init sram_pool_init(void)
+{
+       /*
+        * This is a global pool, we don't care about node locality.
+        */
+       sram_pool = gen_pool_create(1, -1);
+       if (unlikely(!sram_pool))
+               return -ENOMEM;
+
+       return 0;
+}
+core_initcall(sram_pool_init);
index 229bf75f28df32d753b1f8c2d5b7d605a9474f36..dea637a09246c2f7136255dff64b00c8558b7155 100644 (file)
@@ -151,15 +151,13 @@ static int __init tlb_debugfs_init(void)
 {
        struct dentry *itlb, *utlb;
 
-       itlb = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root,
+       itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
                                   (unsigned int *)TLB_TYPE_ITLB,
                                   &tlb_debugfs_fops);
        if (unlikely(!itlb))
                return -ENOMEM;
-       if (IS_ERR(itlb))
-               return PTR_ERR(itlb);
 
-       utlb = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root,
+       utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
                                   (unsigned int *)TLB_TYPE_UTLB,
                                   &tlb_debugfs_fops);
        if (unlikely(!utlb)) {
@@ -167,11 +165,6 @@ static int __init tlb_debugfs_init(void)
                return -ENOMEM;
        }
 
-       if (IS_ERR(utlb)) {
-               debugfs_remove(itlb);
-               return PTR_ERR(utlb);
-       }
-
        return 0;
 }
 module_init(tlb_debugfs_init);
index 3fbe03ce8fe3a665768516dd4e341e783e164e69..a6a20d6de4c0b9535679a85ebbcc8522810b86cc 100644 (file)
@@ -119,3 +119,19 @@ void local_flush_tlb_mm(struct mm_struct *mm)
                local_irq_restore(flags);
        }
 }
+
+void __flush_tlb_global(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       /*
+        * This is the most destructive of the TLB flushing options,
+        * and will tear down all of the UTLB/ITLB mappings, including
+        * wired entries.
+        */
+       __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
+
+       local_irq_restore(flags);
+}
index 03db41cc126854bdf5b8e61ef7e918d6558e7db3..7f5810f5dfdc4b5141aabcacf7ca6b61f1b5bba5 100644 (file)
@@ -455,6 +455,11 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
         flush_tlb_all();
 }
 
+void __flush_tlb_global(void)
+{
+       flush_tlb_all();
+}
+
 void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 }
index b25aa554ee5e8d03882ef1ce52576796a096055d..9f56eb978024ef2b6e93497a6580d00dbc7f62eb 100644 (file)
@@ -52,6 +52,8 @@ MIGOR                 SH_MIGOR
 RSK7201                        SH_RSK7201
 RSK7203                        SH_RSK7203
 AP325RXA               SH_AP325RXA
+SH2007                 SH_SH2007
+SH7757LCR              SH_SH7757LCR
 SH7763RDP              SH_SH7763RDP
 SH7785LCR              SH_SH7785LCR
 SH7785LCR_PT           SH_SH7785LCR_PT
index 3e9d31401fb24e9dd1b6b3e67add09a4ea7f1468..8e7bafc5dd0eb412282c3c8f0ebfb1314e422cc0 100644 (file)
@@ -19,6 +19,7 @@ config SPARC
        bool
        default y
        select OF
+       select OF_PROMTREE
        select HAVE_IDE
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB if !SMP || SPARC64
index deeb0fba8029246bcd7c1984a2513824696f016b..3c93f08ce187d7234b36f9952813f29f5a3942fa 100644 (file)
@@ -7,7 +7,6 @@ header-y += display7seg.h
 header-y += envctrl.h
 header-y += fbio.h
 header-y += jsflash.h
-header-y += openprom.h
 header-y += openpromio.h
 header-y += perfctr.h
 header-y += psrcompat.h
index c792830636decfa4c3652d25d9947837bdf362f2..86666f70322e753430d661b6c854a5150208ff9e 100644 (file)
@@ -304,7 +304,8 @@ static struct linux_prom_registers fd_regs[2];
 static int sun_floppy_init(void)
 {
        char state[128];
-       int tnode, fd_node, num_regs;
+       phandle tnode, fd_node;
+       int num_regs;
        struct resource r;
 
        use_virtual_dma = 1;
index ec23b0a87b98fa1ea3038cb1e8b0141da05ec991..3d7afbb7f4bbd0ba4022151a3e09ef6e9ad645f8 100644 (file)
@@ -70,8 +70,8 @@ static inline void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
 extern struct page *kmap_atomic_to_page(void *vaddr);
 
 #define flush_cache_kmaps()    flush_cache_all()
index 963e1a45c35faa9df9197e38bb9e5b8c05bf4434..81cd43432dc0ea5027eb0757ae2e27e2b13c5358 100644 (file)
@@ -11,6 +11,8 @@
 #define LINUX_OPPROM_MAGIC      0x10010407
 
 #ifndef __ASSEMBLY__
+#include <linux/of.h>
+
 /* V0 prom device operations. */
 struct linux_dev_v0_funcs {
        int (*v0_devopen)(char *device_str);
@@ -26,7 +28,7 @@ struct linux_dev_v0_funcs {
 
 /* V2 and later prom device operations. */
 struct linux_dev_v2_funcs {
-       int (*v2_inst2pkg)(int d);      /* Convert ihandle to phandle */
+       phandle (*v2_inst2pkg)(int d);  /* Convert ihandle to phandle */
        char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
        void (*v2_dumb_mem_free)(char *va, unsigned sz);
 
@@ -168,12 +170,12 @@ struct linux_romvec {
 
 /* Routines for traversing the prom device tree. */
 struct linux_nodeops {
-       int (*no_nextnode)(int node);
-       int (*no_child)(int node);
-       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);
+       phandle (*no_nextnode)(phandle node);
+       phandle (*no_child)(phandle node);
+       int (*no_proplen)(phandle node, const char *name);
+       int (*no_getprop)(phandle node, const char *name, char *val);
+       int (*no_setprop)(phandle node, const char *name, char *val, int len);
+       char * (*no_nextprop)(phandle node, char *name);
 };
 
 /* More fun PROM structures for device probing. */
index 33e31ce6b31f56c4952083096fb9bc5c58928cd9..51296a6f5005389877ca17c234f670fa71a3f8c0 100644 (file)
@@ -30,7 +30,7 @@ extern unsigned int prom_rev, prom_prev;
 /* Root node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_root_node;
+extern phandle prom_root_node;
 
 /* Pointer to prom structure containing the device tree traversal
  * and usage utility functions.  Only prom-lib should use these,
@@ -178,68 +178,68 @@ extern void prom_putsegment(int context, unsigned long virt_addr,
 /* PROM device tree traversal functions... */
 
 /* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
 
 /* Get the next sibling node of the given node, or zero if no further
  * siblings exist.
  */
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle 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, const char *property);
+extern int prom_getproplen(phandle 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, const char *property,
+extern int __must_check prom_getproperty(phandle thisnode, const char *property,
                                         char *prop_buffer, int propbuf_size);
 
 /* Acquire an integer property. */
-extern int prom_getint(int node, char *property);
+extern int prom_getint(phandle node, char *property);
 
 /* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getintdefault(phandle node, char *property, int defval);
 
 /* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, char *prop);
+extern int prom_getbool(phandle node, char *prop);
 
 /* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, char *prop, char *buf, int bufsize);
 
 /* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, char *name);
+extern int prom_nodematch(phandle thisnode, char *name);
 
 /* Search all siblings starting at the passed node for "name" matching
  * the given string.  Returns the node on success, zero on failure.
  */
-extern int prom_searchsiblings(int node_start, char *name);
+extern phandle prom_searchsiblings(phandle node_start, char *name);
 
 /* Return the first property type, as a string, for the given node.
  * Returns a null string on error.
  */
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
 
 /* Returns the next property after the passed property for the given
  * node.  Returns null string on failure.
  */
-extern char *prom_nextprop(int node, char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, char *prev_property, char *buffer);
 
 /* Returns phandle of the path specified */
-extern int prom_finddevice(char *name);
+extern phandle prom_finddevice(char *name);
 
 /* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, char *property);
+extern int prom_node_has_property(phandle 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, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
                        int value_size);
 
-extern int prom_pathtoinode(char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(char *path);
+extern phandle prom_inst2pkg(int);
 
 /* Dorking with Bus ranges... */
 
@@ -247,13 +247,13 @@ extern int prom_inst2pkg(int);
 extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
 
 /* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent,
+extern void prom_apply_generic_ranges(phandle node, phandle parent,
                                      struct linux_prom_registers *sbusregs, int nregs);
 
 /* CPU probing helpers.  */
-int cpu_find_by_instance(int instance, int *prom_node, int *mid);
-int cpu_find_by_mid(int mid, int *prom_node);
-int cpu_get_hwmid(int prom_node);
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid);
+int cpu_find_by_mid(int mid, phandle *prom_node);
+int cpu_get_hwmid(phandle prom_node);
 
 extern spinlock_t prom_lock;
 
index 3e0b2d62303df55133d1f9547e8c984ba5dbbeb2..c9cc078e3e31531522fe5d531abcb0b72a1980b2 100644 (file)
@@ -16,7 +16,7 @@ extern char prom_version[];
 /* Root node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_root_node;
+extern phandle prom_root_node;
 
 /* PROM stdin and stdout */
 extern int prom_stdin, prom_stdout;
@@ -24,7 +24,7 @@ extern int prom_stdin, prom_stdout;
 /* /chosen node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_chosen_node;
+extern phandle prom_chosen_node;
 
 /* Helper values and strings in arch/sparc64/kernel/head.S */
 extern const char prom_peer_name[];
@@ -218,68 +218,69 @@ extern void prom_unmap(unsigned long size, unsigned long vaddr);
 /* PROM device tree traversal functions... */
 
 /* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
 
 /* Get the next sibling node of the given node, or zero if no further
  * siblings exist.
  */
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle 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, const char *property);
+extern int prom_getproplen(phandle 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 prom_getproperty(int thisnode, const char *property,
+extern int prom_getproperty(phandle thisnode, const char *property,
                            char *prop_buffer, int propbuf_size);
 
 /* Acquire an integer property. */
-extern int prom_getint(int node, const char *property);
+extern int prom_getint(phandle node, const char *property);
 
 /* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, const char *property, int defval);
+extern int prom_getintdefault(phandle node, const char *property, int defval);
 
 /* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, const char *prop);
+extern int prom_getbool(phandle node, const char *prop);
 
 /* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, const char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, const char *prop, char *buf,
+                          int bufsize);
 
 /* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, const char *name);
+extern int prom_nodematch(phandle thisnode, const char *name);
 
 /* Search all siblings starting at the passed node for "name" matching
  * the given string.  Returns the node on success, zero on failure.
  */
-extern int prom_searchsiblings(int node_start, const char *name);
+extern phandle prom_searchsiblings(phandle node_start, const char *name);
 
 /* Return the first property type, as a string, for the given node.
  * Returns a null string on error. Buffer should be at least 32B long.
  */
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
 
 /* Returns the next property after the passed property for the given
  * node.  Returns null string on failure. Buffer should be at least 32B long.
  */
-extern char *prom_nextprop(int node, const char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, const char *prev_property, char *buf);
 
 /* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, const char *property);
+extern int prom_node_has_property(phandle node, const char *property);
 
 /* Returns phandle of the path specified */
-extern int prom_finddevice(const char *name);
+extern phandle prom_finddevice(const char *name);
 
 /* 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, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
                        int value_size);
 
-extern int prom_pathtoinode(const char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(const char *path);
+extern phandle prom_inst2pkg(int);
 extern int prom_service_exists(const char *service_name);
 extern void prom_sun4v_guest_soft_state(void);
 
index 0ece77f477536b773a9bd310515008c3b152055c..303bd4dc82927b3bf85371c01200054f94e101bb 100644 (file)
@@ -304,10 +304,7 @@ BTFIXUPDEF_CALL(pte_t *, pte_offset_kernel, pmd_t *, unsigned long)
  * and sun4c is guaranteed to have no highmem anyway.
  */
 #define pte_offset_map(d, a)           pte_offset_kernel(d,a)
-#define pte_offset_map_nested(d, a)    pte_offset_kernel(d,a)
-
 #define pte_unmap(pte)         do{}while(0)
-#define pte_unmap_nested(pte)  do{}while(0)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
index f5b5fa76c02dbb2eb385220a5222c191f1bf2a8e..f8dddb7045bbb2d16744e09b4200969178c2eb89 100644 (file)
@@ -652,9 +652,7 @@ static inline int pte_special(pte_t pte)
         ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 #define pte_offset_kernel              pte_index
 #define pte_offset_map                 pte_index
-#define pte_offset_map_nested          pte_index
 #define pte_unmap(pte)                 do { } while (0)
-#define pte_unmap_nested(pte)          do { } while (0)
 
 /* Actual page table PTE updates.  */
 extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
index 291f12575eddcd598aca91ce46dbe1c9e08b31e1..56bbaadef6462a6eca1ccf6b375e951d42f51c8d 100644 (file)
@@ -18,6 +18,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <linux/types.h>
+#include <linux/of_pdt.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <asm/atomic.h>
@@ -67,8 +68,8 @@ extern struct device_node *of_console_device;
 extern char *of_console_path;
 extern char *of_console_options;
 
-extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-extern char *build_full_name(struct device_node *dp);
+extern void irq_trans_init(struct device_node *dp);
+extern char *build_path_component(struct device_node *dp);
 
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
index ee8d214cae1efe81c900ce9e279baafdd856c5bc..35f48837871aaf8bb185eea89aab0ba1e281910b 100644 (file)
@@ -23,7 +23,7 @@ static DEFINE_SPINLOCK(auxio_lock);
 
 void __init auxio_probe(void)
 {
-       int node, auxio_nd;
+       phandle node, auxio_nd;
        struct linux_prom_registers auxregs[1];
        struct resource r;
 
@@ -113,7 +113,7 @@ volatile unsigned char * auxio_power_register = NULL;
 void __init auxio_power_probe(void)
 {
        struct linux_prom_registers regs;
-       int node;
+       phandle node;
        struct resource r;
 
        /* Attempt to find the sun4m power control node. */
index 8cc2d56ffe9adfb5afb560f3389686fdd34e662e..89aa4eb20cf5b47b5819077796c34e47f3ca9c7c 100644 (file)
@@ -40,7 +40,7 @@ static unsigned char *dispDeviceBase __force_data;
 
 static unsigned char vga_font[cmapsz];
 
-static int __init btext_initialize(unsigned int node)
+static int __init btext_initialize(phandle node)
 {
        unsigned int width, height, depth, pitch;
        unsigned long address = 0;
@@ -309,7 +309,7 @@ static struct console btext_console = {
 
 int __init btext_find_display(void)
 {
-       unsigned int node;
+       phandle node;
        char type[32];
        int ret;
 
index 62dc7a02141332b0dabad5a60c1eb19b7fc89afd..d2eddd6647cd2d1debfb79d11a9bce1cc87e8c74 100644 (file)
@@ -31,9 +31,9 @@ static char *cpu_mid_prop(void)
        return "mid";
 }
 
-static int check_cpu_node(int nd, int *cur_inst,
-                         int (*compare)(int, int, void *), void *compare_arg,
-                         int *prom_node, int *mid)
+static int check_cpu_node(phandle nd, int *cur_inst,
+               int (*compare)(phandle, int, void *), void *compare_arg,
+               phandle *prom_node, int *mid)
 {
        if (!compare(nd, *cur_inst, compare_arg)) {
                if (prom_node)
@@ -51,8 +51,8 @@ static int check_cpu_node(int nd, int *cur_inst,
        return -ENODEV;
 }
 
-static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
-                        int *prom_node, int *mid)
+static int __cpu_find_by(int (*compare)(phandle, int, void *),
+               void *compare_arg, phandle *prom_node, int *mid)
 {
        struct device_node *dp;
        int cur_inst;
@@ -71,7 +71,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
        return -ENODEV;
 }
 
-static int cpu_instance_compare(int nd, int instance, void *_arg)
+static int cpu_instance_compare(phandle nd, int instance, void *_arg)
 {
        int desired_instance = (int) _arg;
 
@@ -80,13 +80,13 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
        return -ENODEV;
 }
 
-int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid)
 {
        return __cpu_find_by(cpu_instance_compare, (void *)instance,
                             prom_node, mid);
 }
 
-static int cpu_mid_compare(int nd, int instance, void *_arg)
+static int cpu_mid_compare(phandle nd, int instance, void *_arg)
 {
        int desired_mid = (int) _arg;
        int this_mid;
@@ -98,7 +98,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg)
        return -ENODEV;
 }
 
-int cpu_find_by_mid(int mid, int *prom_node)
+int cpu_find_by_mid(int mid, phandle *prom_node)
 {
        return __cpu_find_by(cpu_mid_compare, (void *)mid,
                             prom_node, NULL);
@@ -108,7 +108,7 @@ int cpu_find_by_mid(int mid, int *prom_node)
  * address (0-3).  This gives us the true hardware mid, which might have
  * some other bits set.  On 4d hardware and software mids are the same.
  */
-int cpu_get_hwmid(int prom_node)
+int cpu_get_hwmid(phandle prom_node)
 {
        return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
 }
@@ -119,7 +119,8 @@ void __init device_scan(void)
 
 #ifndef CONFIG_SMP
        {
-               int err, cpu_node;
+               phandle cpu_node;
+               int err;
                err = cpu_find_by_instance(0, &cpu_node, NULL);
                if (err) {
                        /* Probably a sun4e, Sun is trying to trick us ;-) */
index 6a7b4dbc8e09b6c11f8853002ab89130b1547b9e..2d51527d810fc811531dae33c4bafc281b47d924 100644 (file)
@@ -282,5 +282,5 @@ void __init leon_init_IRQ(void)
 
 void __init leon_init(void)
 {
-       prom_build_more = &leon_node_init;
+       of_pdt_build_more = &leon_node_init;
 }
index d36a8d391ca0639e6a2bb73defd5b2fd05bb38a2..aeaa09a3c655606fa01bdb90be3491983b6ecf98 100644 (file)
@@ -284,7 +284,7 @@ int __init pcic_probe(void)
        struct linux_prom_registers regs[PROMREG_MAX];
        struct linux_pbm_info* pbm;
        char namebuf[64];
-       int node;
+       phandle node;
        int err;
 
        if (pcic0_up) {
@@ -440,7 +440,7 @@ static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm,
 {
        struct linux_prom_pci_registers regs[PROMREG_MAX];
        int err;
-       int node = prom_getchild(pbm->prom_node);
+       phandle node = prom_getchild(pbm->prom_node);
 
        while(node) {
                err = prom_getproperty(node, "reg", 
index eeb04a782ec81d3c870d99f64299b5a8f991698e..cf5fe1c0b024b748b682498093f4a9fd759cf3dd 100644 (file)
@@ -4,12 +4,6 @@
 #include <linux/spinlock.h>
 #include <asm/prom.h>
 
-extern void * prom_early_alloc(unsigned long size);
-extern void irq_trans_init(struct device_node *dp);
-
-extern unsigned int prom_unique_id;
-
-extern char *build_path_component(struct device_node *dp);
 extern void of_console_init(void);
 
 extern unsigned int prom_early_allocated;
index 1f830da2ddf2317df09c8b62340c41050ba55883..ed25834328f4674f19dd7196fcc19153a337fd14 100644 (file)
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_pdt.h>
 #include <asm/prom.h>
 #include <asm/oplib.h>
 #include <asm/leon.h>
 
 #include "prom.h"
 
-void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-
 struct device_node *of_console_device;
 EXPORT_SYMBOL(of_console_device);
 
@@ -119,192 +118,47 @@ int of_find_in_proplist(const char *list, const char *match, int len)
 }
 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)
+/*
+ * SPARC32 and SPARC64's prom_nextprop() do things differently
+ * here, despite sharing the same interface.  SPARC32 doesn't fill in 'buf',
+ * returning NULL on an error.  SPARC64 fills in 'buf', but sets it to an
+ * empty string upon error.
+ */
+static int __init handle_nextprop_quirks(char *buf, const char *name)
 {
-       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 {
-               if (prev == NULL) {
-                       name = prom_firstprop(node, p->name);
-               } else {
-                       name = prom_nextprop(node, prev, p->name);
-               }
+       if (!name || strlen(name) == 0)
+               return -1;
 
-               if (!name || strlen(name) == 0) {
-                       tmp = p;
-                       return NULL;
-               }
 #ifdef CONFIG_SPARC32
-               strcpy(p->name, name);
+       strcpy(buf, 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->phandle = node;
-
-       dp->properties = build_prop_list(node);
-
-       irq_trans_init(dp);
-
-       return dp;
-}
-
-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 (!of_node_is_root(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, dp->path_component_name);
-
-       return n;
+       return 0;
 }
 
-static struct device_node * __init prom_build_tree(struct device_node *parent,
-                                                  phandle node,
-                                                  struct device_node ***nextp)
+static int __init prom_common_nextprop(phandle node, char *prev, char *buf)
 {
-       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);
-
-               if (prom_build_more)
-                       prom_build_more(dp, nextp);
-
-               node = prom_getsibling(node);
-       }
+       const char *name;
 
-       return ret;
+       buf[0] = '\0';
+       name = prom_nextprop(node, prev, buf);
+       return handle_nextprop_quirks(buf, name);
 }
 
 unsigned int prom_early_allocated __initdata;
 
+static struct of_pdt_ops prom_sparc_ops __initdata = {
+       .nextprop = prom_common_nextprop,
+       .getproplen = prom_getproplen,
+       .getproperty = prom_getproperty,
+       .getchild = prom_getchild,
+       .getsibling = prom_getsibling,
+};
+
 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->phandle),
-                                         &nextp);
+       of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops);
        of_console_init();
 
-       printk("PROM: Built device tree with %u bytes of memory.\n",
-              prom_early_allocated);
+       pr_info("PROM: Built device tree with %u bytes of memory.\n",
+                       prom_early_allocated);
 }
index 5f72de67588b876989ec96243b03e633442ad59c..29bafe051bb172ab8878dbc960a65730eea9e7f3 100644 (file)
@@ -315,7 +315,7 @@ void __init setup_arch(char **cmdline_p)
 
 #ifdef CONFIG_IP_PNP
        if (!ic_set_manually) {
-               int chosen = prom_finddevice ("/chosen");
+               phandle chosen = prom_finddevice("/chosen");
                u32 cl, sv, gw;
                
                cl = prom_getintdefault (chosen, "client-ip", 0);
index 060d0f3a61511ee2b1891837ea4de94ca398d69c..a4446c0fb7a1c7220084c035f804e34d084c7a48 100644 (file)
@@ -23,7 +23,7 @@ int this_is_starfire = 0;
 
 void check_if_starfire(void)
 {
-       int ssnode = prom_finddevice("/ssp-serial");
+       phandle ssnode = prom_finddevice("/ssp-serial");
        if (ssnode != 0 && ssnode != -1)
                this_is_starfire = 1;
 }
index f476a5f4af6a15187eab4279cc90147e88b6e58b..9aba8bd5a78b56a94c22d9387588d84bf85a97d3 100644 (file)
@@ -100,7 +100,7 @@ static void swift_clockstop(void)
 
 void __init clock_stop_probe(void)
 {
-       unsigned int node, clk_nd;
+       phandle node, clk_nd;
        char name[20];
     
        prom_getstring(prom_root_node, "name", name, sizeof(name));
index e139e9cbf5f7a2aaa94c7d8d2f561e67b1fa0951..5e50c09b7dcea796aceea1b88fbd3c0338955abf 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/fixmap.h>
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
-       unsigned long idx;
        unsigned long vaddr;
+       long idx, type;
 
        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
        pagefault_disable();
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 
@@ -63,44 +63,50 @@ void *kmap_atomic(struct page *page, enum km_type type)
 
        return (void*) vaddr;
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
+       int type;
 
        if (vaddr < FIXADDR_START) { // FIXME
                pagefault_enable();
                return;
        }
 
-       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+       type = kmap_atomic_idx_pop();
 
-/* XXX Fix - Anton */
+#ifdef CONFIG_DEBUG_HIGHMEM
+       {
+               unsigned long idx;
+
+               idx = type + KM_TYPE_NR * smp_processor_id();
+               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+
+               /* XXX Fix - Anton */
 #if 0
-       __flush_cache_one(vaddr);
+               __flush_cache_one(vaddr);
 #else
-       flush_cache_all();
+               flush_cache_all();
 #endif
 
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(&init_mm, vaddr, kmap_pte-idx);
-/* XXX Fix - Anton */
+               /*
+                * force other mappings to Oops if they'll try to access
+                * this pte without first remap it
+                */
+               pte_clear(&init_mm, vaddr, kmap_pte-idx);
+               /* XXX Fix - Anton */
 #if 0
-       __flush_tlb_one(vaddr);
+               __flush_tlb_one(vaddr);
 #else
-       flush_tlb_all();
+               flush_tlb_all();
 #endif
+       }
 #endif
-
        pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /* We may be fed a pagetable here by ptep_to_xxx and others. */
 struct page *kmap_atomic_to_page(void *ptr)
index 4c2572773b55a330868933b633882f9520a155ba..2f6ae1d1fb6b19c3475efec961812c991e417a79 100644 (file)
@@ -88,7 +88,7 @@ static void __init read_obp_memory(const char *property,
                                   struct linux_prom64_registers *regs,
                                   int *num_ents)
 {
-       int node = prom_finddevice("/memory");
+       phandle node = prom_finddevice("/memory");
        int prop_size = prom_getproplen(node, property);
        int ents, ret, i;
 
index b0b43aa5e45a483984b0acd7a4641c0765eb8859..92319aa8b66212c35b6ee377db990057d05ee0df 100644 (file)
@@ -1262,7 +1262,8 @@ extern unsigned long bootmem_init(unsigned long *pages_avail);
 
 void __init srmmu_paging_init(void)
 {
-       int i, cpunode;
+       int i;
+       phandle cpunode;
        char node_str[128];
        pgd_t *pgd;
        pmd_t *pmd;
@@ -1398,7 +1399,8 @@ static void __init srmmu_is_bad(void)
 
 static void __init init_vac_layout(void)
 {
-       int nd, cache_lines;
+       phandle nd;
+       int cache_lines;
        char node_str[128];
 #ifdef CONFIG_SMP
        int cpu = 0;
@@ -2082,7 +2084,7 @@ static void __init get_srmmu_type(void)
 
        /* Next check for Fujitsu Swift. */
        if(psr_typ == 0 && psr_vers == 4) {
-               int cpunode;
+               phandle cpunode;
                char node_str[128];
 
                /* Look if it is not a TurboSparc emulating Swift... */
index 4289f90f86972f6020318bf002162fccf5a968e8..ddd0d86e508ecff9924ebd2aef5fe262eb77906c 100644 (file)
@@ -420,7 +420,7 @@ volatile unsigned long __iomem *sun4c_memerr_reg = NULL;
 
 void __init sun4c_probe_memerr_reg(void)
 {
-       int node;
+       phandle node;
        struct linux_prom_registers regs[1];
 
        node = prom_getchild(prom_root_node);
index ccb36c7f9b8c600d1e24bf322d4f36df833df553..d342dba4dd54bb2c33f4a0804f383c2b34e3bc61 100644 (file)
@@ -20,7 +20,7 @@ enum prom_major_version prom_vers;
 unsigned int prom_rev, prom_prev;
 
 /* The root node of the prom device tree. */
-int prom_root_node;
+phandle prom_root_node;
 EXPORT_SYMBOL(prom_root_node);
 
 /* Pointer to the device tree operations structure. */
index 7b00f89490a4d1babbf14b7079b3072546743a1a..3ff911e7d25b057904cded5d5bae305fed25ad81 100644 (file)
@@ -19,7 +19,7 @@ char prom_version[80];
 
 /* The root node of the prom device tree. */
 int prom_stdin, prom_stdout;
-int prom_chosen_node;
+phandle prom_chosen_node;
 
 /* You must call prom_init() before you attempt to use any of the
  * routines in the prom library.  It returns 0 on success, 1 on
@@ -30,7 +30,7 @@ extern void prom_cif_init(void *, void *);
 
 void __init prom_init(void *cif_handler, void *cif_stack)
 {
-       int node;
+       phandle node;
 
        prom_cif_init(cif_handler, cif_stack);
 
index fac7899a29c39042ab0a69be31c6cc0bc1b8fb32..3f263a64857d5962c7738ec72b6c9bca16b7d353 100644 (file)
@@ -31,7 +31,8 @@ static int __init prom_meminit_v0(void)
 static int __init prom_meminit_v2(void)
 {
        struct linux_prom_registers reg[64];
-       int node, size, num_ents, i;
+       phandle node;
+       int size, num_ents, i;
 
        node = prom_searchsiblings(prom_getchild(prom_root_node), "memory");
        size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
index 6cb1581d6aef507fca9c036708cebe24e5ab053c..d24bc44e361ee20b654960cc7784176670705da6 100644 (file)
@@ -183,7 +183,8 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes)
 
 int prom_get_mmu_ihandle(void)
 {
-       int node, ret;
+       phandle node;
+       int ret;
 
        if (prom_mmu_ihandle_cache != 0)
                return prom_mmu_ihandle_cache;
@@ -201,7 +202,8 @@ int prom_get_mmu_ihandle(void)
 static int prom_get_memory_ihandle(void)
 {
        static int memory_ihandle_cache;
-       int node, ret;
+       phandle node;
+       int ret;
 
        if (memory_ihandle_cache != 0)
                return memory_ihandle_cache;
index aeff43e44e45a9d03580558dd4d8bc8cda35e022..541fc829c2077aac8ec2751ecc2033556e79b782 100644 (file)
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(prom_apply_obio_ranges);
 
 void __init prom_ranges_init(void)
 {
-       int node, obio_node;
+       phandle node, obio_node;
        int success;
 
        num_obio_ranges = 0;
@@ -89,8 +89,8 @@ void __init prom_ranges_init(void)
                prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges);
 }
 
-void
-prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
+void prom_apply_generic_ranges(phandle node, phandle parent,
+               struct linux_prom_registers *regs, int nregs)
 {
        int success;
        int num_ranges;
index b21592f8e3fe98db86e3fd1c69e72666989d8bce..63e08e149774fc6a0a30fcd9228abb83f434aae7 100644 (file)
@@ -20,10 +20,10 @@ extern void restore_current(void);
 static char promlib_buf[128];
 
 /* Internal version of prom_getchild that does not alter return values. */
-int __prom_getchild(int node)
+phandle __prom_getchild(phandle node)
 {
        unsigned long flags;
-       int cnode;
+       phandle cnode;
 
        spin_lock_irqsave(&prom_lock, flags);
        cnode = prom_nodeops->no_child(node);
@@ -36,9 +36,9 @@ int __prom_getchild(int node)
 /* Return the child of node 'node' or zero if no this node has no
  * direct descendent.
  */
-int prom_getchild(int node)
+phandle prom_getchild(phandle node)
 {
-       int cnode;
+       phandle cnode;
 
        if (node == -1)
                return 0;
@@ -52,10 +52,10 @@ int prom_getchild(int node)
 EXPORT_SYMBOL(prom_getchild);
 
 /* Internal version of prom_getsibling that does not alter return values. */
-int __prom_getsibling(int node)
+phandle __prom_getsibling(phandle node)
 {
        unsigned long flags;
-       int cnode;
+       phandle cnode;
 
        spin_lock_irqsave(&prom_lock, flags);
        cnode = prom_nodeops->no_nextnode(node);
@@ -68,9 +68,9 @@ int __prom_getsibling(int node)
 /* Return the next sibling of node 'node' or zero if no more siblings
  * at this level of depth in the tree.
  */
-int prom_getsibling(int node)
+phandle prom_getsibling(phandle node)
 {
-       int sibnode;
+       phandle sibnode;
 
        if (node == -1)
                return 0;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL(prom_getsibling);
 /* Return the length in bytes of property 'prop' at node 'node'.
  * Return -1 on error.
  */
-int prom_getproplen(int node, const char *prop)
+int prom_getproplen(phandle node, const char *prop)
 {
        int ret;
        unsigned long flags;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(prom_getproplen);
  * '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, const char *prop, char *buffer, int bufsize)
+int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
 {
        int plen, ret;
        unsigned long flags;
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(prom_getproperty);
 /* Acquire an integer property and return its value.  Returns -1
  * on failure.
  */
-int prom_getint(int node, char *prop)
+int prom_getint(phandle node, char *prop)
 {
        static int intprop;
 
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(prom_getint);
 /* Acquire an integer property, upon error return the passed default
  * integer.
  */
-int prom_getintdefault(int node, char *property, int deflt)
+int prom_getintdefault(phandle node, char *property, int deflt)
 {
        int retval;
 
@@ -152,7 +152,7 @@ int prom_getintdefault(int node, char *property, int deflt)
 EXPORT_SYMBOL(prom_getintdefault);
 
 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, char *prop)
+int prom_getbool(phandle node, char *prop)
 {
        int retval;
 
@@ -166,7 +166,7 @@ EXPORT_SYMBOL(prom_getbool);
  * string on error.  The char pointer is the user supplied string
  * buffer.
  */
-void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
 {
        int len;
 
@@ -180,7 +180,7 @@ EXPORT_SYMBOL(prom_getstring);
 /* Does the device at node 'node' have name 'name'?
  * YES = 1   NO = 0
  */
-int prom_nodematch(int node, char *name)
+int prom_nodematch(phandle node, char *name)
 {
        int error;
 
@@ -194,10 +194,11 @@ int prom_nodematch(int node, char *name)
 /* Search siblings at 'node_start' for a node with name
  * 'nodename'.  Return node if successful, zero if not.
  */
-int prom_searchsiblings(int node_start, char *nodename)
+phandle prom_searchsiblings(phandle node_start, char *nodename)
 {
 
-       int thisnode, error;
+       phandle thisnode;
+       int error;
 
        for(thisnode = node_start; thisnode;
            thisnode=prom_getsibling(thisnode)) {
@@ -213,7 +214,7 @@ int prom_searchsiblings(int node_start, char *nodename)
 EXPORT_SYMBOL(prom_searchsiblings);
 
 /* Interal version of nextprop that does not alter return values. */
-char * __prom_nextprop(int node, char * oprop)
+char *__prom_nextprop(phandle node, char * oprop)
 {
        unsigned long flags;
        char *prop;
@@ -228,7 +229,7 @@ char * __prom_nextprop(int node, char * oprop)
 
 /* Return the first property name for node 'node'. */
 /* buffer is unused argument, but as v9 uses it, we need to have the same interface */
-char * prom_firstprop(int node, char *bufer)
+char *prom_firstprop(phandle node, char *bufer)
 {
        if (node == 0 || node == -1)
                return "";
@@ -241,7 +242,7 @@ EXPORT_SYMBOL(prom_firstprop);
  * at node 'node' .  Returns empty string if no more
  * property types for this node.
  */
-char * prom_nextprop(int node, char *oprop, char *buffer)
+char *prom_nextprop(phandle node, char *oprop, char *buffer)
 {
        if (node == 0 || node == -1)
                return "";
@@ -250,11 +251,11 @@ char * prom_nextprop(int node, char *oprop, char *buffer)
 }
 EXPORT_SYMBOL(prom_nextprop);
 
-int prom_finddevice(char *name)
+phandle prom_finddevice(char *name)
 {
        char nbuf[128];
        char *s = name, *d;
-       int node = prom_root_node, node2;
+       phandle node = prom_root_node, node2;
        unsigned int which_io, phys_addr;
        struct linux_prom_registers reg[PROMREG_MAX];
 
@@ -298,7 +299,7 @@ int prom_finddevice(char *name)
 }
 EXPORT_SYMBOL(prom_finddevice);
 
-int prom_node_has_property(int node, char *prop)
+int prom_node_has_property(phandle node, char *prop)
 {
        char *current_property = "";
 
@@ -314,7 +315,7 @@ EXPORT_SYMBOL(prom_node_has_property);
 /* 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, const char *pname, char *value, int size)
+int prom_setprop(phandle node, const char *pname, char *value, int size)
 {
        unsigned long flags;
        int ret;
@@ -329,9 +330,9 @@ int prom_setprop(int node, const char *pname, char *value, int size)
 }
 EXPORT_SYMBOL(prom_setprop);
 
-int prom_inst2pkg(int inst)
+phandle prom_inst2pkg(int inst)
 {
-       int node;
+       phandle node;
        unsigned long flags;
        
        spin_lock_irqsave(&prom_lock, flags);
@@ -345,9 +346,10 @@ int prom_inst2pkg(int inst)
 /* Return 'node' assigned to a particular prom 'path'
  * FIXME: Should work for v0 as well
  */
-int prom_pathtoinode(char *path)
+phandle prom_pathtoinode(char *path)
 {
-       int node, inst;
+       phandle node;
+       int inst;
        
        inst = prom_devopen (path);
        if (inst == -1) return 0;
index 9d3f9137a43ae1307ea698d81e13896af7504453..691be68932f84cf7d804b2a7ce6720fceeedc447 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/oplib.h>
 #include <asm/ldc.h>
 
-static int prom_node_to_node(const char *type, int node)
+static phandle prom_node_to_node(const char *type, phandle node)
 {
        unsigned long args[5];
 
@@ -28,20 +28,20 @@ static int prom_node_to_node(const char *type, int node)
 
        p1275_cmd_direct(args);
 
-       return (int) args[4];
+       return (phandle) args[4];
 }
 
 /* Return the child of node 'node' or zero if no this node has no
  * direct descendent.
  */
-inline int __prom_getchild(int node)
+inline phandle __prom_getchild(phandle node)
 {
        return prom_node_to_node("child", node);
 }
 
-inline int prom_getchild(int node)
+inline phandle prom_getchild(phandle node)
 {
-       int cnode;
+       phandle cnode;
 
        if (node == -1)
                return 0;
@@ -52,9 +52,9 @@ inline int prom_getchild(int node)
 }
 EXPORT_SYMBOL(prom_getchild);
 
-inline int prom_getparent(int node)
+inline phandle prom_getparent(phandle node)
 {
-       int cnode;
+       phandle cnode;
 
        if (node == -1)
                return 0;
@@ -67,14 +67,14 @@ inline int prom_getparent(int node)
 /* Return the next sibling of node 'node' or zero if no more siblings
  * at this level of depth in the tree.
  */
-inline int __prom_getsibling(int node)
+inline phandle __prom_getsibling(phandle node)
 {
        return prom_node_to_node(prom_peer_name, node);
 }
 
-inline int prom_getsibling(int node)
+inline phandle prom_getsibling(phandle node)
 {
-       int sibnode;
+       phandle sibnode;
 
        if (node == -1)
                return 0;
@@ -89,7 +89,7 @@ EXPORT_SYMBOL(prom_getsibling);
 /* Return the length in bytes of property 'prop' at node 'node'.
  * Return -1 on error.
  */
-inline int prom_getproplen(int node, const char *prop)
+inline int prom_getproplen(phandle node, const char *prop)
 {
        unsigned long args[6];
 
@@ -113,7 +113,7 @@ EXPORT_SYMBOL(prom_getproplen);
  * 'buffer' which has a size of 'bufsize'.  If the acquisition
  * was successful the length will be returned, else -1 is returned.
  */
-inline int prom_getproperty(int node, const char *prop,
+inline int prom_getproperty(phandle node, const char *prop,
                            char *buffer, int bufsize)
 {
        unsigned long args[8];
@@ -141,7 +141,7 @@ EXPORT_SYMBOL(prom_getproperty);
 /* Acquire an integer property and return its value.  Returns -1
  * on failure.
  */
-inline int prom_getint(int node, const char *prop)
+inline int prom_getint(phandle node, const char *prop)
 {
        int intprop;
 
@@ -156,7 +156,7 @@ EXPORT_SYMBOL(prom_getint);
  * integer.
  */
 
-int prom_getintdefault(int node, const char *property, int deflt)
+int prom_getintdefault(phandle node, const char *property, int deflt)
 {
        int retval;
 
@@ -169,7 +169,7 @@ int prom_getintdefault(int node, const char *property, int deflt)
 EXPORT_SYMBOL(prom_getintdefault);
 
 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, const char *prop)
+int prom_getbool(phandle node, const char *prop)
 {
        int retval;
 
@@ -184,7 +184,8 @@ EXPORT_SYMBOL(prom_getbool);
  * string on error.  The char pointer is the user supplied string
  * buffer.
  */
-void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, const char *prop, char *user_buf,
+               int ubuf_size)
 {
        int len;
 
@@ -198,7 +199,7 @@ EXPORT_SYMBOL(prom_getstring);
 /* Does the device at node 'node' have name 'name'?
  * YES = 1   NO = 0
  */
-int prom_nodematch(int node, const char *name)
+int prom_nodematch(phandle node, const char *name)
 {
        char namebuf[128];
        prom_getproperty(node, "name", namebuf, sizeof(namebuf));
@@ -210,10 +211,10 @@ int prom_nodematch(int node, const char *name)
 /* Search siblings at 'node_start' for a node with name
  * 'nodename'.  Return node if successful, zero if not.
  */
-int prom_searchsiblings(int node_start, const char *nodename)
+phandle prom_searchsiblings(phandle node_start, const char *nodename)
 {
-
-       int thisnode, error;
+       phandle thisnode;
+       int error;
        char promlib_buf[128];
 
        for(thisnode = node_start; thisnode;
@@ -234,7 +235,7 @@ static const char *prom_nextprop_name = "nextprop";
 /* Return the first property type for node 'node'.
  * buffer should be at least 32B in length
  */
-inline char *prom_firstprop(int node, char *buffer)
+inline char *prom_firstprop(phandle node, char *buffer)
 {
        unsigned long args[7];
 
@@ -260,7 +261,7 @@ EXPORT_SYMBOL(prom_firstprop);
  * at node 'node' .  Returns NULL string if no more
  * property types for this node.
  */
-inline char *prom_nextprop(int node, const char *oprop, char *buffer)
+inline char *prom_nextprop(phandle node, const char *oprop, char *buffer)
 {
        unsigned long args[7];
        char buf[32];
@@ -288,8 +289,7 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer)
 }
 EXPORT_SYMBOL(prom_nextprop);
 
-int
-prom_finddevice(const char *name)
+phandle prom_finddevice(const char *name)
 {
        unsigned long args[5];
 
@@ -307,7 +307,7 @@ prom_finddevice(const char *name)
 }
 EXPORT_SYMBOL(prom_finddevice);
 
-int prom_node_has_property(int node, const char *prop)
+int prom_node_has_property(phandle node, const char *prop)
 {
        char buf [32];
         
@@ -325,7 +325,7 @@ EXPORT_SYMBOL(prom_node_has_property);
  * of 'size' bytes.  Return the number of bytes the prom accepted.
  */
 int
-prom_setprop(int node, const char *pname, char *value, int size)
+prom_setprop(phandle node, const char *pname, char *value, int size)
 {
        unsigned long args[8];
 
@@ -355,10 +355,10 @@ prom_setprop(int node, const char *pname, char *value, int size)
 }
 EXPORT_SYMBOL(prom_setprop);
 
-inline int prom_inst2pkg(int inst)
+inline phandle prom_inst2pkg(int inst)
 {
        unsigned long args[5];
-       int node;
+       phandle node;
        
        args[0] = (unsigned long) "instance-to-package";
        args[1] = 1;
@@ -377,10 +377,10 @@ inline int prom_inst2pkg(int inst)
 /* Return 'node' assigned to a particular prom 'path'
  * FIXME: Should work for v0 as well
  */
-int
-prom_pathtoinode(const char *path)
+phandle prom_pathtoinode(const char *path)
 {
-       int node, inst;
+       phandle node;
+       int inst;
 
        inst = prom_devopen (path);
        if (inst == 0)
index 1eb308cb711ab1171779d52d8014041c923fc8a3..89cfee07efa98fc9dc78e42c0f6dc3cb36a651e2 100644 (file)
@@ -96,6 +96,7 @@ config HVC_TILE
 
 config TILE
        def_bool y
+       select HAVE_KVM if !TILEGX
        select GENERIC_FIND_FIRST_BIT
        select GENERIC_FIND_NEXT_BIT
        select USE_GENERIC_SMP_HELPERS
@@ -236,9 +237,9 @@ choice
          If you are not absolutely sure what you are doing, leave this
          option alone!
 
-       config VMSPLIT_375G
+       config VMSPLIT_3_75G
                bool "3.75G/0.25G user/kernel split (no kernel networking)"
-       config VMSPLIT_35G
+       config VMSPLIT_3_5G
                bool "3.5G/0.5G user/kernel split"
        config VMSPLIT_3G
                bool "3G/1G user/kernel split"
@@ -252,8 +253,8 @@ endchoice
 
 config PAGE_OFFSET
        hex
-       default 0xF0000000 if VMSPLIT_375G
-       default 0xE0000000 if VMSPLIT_35G
+       default 0xF0000000 if VMSPLIT_3_75G
+       default 0xE0000000 if VMSPLIT_3_5G
        default 0xB0000000 if VMSPLIT_3G_OPT
        default 0x80000000 if VMSPLIT_2G
        default 0x40000000 if VMSPLIT_1G
@@ -314,6 +315,15 @@ config HARDWALL
        bool "Hardwall support to allow access to user dynamic network"
        default y
 
+config KERNEL_PL
+       int "Processor protection level for kernel"
+       range 1 2
+       default "1"
+       ---help---
+         This setting determines the processor protection level the
+         kernel will be built to run at.  Generally you should use
+         the default value here.
+
 endmenu  # Tilera-specific configuration
 
 menu "Bus options"
@@ -354,3 +364,5 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+source "arch/tile/kvm/Kconfig"
index fd8f6bb5facecafb70c223f24638cb43138458d3..17acce70569b01aaf7de554a66c0f7e6e8a47157 100644 (file)
@@ -26,8 +26,9 @@ $(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH))
   endif
 endif
 
-
+ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"")
 KBUILD_CFLAGS   += $(CONFIG_DEBUG_EXTRA_FLAGS)
+endif
 
 LIBGCC_PATH     := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
@@ -49,6 +50,20 @@ head-y               := arch/tile/kernel/head_$(BITS).o
 libs-y         += arch/tile/lib/
 libs-y         += $(LIBGCC_PATH)
 
-
 # See arch/tile/Kbuild for content of core part of the kernel
 core-y         += arch/tile/
+
+core-$(CONFIG_KVM) += arch/tile/kvm/
+
+ifdef TILERA_ROOT
+INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot
+endif
+
+install:
+       install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
+       install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
+       install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
+
+define archhelp
+       echo '  install         - install kernel into $(INSTALL_PATH)'
+endef
diff --git a/arch/tile/include/arch/sim.h b/arch/tile/include/arch/sim.h
new file mode 100644 (file)
index 0000000..74b7c16
--- /dev/null
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2010 Tilera Corporation. 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, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file
+ *
+ * Provides an API for controlling the simulator at runtime.
+ */
+
+/**
+ * @addtogroup arch_sim
+ * @{
+ *
+ * An API for controlling the simulator at runtime.
+ *
+ * The simulator's behavior can be modified while it is running.
+ * For example, human-readable trace output can be enabled and disabled
+ * around code of interest.
+ *
+ * There are two ways to modify simulator behavior:
+ * programmatically, by calling various sim_* functions, and
+ * interactively, by entering commands like "sim set functional true"
+ * at the tile-monitor prompt.  Typing "sim help" at that prompt provides
+ * a list of interactive commands.
+ *
+ * All interactive commands can also be executed programmatically by
+ * passing a string to the sim_command function.
+ */
+
+#ifndef __ARCH_SIM_H__
+#define __ARCH_SIM_H__
+
+#include <arch/sim_def.h>
+#include <arch/abi.h>
+
+#ifndef __ASSEMBLER__
+
+#include <arch/spr_def.h>
+
+
+/**
+ * Return true if the current program is running under a simulator,
+ * rather than on real hardware.  If running on hardware, other "sim_xxx()"
+ * calls have no useful effect.
+ */
+static inline int
+sim_is_simulator(void)
+{
+  return __insn_mfspr(SPR_SIM_CONTROL) != 0;
+}
+
+
+/**
+ * Checkpoint the simulator state to a checkpoint file.
+ *
+ * The checkpoint file name is either the default or the name specified
+ * on the command line with "--checkpoint-file".
+ */
+static __inline void
+sim_checkpoint(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT);
+}
+
+
+/**
+ * Report whether or not various kinds of simulator tracing are enabled.
+ *
+ * @return The bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline unsigned int
+sim_get_tracing(void)
+{
+  return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK;
+}
+
+
+/**
+ * Turn on or off different kinds of simulator tracing.
+ *
+ * @param mask Either one of these special values:
+ *
+ * SIM_TRACE_NONE (turns off tracing),
+ * SIM_TRACE_ALL (turns on all possible tracing).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline void
+sim_set_tracing(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask));
+}
+
+
+/**
+ * Request dumping of different kinds of simulator state.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_DUMP_ALL (dump all known state)
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_DUMP_REGS (the register file),
+ * SIM_DUMP_SPRS (the SPRs),
+ * SIM_DUMP_ITLB (the iTLB),
+ * SIM_DUMP_DTLB (the dTLB),
+ * SIM_DUMP_L1I (the L1 I-cache),
+ * SIM_DUMP_L1D (the L1 D-cache),
+ * SIM_DUMP_L2 (the L2 cache),
+ * SIM_DUMP_SNREGS (the switch register file),
+ * SIM_DUMP_SNITLB (the switch iTLB),
+ * SIM_DUMP_SNL1I (the switch L1 I-cache),
+ * SIM_DUMP_BACKTRACE (the current backtrace)
+ */
+static __inline void
+sim_dump(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask));
+}
+
+
+/**
+ * Print a string to the simulator stdout.
+ *
+ * @param str The string to be written; a newline is automatically added.
+ */
+static __inline void
+sim_print_string(const char* str)
+{
+  int i;
+  for (i = 0; str[i] != 0; i++)
+  {
+    __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+                 (str[i] << _SIM_CONTROL_OPERATOR_BITS));
+  }
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+               (SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS));
+}
+
+
+/**
+ * Execute a simulator command string.
+ *
+ * Type 'sim help' at the tile-monitor prompt to learn what commands
+ * are available.  Note the use of the tile-monitor "sim" command to
+ * pass commands to the simulator.
+ *
+ * The argument to sim_command() does not include the leading "sim"
+ * prefix used at the tile-monitor prompt; for example, you might call
+ * sim_command("trace disasm").
+ */
+static __inline void
+sim_command(const char* str)
+{
+  int c;
+  do
+  {
+    c = *str++;
+    __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND |
+                 (c << _SIM_CONTROL_OPERATOR_BITS));
+  }
+  while (c);
+}
+
+
+
+#ifndef __DOXYGEN__
+
+/**
+ * The underlying implementation of "_sim_syscall()".
+ *
+ * We use extra "and" instructions to ensure that all the values
+ * we are passing to the simulator are actually valid in the registers
+ * (i.e. returned from memory) prior to the SIM_CONTROL spr.
+ */
+static __inline int _sim_syscall0(int val)
+{
+  long result;
+  __asm__ __volatile__ ("mtspr SIM_CONTROL, r0"
+                        : "=R00" (result) : "R00" (val));
+  return result;
+}
+
+static __inline int _sim_syscall1(int val, long arg1)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result) : "R00" (val), "R01" (arg1));
+  return result;
+}
+
+static __inline int _sim_syscall2(int val, long arg1, long arg2)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2));
+  return result;
+}
+
+/* Note that _sim_syscall3() and higher are technically at risk of
+   receiving an interrupt right before the mtspr bundle, in which case
+   the register values for arguments 3 and up may still be in flight
+   to the core from a stack frame reload. */
+
+static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r3 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3));
+  return result;
+}
+
+static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
+                                  long arg4)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r4 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3), "R04" (arg4));
+  return result;
+}
+
+static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
+                                  long arg4, long arg5)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3), "R04" (arg4), "R05" (arg5));
+  return result;
+}
+
+
+/**
+ * Make a special syscall to the simulator itself, if running under
+ * simulation. This is used as the implementation of other functions
+ * and should not be used outside this file.
+ *
+ * @param syscall_num The simulator syscall number.
+ * @param nr The number of additional arguments provided.
+ *
+ * @return Varies by syscall.
+ */
+#define _sim_syscall(syscall_num, nr, args...) \
+  _sim_syscall##nr( \
+    ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, args)
+
+
+/* Values for the "access_mask" parameters below. */
+#define SIM_WATCHPOINT_READ    1
+#define SIM_WATCHPOINT_WRITE   2
+#define SIM_WATCHPOINT_EXECUTE 4
+
+
+static __inline int
+sim_add_watchpoint(unsigned int process_id,
+                   unsigned long address,
+                   unsigned long size,
+                   unsigned int access_mask,
+                   unsigned long user_data)
+{
+  return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id,
+                     address, size, access_mask, user_data);
+}
+
+
+static __inline int
+sim_remove_watchpoint(unsigned int process_id,
+                      unsigned long address,
+                      unsigned long size,
+                      unsigned int access_mask,
+                      unsigned long user_data)
+{
+  return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id,
+                     address, size, access_mask, user_data);
+}
+
+
+/**
+ * Return value from sim_query_watchpoint.
+ */
+struct SimQueryWatchpointStatus
+{
+  /**
+   * 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for
+   * error (meaning a bad process_id).
+   */
+  int syscall_status;
+
+  /**
+   * The address of the watchpoint that fired (this is the address
+   * passed to sim_add_watchpoint, not an address within that range
+   * that actually triggered the watchpoint).
+   */
+  unsigned long address;
+
+  /** The arbitrary user_data installed by sim_add_watchpoint. */
+  unsigned long user_data;
+};
+
+
+static __inline struct SimQueryWatchpointStatus
+sim_query_watchpoint(unsigned int process_id)
+{
+  struct SimQueryWatchpointStatus status;
+  long val = SIM_CONTROL_SYSCALL |
+    (SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS);
+  __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (status.syscall_status),
+                          "=R01" (status.address),
+                          "=R02" (status.user_data)
+                        : "R00" (val), "R01" (process_id));
+  return status;
+}
+
+
+/* On the simulator, confirm lines have been evicted everywhere. */
+static __inline void
+sim_validate_lines_evicted(unsigned long long pa, unsigned long length)
+{
+#ifdef __LP64__
+  _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length);
+#else
+  _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4,
+               0 /* dummy */, (long)(pa), (long)(pa >> 32), length);
+#endif
+}
+
+
+#endif /* !__DOXYGEN__ */
+
+
+
+
+/**
+ * Modify the shaping parameters of a shim.
+ *
+ * @param shim The shim to modify. One of:
+ *   SIM_CONTROL_SHAPING_GBE_0
+ *   SIM_CONTROL_SHAPING_GBE_1
+ *   SIM_CONTROL_SHAPING_GBE_2
+ *   SIM_CONTROL_SHAPING_GBE_3
+ *   SIM_CONTROL_SHAPING_XGBE_0
+ *   SIM_CONTROL_SHAPING_XGBE_1
+ *
+ * @param type The type of shaping. This should be the same type of
+ * shaping that is already in place on the shim. One of:
+ *   SIM_CONTROL_SHAPING_MULTIPLIER
+ *   SIM_CONTROL_SHAPING_PPS
+ *   SIM_CONTROL_SHAPING_BPS
+ *
+ * @param units The magnitude of the rate. One of:
+ *   SIM_CONTROL_SHAPING_UNITS_SINGLE
+ *   SIM_CONTROL_SHAPING_UNITS_KILO
+ *   SIM_CONTROL_SHAPING_UNITS_MEGA
+ *   SIM_CONTROL_SHAPING_UNITS_GIGA
+ *
+ * @param rate The rate to which to change it. This must fit in
+ * SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and
+ * the shaping is not changed.
+ *
+ * @return 0 if no problems were detected in the arguments to sim_set_shaping
+ * or 1 if problems were detected (for example, rate does not fit in 17 bits).
+ */
+static __inline int
+sim_set_shaping(unsigned shim,
+                unsigned type,
+                unsigned units,
+                unsigned rate)
+{
+  if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0)
+    return 1;
+
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate));
+  return 0;
+}
+
+#ifdef __tilegx__
+
+/** Enable a set of mPIPE links.  Pass a -1 link_mask to enable all links. */
+static __inline void
+sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL,
+               (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+                (mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+/** Disable a set of mPIPE links.  Pass a -1 link_mask to disable all links. */
+static __inline void
+sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL,
+               (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+                (mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+#endif /* __tilegx__ */
+
+
+/*
+ * An API for changing "functional" mode.
+ */
+
+#ifndef __DOXYGEN__
+
+#define sim_enable_functional() \
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL)
+
+#define sim_disable_functional() \
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL)
+
+#endif /* __DOXYGEN__ */
+
+
+/*
+ * Profiler support.
+ */
+
+/**
+ * Turn profiling on for the current task.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_enable(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE);
+}
+
+
+/** Turn profiling off for the current task. */
+static __inline void
+sim_profiler_disable(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE);
+}
+
+
+/**
+ * Turn profiling on or off for the current task.
+ *
+ * @param enabled If true, turns on profiling. If false, turns it off.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_set_enabled(int enabled)
+{
+  int val =
+    enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE;
+  __insn_mtspr(SPR_SIM_CONTROL, val);
+}
+
+
+/**
+ * Return true if and only if profiling is currently enabled
+ * for the current task.
+ *
+ * This returns false even if sim_profiler_enable() was called
+ * if the current execution environment does not support profiling.
+ */
+static __inline int
+sim_profiler_is_enabled(void)
+{
+  return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0);
+}
+
+
+/**
+ * Reset profiling counters to zero for the current task.
+ *
+ * Resetting can be done while profiling is enabled.  It does not affect
+ * the chip-wide profiling counters.
+ */
+static __inline void
+sim_profiler_clear(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR);
+}
+
+
+/**
+ * Enable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (enables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (enable all memory controllers)
+ * SIM_CHIP_XAUI (enable all XAUI controllers)
+ * SIM_CHIP_MPIPE (enable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_enable(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Disable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (disables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (disable all memory controllers)
+ * SIM_CHIP_XAUI (disable all XAUI controllers)
+ * SIM_CHIP_MPIPE (disable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_disable(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Reset specified chip-level profiling counters to zero.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (clears all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (clear all memory controllers)
+ * SIM_CHIP_XAUI (clear all XAUI controllers)
+ * SIM_CHIP_MPIPE (clear all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_clear(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask));
+}
+
+
+/*
+ * Event support.
+ */
+
+#ifndef __DOXYGEN__
+
+static __inline void
+sim_event_begin(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+  __insn_mtspr(SPR_EVENT_BEGIN, x);
+#endif
+}
+
+static __inline void
+sim_event_end(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+  __insn_mtspr(SPR_EVENT_END, x);
+#endif
+}
+
+#endif /* !__DOXYGEN__ */
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* !__ARCH_SIM_H__ */
+
+/** @} */
index 6418fbde063e8a996c95c7004c8fd06a6147a54a..7a17082c3773edb6ae7fc4ef537935a2ceefd4d2 100644 (file)
-// Copyright 2010 Tilera Corporation. 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, version 2.
-//
-//   This program is distributed in the hope that it will be useful, but
-//   WITHOUT ANY WARRANTY; without even the implied warranty of
-//   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
-//   NON INFRINGEMENT.  See the GNU General Public License for
-//   more details.
-
-//! @file
-//!
-//! Some low-level simulator definitions.
-//!
+/*
+ * Copyright 2010 Tilera Corporation. 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, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file
+ *
+ * Some low-level simulator definitions.
+ */
 
 #ifndef __ARCH_SIM_DEF_H__
 #define __ARCH_SIM_DEF_H__
 
 
-//! Internal: the low bits of the SIM_CONTROL_* SPR values specify
-//! the operation to perform, and the remaining bits are
-//! an operation-specific parameter (often unused).
-//!
+/**
+ * Internal: the low bits of the SIM_CONTROL_* SPR values specify
+ * the operation to perform, and the remaining bits are
+ * an operation-specific parameter (often unused).
+ */
 #define _SIM_CONTROL_OPERATOR_BITS 8
 
 
-//== Values which can be written to SPR_SIM_CONTROL.
+/*
+ * Values which can be written to SPR_SIM_CONTROL.
+ */
 
-//! If written to SPR_SIM_CONTROL, stops profiling.
-//!
+/** If written to SPR_SIM_CONTROL, stops profiling. */
 #define SIM_CONTROL_PROFILER_DISABLE 0
 
-//! If written to SPR_SIM_CONTROL, starts profiling.
-//!
+/** If written to SPR_SIM_CONTROL, starts profiling. */
 #define SIM_CONTROL_PROFILER_ENABLE 1
 
-//! If written to SPR_SIM_CONTROL, clears profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears profiling counters. */
 #define SIM_CONTROL_PROFILER_CLEAR 2
 
-//! If written to SPR_SIM_CONTROL, checkpoints the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, checkpoints the simulator. */
 #define SIM_CONTROL_CHECKPOINT 3
 
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! sets the tracing mask to the given mask. See "sim_set_tracing()".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * sets the tracing mask to the given mask. See "sim_set_tracing()".
+ */
 #define SIM_CONTROL_SET_TRACING 4
 
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! dumps the requested items of machine state to the log.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * dumps the requested items of machine state to the log.
+ */
 #define SIM_CONTROL_DUMP 5
 
-//! If written to SPR_SIM_CONTROL, clears chip-level profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears chip-level profiling counters. */
 #define SIM_CONTROL_PROFILER_CHIP_CLEAR 6
 
-//! If written to SPR_SIM_CONTROL, disables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level profiling. */
 #define SIM_CONTROL_PROFILER_CHIP_DISABLE 7
 
-//! If written to SPR_SIM_CONTROL, enables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level profiling. */
 #define SIM_CONTROL_PROFILER_CHIP_ENABLE 8
 
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level functional mode */
 #define SIM_CONTROL_ENABLE_FUNCTIONAL 9
 
-//! If written to SPR_SIM_CONTROL, disables chip-level functional mode.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level functional mode. */
 #define SIM_CONTROL_DISABLE_FUNCTIONAL 10
 
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode.
-//! All tiles must perform this write for functional mode to be enabled.
-//! Ignored in naked boot mode unless --functional is specified.
-//! WARNING: Only the hypervisor startup code should use this!
-//!
+/**
+ * If written to SPR_SIM_CONTROL, enables chip-level functional mode.
+ * All tiles must perform this write for functional mode to be enabled.
+ * Ignored in naked boot mode unless --functional is specified.
+ * WARNING: Only the hypervisor startup code should use this!
+ */
 #define SIM_CONTROL_ENABLE_FUNCTIONAL_BARRIER 11
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! writes a string directly to the simulator output.  Written to once for
-//! each character in the string, plus a final NUL.  Instead of NUL,
-//! you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
-//!
-// ISSUE: Document the meaning of "newline", and the handling of NUL.
-//
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * writes a string directly to the simulator output.  Written to once for
+ * each character in the string, plus a final NUL.  Instead of NUL,
+ * you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
+ */
+/* ISSUE: Document the meaning of "newline", and the handling of NUL. */
 #define SIM_CONTROL_PUTC 12
 
-//! If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
-//! this core.  This is intended to be used before a loop that will
-//! invalidate the cache by loading new data and evicting all current data.
-//! Generally speaking, this API should only be used by system code.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
+ * this core.  This is intended to be used before a loop that will
+ * invalidate the cache by loading new data and evicting all current data.
+ * Generally speaking, this API should only be used by system code.
+ */
 #define SIM_CONTROL_GRINDER_CLEAR 13
 
-//! If written to SPR_SIM_CONTROL, shuts down the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, shuts down the simulator. */
 #define SIM_CONTROL_SHUTDOWN 14
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that a fork syscall just created the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that a fork syscall just created the given process.
+ */
 #define SIM_CONTROL_OS_FORK 15
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that an exit syscall was just executed by the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that an exit syscall was just executed by the given process.
+ */
 #define SIM_CONTROL_OS_EXIT 16
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that the OS just switched to the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that the OS just switched to the given process.
+ */
 #define SIM_CONTROL_OS_SWITCH 17
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an exec syscall was just executed. Written to once for
-//! each character in the executable name, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an exec syscall was just executed. Written to once for
+ * each character in the executable name, plus a final NUL.
+ */
 #define SIM_CONTROL_OS_EXEC 18
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an interpreter (PT_INTERP) was loaded.  Written to once
-//! for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
-//! hex load address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an interpreter (PT_INTERP) was loaded.  Written to once
+ * for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
+ * hex load address starting with "0x", and "PATH" is the executable name.
+ */
 #define SIM_CONTROL_OS_INTERP 19
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was loaded.  Written to once for each character
-//! in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was loaded.  Written to once for each character
+ * in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x", and "PATH" is the executable name.
+ */
 #define SIM_CONTROL_DLOPEN 20
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was unloaded.  Written to once for each character
-//! in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was unloaded.  Written to once for each character
+ * in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x".
+ */
 #define SIM_CONTROL_DLCLOSE 21
 
-//! If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
-//! indicates whether to allow data reads to remotely-cached
-//! dirty cache lines to be cached locally without grinder warnings or
-//! assertions (used by Linux kernel fast memcpy).
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
+ * indicates whether to allow data reads to remotely-cached
+ * dirty cache lines to be cached locally without grinder warnings or
+ * assertions (used by Linux kernel fast memcpy).
+ */
 #define SIM_CONTROL_ALLOW_MULTIPLE_CACHING 22
 
-//! If written to SPR_SIM_CONTROL, enables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, enables memory tracing. */
 #define SIM_CONTROL_ENABLE_MEM_LOGGING 23
 
-//! If written to SPR_SIM_CONTROL, disables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, disables memory tracing. */
 #define SIM_CONTROL_DISABLE_MEM_LOGGING 24
 
-//! If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
-//! the gbe or xgbe shims. Must specify the shim id, the type, the units, and
-//! the rate, as defined in SIM_SHAPING_SPR_ARG.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
+ * the gbe or xgbe shims. Must specify the shim id, the type, the units, and
+ * the rate, as defined in SIM_SHAPING_SPR_ARG.
+ */
 #define SIM_CONTROL_SHAPING 25
 
-//! If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
-//! requests that a simulator command be executed.  Written to once for each
-//! character in the command, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
+ * requests that a simulator command be executed.  Written to once for each
+ * character in the command, plus a final NUL.
+ */
 #define SIM_CONTROL_COMMAND 26
 
-//! If written to SPR_SIM_CONTROL, indicates that the simulated system
-//! is panicking, to allow debugging via --debug-on-panic.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, indicates that the simulated system
+ * is panicking, to allow debugging via --debug-on-panic.
+ */
 #define SIM_CONTROL_PANIC 27
 
-//! If written to SPR_SIM_CONTROL, triggers a simulator syscall.
-//! See "sim_syscall()" for more info.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, triggers a simulator syscall.
+ * See "sim_syscall()" for more info.
+ */
 #define SIM_CONTROL_SYSCALL 32
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
-//! use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
+ * use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
+ */
 #define SIM_CONTROL_OS_FORK_PARENT 33
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), clears the pending magic data section.  The cleared
-//! pending magic data section and any subsequently appended magic bytes
-//! will only take effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), clears the pending magic data section.  The cleared
+ * pending magic data section and any subsequently appended magic bytes
+ * will only take effect when the classifier blast programmer is run.
+ */
 #define SIM_CONTROL_CLEAR_MPIPE_MAGIC_BYTES 34
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8) and a byte of data (shifted by 16), appends that byte
-//! to the shim's pending magic data section.  The pending magic data
-//! section takes effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8) and a byte of data (shifted by 16), appends that byte
+ * to the shim's pending magic data section.  The pending magic data
+ * section takes effect when the classifier blast programmer is run.
+ */
 #define SIM_CONTROL_APPEND_MPIPE_MAGIC_BYTE 35
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
-//! mask of links (shifted by 32), enable or disable the corresponding
-//! mPIPE links.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
+ * mask of links (shifted by 32), enable or disable the corresponding
+ * mPIPE links.
+ */
 #define SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE 36
 
-//== Syscall numbers for use with "sim_syscall()".
 
-//! Syscall number for sim_add_watchpoint().
-//!
+/*
+ * Syscall numbers for use with "sim_syscall()".
+ */
+
+/** Syscall number for sim_add_watchpoint(). */
 #define SIM_SYSCALL_ADD_WATCHPOINT 2
 
-//! Syscall number for sim_remove_watchpoint().
-//!
+/** Syscall number for sim_remove_watchpoint(). */
 #define SIM_SYSCALL_REMOVE_WATCHPOINT 3
 
-//! Syscall number for sim_query_watchpoint().
-//!
+/** Syscall number for sim_query_watchpoint(). */
 #define SIM_SYSCALL_QUERY_WATCHPOINT 4
 
-//! Syscall number that asserts that the cache lines whose 64-bit PA
-//! is passed as the second argument to sim_syscall(), and over a
-//! range passed as the third argument, are no longer in cache.
-//! The simulator raises an error if this is not the case.
-//!
+/**
+ * Syscall number that asserts that the cache lines whose 64-bit PA
+ * is passed as the second argument to sim_syscall(), and over a
+ * range passed as the third argument, are no longer in cache.
+ * The simulator raises an error if this is not the case.
+ */
 #define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Enable --trace-cycle when passed to simulator_set_tracing().
-//!
+/** Enable --trace-cycle when passed to simulator_set_tracing(). */
 #define SIM_TRACE_CYCLES          0x01
 
-//! Enable --trace-router when passed to simulator_set_tracing().
-//!
+/** Enable --trace-router when passed to simulator_set_tracing(). */
 #define SIM_TRACE_ROUTER          0x02
 
-//! Enable --trace-register-writes when passed to simulator_set_tracing().
-//!
+/** Enable --trace-register-writes when passed to simulator_set_tracing(). */
 #define SIM_TRACE_REGISTER_WRITES 0x04
 
-//! Enable --trace-disasm when passed to simulator_set_tracing().
-//!
+/** Enable --trace-disasm when passed to simulator_set_tracing(). */
 #define SIM_TRACE_DISASM          0x08
 
-//! Enable --trace-stall-info when passed to simulator_set_tracing().
-//!
+/** Enable --trace-stall-info when passed to simulator_set_tracing(). */
 #define SIM_TRACE_STALL_INFO      0x10
 
-//! Enable --trace-memory-controller when passed to simulator_set_tracing().
-//!
+/** Enable --trace-memory-controller when passed to simulator_set_tracing(). */
 #define SIM_TRACE_MEMORY_CONTROLLER 0x20
 
-//! Enable --trace-l2 when passed to simulator_set_tracing().
-//!
+/** Enable --trace-l2 when passed to simulator_set_tracing(). */
 #define SIM_TRACE_L2_CACHE 0x40
 
-//! Enable --trace-lines when passed to simulator_set_tracing().
-//!
+/** Enable --trace-lines when passed to simulator_set_tracing(). */
 #define SIM_TRACE_LINES 0x80
 
-//! Turn off all tracing when passed to simulator_set_tracing().
-//!
+/** Turn off all tracing when passed to simulator_set_tracing(). */
 #define SIM_TRACE_NONE 0
 
-//! Turn on all tracing when passed to simulator_set_tracing().
-//!
+/** Turn on all tracing when passed to simulator_set_tracing(). */
 #define SIM_TRACE_ALL (-1)
 
-//! @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to set tracing flags.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to set tracing flags. */
 #define SIM_TRACE_SPR_ARG(mask) \
   (SIM_CONTROL_SET_TRACING | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Dump the general-purpose registers.
-//!
+/** Dump the general-purpose registers. */
 #define SIM_DUMP_REGS          0x001
 
-//! Dump the SPRs.
-//!
+/** Dump the SPRs. */
 #define SIM_DUMP_SPRS          0x002
 
-//! Dump the ITLB.
-//!
+/** Dump the ITLB. */
 #define SIM_DUMP_ITLB          0x004
 
-//! Dump the DTLB.
-//!
+/** Dump the DTLB. */
 #define SIM_DUMP_DTLB          0x008
 
-//! Dump the L1 I-cache.
-//!
+/** Dump the L1 I-cache. */
 #define SIM_DUMP_L1I           0x010
 
-//! Dump the L1 D-cache.
-//!
+/** Dump the L1 D-cache. */
 #define SIM_DUMP_L1D           0x020
 
-//! Dump the L2 cache.
-//!
+/** Dump the L2 cache. */
 #define SIM_DUMP_L2            0x040
 
-//! Dump the switch registers.
-//!
+/** Dump the switch registers. */
 #define SIM_DUMP_SNREGS        0x080
 
-//! Dump the switch ITLB.
-//!
+/** Dump the switch ITLB. */
 #define SIM_DUMP_SNITLB        0x100
 
-//! Dump the switch L1 I-cache.
-//!
+/** Dump the switch L1 I-cache. */
 #define SIM_DUMP_SNL1I         0x200
 
-//! Dump the current backtrace.
-//!
+/** Dump the current backtrace. */
 #define SIM_DUMP_BACKTRACE     0x400
 
-//! Only dump valid lines in caches.
-//!
+/** Only dump valid lines in caches. */
 #define SIM_DUMP_VALID_LINES   0x800
 
-//! Dump everything that is dumpable.
-//!
+/** Dump everything that is dumpable. */
 #define SIM_DUMP_ALL (-1 & ~SIM_DUMP_VALID_LINES)
 
-// @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to dump machine state.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to dump machine state. */
 #define SIM_DUMP_SPR_ARG(mask) \
   (SIM_CONTROL_DUMP | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers. */
 #define SIM_CHIP_MEMCTL        0x001
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface. */
 #define SIM_CHIP_XAUI          0x002
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface. */
 #define SIM_CHIP_PCIE          0x004
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface. */
 #define SIM_CHIP_MPIPE         0x008
 
-//! Reference all chip devices.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the TRIO interface. */
+#define SIM_CHIP_TRIO          0x010
+
+/** Reference all chip devices. */
 #define SIM_CHIP_ALL (-1)
 
-//! @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to clear chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to clear chip statistics. */
 #define SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_CLEAR | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.*/
 #define SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_DISABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to enable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to enable chip statistics. */
 #define SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_ENABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
 
-// Shim bitrate controls.
+/* Shim bitrate controls. */
 
-//! The number of bits used to store the shim id.
-//!
+/** The number of bits used to store the shim id. */
 #define SIM_CONTROL_SHAPING_SHIM_ID_BITS 3
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Change the gbe 0 bitrate.
-//!
+/** Change the gbe 0 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_0 0x0
 
-//! Change the gbe 1 bitrate.
-//!
+/** Change the gbe 1 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_1 0x1
 
-//! Change the gbe 2 bitrate.
-//!
+/** Change the gbe 2 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_2 0x2
 
-//! Change the gbe 3 bitrate.
-//!
+/** Change the gbe 3 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_3 0x3
 
-//! Change the xgbe 0 bitrate.
-//!
+/** Change the xgbe 0 bitrate. */
 #define SIM_CONTROL_SHAPING_XGBE_0 0x4
 
-//! Change the xgbe 1 bitrate.
-//!
+/** Change the xgbe 1 bitrate. */
 #define SIM_CONTROL_SHAPING_XGBE_1 0x5
 
-//! The type of shaping to do.
-//!
+/** The type of shaping to do. */
 #define SIM_CONTROL_SHAPING_TYPE_BITS 2
 
-//! Control the multiplier.
-//!
+/** Control the multiplier. */
 #define SIM_CONTROL_SHAPING_MULTIPLIER 0
 
-//! Control the PPS.
-//!
+/** Control the PPS. */
 #define SIM_CONTROL_SHAPING_PPS 1
 
-//! Control the BPS.
-//!
+/** Control the BPS. */
 #define SIM_CONTROL_SHAPING_BPS 2
 
-//! The number of bits for the units for the shaping parameter.
-//!
+/** The number of bits for the units for the shaping parameter. */
 #define SIM_CONTROL_SHAPING_UNITS_BITS 2
 
-//! Provide a number in single units.
-//!
+/** Provide a number in single units. */
 #define SIM_CONTROL_SHAPING_UNITS_SINGLE 0
 
-//! Provide a number in kilo units.
-//!
+/** Provide a number in kilo units. */
 #define SIM_CONTROL_SHAPING_UNITS_KILO 1
 
-//! Provide a number in mega units.
-//!
+/** Provide a number in mega units. */
 #define SIM_CONTROL_SHAPING_UNITS_MEGA 2
 
-//! Provide a number in giga units.
-//!
+/** Provide a number in giga units. */
 #define SIM_CONTROL_SHAPING_UNITS_GIGA 3
 
-// @}
+/** @} */
 
-//! How many bits are available for the rate.
-//!
+/** How many bits are available for the rate. */
 #define SIM_CONTROL_SHAPING_RATE_BITS \
   (32 - (_SIM_CONTROL_OPERATOR_BITS + \
          SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
          SIM_CONTROL_SHAPING_TYPE_BITS + \
          SIM_CONTROL_SHAPING_UNITS_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to change a bitrate.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to change a bitrate. */
 #define SIM_SHAPING_SPR_ARG(shim, type, units, rate) \
   (SIM_CONTROL_SHAPING | \
    ((shim) | \
                SIM_CONTROL_SHAPING_UNITS_BITS))) << _SIM_CONTROL_OPERATOR_BITS)
 
 
-//== Values returned when reading SPR_SIM_CONTROL.
-// ISSUE: These names should share a longer common prefix.
+/*
+ * Values returned when reading SPR_SIM_CONTROL.
+ * ISSUE: These names should share a longer common prefix.
+ */
 
-//! When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
-//! (SIM_TRACE_xxx values).
-//!
+/**
+ * When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
+ * (SIM_TRACE_xxx values).
+ */
 #define SIM_TRACE_FLAG_MASK 0xFFFF
 
-//! When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled.
-//!
+/** When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled. */
 #define SIM_PROFILER_ENABLED_MASK 0x10000
 
 
-//== Special arguments for "SIM_CONTROL_PUTC".
+/*
+ * Special arguments for "SIM_CONTROL_PUTC".
+ */
 
-//! Flag value for forcing a PUTC string-flush, including
-//! coordinate/cycle prefix and newline.
-//!
+/**
+ * Flag value for forcing a PUTC string-flush, including
+ * coordinate/cycle prefix and newline.
+ */
 #define SIM_PUTC_FLUSH_STRING 0x100
 
-//! Flag value for forcing a PUTC binary-data-flush, which skips the
-//! prefix and does not append a newline.
-//!
+/**
+ * Flag value for forcing a PUTC binary-data-flush, which skips the
+ * prefix and does not append a newline.
+ */
 #define SIM_PUTC_FLUSH_BINARY 0x101
 
 
-#endif //__ARCH_SIM_DEF_H__
+#endif /* __ARCH_SIM_DEF_H__ */
index c8fdbd9a45e67b53c4c9da654613e844d9902807..442fcba0d12266db8ed8febd68c62a101a7b3ab6 100644 (file)
  *   more details.
  */
 
+/*
+ * In addition to including the proper base SPR definition file, depending
+ * on machine architecture, this file defines several macros which allow
+ * kernel code to use protection-level dependent SPRs without worrying
+ * about which PL it's running at.  In these macros, the PL that the SPR
+ * or interrupt number applies to is replaced by K.
+ */
+
+#if CONFIG_KERNEL_PL != 1 && CONFIG_KERNEL_PL != 2
+#error CONFIG_KERNEL_PL must be 1 or 2
+#endif
+
+/* Concatenate 4 strings. */
+#define __concat4(a, b, c, d) a ## b ## c ## d
+#define _concat4(a, b, c, d)  __concat4(a, b, c, d)
+
 #ifdef __tilegx__
 #include <arch/spr_def_64.h>
+
+/* TILE-Gx dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K \
+       _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_SET_K \
+       _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_RESET_K \
+       _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_VECTOR_BASE_K \
+       _concat4(SPR_INTERRUPT_VECTOR_BASE_, CONFIG_KERNEL_PL,,)
+
+#define SPR_IPI_MASK_K \
+       _concat4(SPR_IPI_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_RESET_K \
+       _concat4(SPR_IPI_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+       _concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_K \
+       _concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_RESET_K \
+       _concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+       _concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define INT_IPI_K \
+       _concat4(INT_IPI_, CONFIG_KERNEL_PL,,)
+
+#define SPR_SINGLE_STEP_CONTROL_K \
+       _concat4(SPR_SINGLE_STEP_CONTROL_, CONFIG_KERNEL_PL,,)
+#define SPR_SINGLE_STEP_EN_K_K \
+       _concat4(SPR_SINGLE_STEP_EN_, CONFIG_KERNEL_PL, _, CONFIG_KERNEL_PL)
+#define INT_SINGLE_STEP_K \
+       _concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
+
 #else
 #include <arch/spr_def_32.h>
+
+/* TILEPro dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K_0 \
+       _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_K_1 \
+       _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_SET_K_0 \
+       _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_SET_K_1 \
+       _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_RESET_K_0 \
+       _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_RESET_K_1 \
+       _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _1,)
+
 #endif
+
+/* Generic protection-level dependent SPRs. */
+
+#define SPR_SYSTEM_SAVE_K_0 \
+       _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _0,)
+#define SPR_SYSTEM_SAVE_K_1 \
+       _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _1,)
+#define SPR_SYSTEM_SAVE_K_2 \
+       _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _2,)
+#define SPR_SYSTEM_SAVE_K_3 \
+       _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _3,)
+#define SPR_EX_CONTEXT_K_0 \
+       _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _0,)
+#define SPR_EX_CONTEXT_K_1 \
+       _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTCTRL_K_STATUS \
+       _concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
+#define INT_INTCTRL_K \
+       _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
index b4fc06864df652ba9a3c1c9461b008016bff04cd..bbc1f4c924eebe0c9d0183bf5119468297e430a1 100644 (file)
 #define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
 #define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
 #define SPR_EX_CONTEXT_1_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_2_0 0x4605
+#define SPR_EX_CONTEXT_2_1 0x4606
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
 #define SPR_FAIL 0x4e09
 #define SPR_INTCTRL_0_STATUS 0x4a07
 #define SPR_INTCTRL_1_STATUS 0x4807
+#define SPR_INTCTRL_2_STATUS 0x4607
 #define SPR_INTERRUPT_CRITICAL_SECTION 0x4e0a
 #define SPR_INTERRUPT_MASK_0_0 0x4a08
 #define SPR_INTERRUPT_MASK_0_1 0x4a09
 #define SPR_INTERRUPT_MASK_1_0 0x4809
 #define SPR_INTERRUPT_MASK_1_1 0x480a
+#define SPR_INTERRUPT_MASK_2_0 0x4608
+#define SPR_INTERRUPT_MASK_2_1 0x4609
 #define SPR_INTERRUPT_MASK_RESET_0_0 0x4a0a
 #define SPR_INTERRUPT_MASK_RESET_0_1 0x4a0b
 #define SPR_INTERRUPT_MASK_RESET_1_0 0x480b
 #define SPR_INTERRUPT_MASK_RESET_1_1 0x480c
+#define SPR_INTERRUPT_MASK_RESET_2_0 0x460a
+#define SPR_INTERRUPT_MASK_RESET_2_1 0x460b
 #define SPR_INTERRUPT_MASK_SET_0_0 0x4a0c
 #define SPR_INTERRUPT_MASK_SET_0_1 0x4a0d
 #define SPR_INTERRUPT_MASK_SET_1_0 0x480d
 #define SPR_INTERRUPT_MASK_SET_1_1 0x480e
+#define SPR_INTERRUPT_MASK_SET_2_0 0x460c
+#define SPR_INTERRUPT_MASK_SET_2_1 0x460d
 #define SPR_MPL_DMA_CPL_SET_0 0x5800
 #define SPR_MPL_DMA_CPL_SET_1 0x5801
+#define SPR_MPL_DMA_CPL_SET_2 0x5802
 #define SPR_MPL_DMA_NOTIFY_SET_0 0x3800
 #define SPR_MPL_DMA_NOTIFY_SET_1 0x3801
+#define SPR_MPL_DMA_NOTIFY_SET_2 0x3802
 #define SPR_MPL_INTCTRL_0_SET_0 0x4a00
 #define SPR_MPL_INTCTRL_0_SET_1 0x4a01
+#define SPR_MPL_INTCTRL_0_SET_2 0x4a02
 #define SPR_MPL_INTCTRL_1_SET_0 0x4800
 #define SPR_MPL_INTCTRL_1_SET_1 0x4801
+#define SPR_MPL_INTCTRL_1_SET_2 0x4802
+#define SPR_MPL_INTCTRL_2_SET_0 0x4600
+#define SPR_MPL_INTCTRL_2_SET_1 0x4601
+#define SPR_MPL_INTCTRL_2_SET_2 0x4602
 #define SPR_MPL_SN_ACCESS_SET_0 0x0800
 #define SPR_MPL_SN_ACCESS_SET_1 0x0801
+#define SPR_MPL_SN_ACCESS_SET_2 0x0802
 #define SPR_MPL_SN_CPL_SET_0 0x5a00
 #define SPR_MPL_SN_CPL_SET_1 0x5a01
+#define SPR_MPL_SN_CPL_SET_2 0x5a02
 #define SPR_MPL_SN_FIREWALL_SET_0 0x2c00
 #define SPR_MPL_SN_FIREWALL_SET_1 0x2c01
+#define SPR_MPL_SN_FIREWALL_SET_2 0x2c02
 #define SPR_MPL_SN_NOTIFY_SET_0 0x2a00
 #define SPR_MPL_SN_NOTIFY_SET_1 0x2a01
+#define SPR_MPL_SN_NOTIFY_SET_2 0x2a02
 #define SPR_MPL_UDN_ACCESS_SET_0 0x0c00
 #define SPR_MPL_UDN_ACCESS_SET_1 0x0c01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0c02
 #define SPR_MPL_UDN_AVAIL_SET_0 0x4000
 #define SPR_MPL_UDN_AVAIL_SET_1 0x4001
+#define SPR_MPL_UDN_AVAIL_SET_2 0x4002
 #define SPR_MPL_UDN_CA_SET_0 0x3c00
 #define SPR_MPL_UDN_CA_SET_1 0x3c01
+#define SPR_MPL_UDN_CA_SET_2 0x3c02
 #define SPR_MPL_UDN_COMPLETE_SET_0 0x1400
 #define SPR_MPL_UDN_COMPLETE_SET_1 0x1401
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x1402
 #define SPR_MPL_UDN_FIREWALL_SET_0 0x3000
 #define SPR_MPL_UDN_FIREWALL_SET_1 0x3001
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x3002
 #define SPR_MPL_UDN_REFILL_SET_0 0x1000
 #define SPR_MPL_UDN_REFILL_SET_1 0x1001
+#define SPR_MPL_UDN_REFILL_SET_2 0x1002
 #define SPR_MPL_UDN_TIMER_SET_0 0x3600
 #define SPR_MPL_UDN_TIMER_SET_1 0x3601
+#define SPR_MPL_UDN_TIMER_SET_2 0x3602
 #define SPR_MPL_WORLD_ACCESS_SET_0 0x4e00
 #define SPR_MPL_WORLD_ACCESS_SET_1 0x4e01
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x4e02
 #define SPR_PASS 0x4e0b
 #define SPR_PERF_COUNT_0 0x4205
 #define SPR_PERF_COUNT_1 0x4206
 #define SPR_PERF_COUNT_CTL 0x4207
+#define SPR_PERF_COUNT_DN_CTL 0x4210
 #define SPR_PERF_COUNT_STS 0x4208
 #define SPR_PROC_STATUS 0x4f00
 #define SPR_SIM_CONTROL 0x4e0c
 #define SPR_SYSTEM_SAVE_1_1 0x4901
 #define SPR_SYSTEM_SAVE_1_2 0x4902
 #define SPR_SYSTEM_SAVE_1_3 0x4903
+#define SPR_SYSTEM_SAVE_2_0 0x4700
+#define SPR_SYSTEM_SAVE_2_1 0x4701
+#define SPR_SYSTEM_SAVE_2_2 0x4702
+#define SPR_SYSTEM_SAVE_2_3 0x4703
 #define SPR_TILE_COORD 0x4c17
 #define SPR_TILE_RTF_HWM 0x4e10
 #define SPR_TILE_TIMER_CONTROL 0x3205
index 758ca4619d50017bffdec27c460edc2a95bfd38e..f18887d823999f8a7778defa2196ab10b586b81d 100644 (file)
@@ -146,7 +146,10 @@ enum {
 
        CALLER_SP_IN_R52_BASE = 4,
 
-       CALLER_SP_OFFSET_BASE = 8
+       CALLER_SP_OFFSET_BASE = 8,
+
+       /* Marks the entry point of certain functions. */
+       ENTRY_POINT_INFO_OP = 16
 };
 
 
index 8b60ec8b2d194f6e352df18eba598e3a61ef52f3..c3ae570c0a5d9ef209970d6d00a388a3128e550a 100644 (file)
@@ -216,15 +216,16 @@ struct compat_siginfo;
 struct compat_sigaltstack;
 long compat_sys_execve(const char __user *path,
                       const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp);
+                      const compat_uptr_t __user *envp, struct pt_regs *);
 long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
                             struct compat_sigaction __user *oact,
                             size_t sigsetsize);
 long compat_sys_rt_sigqueueinfo(int pid, int sig,
                                struct compat_siginfo __user *uinfo);
-long compat_sys_rt_sigreturn(void);
+long compat_sys_rt_sigreturn(struct pt_regs *);
 long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                           struct compat_sigaltstack __user *uoss_ptr);
+                           struct compat_sigaltstack __user *uoss_ptr,
+                           struct pt_regs *);
 long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
 long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
 long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
@@ -255,4 +256,12 @@ long tile_compat_sys_ptrace(compat_long_t request, compat_long_t pid,
 /* Tilera Linux syscalls that don't have "compat" versions. */
 #define compat_sys_flush_cache sys_flush_cache
 
+/* These are the intvec_64.S trampolines. */
+long _compat_sys_execve(const char __user *path,
+                       const compat_uptr_t __user *argv,
+                       const compat_uptr_t __user *envp);
+long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+                           struct compat_sigaltstack __user *uoss_ptr);
+long _compat_sys_rt_sigreturn(void);
+
 #endif /* _ASM_TILE_COMPAT_H */
index d155db6fa9bd9e64858858e01637e3ba420700aa..e0f7ee186721cf554dc142efdfc58350eaf6a7df 100644 (file)
@@ -60,12 +60,12 @@ void *kmap_fix_kpte(struct page *page, int finished);
 /* This macro is used only in map_new_virtual() to map "page". */
 #define kmap_prot page_to_kpgprot(page)
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
 void kmap_atomic_fix_kpte(struct page *page, int finished);
 
 #define flush_cache_kmaps()    do { } while (0)
index a11d4837ee4d6526137858e8fdd6226deb0a95d0..641e4ff3d805aa2014d6f6df0948c80fba580947 100644 (file)
        int __n = (n); \
        int __mask = 1 << (__n & 0x1f); \
        if (__n < 32) \
-               __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, __mask); \
+               __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, __mask); \
        else \
-               __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, __mask); \
+               __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, __mask); \
 } while (0)
 #define interrupt_mask_reset(n) do { \
        int __n = (n); \
        int __mask = 1 << (__n & 0x1f); \
        if (__n < 32) \
-               __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, __mask); \
+               __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, __mask); \
        else \
-               __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, __mask); \
+               __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, __mask); \
 } while (0)
 #define interrupt_mask_check(n) ({ \
        int __n = (n); \
        (((__n < 32) ? \
-        __insn_mfspr(SPR_INTERRUPT_MASK_1_0) : \
-        __insn_mfspr(SPR_INTERRUPT_MASK_1_1)) \
+        __insn_mfspr(SPR_INTERRUPT_MASK_K_0) : \
+        __insn_mfspr(SPR_INTERRUPT_MASK_K_1)) \
          >> (__n & 0x1f)) & 1; \
 })
 #define interrupt_mask_set_mask(mask) do { \
        unsigned long long __m = (mask); \
-       __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, (unsigned long)(__m)); \
-       __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, (unsigned long)(__m>>32)); \
+       __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, (unsigned long)(__m)); \
+       __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, (unsigned long)(__m>>32)); \
 } while (0)
 #define interrupt_mask_reset_mask(mask) do { \
        unsigned long long __m = (mask); \
-       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, (unsigned long)(__m)); \
-       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, (unsigned long)(__m>>32)); \
+       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \
+       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m>>32)); \
 } while (0)
 #else
 #define interrupt_mask_set(n) \
-       __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (1UL << (n)))
+       __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL << (n)))
 #define interrupt_mask_reset(n) \
-       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (1UL << (n)))
+       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (1UL << (n)))
 #define interrupt_mask_check(n) \
-       ((__insn_mfspr(SPR_INTERRUPT_MASK_1) >> (n)) & 1)
+       ((__insn_mfspr(SPR_INTERRUPT_MASK_K) >> (n)) & 1)
 #define interrupt_mask_set_mask(mask) \
-       __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (mask))
+       __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask))
 #define interrupt_mask_reset_mask(mask) \
-       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (mask))
+       __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask))
 #endif
 
 /*
  * The set of interrupts we want active if irqs are enabled.
  * Note that in particular, the tile timer interrupt comes and goes
  * from this set, since we have no other way to turn off the timer.
- * Likewise, INTCTRL_1 is removed and re-added during device
+ * Likewise, INTCTRL_K is removed and re-added during device
  * interrupts, as is the the hardwall UDN_FIREWALL interrupt.
  * We use a low bit (MEM_ERROR) as our sentinel value and make sure it
  * is always claimed as an "active interrupt" so we can query that bit
@@ -170,14 +170,14 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 
 /* Return 0 or 1 to indicate whether interrupts are currently disabled. */
 #define IRQS_DISABLED(tmp)                                     \
-       mfspr   tmp, INTERRUPT_MASK_1;                          \
+       mfspr   tmp, SPR_INTERRUPT_MASK_K;                      \
        andi    tmp, tmp, 1
 
 /* Load up a pointer to &interrupts_enabled_mask. */
 #define GET_INTERRUPTS_ENABLED_MASK_PTR(reg)                   \
-       moveli reg, hw2_last(interrupts_enabled_mask); \
-       shl16insli reg, reg, hw1(interrupts_enabled_mask); \
-       shl16insli reg, reg, hw0(interrupts_enabled_mask); \
+       moveli reg, hw2_last(interrupts_enabled_mask);          \
+       shl16insli reg, reg, hw1(interrupts_enabled_mask);      \
+       shl16insli reg, reg, hw0(interrupts_enabled_mask);      \
        add     reg, reg, tp
 
 /* Disable interrupts. */
@@ -185,18 +185,18 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
        moveli  tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS);      \
        shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS);  \
        shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS);  \
-       mtspr   INTERRUPT_MASK_SET_1, tmp0
+       mtspr   SPR_INTERRUPT_MASK_SET_K, tmp0
 
 /* Disable ALL synchronous interrupts (used by NMI entry). */
 #define IRQ_DISABLE_ALL(tmp)                                   \
        movei   tmp, -1;                                        \
-       mtspr   INTERRUPT_MASK_SET_1, tmp
+       mtspr   SPR_INTERRUPT_MASK_SET_K, tmp
 
 /* Enable interrupts. */
 #define IRQ_ENABLE(tmp0, tmp1)                                 \
        GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0);                  \
        ld      tmp0, tmp0;                                     \
-       mtspr   INTERRUPT_MASK_RESET_1, tmp0
+       mtspr   SPR_INTERRUPT_MASK_RESET_K, tmp0
 
 #else /* !__tilegx__ */
 
@@ -210,14 +210,14 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
  * (making the original code's write of the "high" mask word idempotent).
  */
 #define IRQS_DISABLED(tmp)                                     \
-       mfspr   tmp, INTERRUPT_MASK_1_0;                        \
+       mfspr   tmp, SPR_INTERRUPT_MASK_K_0;                    \
        shri    tmp, tmp, INT_MEM_ERROR;                        \
        andi    tmp, tmp, 1
 
 /* Load up a pointer to &interrupts_enabled_mask. */
 #define GET_INTERRUPTS_ENABLED_MASK_PTR(reg)                   \
-       moveli  reg, lo16(interrupts_enabled_mask);     \
-       auli    reg, reg, ha16(interrupts_enabled_mask);\
+       moveli  reg, lo16(interrupts_enabled_mask);             \
+       auli    reg, reg, ha16(interrupts_enabled_mask);        \
        add     reg, reg, tp
 
 /* Disable interrupts. */
@@ -227,16 +227,16 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
         moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS)           \
        };                                                      \
        {                                                       \
-        mtspr  INTERRUPT_MASK_SET_1_0, tmp0;                   \
+        mtspr  SPR_INTERRUPT_MASK_SET_K_0, tmp0;               \
         auli   tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS)     \
        };                                                      \
-       mtspr   INTERRUPT_MASK_SET_1_1, tmp1
+       mtspr   SPR_INTERRUPT_MASK_SET_K_1, tmp1
 
 /* Disable ALL synchronous interrupts (used by NMI entry). */
 #define IRQ_DISABLE_ALL(tmp)                                   \
        movei   tmp, -1;                                        \
-       mtspr   INTERRUPT_MASK_SET_1_0, tmp;                    \
-       mtspr   INTERRUPT_MASK_SET_1_1, tmp
+       mtspr   SPR_INTERRUPT_MASK_SET_K_0, tmp;                \
+       mtspr   SPR_INTERRUPT_MASK_SET_K_1, tmp
 
 /* Enable interrupts. */
 #define IRQ_ENABLE(tmp0, tmp1)                                 \
@@ -246,8 +246,8 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
         addi   tmp1, tmp0, 4                                   \
        };                                                      \
        lw      tmp1, tmp1;                                     \
-       mtspr   INTERRUPT_MASK_RESET_1_0, tmp0;                 \
-       mtspr   INTERRUPT_MASK_RESET_1_1, tmp1
+       mtspr   SPR_INTERRUPT_MASK_RESET_K_0, tmp0;             \
+       mtspr   SPR_INTERRUPT_MASK_RESET_K_1, tmp1
 #endif
 
 /*
index 4c6811e3e8dc09a88bf97881dfa50d17ef426acb..81b8fc348d63d9caea21b2edd5e94cfe999313dd 100644 (file)
@@ -23,6 +23,7 @@
 #define MAP_POPULATE   0x0040          /* populate (prefault) pagetables */
 #define MAP_NONBLOCK   0x0080          /* do not block on IO */
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_STACK      MAP_GROWSDOWN   /* provide convenience alias */
 #define MAP_LOCKED     0x0200          /* pages are locked */
 #define MAP_NORESERVE  0x0400          /* don't check for reservations */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 7d90641cf18d8e58a1a6e39d4ef83292a316388d..7979a45430d3bc46aa2d2fc39c8e65772706f0dc 100644 (file)
@@ -199,17 +199,17 @@ static inline __attribute_const__ int get_order(unsigned long size)
  * If you want more physical memory than this then see the CONFIG_HIGHMEM
  * option in the kernel configuration.
  *
- * The top two 16MB chunks in the table below (VIRT and HV) are
- * unavailable to Linux.  Since the kernel interrupt vectors must live
- * at 0xfd000000, we map all of the bottom of RAM at this address with
- * a huge page table entry to minimize its ITLB footprint (as well as
- * at PAGE_OFFSET).  The last architected requirement is that user
- * interrupt vectors live at 0xfc000000, so we make that range of
- * memory available to user processes.  The remaining regions are sized
- * as shown; after the first four addresses, we show "typical" values,
- * since the actual addresses depend on kernel #defines.
+ * The top 16MB chunk in the table below is unavailable to Linux.  Since
+ * the kernel interrupt vectors must live at ether 0xfe000000 or 0xfd000000
+ * (depending on whether the kernel is at PL2 or Pl1), we map all of the
+ * bottom of RAM at this address with a huge page table entry to minimize
+ * its ITLB footprint (as well as at PAGE_OFFSET).  The last architected
+ * requirement is that user interrupt vectors live at 0xfc000000, so we
+ * make that range of memory available to user processes.  The remaining
+ * regions are sized as shown; the first four addresses use the PL 1
+ * values, and after that, we show "typical" values, since the actual
+ * addresses depend on kernel #defines.
  *
- * MEM_VIRT_INTRPT                 0xff000000
  * MEM_HV_INTRPT                   0xfe000000
  * MEM_SV_INTRPT (kernel code)     0xfd000000
  * MEM_USER_INTRPT (user vector)   0xfc000000
@@ -221,9 +221,14 @@ static inline __attribute_const__ int get_order(unsigned long size)
  */
 
 #define MEM_USER_INTRPT                _AC(0xfc000000, UL)
+#if CONFIG_KERNEL_PL == 1
 #define MEM_SV_INTRPT          _AC(0xfd000000, UL)
 #define MEM_HV_INTRPT          _AC(0xfe000000, UL)
-#define MEM_VIRT_INTRPT                _AC(0xff000000, UL)
+#else
+#define MEM_GUEST_INTRPT       _AC(0xfd000000, UL)
+#define MEM_SV_INTRPT          _AC(0xfe000000, UL)
+#define MEM_HV_INTRPT          _AC(0xff000000, UL)
+#endif
 
 #define INTRPT_SIZE            0x4000
 
index b3367379d53754cd7540ff29987e591481767480..dc4ccdd855bca293070ea8bff94a699821d5e01b 100644 (file)
@@ -347,15 +347,10 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
 #define pte_offset_map(dir, address) \
        _pte_offset_map(dir, address, KM_PTE0)
-#define pte_offset_map_nested(dir, address) \
-       _pte_offset_map(dir, address, KM_PTE1)
 #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /* Clear a non-executable kernel PTE and flush it from the TLB. */
index ccd5f84256886c7526edd78bc58ab621f14ef2ac..1747ff3946b2ef50dea6e9591730238f3c720d08 100644 (file)
@@ -328,18 +328,21 @@ extern int kdata_huge;
  * Note that assembly code assumes that USER_PL is zero.
  */
 #define USER_PL 0
-#define KERNEL_PL 1
+#if CONFIG_KERNEL_PL == 2
+#define GUEST_PL 1
+#endif
+#define KERNEL_PL CONFIG_KERNEL_PL
 
-/* SYSTEM_SAVE_1_0 holds the current cpu number ORed with ksp0. */
+/* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */
 #define CPU_LOG_MASK_VALUE 12
 #define CPU_MASK_VALUE ((1 << CPU_LOG_MASK_VALUE) - 1)
 #if CONFIG_NR_CPUS > CPU_MASK_VALUE
 # error Too many cpus!
 #endif
 #define raw_smp_processor_id() \
-       ((int)__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & CPU_MASK_VALUE)
+       ((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & CPU_MASK_VALUE)
 #define get_current_ksp0() \
-       (__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & ~CPU_MASK_VALUE)
+       (__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~CPU_MASK_VALUE)
 #define next_current_ksp0(task) ({ \
        unsigned long __ksp0 = task_ksp0(task); \
        int __cpu = raw_smp_processor_id(); \
index 4a02bb07397993a2eb025ae7cd79caf618ae03d6..ac6d343129d3f92dd2b7148d72571c0562fffdee 100644 (file)
@@ -62,8 +62,8 @@ struct pt_regs {
        pt_reg_t lr;            /* aliases regs[TREG_LR] */
 
        /* Saved special registers. */
-       pt_reg_t pc;            /* stored in EX_CONTEXT_1_0 */
-       pt_reg_t ex1;           /* stored in EX_CONTEXT_1_1 (PL and ICS bit) */
+       pt_reg_t pc;            /* stored in EX_CONTEXT_K_0 */
+       pt_reg_t ex1;           /* stored in EX_CONTEXT_K_1 (PL and ICS bit) */
        pt_reg_t faultnum;      /* fault number (INT_SWINT_1 for syscall) */
        pt_reg_t orig_r0;       /* r0 at syscall entry, else zero */
        pt_reg_t flags;         /* flags (see below) */
index ce99ffefeacff351c5523d574581e1092d57ca06..3b5507c31eae592a850c8c8ff8851bb14b49682a 100644 (file)
@@ -32,8 +32,9 @@ extern void *compat_sys_call_table[];
 
 /*
  * Note that by convention, any syscall which requires the current
- * register set takes an additional "struct pt_regs *" pointer; the
- * sys_xxx() function just adds the pointer and tail-calls to _sys_xxx().
+ * register set takes an additional "struct pt_regs *" pointer; a
+ * _sys_xxx() trampoline in intvec*.S just sets up the pointer and
+ * jumps to sys_xxx().
  */
 
 /* kernel/sys.c */
@@ -43,66 +44,17 @@ long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
 int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
                       u32 len_lo, u32 len_hi, int advice);
 long sys_flush_cache(void);
-long sys_mmap2(unsigned long addr, unsigned long len,
-              unsigned long prot, unsigned long flags,
-              unsigned long fd, unsigned long pgoff);
-#ifdef __tilegx__
-long sys_mmap(unsigned long addr, unsigned long len,
-             unsigned long prot, unsigned long flags,
-             unsigned long fd, off_t pgoff);
+#ifndef __tilegx__  /* No mmap() in the 32-bit kernel. */
+#define sys_mmap sys_mmap
 #endif
 
-/* kernel/process.c */
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-              void __user *parent_tid, void __user *child_tid);
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
-               void __user *parent_tid, void __user *child_tid,
-               struct pt_regs *regs);
-long sys_fork(void);
-long _sys_fork(struct pt_regs *regs);
-long sys_vfork(void);
-long _sys_vfork(struct pt_regs *regs);
-long sys_execve(const char __user *filename,
-               const char __user *const __user *argv,
-               const char __user *const __user *envp);
-long _sys_execve(const char __user *filename,
-                const char __user *const __user *argv,
-                const char __user *const __user *envp, struct pt_regs *regs);
-
-/* kernel/signal.c */
-long sys_sigaltstack(const stack_t __user *, stack_t __user *);
-long _sys_sigaltstack(const stack_t __user *, stack_t __user *,
-                     struct pt_regs *);
-long sys_rt_sigreturn(void);
-long _sys_rt_sigreturn(struct pt_regs *regs);
-
-/* platform-independent functions */
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
-long sys_rt_sigaction(int sig, const struct sigaction __user *act,
-                     struct sigaction __user *oact, size_t sigsetsize);
-
 #ifndef __tilegx__
 /* mm/fault.c */
-int sys_cmpxchg_badaddr(unsigned long address);
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long _sys_cmpxchg_badaddr(unsigned long address);
 #endif
 
 #ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
-                      const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp);
-long _compat_sys_execve(const char __user *path,
-                       const compat_uptr_t __user *argv,
-                       const compat_uptr_t __user *envp,
-                       struct pt_regs *regs);
-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                           struct compat_sigaltstack __user *uoss_ptr);
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                            struct compat_sigaltstack __user *uoss_ptr,
-                            struct pt_regs *regs);
-long compat_sys_rt_sigreturn(void);
-long _compat_sys_rt_sigreturn(struct pt_regs *regs);
-
 /* These four are not defined for 64-bit, but serve as "compat" syscalls. */
 long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
 long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
@@ -110,4 +62,15 @@ long sys_truncate64(const char __user *path, loff_t length);
 long sys_ftruncate64(unsigned int fd, loff_t length);
 #endif
 
+/* These are the intvec*.S trampolines. */
+long _sys_sigaltstack(const stack_t __user *, stack_t __user *);
+long _sys_rt_sigreturn(void);
+long _sys_clone(unsigned long clone_flags, unsigned long newsp,
+               void __user *parent_tid, void __user *child_tid);
+long _sys_execve(const char __user *filename,
+                const char __user *const __user *argv,
+                const char __user *const __user *envp);
+
+#include <asm-generic/syscalls.h>
+
 #endif /* _ASM_TILE_SYSCALLS_H */
index f749be327ce0c503fa80227fb49f1821da6ccab3..5388850deeb231a64b212bb4ddb3c93f419f8167 100644 (file)
 #define get_cycles_low() __insn_mfspr(SPR_CYCLE)   /* just get all 64 bits */
 #endif
 
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+int __mb_incoherent(void);  /* Helper routine for mb_incoherent(). */
+#endif
+
 /* Fence to guarantee visibility of stores to incoherent memory. */
 static inline void
 mb_incoherent(void)
@@ -97,7 +101,6 @@ mb_incoherent(void)
 
 #if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
        {
-               int __mb_incoherent(void);
 #if CHIP_HAS_TILE_WRITE_PENDING()
                const unsigned long WRITE_TIMEOUT_CYCLES = 400;
                unsigned long start = get_cycles_low();
@@ -161,7 +164,7 @@ extern struct task_struct *_switch_to(struct task_struct *prev,
 /* Helper function for _switch_to(). */
 extern struct task_struct *__switch_to(struct task_struct *prev,
                                       struct task_struct *next,
-                                      unsigned long new_system_save_1_0);
+                                      unsigned long new_system_save_k_0);
 
 /* Address that switched-away from tasks are at. */
 extern unsigned long get_switch_to_pc(void);
@@ -214,13 +217,6 @@ int hardwall_deactivate(struct task_struct *task);
 } while (0)
 #endif
 
-/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
-extern int _sim_syscall(int syscall_num, ...);
-#define sim_syscall(syscall_num, ...) \
-       _sim_syscall(SIM_CONTROL_SYSCALL + \
-               ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
-               ## __VA_ARGS__)
-
 /*
  * Kernel threads can check to see if they need to migrate their
  * stack whenever they return from a context switch; for user
index 432a9c15c8a2bff86d997703fd5212ed3cc02e26..d06e35f572010cc1a5f4de4e78740039b785f89d 100644 (file)
@@ -59,4 +59,8 @@ void do_hardwall_trap(struct pt_regs *, int fault_num);
 void do_breakpoint(struct pt_regs *, int fault_num);
 
 
+#ifdef __tilegx__
+void gx_singlestep_handle(struct pt_regs *, int fault_num);
+#endif
+
 #endif /* _ASM_TILE_SYSCALLS_H */
index 9bd303a141b260026ce5327020f62142a9b0c07b..f672544cd4f94ed2ebdfbdb9af2cd8edbb021f3a 100644 (file)
@@ -1003,37 +1003,37 @@ int hv_console_write(HV_VirtAddr bytes, int len);
  *  when these occur in a client's interrupt critical section, they must
  *  be delivered through the downcall mechanism.
  *
- *  A downcall is initially delivered to the client as an INTCTRL_1
- *  interrupt.  Upon entry to the INTCTRL_1 vector, the client must
- *  immediately invoke the hv_downcall_dispatch service.  This service
- *  will not return; instead it will cause one of the client's actual
- *  downcall-handling interrupt vectors to be entered.  The EX_CONTEXT
- *  registers in the client will be set so that when the client irets,
- *  it will return to the code which was interrupted by the INTCTRL_1
- *  interrupt.
- *
- *  Under some circumstances, the firing of INTCTRL_1 can race with
+ *  A downcall is initially delivered to the client as an INTCTRL_CL
+ *  interrupt, where CL is the client's PL.  Upon entry to the INTCTRL_CL
+ *  vector, the client must immediately invoke the hv_downcall_dispatch
+ *  service.  This service will not return; instead it will cause one of
+ *  the client's actual downcall-handling interrupt vectors to be entered.
+ *  The EX_CONTEXT registers in the client will be set so that when the
+ *  client irets, it will return to the code which was interrupted by the
+ *  INTCTRL_CL interrupt.
+ *
+ *  Under some circumstances, the firing of INTCTRL_CL can race with
  *  the lowering of a device interrupt.  In such a case, the
  *  hv_downcall_dispatch service may issue an iret instruction instead
  *  of entering one of the client's actual downcall-handling interrupt
  *  vectors.  This will return execution to the location that was
- *  interrupted by INTCTRL_1.
+ *  interrupted by INTCTRL_CL.
  *
  *  Any saving of registers should be done by the actual handling
- *  vectors; no registers should be changed by the INTCTRL_1 handler.
+ *  vectors; no registers should be changed by the INTCTRL_CL handler.
  *  In particular, the client should not use a jal instruction to invoke
  *  the hv_downcall_dispatch service, as that would overwrite the client's
  *  lr register.  Note that the hv_downcall_dispatch service may overwrite
  *  one or more of the client's system save registers.
  *
- *  The client must not modify the INTCTRL_1_STATUS SPR.  The hypervisor
+ *  The client must not modify the INTCTRL_CL_STATUS SPR.  The hypervisor
  *  will set this register to cause a downcall to happen, and will clear
  *  it when no further downcalls are pending.
  *
- *  When a downcall vector is entered, the INTCTRL_1 interrupt will be
+ *  When a downcall vector is entered, the INTCTRL_CL interrupt will be
  *  masked.  When the client is done processing a downcall, and is ready
  *  to accept another, it must unmask this interrupt; if more downcalls
- *  are pending, this will cause the INTCTRL_1 vector to be reentered.
+ *  are pending, this will cause the INTCTRL_CL vector to be reentered.
  *  Currently the following interrupt vectors can be entered through a
  *  downcall:
  *
index d3c41c1ff6bd9dae73908276cd7a41b1c70696a6..55a6a74974b4dad8c973484bcf2dc1934c34b309 100644 (file)
@@ -369,6 +369,10 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                        /* Weird; reserved value, ignore it. */
                                        continue;
                                }
+                               if (info_operand & ENTRY_POINT_INFO_OP) {
+                                       /* This info op is ignored by the backtracer. */
+                                       continue;
+                               }
 
                                /* Skip info ops which are not in the
                                 * "one_ago" mode we want right now.
index b1e06d0415555e5437ccd26d9c1ec8990582851a..77739cdd9462dacf2a9188a0a0418c014e6379f9 100644 (file)
@@ -154,8 +154,14 @@ long tile_compat_sys_msgrcv(int msqid,
 #define compat_sys_fstat64 sys_newfstat
 #define compat_sys_fstatat64 sys_newfstatat
 
-/* Pass full 64-bit values through ptrace. */
-#define compat_sys_ptrace tile_compat_sys_ptrace
+/* The native sys_ptrace dynamically handles compat binaries. */
+#define compat_sys_ptrace sys_ptrace
+
+/* Call the trampolines to manage pt_regs where necessary. */
+#define compat_sys_execve _compat_sys_execve
+#define compat_sys_sigaltstack _compat_sys_sigaltstack
+#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
+#define sys_clone _sys_clone
 
 /*
  * Note that we can't include <linux/unistd.h> here since the header
index 9c710db43f1329c8b850f4a058e295df171c314e..fb64b99959d42dd796c6d16c4b471cc8d9769a50 100644 (file)
@@ -256,9 +256,9 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
        return err;
 }
 
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                            struct compat_sigaltstack __user *uoss_ptr,
-                            struct pt_regs *regs)
+long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+                           struct compat_sigaltstack __user *uoss_ptr,
+                           struct pt_regs *regs)
 {
        stack_t uss, uoss;
        int ret;
@@ -291,7 +291,7 @@ long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
        return ret;
 }
 
-long _compat_sys_rt_sigreturn(struct pt_regs *regs)
+long compat_sys_rt_sigreturn(struct pt_regs *regs)
 {
        struct compat_rt_sigframe __user *frame =
                (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
@@ -312,7 +312,7 @@ long _compat_sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
                goto badframe;
 
-       if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+       if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
                goto badframe;
 
        return r0;
index 3d01383b1b0e3c8c6e805570599eb0b0d6fa211f..fd8dc42abdcb15c07e231f57205045f735c815c0 100644 (file)
@@ -15,7 +15,9 @@
 #include <linux/linkage.h>
 #include <linux/unistd.h>
 #include <asm/irqflags.h>
+#include <asm/processor.h>
 #include <arch/abi.h>
+#include <arch/spr_def.h>
 
 #ifdef __tilegx__
 #define bnzt bnezt
@@ -25,28 +27,6 @@ STD_ENTRY(current_text_addr)
        { move r0, lr; jrp lr }
        STD_ENDPROC(current_text_addr)
 
-STD_ENTRY(_sim_syscall)
-       /*
-        * Wait for r0-r9 to be ready (and lr on the off chance we
-        * want the syscall to locate its caller), then make a magic
-        * simulator syscall.
-        *
-        * We carefully stall until the registers are readable in case they
-        * are the target of a slow load, etc. so that tile-sim will
-        * definitely be able to read all of them inside the magic syscall.
-        *
-        * Technically this is wrong for r3-r9 and lr, since an interrupt
-        * could come in and restore the registers with a slow load right
-        * before executing the mtspr. We may need to modify tile-sim to
-        * explicitly stall for this case, but we do not yet have
-        * a way to implement such a stall.
-        */
-       { and zero, lr, r9 ; and zero, r8, r7 }
-       { and zero, r6, r5 ; and zero, r4, r3 }
-       { and zero, r2, r1 ; mtspr SIM_CONTROL, r0 }
-       { jrp lr }
-       STD_ENDPROC(_sim_syscall)
-
 /*
  * Implement execve().  The i386 code has a note that forking from kernel
  * space results in no copy on write until the execve, so we should be
@@ -102,7 +82,7 @@ STD_ENTRY(KBacktraceIterator_init_current)
 STD_ENTRY(cpu_idle_on_new_stack)
        {
         move sp, r1
-        mtspr SYSTEM_SAVE_1_0, r2
+        mtspr SPR_SYSTEM_SAVE_K_0, r2
        }
        jal free_thread_info
        j cpu_idle
@@ -124,15 +104,15 @@ STD_ENTRY(smp_nap)
 STD_ENTRY(_cpu_idle)
        {
         lnk r0
-        movei r1, 1
+        movei r1, KERNEL_PL
        }
        {
         addli r0, r0, _cpu_idle_nap - .
         mtspr INTERRUPT_CRITICAL_SECTION, r1
        }
-       IRQ_ENABLE(r2, r3)         /* unmask, but still with ICS set */
-       mtspr EX_CONTEXT_1_1, r1   /* PL1, ICS clear */
-       mtspr EX_CONTEXT_1_0, r0
+       IRQ_ENABLE(r2, r3)             /* unmask, but still with ICS set */
+       mtspr SPR_EX_CONTEXT_K_1, r1   /* Kernel PL, ICS clear */
+       mtspr SPR_EX_CONTEXT_K_0, r0
        iret
        .global _cpu_idle_nap
 _cpu_idle_nap:
index 2b4f6c09170179d85884d13574670a47e5220ef2..90e7c4435693d1848917b267a28a8770a8d5c64b 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/asm-offsets.h>
 #include <hv/hypervisor.h>
 #include <arch/chip.h>
+#include <arch/spr_def.h>
 
 /*
  * This module contains the entry code for kernel images. It performs the
@@ -76,7 +77,7 @@ ENTRY(_start)
        }
 1:
 
-       /* Get our processor number and save it away in SAVE_1_0. */
+       /* Get our processor number and save it away in SAVE_K_0. */
        jal hv_inquire_topology
        mulll_uu r4, r1, r2        /* r1 == y, r2 == width */
        add r4, r4, r0             /* r0 == x, so r4 == cpu == y*width + x */
@@ -124,7 +125,7 @@ ENTRY(_start)
        lw r0, r0
        lw sp, r1
        or r4, sp, r4
-       mtspr SYSTEM_SAVE_1_0, r4  /* save ksp0 + cpu */
+       mtspr SPR_SYSTEM_SAVE_K_0, r4  /* save ksp0 + cpu */
        addi sp, sp, -STACK_TOP_DELTA
        {
          move lr, zero   /* stop backtraces in the called function */
index 8f58bdff20d7f7dd9b77d16a6901eb9db82f056b..f5821626247fee9891d47eca123b26440f6c025c 100644 (file)
@@ -32,8 +32,8 @@
 # error "No support for kernel preemption currently"
 #endif
 
-#if INT_INTCTRL_1 < 32 || INT_INTCTRL_1 >= 48
-# error INT_INTCTRL_1 coded to set high interrupt mask
+#if INT_INTCTRL_K < 32 || INT_INTCTRL_K >= 48
+# error INT_INTCTRL_K coded to set high interrupt mask
 #endif
 
 #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
@@ -132,8 +132,8 @@ intvec_\vecname:
 
        /* Temporarily save a register so we have somewhere to work. */
 
-       mtspr   SYSTEM_SAVE_1_1, r0
-       mfspr   r0, EX_CONTEXT_1_1
+       mtspr   SPR_SYSTEM_SAVE_K_1, r0
+       mfspr   r0, SPR_EX_CONTEXT_K_1
 
        /* The cmpxchg code clears sp to force us to reset it here on fault. */
        {
@@ -167,18 +167,18 @@ intvec_\vecname:
         * The page_fault handler may be downcalled directly by the
         * hypervisor even when Linux is running and has ICS set.
         *
-        * In this case the contents of EX_CONTEXT_1_1 reflect the
+        * In this case the contents of EX_CONTEXT_K_1 reflect the
         * previous fault and can't be relied on to choose whether or
         * not to reinitialize the stack pointer.  So we add a test
-        * to see whether SYSTEM_SAVE_1_2 has the high bit set,
+        * to see whether SYSTEM_SAVE_K_2 has the high bit set,
         * and if so we don't reinitialize sp, since we must be coming
         * from Linux.  (In fact the precise case is !(val & ~1),
         * but any Linux PC has to have the high bit set.)
         *
-        * Note that the hypervisor *always* sets SYSTEM_SAVE_1_2 for
+        * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
         * any path that turns into a downcall to one of our TLB handlers.
         */
-       mfspr   r0, SYSTEM_SAVE_1_2
+       mfspr   r0, SPR_SYSTEM_SAVE_K_2
        {
         blz    r0, 0f    /* high bit in S_S_1_2 is for a PC to use */
         move   r0, sp
@@ -187,12 +187,12 @@ intvec_\vecname:
 
 2:
        /*
-        * SYSTEM_SAVE_1_0 holds the cpu number in the low bits, and
+        * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
         * the current stack top in the higher bits.  So we recover
         * our stack top by just masking off the low bits, then
         * point sp at the top aligned address on the actual stack page.
         */
-       mfspr   r0, SYSTEM_SAVE_1_0
+       mfspr   r0, SPR_SYSTEM_SAVE_K_0
        mm      r0, r0, zero, LOG2_THREAD_SIZE, 31
 
 0:
@@ -254,7 +254,7 @@ intvec_\vecname:
         sw     sp, r3
         addli  sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
        }
-       mfspr   r0, EX_CONTEXT_1_0
+       mfspr   r0, SPR_EX_CONTEXT_K_0
        .ifc \processing,handle_syscall
        /*
         * Bump the saved PC by one bundle so that when we return, we won't
@@ -267,7 +267,7 @@ intvec_\vecname:
         sw     sp, r0
         addli  sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
        }
-       mfspr   r0, EX_CONTEXT_1_1
+       mfspr   r0, SPR_EX_CONTEXT_K_1
        {
         sw     sp, r0
         addi   sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
@@ -289,7 +289,7 @@ intvec_\vecname:
         .endif
         addli  sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
        }
-       mfspr   r0, SYSTEM_SAVE_1_1    /* Original r0 */
+       mfspr   r0, SPR_SYSTEM_SAVE_K_1    /* Original r0 */
        {
         sw     sp, r0
         addi   sp, sp, -PTREGS_OFFSET_REG(0) - 4
@@ -309,12 +309,12 @@ intvec_\vecname:
         * See discussion below at "finish_interrupt_save".
         */
        .ifc \c_routine, do_page_fault
-       mfspr   r2, SYSTEM_SAVE_1_3   /* address of page fault */
-       mfspr   r3, SYSTEM_SAVE_1_2   /* info about page fault */
+       mfspr   r2, SPR_SYSTEM_SAVE_K_3   /* address of page fault */
+       mfspr   r3, SPR_SYSTEM_SAVE_K_2   /* info about page fault */
        .else
        .ifc \vecnum, INT_DOUBLE_FAULT
        {
-        mfspr  r2, SYSTEM_SAVE_1_2   /* double fault info from HV */
+        mfspr  r2, SPR_SYSTEM_SAVE_K_2   /* double fault info from HV */
         movei  r3, 0
        }
        .else
@@ -467,7 +467,7 @@ intvec_\vecname:
        /* Load tp with our per-cpu offset. */
 #ifdef CONFIG_SMP
        {
-        mfspr  r20, SYSTEM_SAVE_1_0
+        mfspr  r20, SPR_SYSTEM_SAVE_K_0
         moveli r21, lo16(__per_cpu_offset)
        }
        {
@@ -487,7 +487,7 @@ intvec_\vecname:
         * We load flags in r32 here so we can jump to .Lrestore_regs
         * directly after do_page_fault_ics() if necessary.
         */
-       mfspr   r32, EX_CONTEXT_1_1
+       mfspr   r32, SPR_EX_CONTEXT_K_1
        {
         andi   r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
         PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
@@ -957,11 +957,11 @@ STD_ENTRY(interrupt_return)
        pop_reg_zero r21, r3, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
        pop_reg_zero lr, r4, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_EX1
        {
-        mtspr  EX_CONTEXT_1_0, r21
+        mtspr  SPR_EX_CONTEXT_K_0, r21
         move   r5, zero
        }
        {
-        mtspr  EX_CONTEXT_1_1, lr
+        mtspr  SPR_EX_CONTEXT_K_1, lr
         andi   lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
        }
 
@@ -1020,7 +1020,7 @@ STD_ENTRY(interrupt_return)
 
        /* Set r1 to errno if we are returning an error, otherwise zero. */
        {
-        moveli r29, 1024
+        moveli r29, 4096
         sub    r1, zero, r0
        }
        slt_u   r29, r1, r29
@@ -1199,7 +1199,7 @@ STD_ENTRY(interrupt_return)
        STD_ENDPROC(interrupt_return)
 
        /*
-        * This interrupt variant clears the INT_INTCTRL_1 interrupt mask bit
+        * This interrupt variant clears the INT_INTCTRL_K interrupt mask bit
         * before returning, so we can properly get more downcalls.
         */
        .pushsection .text.handle_interrupt_downcall,"ax"
@@ -1208,11 +1208,11 @@ handle_interrupt_downcall:
        check_single_stepping normal, .Ldispatch_downcall
 .Ldispatch_downcall:
 
-       /* Clear INTCTRL_1 from the set of interrupts we ever enable. */
+       /* Clear INTCTRL_K from the set of interrupts we ever enable. */
        GET_INTERRUPTS_ENABLED_MASK_PTR(r30)
        {
         addi   r30, r30, 4
-        movei  r31, INT_MASK(INT_INTCTRL_1)
+        movei  r31, INT_MASK(INT_INTCTRL_K)
        }
        {
         lw     r20, r30
@@ -1227,7 +1227,7 @@ handle_interrupt_downcall:
        }
        FEEDBACK_REENTER(handle_interrupt_downcall)
 
-       /* Allow INTCTRL_1 to be enabled next time we enable interrupts. */
+       /* Allow INTCTRL_K to be enabled next time we enable interrupts. */
        lw      r20, r30
        or      r20, r20, r31
        sw      r30, r20
@@ -1472,7 +1472,12 @@ handle_ill:
        lw      r26, r24
        sw      r28, r26
 
-       /* Clear TIF_SINGLESTEP */
+       /*
+        * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill.
+        * The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we
+        * need to clear it here and can't really impose on all other arches.
+        * So what's another write between friends?
+        */
        GET_THREAD_INFO(r0)
 
        addi    r1, r0, THREAD_INFO_FLAGS_OFFSET
@@ -1509,7 +1514,7 @@ handle_ill:
 /* Various stub interrupt handlers and syscall handlers */
 
 STD_ENTRY_LOCAL(_kernel_double_fault)
-       mfspr   r1, EX_CONTEXT_1_0
+       mfspr   r1, SPR_EX_CONTEXT_K_0
        move    r2, lr
        move    r3, sp
        move    r4, r52
@@ -1518,34 +1523,29 @@ STD_ENTRY_LOCAL(_kernel_double_fault)
        STD_ENDPROC(_kernel_double_fault)
 
 STD_ENTRY_LOCAL(bad_intr)
-       mfspr   r2, EX_CONTEXT_1_0
+       mfspr   r2, SPR_EX_CONTEXT_K_0
        panic   "Unhandled interrupt %#x: PC %#lx"
        STD_ENDPROC(bad_intr)
 
 /* Put address of pt_regs in reg and jump. */
 #define PTREGS_SYSCALL(x, reg)                          \
-       STD_ENTRY(x);                                   \
+       STD_ENTRY(_##x);                                \
        {                                               \
         PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
-        j      _##x                                    \
+        j      x                                       \
        };                                              \
-       STD_ENDPROC(x)
+       STD_ENDPROC(_##x)
 
 PTREGS_SYSCALL(sys_execve, r3)
 PTREGS_SYSCALL(sys_sigaltstack, r2)
 PTREGS_SYSCALL(sys_rt_sigreturn, r0)
+PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
 
-/* Save additional callee-saves to pt_regs, put address in reg and jump. */
-#define PTREGS_SYSCALL_ALL_REGS(x, reg)                 \
-       STD_ENTRY(x);                                   \
-       push_extra_callee_saves reg;                    \
-       j       _##x;                                   \
-       STD_ENDPROC(x)
-
-PTREGS_SYSCALL_ALL_REGS(sys_fork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_vfork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_clone, r4)
-PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+       push_extra_callee_saves r4
+       j       sys_clone
+       STD_ENDPROC(_sys_clone)
 
 /*
  * This entrypoint is taken for the cmpxchg and atomic_update fast
@@ -1558,12 +1558,14 @@ PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
  * to be available to it on entry.  It does not modify any callee-save
  * registers (including "lr").  It does not check what PL it is being
  * called at, so you'd better not call it other than at PL0.
+ * The <atomic.h> wrapper assumes it only clobbers r20-r29, so if
+ * it ever is necessary to use more registers, be aware.
  *
  * It does not use the stack, but since it might be re-interrupted by
  * a page fault which would assume the stack was valid, it does
  * save/restore the stack pointer and zero it out to make sure it gets reset.
  * Since we always keep interrupts disabled, the hypervisor won't
- * clobber our EX_CONTEXT_1_x registers, so we don't save/restore them
+ * clobber our EX_CONTEXT_K_x registers, so we don't save/restore them
  * (other than to advance the PC on return).
  *
  * We have to manually validate the user vs kernel address range
@@ -1769,7 +1771,7 @@ ENTRY(sys_cmpxchg)
        /* Do slow mtspr here so the following "mf" waits less. */
        {
         move   sp, r27
-        mtspr  EX_CONTEXT_1_0, r28
+        mtspr  SPR_EX_CONTEXT_K_0, r28
        }
        mf
 
@@ -1788,7 +1790,7 @@ ENTRY(sys_cmpxchg)
        }
        {
         move   sp, r27
-        mtspr  EX_CONTEXT_1_0, r28
+        mtspr  SPR_EX_CONTEXT_K_0, r28
        }
        iret
 
@@ -1816,7 +1818,7 @@ ENTRY(sys_cmpxchg)
 #endif
 
        /* Issue the slow SPR here while the tns result is in flight. */
-       mfspr   r28, EX_CONTEXT_1_0
+       mfspr   r28, SPR_EX_CONTEXT_K_0
 
        {
         addi   r28, r28, 8    /* return to the instruction after the swint1 */
@@ -1904,7 +1906,7 @@ ENTRY(sys_cmpxchg)
 .Lcmpxchg64_mismatch:
        {
         move   sp, r27
-        mtspr  EX_CONTEXT_1_0, r28
+        mtspr  SPR_EX_CONTEXT_K_0, r28
        }
        mf
        {
@@ -1985,8 +1987,13 @@ int_unalign:
        int_hand     INT_PERF_COUNT, PERF_COUNT, \
                     op_handle_perf_interrupt, handle_nmi
        int_hand     INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       dc_dispatch  INT_INTCTRL_2, INTCTRL_2
+       int_hand     INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
        int_hand     INT_INTCTRL_2, INTCTRL_2, bad_intr
        dc_dispatch  INT_INTCTRL_1, INTCTRL_1
+#endif
        int_hand     INT_INTCTRL_0, INTCTRL_0, bad_intr
        int_hand     INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
                     hv_message_intr, handle_interrupt_downcall
index 9a27d563fc30968ce3efb46ac11ce241e10d8cc0..e63917687e998907824a62b1783ffef599418818 100644 (file)
@@ -61,9 +61,9 @@ static DEFINE_SPINLOCK(available_irqs_lock);
 
 #if CHIP_HAS_IPI()
 /* Use SPRs to manipulate device interrupts. */
-#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_1, irq_mask)
-#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_1, irq_mask)
-#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_1, irq_mask)
+#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask)
+#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_K, irq_mask)
+#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_K, irq_mask)
 #else
 /* Use HV to manipulate device interrupts. */
 #define mask_irqs(irq_mask) hv_disable_intr(irq_mask)
@@ -89,16 +89,16 @@ void tile_dev_intr(struct pt_regs *regs, int intnum)
         * masked by a previous interrupt.  Then, mask out the ones
         * we're going to handle.
         */
-       unsigned long masked = __insn_mfspr(SPR_IPI_MASK_1);
-       original_irqs = __insn_mfspr(SPR_IPI_EVENT_1) & ~masked;
-       __insn_mtspr(SPR_IPI_MASK_SET_1, original_irqs);
+       unsigned long masked = __insn_mfspr(SPR_IPI_MASK_K);
+       original_irqs = __insn_mfspr(SPR_IPI_EVENT_K) & ~masked;
+       __insn_mtspr(SPR_IPI_MASK_SET_K, original_irqs);
 #else
        /*
         * Hypervisor performs the equivalent of the Gx code above and
         * then puts the pending interrupt mask into a system save reg
         * for us to find.
         */
-       original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_1_3);
+       original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_K_3);
 #endif
        remaining_irqs = original_irqs;
 
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
        /* Enable interrupt delivery. */
        unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-       raw_local_irq_unmask(INT_IPI_1);
+       raw_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
index 6d23ed271d10f0b87280e26660451e320f6a6ff4..997e3933f72679718583dae5a82c72c4d2f9fbdb 100644 (file)
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
                panic("hv_register_message_state: error %d", rc);
 
        /* Make sure downcall interrupts will be enabled. */
-       raw_local_irq_unmask(INT_INTCTRL_1);
+       raw_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
index 84c29111756c2212f02cd5bc841691c1cc0a0fd9..8430f45daea6bce566cc0980db85f0d0b213af72 100644 (file)
@@ -214,9 +214,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        /*
         * Copy the callee-saved registers from the passed pt_regs struct
         * into the context-switch callee-saved registers area.
-        * We have to restore the callee-saved registers since we may
-        * be cloning a userspace task with userspace register state,
-        * and we won't be unwinding the same kernel frames to restore them.
+        * This way when we start the interrupt-return sequence, the
+        * callee-save registers will be correctly in registers, which
+        * is how we assume the compiler leaves them as we start doing
+        * the normal return-from-interrupt path after calling C code.
         * Zero out the C ABI save area to mark the top of the stack.
         */
        ksp = (unsigned long) childregs;
@@ -304,15 +305,25 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
 /* Allow user processes to access the DMA SPRs */
 void grant_dma_mpls(void)
 {
+#if CONFIG_KERNEL_PL == 2
+       __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
+       __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#else
        __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1);
        __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1);
+#endif
 }
 
 /* Forbid user processes from accessing the DMA SPRs */
 void restrict_dma_mpls(void)
 {
+#if CONFIG_KERNEL_PL == 2
+       __insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1);
+       __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1);
+#else
        __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
        __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#endif
 }
 
 /* Pause the DMA engine, then save off its state registers. */
@@ -523,19 +534,14 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
         * Switch kernel SP, PC, and callee-saved registers.
         * In the context of the new task, return the old task pointer
         * (i.e. the task that actually called __switch_to).
-        * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp.
+        * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp.
         */
        return __switch_to(prev, next, next_current_ksp0(next));
 }
 
-long _sys_fork(struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
-}
-
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
-               void __user *parent_tidptr, void __user *child_tidptr,
-               struct pt_regs *regs)
+SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
+               void __user *, parent_tidptr, void __user *, child_tidptr,
+               struct pt_regs *, regs)
 {
        if (!newsp)
                newsp = regs->sp;
@@ -543,18 +549,13 @@ long _sys_clone(unsigned long clone_flags, unsigned long newsp,
                       parent_tidptr, child_tidptr);
 }
 
-long _sys_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
-                      regs, 0, NULL, NULL);
-}
-
 /*
  * sys_execve() executes a new program.
  */
-long _sys_execve(const char __user *path,
-                const char __user *const __user *argv,
-                const char __user *const __user *envp, struct pt_regs *regs)
+SYSCALL_DEFINE4(execve, const char __user *, path,
+               const char __user *const __user *, argv,
+               const char __user *const __user *, envp,
+               struct pt_regs *, regs)
 {
        long error;
        char *filename;
@@ -570,9 +571,10 @@ out:
 }
 
 #ifdef CONFIG_COMPAT
-long _compat_sys_execve(const char __user *path,
-                       const compat_uptr_t __user *argv,
-                       const compat_uptr_t __user *envp, struct pt_regs *regs)
+long compat_sys_execve(const char __user *path,
+                      const compat_uptr_t __user *argv,
+                      const compat_uptr_t __user *envp,
+                      struct pt_regs *regs)
 {
        long error;
        char *filename;
index 7161bd03d2fdbe8d057587f20c4adf3ffffcb61a..5b20c2874d51e84da57c151f1244a42e386952bd 100644 (file)
@@ -31,25 +31,6 @@ void user_disable_single_step(struct task_struct *child)
        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
-/*
- * This routine will put a word on the process's privileged stack.
- */
-static void putreg(struct task_struct *task,
-                  unsigned long addr, unsigned long value)
-{
-       unsigned int regno = addr / sizeof(unsigned long);
-       struct pt_regs *childregs = task_pt_regs(task);
-       childregs->regs[regno] = value;
-       childregs->flags |= PT_FLAGS_RESTORE_REGS;
-}
-
-static unsigned long getreg(struct task_struct *task, unsigned long addr)
-{
-       unsigned int regno = addr / sizeof(unsigned long);
-       struct pt_regs *childregs = task_pt_regs(task);
-       return childregs->regs[regno];
-}
-
 /*
  * Called by kernel/ptrace.c when detaching..
  */
@@ -66,59 +47,72 @@ void ptrace_disable(struct task_struct *child)
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
-       unsigned long __user *datap;
+       unsigned long __user *datap = (long __user __force *)data;
        unsigned long tmp;
        int i;
        long ret = -EIO;
-
-#ifdef CONFIG_COMPAT
-       if (task_thread_info(current)->status & TS_COMPAT)
-               data = (u32)data;
-       if (task_thread_info(child)->status & TS_COMPAT)
-               addr = (u32)addr;
-#endif
-       datap = (unsigned long __user __force *)data;
+       unsigned long *childregs;
+       char *childreg;
 
        switch (request) {
 
        case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
-               if (addr & (sizeof(data)-1))
-                       break;
                if (addr < 0 || addr >= PTREGS_SIZE)
                        break;
-               tmp = getreg(child, addr);   /* Read register */
-               ret = put_user(tmp, datap);
+               childreg = (char *)task_pt_regs(child) + addr;
+#ifdef CONFIG_COMPAT
+               if (is_compat_task()) {
+                       if (addr & (sizeof(compat_long_t)-1))
+                               break;
+                       ret = put_user(*(compat_long_t *)childreg,
+                                      (compat_long_t __user *)datap);
+               } else
+#endif
+               {
+                       if (addr & (sizeof(long)-1))
+                               break;
+                       ret = put_user(*(long *)childreg, datap);
+               }
                break;
 
        case PTRACE_POKEUSR:  /* Write register in pt_regs. */
-               if (addr & (sizeof(data)-1))
-                       break;
                if (addr < 0 || addr >= PTREGS_SIZE)
                        break;
-               putreg(child, addr, data);   /* Write register */
+               childreg = (char *)task_pt_regs(child) + addr;
+#ifdef CONFIG_COMPAT
+               if (is_compat_task()) {
+                       if (addr & (sizeof(compat_long_t)-1))
+                               break;
+                       *(compat_long_t *)childreg = data;
+               } else
+#endif
+               {
+                       if (addr & (sizeof(long)-1))
+                               break;
+                       *(long *)childreg = data;
+               }
                ret = 0;
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
                if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
                        break;
-               for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
-                       ret = __put_user(getreg(child, i), datap);
+               childregs = (long *)task_pt_regs(child);
+               for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) {
+                       ret = __put_user(childregs[i], &datap[i]);
                        if (ret != 0)
                                break;
-                       datap++;
                }
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
                if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
                        break;
-               for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
-                       ret = __get_user(tmp, datap);
+               childregs = (long *)task_pt_regs(child);
+               for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) {
+                       ret = __get_user(childregs[i], &datap[i]);
                        if (ret != 0)
                                break;
-                       putreg(child, i, tmp);
-                       datap++;
                }
                break;
 
index e88d6e122783d94f46aadaf8618d99383486ec58..caa13101c26474f352c4e60a00666d1ccefcb6de 100644 (file)
@@ -85,7 +85,7 @@ STD_ENTRY_SECTION(__switch_to, .sched.text)
        {
          /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
          move sp, r13
-         mtspr SYSTEM_SAVE_1_0, r2
+         mtspr SPR_SYSTEM_SAVE_K_0, r2
        }
        FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
 .L__switch_to_pc:
index e7d54c73d5c125e3ccc220b8552e4c012a8aeae3..f3a50e74f9a4a0768058d81564c9da9c625938a5 100644 (file)
@@ -187,11 +187,11 @@ early_param("vmalloc", parse_vmalloc);
 
 #ifdef CONFIG_HIGHMEM
 /*
- * Determine for each controller where its lowmem is mapped and how
- * much of it is mapped there.  On controller zero, the first few
- * megabytes are mapped at 0xfd000000 as code, so in principle we
- * could start our data mappings higher up, but for now we don't
- * bother, to avoid additional confusion.
+ * Determine for each controller where its lowmem is mapped and how much of
+ * it is mapped there.  On controller zero, the first few megabytes are
+ * already mapped in as code at MEM_SV_INTRPT, so in principle we could
+ * start our data mappings higher up, but for now we don't bother, to avoid
+ * additional confusion.
  *
  * One question is whether, on systems with more than 768 Mb and
  * controllers of different sizes, to map in a proportionate amount of
@@ -311,7 +311,7 @@ static void __init setup_memory(void)
 #endif
 
        /* We are using a char to hold the cpu_2_node[] mapping */
-       BUG_ON(MAX_NUMNODES > 127);
+       BUILD_BUG_ON(MAX_NUMNODES > 127);
 
        /* Discover the ranges of memory available to us */
        for (i = 0; ; ++i) {
@@ -876,6 +876,9 @@ void __cpuinit setup_cpu(int boot)
 #if CHIP_HAS_SN_PROC()
        raw_local_irq_unmask(INT_SNITLB_MISS);
 #endif
+#ifdef __tilegx__
+       raw_local_irq_unmask(INT_SINGLE_STEP_K);
+#endif
 
        /*
         * Allow user access to many generic SPRs, like the cycle
@@ -893,11 +896,12 @@ void __cpuinit setup_cpu(int boot)
 #endif
 
        /*
-        * Set the MPL for interrupt control 0 to user level.
-        * This includes access to the SYSTEM_SAVE and EX_CONTEXT SPRs,
-        * as well as the PL 0 interrupt mask.
+        * Set the MPL for interrupt control 0 & 1 to the corresponding
+        * values.  This includes access to the SYSTEM_SAVE and EX_CONTEXT
+        * SPRs, as well as the interrupt mask.
         */
        __insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1);
+       __insn_mtspr(SPR_MPL_INTCTRL_1_SET_1, 1);
 
        /* Initialize IRQ support for this cpu. */
        setup_irq_regs();
@@ -1033,7 +1037,7 @@ static void __init validate_va(void)
         * In addition, make sure we CAN'T use the end of memory, since
         * we use the last chunk of each pgd for the pgd_list.
         */
-       int i, fc_fd_ok = 0;
+       int i, user_kernel_ok = 0;
        unsigned long max_va = 0;
        unsigned long list_va =
                ((PGD_LIST_OFFSET / sizeof(pgd_t)) << PGDIR_SHIFT);
@@ -1044,13 +1048,13 @@ static void __init validate_va(void)
                        break;
                if (range.start <= MEM_USER_INTRPT &&
                    range.start + range.size >= MEM_HV_INTRPT)
-                       fc_fd_ok = 1;
+                       user_kernel_ok = 1;
                if (range.start == 0)
                        max_va = range.size;
                BUG_ON(range.start + range.size > list_va);
        }
-       if (!fc_fd_ok)
-               early_panic("Hypervisor not configured for VAs 0xfc/0xfd\n");
+       if (!user_kernel_ok)
+               early_panic("Hypervisor not configured for user/kernel VAs\n");
        if (max_va == 0)
                early_panic("Hypervisor not configured for low VAs\n");
        if (max_va < KERNEL_HIGH_VADDR)
@@ -1334,6 +1338,10 @@ static void __init pcpu_fc_populate_pte(unsigned long addr)
        pte_t *pte;
 
        BUG_ON(pgd_addr_invalid(addr));
+       if (addr < VMALLOC_START || addr >= VMALLOC_END)
+               panic("PCPU addr %#lx outside vmalloc range %#lx..%#lx;"
+                     " try increasing CONFIG_VMALLOC_RESERVE\n",
+                     addr, VMALLOC_START, VMALLOC_END);
 
        pgd = swapper_pg_dir + pgd_index(addr);
        pud = pud_offset(pgd, addr);
index ce183aa1492c7abfaadfca95d54ec76bddc11455..fb28e85ae3aea3698c7d2cd5da564bb0a5f7fb0d 100644 (file)
@@ -41,8 +41,8 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 
-long _sys_sigaltstack(const stack_t __user *uss,
-                     stack_t __user *uoss, struct pt_regs *regs)
+SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
+               stack_t __user *, uoss, struct pt_regs *, regs)
 {
        return do_sigaltstack(uss, uoss, regs->sp);
 }
@@ -78,7 +78,7 @@ int restore_sigcontext(struct pt_regs *regs,
 }
 
 /* sigreturn() returns long since it restores r0 in the interrupted code. */
-long _sys_rt_sigreturn(struct pt_regs *regs)
+SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
 {
        struct rt_sigframe __user *frame =
                (struct rt_sigframe __user *)(regs->sp);
index 5ec4b9c651f26a72e6ef39616827b6f29d2b0d4d..1eb3b39e36c70e01ad65e325496081157524fc40 100644 (file)
@@ -15,7 +15,7 @@
  * Derived from iLib's single-stepping code.
  */
 
-#ifndef __tilegx__   /* No support for single-step yet. */
+#ifndef __tilegx__   /* Hardware support for single step unavailable. */
 
 /* These functions are only used on the TILE platform */
 #include <linux/slab.h>
@@ -660,4 +660,75 @@ void single_step_once(struct pt_regs *regs)
                regs->pc += 8;
 }
 
+#else
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <arch/spr_def.h>
+
+static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
+
+
+/*
+ * Called directly on the occasion of an interrupt.
+ *
+ * If the process doesn't have single step set, then we use this as an
+ * opportunity to turn single step off.
+ *
+ * It has been mentioned that we could conditionally turn off single stepping
+ * on each entry into the kernel and rely on single_step_once to turn it
+ * on for the processes that matter (as we already do), but this
+ * implementation is somewhat more efficient in that we muck with registers
+ * once on a bum interrupt rather than on every entry into the kernel.
+ *
+ * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred,
+ * so we have to run through this process again before we can say that an
+ * instruction has executed.
+ *
+ * swint will set CANCELED, but it's a legitimate instruction.  Fortunately
+ * it changes the PC.  If it hasn't changed, then we know that the interrupt
+ * wasn't generated by swint and we'll need to run this process again before
+ * we can say an instruction has executed.
+ *
+ * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get
+ * on with our lives.
+ */
+
+void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
+{
+       unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+       struct thread_info *info = (void *)current_thread_info();
+       int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
+       unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+       if (is_single_step == 0) {
+               __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0);
+
+       } else if ((*ss_pc != regs->pc) ||
+                  (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) {
+
+               ptrace_notify(SIGTRAP);
+               control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+               control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+               __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+       }
+}
+
+
+/*
+ * Called from need_singlestep.  Set up the control registers and the enable
+ * register, then return back.
+ */
+
+void single_step_once(struct pt_regs *regs)
+{
+       unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+       unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+       *ss_pc = regs->pc;
+       control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+       control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+       __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+       __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL);
+}
+
 #endif /* !__tilegx__ */
index 1cb5ec79de043ad4cdf9ebf244e5d9356c767bf1..75255d90aff309669b110dff32f2254ede9daa27 100644 (file)
@@ -212,7 +212,7 @@ void __init ipi_init(void)
 
                tile.x = cpu_x(cpu);
                tile.y = cpu_y(cpu);
-               if (hv_get_ipi_pte(tile, 1, &pte) != 0)
+               if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0)
                        panic("Failed to initialize IPI for cpu %d\n", cpu);
 
                offset = hv_pte_get_pfn(pte) << PAGE_SHIFT;
index ea2e0ce28380a2d3fa59391cfc02cb4ca0022f1e..0d54106be3d66b33f089cc499c0b33d82a3635b6 100644 (file)
 #include <arch/abi.h>
 #include <arch/interrupts.h>
 
+#define KBT_ONGOING    0  /* Backtrace still ongoing */
+#define KBT_DONE       1  /* Backtrace cleanly completed */
+#define KBT_RUNNING    2  /* Can't run backtrace on a running task */
+#define KBT_LOOP       3  /* Backtrace entered a loop */
 
 /* Is address on the specified kernel stack? */
 static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
@@ -207,11 +211,11 @@ static int KBacktraceIterator_next_item_inclusive(
        for (;;) {
                do {
                        if (!KBacktraceIterator_is_sigreturn(kbt))
-                               return 1;
+                               return KBT_ONGOING;
                } while (backtrace_next(&kbt->it));
 
                if (!KBacktraceIterator_restart(kbt))
-                       return 0;
+                       return KBT_DONE;
        }
 }
 
@@ -264,7 +268,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        kbt->pgtable = NULL;
        kbt->verbose = 0;   /* override in caller if desired */
        kbt->profile = 0;   /* override in caller if desired */
-       kbt->end = 0;
+       kbt->end = KBT_ONGOING;
        kbt->new_context = 0;
        if (is_current) {
                HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
@@ -290,7 +294,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        if (regs == NULL) {
                if (is_current || t->state == TASK_RUNNING) {
                        /* Can't do this; we need registers */
-                       kbt->end = 1;
+                       kbt->end = KBT_RUNNING;
                        return;
                }
                pc = get_switch_to_pc();
@@ -305,26 +309,29 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        }
 
        backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
-       kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+       kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
 }
 EXPORT_SYMBOL(KBacktraceIterator_init);
 
 int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
 {
-       return kbt->end;
+       return kbt->end != KBT_ONGOING;
 }
 EXPORT_SYMBOL(KBacktraceIterator_end);
 
 void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
 {
+       VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
        kbt->new_context = 0;
-       if (!backtrace_next(&kbt->it) &&
-           !KBacktraceIterator_restart(kbt)) {
-                       kbt->end = 1;
-                       return;
-               }
-
-       kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+       if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
+               kbt->end = KBT_DONE;
+               return;
+       }
+       kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
+       if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) {
+               /* Trapped in a loop; give up. */
+               kbt->end = KBT_LOOP;
+       }
 }
 EXPORT_SYMBOL(KBacktraceIterator_next);
 
@@ -387,6 +394,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
                        break;
                }
        }
+       if (kbt->end == KBT_LOOP)
+               pr_err("Stack dump stopped; next frame identical to this one\n");
        if (headers)
                pr_err("Stack dump complete\n");
 }
index f0f87eab8c3982f087e6db3a71327ba283659f5e..7e764669a0222755db93373089539e18ade539d8 100644 (file)
@@ -110,6 +110,15 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 #define sys_sync_file_range sys_sync_file_range2
 #endif
 
+/* Call the trampolines to manage pt_regs where necessary. */
+#define sys_execve _sys_execve
+#define sys_sigaltstack _sys_sigaltstack
+#define sys_rt_sigreturn _sys_rt_sigreturn
+#define sys_clone _sys_clone
+#ifndef __tilegx__
+#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
+#endif
+
 /*
  * Note that we can't include <linux/unistd.h> here since the header
  * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
index 0f362dc2c57f6f68d5c32e90b65c32f5b28d8f7d..5474fc2e77e8456b3d6e745b8defc3129e08eb85 100644 (file)
@@ -260,7 +260,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
                address = regs->pc;
                break;
        case INT_UNALIGN_DATA:
-#ifndef __tilegx__  /* FIXME: GX: no single-step yet */
+#ifndef __tilegx__  /* Emulated support for single step debugging */
                if (unaligned_fixup >= 0) {
                        struct single_step_state *state =
                                current_thread_info()->step_state;
@@ -278,7 +278,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
        case INT_DOUBLE_FAULT:
                /*
                 * For double fault, "reason" is actually passed as
-                * SYSTEM_SAVE_1_2, the hypervisor's double-fault info, so
+                * SYSTEM_SAVE_K_2, the hypervisor's double-fault info, so
                 * we can provide the original fault number rather than
                 * the uninteresting "INT_DOUBLE_FAULT" so the user can
                 * learn what actually struck while PL0 ICS was set.
diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig
new file mode 100644 (file)
index 0000000..b88f9c0
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+       bool "Virtualization"
+       ---help---
+         Say Y here to get to see options for using your Linux host to run
+         other operating systems inside virtual machines (guests).
+         This option alone does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and
+         disabled.
+
+if VIRTUALIZATION
+
+config KVM
+       tristate "Kernel-based Virtual Machine (KVM) support"
+       depends on HAVE_KVM && MODULES && EXPERIMENTAL
+       select PREEMPT_NOTIFIERS
+       select ANON_INODES
+       ---help---
+         Support hosting paravirtualized guest machines.
+
+         This module provides access to the hardware capabilities through
+         a character device node named /dev/kvm.
+
+         To compile this as a module, choose M here: the module
+         will be called kvm.
+
+         If unsure, say N.
+
+source drivers/vhost/Kconfig
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
index 746dc81ed3c4fa3110386852c34b5a8597c082dd..93122d5b1558dad80205f1b09fdfbd19dcfc8a97 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 lib-y = cacheflush.o checksum.o cpumask.o delay.o \
-       mb_incoherent.o uaccess.o \
-       memcpy_$(BITS).o memchr_$(BITS).o memmove_$(BITS).o memset_$(BITS).o \
+       mb_incoherent.o uaccess.o memmove.o \
+       memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
        strchr_$(BITS).o strlen_$(BITS).o
 
 ifeq ($(CONFIG_TILEGX),y)
index 8040b42a8eea4b4172271b344aa978b7cc587d55..7a5cc706ab62cf19dbbcae51fdb5b2a4ea04680a 100644 (file)
@@ -300,7 +300,7 @@ void __init __init_atomic_per_cpu(void)
 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
        /* Validate power-of-two and "bigger than cpus" assumption */
-       BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
+       BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
        BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids);
 
        /*
@@ -314,17 +314,17 @@ void __init __init_atomic_per_cpu(void)
        BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0);
 
        /* The locks must all fit on one page. */
-       BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
+       BUILD_BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
 
        /*
         * We use the page offset of the atomic value's address as
         * an index into atomic_locks, excluding the low 3 bits.
         * That should not produce more indices than ATOMIC_HASH_SIZE.
         */
-       BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
+       BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
        /* The futex code makes this assumption, so we validate it here. */
-       BUG_ON(sizeof(atomic_t) != sizeof(int));
+       BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 }
index ce5dbf56578f6a9ee303f484ea54bbdba06c40f2..1509c5597653c0c7e6731ed071477574aad09720 100644 (file)
@@ -45,6 +45,9 @@ EXPORT_SYMBOL(__copy_from_user_zeroing);
 EXPORT_SYMBOL(__copy_in_user_inatomic);
 #endif
 
+/* arch/tile/lib/mb_incoherent.S */
+EXPORT_SYMBOL(__mb_incoherent);
+
 /* hypervisor glue */
 #include <hv/hypervisor.h>
 EXPORT_SYMBOL(hv_dev_open);
index 30c3b7ebb55d54a7017657034e30f74c00c506e0..2a419a6122db78e4b45c532de3b5ef6d24cc1cad 100644 (file)
  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  *   NON INFRINGEMENT.  See the GNU General Public License for
  *   more details.
- *
- * This file shares the implementation of the userspace memcpy and
- * the kernel's memcpy, copy_to_user and copy_from_user.
  */
 
 #include <arch/chip.h>
 
 
+/*
+ * This file shares the implementation of the userspace memcpy and
+ * the kernel's memcpy, copy_to_user and copy_from_user.
+ */
+
 #include <linux/linkage.h>
 
 /* On TILE64, we wrap these functions via arch/tile/lib/memcpy_tile64.c */
@@ -53,9 +55,9 @@
  */
 ENTRY(__copy_from_user_inatomic)
 .type __copy_from_user_inatomic, @function
-        FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
+       FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
          .text.memcpy_common, \
-          .Lend_memcpy_common - __copy_from_user_inatomic)
+         .Lend_memcpy_common - __copy_from_user_inatomic)
        { movei r29, IS_COPY_FROM_USER; j memcpy_common }
        .size __copy_from_user_inatomic, . - __copy_from_user_inatomic
 
@@ -64,7 +66,7 @@ ENTRY(__copy_from_user_inatomic)
  */
 ENTRY(__copy_from_user_zeroing)
 .type __copy_from_user_zeroing, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+       FEEDBACK_REENTER(__copy_from_user_inatomic)
        { movei r29, IS_COPY_FROM_USER_ZEROING; j memcpy_common }
        .size __copy_from_user_zeroing, . - __copy_from_user_zeroing
 
@@ -74,13 +76,13 @@ ENTRY(__copy_from_user_zeroing)
  */
 ENTRY(__copy_to_user_inatomic)
 .type __copy_to_user_inatomic, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+       FEEDBACK_REENTER(__copy_from_user_inatomic)
        { movei r29, IS_COPY_TO_USER; j memcpy_common }
        .size __copy_to_user_inatomic, . - __copy_to_user_inatomic
 
 ENTRY(memcpy)
 .type memcpy, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+       FEEDBACK_REENTER(__copy_from_user_inatomic)
        { movei r29, IS_MEMCPY }
        .size memcpy, . - memcpy
        /* Fall through */
@@ -157,35 +159,35 @@ EX:       { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
        { addi r3, r1, 60; andi r9, r9, -64 }
 
 #if CHIP_HAS_WH64()
-        /* No need to prefetch dst, we'll just do the wh64
-         * right before we copy a line.
+       /* No need to prefetch dst, we'll just do the wh64
+        * right before we copy a line.
         */
 #endif
 
 EX:    { lw r5, r3; addi r3, r3, 64; movei r4, 1 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, .; move r27, lr }
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bnzt zero, .; move r27, lr }
 EX:    { lw r6, r3; addi r3, r3, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bnzt zero, . }
 EX:    { lw r7, r3; addi r3, r3, 64 }
 #if !CHIP_HAS_WH64()
-        /* Prefetch the dest */
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        /* Use a real load to cause a TLB miss if necessary.  We aren't using
-         * r28, so this should be fine.
-         */
+       /* Prefetch the dest */
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bnzt zero, . }
+       /* Use a real load to cause a TLB miss if necessary.  We aren't using
+        * r28, so this should be fine.
+        */
 EX:    { lw r28, r9; addi r9, r9, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        { prefetch r9; addi r9, r9, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        { prefetch r9; addi r9, r9, 64 }
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bnzt zero, . }
+       { prefetch r9; addi r9, r9, 64 }
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bnzt zero, . }
+       { prefetch r9; addi r9, r9, 64 }
 #endif
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bz zero, .Lbig_loop2 }
+       /* Intentionally stall for a few cycles to leave L2 cache alone. */
+       { bz zero, .Lbig_loop2 }
 
        /* On entry to this loop:
         * - r0 points to the start of dst line 0
@@ -197,7 +199,7 @@ EX: { lw r28, r9; addi r9, r9, 64 }
         *   to some "safe" recently loaded address.
         * - r5 contains *(r1 + 60)       [i.e. last word of source line 0]
         * - r6 contains *(r1 + 64 + 60)  [i.e. last word of source line 1]
-         * - r9 contains ((r0 + 63) & -64)
+        * - r9 contains ((r0 + 63) & -64)
         *     [start of next dst cache line.]
         */
 
@@ -208,137 +210,137 @@ EX:     { lw r28, r9; addi r9, r9, 64 }
        /* Copy line 0, first stalling until r5 is ready. */
 EX:    { move r12, r5; lw r16, r1 }
        { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+       /* Prefetch several lines ahead. */
 EX:    { lw r5, r3; addi r3, r3, 64 }
-        { jal .Lcopy_line }
+       { jal .Lcopy_line }
 
        /* Copy line 1, first stalling until r6 is ready. */
 EX:    { move r12, r6; lw r16, r1 }
        { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+       /* Prefetch several lines ahead. */
 EX:    { lw r6, r3; addi r3, r3, 64 }
        { jal .Lcopy_line }
 
        /* Copy line 2, first stalling until r7 is ready. */
 EX:    { move r12, r7; lw r16, r1 }
        { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+       /* Prefetch several lines ahead. */
 EX:    { lw r7, r3; addi r3, r3, 64 }
-        /* Use up a caches-busy cycle by jumping back to the top of the
-         * loop. Might as well get it out of the way now.
-         */
-        { j .Lbig_loop }
+       /* Use up a caches-busy cycle by jumping back to the top of the
+        * loop. Might as well get it out of the way now.
+        */
+       { j .Lbig_loop }
 
 
        /* On entry:
         * - r0 points to the destination line.
         * - r1 points to the source line.
-         * - r3 is the next prefetch address.
+        * - r3 is the next prefetch address.
         * - r9 holds the last address used for wh64.
         * - r12 = WORD_15
-         * - r16 = WORD_0.
-         * - r17 == r1 + 16.
-         * - r27 holds saved lr to restore.
+        * - r16 = WORD_0.
+        * - r17 == r1 + 16.
+        * - r27 holds saved lr to restore.
         *
         * On exit:
         * - r0 is incremented by 64.
         * - r1 is incremented by 64, unless that would point to a word
-         *   beyond the end of the source array, in which case it is redirected
-         *   to point to an arbitrary word already in the cache.
+        *   beyond the end of the source array, in which case it is redirected
+        *   to point to an arbitrary word already in the cache.
         * - r2 is decremented by 64.
-         * - r3 is unchanged, unless it points to a word beyond the
-         *   end of the source array, in which case it is redirected
-         *   to point to an arbitrary word already in the cache.
-         *   Redirecting is OK since if we are that close to the end
-         *   of the array we will not come back to this subroutine
-         *   and use the contents of the prefetched address.
+        * - r3 is unchanged, unless it points to a word beyond the
+        *   end of the source array, in which case it is redirected
+        *   to point to an arbitrary word already in the cache.
+        *   Redirecting is OK since if we are that close to the end
+        *   of the array we will not come back to this subroutine
+        *   and use the contents of the prefetched address.
         * - r4 is nonzero iff r2 >= 64.
-         * - r9 is incremented by 64, unless it points beyond the
-         *   end of the last full destination cache line, in which
-         *   case it is redirected to a "safe address" that can be
-         *   clobbered (sp - 64)
+        * - r9 is incremented by 64, unless it points beyond the
+        *   end of the last full destination cache line, in which
+        *   case it is redirected to a "safe address" that can be
+        *   clobbered (sp - 64)
         * - lr contains the value in r27.
         */
 
 /* r26 unused */
 
 .Lcopy_line:
-        /* TODO: when r3 goes past the end, we would like to redirect it
-         * to prefetch the last partial cache line (if any) just once, for the
-         * benefit of the final cleanup loop. But we don't want to
-         * prefetch that line more than once, or subsequent prefetches
-         * will go into the RTF. But then .Lbig_loop should unconditionally
-         * branch to top of loop to execute final prefetch, and its
-         * nop should become a conditional branch.
-         */
-
-        /* We need two non-memory cycles here to cover the resources
-         * used by the loads initiated by the caller.
-         */
-        { add r15, r1, r2 }
+       /* TODO: when r3 goes past the end, we would like to redirect it
+        * to prefetch the last partial cache line (if any) just once, for the
+        * benefit of the final cleanup loop. But we don't want to
+        * prefetch that line more than once, or subsequent prefetches
+        * will go into the RTF. But then .Lbig_loop should unconditionally
+        * branch to top of loop to execute final prefetch, and its
+        * nop should become a conditional branch.
+        */
+
+       /* We need two non-memory cycles here to cover the resources
+        * used by the loads initiated by the caller.
+        */
+       { add r15, r1, r2 }
 .Lcopy_line2:
-        { slt_u r13, r3, r15; addi r17, r1, 16 }
+       { slt_u r13, r3, r15; addi r17, r1, 16 }
 
-        /* NOTE: this will stall for one cycle as L1 is busy. */
+       /* NOTE: this will stall for one cycle as L1 is busy. */
 
-        /* Fill second L1D line. */
+       /* Fill second L1D line. */
 EX:    { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */
 
 #if CHIP_HAS_WH64()
-        /* Prepare destination line for writing. */
+       /* Prepare destination line for writing. */
 EX:    { wh64 r9; addi r9, r9, 64 }
 #else
-        /* Prefetch dest line */
+       /* Prefetch dest line */
        { prefetch r9; addi r9, r9, 64 }
 #endif
-        /* Load seven words that are L1D hits to cover wh64 L2 usage. */
+       /* Load seven words that are L1D hits to cover wh64 L2 usage. */
 
-        /* Load the three remaining words from the last L1D line, which
-         * we know has already filled the L1D.
-         */
+       /* Load the three remaining words from the last L1D line, which
+        * we know has already filled the L1D.
+        */
 EX:    { lw r4, r1;  addi r1, r1, 4;   addi r20, r1, 16 }   /* r4 = WORD_12 */
 EX:    { lw r8, r1;  addi r1, r1, 4;   slt_u r13, r20, r15 }/* r8 = WORD_13 */
 EX:    { lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 }  /* r11 = WORD_14 */
 
-        /* Load the three remaining words from the first L1D line, first
-         * stalling until it has filled by "looking at" r16.
-         */
+       /* Load the three remaining words from the first L1D line, first
+        * stalling until it has filled by "looking at" r16.
+        */
 EX:    { lw r13, r1; addi r1, r1, 4; move zero, r16 }   /* r13 = WORD_1 */
 EX:    { lw r14, r1; addi r1, r1, 4 }                   /* r14 = WORD_2 */
 EX:    { lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */
 
-        /* Load second word from the second L1D line, first
-         * stalling until it has filled by "looking at" r17.
-         */
+       /* Load second word from the second L1D line, first
+        * stalling until it has filled by "looking at" r17.
+        */
 EX:    { lw r19, r1; addi r1, r1, 4; move zero, r17 }  /* r19 = WORD_5 */
 
-        /* Store last word to the destination line, potentially dirtying it
-         * for the first time, which keeps the L2 busy for two cycles.
-         */
+       /* Store last word to the destination line, potentially dirtying it
+        * for the first time, which keeps the L2 busy for two cycles.
+        */
 EX:    { sw r10, r12 }                                 /* store(WORD_15) */
 
-        /* Use two L1D hits to cover the sw L2 access above. */
+       /* Use two L1D hits to cover the sw L2 access above. */
 EX:    { lw r10, r1; addi r1, r1, 4 }                  /* r10 = WORD_6 */
 EX:    { lw r12, r1; addi r1, r1, 4 }                  /* r12 = WORD_7 */
 
-        /* Fill third L1D line. */
+       /* Fill third L1D line. */
 EX:    { lw r18, r1; addi r1, r1, 4 }                  /* r18 = WORD_8 */
 
-        /* Store first L1D line. */
+       /* Store first L1D line. */
 EX:    { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */
 EX:    { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */
 EX:    { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */
 #if CHIP_HAS_WH64()
 EX:    { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */
 #else
-        /* Back up the r9 to a cache line we are already storing to
+       /* Back up the r9 to a cache line we are already storing to
         * if it gets past the end of the dest vector.  Strictly speaking,
         * we don't need to back up to the start of a cache line, but it's free
         * and tidy, so why not?
-         */
+        */
 EX:    { sw r0, r15; addi r0, r0, 4; andi r13, r0, -64 } /* store(WORD_3) */
 #endif
-        /* Store second L1D line. */
+       /* Store second L1D line. */
 EX:    { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */
 EX:    { sw r0, r19; addi r0, r0, 4 }                  /* store(WORD_5) */
 EX:    { sw r0, r10; addi r0, r0, 4 }                  /* store(WORD_6) */
@@ -348,30 +350,30 @@ EX:       { lw r13, r1; addi r1, r1, 4; move zero, r18 }  /* r13 = WORD_9 */
 EX:    { lw r14, r1; addi r1, r1, 4 }                  /* r14 = WORD_10 */
 EX:    { lw r15, r1; move r1, r20   }                  /* r15 = WORD_11 */
 
-        /* Store third L1D line. */
+       /* Store third L1D line. */
 EX:    { sw r0, r18; addi r0, r0, 4 }                  /* store(WORD_8) */
 EX:    { sw r0, r13; addi r0, r0, 4 }                  /* store(WORD_9) */
 EX:    { sw r0, r14; addi r0, r0, 4 }                  /* store(WORD_10) */
 EX:    { sw r0, r15; addi r0, r0, 4 }                  /* store(WORD_11) */
 
-        /* Store rest of fourth L1D line. */
+       /* Store rest of fourth L1D line. */
 EX:    { sw r0, r4;  addi r0, r0, 4 }                  /* store(WORD_12) */
-        {
+       {
 EX:    sw r0, r8                                       /* store(WORD_13) */
-        addi r0, r0, 4
+       addi r0, r0, 4
        /* Will r2 be > 64 after we subtract 64 below? */
-        shri r4, r2, 7
-        }
-        {
+       shri r4, r2, 7
+       }
+       {
 EX:    sw r0, r11                                      /* store(WORD_14) */
-        addi r0, r0, 8
-        /* Record 64 bytes successfully copied. */
-        addi r2, r2, -64
-        }
+       addi r0, r0, 8
+       /* Record 64 bytes successfully copied. */
+       addi r2, r2, -64
+       }
 
        { jrp lr; move lr, r27 }
 
-        /* Convey to the backtrace library that the stack frame is size
+       /* Convey to the backtrace library that the stack frame is size
         * zero, and the real return address is on the stack rather than
         * in 'lr'.
         */
diff --git a/arch/tile/lib/memmove.c b/arch/tile/lib/memmove.c
new file mode 100644 (file)
index 0000000..fd615ae
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010 Tilera Corporation. 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, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       if ((const char *)src >= (char *)dest + n
+           || (char *)dest >= (const char *)src + n) {
+               /* We found no overlap, so let memcpy do all the heavy
+                * lifting (prefetching, etc.)
+                */
+               return memcpy(dest, src, n);
+       }
+
+       if (n != 0) {
+               const uint8_t *in;
+               uint8_t x;
+               uint8_t *out;
+               int stride;
+
+               if (src < dest) {
+                       /* copy backwards */
+                       in = (const uint8_t *)src + n - 1;
+                       out = (uint8_t *)dest + n - 1;
+                       stride = -1;
+               } else {
+                       /* copy forwards */
+                       in = (const uint8_t *)src;
+                       out = (uint8_t *)dest;
+                       stride = 1;
+               }
+
+               /* Manually software-pipeline this loop. */
+               x = *in;
+               in += stride;
+
+               while (--n != 0) {
+                       *out = x;
+                       out += stride;
+                       x = *in;
+                       in += stride;
+               }
+
+               *out = x;
+       }
+
+       return dest;
+}
+EXPORT_SYMBOL(memmove);
diff --git a/arch/tile/lib/memmove_32.c b/arch/tile/lib/memmove_32.c
deleted file mode 100644 (file)
index fd615ae..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. 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, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/module.h>
-
-void *memmove(void *dest, const void *src, size_t n)
-{
-       if ((const char *)src >= (char *)dest + n
-           || (char *)dest >= (const char *)src + n) {
-               /* We found no overlap, so let memcpy do all the heavy
-                * lifting (prefetching, etc.)
-                */
-               return memcpy(dest, src, n);
-       }
-
-       if (n != 0) {
-               const uint8_t *in;
-               uint8_t x;
-               uint8_t *out;
-               int stride;
-
-               if (src < dest) {
-                       /* copy backwards */
-                       in = (const uint8_t *)src + n - 1;
-                       out = (uint8_t *)dest + n - 1;
-                       stride = -1;
-               } else {
-                       /* copy forwards */
-                       in = (const uint8_t *)src;
-                       out = (uint8_t *)dest;
-                       stride = 1;
-               }
-
-               /* Manually software-pipeline this loop. */
-               x = *in;
-               in += stride;
-
-               while (--n != 0) {
-                       *out = x;
-                       out += stride;
-                       x = *in;
-                       in += stride;
-               }
-
-               *out = x;
-       }
-
-       return dest;
-}
-EXPORT_SYMBOL(memmove);
index d014c1fbcbc28816af4925b72d121c1d201edf0a..57dbb3a5bff86a59e71054100c4ac1c885402a7b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#undef memset
 
 void *memset(void *s, int c, size_t n)
 {
index f26f88e11e4a8d9885ba10eec773b4181a5739a8..4974292a553498bc789dae5e4e938e95e311051c 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#undef strlen
+
 size_t strlen(const char *s)
 {
        /* Get an aligned pointer. */
index 704f3e8a43850c5d32a0eda83bb33190b72d07b3..f295b4ac941de22b760651f5ac019361e00802d2 100644 (file)
@@ -66,10 +66,10 @@ static noinline void force_sig_info_fault(int si_signo, int si_code,
 #ifndef __tilegx__
 /*
  * Synthesize the fault a PL0 process would get by doing a word-load of
- * an unaligned address or a high kernel address.  Called indirectly
- * from sys_cmpxchg() in kernel/intvec.S.
+ * an unaligned address or a high kernel address.
  */
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *regs)
+SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
+               struct pt_regs *, regs)
 {
        if (address >= PAGE_OFFSET)
                force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
@@ -563,10 +563,10 @@ do_sigbus:
 /*
  * When we take an ITLB or DTLB fault or access violation in the
  * supervisor while the critical section bit is set, the hypervisor is
- * reluctant to write new values into the EX_CONTEXT_1_x registers,
+ * reluctant to write new values into the EX_CONTEXT_K_x registers,
  * since that might indicate we have not yet squirreled the SPR
  * contents away and can thus safely take a recursive interrupt.
- * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_1_2.
+ * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_K_2.
  *
  * Note that this routine is called before homecache_tlb_defer_enter(),
  * which means that we can properly unlock any atomics that might
@@ -610,7 +610,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
         * fault.  We didn't set up a kernel stack on initial entry to
         * sys_cmpxchg, but instead had one set up by the fault, which
         * (because sys_cmpxchg never releases ICS) came to us via the
-        * SYSTEM_SAVE_1_2 mechanism, and thus EX_CONTEXT_1_[01] are
+        * SYSTEM_SAVE_K_2 mechanism, and thus EX_CONTEXT_K_[01] are
         * still referencing the original user code.  We release the
         * atomic lock and rewrite pt_regs so that it appears that we
         * came from user-space directly, and after we finish the
index 12ab137e7d4f837f36c95a7ebd3b82caa5a30869..8ef6595e162c1348ca65aa21e349bd2d47b81b42 100644 (file)
@@ -56,50 +56,6 @@ void kunmap(struct page *page)
 }
 EXPORT_SYMBOL(kunmap);
 
-static void debug_kmap_atomic_prot(enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-       static unsigned warn_count = 10;
-
-       if (unlikely(warn_count == 0))
-               return;
-
-       if (unlikely(in_interrupt())) {
-               if (in_irq()) {
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_BIO_SRC_IRQ &&
-                           /* type != KM_BIO_DST_IRQ && */
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               } else if (!irqs_disabled()) {  /* softirq */
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
-                           type != KM_SKB_SUNRPC_DATA &&
-                           type != KM_SKB_DATA_SOFTIRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               }
-       }
-
-       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
-           type == KM_BIO_SRC_IRQ /* || type == KM_BIO_DST_IRQ */) {
-               if (!irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
-               if (irq_count() == 0 && !irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       }
-#endif
-}
-
 /*
  * Describe a single atomic mapping of a page on a given cpu at a
  * given address, and allow it to be linked into a list.
@@ -240,10 +196,10 @@ void kmap_atomic_fix_kpte(struct page *page, int finished)
  * When holding an atomic kmap is is not legal to sleep, so atomic
  * kmaps are appropriate for short, tight code paths only.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
        pte_t *pte;
 
        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
@@ -255,8 +211,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic_prot(type);
-
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        pte = kmap_get_pte(vaddr);
@@ -269,25 +224,31 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
 }
 EXPORT_SYMBOL(kmap_atomic_prot);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
        /* PAGE_NONE is a magic value that tells us to check immutability. */
        return kmap_atomic_prot(page, type, PAGE_NONE);
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
-       /*
-        * Force other mappings to Oops if they try to access this pte without
-        * first remapping it.  Keeping stale mappings around is a bad idea.
-        */
-       if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) {
+       if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+           vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
                pte_t *pte = kmap_get_pte(vaddr);
                pte_t pteval = *pte;
+               int idx, type;
+
+               type = kmap_atomic_idx_pop();
+               idx = type + KM_TYPE_NR*smp_processor_id();
+
+               /*
+                * Force other mappings to Oops if they try to access this pte
+                * without first remapping it.  Keeping stale mappings around
+                * is a bad idea.
+                */
                BUG_ON(!pte_present(pteval) && !pte_migrating(pteval));
                kmap_atomic_unregister(pte_page(pteval), vaddr);
                kpte_clear_flush(pte, vaddr);
@@ -300,19 +261,19 @@ void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
        arch_flush_lazy_mmu_mode();
        pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /*
  * This API is supposed to allow us to map memory without a "struct page".
  * Currently we don't support this, though this may change in the future.
  */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-       return kmap_atomic(pfn_to_page(pfn), type);
+       return kmap_atomic(pfn_to_page(pfn));
 }
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
-       return kmap_atomic_prot(pfn_to_page(pfn), type, prot);
+       return kmap_atomic_prot(pfn_to_page(pfn), prot);
 }
 
 struct page *kmap_atomic_to_page(void *ptr)
index fb3b4a55cec4cd24b29bcf4c6220f0f4c33281cb..d78df3a6ee15e0d30cd2207d1f64df88de2ec590 100644 (file)
@@ -37,6 +37,8 @@
 #include <asm/pgalloc.h>
 #include <asm/homecache.h>
 
+#include <arch/sim.h>
+
 #include "migrate.h"
 
 
@@ -217,13 +219,6 @@ static unsigned long cache_flush_length(unsigned long length)
        return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
 }
 
-/* On the simulator, confirm lines have been evicted everywhere. */
-static void validate_lines_evicted(unsigned long pfn, size_t length)
-{
-       sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
-                   (HV_PhysAddr)pfn << PAGE_SHIFT, length);
-}
-
 /* Flush a page out of whatever cache(s) it is in. */
 void homecache_flush_cache(struct page *page, int order)
 {
@@ -234,7 +229,7 @@ void homecache_flush_cache(struct page *page, int order)
 
        homecache_mask(page, pages, &home_mask);
        flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
-       validate_lines_evicted(pfn, pages * PAGE_SIZE);
+       sim_validate_lines_evicted(PFN_PHYS(pfn), pages * PAGE_SIZE);
 }
 
 
index d89c9eacd162c40a93bc37482a4ed55a4f3d681e..78e1982cb6c9dc0385e258b81bfc233f23baaaac 100644 (file)
@@ -1060,7 +1060,7 @@ void free_initmem(void)
 
        /*
         * Free the pages mapped from 0xc0000000 that correspond to code
-        * pages from 0xfd000000 that we won't use again after init.
+        * pages from MEM_SV_INTRPT that we won't use again after init.
         */
        free_init_pages("unused kernel text",
                        (unsigned long)_sinittext - text_delta,
index ec2b8da1aba483acb7e80b20c2c14041c81f4e7c..50d6aa20c3538637ae7d8e939d64717acbf53fd7 100644 (file)
@@ -120,6 +120,9 @@ config SMP
 
          If you don't know what to do, say N.
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       def_bool y
+
 config NR_CPUS
        int "Maximum number of CPUs (2-32)"
        range 2 32
@@ -147,3 +150,6 @@ config KERNEL_STACK_ORDER
          This option determines the size of UML kernel stacks.  They will
          be 1 << order pages.  The default is OK unless you're running Valgrind
          on UML, in which case, set this to 3.
+
+config NO_DMA
+       def_bool y
index 6bd456f96f90f6a345466f20cb0fc64b84a1c082..564f3de65b4ae129675fc82c56feebb635fc9279 100644 (file)
@@ -566,7 +566,6 @@ CONFIG_CRC32=m
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
-CONFIG_HAS_DMA=y
 
 #
 # SCSI device support
diff --git a/arch/um/include/asm/dma-mapping.h b/arch/um/include/asm/dma-mapping.h
deleted file mode 100644 (file)
index 1f469e8..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef _ASM_DMA_MAPPING_H
-#define _ASM_DMA_MAPPING_H
-
-#include <asm/scatterlist.h>
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       BUG();
-       return(0);
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG();
-       return(0);
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flag)
-{
-       BUG();
-       return((void *) 0);
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                 dma_addr_t dma_handle)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-       return(0);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-            unsigned long offset, size_t size,
-            enum dma_data_direction direction)
-{
-       BUG();
-       return(0);
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-          enum dma_data_direction direction)
-{
-       BUG();
-       return(0);
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-           enum dma_data_direction direction)
-{
-       BUG();
-}
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
-{
-       BUG();
-       return 0;
-}
-
-#endif
index a9f7251b4a8dcadd347d7a8d71043e5b312ff673..41474fb5eee70d3f89474ae13c59cbaef10b0f37 100644 (file)
@@ -338,9 +338,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
        ((pte_t *) pmd_page_vaddr(*(dir)) +  pte_index(address))
 #define pte_offset_map(dir, address) \
        ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 struct mm_struct;
 extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
index 93af1cf0907ddafdca68e8884e5dc99a2ed0ea0b..68a90ecd14501aaaeb4a832364c58c89c1697d59 100644 (file)
@@ -8,23 +8,38 @@ extern int set_signals(int enable);
 extern void block_signals(void);
 extern void unblock_signals(void);
 
-#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
-                                    (flags) = get_signals(); } while(0)
-#define 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 local_irq_enable() unblock_signals()
-#define local_irq_disable() block_signals()
-
-#define irqs_disabled()                 \
-({                                      \
-        unsigned long flags;            \
-        local_save_flags(flags);        \
-        (flags == 0);                   \
-})
+static inline unsigned long arch_local_save_flags(void)
+{
+       return get_signals();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       set_signals(flags);
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       unblock_signals();
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       block_signals();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+       flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_local_save_flags() == 0;
+}
 
 extern void *_switch_to(void *prev, void *next, void *last);
 #define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
index 69268014dd8e966860f7faa323b394961b6f6428..a3cab6d3ae020ccbb1701742e3e85c5c8d2af161 100644 (file)
@@ -50,8 +50,18 @@ SECTIONS
   .rela.got       : { *(.rela.got) }
   .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
   .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
-  .rel.plt        : { *(.rel.plt) }
-  .rela.plt       : { *(.rela.plt) }
+  .rel.plt : {
+       *(.rel.plt)
+       PROVIDE_HIDDEN(__rel_iplt_start = .);
+       *(.rel.iplt)
+       PROVIDE_HIDDEN(__rel_iplt_end = .);
+  }
+  .rela.plt : {
+       *(.rela.plt)
+       PROVIDE_HIDDEN(__rela_iplt_start = .);
+       *(.rela.iplt)
+       PROVIDE_HIDDEN(__rela_iplt_end = .);
+  }
   .init           : {
     KEEP (*(.init))
   } =0x90909090
index a746e3037a5bc896462affb2c62ab493a625cc58..3f0ac9e0c96639b1d1a346be1686d3f6374e5479 100644 (file)
@@ -334,7 +334,7 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
        irq_enter();
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
        set_irq_regs(old_regs);
        return 1;
@@ -391,17 +391,10 @@ void __init init_IRQ(void)
 {
        int i;
 
-       irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
-       irq_desc[TIMER_IRQ].action = NULL;
-       irq_desc[TIMER_IRQ].depth = 1;
-       irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
-       enable_irq(TIMER_IRQ);
+       set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
+
        for (i = 1; i < NR_IRQS; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-               irq_desc[i].chip = &normal_irq_type;
-               enable_irq(i);
+               set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
        }
 }
 
index ec63785506714f8059c9c7a31cf44d4875466698..fbd99402d4d26219443f3d46c3b355b3c137790e 100644 (file)
@@ -22,7 +22,7 @@ SECTIONS
   _text = .;
   _stext = .;
   __init_begin = .;
-  INIT_TEXT_SECTION(PAGE_SIZE)
+  INIT_TEXT_SECTION(0)
   . = ALIGN(PAGE_SIZE);
 
   .text      :
@@ -43,6 +43,23 @@ SECTIONS
        __syscall_stub_end = .;
   }
 
+  /*
+   * These are needed even in a static link, even if they wind up being empty.
+   * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols.
+   */
+  .rel.plt : {
+       *(.rel.plt)
+       PROVIDE_HIDDEN(__rel_iplt_start = .);
+       *(.rel.iplt)
+       PROVIDE_HIDDEN(__rel_iplt_end = .);
+  }
+  .rela.plt : {
+       *(.rela.plt)
+       PROVIDE_HIDDEN(__rela_iplt_start = .);
+       *(.rela.iplt)
+       PROVIDE_HIDDEN(__rela_iplt_end = .);
+  }
+
   #include "asm/common.lds.S"
 
   init.data : { INIT_DATA }
index dec5678fc17f7b65ef5b1113d8f6246f910bab79..6e3359d6a8394c0d2f811a28a24f41e673e8793c 100644 (file)
@@ -60,7 +60,7 @@ static inline long long timeval_to_ns(const struct timeval *tv)
 long long disable_timer(void)
 {
        struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
-       int remain, max = UM_NSEC_PER_SEC / UM_HZ;
+       long long remain, max = UM_NSEC_PER_SEC / UM_HZ;
 
        if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
                printk(UM_KERN_ERR "disable_timer - setitimer failed, "
index 8caac76ac324b39c647fc3762b25920b06fe6a08..3bd04022fd0c51acf29cc64c0720df69e08a245f 100644 (file)
@@ -59,11 +59,12 @@ extern void kunmap_high(struct page *page);
 
 void *kmap(struct page *page);
 void kunmap(struct page *page);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()    do { } while (0)
index c4191b3b7056c6ad16563375f529d1480668a26e..363e33eb6ec18c5f1fbe0df10113361daaca6505 100644 (file)
 #include <asm/tlbflush.h>
 
 void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 
 void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type);
+iounmap_atomic(void __iomem *kvaddr);
 
 int
 iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot);
index 101229b0d8ed43f7f85ed30ef7a679d6728ecefc..42a978c0c1b326b96c2a118729c1eafebf1b2cb3 100644 (file)
@@ -89,6 +89,8 @@ extern int olpc_ec_mask_unset(uint8_t bits);
 /* EC commands */
 
 #define EC_FIRMWARE_REV                0x08
+#define EC_WLAN_ENTER_RESET    0x35
+#define EC_WLAN_LEAVE_RESET    0x25
 
 /* SCI source values */
 
index 8abde9ec90bffba165cd28cf250b89519507f22e..0c92113c4cb6d63a82cc48f10b2d0b9343eeb1ee 100644 (file)
@@ -49,24 +49,14 @@ extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
 #endif
 
 #if defined(CONFIG_HIGHPTE)
-#define __KM_PTE                       \
-       (in_nmi() ? KM_NMI_PTE :        \
-        in_irq() ? KM_IRQ_PTE :        \
-        KM_PTE0)
 #define pte_offset_map(dir, address)                                   \
-       ((pte_t *)kmap_atomic(pmd_page(*(dir)), __KM_PTE) +             \
+       ((pte_t *)kmap_atomic(pmd_page(*(dir))) +               \
         pte_index((address)))
-#define pte_offset_map_nested(dir, address)                            \
-       ((pte_t *)kmap_atomic(pmd_page(*(dir)), KM_PTE1) +              \
-        pte_index((address)))
-#define pte_unmap(pte) kunmap_atomic((pte), __KM_PTE)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic((pte))
 #else
 #define pte_offset_map(dir, address)                                   \
        ((pte_t *)page_address(pmd_page(*(dir))) + pte_index((address)))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /* Clear a kernel PTE and flush it from the TLB */
index f96ac9bedf75db0ca247326ab580301832761d82..f86da20347f27b24fcc5fab4dc4712c4b71584c0 100644 (file)
@@ -127,9 +127,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
 
 /* x86-64 always has all page tables mapped. */
 #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
-#define pte_offset_map_nested(dir, address) pte_offset_kernel((dir), (address))
 #define pte_unmap(pte) ((void)(pte))/* NOP */
-#define pte_unmap_nested(pte) ((void)(pte)) /* NOP */
 
 #define update_mmu_cache(vma, address, ptep) do { } while (0)
 
index 7fda040a76cd7cae4e9caa3bbc9cf37661694993..a3c28ae4025b2c9a9422fa492faac821b7f221d3 100644 (file)
@@ -200,6 +200,23 @@ extern struct { char _entry[32]; } hypercall_page[];
        (type)__res;                                                    \
 })
 
+static inline long
+privcmd_call(unsigned call,
+            unsigned long a1, unsigned long a2,
+            unsigned long a3, unsigned long a4,
+            unsigned long a5)
+{
+       __HYPERCALL_DECLS;
+       __HYPERCALL_5ARG(a1, a2, a3, a4, a5);
+
+       asm volatile("call *%[call]"
+                    : __HYPERCALL_5PARAM
+                    : [call] "a" (&hypercall_page[call])
+                    : __HYPERCALL_CLOBBER5);
+
+       return (long)__res;
+}
+
 static inline int
 HYPERVISOR_set_trap_table(struct trap_info *table)
 {
index bf5f7d32bd08d4a6dc253a624fe9111a73327c75..dd8c1414b3d57540d374fee9d923947aaa57ceb1 100644 (file)
@@ -37,14 +37,21 @@ typedef struct xpaddr {
 
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
-extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 
 static inline unsigned long pfn_to_mfn(unsigned long pfn)
 {
+       unsigned long mfn;
+
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return pfn;
 
-       return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
+       mfn = get_phys_to_machine(pfn);
+
+       if (mfn != INVALID_P2M_ENTRY)
+               mfn &= ~FOREIGN_FRAME_BIT;
+
+       return mfn;
 }
 
 static inline int phys_to_machine_mapping_valid(unsigned long pfn)
@@ -159,6 +166,7 @@ static inline pte_t __pte_ma(pteval_t x)
 
 #define pgd_val_ma(x)  ((x).pgd)
 
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid);
 
 xmaddr_t arbitrary_virt_to_machine(void *address);
 unsigned long arbitrary_virt_to_mfn(void *vaddr);
index 74a847835babc534721bed1496d2be129c247e15..69fd72aa5594bec4d34b51ac4dd52b24c5547bec 100644 (file)
@@ -15,7 +15,6 @@
 
 #ifdef CONFIG_X86_32
 #include <asm/pgtable.h>
-#include <asm/pgtable_32.h>
 #endif
 
 #include "realmode/wakeup.h"
index cd8da247dda14c8f638ba1b8df2a7b53aacd1212..a2baafb2fe6d38cddaf3e62dc1a8dd9feb18baf3 100644 (file)
@@ -701,6 +701,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
                per_cpu(acfreq_data, policy->cpu) = NULL;
                acpi_processor_unregister_performance(data->acpi_data,
                                                      policy->cpu);
+               kfree(data->freq_table);
                kfree(data);
        }
 
index 733093d6043698ecba3eca01249b3d301f6008b2..141abebc4516a2070c7607a6135a5c20abe107b8 100644 (file)
@@ -393,7 +393,7 @@ static struct cpufreq_driver nforce2_driver = {
  * Detects nForce2 A2 and C1 stepping
  *
  */
-static unsigned int nforce2_detect_chipset(void)
+static int nforce2_detect_chipset(void)
 {
        nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
                                        PCI_DEVICE_ID_NVIDIA_NFORCE2,
index fc09f142d94d964539e11e55101e5edaaf60eaac..d9f51367666b0c3096829b69fb1db04fb0f34d63 100644 (file)
@@ -35,7 +35,7 @@ static unsigned int longrun_low_freq, longrun_high_freq;
  * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
  * and MSR_TMTA_LONGRUN_CTRL
  */
-static void __init longrun_get_policy(struct cpufreq_policy *policy)
+static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy)
 {
        u32 msr_lo, msr_hi;
 
@@ -165,7 +165,7 @@ static unsigned int longrun_get(unsigned int cpu)
  * TMTA rules:
  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
  */
-static unsigned int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
+static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
                                                      unsigned int *high_freq)
 {
        u32 msr_lo, msr_hi;
index 12cd823c8d038008f8abe77785b4bb475dd3cf20..17ad0336621135a2310f3e9a2e5d9bf3d2f668ba 100644 (file)
@@ -327,6 +327,7 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3)
        l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
 
        l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+       l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
 static struct amd_l3_cache * __cpuinit amd_init_l3_cache(int node)
index fe73c1844a9a5b7c9a0c902bef0b9f993207acee..c1e8c7a5116493568e06ba353dd4150d6c027d9a 100644 (file)
@@ -49,7 +49,6 @@ static unsigned long
 copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
 {
        unsigned long offset, addr = (unsigned long)from;
-       int type = in_nmi() ? KM_NMI : KM_IRQ0;
        unsigned long size, len = 0;
        struct page *page;
        void *map;
@@ -63,9 +62,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
                offset = addr & (PAGE_SIZE - 1);
                size = min(PAGE_SIZE - offset, n - len);
 
-               map = kmap_atomic(page, type);
+               map = kmap_atomic(page);
                memcpy(to, map+offset, size);
-               kunmap_atomic(map, type);
+               kunmap_atomic(map);
                put_page(page);
 
                len  += size;
index 67414550c3ccf25b3d5a3094ba42b5d0f158610d..d5cd13945d5a48a30cc0c61c26824aa2dad38b5b 100644 (file)
@@ -61,7 +61,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
        if (!is_crashed_pfn_valid(pfn))
                return -EFAULT;
 
-       vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
+       vaddr = kmap_atomic_pfn(pfn);
 
        if (!userbuf) {
                memcpy(buf, (vaddr + offset), csize);
index aff0b3c2750929aff9f36ccf946f4a7ae31b1afa..ae03cab4352e8535946a835787c83e5c8563079b 100644 (file)
@@ -713,7 +713,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
 
        switch (action & 0xf) {
        case CPU_ONLINE:
-               INIT_DELAYED_WORK_ON_STACK(&work.work, hpet_work);
+               INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work);
                init_completion(&work.complete);
                /* FIXME: add schedule_work_on() */
                schedule_delayed_work_on(cpu, &work.work, 0);
index 6af118511b4a56fde1ee915162d2013c61e3d7b2..6c7faecd9e4aba5fa26919714a696f215d7d97d3 100644 (file)
@@ -747,7 +747,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
                .done   = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
 
-       INIT_WORK_ON_STACK(&c_idle.work, do_fork_idle);
+       INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
 
        alternatives_smp_switch(1);
 
index 79b0b372d2d033ca35a4bb83295a332c17bbb6c4..7d90ceb882a41ec55f0d8aea7b2c40cd806afd81 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kprobes.h>             /* __kprobes, ...               */
 #include <linux/mmiotrace.h>           /* kmmio_handler, ...           */
 #include <linux/perf_event.h>          /* perf_sw_event                */
+#include <linux/hugetlb.h>             /* hstate_index_to_shift        */
 
 #include <asm/traps.h>                 /* dotraplinkage, ...           */
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
@@ -160,15 +161,20 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
 
 static void
 force_sig_info_fault(int si_signo, int si_code, unsigned long address,
-                    struct task_struct *tsk)
+                    struct task_struct *tsk, int fault)
 {
+       unsigned lsb = 0;
        siginfo_t info;
 
        info.si_signo   = si_signo;
        info.si_errno   = 0;
        info.si_code    = si_code;
        info.si_addr    = (void __user *)address;
-       info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0;
+       if (fault & VM_FAULT_HWPOISON_LARGE)
+               lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); 
+       if (fault & VM_FAULT_HWPOISON)
+               lsb = PAGE_SHIFT;
+       info.si_addr_lsb = lsb;
 
        force_sig_info(si_signo, &info, tsk);
 }
@@ -722,7 +728,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                tsk->thread.error_code  = error_code | (address >= TASK_SIZE);
                tsk->thread.trap_no     = 14;
 
-               force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+               force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
 
                return;
        }
@@ -807,14 +813,14 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
        tsk->thread.trap_no     = 14;
 
 #ifdef CONFIG_MEMORY_FAILURE
-       if (fault & VM_FAULT_HWPOISON) {
+       if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
                printk(KERN_ERR
        "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
                        tsk->comm, tsk->pid, address);
                code = BUS_MCEERR_AR;
        }
 #endif
-       force_sig_info_fault(SIGBUS, code, address, tsk);
+       force_sig_info_fault(SIGBUS, code, address, tsk, fault);
 }
 
 static noinline void
@@ -824,7 +830,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
        if (fault & VM_FAULT_OOM) {
                out_of_memory(regs, error_code, address);
        } else {
-               if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON))
+               if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+                            VM_FAULT_HWPOISON_LARGE))
                        do_sigbus(regs, error_code, address, fault);
                else
                        BUG();
@@ -912,9 +919,9 @@ spurious_fault(unsigned long error_code, unsigned long address)
 int show_unhandled_signals = 1;
 
 static inline int
-access_error(unsigned long error_code, int write, struct vm_area_struct *vma)
+access_error(unsigned long error_code, struct vm_area_struct *vma)
 {
-       if (write) {
+       if (error_code & PF_WRITE) {
                /* write, present and write, not present: */
                if (unlikely(!(vma->vm_flags & VM_WRITE)))
                        return 1;
@@ -949,8 +956,10 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
        struct task_struct *tsk;
        unsigned long address;
        struct mm_struct *mm;
-       int write;
        int fault;
+       int write = error_code & PF_WRITE;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+                                       (write ? FAULT_FLAG_WRITE : 0);
 
        tsk = current;
        mm = tsk->mm;
@@ -1061,6 +1070,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
                        bad_area_nosemaphore(regs, error_code, address);
                        return;
                }
+retry:
                down_read(&mm->mmap_sem);
        } else {
                /*
@@ -1104,9 +1114,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
         * we can handle it..
         */
 good_area:
-       write = error_code & PF_WRITE;
-
-       if (unlikely(access_error(error_code, write, vma))) {
+       if (unlikely(access_error(error_code, vma))) {
                bad_area_access_error(regs, error_code, address);
                return;
        }
@@ -1116,21 +1124,34 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault:
         */
-       fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, address, flags);
 
        if (unlikely(fault & VM_FAULT_ERROR)) {
                mm_fault_error(regs, error_code, address, fault);
                return;
        }
 
-       if (fault & VM_FAULT_MAJOR) {
-               tsk->maj_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
-                                    regs, address);
-       } else {
-               tsk->min_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
-                                    regs, address);
+       /*
+        * Major/minor page fault accounting is only done on the
+        * initial attempt. If we go through a retry, it is extremely
+        * likely that the page will be found in page cache at that point.
+        */
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR) {
+                       tsk->maj_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                     regs, address);
+               } else {
+                       tsk->min_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                     regs, address);
+               }
+               if (fault & VM_FAULT_RETRY) {
+                       /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+                        * of starvation. */
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                       goto retry;
+               }
        }
 
        check_v8086_mode(regs, address, tsk);
index 5e8fa12ef861738aae4e91ec8b165f6d2e58a55b..d723e369003cb3658eb60f4e7eed1a94a6a4afda 100644 (file)
@@ -9,6 +9,7 @@ void *kmap(struct page *page)
                return page_address(page);
        return kmap_high(page);
 }
+EXPORT_SYMBOL(kmap);
 
 void kunmap(struct page *page)
 {
@@ -18,6 +19,7 @@ void kunmap(struct page *page)
                return;
        kunmap_high(page);
 }
+EXPORT_SYMBOL(kunmap);
 
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -27,10 +29,10 @@ void kunmap(struct page *page)
  * However when holding an atomic kmap it is not legal to sleep, so atomic
  * kmaps are appropriate for short, tight code paths only.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
 
        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
        pagefault_disable();
@@ -38,8 +40,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
        if (!PageHighMem(page))
                return page_address(page);
 
-       debug_kmap_atomic(type);
-
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        BUG_ON(!pte_none(*(kmap_pte-idx)));
@@ -47,44 +48,56 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
 
        return (void *)vaddr;
 }
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void *__kmap_atomic(struct page *page)
+{
+       return kmap_atomic_prot(page, kmap_prot);
+}
+EXPORT_SYMBOL(__kmap_atomic);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+/*
+ * This is the same as kmap_atomic() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-       return kmap_atomic_prot(page, type, kmap_prot);
+       return kmap_atomic_prot_pfn(pfn, kmap_prot);
 }
+EXPORT_SYMBOL_GPL(kmap_atomic_pfn);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
-
-       /*
-        * Force other mappings to Oops if they'll try to access this pte
-        * without first remap it.  Keeping stale mappings around is a bad idea
-        * also, in case the page changes cacheability attributes or becomes
-        * a protected page in a hypervisor.
-        */
-       if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+
+       if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+           vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+               int idx, type;
+
+               type = kmap_atomic_idx_pop();
+               idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+               WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+               /*
+                * Force other mappings to Oops if they'll try to access this
+                * pte without first remap it.  Keeping stale mappings around
+                * is a bad idea also, in case the page changes cacheability
+                * attributes or becomes a protected page in a hypervisor.
+                */
                kpte_clear_flush(kmap_pte-idx, vaddr);
-       else {
+       }
 #ifdef CONFIG_DEBUG_HIGHMEM
+       else {
                BUG_ON(vaddr < PAGE_OFFSET);
                BUG_ON(vaddr >= (unsigned long)high_memory);
-#endif
        }
+#endif
 
        pagefault_enable();
 }
-
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
-{
-       return kmap_atomic_prot_pfn(pfn, type, kmap_prot);
-}
-EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
+EXPORT_SYMBOL(__kunmap_atomic);
 
 struct page *kmap_atomic_to_page(void *ptr)
 {
@@ -98,12 +111,6 @@ struct page *kmap_atomic_to_page(void *ptr)
        pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
        return pte_page(*pte);
 }
-
-EXPORT_SYMBOL(kmap);
-EXPORT_SYMBOL(kunmap);
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
-EXPORT_SYMBOL(kmap_atomic_prot);
 EXPORT_SYMBOL(kmap_atomic_to_page);
 
 void __init set_highmem_pages_init(void)
index 72fc70cf6184c756b1157f272b0d5e2b7bcc0609..75a3d7f24a2cc1d635c4820b89a1fd4873698ca9 100644 (file)
@@ -48,21 +48,20 @@ int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot)
 }
 EXPORT_SYMBOL_GPL(iomap_create_wc);
 
-void
-iomap_free(resource_size_t base, unsigned long size)
+void iomap_free(resource_size_t base, unsigned long size)
 {
        io_free_memtype(base, base + size);
 }
 EXPORT_SYMBOL_GPL(iomap_free);
 
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
-       enum fixed_addresses idx;
        unsigned long vaddr;
+       int idx, type;
 
        pagefault_disable();
 
-       debug_kmap_atomic(type);
+       type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR * smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        set_pte(kmap_pte - idx, pfn_pte(pfn, prot));
@@ -72,10 +71,10 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
 }
 
 /*
- * Map 'pfn' using fixed map 'type' and protections 'prot'
+ * Map 'pfn' using protections 'prot'
  */
 void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
        /*
         * For non-PAT systems, promote PAGE_KERNEL_WC to PAGE_KERNEL_UC_MINUS.
@@ -86,24 +85,33 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
        if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC))
                prot = PAGE_KERNEL_UC_MINUS;
 
-       return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, type, prot);
+       return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot);
 }
 EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn);
 
 void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type)
+iounmap_atomic(void __iomem *kvaddr)
 {
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
-       /*
-        * Force other mappings to Oops if they'll try to access this pte
-        * without first remap it.  Keeping stale mappings around is a bad idea
-        * also, in case the page changes cacheability attributes or becomes
-        * a protected page in a hypervisor.
-        */
-       if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+       if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+           vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+               int idx, type;
+
+               type = kmap_atomic_idx_pop();
+               idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+               WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+               /*
+                * Force other mappings to Oops if they'll try to access this
+                * pte without first remap it.  Keeping stale mappings around
+                * is a bad idea also, in case the page changes cacheability
+                * attributes or becomes a protected page in a hypervisor.
+                */
                kpte_clear_flush(kmap_pte-idx, vaddr);
+       }
 
        pagefault_enable();
 }
index 68128a1b401a30a9316b0a9cfa35369c88f9e81a..90a7f5ad6916418e621ce1a7d3422125d0aacd5c 100644 (file)
@@ -19,15 +19,12 @@ config XEN_PVHVM
        depends on X86_LOCAL_APIC
 
 config XEN_MAX_DOMAIN_MEMORY
-       int "Maximum allowed size of a domain in gigabytes"
-       default 8 if X86_32
-       default 32 if X86_64
+       int
+       default 128
        depends on XEN
        help
-         The pseudo-physical to machine address array is sized
-         according to the maximum possible memory size of a Xen
-         domain.  This array uses 1 page per gigabyte, so there's no
-         need to be too stingy here.
+         This only affects the sizing of some bss arrays, the unused
+         portions of which are freed.
 
 config XEN_SAVE_RESTORE
        bool
index 63b83ceebd1a0984403af50aaefe29331d5f3132..44ab12dc2a12ee57a2f966d420e2c4cc46e0b704 100644 (file)
@@ -136,9 +136,6 @@ static void xen_vcpu_setup(int cpu)
        info.mfn = arbitrary_virt_to_mfn(vcpup);
        info.offset = offset_in_page(vcpup);
 
-       printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %llx, offset %d\n",
-              cpu, vcpup, info.mfn, info.offset);
-
        /* Check to see if the hypervisor will put the vcpu_info
           structure where we want it, which allows direct access via
           a percpu-variable. */
@@ -152,9 +149,6 @@ static void xen_vcpu_setup(int cpu)
                /* This cpu is using the registered vcpu info, even if
                   later ones fail to. */
                per_cpu(xen_vcpu, cpu) = vcpup;
-
-               printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
-                      cpu, vcpup);
        }
 }
 
@@ -836,6 +830,11 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
                   Xen console noise. */
                break;
 
+       case MSR_IA32_CR_PAT:
+               if (smp_processor_id() == 0)
+                       xen_set_pat(((u64)high << 32) | low);
+               break;
+
        default:
                ret = native_write_msr_safe(msr, low, high);
        }
@@ -874,8 +873,6 @@ void xen_setup_vcpu_info_placement(void)
        /* xen_vcpu_setup managed to place the vcpu_info within the
           percpu area for all cpus, so make use of it */
        if (have_vcpu_info_placement) {
-               printk(KERN_INFO "Xen: using vcpu_info placement\n");
-
                pv_irq_ops.save_fl = __PV_IS_CALLEE_SAVE(xen_save_fl_direct);
                pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(xen_restore_fl_direct);
                pv_irq_ops.irq_disable = __PV_IS_CALLEE_SAVE(xen_irq_disable_direct);
@@ -1189,6 +1186,9 @@ asmlinkage void __init xen_start_kernel(void)
        xen_raw_console_write("mapping kernel into physical memory\n");
        pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
 
+       /* Allocate and initialize top and mid mfn levels for p2m structure */
+       xen_build_mfn_list_list();
+
        init_mm.pgd = pgd;
 
        /* keep using Xen gdt for now; no urgent need to change it */
index f72d18c692217d67c45e57c16ea8585904097d1f..9631c90907ebd67b5522cac2c224cf445cfe7856 100644 (file)
@@ -57,6 +57,7 @@
 #include <asm/linkage.h>
 #include <asm/page.h>
 #include <asm/init.h>
+#include <asm/pat.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -140,7 +141,8 @@ static inline void check_zero(void)
  * large enough to allocate page table pages to allocate the rest.
  * Each page can map 2MB.
  */
-static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss;
+#define LEVEL1_IDENT_ENTRIES   (PTRS_PER_PTE * 4)
+static RESERVE_BRK_ARRAY(pte_t, level1_ident_pgt, LEVEL1_IDENT_ENTRIES);
 
 #ifdef CONFIG_X86_64
 /* l3 pud for userspace vsyscall mapping */
@@ -171,49 +173,182 @@ DEFINE_PER_CPU(unsigned long, xen_current_cr3);   /* actual vcpu cr3 */
  */
 #define USER_LIMIT     ((STACK_TOP_MAX + PGDIR_SIZE - 1) & PGDIR_MASK)
 
+/*
+ * Xen leaves the responsibility for maintaining p2m mappings to the
+ * guests themselves, but it must also access and update the p2m array
+ * during suspend/resume when all the pages are reallocated.
+ *
+ * The p2m table is logically a flat array, but we implement it as a
+ * three-level tree to allow the address space to be sparse.
+ *
+ *                               Xen
+ *                                |
+ *     p2m_top              p2m_top_mfn
+ *       /  \                   /   \
+ * p2m_mid p2m_mid     p2m_mid_mfn p2m_mid_mfn
+ *    / \      / \         /           /
+ *  p2m p2m p2m p2m p2m p2m p2m ...
+ *
+ * The p2m_mid_mfn pages are mapped by p2m_top_mfn_p.
+ *
+ * The p2m_top and p2m_top_mfn levels are limited to 1 page, so the
+ * maximum representable pseudo-physical address space is:
+ *  P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE pages
+ *
+ * P2M_PER_PAGE depends on the architecture, as a mfn is always
+ * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
+ * 512 and 1024 entries respectively. 
+ */
+
+unsigned long xen_max_p2m_pfn __read_mostly;
 
-#define P2M_ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof(unsigned long))
-#define TOP_ENTRIES            (MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE)
+#define P2M_PER_PAGE           (PAGE_SIZE / sizeof(unsigned long))
+#define P2M_MID_PER_PAGE       (PAGE_SIZE / sizeof(unsigned long *))
+#define P2M_TOP_PER_PAGE       (PAGE_SIZE / sizeof(unsigned long **))
 
-/* Placeholder for holes in the address space */
-static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE] __page_aligned_data =
-               { [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL };
+#define MAX_P2M_PFN            (P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE)
 
- /* Array of pointers to pages containing p2m entries */
-static unsigned long *p2m_top[TOP_ENTRIES] __page_aligned_data =
-               { [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] };
+/* Placeholders for holes in the address space */
+static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_missing_mfn, P2M_MID_PER_PAGE);
 
-/* Arrays of p2m arrays expressed in mfns used for save/restore */
-static unsigned long p2m_top_mfn[TOP_ENTRIES] __page_aligned_bss;
+static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
 
-static unsigned long p2m_top_mfn_list[TOP_ENTRIES / P2M_ENTRIES_PER_PAGE]
-       __page_aligned_bss;
+RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
+RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
-       BUG_ON(pfn >= MAX_DOMAIN_PAGES);
-       return pfn / P2M_ENTRIES_PER_PAGE;
+       BUG_ON(pfn >= MAX_P2M_PFN);
+       return pfn / (P2M_MID_PER_PAGE * P2M_PER_PAGE);
+}
+
+static inline unsigned p2m_mid_index(unsigned long pfn)
+{
+       return (pfn / P2M_PER_PAGE) % P2M_MID_PER_PAGE;
 }
 
 static inline unsigned p2m_index(unsigned long pfn)
 {
-       return pfn % P2M_ENTRIES_PER_PAGE;
+       return pfn % P2M_PER_PAGE;
+}
+
+static void p2m_top_init(unsigned long ***top)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+               top[i] = p2m_mid_missing;
+}
+
+static void p2m_top_mfn_init(unsigned long *top)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+               top[i] = virt_to_mfn(p2m_mid_missing_mfn);
+}
+
+static void p2m_top_mfn_p_init(unsigned long **top)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+               top[i] = p2m_mid_missing_mfn;
+}
+
+static void p2m_mid_init(unsigned long **mid)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_MID_PER_PAGE; i++)
+               mid[i] = p2m_missing;
+}
+
+static void p2m_mid_mfn_init(unsigned long *mid)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_MID_PER_PAGE; i++)
+               mid[i] = virt_to_mfn(p2m_missing);
 }
 
-/* Build the parallel p2m_top_mfn structures */
+static void p2m_init(unsigned long *p2m)
+{
+       unsigned i;
+
+       for (i = 0; i < P2M_MID_PER_PAGE; i++)
+               p2m[i] = INVALID_P2M_ENTRY;
+}
+
+/*
+ * Build the parallel p2m_top_mfn and p2m_mid_mfn structures
+ *
+ * This is called both at boot time, and after resuming from suspend:
+ * - At boot time we're called very early, and must use extend_brk()
+ *   to allocate memory.
+ *
+ * - After resume we're called from within stop_machine, but the mfn
+ *   tree should alreay be completely allocated.
+ */
 void xen_build_mfn_list_list(void)
 {
-       unsigned pfn, idx;
+       unsigned long pfn;
 
-       for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
-               unsigned topidx = p2m_top_index(pfn);
+       /* Pre-initialize p2m_top_mfn to be completely missing */
+       if (p2m_top_mfn == NULL) {
+               p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+               p2m_mid_mfn_init(p2m_mid_missing_mfn);
+
+               p2m_top_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+               p2m_top_mfn_p_init(p2m_top_mfn_p);
 
-               p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
+               p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+               p2m_top_mfn_init(p2m_top_mfn);
+       } else {
+               /* Reinitialise, mfn's all change after migration */
+               p2m_mid_mfn_init(p2m_mid_missing_mfn);
        }
 
-       for (idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
-               unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
-               p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
+       for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) {
+               unsigned topidx = p2m_top_index(pfn);
+               unsigned mididx = p2m_mid_index(pfn);
+               unsigned long **mid;
+               unsigned long *mid_mfn_p;
+
+               mid = p2m_top[topidx];
+               mid_mfn_p = p2m_top_mfn_p[topidx];
+
+               /* Don't bother allocating any mfn mid levels if
+                * they're just missing, just update the stored mfn,
+                * since all could have changed over a migrate.
+                */
+               if (mid == p2m_mid_missing) {
+                       BUG_ON(mididx);
+                       BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
+                       p2m_top_mfn[topidx] = virt_to_mfn(p2m_mid_missing_mfn);
+                       pfn += (P2M_MID_PER_PAGE - 1) * P2M_PER_PAGE;
+                       continue;
+               }
+
+               if (mid_mfn_p == p2m_mid_missing_mfn) {
+                       /*
+                        * XXX boot-time only!  We should never find
+                        * missing parts of the mfn tree after
+                        * runtime.  extend_brk() will BUG if we call
+                        * it too late.
+                        */
+                       mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+                       p2m_mid_mfn_init(mid_mfn_p);
+
+                       p2m_top_mfn_p[topidx] = mid_mfn_p;
+               }
+
+               p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
+               mid_mfn_p[mididx] = virt_to_mfn(mid[mididx]);
        }
 }
 
@@ -222,8 +357,8 @@ void xen_setup_mfn_list_list(void)
        BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
 
        HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
-               virt_to_mfn(p2m_top_mfn_list);
-       HYPERVISOR_shared_info->arch.max_pfn = xen_start_info->nr_pages;
+               virt_to_mfn(p2m_top_mfn);
+       HYPERVISOR_shared_info->arch.max_pfn = xen_max_p2m_pfn;
 }
 
 /* Set up p2m_top to point to the domain-builder provided p2m pages */
@@ -231,98 +366,176 @@ void __init xen_build_dynamic_phys_to_machine(void)
 {
        unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
        unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
-       unsigned pfn;
+       unsigned long pfn;
+
+       xen_max_p2m_pfn = max_pfn;
 
-       for (pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
+       p2m_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+       p2m_init(p2m_missing);
+
+       p2m_mid_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+       p2m_mid_init(p2m_mid_missing);
+
+       p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
+       p2m_top_init(p2m_top);
+
+       /*
+        * The domain builder gives us a pre-constructed p2m array in
+        * mfn_list for all the pages initially given to us, so we just
+        * need to graft that into our tree structure.
+        */
+       for (pfn = 0; pfn < max_pfn; pfn += P2M_PER_PAGE) {
                unsigned topidx = p2m_top_index(pfn);
+               unsigned mididx = p2m_mid_index(pfn);
 
-               p2m_top[topidx] = &mfn_list[pfn];
-       }
+               if (p2m_top[topidx] == p2m_mid_missing) {
+                       unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+                       p2m_mid_init(mid);
+
+                       p2m_top[topidx] = mid;
+               }
 
-       xen_build_mfn_list_list();
+               p2m_top[topidx][mididx] = &mfn_list[pfn];
+       }
 }
 
 unsigned long get_phys_to_machine(unsigned long pfn)
 {
-       unsigned topidx, idx;
+       unsigned topidx, mididx, idx;
 
-       if (unlikely(pfn >= MAX_DOMAIN_PAGES))
+       if (unlikely(pfn >= MAX_P2M_PFN))
                return INVALID_P2M_ENTRY;
 
        topidx = p2m_top_index(pfn);
+       mididx = p2m_mid_index(pfn);
        idx = p2m_index(pfn);
-       return p2m_top[topidx][idx];
+
+       return p2m_top[topidx][mididx][idx];
 }
 EXPORT_SYMBOL_GPL(get_phys_to_machine);
 
-/* install a  new p2m_top page */
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
+static void *alloc_p2m_page(void)
 {
-       unsigned topidx = p2m_top_index(pfn);
-       unsigned long **pfnp, *mfnp;
-       unsigned i;
+       return (void *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
+}
 
-       pfnp = &p2m_top[topidx];
-       mfnp = &p2m_top_mfn[topidx];
+static void free_p2m_page(void *p)
+{
+       free_page((unsigned long)p);
+}
 
-       for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
-               p[i] = INVALID_P2M_ENTRY;
+/* 
+ * Fully allocate the p2m structure for a given pfn.  We need to check
+ * that both the top and mid levels are allocated, and make sure the
+ * parallel mfn tree is kept in sync.  We may race with other cpus, so
+ * the new pages are installed with cmpxchg; if we lose the race then
+ * simply free the page we allocated and use the one that's there.
+ */
+static bool alloc_p2m(unsigned long pfn)
+{
+       unsigned topidx, mididx;
+       unsigned long ***top_p, **mid;
+       unsigned long *top_mfn_p, *mid_mfn;
 
-       if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
-               *mfnp = virt_to_mfn(p);
-               return true;
+       topidx = p2m_top_index(pfn);
+       mididx = p2m_mid_index(pfn);
+
+       top_p = &p2m_top[topidx];
+       mid = *top_p;
+
+       if (mid == p2m_mid_missing) {
+               /* Mid level is missing, allocate a new one */
+               mid = alloc_p2m_page();
+               if (!mid)
+                       return false;
+
+               p2m_mid_init(mid);
+
+               if (cmpxchg(top_p, p2m_mid_missing, mid) != p2m_mid_missing)
+                       free_p2m_page(mid);
        }
 
-       return false;
-}
+       top_mfn_p = &p2m_top_mfn[topidx];
+       mid_mfn = p2m_top_mfn_p[topidx];
 
-static void alloc_p2m(unsigned long pfn)
-{
-       unsigned long *p;
+       BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
+
+       if (mid_mfn == p2m_mid_missing_mfn) {
+               /* Separately check the mid mfn level */
+               unsigned long missing_mfn;
+               unsigned long mid_mfn_mfn;
+
+               mid_mfn = alloc_p2m_page();
+               if (!mid_mfn)
+                       return false;
+
+               p2m_mid_mfn_init(mid_mfn);
+
+               missing_mfn = virt_to_mfn(p2m_mid_missing_mfn);
+               mid_mfn_mfn = virt_to_mfn(mid_mfn);
+               if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn)
+                       free_p2m_page(mid_mfn);
+               else
+                       p2m_top_mfn_p[topidx] = mid_mfn;
+       }
+
+       if (p2m_top[topidx][mididx] == p2m_missing) {
+               /* p2m leaf page is missing */
+               unsigned long *p2m;
+
+               p2m = alloc_p2m_page();
+               if (!p2m)
+                       return false;
 
-       p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
-       BUG_ON(p == NULL);
+               p2m_init(p2m);
+
+               if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
+                       free_p2m_page(p2m);
+               else
+                       mid_mfn[mididx] = virt_to_mfn(p2m);
+       }
 
-       if (!install_p2mtop_page(pfn, p))
-               free_page((unsigned long)p);
+       return true;
 }
 
 /* Try to install p2m mapping; fail if intermediate bits missing */
 bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
-       unsigned topidx, idx;
+       unsigned topidx, mididx, idx;
 
-       if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
+       if (unlikely(pfn >= MAX_P2M_PFN)) {
                BUG_ON(mfn != INVALID_P2M_ENTRY);
                return true;
        }
 
        topidx = p2m_top_index(pfn);
-       if (p2m_top[topidx] == p2m_missing) {
-               if (mfn == INVALID_P2M_ENTRY)
-                       return true;
-               return false;
-       }
-
+       mididx = p2m_mid_index(pfn);
        idx = p2m_index(pfn);
-       p2m_top[topidx][idx] = mfn;
+
+       if (p2m_top[topidx][mididx] == p2m_missing)
+               return mfn == INVALID_P2M_ENTRY;
+
+       p2m_top[topidx][mididx][idx] = mfn;
 
        return true;
 }
 
-void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
        if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
                BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-               return;
+               return true;
        }
 
        if (unlikely(!__set_phys_to_machine(pfn, mfn)))  {
-               alloc_p2m(pfn);
+               if (!alloc_p2m(pfn))
+                       return false;
 
                if (!__set_phys_to_machine(pfn, mfn))
-                       BUG();
+                       return false;
        }
+
+       return true;
 }
 
 unsigned long arbitrary_virt_to_mfn(void *vaddr)
@@ -399,7 +612,7 @@ static bool xen_iomap_pte(pte_t pte)
        return pte_flags(pte) & _PAGE_IOMAP;
 }
 
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 {
        struct multicall_space mcs;
        struct mmu_update *u;
@@ -411,10 +624,16 @@ static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
        u->ptr = arbitrary_virt_to_machine(ptep).maddr;
        u->val = pte_val_ma(pteval);
 
-       MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_IO);
+       MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
+EXPORT_SYMBOL_GPL(xen_set_domain_pte);
+
+static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+{
+       xen_set_domain_pte(ptep, pteval, DOMID_IO);
+}
 
 static void xen_extend_mmu_update(const struct mmu_update *update)
 {
@@ -561,7 +780,20 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
        if (val & _PAGE_PRESENT) {
                unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
                pteval_t flags = val & PTE_FLAGS_MASK;
-               val = ((pteval_t)pfn_to_mfn(pfn) << PAGE_SHIFT) | flags;
+               unsigned long mfn = pfn_to_mfn(pfn);
+
+               /*
+                * If there's no mfn for the pfn, then just create an
+                * empty non-present pte.  Unfortunately this loses
+                * information about the original pfn, so
+                * pte_mfn_to_pfn is asymmetric.
+                */
+               if (unlikely(mfn == INVALID_P2M_ENTRY)) {
+                       mfn = 0;
+                       flags = 0;
+               }
+
+               val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
        }
 
        return val;
@@ -583,10 +815,18 @@ static pteval_t iomap_pte(pteval_t val)
 
 pteval_t xen_pte_val(pte_t pte)
 {
-       if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP))
-               return pte.pte;
+       pteval_t pteval = pte.pte;
+
+       /* If this is a WC pte, convert back from Xen WC to Linux WC */
+       if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
+               WARN_ON(!pat_enabled);
+               pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
+       }
 
-       return pte_mfn_to_pfn(pte.pte);
+       if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
+               return pteval;
+
+       return pte_mfn_to_pfn(pteval);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
 
@@ -596,10 +836,48 @@ pgdval_t xen_pgd_val(pgd_t pgd)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val);
 
+/*
+ * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7
+ * are reserved for now, to correspond to the Intel-reserved PAT
+ * types.
+ *
+ * We expect Linux's PAT set as follows:
+ *
+ * Idx  PTE flags        Linux    Xen    Default
+ * 0                     WB       WB     WB
+ * 1            PWT      WC       WT     WT
+ * 2        PCD          UC-      UC-    UC-
+ * 3        PCD PWT      UC       UC     UC
+ * 4    PAT              WB       WC     WB
+ * 5    PAT     PWT      WC       WP     WT
+ * 6    PAT PCD          UC-      UC     UC-
+ * 7    PAT PCD PWT      UC       UC     UC
+ */
+
+void xen_set_pat(u64 pat)
+{
+       /* We expect Linux to use a PAT setting of
+        * UC UC- WC WB (ignoring the PAT flag) */
+       WARN_ON(pat != 0x0007010600070106ull);
+}
+
 pte_t xen_make_pte(pteval_t pte)
 {
        phys_addr_t addr = (pte & PTE_PFN_MASK);
 
+       /* If Linux is trying to set a WC pte, then map to the Xen WC.
+        * If _PAGE_PAT is set, then it probably means it is really
+        * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
+        * things work out OK...
+        *
+        * (We should never see kernel mappings with _PAGE_PSE set,
+        * but we could see hugetlbfs mappings, I think.).
+        */
+       if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) {
+               if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
+                       pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
+       }
+
        /*
         * Unprivileged domains are allowed to do IOMAPpings for
         * PCI passthrough, but not map ISA space.  The ISA
@@ -1712,6 +1990,9 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
        unsigned ident_pte;
        unsigned long pfn;
 
+       level1_ident_pgt = extend_brk(sizeof(pte_t) * LEVEL1_IDENT_ENTRIES,
+                                     PAGE_SIZE);
+
        ident_pte = 0;
        pfn = 0;
        for (pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) {
@@ -1722,7 +2003,7 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
                        pte_page = m2v(pmd[pmdidx].pmd);
                else {
                        /* Check for free pte pages */
-                       if (ident_pte == ARRAY_SIZE(level1_ident_pgt))
+                       if (ident_pte == LEVEL1_IDENT_ENTRIES)
                                break;
 
                        pte_page = &level1_ident_pgt[ident_pte];
@@ -1837,13 +2118,15 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
        return pgd;
 }
 #else  /* !CONFIG_X86_64 */
-static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss;
+static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD);
 
 __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
                                         unsigned long max_pfn)
 {
        pmd_t *kernel_pmd;
 
+       level2_kernel_pgt = extend_brk(sizeof(pmd_t *) * PTRS_PER_PMD, PAGE_SIZE);
+
        max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
                                  xen_start_info->nr_pt_frames * PAGE_SIZE +
                                  512*1024);
@@ -2269,6 +2552,72 @@ void __init xen_hvm_init_mmu_ops(void)
 }
 #endif
 
+#define REMAP_BATCH_SIZE 16
+
+struct remap_data {
+       unsigned long mfn;
+       pgprot_t prot;
+       struct mmu_update *mmu_update;
+};
+
+static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
+                                unsigned long addr, void *data)
+{
+       struct remap_data *rmd = data;
+       pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
+
+       rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+       rmd->mmu_update->val = pte_val_ma(pte);
+       rmd->mmu_update++;
+
+       return 0;
+}
+
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+                              unsigned long addr,
+                              unsigned long mfn, int nr,
+                              pgprot_t prot, unsigned domid)
+{
+       struct remap_data rmd;
+       struct mmu_update mmu_update[REMAP_BATCH_SIZE];
+       int batch;
+       unsigned long range;
+       int err = 0;
+
+       prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
+
+       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+
+       rmd.mfn = mfn;
+       rmd.prot = prot;
+
+       while (nr) {
+               batch = min(REMAP_BATCH_SIZE, nr);
+               range = (unsigned long)batch << PAGE_SHIFT;
+
+               rmd.mmu_update = mmu_update;
+               err = apply_to_page_range(vma->vm_mm, addr, range,
+                                         remap_area_mfn_pte_fn, &rmd);
+               if (err)
+                       goto out;
+
+               err = -EFAULT;
+               if (HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+                       goto out;
+
+               nr -= batch;
+               addr += range;
+       }
+
+       err = 0;
+out:
+
+       flush_tlb_all();
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
+
 #ifdef CONFIG_XEN_DEBUG_FS
 
 static struct dentry *d_mmu_debug;
index fa938c4aa2f72940e56c439f01d4e14f6aa499ba..537bb9aab777ab00b446d1cec9daded81a3ed71f 100644 (file)
@@ -12,7 +12,6 @@ enum pt_level {
 
 
 bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
index 9729c903404b1633a0eaed2b06bd0cfadabf9aa7..105db2501050483901a3ba9be6b37310b4152481 100644 (file)
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/interface/callback.h>
+#include <xen/interface/memory.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/memory.h>
 #include <xen/features.h>
@@ -34,6 +36,39 @@ extern void xen_sysenter_target(void);
 extern void xen_syscall_target(void);
 extern void xen_syscall32_target(void);
 
+/* Amount of extra memory space we add to the e820 ranges */
+phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+
+/* 
+ * The maximum amount of extra memory compared to the base size.  The
+ * main scaling factor is the size of struct page.  At extreme ratios
+ * of base:extra, all the base memory can be filled with page
+ * structures for the extra memory, leaving no space for anything
+ * else.
+ * 
+ * 10x seems like a reasonable balance between scaling flexibility and
+ * leaving a practically usable system.
+ */
+#define EXTRA_MEM_RATIO                (10)
+
+static __init void xen_add_extra_mem(unsigned long pages)
+{
+       u64 size = (u64)pages * PAGE_SIZE;
+       u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
+
+       if (!pages)
+               return;
+
+       e820_add_region(extra_start, size, E820_RAM);
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+       memblock_x86_reserve_range(extra_start, extra_start + size, "XEN EXTRA");
+
+       xen_extra_mem_size += size;
+
+       xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+}
+
 static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
                                              phys_addr_t end_addr)
 {
@@ -105,16 +140,65 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
 /**
  * machine_specific_memory_setup - Hook for machine specific memory setup.
  **/
-
 char * __init xen_memory_setup(void)
 {
+       static struct e820entry map[E820MAX] __initdata;
+
        unsigned long max_pfn = xen_start_info->nr_pages;
+       unsigned long long mem_end;
+       int rc;
+       struct xen_memory_map memmap;
+       unsigned long extra_pages = 0;
+       unsigned long extra_limit;
+       int i;
+       int op;
 
        max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
+       mem_end = PFN_PHYS(max_pfn);
+
+       memmap.nr_entries = E820MAX;
+       set_xen_guest_handle(memmap.buffer, map);
+
+       op = xen_initial_domain() ?
+               XENMEM_machine_memory_map :
+               XENMEM_memory_map;
+       rc = HYPERVISOR_memory_op(op, &memmap);
+       if (rc == -ENOSYS) {
+               memmap.nr_entries = 1;
+               map[0].addr = 0ULL;
+               map[0].size = mem_end;
+               /* 8MB slack (to balance backend allocations). */
+               map[0].size += 8ULL << 20;
+               map[0].type = E820_RAM;
+               rc = 0;
+       }
+       BUG_ON(rc);
 
        e820.nr_map = 0;
+       xen_extra_mem_start = mem_end;
+       for (i = 0; i < memmap.nr_entries; i++) {
+               unsigned long long end = map[i].addr + map[i].size;
+
+               if (map[i].type == E820_RAM) {
+                       if (map[i].addr < mem_end && end > mem_end) {
+                               /* Truncate region to max_mem. */
+                               u64 delta = end - mem_end;
+
+                               map[i].size -= delta;
+                               extra_pages += PFN_DOWN(delta);
+
+                               end = mem_end;
+                       }
+               }
 
-       e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
+               if (end > xen_extra_mem_start)
+                       xen_extra_mem_start = end;
+
+               /* If region is non-RAM or below mem_end, add what remains */
+               if ((map[i].type != E820_RAM || map[i].addr < mem_end) &&
+                   map[i].size > 0)
+                       e820_add_region(map[i].addr, map[i].size, map[i].type);
+       }
 
        /*
         * Even though this is normal, usable memory under Xen, reserve
@@ -136,7 +220,29 @@ char * __init xen_memory_setup(void)
 
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 
-       xen_return_unused_memory(xen_start_info->nr_pages, &e820);
+       extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
+
+       /*
+        * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
+        * factor the base size.  On non-highmem systems, the base
+        * size is the full initial memory allocation; on highmem it
+        * is limited to the max size of lowmem, so that it doesn't
+        * get completely filled.
+        *
+        * In principle there could be a problem in lowmem systems if
+        * the initial memory is also very large with respect to
+        * lowmem, but we won't try to deal with that here.
+        */
+       extra_limit = min(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
+                         max_pfn + extra_pages);
+
+       if (extra_limit >= max_pfn)
+               extra_pages = extra_limit - max_pfn;
+       else
+               extra_pages = 0;
+
+       if (!xen_initial_domain())
+               xen_add_extra_mem(extra_pages);
 
        return "Xen";
 }
index 7c8ab86163e9142b1c49c6c1ddad13ff203b7a59..64044747348efb3535461a67610621d9067767e3 100644 (file)
@@ -30,6 +30,9 @@ void xen_setup_machphys_mapping(void);
 pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
 void xen_ident_map_ISA(void);
 void xen_reserve_top(void);
+extern unsigned long xen_max_p2m_pfn;
+
+void xen_set_pat(u64);
 
 char * __init xen_memory_setup(void);
 void __init xen_arch_setup(void);
index 76bf35554117d8044de73e9b3e1138e562379c0c..b03c043ce75b1243f18f080bbb06750913853a03 100644 (file)
@@ -324,10 +324,7 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 #define pte_offset_kernel(dir,addr)                                    \
        ((pte_t*) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir,addr)       pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir),(addr))
-
 #define pte_unmap(pte)         do { } while (0)
-#define pte_unmap_nested(pte)  do { } while (0)
 
 
 /*
index 881fe44ec7da3c8356a3fca07f3905cd8befc0f2..f0834e2f57275d8903f65b655645f66a9b2016ee 100644 (file)
@@ -64,15 +64,13 @@ static void drive_stat_acct(struct request *rq, int new_io)
                return;
 
        cpu = part_stat_lock();
+       part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
 
-       if (!new_io) {
-               part = rq->part;
+       if (!new_io)
                part_stat_inc(cpu, part, merges[rw]);
-       } else {
-               part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
+       else {
                part_round_stats(cpu, part);
                part_inc_in_flight(part, rw);
-               rq->part = part;
        }
 
        part_stat_unlock();
@@ -130,7 +128,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
        rq->ref_count = 1;
        rq->start_time = jiffies;
        set_start_time_ns(rq);
-       rq->part = NULL;
 }
 EXPORT_SYMBOL(blk_rq_init);
 
@@ -805,16 +802,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
        rl->starved[is_sync] = 0;
 
        priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
-       if (priv) {
+       if (priv)
                rl->elvpriv++;
 
-               /*
-                * Don't do stats for non-priv requests
-                */
-               if (blk_queue_io_stat(q))
-                       rw_flags |= REQ_IO_STAT;
-       }
-
+       if (blk_queue_io_stat(q))
+               rw_flags |= REQ_IO_STAT;
        spin_unlock_irq(q->queue_lock);
 
        rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);
@@ -1791,7 +1783,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes)
                int cpu;
 
                cpu = part_stat_lock();
-               part = req->part;
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
                part_stat_add(cpu, part, sectors[rw], bytes >> 9);
                part_stat_unlock();
        }
@@ -1811,7 +1803,7 @@ static void blk_account_io_done(struct request *req)
                int cpu;
 
                cpu = part_stat_lock();
-               part = req->part;
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
 
                part_stat_inc(cpu, part, ios[rw]);
                part_stat_add(cpu, part, ticks[rw], duration);
index 0a2fd8a48a38ba7e7a6fa496438330f042047cd1..77b7c26df6b50fea7a38ba0825d91583f1c4031c 100644 (file)
@@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req)
                int cpu;
 
                cpu = part_stat_lock();
-               part = req->part;
+               part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
 
                part_round_stats(cpu, part);
                part_dec_in_flight(part, rq_data_dir(req));
index 1e675e5ade02615ee5eba4293a6f6b07cbf3c9c1..2db8f32838e7336d1a53bbddc8a4c01ec0c3489f 100644 (file)
@@ -116,6 +116,10 @@ void blk_queue_congestion_threshold(struct request_queue *q);
 
 int blk_dev_init(void);
 
+void elv_quiesce_start(struct request_queue *q);
+void elv_quiesce_end(struct request_queue *q);
+
+
 /*
  * Return the threshold (number of used requests) at which the queue is
  * considered to be congested.  It include a little hysteresis to keep the
index a8adf96a4b411bbb73e69ff9738fc6d546733bda..5fa2b44a72ffd22994d2e648b3d247f3f4877c95 100644 (file)
@@ -929,15 +929,8 @@ static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
 {
        struct disk_part_tbl *ptbl =
                container_of(head, struct disk_part_tbl, rcu_head);
-       struct gendisk *disk = ptbl->disk;
-       struct request_queue *q = disk->queue;
-       unsigned long flags;
 
        kfree(ptbl);
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       elv_quiesce_end(q);
-       spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
 /**
@@ -955,17 +948,11 @@ static void disk_replace_part_tbl(struct gendisk *disk,
                                  struct disk_part_tbl *new_ptbl)
 {
        struct disk_part_tbl *old_ptbl = disk->part_tbl;
-       struct request_queue *q = disk->queue;
 
        rcu_assign_pointer(disk->part_tbl, new_ptbl);
 
        if (old_ptbl) {
                rcu_assign_pointer(old_ptbl->last_lookup, NULL);
-
-               spin_lock_irq(q->queue_lock);
-               elv_quiesce_start(q);
-               spin_unlock_irq(q->queue_lock);
-
                call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
        }
 }
@@ -1006,7 +993,6 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
                return -ENOMEM;
 
        new_ptbl->len = target;
-       new_ptbl->disk = disk;
 
        for (i = 0; i < len; i++)
                rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
index 0ec1fb69d4eacc2a310504caa9109186f9e89370..518c22bd9562ee20cb040c63d7f9eb6a62b4d5c0 100644 (file)
@@ -83,8 +83,8 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
 
                memcpy(dest_buf, src_buf, len);
 
-               kunmap_atomic(dest_buf, KM_USER0);
                kunmap_atomic(src_buf, KM_USER1);
+               kunmap_atomic(dest_buf, KM_USER0);
 
                async_tx_sync_epilog(submit);
        }
index 90d26c91f4e9e183b2a41363318344e3d646c20a..7a7219266e3cc343d1a9a63a492a9cd38e876db5 100644 (file)
@@ -89,9 +89,9 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
                memcpy(walk->dst.virt.addr, walk->page, n);
                blkcipher_unmap_dst(walk);
        } else if (!(walk->flags & BLKCIPHER_WALK_PHYS)) {
-               blkcipher_unmap_src(walk);
                if (walk->flags & BLKCIPHER_WALK_DIFF)
                        blkcipher_unmap_dst(walk);
+               blkcipher_unmap_src(walk);
        }
 
        scatterwalk_advance(&walk->in, n);
index a2aea53a75ed9fdf99058f9676429c84104c2f27..14cf9077bb2bcf4f01025518b11b0e87e072e9b5 100644 (file)
@@ -51,7 +51,6 @@ obj-y                         += net/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_FUSION)           += message/
 obj-y                          += firewire/
-obj-y                          += ieee1394/
 obj-$(CONFIG_UIO)              += uio/
 obj-y                          += cdrom/
 obj-y                          += auxdisplay/
@@ -92,6 +91,7 @@ obj-$(CONFIG_EISA)            += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
+obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-$(CONFIG_NEW_LEDS)         += leds/
@@ -104,7 +104,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += sh/
 ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 obj-y                          += clocksource/
 endif
-obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_DCA)              += dca/
 obj-$(CONFIG_HID)              += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
index 88681aca88c581891399e18b056d9a6df94a9e01..3f3489c5ca8c3ade9d27adc657ea4cce27cc86f2 100644 (file)
@@ -9,7 +9,6 @@ menuconfig ACPI
        depends on PCI
        depends on PM
        select PNP
-       select CPU_IDLE
        default y
        help
          Advanced Configuration and Power Interface (ACPI) support for 
@@ -66,7 +65,6 @@ config ACPI_PROCFS
 config ACPI_PROCFS_POWER
        bool "Deprecated power /proc/acpi directories"
        depends on PROC_FS
-       default y
        help
          For backwards compatibility, this option allows
           deprecated power /proc/acpi/ directories to exist, even when
@@ -90,13 +88,6 @@ config ACPI_POWER_METER
          To compile this driver as a module, choose M here:
          the module will be called power-meter.
 
-config ACPI_SYSFS_POWER
-       bool "Future power /sys interface"
-       select POWER_SUPPLY
-       default y
-       help
-         Say N to disable power /sys interface
-
 config ACPI_EC_DEBUGFS
        tristate "EC read/write access through /sys/kernel/debug/ec"
        default n
@@ -136,6 +127,7 @@ config ACPI_PROC_EVENT
 config ACPI_AC
        tristate "AC Adapter"
        depends on X86
+       select POWER_SUPPLY
        default y
        help
          This driver supports the AC Adapter object, which indicates
@@ -148,6 +140,7 @@ config ACPI_AC
 config ACPI_BATTERY
        tristate "Battery"
        depends on X86
+       select POWER_SUPPLY
        default y
        help
          This driver adds support for battery information through
@@ -206,6 +199,7 @@ config ACPI_DOCK
 config ACPI_PROCESSOR
        tristate "Processor"
        select THERMAL
+       select CPU_IDLE
        default y
        help
          This driver installs ACPI as the idle handler for Linux and uses
@@ -364,6 +358,7 @@ config ACPI_HOTPLUG_MEMORY
 config ACPI_SBS
        tristate "Smart Battery System"
        depends on X86
+       select POWER_SUPPLY
        help
          This driver supports the Smart Battery System, another
          type of access to battery information, found on some laptops.
index 56205a0b85dfc60eb3dc85def0a7432639ea0142..ba9afeaa23acfb676021c86432fd89b45f8ba5cf 100644 (file)
@@ -32,9 +32,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -86,9 +84,7 @@ static struct acpi_driver acpi_ac_driver = {
 };
 
 struct acpi_ac {
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply charger;
-#endif
        struct acpi_device * device;
        unsigned long long state;
 };
@@ -104,7 +100,6 @@ static const struct file_operations acpi_ac_fops = {
        .release = single_release,
 };
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int get_ac_property(struct power_supply *psy,
                           enum power_supply_property psp,
                           union power_supply_propval *val)
@@ -123,7 +118,6 @@ static int get_ac_property(struct power_supply *psy,
 static enum power_supply_property ac_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
 };
-#endif
 /* --------------------------------------------------------------------------
                                AC Adapter Management
    -------------------------------------------------------------------------- */
@@ -247,9 +241,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
                                                  dev_name(&device->dev), event,
                                                  (u32) ac->state);
                acpi_notifier_call_chain(device, event, (u32) ac->state);
-#ifdef CONFIG_ACPI_SYSFS_POWER
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
        }
 
        return;
@@ -282,14 +274,12 @@ static int acpi_ac_add(struct acpi_device *device)
 #endif
        if (result)
                goto end;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        ac->charger.name = acpi_device_bid(device);
        ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
        ac->charger.properties = ac_props;
        ac->charger.num_properties = ARRAY_SIZE(ac_props);
        ac->charger.get_property = get_ac_property;
        power_supply_register(&ac->device->dev, &ac->charger);
-#endif
 
        printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
               acpi_device_name(device), acpi_device_bid(device),
@@ -316,10 +306,8 @@ static int acpi_ac_resume(struct acpi_device *device)
        old_state = ac->state;
        if (acpi_ac_get_state(ac))
                return 0;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (old_state != ac->state)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
        return 0;
 }
 
@@ -333,10 +321,8 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
 
        ac = acpi_driver_data(device);
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (ac->charger.dev)
                power_supply_unregister(&ac->charger);
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_ac_remove_fs(device);
 #endif
index d93cc06f4bf81a356ceb33f6a279796d9464f7e6..a7e1d1aa4107c29d454e774ce912e60b7ace4ce5 100644 (file)
@@ -21,7 +21,7 @@ acpi-y += exconfig.o  exfield.o  exnames.o   exoparg6.o  exresolv.o  exstorob.o\
         excreate.o  exmisc.o   exoparg2.o  exregion.o  exstore.o   exutils.o \
         exdump.o    exmutex.o  exoparg3.o  exresnte.o  exstoren.o  exdebug.o
 
-acpi-y += hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o hwxface.o hwvalid.o
+acpi-y += hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o hwxface.o hwvalid.o hwpci.o
 
 acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
@@ -44,4 +44,5 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
 
 acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
                utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
-               utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o
+               utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \
+               utosi.o utxferror.o
index 48faf3eba9fb60cf0806d2516a69d1150b6883f0..72e9d5eb083cf09c3b9d0c55850f9c362b175fa0 100644 (file)
@@ -105,6 +105,8 @@ void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg);
 acpi_status
 acpi_db_display_objects(char *obj_type_arg, char *display_count_arg);
 
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg);
+
 acpi_status acpi_db_find_name_in_namespace(char *name_arg);
 
 void acpi_db_set_scope(char *name);
index 36867cd70eacf3f9495325c71200bc688d705510..a6f99cc37a19947ece8c6ebb322687320e6d2853 100644 (file)
@@ -105,8 +105,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
                         struct acpi_gpe_block_info **return_gpe_block);
 
 acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
-                            struct acpi_gpe_block_info *gpe_block);
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+                            struct acpi_gpe_block_info *gpe_block,
+                            void *ignored);
 
 acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
 
index 1d192142c69114ea65ecec63c98209190aa2eb83..ad88fcae4eb9859be0c4ecf8d2780ab42dbf621e 100644 (file)
@@ -132,6 +132,7 @@ struct acpi_table_fadt acpi_gbl_FADT;
 u32 acpi_current_gpe_count;
 u32 acpi_gbl_trace_flags;
 acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
 
 #endif
 
@@ -187,6 +188,10 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
 ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
 
+/* Mutex for _OSI support */
+
+ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+
 /* Reader/Writer lock is used for namespace walk and dynamic table unload */
 
 ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
@@ -255,6 +260,7 @@ ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
 ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
 ACPI_EXTERN void *acpi_gbl_table_handler_context;
 ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
 
 /* Owner ID support */
 
@@ -273,8 +279,8 @@ ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
 ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
 ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
 ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
 ACPI_EXTERN u8 acpi_gbl_osi_data;
+ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
 
 #ifndef DEFINE_ACPI_GLOBALS
 
@@ -364,6 +370,7 @@ ACPI_EXTERN struct acpi_fixed_event_handler
 ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
 ACPI_EXTERN struct acpi_gpe_block_info
 *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+ACPI_EXTERN u8 acpi_all_gpes_initialized;
 
 /*****************************************************************************
  *
index 120b3af565968cf0b68d2af967cd20ff90c1ca40..167470ad2d21756874592a51617a499f10e84907 100644 (file)
@@ -121,6 +121,13 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                                 struct acpi_gpe_block_info *gpe_block,
                                 void *context);
 
+/*
+ * hwpci - PCI configuration support
+ */
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+                     acpi_handle root_pci_device, acpi_handle pci_region);
+
 #ifdef ACPI_FUTURE_USAGE
 /*
  * hwtimer - ACPI Timer prototypes
index 7dad9160f20998112cc302d0a239c9fa27fcd429..2ceb0c05b2d7d158a8f5489ac21fe445f4a9980f 100644 (file)
@@ -413,6 +413,7 @@ struct acpi_handler_info {
        void *context;          /* Context to be passed to handler */
        struct acpi_namespace_node *method_node;        /* Method node for this GPE level (saved) */
        u8 orig_flags;          /* Original misc info about this GPE */
+       u8 orig_enabled;        /* Set if the GPE was originally enabled */
 };
 
 union acpi_gpe_dispatch_info {
@@ -457,6 +458,7 @@ struct acpi_gpe_block_info {
        u32 register_count;     /* Number of register pairs in block */
        u16 gpe_count;          /* Number of individual GPEs in block */
        u8 block_base_number;   /* Base GPE number for this block */
+       u8 initialized;         /* If set, the GPE block has been initialized */
 };
 
 /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
@@ -473,7 +475,6 @@ struct acpi_gpe_walk_info {
        struct acpi_gpe_block_info *gpe_block;
        u16 count;
        acpi_owner_id owner_id;
-       u8 enable_this_gpe;
        u8 execute_by_owner_id;
 };
 
@@ -854,7 +855,7 @@ struct acpi_bit_register_info {
        ACPI_BITMASK_POWER_BUTTON_STATUS   | \
        ACPI_BITMASK_SLEEP_BUTTON_STATUS   | \
        ACPI_BITMASK_RT_CLOCK_STATUS       | \
-       ACPI_BITMASK_PCIEXP_WAKE_DISABLE   | \
+       ACPI_BITMASK_PCIEXP_WAKE_STATUS    | \
        ACPI_BITMASK_WAKE_STATUS)
 
 #define ACPI_BITMASK_TIMER_ENABLE               0x0001
@@ -909,15 +910,21 @@ struct acpi_bit_register_info {
 #define ACPI_OSI_WIN_VISTA              0x07
 #define ACPI_OSI_WINSRV_2008            0x08
 #define ACPI_OSI_WIN_VISTA_SP1          0x09
-#define ACPI_OSI_WIN_7                  0x0A
+#define ACPI_OSI_WIN_VISTA_SP2          0x0A
+#define ACPI_OSI_WIN_7                  0x0B
 
 #define ACPI_ALWAYS_ILLEGAL             0x00
 
 struct acpi_interface_info {
        char *name;
+       struct acpi_interface_info *next;
+       u8 flags;
        u8 value;
 };
 
+#define ACPI_OSI_INVALID                0x01
+#define ACPI_OSI_DYNAMIC                0x02
+
 struct acpi_port_info {
        char *name;
        u16 start;
@@ -997,7 +1004,7 @@ struct acpi_port_info {
 struct acpi_db_method_info {
        acpi_handle main_thread_gate;
        acpi_handle thread_complete_gate;
-       u32 *threads;
+       acpi_thread_id *threads;
        u32 num_threads;
        u32 num_created;
        u32 num_completed;
index 9894929a2abbc8320f31133f3f68a5f516cc3721..8d5c9e0a495f8ab231101e051f824f52e7d5480a 100644 (file)
  * the plist contains a set of parens to allow variable-length lists.
  * These macros are used for both the debug and non-debug versions of the code.
  */
-#define ACPI_ERROR_NAMESPACE(s, e)      acpi_ns_report_error (AE_INFO, s, e);
-#define ACPI_ERROR_METHOD(s, n, p, e)   acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+#define ACPI_ERROR_NAMESPACE(s, e)      acpi_ut_namespace_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e)   acpi_ut_method_error (AE_INFO, s, n, p, e);
 #define ACPI_WARN_PREDEFINED(plist)     acpi_ut_predefined_warning plist
 #define ACPI_INFO_PREDEFINED(plist)     acpi_ut_predefined_info plist
 
index 9f60ff002203b91907ed0fa2b30dc3634ec0bb66..d44d3bc5b847363959fcf64e8d1751916d001c83 100644 (file)
@@ -338,18 +338,6 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
 
 u32 acpi_ns_local(acpi_object_type type);
 
-void
-acpi_ns_report_error(const char *module_name,
-                    u32 line_number,
-                    const char *internal_name, acpi_status lookup_status);
-
-void
-acpi_ns_report_method_error(const char *module_name,
-                           u32 line_number,
-                           const char *message,
-                           struct acpi_namespace_node *node,
-                           const char *path, acpi_status lookup_status);
-
 void
 acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg);
 
index 54857fa87aafa3d5c157a7dff812df0d77108c4c..bdbfaf22bd14e0492cd07c9c35eb6f781a9fd54b 100644 (file)
@@ -248,7 +248,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
        u32                             base_byte_offset;   /* Byte offset within containing object */\
        u32                             value;              /* Value to store into the Bank or Index register */\
        u8                              start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
-       u8                              access_bit_width;       /* Read/Write size in bits (8-64) */
+
 
 struct acpi_object_field_common {      /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
        ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */
index 35df755251ce0522907b4dd619f065e073c236e3..72e4183c193777add40ddff637eaa87806330296 100644 (file)
@@ -312,8 +312,6 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list);
 /*
  * uteval - object evaluation
  */
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
-
 acpi_status
 acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
                        char *path,
@@ -394,6 +392,21 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size);
 acpi_status
 acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
 
+/*
+ * utosi - Support for the _OSI predefined control method
+ */
+acpi_status acpi_ut_initialize_interfaces(void);
+
+void acpi_ut_interface_terminate(void);
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name);
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
+
 /*
  * utstate - Generic state creation/cache routines
  */
@@ -473,17 +486,6 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position);
 
 acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer);
 
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
-                          u32 line_number,
-                          char *pathname,
-                          u8 node_flags, const char *format, ...);
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
-                       u32 line_number,
-                       char *pathname, u8 node_flags, const char *format, ...);
-
 /* Values for Base above (16=Hex, 10=Decimal) */
 
 #define ACPI_ANY_BASE        0
@@ -574,6 +576,32 @@ acpi_status
 acpi_ut_create_list(char *list_name,
                    u16 object_size, struct acpi_memory_list **return_cache);
 
-#endif
+#endif                         /* ACPI_DBG_TRACK_ALLOCATIONS */
+
+/*
+ * utxferror - various error/warning output functions
+ */
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+                          u32 line_number,
+                          char *pathname,
+                          u8 node_flags, const char *format, ...);
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+                       u32 line_number,
+                       char *pathname, u8 node_flags, const char *format, ...);
+
+void
+acpi_ut_namespace_error(const char *module_name,
+                       u32 line_number,
+                       const char *internal_name, acpi_status lookup_status);
+
+void
+acpi_ut_method_error(const char *module_name,
+                    u32 line_number,
+                    const char *message,
+                    struct acpi_namespace_node *node,
+                    const char *path, acpi_status lookup_status);
 
 #endif                         /* _ACUTILS_H */
index 64750ee96e2012047742d2e5e20acb89110c6bbb..d94dd8974b55c5fb03845a52f64ec430c70a6ec1 100644 (file)
@@ -573,7 +573,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
 
                                acpi_os_release_mutex(method_desc->method.
                                                      mutex->mutex.os_mutex);
-                               method_desc->method.mutex->mutex.thread_id = NULL;
+                               method_desc->method.mutex->mutex.thread_id = 0;
                        }
                }
 
index d555b374e314a881b463083c890563a658257f4d..6b0b5d08d97acf12d35016c96ce0eaaaa0126627 100644 (file)
@@ -300,10 +300,25 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
                         * we must enter this object into the namespace.  The created
                         * object is temporary and will be deleted upon completion of
                         * the execution of this method.
+                        *
+                        * Note 10/2010: Except for the Scope() op. This opcode does
+                        * not actually create a new object, it refers to an existing
+                        * object. However, for Scope(), we want to indeed open a
+                        * new scope.
                         */
-                       status = acpi_ds_load2_begin_op(walk_state, NULL);
+                       if (op->common.aml_opcode != AML_SCOPE_OP) {
+                               status =
+                                   acpi_ds_load2_begin_op(walk_state, NULL);
+                       } else {
+                               status =
+                                   acpi_ds_scope_stack_push(op->named.node,
+                                                            op->named.node->
+                                                            type, walk_state);
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
                }
-
                break;
 
        case AML_CLASS_EXECUTE:
index 303618889da0a73a65a5d8ff8c79600cc90e6254..c61c3039c31ac3b951203640c555bb807f81c4b0 100644 (file)
@@ -93,47 +93,6 @@ acpi_status acpi_ev_initialize_events(void)
        return_ACPI_STATUS(status);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_install_fadt_gpes
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
- *              (0 and 1). The HW must be fully initialized at this point,
- *              including global lock support.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_install_fadt_gpes(void)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
-
-       /* Namespace must be locked */
-
-       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
-
-       /* FADT GPE Block 0 */
-
-       (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
-                                          acpi_gbl_gpe_fadt_blocks[0]);
-
-       /* FADT GPE Block 1 */
-
-       (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
-                                          acpi_gbl_gpe_fadt_blocks[1]);
-
-       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-       return_ACPI_STATUS(AE_OK);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_install_xrupt_handlers
index 85445fb5844e503fe1a7f9282afafd3bb7cd4740..020add3eee1c65bfa5d7e03b3d1fee5a074558c2 100644 (file)
@@ -363,6 +363,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
        gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
        gpe_block->register_count = register_count;
        gpe_block->block_base_number = gpe_block_base_number;
+       gpe_block->initialized = FALSE;
 
        ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
                    sizeof(struct acpi_generic_address));
@@ -385,11 +386,12 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
                return_ACPI_STATUS(status);
        }
 
+       acpi_all_gpes_initialized = FALSE;
+
        /* Find all GPE methods (_Lxx or_Exx) for this block */
 
        walk_info.gpe_block = gpe_block;
        walk_info.gpe_device = gpe_device;
-       walk_info.enable_this_gpe = FALSE;
        walk_info.execute_by_owner_id = FALSE;
 
        status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
@@ -434,35 +436,34 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
  ******************************************************************************/
 
 acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
-                            struct acpi_gpe_block_info *gpe_block)
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+                            struct acpi_gpe_block_info *gpe_block,
+                            void *ignored)
 {
        acpi_status status;
        struct acpi_gpe_event_info *gpe_event_info;
        u32 gpe_enabled_count;
        u32 gpe_index;
-       u32 gpe_number;
        u32 i;
        u32 j;
 
        ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
 
-       /* Ignore a null GPE block (e.g., if no GPE block 1 exists) */
-
-       if (!gpe_block) {
+       /*
+        * Ignore a null GPE block (e.g., if no GPE block 1 exists) and
+        * GPE blocks that have been initialized already.
+        */
+       if (!gpe_block || gpe_block->initialized) {
                return_ACPI_STATUS(AE_OK);
        }
 
        /*
-        * Enable all GPEs that have a corresponding method.  Any other GPEs
-        * within this block must be enabled via the acpi_enable_gpe interface.
+        * Enable all GPEs that have a corresponding method and have the
+        * ACPI_GPE_CAN_WAKE flag unset.  Any other GPEs within this block must
+        * be enabled via the acpi_enable_gpe() interface.
         */
        gpe_enabled_count = 0;
 
-       if (gpe_device == acpi_gbl_fadt_gpe_device) {
-               gpe_device = NULL;
-       }
-
        for (i = 0; i < gpe_block->register_count; i++) {
                for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 
@@ -470,27 +471,19 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
 
                        gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
                        gpe_event_info = &gpe_block->event_info[gpe_index];
-                       gpe_number = gpe_index + gpe_block->block_base_number;
 
                        /* Ignore GPEs that have no corresponding _Lxx/_Exx method */
 
-                       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) {
+                       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+                           || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
                                continue;
                        }
 
-                       /*
-                        * If the GPE has already been enabled for runtime
-                        * signaling, make sure it remains enabled, but do not
-                        * increment its reference counter.
-                        */
-                       status = gpe_event_info->runtime_count ?
-                               acpi_ev_enable_gpe(gpe_event_info) :
-                               acpi_enable_gpe(gpe_device, gpe_number);
-
+                       status = acpi_raw_enable_gpe(gpe_event_info);
                        if (ACPI_FAILURE(status)) {
                                ACPI_EXCEPTION((AE_INFO, status,
-                                               "Could not enable GPE 0x%02X",
-                                               gpe_number));
+                                       "Could not enable GPE 0x%02X",
+                                       gpe_index + gpe_block->block_base_number));
                                continue;
                        }
 
@@ -504,5 +497,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
                                  gpe_enabled_count));
        }
 
+       gpe_block->initialized = TRUE;
+
        return_ACPI_STATUS(AE_OK);
 }
index 3084c5de1bba1b2a22c8ca2324a885ad6838b058..2c7def95f721c6d08596c9ce852a3ac4a1c54e38 100644 (file)
@@ -210,8 +210,7 @@ acpi_status acpi_ev_gpe_initialize(void)
  *
  * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
  *              result of a Load() or load_table() operation. If new GPE
- *              methods have been installed, register the new methods and
- *              enable and runtime GPEs that are associated with them.
+ *              methods have been installed, register the new methods.
  *
  ******************************************************************************/
 
@@ -239,7 +238,6 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
        walk_info.owner_id = table_owner_id;
        walk_info.execute_by_owner_id = TRUE;
        walk_info.count = 0;
-       walk_info.enable_this_gpe = TRUE;
 
        /* Walk the interrupt level descriptor list */
 
@@ -301,8 +299,6 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
  *
  * If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
  *    with that owner.
- * If walk_info->enable_this_gpe is TRUE, the GPE that is referred to by a GPE
- *    method is immediately enabled (Used for Load/load_table operators)
  *
  ******************************************************************************/
 
@@ -315,8 +311,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
        struct acpi_gpe_walk_info *walk_info =
            ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
        struct acpi_gpe_event_info *gpe_event_info;
-       struct acpi_namespace_node *gpe_device;
-       acpi_status status;
        u32 gpe_number;
        char name[ACPI_NAME_SIZE + 1];
        u8 type;
@@ -421,29 +415,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
        gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
        gpe_event_info->dispatch.method_node = method_node;
 
-       /*
-        * Enable this GPE if requested. This only happens when during the
-        * execution of a Load or load_table operator. We have found a new
-        * GPE method and want to immediately enable the GPE if it is a
-        * runtime GPE.
-        */
-       if (walk_info->enable_this_gpe) {
-
-               walk_info->count++;
-               gpe_device = walk_info->gpe_device;
-
-               if (gpe_device == acpi_gbl_fadt_gpe_device) {
-                       gpe_device = NULL;
-               }
-
-               status = acpi_enable_gpe(gpe_device, gpe_number);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_EXCEPTION((AE_INFO, status,
-                                       "Could not enable GPE 0x%02X",
-                                       gpe_number));
-               }
-       }
-
        ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
                          "Registered GPE method %s as GPE number 0x%.2X\n",
                          name, gpe_number));
index df0aea9a8cfdce1c861dd2baa2e77b94e9660e3a..fcaed9fb44ff1957dee8864d3d4feba13ec3f8ba 100644 (file)
@@ -553,7 +553,7 @@ acpi_status acpi_ev_release_global_lock(void)
        acpi_gbl_global_lock_acquired = FALSE;
 
        /* Release the local GL mutex */
-       acpi_ev_global_lock_thread_id = NULL;
+       acpi_ev_global_lock_thread_id = 0;
        acpi_ev_global_lock_acquired = 0;
        acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
        return_ACPI_STATUS(status);
index f40d271bf5688fa6401f542d21c42228fa6268ea..0b47a6dc92902f5333d3fc668597992a2bee24a1 100644 (file)
@@ -289,8 +289,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
        }
 
        /*
-        * Get the PCI device and function numbers from the _ADR object contained
-        * in the parent's scope.
+        * Get the PCI device and function numbers from the _ADR object
+        * contained in the parent's scope.
         */
        status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
                                                 pci_device_node, &pci_value);
@@ -320,9 +320,15 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
                pci_id->bus = ACPI_LOWORD(pci_value);
        }
 
-       /* Complete this device's pci_id */
+       /* Complete/update the PCI ID for this device */
 
-       acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id);
+       status =
+           acpi_hw_derive_pci_id(pci_id, pci_root_node,
+                                 region_obj->region.node);
+       if (ACPI_FAILURE(status)) {
+               ACPI_FREE(pci_id);
+               return_ACPI_STATUS(status);
+       }
 
        *region_context = pci_id;
        return_ACPI_STATUS(AE_OK);
index 14e48add32fa0ede706a120b87d3a885e8ecbf0f..36af222cac654d3e2de0cb9c4ed7dc45fb4a0a49 100644 (file)
@@ -726,15 +726,16 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
                        (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 
        /*
-        * If the GPE is associated with a method and it cannot wake up the
-        * system from sleep states, it was enabled automatically during
-        * initialization, so it has to be disabled now to avoid spurious
-        * execution of the handler.
+        * If the GPE is associated with a method, it might have been enabled
+        * automatically during initialization, in which case it has to be
+        * disabled now to avoid spurious execution of the handler.
         */
 
        if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
-           && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+           && gpe_event_info->runtime_count) {
+               handler->orig_enabled = 1;
                (void)acpi_raw_disable_gpe(gpe_event_info);
+       }
 
        /* Install the handler */
 
@@ -837,13 +838,13 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
        gpe_event_info->flags |= handler->orig_flags;
 
        /*
-        * If the GPE was previously associated with a method and it cannot wake
-        * up the system from sleep states, it should be enabled at this point
-        * to restore the post-initialization configuration.
+        * If the GPE was previously associated with a method and it was
+        * enabled, it should be enabled at this point to restore the
+        * post-initialization configuration.
         */
 
        if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
-           && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+           && handler->orig_enabled)
                (void)acpi_raw_enable_gpe(gpe_event_info);
 
        /* Now we can free the handler object */
index 304825528d4803d22e025b9fb6d2220b10851d0b..a1dabe3fd8ae771c7f8e676d907e4ad4cfba4ba3 100644 (file)
@@ -379,21 +379,12 @@ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
        /* Ensure that we have a valid GPE number */
 
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (!gpe_event_info) {
+       if (gpe_event_info) {
+               gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       } else {
                status = AE_BAD_PARAMETER;
-               goto unlock_and_exit;
-       }
-
-       if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
-               goto unlock_and_exit;
        }
 
-       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
-       if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
-               (void)acpi_raw_disable_gpe(gpe_event_info);
-       }
-
-unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
@@ -651,7 +642,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
                       struct acpi_generic_address *gpe_block_address,
                       u32 register_count, u32 interrupt_number)
 {
-       acpi_status status;
+       acpi_status status = AE_OK;
        union acpi_operand_object *obj_desc;
        struct acpi_namespace_node *node;
        struct acpi_gpe_block_info *gpe_block;
@@ -715,10 +706,6 @@ acpi_install_gpe_block(acpi_handle gpe_device,
 
        obj_desc->device.gpe_block = gpe_block;
 
-       /* Enable the runtime GPEs in the new block */
-
-       status = acpi_ev_initialize_gpe_block(node, gpe_block);
-
       unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
@@ -924,3 +911,43 @@ acpi_status acpi_enable_all_runtime_gpes(void)
 
        return_ACPI_STATUS(status);
 }
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_update_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and
+ *              are not pointed to by any device _PRW methods indicating that
+ *              these GPEs are generally intended for system or device wakeup
+ *              (such GPEs have to be enabled directly when the devices whose
+ *              _PRW methods point to them are set up for wakeup signaling).
+ *
+ ******************************************************************************/
+
+acpi_status acpi_update_gpes(void)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(acpi_update_gpes);
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       } else if (acpi_all_gpes_initialized) {
+               goto unlock;
+       }
+
+       status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+       if (ACPI_SUCCESS(status)) {
+               acpi_all_gpes_initialized = TRUE;
+       }
+
+unlock:
+       (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+       return_ACPI_STATUS(status);
+}
index 541cbc1544d5d92a5afe113ddb083bc7481b1534..ce9314f79451ecf5a42e02486475a9bfeca54987 100644 (file)
@@ -64,6 +64,12 @@ ACPI_MODULE_NAME("evxfregn")
  *
  * DESCRIPTION: Install a handler for all op_regions of a given space_id.
  *
+ * NOTE: This function should only be called after acpi_enable_subsystem has
+ * been called. This is because any _REG methods associated with the Space ID
+ * are executed here, and these methods can only be safely executed after
+ * the default handlers have been installed and the hardware has been
+ * initialized (via acpi_enable_subsystem.)
+ *
  ******************************************************************************/
 acpi_status
 acpi_install_address_space_handler(acpi_handle device,
index 047217303a4b748bf091a9a88454f37fc86e9400..38293fd3e088bd008fd5f9855ff72b15766bdb35 100644 (file)
@@ -119,8 +119,8 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
        }
 
        /*
-        * Exit now for SMBus or IPMI address space, it has a non-linear address space
-        * and the request cannot be directly validated
+        * Exit now for SMBus or IPMI address space, it has a non-linear
+        * address space and the request cannot be directly validated
         */
        if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
            rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
@@ -147,8 +147,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
         * (Region length is specified in bytes)
         */
        if (rgn_desc->region.length <
-           (obj_desc->common_field.base_byte_offset +
-            field_datum_byte_offset +
+           (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
             obj_desc->common_field.access_byte_width)) {
                if (acpi_gbl_enable_interpreter_slack) {
                        /*
@@ -680,6 +679,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
        u32 buffer_tail_bits;
        u32 datum_count;
        u32 field_datum_count;
+       u32 access_bit_width;
        u32 i;
 
        ACPI_FUNCTION_TRACE(ex_extract_from_field);
@@ -694,16 +694,36 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
 
                return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
        }
+
        ACPI_MEMSET(buffer, 0, buffer_length);
+       access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
+       /* Handle the simple case here */
+
+       if ((obj_desc->common_field.start_field_bit_offset == 0) &&
+           (obj_desc->common_field.bit_length == access_bit_width)) {
+               status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ);
+               return_ACPI_STATUS(status);
+       }
+
+/* TBD: Move to common setup code */
+
+       /* Field algorithm is limited to sizeof(u64), truncate if needed */
+
+       if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+               obj_desc->common_field.access_byte_width = sizeof(u64);
+               access_bit_width = sizeof(u64) * 8;
+       }
 
        /* Compute the number of datums (access width data items) */
 
-       datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
-                                      obj_desc->common_field.access_bit_width);
+       datum_count =
+           ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
+                            access_bit_width);
+
        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
                                             obj_desc->common_field.
                                             start_field_bit_offset,
-                                            obj_desc->common_field.
                                             access_bit_width);
 
        /* Priming read from the field */
@@ -738,12 +758,11 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
                 * This avoids the differences in behavior between different compilers
                 * concerning shift values larger than the target data width.
                 */
-               if ((obj_desc->common_field.access_bit_width -
-                    obj_desc->common_field.start_field_bit_offset) <
+               if (access_bit_width -
+                   obj_desc->common_field.start_field_bit_offset <
                    ACPI_INTEGER_BIT_SIZE) {
                        merged_datum |=
-                           raw_datum << (obj_desc->common_field.
-                                         access_bit_width -
+                           raw_datum << (access_bit_width -
                                          obj_desc->common_field.
                                          start_field_bit_offset);
                }
@@ -765,8 +784,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
 
        /* Mask off any extra bits in the last datum */
 
-       buffer_tail_bits = obj_desc->common_field.bit_length %
-           obj_desc->common_field.access_bit_width;
+       buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
        if (buffer_tail_bits) {
                merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
        }
@@ -798,6 +816,7 @@ acpi_status
 acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
                          void *buffer, u32 buffer_length)
 {
+       void *new_buffer;
        acpi_status status;
        u64 mask;
        u64 width_mask;
@@ -808,9 +827,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
        u32 buffer_tail_bits;
        u32 datum_count;
        u32 field_datum_count;
-       u32 i;
+       u32 access_bit_width;
        u32 required_length;
-       void *new_buffer;
+       u32 i;
 
        ACPI_FUNCTION_TRACE(ex_insert_into_field);
 
@@ -844,17 +863,24 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
                buffer_length = required_length;
        }
 
+/* TBD: Move to common setup code */
+
+       /* Algo is limited to sizeof(u64), so cut the access_byte_width */
+       if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+               obj_desc->common_field.access_byte_width = sizeof(u64);
+       }
+
+       access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
        /*
         * Create the bitmasks used for bit insertion.
         * Note: This if/else is used to bypass compiler differences with the
         * shift operator
         */
-       if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
+       if (access_bit_width == ACPI_INTEGER_BIT_SIZE) {
                width_mask = ACPI_UINT64_MAX;
        } else {
-               width_mask =
-                   ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
-                                        access_bit_width);
+               width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width);
        }
 
        mask = width_mask &
@@ -863,12 +889,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
        /* Compute the number of datums (access width data items) */
 
        datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
-                                      obj_desc->common_field.access_bit_width);
+                                      access_bit_width);
 
        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
                                             obj_desc->common_field.
                                             start_field_bit_offset,
-                                            obj_desc->common_field.
                                             access_bit_width);
 
        /* Get initial Datum from the input buffer */
@@ -905,12 +930,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
                 * This avoids the differences in behavior between different compilers
                 * concerning shift values larger than the target data width.
                 */
-               if ((obj_desc->common_field.access_bit_width -
+               if ((access_bit_width -
                     obj_desc->common_field.start_field_bit_offset) <
                    ACPI_INTEGER_BIT_SIZE) {
                        merged_datum =
-                           raw_datum >> (obj_desc->common_field.
-                                         access_bit_width -
+                           raw_datum >> (access_bit_width -
                                          obj_desc->common_field.
                                          start_field_bit_offset);
                } else {
@@ -929,6 +953,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
                ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset,
                            ACPI_MIN(obj_desc->common_field.access_byte_width,
                                     buffer_length - buffer_offset));
+
                merged_datum |=
                    raw_datum << obj_desc->common_field.start_field_bit_offset;
        }
@@ -937,7 +962,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
 
        buffer_tail_bits = (obj_desc->common_field.bit_length +
                            obj_desc->common_field.start_field_bit_offset) %
-           obj_desc->common_field.access_bit_width;
+           access_bit_width;
        if (buffer_tail_bits) {
                mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
        }
index f73be97043c0e564b8cab1a56dca2f00697ce807..6af14e43f8394be3f6657994eb42eda9e92fd067 100644 (file)
@@ -336,7 +336,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
 
        /* Clear mutex info */
 
-       obj_desc->mutex.thread_id = NULL;
+       obj_desc->mutex.thread_id = 0;
        return_ACPI_STATUS(status);
 }
 
@@ -393,10 +393,10 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
        if ((owner_thread->thread_id != walk_state->thread->thread_id) &&
            (obj_desc != acpi_gbl_global_lock_mutex)) {
                ACPI_ERROR((AE_INFO,
-                           "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
-                           ACPI_CAST_PTR(void, walk_state->thread->thread_id),
+                           "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
+                           (u32)walk_state->thread->thread_id,
                            acpi_ut_get_node_name(obj_desc->mutex.node),
-                           ACPI_CAST_PTR(void, owner_thread->thread_id)));
+                           (u32)owner_thread->thread_id));
                return_ACPI_STATUS(AE_AML_NOT_OWNER);
        }
 
@@ -488,7 +488,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
                /* Mark mutex unowned */
 
                obj_desc->mutex.owner_thread = NULL;
-               obj_desc->mutex.thread_id = NULL;
+               obj_desc->mutex.thread_id = 0;
 
                /* Update Thread sync_level (Last mutex is the important one) */
 
index 98a331d2249b97394e2e0f006c615bdc08d33010..7aae29f73d3f2dfbc5438ff874e05a7ff7855f5d 100644 (file)
@@ -355,12 +355,10 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
        }
 
-       /* Setup width (access granularity) fields */
+       /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
 
        obj_desc->common_field.access_byte_width = (u8)
-           ACPI_DIV_8(access_bit_width);       /* 1,  2,  4,  8 */
-
-       obj_desc->common_field.access_bit_width = (u8) access_bit_width;
+           ACPI_DIV_8(access_bit_width);
 
        /*
         * base_byte_offset is the address of the start of the field within the
@@ -405,8 +403,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
 {
        union acpi_operand_object *obj_desc;
        union acpi_operand_object *second_desc = NULL;
-       u32 type;
        acpi_status status;
+       u32 access_byte_width;
+       u32 type;
 
        ACPI_FUNCTION_TRACE(ex_prep_field_value);
 
@@ -421,8 +420,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
                type = acpi_ns_get_type(info->region_node);
                if (type != ACPI_TYPE_REGION) {
                        ACPI_ERROR((AE_INFO,
-                                   "Needed Region, found type 0x%X (%s)",
-                                   type, acpi_ut_get_type_name(type)));
+                                   "Needed Region, found type 0x%X (%s)", type,
+                                   acpi_ut_get_type_name(type)));
 
                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
                }
@@ -438,7 +437,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
        /* Initialize areas of the object that are common to all fields */
 
        obj_desc->common_field.node = info->field_node;
-       status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags,
+       status = acpi_ex_prep_common_field_object(obj_desc,
+                                                 info->field_flags,
                                                  info->attribute,
                                                  info->field_bit_position,
                                                  info->field_bit_length);
@@ -455,26 +455,25 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
                obj_desc->field.region_obj =
                    acpi_ns_get_attached_object(info->region_node);
 
-               /* An additional reference for the container */
+               /* Allow full data read from EC address space */
 
-               acpi_ut_add_reference(obj_desc->field.region_obj);
+               if ((obj_desc->field.region_obj->region.space_id ==
+                    ACPI_ADR_SPACE_EC)
+                   && (obj_desc->common_field.bit_length > 8)) {
+                       access_byte_width =
+                           ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
+                                                       bit_length);
+
+                       /* Maximum byte width supported is 255 */
 
-               /* allow full data read from EC address space */
-               if (obj_desc->field.region_obj->region.space_id ==
-                       ACPI_ADR_SPACE_EC) {
-                       if (obj_desc->common_field.bit_length > 8) {
-                               unsigned width =
-                                       ACPI_ROUND_BITS_UP_TO_BYTES(
-                                       obj_desc->common_field.bit_length);
-                               // access_bit_width is u8, don't overflow it
-                               if (width > 8)
-                                       width = 8;
+                       if (access_byte_width < 256) {
                                obj_desc->common_field.access_byte_width =
-                                                       width;
-                               obj_desc->common_field.access_bit_width =
-                                                       8 * width;
+                                   (u8)access_byte_width;
                        }
                }
+               /* An additional reference for the container */
+
+               acpi_ut_add_reference(obj_desc->field.region_obj);
 
                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
                                  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
index 8819d2ac5aee73b0eb8a4bf205b9c1efa7abb5ab..de17e10da0ed9c5593e3e1d1af8bfd0d9dd81ee4 100644 (file)
@@ -353,7 +353,6 @@ acpi_ex_pci_config_space_handler(u32 function,
        acpi_status status = AE_OK;
        struct acpi_pci_id *pci_id;
        u16 pci_register;
-       u32 value32;
 
        ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
 
@@ -381,8 +380,7 @@ acpi_ex_pci_config_space_handler(u32 function,
        case ACPI_READ:
 
                status = acpi_os_read_pci_configuration(pci_id, pci_register,
-                                                       &value32, bit_width);
-               *value = value32;
+                                                       value, bit_width);
                break;
 
        case ACPI_WRITE:
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
new file mode 100644 (file)
index 0000000..ad21c7d
--- /dev/null
@@ -0,0 +1,412 @@
+/*******************************************************************************
+ *
+ * Module Name: hwpci - Obtain PCI bus, device, and function numbers
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_NAMESPACE
+ACPI_MODULE_NAME("hwpci")
+
+/* PCI configuration space values */
+#define PCI_CFG_HEADER_TYPE_REG             0x0E
+#define PCI_CFG_PRIMARY_BUS_NUMBER_REG      0x18
+#define PCI_CFG_SECONDARY_BUS_NUMBER_REG    0x19
+/* PCI header values */
+#define PCI_HEADER_TYPE_MASK                0x7F
+#define PCI_TYPE_BRIDGE                     0x01
+#define PCI_TYPE_CARDBUS_BRIDGE             0x02
+typedef struct acpi_pci_device {
+       acpi_handle device;
+       struct acpi_pci_device *next;
+
+} acpi_pci_device;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+                      acpi_handle pci_region,
+                      struct acpi_pci_device **return_list_head);
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+                        struct acpi_pci_device *list_head);
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+                           acpi_handle pci_device,
+                           u16 *bus_number, u8 *is_bridge);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_derive_pci_id
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              root_pci_device     - A handle to a PCI device object. This
+ *                                    object must be a PCI Root Bridge having a
+ *                                    _HID value of either PNP0A03 or PNP0A08
+ *              pci_region          - A handle to a PCI configuration space
+ *                                    Operation Region being initialized
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function derives a full PCI ID for a PCI device,
+ *              consisting of a Segment number, Bus number, Device number,
+ *              and function code.
+ *
+ *              The PCI hardware dynamically configures PCI bus numbers
+ *              depending on the bus topology discovered during system
+ *              initialization. This function is invoked during configuration
+ *              of a PCI_Config Operation Region in order to (possibly) update
+ *              the Bus/Device/Function numbers in the pci_id with the actual
+ *              values as determined by the hardware and operating system
+ *              configuration.
+ *
+ *              The pci_id parameter is initially populated during the Operation
+ *              Region initialization. This function is then called, and is
+ *              will make any necessary modifications to the Bus, Device, or
+ *              Function number PCI ID subfields as appropriate for the
+ *              current hardware and OS configuration.
+ *
+ * NOTE:        Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
+ *              interface since this feature is OS-independent. This module
+ *              specifically avoids any use of recursion by building a local
+ *              temporary device list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+                     acpi_handle root_pci_device, acpi_handle pci_region)
+{
+       acpi_status status;
+       struct acpi_pci_device *list_head = NULL;
+
+       ACPI_FUNCTION_TRACE(hw_derive_pci_id);
+
+       if (!pci_id) {
+               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
+
+       /* Build a list of PCI devices, from pci_region up to root_pci_device */
+
+       status =
+           acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
+       if (ACPI_SUCCESS(status)) {
+
+               /* Walk the list, updating the PCI device/function/bus numbers */
+
+               status = acpi_hw_process_pci_list(pci_id, list_head);
+       }
+
+       /* Always delete the list */
+
+       acpi_hw_delete_pci_list(list_head);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_build_pci_list
+ *
+ * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
+ *                                    object is guaranteed to be a PCI Root
+ *                                    Bridge having a _HID value of either
+ *                                    PNP0A03 or PNP0A08
+ *              pci_region          - A handle to the PCI configuration space
+ *                                    Operation Region
+ *              return_list_head    - Where the PCI device list is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Builds a list of devices from the input PCI region up to the
+ *              Root PCI device for this namespace subtree.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+                      acpi_handle pci_region,
+                      struct acpi_pci_device **return_list_head)
+{
+       acpi_handle current_device;
+       acpi_handle parent_device;
+       acpi_status status;
+       struct acpi_pci_device *list_element;
+       struct acpi_pci_device *list_head = NULL;
+
+       /*
+        * Ascend namespace branch until the root_pci_device is reached, building
+        * a list of device nodes. Loop will exit when either the PCI device is
+        * found, or the root of the namespace is reached.
+        */
+       current_device = pci_region;
+       while (1) {
+               status = acpi_get_parent(current_device, &parent_device);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
+
+               if (parent_device == root_pci_device) {
+                       *return_list_head = list_head;
+                       return (AE_OK);
+               }
+
+               list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
+               if (!list_element) {
+                       return (AE_NO_MEMORY);
+               }
+
+               /* Put new element at the head of the list */
+
+               list_element->next = list_head;
+               list_element->device = parent_device;
+               list_head = list_element;
+
+               current_device = parent_device;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_process_pci_list
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              list_head           - Device list created by
+ *                                    acpi_hw_build_pci_list
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Walk downward through the PCI device list, getting the device
+ *              info for each, via the PCI configuration space and updating
+ *              the PCI ID as necessary. Deletes the list during traversal.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+                        struct acpi_pci_device *list_head)
+{
+       acpi_status status = AE_OK;
+       struct acpi_pci_device *info;
+       u16 bus_number;
+       u8 is_bridge = TRUE;
+
+       ACPI_FUNCTION_NAME(hw_process_pci_list);
+
+       ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+                         "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
+                         pci_id->segment, pci_id->bus, pci_id->device,
+                         pci_id->function));
+
+       bus_number = pci_id->bus;
+
+       /*
+        * Descend down the namespace tree, collecting PCI device, function,
+        * and bus numbers. bus_number is only important for PCI bridges.
+        * Algorithm: As we descend the tree, use the last valid PCI device,
+        * function, and bus numbers that are discovered, and assign them
+        * to the PCI ID for the target device.
+        */
+       info = list_head;
+       while (info) {
+               status = acpi_hw_get_pci_device_info(pci_id, info->device,
+                                                    &bus_number, &is_bridge);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+
+               info = info->next;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+                         "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
+                         "Status %X BusNumber %X IsBridge %X\n",
+                         pci_id->segment, pci_id->bus, pci_id->device,
+                         pci_id->function, status, bus_number, is_bridge));
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_delete_pci_list
+ *
+ * PARAMETERS:  list_head           - Device list created by
+ *                                    acpi_hw_build_pci_list
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Free the entire PCI list.
+ *
+ ******************************************************************************/
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
+{
+       struct acpi_pci_device *next;
+       struct acpi_pci_device *previous;
+
+       next = list_head;
+       while (next) {
+               previous = next;
+               next = previous->next;
+               ACPI_FREE(previous);
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_get_pci_device_info
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              pci_device          - Handle for the PCI device object
+ *              bus_number          - Where a PCI bridge bus number is returned
+ *              is_bridge           - Return value, indicates if this PCI
+ *                                    device is a PCI bridge
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get the device info for a single PCI device object. Get the
+ *              _ADR (contains PCI device and function numbers), and for PCI
+ *              bridge devices, get the bus number from PCI configuration
+ *              space.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+                           acpi_handle pci_device,
+                           u16 *bus_number, u8 *is_bridge)
+{
+       acpi_status status;
+       acpi_object_type object_type;
+       u64 return_value;
+       u64 pci_value;
+
+       /* We only care about objects of type Device */
+
+       status = acpi_get_type(pci_device, &object_type);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       if (object_type != ACPI_TYPE_DEVICE) {
+               return (AE_OK);
+       }
+
+       /* We need an _ADR. Ignore device if not present */
+
+       status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
+                                                pci_device, &return_value);
+       if (ACPI_FAILURE(status)) {
+               return (AE_OK);
+       }
+
+       /*
+        * From _ADR, get the PCI Device and Function and
+        * update the PCI ID.
+        */
+       pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
+       pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
+
+       /*
+        * If the previous device was a bridge, use the previous
+        * device bus number
+        */
+       if (*is_bridge) {
+               pci_id->bus = *bus_number;
+       }
+
+       /*
+        * Get the bus numbers from PCI Config space:
+        *
+        * First, get the PCI header_type
+        */
+       *is_bridge = FALSE;
+       status = acpi_os_read_pci_configuration(pci_id,
+                                               PCI_CFG_HEADER_TYPE_REG,
+                                               &pci_value, 8);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
+
+       pci_value &= PCI_HEADER_TYPE_MASK;
+
+       if ((pci_value != PCI_TYPE_BRIDGE) &&
+           (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
+               return (AE_OK);
+       }
+
+       /* Bridge: Get the Primary bus_number */
+
+       status = acpi_os_read_pci_configuration(pci_id,
+                                               PCI_CFG_PRIMARY_BUS_NUMBER_REG,
+                                               &pci_value, 8);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       *is_bridge = TRUE;
+       pci_id->bus = (u16)pci_value;
+
+       /* Bridge: Get the Secondary bus_number */
+
+       status = acpi_os_read_pci_configuration(pci_id,
+                                               PCI_CFG_SECONDARY_BUS_NUMBER_REG,
+                                               &pci_value, 8);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       *bus_number = (u16)pci_value;
+       return (AE_OK);
+}
index 4009498fbabd038520fdb47756cd263386f0b980..4ef9f43ea9262273ed06686eae439b9675f5d10d 100644 (file)
@@ -73,10 +73,18 @@ static acpi_status
 acpi_ns_repair_ALR(struct acpi_predefined_data *data,
                   union acpi_operand_object **return_object_ptr);
 
+static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+                  union acpi_operand_object **return_object_ptr);
+
 static acpi_status
 acpi_ns_repair_FDE(struct acpi_predefined_data *data,
                   union acpi_operand_object **return_object_ptr);
 
+static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+                  union acpi_operand_object **return_object_ptr);
+
 static acpi_status
 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
                   union acpi_operand_object **return_object_ptr);
@@ -108,8 +116,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
  * As necessary:
  *
  * _ALR: Sort the list ascending by ambient_illuminance
+ * _CID: Strings: uppercase all, remove any leading asterisk
  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
+ * _HID: Strings: uppercase all, remove any leading asterisk
  * _PSS: Sort the list descending by Power
  * _TSS: Sort the list descending by Power
  *
@@ -122,8 +132,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
  */
 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
        {"_ALR", acpi_ns_repair_ALR},
+       {"_CID", acpi_ns_repair_CID},
        {"_FDE", acpi_ns_repair_FDE},
        {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
+       {"_HID", acpi_ns_repair_HID},
        {"_PSS", acpi_ns_repair_PSS},
        {"_TSS", acpi_ns_repair_TSS},
        {{0, 0, 0, 0}, NULL}    /* Table terminator */
@@ -319,6 +331,157 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
        return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_CID
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
+ *              letters are uppercase and that there is no leading asterisk.
+ *              If a Package, ensure same for all string elements.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+                  union acpi_operand_object **return_object_ptr)
+{
+       acpi_status status;
+       union acpi_operand_object *return_object = *return_object_ptr;
+       union acpi_operand_object **element_ptr;
+       union acpi_operand_object *original_element;
+       u16 original_ref_count;
+       u32 i;
+
+       /* Check for _CID as a simple string */
+
+       if (return_object->common.type == ACPI_TYPE_STRING) {
+               status = acpi_ns_repair_HID(data, return_object_ptr);
+               return (status);
+       }
+
+       /* Exit if not a Package */
+
+       if (return_object->common.type != ACPI_TYPE_PACKAGE) {
+               return (AE_OK);
+       }
+
+       /* Examine each element of the _CID package */
+
+       element_ptr = return_object->package.elements;
+       for (i = 0; i < return_object->package.count; i++) {
+               original_element = *element_ptr;
+               original_ref_count = original_element->common.reference_count;
+
+               status = acpi_ns_repair_HID(data, element_ptr);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               /* Take care with reference counts */
+
+               if (original_element != *element_ptr) {
+
+                       /* Element was replaced */
+
+                       (*element_ptr)->common.reference_count =
+                           original_ref_count;
+
+                       acpi_ut_remove_reference(original_element);
+               }
+
+               element_ptr++;
+       }
+
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_HID
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
+ *              letters are uppercase and that there is no leading asterisk.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+                  union acpi_operand_object **return_object_ptr)
+{
+       union acpi_operand_object *return_object = *return_object_ptr;
+       union acpi_operand_object *new_string;
+       char *source;
+       char *dest;
+
+       ACPI_FUNCTION_NAME(ns_repair_HID);
+
+       /* We only care about string _HID objects (not integers) */
+
+       if (return_object->common.type != ACPI_TYPE_STRING) {
+               return (AE_OK);
+       }
+
+       if (return_object->string.length == 0) {
+               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+                                     "Invalid zero-length _HID or _CID string"));
+
+               /* Return AE_OK anyway, let driver handle it */
+
+               data->flags |= ACPI_OBJECT_REPAIRED;
+               return (AE_OK);
+       }
+
+       /* It is simplest to always create a new string object */
+
+       new_string = acpi_ut_create_string_object(return_object->string.length);
+       if (!new_string) {
+               return (AE_NO_MEMORY);
+       }
+
+       /*
+        * Remove a leading asterisk if present. For some unknown reason, there
+        * are many machines in the field that contains IDs like this.
+        *
+        * Examples: "*PNP0C03", "*ACPI0003"
+        */
+       source = return_object->string.pointer;
+       if (*source == '*') {
+               source++;
+               new_string->string.length--;
+
+               ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+                                 "%s: Removed invalid leading asterisk\n",
+                                 data->pathname));
+       }
+
+       /*
+        * Copy and uppercase the string. From the ACPI specification:
+        *
+        * A valid PNP ID must be of the form "AAA####" where A is an uppercase
+        * letter and # is a hex digit. A valid ACPI ID must be of the form
+        * "ACPI####" where # is a hex digit.
+        */
+       for (dest = new_string->string.pointer; *source; dest++, source++) {
+               *dest = (char)ACPI_TOUPPER(*source);
+       }
+
+       acpi_ut_remove_reference(return_object);
+       *return_object_ptr = new_string;
+       return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_TSS
index e1add3491b04a7def5879b00c4f1e6ab1e6b5353..a7d6ad9c111b6b71fe52f4d5870e0b620efaf356 100644 (file)
@@ -58,104 +58,6 @@ static u8 acpi_ns_valid_path_separator(char sep);
 acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
 #endif
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_report_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              internal_name       - Name or path of the namespace node
- *              lookup_status       - Exception code from NS lookup
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_error(const char *module_name,
-                    u32 line_number,
-                    const char *internal_name, acpi_status lookup_status)
-{
-       acpi_status status;
-       u32 bad_name;
-       char *name = NULL;
-
-       acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
-       if (lookup_status == AE_BAD_CHARACTER) {
-
-               /* There is a non-ascii character in the name */
-
-               ACPI_MOVE_32_TO_32(&bad_name,
-                                  ACPI_CAST_PTR(u32, internal_name));
-               acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
-       } else {
-               /* Convert path to external format */
-
-               status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
-                                                 internal_name, NULL, &name);
-
-               /* Print target name */
-
-               if (ACPI_SUCCESS(status)) {
-                       acpi_os_printf("[%s]", name);
-               } else {
-                       acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
-               }
-
-               if (name) {
-                       ACPI_FREE(name);
-               }
-       }
-
-       acpi_os_printf(" Namespace lookup failure, %s\n",
-                      acpi_format_exception(lookup_status));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_report_method_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              Message             - Error message to use on failure
- *              prefix_node         - Prefix relative to the path
- *              Path                - Path to the node (optional)
- *              method_status       - Execution status
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_method_error(const char *module_name,
-                           u32 line_number,
-                           const char *message,
-                           struct acpi_namespace_node *prefix_node,
-                           const char *path, acpi_status method_status)
-{
-       acpi_status status;
-       struct acpi_namespace_node *node = prefix_node;
-
-       acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
-       if (path) {
-               status =
-                   acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
-                                    &node);
-               if (ACPI_FAILURE(status)) {
-                       acpi_os_printf("[Could not get node by pathname]");
-               }
-       }
-
-       acpi_ns_print_node_pathname(node, message);
-       acpi_os_printf(", %s\n", acpi_format_exception(method_status));
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_print_node_pathname
index 1728cb9bf600f020609a4bb2491f61508fd694c9..d2ff4325c4270a6c34e063bccfdf020175ae72b6 100644 (file)
@@ -49,7 +49,7 @@
 ACPI_MODULE_NAME("tbfadt")
 
 /* Local prototypes */
-static inline void
+static ACPI_INLINE void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
                             u8 space_id, u8 byte_width, u64 address);
 
@@ -181,7 +181,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
  *
  ******************************************************************************/
 
-static inline void
+static ACPI_INLINE void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
                             u8 space_id, u8 byte_width, u64 address)
 {
index 983510640059a5bf24feb6e9d85620e918223ee3..f21c486929a54a96fcf8bbcf5a6d34049b00bbf5 100644 (file)
@@ -179,9 +179,8 @@ acpi_debug_print(u32 requested_debug_level,
        if (thread_id != acpi_gbl_prev_thread_id) {
                if (ACPI_LV_THREADS & acpi_dbg_level) {
                        acpi_os_printf
-                           ("\n**** Context Switch from TID %p to TID %p ****\n\n",
-                            ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id),
-                            ACPI_CAST_PTR(void, thread_id));
+                           ("\n**** Context Switch from TID %u to TID %u ****\n\n",
+                            (u32)acpi_gbl_prev_thread_id, (u32)thread_id);
                }
 
                acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +193,7 @@ acpi_debug_print(u32 requested_debug_level,
        acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
        if (ACPI_LV_THREADS & acpi_dbg_level) {
-               acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id));
+               acpi_os_printf("[%u] ", (u32)thread_id);
        }
 
        acpi_os_printf("[%02ld] %-22.22s: ",
index 6dfdeb65349058c3fda58ec860236a90ac505665..22f59ef604e06b840f95c0d16ffa048614091071 100644 (file)
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("uteval")
 
-/*
- * Strings supported by the _OSI predefined (internal) method.
- *
- * March 2009: Removed "Linux" as this host no longer wants to respond true
- * for this string. Basically, the only safe OS strings are windows-related
- * and in many or most cases represent the only test path within the
- * BIOS-provided ASL code.
- *
- * The second element of each entry is used to track the newest version of
- * Windows that the BIOS has requested.
- */
-static struct acpi_interface_info acpi_interfaces_supported[] = {
-       /* Operating System Vendor Strings */
-
-       {"Windows 2000", ACPI_OSI_WIN_2000},    /* Windows 2000 */
-       {"Windows 2001", ACPI_OSI_WIN_XP},      /* Windows XP */
-       {"Windows 2001 SP1", ACPI_OSI_WIN_XP_SP1},      /* Windows XP SP1 */
-       {"Windows 2001.1", ACPI_OSI_WINSRV_2003},       /* Windows Server 2003 */
-       {"Windows 2001 SP2", ACPI_OSI_WIN_XP_SP2},      /* Windows XP SP2 */
-       {"Windows 2001.1 SP1", ACPI_OSI_WINSRV_2003_SP1},       /* Windows Server 2003 SP1 - Added 03/2006 */
-       {"Windows 2006", ACPI_OSI_WIN_VISTA},   /* Windows Vista - Added 03/2006 */
-       {"Windows 2006.1", ACPI_OSI_WINSRV_2008},       /* Windows Server 2008 - Added 09/2009 */
-       {"Windows 2006 SP1", ACPI_OSI_WIN_VISTA_SP1},   /* Windows Vista SP1 - Added 09/2009 */
-       {"Windows 2009", ACPI_OSI_WIN_7},       /* Windows 7 and Server 2008 R2 - Added 09/2009 */
-
-       /* Feature Group Strings */
-
-       {"Extended Address Space Descriptor", 0}
-
-       /*
-        * All "optional" feature group strings (features that are implemented
-        * by the host) should be implemented in the host version of
-        * acpi_os_validate_interface and should not be added here.
-        */
-};
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_osi_implementation
- *
- * PARAMETERS:  walk_state          - Current walk state
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Implementation of the _OSI predefined control method
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
-{
-       acpi_status status;
-       union acpi_operand_object *string_desc;
-       union acpi_operand_object *return_desc;
-       u32 return_value;
-       u32 i;
-
-       ACPI_FUNCTION_TRACE(ut_osi_implementation);
-
-       /* Validate the string input argument */
-
-       string_desc = walk_state->arguments[0].object;
-       if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
-               return_ACPI_STATUS(AE_TYPE);
-       }
-
-       /* Create a return object */
-
-       return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
-       if (!return_desc) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
-       }
-
-       /* Default return value is 0, NOT SUPPORTED */
-
-       return_value = 0;
-
-       /* Compare input string to static table of supported interfaces */
-
-       for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
-               if (!ACPI_STRCMP(string_desc->string.pointer,
-                                acpi_interfaces_supported[i].name)) {
-                       /*
-                        * The interface is supported.
-                        * Update the osi_data if necessary. We keep track of the latest
-                        * version of Windows that has been requested by the BIOS.
-                        */
-                       if (acpi_interfaces_supported[i].value >
-                           acpi_gbl_osi_data) {
-                               acpi_gbl_osi_data =
-                                   acpi_interfaces_supported[i].value;
-                       }
-
-                       return_value = ACPI_UINT32_MAX;
-                       goto exit;
-               }
-       }
-
-       /*
-        * Did not match the string in the static table, call the host OSL to
-        * check for a match with one of the optional strings (such as
-        * "Module Device", "3.0 Thermal Model", etc.)
-        */
-       status = acpi_os_validate_interface(string_desc->string.pointer);
-       if (ACPI_SUCCESS(status)) {
-
-               /* The interface is supported */
-
-               return_value = ACPI_UINT32_MAX;
-       }
-
-exit:
-       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO,
-               "ACPI: BIOS _OSI(%s) is %ssupported\n",
-               string_desc->string.pointer, return_value == 0 ? "not " : ""));
-
-       /* Complete the return value */
-
-       return_desc->integer.value = return_value;
-       walk_state->return_desc = return_desc;
-       return_ACPI_STATUS (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_osi_invalidate
- *
- * PARAMETERS:  interface_string
- *
- * RETURN:      Status
- *
- * DESCRIPTION: invalidate string in pre-defiend _OSI string list
- *
- ******************************************************************************/
-
-acpi_status acpi_osi_invalidate(char *interface)
-{
-       int i;
-
-       for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
-               if (!ACPI_STRCMP(interface, acpi_interfaces_supported[i].name)) {
-                       *acpi_interfaces_supported[i].name = '\0';
-                       return AE_OK;
-               }
-       }
-       return AE_NOT_FOUND;
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_evaluate_object
index 0558747579efd862ec3aee833fc742943275bc87..e87bc6760be6e01e1b0d5ed52912a2194a7246f3 100644 (file)
@@ -154,14 +154,16 @@ ACPI_EXPORT_SYMBOL(acpi_format_exception)
  * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run
  *    during the initialization sequence.
  * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to
- *    perform a Notify() operation on it.
+ *    perform a Notify() operation on it. 09/2010: Changed to type Device.
+ *    This still allows notifies, but does not confuse host code that
+ *    searches for valid thermal_zone objects.
  */
 const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
        {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL},
        {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL},
        {"_SB_", ACPI_TYPE_DEVICE, NULL},
        {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
-       {"_TZ_", ACPI_TYPE_THERMAL, NULL},
+       {"_TZ_", ACPI_TYPE_DEVICE, NULL},
        {"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL},
        {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
        {"_GL_", ACPI_TYPE_MUTEX, (char *)1},
@@ -766,6 +768,7 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_gpe_fadt_blocks[0] = NULL;
        acpi_gbl_gpe_fadt_blocks[1] = NULL;
        acpi_current_gpe_count = 0;
+       acpi_all_gpes_initialized = FALSE;
 
        /* Global handlers */
 
@@ -774,6 +777,7 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_exception_handler = NULL;
        acpi_gbl_init_handler = NULL;
        acpi_gbl_table_handler = NULL;
+       acpi_gbl_interface_handler = NULL;
 
        /* Global Lock support */
 
@@ -800,6 +804,7 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
        acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
        acpi_gbl_osi_data = 0;
+       acpi_gbl_osi_mutex = NULL;
 
        /* Hardware oriented */
 
index 1397fadd0d4b14807b00650732fee18970e5328b..d2906328535df5903b887ae3c744473e27061e64 100644 (file)
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utids")
 
-/* Local prototypes */
-static void acpi_ut_copy_id_string(char *destination, char *source);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_copy_id_string
- *
- * PARAMETERS:  Destination         - Where to copy the string
- *              Source              - Source string
- *
- * RETURN:      None
- *
- * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
- *              Performs removal of a leading asterisk if present -- workaround
- *              for a known issue on a bunch of machines.
- *
- ******************************************************************************/
-
-static void acpi_ut_copy_id_string(char *destination, char *source)
-{
-
-       /*
-        * Workaround for ID strings that have a leading asterisk. This construct
-        * is not allowed by the ACPI specification  (ID strings must be
-        * alphanumeric), but enough existing machines have this embedded in their
-        * ID strings that the following code is useful.
-        */
-       if (*source == '*') {
-               source++;
-       }
-
-       /* Do the actual copy */
-
-       ACPI_STRCPY(destination, source);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_execute_HID
@@ -101,7 +65,6 @@ static void acpi_ut_copy_id_string(char *destination, char *source)
  *              NOTE: Internal function, no parameter validation
  *
  ******************************************************************************/
-
 acpi_status
 acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
                    struct acpica_device_id **return_id)
@@ -147,7 +110,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
                acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
        } else {
-               acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer);
+               ACPI_STRCPY(hid->string, obj_desc->string.pointer);
        }
 
        hid->length = length;
@@ -224,7 +187,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
                acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
        } else {
-               acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer);
+               ACPI_STRCPY(uid->string, obj_desc->string.pointer);
        }
 
        uid->length = length;
@@ -357,8 +320,8 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
 
                        /* Copy the String CID from the returned object */
 
-                       acpi_ut_copy_id_string(next_id_string,
-                                              cid_objects[i]->string.pointer);
+                       ACPI_STRCPY(next_id_string,
+                                   cid_objects[i]->string.pointer);
                        length = cid_objects[i]->string.length + 1;
                }
 
index a39c93dac7193794e3a063e89a6432db9ff9cc67..c1b1c803ea9b62f8072a4af3d6ea8c8342aa1a91 100644 (file)
@@ -117,6 +117,10 @@ void acpi_ut_subsystem_shutdown(void)
        /* Close the acpi_event Handling */
 
        acpi_ev_terminate();
+
+       /* Delete any dynamic _OSI interfaces */
+
+       acpi_ut_interface_terminate();
 #endif
 
        /* Close the Namespace */
index 35059a14eb72c87eaa86e6345a477822ece004ec..49cf7b7fd816ca8b453b7f6c2e6b736d98b611a3 100644 (file)
 ACPI_MODULE_NAME("utmath")
 
 /*
- * Support for double-precision integer divide.  This code is included here
- * in order to support kernel environments where the double-precision math
- * library is not available.
+ * Optional support for 64-bit double-precision integer divide. This code
+ * is configurable and is implemented in order to support 32-bit kernel
+ * environments where a 64-bit double-precision math library is not available.
+ *
+ * Support for a more normal 64-bit divide/modulo (with check for a divide-
+ * by-zero) appears after this optional section of code.
  */
 #ifndef ACPI_USE_NATIVE_DIVIDE
+/* Structures used only for 64-bit divide */
+typedef struct uint64_struct {
+       u32 lo;
+       u32 hi;
+
+} uint64_struct;
+
+typedef union uint64_overlay {
+       u64 full;
+       struct uint64_struct part;
+
+} uint64_overlay;
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_short_divide
@@ -69,6 +85,7 @@ ACPI_MODULE_NAME("utmath")
  *              32-bit remainder.
  *
  ******************************************************************************/
+
 acpi_status
 acpi_ut_short_divide(u64 dividend,
                     u32 divisor, u64 *out_quotient, u32 *out_remainder)
index e8d0724ee4032a25f5fb5a4ab3035aed00bf59cc..c7d0e05ef5a4ebccdf6586249136b0b4ac5c6ca9 100644 (file)
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utmisc")
 
-/*
- * Common suffix for messages
- */
-#define ACPI_COMMON_MSG_SUFFIX \
-       acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_validate_exception
@@ -1044,160 +1039,3 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
 
        return_ACPI_STATUS(AE_AML_INTERNAL);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_error, acpi_exception, acpi_warning, acpi_info
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              Format              - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print message with module/line/version info
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_error(const char *module_name, u32 line_number, const char *format, ...)
-{
-       va_list args;
-
-       acpi_os_printf("ACPI Error: ");
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       ACPI_COMMON_MSG_SUFFIX;
-       va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_exception(const char *module_name,
-              u32 line_number, acpi_status status, const char *format, ...)
-{
-       va_list args;
-
-       acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status));
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       ACPI_COMMON_MSG_SUFFIX;
-       va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
-{
-       va_list args;
-
-       acpi_os_printf("ACPI Warning: ");
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       ACPI_COMMON_MSG_SUFFIX;
-       va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_info(const char *module_name, u32 line_number, const char *format, ...)
-{
-       va_list args;
-
-       acpi_os_printf("ACPI: ");
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       acpi_os_printf("\n");
-       va_end(args);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_error)
-ACPI_EXPORT_SYMBOL(acpi_exception)
-ACPI_EXPORT_SYMBOL(acpi_warning)
-ACPI_EXPORT_SYMBOL(acpi_info)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_warning
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              Pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              Format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Warnings for the predefined validation module. Messages are
- *              only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of error
- *              messages for methods that are repeatedly evaluated.
- *
-******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
-                          u32 line_number,
-                          char *pathname,
-                          u8 node_flags, const char *format, ...)
-{
-       va_list args;
-
-       /*
-        * Warning messages for this method/object will be disabled after the
-        * first time a validation fails or an object is successfully repaired.
-        */
-       if (node_flags & ANOBJ_EVALUATED) {
-               return;
-       }
-
-       acpi_os_printf("ACPI Warning for %s: ", pathname);
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       ACPI_COMMON_MSG_SUFFIX;
-       va_end(args);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_info
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              Pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              Format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Info messages for the predefined validation module. Messages
- *              are only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of
- *              messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
-                       u32 line_number,
-                       char *pathname, u8 node_flags, const char *format, ...)
-{
-       va_list args;
-
-       /*
-        * Warning messages for this method/object will be disabled after the
-        * first time a validation fails or an object is successfully repaired.
-        */
-       if (node_flags & ANOBJ_EVALUATED) {
-               return;
-       }
-
-       acpi_os_printf("ACPI Info for %s: ", pathname);
-
-       va_start(args, format);
-       acpi_os_vprintf(format, args);
-       ACPI_COMMON_MSG_SUFFIX;
-       va_end(args);
-}
index f5cca3a1300c60c1d3fae972389031d27782e1a1..d9efa495b4330049a1fa57fde968938c6cb18f0b 100644 (file)
@@ -86,6 +86,12 @@ acpi_status acpi_ut_mutex_initialize(void)
        spin_lock_init(acpi_gbl_gpe_lock);
        spin_lock_init(acpi_gbl_hardware_lock);
 
+       /* Mutex for _OSI support */
+       status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Create the reader/writer lock for namespace access */
 
        status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
@@ -117,6 +123,8 @@ void acpi_ut_mutex_terminate(void)
                acpi_ut_delete_mutex(i);
        }
 
+       acpi_os_delete_mutex(acpi_gbl_osi_mutex);
+
        /* Delete the spinlocks */
 
        acpi_os_delete_lock(acpi_gbl_gpe_lock);
@@ -220,18 +228,17 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
                        if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
                                if (i == mutex_id) {
                                        ACPI_ERROR((AE_INFO,
-                                                   "Mutex [%s] already acquired by this thread [%p]",
+                                                   "Mutex [%s] already acquired by this thread [%u]",
                                                    acpi_ut_get_mutex_name
                                                    (mutex_id),
-                                                   ACPI_CAST_PTR(void,
-                                                                 this_thread_id)));
+                                                   (u32)this_thread_id));
 
                                        return (AE_ALREADY_ACQUIRED);
                                }
 
                                ACPI_ERROR((AE_INFO,
-                                           "Invalid acquire order: Thread %p owns [%s], wants [%s]",
-                                           ACPI_CAST_PTR(void, this_thread_id),
+                                           "Invalid acquire order: Thread %u owns [%s], wants [%s]",
+                                           (u32)this_thread_id,
                                            acpi_ut_get_mutex_name(i),
                                            acpi_ut_get_mutex_name(mutex_id)));
 
@@ -242,24 +249,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 #endif
 
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                         "Thread %p attempting to acquire Mutex [%s]\n",
-                         ACPI_CAST_PTR(void, this_thread_id),
+                         "Thread %u attempting to acquire Mutex [%s]\n",
+                         (u32)this_thread_id,
                          acpi_ut_get_mutex_name(mutex_id)));
 
        status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
                                       ACPI_WAIT_FOREVER);
        if (ACPI_SUCCESS(status)) {
                ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                                 "Thread %p acquired Mutex [%s]\n",
-                                 ACPI_CAST_PTR(void, this_thread_id),
+                                 "Thread %u acquired Mutex [%s]\n",
+                                 (u32)this_thread_id,
                                  acpi_ut_get_mutex_name(mutex_id)));
 
                acpi_gbl_mutex_info[mutex_id].use_count++;
                acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
        } else {
                ACPI_EXCEPTION((AE_INFO, status,
-                               "Thread %p could not acquire Mutex [0x%X]",
-                               ACPI_CAST_PTR(void, this_thread_id), mutex_id));
+                               "Thread %u could not acquire Mutex [0x%X]",
+                               (u32)this_thread_id, mutex_id));
        }
 
        return (status);
@@ -279,10 +286,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 
 acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
 {
+       acpi_thread_id this_thread_id;
+
        ACPI_FUNCTION_NAME(ut_release_mutex);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n",
-                         ACPI_CAST_PTR(void, acpi_os_get_thread_id()),
+       this_thread_id = acpi_os_get_thread_id();
+
+       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
+                         (u32)this_thread_id,
                          acpi_ut_get_mutex_name(mutex_id)));
 
        if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
new file mode 100644 (file)
index 0000000..18c59a8
--- /dev/null
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * Module Name: utosi - Support for the _OSI predefined control method
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utosi")
+
+/*
+ * Strings supported by the _OSI predefined control method (which is
+ * implemented internally within this module.)
+ *
+ * March 2009: Removed "Linux" as this host no longer wants to respond true
+ * for this string. Basically, the only safe OS strings are windows-related
+ * and in many or most cases represent the only test path within the
+ * BIOS-provided ASL code.
+ *
+ * The last element of each entry is used to track the newest version of
+ * Windows that the BIOS has requested.
+ */
+static struct acpi_interface_info acpi_default_supported_interfaces[] = {
+       /* Operating System Vendor Strings */
+
+       {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000},   /* Windows 2000 */
+       {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP},     /* Windows XP */
+       {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1},     /* Windows XP SP1 */
+       {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003},      /* Windows Server 2003 */
+       {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2},     /* Windows XP SP2 */
+       {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1},      /* Windows Server 2003 SP1 - Added 03/2006 */
+       {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA},  /* Windows Vista - Added 03/2006 */
+       {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008},      /* Windows Server 2008 - Added 09/2009 */
+       {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1},  /* Windows Vista SP1 - Added 09/2009 */
+       {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},  /* Windows Vista SP2 - Added 09/2010 */
+       {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},      /* Windows 7 and Server 2008 R2 - Added 09/2009 */
+
+       /* Feature Group Strings */
+
+       {"Extended Address Space Descriptor", NULL, 0, 0}
+
+       /*
+        * All "optional" feature group strings (features that are implemented
+        * by the host) should be dynamically added by the host via
+        * acpi_install_interface and should not be manually added here.
+        *
+        * Examples of optional feature group strings:
+        *
+        * "Module Device"
+        * "Processor Device"
+        * "3.0 Thermal Model"
+        * "3.0 _SCP Extensions"
+        * "Processor Aggregator Device"
+        */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_initialize_interfaces
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Initialize the global _OSI supported interfaces list
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_initialize_interfaces(void)
+{
+       u32 i;
+
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+       acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
+
+       /* Link the static list of supported interfaces */
+
+       for (i = 0;
+            i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
+            i++) {
+               acpi_default_supported_interfaces[i].next =
+                   &acpi_default_supported_interfaces[(acpi_size) i + 1];
+       }
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_interface_terminate
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete all interfaces in the global list. Sets
+ *              acpi_gbl_supported_interfaces to NULL.
+ *
+ ******************************************************************************/
+
+void acpi_ut_interface_terminate(void)
+{
+       struct acpi_interface_info *next_interface;
+
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+       next_interface = acpi_gbl_supported_interfaces;
+
+       while (next_interface) {
+               acpi_gbl_supported_interfaces = next_interface->next;
+
+               /* Only interfaces added at runtime can be freed */
+
+               if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+                       ACPI_FREE(next_interface->name);
+                       ACPI_FREE(next_interface);
+               }
+
+               next_interface = acpi_gbl_supported_interfaces;
+       }
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_install_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to install
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install the interface into the global interface list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name)
+{
+       struct acpi_interface_info *interface_info;
+
+       /* Allocate info block and space for the name string */
+
+       interface_info =
+           ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
+       if (!interface_info) {
+               return (AE_NO_MEMORY);
+       }
+
+       interface_info->name =
+           ACPI_ALLOCATE_ZEROED(ACPI_STRLEN(interface_name) + 1);
+       if (!interface_info->name) {
+               ACPI_FREE(interface_info);
+               return (AE_NO_MEMORY);
+       }
+
+       /* Initialize new info and insert at the head of the global list */
+
+       ACPI_STRCPY(interface_info->name, interface_name);
+       interface_info->flags = ACPI_OSI_DYNAMIC;
+       interface_info->next = acpi_gbl_supported_interfaces;
+
+       acpi_gbl_supported_interfaces = interface_info;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to remove
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove the interface from the global interface list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name)
+{
+       struct acpi_interface_info *previous_interface;
+       struct acpi_interface_info *next_interface;
+
+       previous_interface = next_interface = acpi_gbl_supported_interfaces;
+       while (next_interface) {
+               if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+
+                       /* Found: name is in either the static list or was added at runtime */
+
+                       if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+                               /* Interface was added dynamically, remove and free it */
+
+                               if (previous_interface == next_interface) {
+                                       acpi_gbl_supported_interfaces =
+                                           next_interface->next;
+                               } else {
+                                       previous_interface->next =
+                                           next_interface->next;
+                               }
+
+                               ACPI_FREE(next_interface->name);
+                               ACPI_FREE(next_interface);
+                       } else {
+                               /*
+                                * Interface is in static list. If marked invalid, then it
+                                * does not actually exist. Else, mark it invalid.
+                                */
+                               if (next_interface->flags & ACPI_OSI_INVALID) {
+                                       return (AE_NOT_EXIST);
+                               }
+
+                               next_interface->flags |= ACPI_OSI_INVALID;
+                       }
+
+                       return (AE_OK);
+               }
+
+               previous_interface = next_interface;
+               next_interface = next_interface->next;
+       }
+
+       /* Interface was not found */
+
+       return (AE_NOT_EXIST);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to find
+ *
+ * RETURN:      struct acpi_interface_info if found. NULL if not found.
+ *
+ * DESCRIPTION: Search for the specified interface name in the global list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
+{
+       struct acpi_interface_info *next_interface;
+
+       next_interface = acpi_gbl_supported_interfaces;
+       while (next_interface) {
+               if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+                       return (next_interface);
+               }
+
+               next_interface = next_interface->next;
+       }
+
+       return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_osi_implementation
+ *
+ * PARAMETERS:  walk_state          - Current walk state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Implementation of the _OSI predefined control method. When
+ *              an invocation of _OSI is encountered in the system AML,
+ *              control is transferred to this function.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
+{
+       union acpi_operand_object *string_desc;
+       union acpi_operand_object *return_desc;
+       struct acpi_interface_info *interface_info;
+       acpi_interface_handler interface_handler;
+       u32 return_value;
+
+       ACPI_FUNCTION_TRACE(ut_osi_implementation);
+
+       /* Validate the string input argument (from the AML caller) */
+
+       string_desc = walk_state->arguments[0].object;
+       if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
+               return_ACPI_STATUS(AE_TYPE);
+       }
+
+       /* Create a return object */
+
+       return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+       if (!return_desc) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Default return value is 0, NOT SUPPORTED */
+
+       return_value = 0;
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+       /* Lookup the interface in the global _OSI list */
+
+       interface_info = acpi_ut_get_interface(string_desc->string.pointer);
+       if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
+               /*
+                * The interface is supported.
+                * Update the osi_data if necessary. We keep track of the latest
+                * version of Windows that has been requested by the BIOS.
+                */
+               if (interface_info->value > acpi_gbl_osi_data) {
+                       acpi_gbl_osi_data = interface_info->value;
+               }
+
+               return_value = ACPI_UINT32_MAX;
+       }
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+
+       /*
+        * Invoke an optional _OSI interface handler. The host OS may wish
+        * to do some interface-specific handling. For example, warn about
+        * certain interfaces or override the true/false support value.
+        */
+       interface_handler = acpi_gbl_interface_handler;
+       if (interface_handler) {
+               return_value =
+                   interface_handler(string_desc->string.pointer,
+                                     return_value);
+       }
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
+                             "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
+                             string_desc->string.pointer,
+                             return_value == 0 ? "not " : ""));
+
+       /* Complete the return object */
+
+       return_desc->integer.value = return_value;
+       walk_state->return_desc = return_desc;
+       return_ACPI_STATUS(AE_OK);
+}
index 7f8cefcb2b32da538adb9a2fb73e4dbae645924e..1f484c9a6888934bd82949a86e93339c033a13a1 100644 (file)
@@ -110,6 +110,15 @@ acpi_status __init acpi_initialize_subsystem(void)
                return_ACPI_STATUS(status);
        }
 
+       /* Initialize the global OSI interfaces list with the static names */
+
+       status = acpi_ut_initialize_interfaces();
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "During OSI interfaces initialization"));
+               return_ACPI_STATUS(status);
+       }
+
        /* If configured, initialize the AML debugger */
 
        ACPI_DEBUGGER_EXEC(status = acpi_db_initialize());
@@ -289,19 +298,6 @@ acpi_status acpi_initialize_objects(u32 flags)
                }
        }
 
-       /*
-        * Complete the GPE initialization for the GPE blocks defined in the FADT
-        * (GPE block 0 and 1).
-        *
-        * NOTE: Currently, there seems to be no need to run the _REG methods
-        * before enabling the GPEs.
-        */
-       if (!(flags & ACPI_NO_EVENT_INIT)) {
-               status = acpi_ev_install_fadt_gpes();
-               if (ACPI_FAILURE(status))
-                       return (status);
-       }
-
        /*
         * Empty the caches (delete the cached objects) on the assumption that
         * the table load filled them up more than they will be at runtime --
@@ -506,6 +502,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
 #endif                         /*  ACPI_FUTURE_USAGE  */
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_purge_cached_objects
@@ -529,4 +526,117 @@ acpi_status acpi_purge_cached_objects(void)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
-#endif
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_install_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to install
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install an _OSI interface to the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface(acpi_string interface_name)
+{
+       acpi_status status;
+       struct acpi_interface_info *interface_info;
+
+       /* Parameter validation */
+
+       if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+               return (AE_BAD_PARAMETER);
+       }
+
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+       /* Check if the interface name is already in the global list */
+
+       interface_info = acpi_ut_get_interface(interface_name);
+       if (interface_info) {
+               /*
+                * The interface already exists in the list. This is OK if the
+                * interface has been marked invalid -- just clear the bit.
+                */
+               if (interface_info->flags & ACPI_OSI_INVALID) {
+                       interface_info->flags &= ~ACPI_OSI_INVALID;
+                       status = AE_OK;
+               } else {
+                       status = AE_ALREADY_EXISTS;
+               }
+       } else {
+               /* New interface name, install into the global list */
+
+               status = acpi_ut_install_interface(interface_name);
+       }
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+       return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_remove_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to remove
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove an _OSI interface from the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_remove_interface(acpi_string interface_name)
+{
+       acpi_status status;
+
+       /* Parameter validation */
+
+       if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+               return (AE_BAD_PARAMETER);
+       }
+
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+       status = acpi_ut_remove_interface(interface_name);
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+       return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_install_interface_handler
+ *
+ * PARAMETERS:  Handler             - The _OSI interface handler to install
+ *                                    NULL means "remove existing handler"
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for the predefined _OSI ACPI method.
+ *              invoked during execution of the internal implementation of
+ *              _OSI. A NULL handler simply removes any existing handler.
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
+{
+       acpi_status status = AE_OK;
+
+       (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+       if (handler && acpi_gbl_interface_handler) {
+               status = AE_ALREADY_EXISTS;
+       } else {
+               acpi_gbl_interface_handler = handler;
+       }
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+       return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
+#endif                         /* !ACPI_ASL_COMPILER */
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
new file mode 100644 (file)
index 0000000..6f12e31
--- /dev/null
@@ -0,0 +1,415 @@
+/*******************************************************************************
+ *
+ * Module Name: utxferror - Various error/warning output functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utxferror")
+
+/*
+ * This module is used for the in-kernel ACPICA as well as the ACPICA
+ * tools/applications.
+ *
+ * For the i_aSL compiler case, the output is redirected to stderr so that
+ * any of the various ACPI errors and warnings do not appear in the output
+ * files, for either the compiler or disassembler portions of the tool.
+ */
+#ifdef ACPI_ASL_COMPILER
+#include <stdio.h>
+extern FILE *acpi_gbl_output_file;
+
+#define ACPI_MSG_REDIRECT_BEGIN \
+       FILE                            *output_file = acpi_gbl_output_file; \
+       acpi_os_redirect_output (stderr);
+
+#define ACPI_MSG_REDIRECT_END \
+       acpi_os_redirect_output (output_file);
+
+#else
+/*
+ * non-i_aSL case - no redirection, nothing to do
+ */
+#define ACPI_MSG_REDIRECT_BEGIN
+#define ACPI_MSG_REDIRECT_END
+#endif
+/*
+ * Common message prefixes
+ */
+#define ACPI_MSG_ERROR          "ACPI Error: "
+#define ACPI_MSG_EXCEPTION      "ACPI Exception: "
+#define ACPI_MSG_WARNING        "ACPI Warning: "
+#define ACPI_MSG_INFO           "ACPI: "
+/*
+ * Common message suffix
+ */
+#define ACPI_MSG_SUFFIX \
+       acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Error" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_error(const char *module_name, u32 line_number, const char *format, ...)
+{
+       va_list arg_list;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_ERROR);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+
+       ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_error)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_exception
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Status              - Status to be formatted
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Exception" message with module/line/version info
+ *              and decoded acpi_status.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_exception(const char *module_name,
+              u32 line_number, acpi_status status, const char *format, ...)
+{
+       va_list arg_list;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
+                      acpi_format_exception(status));
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+
+       ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_exception)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_warning
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Warning" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
+{
+       va_list arg_list;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_WARNING);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+
+       ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_warning)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_info
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print generic "ACPI:" information message. There is no
+ *              module/line/version info in order to keep the message simple.
+ *
+ * TBD: module_name and line_number args are not needed, should be removed.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_info(const char *module_name, u32 line_number, const char *format, ...)
+{
+       va_list arg_list;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_INFO);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       acpi_os_printf("\n");
+       va_end(arg_list);
+
+       ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_info)
+
+/*
+ * The remainder of this module contains internal error functions that may
+ * be configured out.
+ */
+#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_warning
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              Pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              Format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ *              only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of error
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+                          u32 line_number,
+                          char *pathname,
+                          u8 node_flags, const char *format, ...)
+{
+       va_list arg_list;
+
+       /*
+        * Warning messages for this method/object will be disabled after the
+        * first time a validation fails or an object is successfully repaired.
+        */
+       if (node_flags & ANOBJ_EVALUATED) {
+               return;
+       }
+
+       acpi_os_printf(ACPI_MSG_WARNING "For %s: ", pathname);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_info
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              Pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              Format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Info messages for the predefined validation module. Messages
+ *              are only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+                       u32 line_number,
+                       char *pathname, u8 node_flags, const char *format, ...)
+{
+       va_list arg_list;
+
+       /*
+        * Warning messages for this method/object will be disabled after the
+        * first time a validation fails or an object is successfully repaired.
+        */
+       if (node_flags & ANOBJ_EVALUATED) {
+               return;
+       }
+
+       acpi_os_printf(ACPI_MSG_INFO "For %s: ", pathname);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_namespace_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              internal_name       - Name or path of the namespace node
+ *              lookup_status       - Exception code from NS lookup
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the NS node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_namespace_error(const char *module_name,
+                       u32 line_number,
+                       const char *internal_name, acpi_status lookup_status)
+{
+       acpi_status status;
+       u32 bad_name;
+       char *name = NULL;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_ERROR);
+
+       if (lookup_status == AE_BAD_CHARACTER) {
+
+               /* There is a non-ascii character in the name */
+
+               ACPI_MOVE_32_TO_32(&bad_name,
+                                  ACPI_CAST_PTR(u32, internal_name));
+               acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
+       } else {
+               /* Convert path to external format */
+
+               status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
+                                                 internal_name, NULL, &name);
+
+               /* Print target name */
+
+               if (ACPI_SUCCESS(status)) {
+                       acpi_os_printf("[%s]", name);
+               } else {
+                       acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
+               }
+
+               if (name) {
+                       ACPI_FREE(name);
+               }
+       }
+
+       acpi_os_printf(" Namespace lookup failure, %s",
+                      acpi_format_exception(lookup_status));
+
+       ACPI_MSG_SUFFIX;
+       ACPI_MSG_REDIRECT_END;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_method_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Message             - Error message to use on failure
+ *              prefix_node         - Prefix relative to the path
+ *              Path                - Path to the node (optional)
+ *              method_status       - Execution status
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_method_error(const char *module_name,
+                    u32 line_number,
+                    const char *message,
+                    struct acpi_namespace_node *prefix_node,
+                    const char *path, acpi_status method_status)
+{
+       acpi_status status;
+       struct acpi_namespace_node *node = prefix_node;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_ERROR);
+
+       if (path) {
+               status =
+                   acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+                                    &node);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("[Could not get node by pathname]");
+               }
+       }
+
+       acpi_ns_print_node_pathname(node, message);
+       acpi_os_printf(", %s", acpi_format_exception(method_status));
+
+       ACPI_MSG_SUFFIX;
+       ACPI_MSG_REDIRECT_END;
+}
+
+#endif                         /* ACPI_NO_ERROR_MESSAGES */
index 98417201e9ce3881257354e7c2a360ee019a4e39..95649d373071ac93d14bbbb478db1ab4a8cdb801 100644 (file)
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 
 #define PREFIX "ACPI: "
 
@@ -98,13 +95,12 @@ enum {
         * due to bad math.
         */
        ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
+       ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
 };
 
 struct acpi_battery {
        struct mutex lock;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply bat;
-#endif
        struct acpi_device *device;
        unsigned long update_time;
        int rate_now;
@@ -141,7 +137,6 @@ inline int acpi_battery_present(struct acpi_battery *battery)
        return battery->device->status.battery_present;
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int acpi_battery_technology(struct acpi_battery *battery)
 {
        if (!strcasecmp("NiCd", battery->type))
@@ -186,6 +181,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
                                     enum power_supply_property psp,
                                     union power_supply_propval *val)
 {
+       int ret = 0;
        struct acpi_battery *battery = to_acpi_battery(psy);
 
        if (acpi_battery_present(battery)) {
@@ -214,26 +210,44 @@ static int acpi_battery_get_property(struct power_supply *psy,
                val->intval = battery->cycle_count;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-               val->intval = battery->design_voltage * 1000;
+               if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->design_voltage * 1000;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = battery->voltage_now * 1000;
+               if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->voltage_now * 1000;
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
        case POWER_SUPPLY_PROP_POWER_NOW:
-               val->intval = battery->rate_now * 1000;
+               if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->rate_now * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
        case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-               val->intval = battery->design_capacity * 1000;
+               if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->design_capacity * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
        case POWER_SUPPLY_PROP_ENERGY_FULL:
-               val->intval = battery->full_charge_capacity * 1000;
+               if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->full_charge_capacity * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_NOW:
        case POWER_SUPPLY_PROP_ENERGY_NOW:
-               val->intval = battery->capacity_now * 1000;
+               if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->capacity_now * 1000;
                break;
        case POWER_SUPPLY_PROP_MODEL_NAME:
                val->strval = battery->model_number;
@@ -245,9 +259,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
                val->strval = battery->serial_number;
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
-       return 0;
+       return ret;
 }
 
 static enum power_supply_property charge_battery_props[] = {
@@ -281,7 +295,6 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
-#endif
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -412,6 +425,8 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
                result = extract_package(battery, buffer.pointer,
                                info_offsets, ARRAY_SIZE(info_offsets));
        kfree(buffer.pointer);
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+               battery->full_charge_capacity = battery->design_capacity;
        return result;
 }
 
@@ -448,6 +463,10 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
            battery->rate_now != -1)
                battery->rate_now = abs((s16)battery->rate_now);
 
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
+           && battery->capacity_now >= 0 && battery->capacity_now <= 100)
+               battery->capacity_now = (battery->capacity_now *
+                               battery->full_charge_capacity) / 100;
        return result;
 }
 
@@ -492,7 +511,6 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
        return acpi_battery_set_alarm(battery);
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -552,7 +570,6 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
        power_supply_unregister(&battery->bat);
        battery->bat.dev = NULL;
 }
-#endif
 
 static void acpi_battery_quirks(struct acpi_battery *battery)
 {
@@ -561,6 +578,33 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
        }
 }
 
+/*
+ * According to the ACPI spec, some kinds of primary batteries can
+ * report percentage battery remaining capacity directly to OS.
+ * In this case, it reports the Last Full Charged Capacity == 100
+ * and BatteryPresentRate == 0xFFFFFFFF.
+ *
+ * Now we found some battery reports percentage remaining capacity
+ * even if it's rechargeable.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15979
+ *
+ * Handle this correctly so that they won't break userspace.
+ */
+static void acpi_battery_quirks2(struct acpi_battery *battery)
+{
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+               return ;
+
+        if (battery->full_charge_capacity == 100 &&
+            battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+            battery->capacity_now >=0 && battery->capacity_now <= 100) {
+               set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
+               battery->full_charge_capacity = battery->design_capacity;
+               battery->capacity_now = (battery->capacity_now *
+                               battery->full_charge_capacity) / 100;
+       }
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
        int result, old_present = acpi_battery_present(battery);
@@ -568,9 +612,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
        if (result)
                return result;
        if (!acpi_battery_present(battery)) {
-#ifdef CONFIG_ACPI_SYSFS_POWER
                sysfs_remove_battery(battery);
-#endif
                battery->update_time = 0;
                return 0;
        }
@@ -582,11 +624,11 @@ static int acpi_battery_update(struct acpi_battery *battery)
                acpi_battery_quirks(battery);
                acpi_battery_init_alarm(battery);
        }
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (!battery->bat.dev)
                sysfs_add_battery(battery);
-#endif
-       return acpi_battery_get_state(battery);
+       result = acpi_battery_get_state(battery);
+       acpi_battery_quirks2(battery);
+       return result;
 }
 
 /* --------------------------------------------------------------------------
@@ -867,26 +909,20 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
 static void acpi_battery_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_battery *battery = acpi_driver_data(device);
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct device *old;
-#endif
 
        if (!battery)
                return;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        old = battery->bat.dev;
-#endif
        acpi_battery_update(battery);
        acpi_bus_generate_proc_event(device, event,
                                     acpi_battery_present(battery));
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
-#ifdef CONFIG_ACPI_SYSFS_POWER
        /* acpi_battery_update could remove power_supply object */
        if (old && battery->bat.dev)
                power_supply_changed(&battery->bat);
-#endif
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -934,9 +970,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_remove_fs(device);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
        sysfs_remove_battery(battery);
-#endif
        mutex_destroy(&battery->lock);
        kfree(battery);
        return 0;
index 310e3b9749cbbacdabb3c03d288a6b42874aa41b..d68bd61072bb797e3e7f0413d6b97a9650f99222 100644 (file)
@@ -935,6 +935,12 @@ static int __init acpi_bus_init(void)
                goto error1;
        }
 
+       /*
+        * _PDC control method may load dynamic SSDT tables,
+        * and we need to install the table handler before that.
+        */
+       acpi_sysfs_init();
+
        acpi_early_processor_set_pdc();
 
        /*
@@ -1026,7 +1032,6 @@ static int __init acpi_init(void)
        acpi_scan_init();
        acpi_ec_init();
        acpi_power_init();
-       acpi_sysfs_init();
        acpi_debugfs_init();
        acpi_sleep_proc_init();
        acpi_wakeup_device_init();
index 1575a9b51f1d9e1dfb0e16efb65bf31f60bcb506..71ef9cd0735f2fadd8c76d67cee4029bc72b1ce1 100644 (file)
@@ -338,7 +338,8 @@ static int acpi_button_add(struct acpi_device *device)
 {
        struct acpi_button *button;
        struct input_dev *input;
-       char *hid, *name, *class;
+       const char *hid = acpi_device_hid(device);
+       char *name, *class;
        int error;
 
        button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
@@ -353,7 +354,6 @@ static int acpi_button_add(struct acpi_device *device)
                goto err_free_button;
        }
 
-       hid = acpi_device_hid(device);
        name = acpi_device_name(device);
        class = acpi_device_class(device);
 
index 3fe29e992be8aa2cd324f02696388862319327e2..81514a4918cc11ee1313b234aec2daa6d6b0765b 100644 (file)
@@ -725,6 +725,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
                        complete_dock(ds);
                        dock_event(ds, event, DOCK_EVENT);
                        dock_lock(ds, 1);
+                       acpi_update_gpes();
                        break;
                }
                if (dock_present(ds) || dock_in_progress(ds))
@@ -929,7 +930,7 @@ static struct attribute_group dock_attribute_group = {
  * allocated and initialize a new dock station device.  Find all devices
  * that are on the dock station, and register for dock event notifications.
  */
-static int dock_add(acpi_handle handle)
+static int __init dock_add(acpi_handle handle)
 {
        int ret, id;
        struct dock_station ds, *dock_station;
@@ -1023,7 +1024,7 @@ static int dock_remove(struct dock_station *ds)
  *
  * This is called by acpi_walk_namespace to look for dock stations.
  */
-static acpi_status
+static __init acpi_status
 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        if (is_dock(handle))
@@ -1032,7 +1033,7 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-static acpi_status
+static __init acpi_status
 find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        /* If bay is a dock, it's already handled */
index f31291ba94d092ec3a9cc9b6a51fc0383ee1d56a..372ff80b7b0c93f88f6f2ea9e100c0fdd2aaf6bf 100644 (file)
@@ -83,6 +83,11 @@ enum {
        EC_FLAGS_BLOCKED,               /* Transactions are blocked */
 };
 
+/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
+static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
+module_param(ec_delay, uint, 0644);
+MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
+
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
 typedef int (*acpi_ec_query_func) (void *data);
@@ -210,7 +215,7 @@ static int ec_poll(struct acpi_ec *ec)
        int repeat = 2; /* number of command restarts */
        while (repeat--) {
                unsigned long delay = jiffies +
-                       msecs_to_jiffies(ACPI_EC_DELAY);
+                       msecs_to_jiffies(ec_delay);
                do {
                        /* don't sleep with disabled interrupts */
                        if (EC_FLAGS_MSI || irqs_disabled()) {
@@ -265,7 +270,7 @@ static int ec_check_ibf0(struct acpi_ec *ec)
 
 static int ec_wait_ibf0(struct acpi_ec *ec)
 {
-       unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+       unsigned long delay = jiffies + msecs_to_jiffies(ec_delay);
        /* interrupt wait manually if GPE mode is not active */
        while (time_before(jiffies, delay))
                if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
index d94d2953c9740f34675eeb576e00e74ee621bfd2..60049080c86985755109074a26a260e660ae7a72 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
@@ -118,122 +116,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = {
        .set_cur_state = fan_set_cur_state,
 };
 
-/* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_fan_dir;
-
-static int acpi_fan_read_state(struct seq_file *seq, void *offset)
-{
-       struct acpi_device *device = seq->private;
-       int state = 0;
-
-
-       if (device) {
-               if (acpi_bus_get_power(device->handle, &state))
-                       seq_printf(seq, "status:                  ERROR\n");
-               else
-                       seq_printf(seq, "status:                  %s\n",
-                                  !state ? "on" : "off");
-       }
-       return 0;
-}
-
-static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_fan_read_state, PDE(inode)->data);
-}
-
-static ssize_t
-acpi_fan_write_state(struct file *file, const char __user * buffer,
-                    size_t count, loff_t * ppos)
-{
-       int result = 0;
-       struct seq_file *m = file->private_data;
-       struct acpi_device *device = m->private;
-       char state_string[3] = { '\0' };
-
-       if (count > sizeof(state_string) - 1)
-               return -EINVAL;
-
-       if (copy_from_user(state_string, buffer, count))
-               return -EFAULT;
-
-       state_string[count] = '\0';
-       if ((state_string[0] < '0') || (state_string[0] > '3'))
-               return -EINVAL;
-       if (state_string[1] == '\n')
-               state_string[1] = '\0';
-       if (state_string[1] != '\0')
-               return -EINVAL;
-
-       result = acpi_bus_set_power(device->handle,
-                                   simple_strtoul(state_string, NULL, 0));
-       if (result)
-               return result;
-
-       return count;
-}
-
-static const struct file_operations acpi_fan_state_ops = {
-       .open = acpi_fan_state_open_fs,
-       .read = seq_read,
-       .write = acpi_fan_write_state,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
-};
-
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *entry = NULL;
-
-
-       if (!device)
-               return -EINVAL;
-
-       if (!acpi_device_dir(device)) {
-               acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
-                                                    acpi_fan_dir);
-               if (!acpi_device_dir(device))
-                       return -ENODEV;
-       }
-
-       /* 'status' [R/W] */
-       entry = proc_create_data(ACPI_FAN_FILE_STATE,
-                                S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
-                                &acpi_fan_state_ops,
-                                device);
-       if (!entry)
-               return -ENODEV;
-       return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
-
-       if (acpi_device_dir(device)) {
-               remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
-               remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
-               acpi_device_dir(device) = NULL;
-       }
-
-       return 0;
-}
-#else
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
-       return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
-       return 0;
-}
-#endif
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -284,10 +166,6 @@ static int acpi_fan_add(struct acpi_device *device)
                dev_err(&device->dev, "Failed to create sysfs link "
                        "'device'\n");
 
-       result = acpi_fan_add_fs(device);
-       if (result)
-               goto end;
-
        printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
               acpi_device_name(device), acpi_device_bid(device),
               !device->power.state ? "on" : "off");
@@ -303,7 +181,6 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        if (!device || !cdev)
                return -EINVAL;
 
-       acpi_fan_remove_fs(device);
        sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
        sysfs_remove_link(&cdev->device.kobj, "device");
        thermal_cooling_device_unregister(cdev);
@@ -347,19 +224,9 @@ static int __init acpi_fan_init(void)
 {
        int result = 0;
 
-#ifdef CONFIG_ACPI_PROCFS
-       acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
-       if (!acpi_fan_dir)
-               return -ENODEV;
-#endif
-
        result = acpi_bus_register_driver(&acpi_fan_driver);
-       if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
-               remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
+       if (result < 0)
                return -ENODEV;
-       }
 
        return 0;
 }
@@ -369,10 +236,6 @@ static void __exit acpi_fan_exit(void)
 
        acpi_bus_unregister_driver(&acpi_fan_driver);
 
-#ifdef CONFIG_ACPI_PROCFS
-       remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
-
        return;
 }
 
index 65b25a303b86e495d3f539e94d6a912ae3252325..966feddf6b1ba29457fde294223018ad23666e39 100644 (file)
@@ -95,8 +95,25 @@ struct acpi_res_list {
 static LIST_HEAD(resource_list_head);
 static DEFINE_SPINLOCK(acpi_res_lock);
 
+/*
+ * This list of permanent mappings is for memory that may be accessed from
+ * interrupt context, where we can't do the ioremap().
+ */
+struct acpi_ioremap {
+       struct list_head list;
+       void __iomem *virt;
+       acpi_physical_address phys;
+       acpi_size size;
+       struct kref ref;
+};
+
+static LIST_HEAD(acpi_ioremaps);
+static DEFINE_SPINLOCK(acpi_ioremap_lock);
+
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
-static char osi_additional_string[OSI_STRING_LENGTH_MAX];
+static char osi_setup_string[OSI_STRING_LENGTH_MAX];
+
+static void __init acpi_osi_setup_late(void);
 
 /*
  * The story of _OSI(Linux)
@@ -138,6 +155,20 @@ static struct osi_linux {
        unsigned int    known:1;
 } osi_linux = { 0, 0, 0, 0};
 
+static u32 acpi_osi_handler(acpi_string interface, u32 supported)
+{
+       if (!strcmp("Linux", interface)) {
+
+               printk(KERN_NOTICE FW_BUG PREFIX
+                       "BIOS _OSI(Linux) query %s%s\n",
+                       osi_linux.enable ? "honored" : "ignored",
+                       osi_linux.cmdline ? " via cmdline" :
+                       osi_linux.dmi ? " via DMI" : "");
+       }
+
+       return supported;
+}
+
 static void __init acpi_request_region (struct acpi_generic_address *addr,
        unsigned int length, char *desc)
 {
@@ -185,36 +216,6 @@ static int __init acpi_reserve_resources(void)
 }
 device_initcall(acpi_reserve_resources);
 
-acpi_status __init acpi_os_initialize(void)
-{
-       return AE_OK;
-}
-
-acpi_status acpi_os_initialize1(void)
-{
-       kacpid_wq = create_workqueue("kacpid");
-       kacpi_notify_wq = create_workqueue("kacpi_notify");
-       kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
-       BUG_ON(!kacpid_wq);
-       BUG_ON(!kacpi_notify_wq);
-       BUG_ON(!kacpi_hotplug_wq);
-       return AE_OK;
-}
-
-acpi_status acpi_os_terminate(void)
-{
-       if (acpi_irq_handler) {
-               acpi_os_remove_interrupt_handler(acpi_irq_irq,
-                                                acpi_irq_handler);
-       }
-
-       destroy_workqueue(kacpid_wq);
-       destroy_workqueue(kacpi_notify_wq);
-       destroy_workqueue(kacpi_hotplug_wq);
-
-       return AE_OK;
-}
-
 void acpi_os_printf(const char *fmt, ...)
 {
        va_list args;
@@ -260,29 +261,135 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
        }
 }
 
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup(acpi_physical_address phys, acpi_size size)
+{
+       struct acpi_ioremap *map;
+
+       list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+               if (map->phys <= phys &&
+                   phys + size <= map->phys + map->size)
+                       return map;
+
+       return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static void __iomem *
+acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
+{
+       struct acpi_ioremap *map;
+
+       map = acpi_map_lookup(phys, size);
+       if (map)
+               return map->virt + (phys - map->phys);
+
+       return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
+{
+       struct acpi_ioremap *map;
+
+       list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+               if (map->virt <= virt &&
+                   virt + size <= map->virt + map->size)
+                       return map;
+
+       return NULL;
+}
+
 void __iomem *__init_refok
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
+       struct acpi_ioremap *map, *tmp_map;
+       unsigned long flags, pg_sz;
+       void __iomem *virt;
+       phys_addr_t pg_off;
+
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
                return NULL;
        }
-       if (acpi_gbl_permanent_mmap)
-               /*
-               * ioremap checks to ensure this is in reserved space
-               */
-               return ioremap((unsigned long)phys, size);
-       else
+
+       if (!acpi_gbl_permanent_mmap)
                return __acpi_map_table((unsigned long)phys, size);
+
+       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       if (!map)
+               return NULL;
+
+       pg_off = round_down(phys, PAGE_SIZE);
+       pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
+       virt = ioremap(pg_off, pg_sz);
+       if (!virt) {
+               kfree(map);
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&map->list);
+       map->virt = virt;
+       map->phys = pg_off;
+       map->size = pg_sz;
+       kref_init(&map->ref);
+
+       spin_lock_irqsave(&acpi_ioremap_lock, flags);
+       /* Check if page has already been mapped. */
+       tmp_map = acpi_map_lookup(phys, size);
+       if (tmp_map) {
+               kref_get(&tmp_map->ref);
+               spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+               iounmap(map->virt);
+               kfree(map);
+               return tmp_map->virt + (phys - tmp_map->phys);
+       }
+       list_add_tail_rcu(&map->list, &acpi_ioremaps);
+       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+       return map->virt + (phys - map->phys);
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
+static void acpi_kref_del_iomap(struct kref *ref)
+{
+       struct acpi_ioremap *map;
+
+       map = container_of(ref, struct acpi_ioremap, ref);
+       list_del_rcu(&map->list);
+}
+
 void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
 {
-       if (acpi_gbl_permanent_mmap)
-               iounmap(virt);
-       else
+       struct acpi_ioremap *map;
+       unsigned long flags;
+       int del;
+
+       if (!acpi_gbl_permanent_mmap) {
                __acpi_unmap_table(virt, size);
+               return;
+       }
+
+       spin_lock_irqsave(&acpi_ioremap_lock, flags);
+       map = acpi_map_lookup_virt(virt, size);
+       if (!map) {
+               spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+               printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
+               dump_stack();
+               return;
+       }
+
+       del = kref_put(&map->ref, acpi_kref_del_iomap);
+       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+       if (!del)
+               return;
+
+       synchronize_rcu();
+       iounmap(map->virt);
+       kfree(map);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
@@ -292,6 +399,44 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
                __acpi_unmap_table(virt, size);
 }
 
+int acpi_os_map_generic_address(struct acpi_generic_address *addr)
+{
+       void __iomem *virt;
+
+       if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return 0;
+
+       if (!addr->address || !addr->bit_width)
+               return -EINVAL;
+
+       virt = acpi_os_map_memory(addr->address, addr->bit_width / 8);
+       if (!virt)
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
+
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
+{
+       void __iomem *virt;
+       unsigned long flags;
+       acpi_size size = addr->bit_width / 8;
+
+       if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return;
+
+       if (!addr->address || !addr->bit_width)
+               return;
+
+       spin_lock_irqsave(&acpi_ioremap_lock, flags);
+       virt = acpi_map_vaddr_lookup(addr->address, size);
+       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+       acpi_os_unmap_memory(virt, size);
+}
+EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
+
 #ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
@@ -495,8 +640,15 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
 {
        u32 dummy;
        void __iomem *virt_addr;
-
-       virt_addr = ioremap(phys_addr, width);
+       int size = width / 8, unmap = 0;
+
+       rcu_read_lock();
+       virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+       rcu_read_unlock();
+       if (!virt_addr) {
+               virt_addr = ioremap(phys_addr, size);
+               unmap = 1;
+       }
        if (!value)
                value = &dummy;
 
@@ -514,7 +666,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
                BUG();
        }
 
-       iounmap(virt_addr);
+       if (unmap)
+               iounmap(virt_addr);
 
        return AE_OK;
 }
@@ -523,8 +676,15 @@ acpi_status
 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 {
        void __iomem *virt_addr;
-
-       virt_addr = ioremap(phys_addr, width);
+       int size = width / 8, unmap = 0;
+
+       rcu_read_lock();
+       virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+       rcu_read_unlock();
+       if (!virt_addr) {
+               virt_addr = ioremap(phys_addr, size);
+               unmap = 1;
+       }
 
        switch (width) {
        case 8:
@@ -540,16 +700,18 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
                BUG();
        }
 
-       iounmap(virt_addr);
+       if (unmap)
+               iounmap(virt_addr);
 
        return AE_OK;
 }
 
 acpi_status
 acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
-                              u32 *value, u32 width)
+                              u64 *value, u32 width)
 {
        int result, size;
+       u32 value32;
 
        if (!value)
                return AE_BAD_PARAMETER;
@@ -570,7 +732,8 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
 
        result = raw_pci_read(pci_id->segment, pci_id->bus,
                                PCI_DEVFN(pci_id->device, pci_id->function),
-                               reg, size, value);
+                               reg, size, &value32);
+       *value = value32;
 
        return (result ? AE_ERROR : AE_OK);
 }
@@ -602,74 +765,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
        return (result ? AE_ERROR : AE_OK);
 }
 
-/* TODO: Change code to take advantage of driver model more */
-static void acpi_os_derive_pci_id_2(acpi_handle rhandle,       /* upper bound  */
-                                   acpi_handle chandle,        /* current node */
-                                   struct acpi_pci_id **id,
-                                   int *is_bridge, u8 * bus_number)
-{
-       acpi_handle handle;
-       struct acpi_pci_id *pci_id = *id;
-       acpi_status status;
-       unsigned long long temp;
-       acpi_object_type type;
-
-       acpi_get_parent(chandle, &handle);
-       if (handle != rhandle) {
-               acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
-                                       bus_number);
-
-               status = acpi_get_type(handle, &type);
-               if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
-                       return;
-
-               status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
-                                         &temp);
-               if (ACPI_SUCCESS(status)) {
-                       u32 val;
-                       pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
-                       pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
-
-                       if (*is_bridge)
-                               pci_id->bus = *bus_number;
-
-                       /* any nicer way to get bus number of bridge ? */
-                       status =
-                           acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
-                                                          8);
-                       if (ACPI_SUCCESS(status)
-                           && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
-                               status =
-                                   acpi_os_read_pci_configuration(pci_id, 0x18,
-                                                                  &val, 8);
-                               if (!ACPI_SUCCESS(status)) {
-                                       /* Certainly broken...  FIX ME */
-                                       return;
-                               }
-                               *is_bridge = 1;
-                               pci_id->bus = val;
-                               status =
-                                   acpi_os_read_pci_configuration(pci_id, 0x19,
-                                                                  &val, 8);
-                               if (ACPI_SUCCESS(status)) {
-                                       *bus_number = val;
-                               }
-                       } else
-                               *is_bridge = 0;
-               }
-       }
-}
-
-void acpi_os_derive_pci_id(acpi_handle rhandle,        /* upper bound  */
-                          acpi_handle chandle, /* current node */
-                          struct acpi_pci_id **id)
-{
-       int is_bridge = 1;
-       u8 bus_number = (*id)->bus;
-
-       acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
-}
-
 static void acpi_os_execute_deferred(struct work_struct *work)
 {
        struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
@@ -779,16 +874,6 @@ void acpi_os_wait_events_complete(void *context)
 
 EXPORT_SYMBOL(acpi_os_wait_events_complete);
 
-/*
- * Allocate the memory for a spinlock and initialize it.
- */
-acpi_status acpi_os_create_lock(acpi_spinlock * handle)
-{
-       spin_lock_init(*handle);
-
-       return AE_OK;
-}
-
 /*
  * Deallocate the memory for a spinlock.
  */
@@ -977,6 +1062,12 @@ static void __init set_osi_linux(unsigned int enable)
                printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
                        enable ? "Add": "Delet");
        }
+
+       if (osi_linux.enable)
+               acpi_osi_setup("Linux");
+       else
+               acpi_osi_setup("!Linux");
+
        return;
 }
 
@@ -1011,21 +1102,33 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
  * string starting with '!' disables that string
  * otherwise string is added to list, augmenting built-in strings
  */
-int __init acpi_osi_setup(char *str)
+static void __init acpi_osi_setup_late(void)
 {
-       if (str == NULL || *str == '\0') {
-               printk(KERN_INFO PREFIX "_OSI method disabled\n");
-               acpi_gbl_create_osi_method = FALSE;
-       } else if (!strcmp("!Linux", str)) {
+       char *str = osi_setup_string;
+
+       if (*str == '\0')
+               return;
+
+       if (!strcmp("!Linux", str)) {
                acpi_cmdline_osi_linux(0);      /* !enable */
        } else if (*str == '!') {
-               if (acpi_osi_invalidate(++str) == AE_OK)
+               if (acpi_remove_interface(++str) == AE_OK)
                        printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
        } else if (!strcmp("Linux", str)) {
                acpi_cmdline_osi_linux(1);      /* enable */
-       } else if (*osi_additional_string == '\0') {
-               strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
-               printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+       } else {
+               if (acpi_install_interface(str) == AE_OK)
+                       printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+       }
+}
+
+int __init acpi_osi_setup(char *str)
+{
+       if (str == NULL || *str == '\0') {
+               printk(KERN_INFO PREFIX "_OSI method disabled\n");
+               acpi_gbl_create_osi_method = FALSE;
+       } else {
+               strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
        }
 
        return 1;
@@ -1152,21 +1255,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
 }
 EXPORT_SYMBOL(acpi_check_region);
 
-int acpi_check_mem_region(resource_size_t start, resource_size_t n,
-                     const char *name)
-{
-       struct resource res = {
-               .start = start,
-               .end   = start + n - 1,
-               .name  = name,
-               .flags = IORESOURCE_MEM,
-       };
-
-       return acpi_check_resource_conflict(&res);
-
-}
-EXPORT_SYMBOL(acpi_check_mem_region);
-
 /*
  * Let drivers know whether the resource checks are effective
  */
@@ -1282,38 +1370,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
        return (AE_OK);
 }
 
-/******************************************************************************
- *
- * FUNCTION:    acpi_os_validate_interface
- *
- * PARAMETERS:  interface           - Requested interface to be validated
- *
- * RETURN:      AE_OK if interface is supported, AE_SUPPORT otherwise
- *
- * DESCRIPTION: Match an interface string to the interfaces supported by the
- *              host. Strings originate from an AML call to the _OSI method.
- *
- *****************************************************************************/
-
-acpi_status
-acpi_os_validate_interface (char *interface)
-{
-       if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
-               return AE_OK;
-       if (!strcmp("Linux", interface)) {
-
-               printk(KERN_NOTICE PREFIX
-                       "BIOS _OSI(Linux) query %s%s\n",
-                       osi_linux.enable ? "honored" : "ignored",
-                       osi_linux.cmdline ? " via cmdline" :
-                       osi_linux.dmi ? " via DMI" : "");
-
-               if (osi_linux.enable)
-                       return AE_OK;
-       }
-       return AE_SUPPORT;
-}
-
 static inline int acpi_res_list_add(struct acpi_res_list *res)
 {
        struct acpi_res_list *res_list_elem;
@@ -1462,5 +1518,46 @@ acpi_os_validate_address (
        }
        return AE_OK;
 }
-
 #endif
+
+acpi_status __init acpi_os_initialize(void)
+{
+       acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+       acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+       acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
+       acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
+
+       return AE_OK;
+}
+
+acpi_status acpi_os_initialize1(void)
+{
+       kacpid_wq = create_workqueue("kacpid");
+       kacpi_notify_wq = create_workqueue("kacpi_notify");
+       kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
+       BUG_ON(!kacpid_wq);
+       BUG_ON(!kacpi_notify_wq);
+       BUG_ON(!kacpi_hotplug_wq);
+       acpi_install_interface_handler(acpi_osi_handler);
+       acpi_osi_setup_late();
+       return AE_OK;
+}
+
+acpi_status acpi_os_terminate(void)
+{
+       if (acpi_irq_handler) {
+               acpi_os_remove_interrupt_handler(acpi_irq_irq,
+                                                acpi_irq_handler);
+       }
+
+       acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block);
+       acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);
+       acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+       acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+
+       destroy_workqueue(kacpid_wq);
+       destroy_workqueue(kacpi_notify_wq);
+       destroy_workqueue(kacpi_hotplug_wq);
+
+       return AE_OK;
+}
index e4804fb05e233d8dae18aacce47835a06dca16ec..f907cfbfa13c89cc0d173161b14e4f176d62296f 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
index 8d47a5846aebc192479d943b0a4826030b5a4344..9ff80a7e9f6ada0aef1c57bea5e3f6b142037de5 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
index 3ba8d1f44a73ed3b234e810f5316f6531e4d6718..96668ad096227add7ca952fd66cb9cf8c80bf20f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
index 844c155aeb0faa558b789fa7a3b680971df8f536..67dedeed144cf82c8e13859e7222b976d0eebb2e 100644 (file)
@@ -80,18 +80,13 @@ static struct acpi_driver acpi_power_driver = {
                },
 };
 
-struct acpi_power_reference {
-       struct list_head node;
-       struct acpi_device *device;
-};
-
 struct acpi_power_resource {
        struct acpi_device * device;
        acpi_bus_id name;
        u32 system_level;
        u32 order;
+       unsigned int ref_count;
        struct mutex resource_lock;
-       struct list_head reference;
 };
 
 static struct list_head acpi_power_resource_list;
@@ -184,101 +179,89 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
        return result;
 }
 
-static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
+static int __acpi_power_on(struct acpi_power_resource *resource)
 {
-       int result = 0;
-       int found = 0;
        acpi_status status = AE_OK;
-       struct acpi_power_resource *resource = NULL;
-       struct list_head *node, *next;
-       struct acpi_power_reference *ref;
 
+       status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       /* Update the power resource's _device_ power state */
+       resource->device->power.state = ACPI_STATE_D0;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
+                         resource->name));
+
+       return 0;
+}
+
+static int acpi_power_on(acpi_handle handle)
+{
+       int result = 0;
+       struct acpi_power_resource *resource = NULL;
 
        result = acpi_power_get_context(handle, &resource);
        if (result)
                return result;
 
        mutex_lock(&resource->resource_lock);
-       list_for_each_safe(node, next, &resource->reference) {
-               ref = container_of(node, struct acpi_power_reference, node);
-               if (dev->handle == ref->device->handle) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n",
-                                 dev->pnp.bus_id, resource->name));
-                       found = 1;
-                       break;
-               }
-       }
 
-       if (!found) {
-               ref = kmalloc(sizeof (struct acpi_power_reference),
-                   irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
-               if (!ref) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n"));
-                       mutex_unlock(&resource->resource_lock);
-                       return -ENOMEM;
-               }
-               list_add_tail(&ref->node, &resource->reference);
-               ref->device = dev;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n",
-                         dev->pnp.bus_id, resource->name));
+       if (resource->ref_count++) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Power resource [%s] already on",
+                                 resource->name));
+       } else {
+               result = __acpi_power_on(resource);
        }
-       mutex_unlock(&resource->resource_lock);
 
-       status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       /* Update the power resource's _device_ power state */
-       resource->device->power.state = ACPI_STATE_D0;
+       mutex_unlock(&resource->resource_lock);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
-                         resource->name));
        return 0;
 }
 
-static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
+static int acpi_power_off_device(acpi_handle handle)
 {
        int result = 0;
        acpi_status status = AE_OK;
        struct acpi_power_resource *resource = NULL;
-       struct list_head *node, *next;
-       struct acpi_power_reference *ref;
 
        result = acpi_power_get_context(handle, &resource);
        if (result)
                return result;
 
        mutex_lock(&resource->resource_lock);
-       list_for_each_safe(node, next, &resource->reference) {
-               ref = container_of(node, struct acpi_power_reference, node);
-               if (dev->handle == ref->device->handle) {
-                       list_del(&ref->node);
-                       kfree(ref);
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n",
-                           dev->pnp.bus_id, resource->name));
-                       break;
-               }
+
+       if (!resource->ref_count) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Power resource [%s] already off",
+                                 resource->name));
+               goto unlock;
        }
 
-       if (!list_empty(&resource->reference)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n",
-                   resource->name));
-               mutex_unlock(&resource->resource_lock);
-               return 0;
+       if (--resource->ref_count) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Power resource [%s] still in use\n",
+                                 resource->name));
+               goto unlock;
        }
-       mutex_unlock(&resource->resource_lock);
 
        status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
+       if (ACPI_FAILURE(status)) {
+               result = -ENODEV;
+       } else {
+               /* Update the power resource's _device_ power state */
+               resource->device->power.state = ACPI_STATE_D3;
 
-       /* Update the power resource's _device_ power state */
-       resource->device->power.state = ACPI_STATE_D3;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Power resource [%s] turned off\n",
+                                 resource->name));
+       }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
-                         resource->name));
+ unlock:
+       mutex_unlock(&resource->resource_lock);
 
-       return 0;
+       return result;
 }
 
 /**
@@ -364,7 +347,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
 
        /* Open power resource */
        for (i = 0; i < dev->wakeup.resources.count; i++) {
-               int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
+               int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
                if (ret) {
                        printk(KERN_ERR PREFIX "Transition power state\n");
                        dev->wakeup.flags.valid = 0;
@@ -420,7 +403,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
        /* Close power resource */
        for (i = 0; i < dev->wakeup.resources.count; i++) {
                int ret = acpi_power_off_device(
-                               dev->wakeup.resources.handles[i], dev);
+                               dev->wakeup.resources.handles[i]);
                if (ret) {
                        printk(KERN_ERR PREFIX "Transition power state\n");
                        dev->wakeup.flags.valid = 0;
@@ -500,7 +483,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
         * (e.g. so the device doesn't lose power while transitioning).
         */
        for (i = 0; i < tl->count; i++) {
-               result = acpi_power_on(tl->handles[i], device);
+               result = acpi_power_on(tl->handles[i]);
                if (result)
                        goto end;
        }
@@ -513,7 +496,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
         * Then we dereference all power resources used in the current list.
         */
        for (i = 0; i < cl->count; i++) {
-               result = acpi_power_off_device(cl->handles[i], device);
+               result = acpi_power_off_device(cl->handles[i]);
                if (result)
                        goto end;
        }
@@ -551,7 +534,6 @@ static int acpi_power_add(struct acpi_device *device)
 
        resource->device = device;
        mutex_init(&resource->resource_lock);
-       INIT_LIST_HEAD(&resource->reference);
        strcpy(resource->name, device->pnp.bus_id);
        strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
@@ -594,22 +576,14 @@ static int acpi_power_add(struct acpi_device *device)
 
 static int acpi_power_remove(struct acpi_device *device, int type)
 {
-       struct acpi_power_resource *resource = NULL;
-       struct list_head *node, *next;
+       struct acpi_power_resource *resource;
 
-
-       if (!device || !acpi_driver_data(device))
+       if (!device)
                return -EINVAL;
 
        resource = acpi_driver_data(device);
-
-       mutex_lock(&resource->resource_lock);
-       list_for_each_safe(node, next, &resource->reference) {
-               struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node);
-               list_del(&ref->node);
-               kfree(ref);
-       }
-       mutex_unlock(&resource->resource_lock);
+       if (!resource)
+               return -EINVAL;
 
        kfree(resource);
 
@@ -619,29 +593,28 @@ static int acpi_power_remove(struct acpi_device *device, int type)
 static int acpi_power_resume(struct acpi_device *device)
 {
        int result = 0, state;
-       struct acpi_power_resource *resource = NULL;
-       struct acpi_power_reference *ref;
+       struct acpi_power_resource *resource;
 
-       if (!device || !acpi_driver_data(device))
+       if (!device)
                return -EINVAL;
 
        resource = acpi_driver_data(device);
+       if (!resource)
+               return -EINVAL;
+
+       mutex_lock(&resource->resource_lock);
 
        result = acpi_power_get_state(device->handle, &state);
        if (result)
-               return result;
+               goto unlock;
 
-       mutex_lock(&resource->resource_lock);
-       if (state == ACPI_POWER_RESOURCE_STATE_OFF &&
-           !list_empty(&resource->reference)) {
-               ref = container_of(resource->reference.next, struct acpi_power_reference, node);
-               mutex_unlock(&resource->resource_lock);
-               result = acpi_power_on(device->handle, ref->device);
-               return result;
-       }
+       if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
+               result = __acpi_power_on(resource);
 
+ unlock:
        mutex_unlock(&resource->resource_lock);
-       return 0;
+
+       return result;
 }
 
 int __init acpi_power_init(void)
index 347eb21b235302d44d0c5e2d768ce3a8870142f2..85e48047d7b0fd8f549fca988f96ed0f1770a9ae 100644 (file)
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
+#ifdef CONFIG_ACPI_PROCFS
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#endif
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/cpuidle.h>
@@ -244,6 +246,7 @@ static int acpi_processor_errata(struct acpi_processor *pr)
        return result;
 }
 
+#ifdef CONFIG_ACPI_PROCFS
 static struct proc_dir_entry *acpi_processor_dir = NULL;
 
 static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
@@ -280,7 +283,16 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
 
        return 0;
 }
-
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+       return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+       return 0;
+}
+#endif
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -842,9 +854,11 @@ static int __init acpi_processor_init(void)
 
        memset(&errata, 0, sizeof(errata));
 
+#ifdef CONFIG_ACPI_PROCFS
        acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
        if (!acpi_processor_dir)
                return -ENOMEM;
+#endif
 
        if (!cpuidle_register_driver(&acpi_idle_driver)) {
                printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
@@ -871,7 +885,9 @@ static int __init acpi_processor_init(void)
 out_cpuidle:
        cpuidle_unregister_driver(&acpi_idle_driver);
 
+#ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
 
        return result;
 }
@@ -891,7 +907,9 @@ static void __exit acpi_processor_exit(void)
 
        cpuidle_unregister_driver(&acpi_idle_driver);
 
+#ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
 
        return;
 }
@@ -899,6 +917,4 @@ static void __exit acpi_processor_exit(void)
 module_init(acpi_processor_init);
 module_exit(acpi_processor_exit);
 
-EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
-
 MODULE_ALIAS("processor");
index f4428e82b352940f7b9f8687c3c242b213d48421..dcb38f8ddfda09142f5962cfcfe38b9aa9fc5570 100644 (file)
@@ -64,7 +64,6 @@
 #define ACPI_PROCESSOR_CLASS            "processor"
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_idle");
-#define ACPI_PROCESSOR_FILE_POWER      "power"
 #define PM_TIMER_TICK_NS               (1000000000ULL/PM_TIMER_FREQUENCY)
 #define C2_OVERHEAD                    1       /* 1us */
 #define C3_OVERHEAD                    1       /* 1us */
@@ -1013,7 +1012,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
                strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
                state->exit_latency = cx->latency;
                state->target_residency = cx->latency * latency_factor;
-               state->power_usage = cx->power;
 
                state->flags = 0;
                switch (cx->type) {
index 953b25fb986968ad47be94d0b8ea000347e4468e..fde49b9b1d99ed04eaf4192473ff7ce3bb913fd6 100644 (file)
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_thermal");
 
-/* --------------------------------------------------------------------------
-                                 Limit Interface
-   -------------------------------------------------------------------------- */
-static int acpi_processor_apply_limit(struct acpi_processor *pr)
-{
-       int result = 0;
-       u16 px = 0;
-       u16 tx = 0;
-
-
-       if (!pr)
-               return -EINVAL;
-
-       if (!pr->flags.limit)
-               return -ENODEV;
-
-       if (pr->flags.throttling) {
-               if (pr->limit.user.tx > tx)
-                       tx = pr->limit.user.tx;
-               if (pr->limit.thermal.tx > tx)
-                       tx = pr->limit.thermal.tx;
-
-               result = acpi_processor_set_throttling(pr, tx, false);
-               if (result)
-                       goto end;
-       }
-
-       pr->limit.state.px = px;
-       pr->limit.state.tx = tx;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Processor [%d] limit set to (P%d:T%d)\n", pr->id,
-                         pr->limit.state.px, pr->limit.state.tx));
-
-      end:
-       if (result)
-               printk(KERN_ERR PREFIX "Unable to set limit\n");
-
-       return result;
-}
-
 #ifdef CONFIG_CPU_FREQ
 
 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it
@@ -107,36 +66,6 @@ static int cpu_has_cpufreq(unsigned int cpu)
        return 1;
 }
 
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
-       if (!cpu_has_cpufreq(cpu))
-               return -ENODEV;
-
-       if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) <
-               CPUFREQ_THERMAL_MAX_STEP) {
-               per_cpu(cpufreq_thermal_reduction_pctg, cpu)++;
-               cpufreq_update_policy(cpu);
-               return 0;
-       }
-
-       return -ERANGE;
-}
-
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
-       if (!cpu_has_cpufreq(cpu))
-               return -ENODEV;
-
-       if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) >
-               (CPUFREQ_THERMAL_MIN_STEP + 1))
-               per_cpu(cpufreq_thermal_reduction_pctg, cpu)--;
-       else
-               per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0;
-       cpufreq_update_policy(cpu);
-       /* We reached max freq again and can leave passive mode */
-       return !per_cpu(cpufreq_thermal_reduction_pctg, cpu);
-}
-
 static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
                                         unsigned long event, void *data)
 {
@@ -238,113 +167,6 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
 
 #endif
 
-int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
-{
-       int result = 0;
-       struct acpi_processor *pr = NULL;
-       struct acpi_device *device = NULL;
-       int tx = 0, max_tx_px = 0;
-
-
-       if ((type < ACPI_PROCESSOR_LIMIT_NONE)
-           || (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
-               return -EINVAL;
-
-       result = acpi_bus_get_device(handle, &device);
-       if (result)
-               return result;
-
-       pr = acpi_driver_data(device);
-       if (!pr)
-               return -ENODEV;
-
-       /* Thermal limits are always relative to the current Px/Tx state. */
-       if (pr->flags.throttling)
-               pr->limit.thermal.tx = pr->throttling.state;
-
-       /*
-        * Our default policy is to only use throttling at the lowest
-        * performance state.
-        */
-
-       tx = pr->limit.thermal.tx;
-
-       switch (type) {
-
-       case ACPI_PROCESSOR_LIMIT_NONE:
-               do {
-                       result = acpi_thermal_cpufreq_decrease(pr->id);
-               } while (!result);
-               tx = 0;
-               break;
-
-       case ACPI_PROCESSOR_LIMIT_INCREMENT:
-               /* if going up: P-states first, T-states later */
-
-               result = acpi_thermal_cpufreq_increase(pr->id);
-               if (!result)
-                       goto end;
-               else if (result == -ERANGE)
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "At maximum performance state\n"));
-
-               if (pr->flags.throttling) {
-                       if (tx == (pr->throttling.state_count - 1))
-                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                                 "At maximum throttling state\n"));
-                       else
-                               tx++;
-               }
-               break;
-
-       case ACPI_PROCESSOR_LIMIT_DECREMENT:
-               /* if going down: T-states first, P-states later */
-
-               if (pr->flags.throttling) {
-                       if (tx == 0) {
-                               max_tx_px = 1;
-                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                                 "At minimum throttling state\n"));
-                       } else {
-                               tx--;
-                               goto end;
-                       }
-               }
-
-               result = acpi_thermal_cpufreq_decrease(pr->id);
-               if (result) {
-                       /*
-                        * We only could get -ERANGE, 1 or 0.
-                        * In the first two cases we reached max freq again.
-                        */
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "At minimum performance state\n"));
-                       max_tx_px = 1;
-               } else
-                       max_tx_px = 0;
-
-               break;
-       }
-
-      end:
-       if (pr->flags.throttling) {
-               pr->limit.thermal.px = 0;
-               pr->limit.thermal.tx = tx;
-
-               result = acpi_processor_apply_limit(pr);
-               if (result)
-                       printk(KERN_ERR PREFIX "Unable to set thermal limit\n");
-
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
-                                 pr->limit.thermal.px, pr->limit.thermal.tx));
-       } else
-               result = 0;
-       if (max_tx_px)
-               return 1;
-       else
-               return result;
-}
-
 int acpi_processor_get_limit_info(struct acpi_processor *pr)
 {
 
index 730863855ed54ebdb49c35cca733bf3a92596c0d..ff3632717c5140bd7c8692e0055b74681ece037c 100644 (file)
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/cpufreq.h>
+#ifdef CONFIG_ACPI_PROCFS
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1214,6 +1216,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
        return result;
 }
 
+#ifdef CONFIG_ACPI_PROCFS
 /* proc interface */
 static int acpi_processor_throttling_seq_show(struct seq_file *seq,
                                              void *offset)
@@ -1322,3 +1325,4 @@ const struct file_operations acpi_processor_throttling_fops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
+#endif
index 4ff76e8174ebf716db53b1d5f2d3bbecd82ad332..e5dbedb16bbfdde815170acbea225b69c65224fd 100644 (file)
 #include <linux/timer.h>
 #include <linux/jiffies.h>
 #include <linux/delay.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 
 #include "sbshc.h"
 
@@ -85,9 +82,7 @@ static const struct acpi_device_id sbs_device_ids[] = {
 MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
 
 struct acpi_battery {
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply bat;
-#endif
        struct acpi_sbs *sbs;
 #ifdef CONFIG_ACPI_PROCFS_POWER
        struct proc_dir_entry *proc_entry;
@@ -120,9 +115,7 @@ struct acpi_battery {
 #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
 
 struct acpi_sbs {
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply charger;
-#endif
        struct acpi_device *device;
        struct acpi_smb_hc *hc;
        struct mutex lock;
@@ -166,7 +159,6 @@ static inline int acpi_battery_scale(struct acpi_battery *battery)
            acpi_battery_ipscale(battery);
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int sbs_get_ac_property(struct power_supply *psy,
                               enum power_supply_property psp,
                               union power_supply_propval *val)
@@ -313,7 +305,6 @@ static enum power_supply_property sbs_energy_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
-#endif
 
 /* --------------------------------------------------------------------------
                             Smart Battery System Management
@@ -449,7 +440,6 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)
        return result;
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -479,7 +469,6 @@ static struct device_attribute alarm_attr = {
        .show = acpi_battery_alarm_show,
        .store = acpi_battery_alarm_store,
 };
-#endif
 
 /* --------------------------------------------------------------------------
                               FS Interface (/proc/acpi)
@@ -798,7 +787,6 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
                        &acpi_battery_state_fops, &acpi_battery_alarm_fops,
                        battery);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
        battery->bat.name = battery->name;
        battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        if (!acpi_battery_mode(battery)) {
@@ -819,7 +807,6 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
                goto end;
        battery->have_sysfs_alarm = 1;
       end:
-#endif
        printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
               ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
               battery->name, battery->present ? "present" : "absent");
@@ -828,17 +815,13 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
 
 static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
 {
-#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER)
        struct acpi_battery *battery = &sbs->battery[id];
-#endif
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (battery->bat.dev) {
                if (battery->have_sysfs_alarm)
                        device_remove_file(battery->bat.dev, &alarm_attr);
                power_supply_unregister(&battery->bat);
        }
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        if (battery->proc_entry)
                acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
@@ -859,14 +842,12 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
        if (result)
                goto end;
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
        sbs->charger.name = "sbs-charger";
        sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
        sbs->charger.properties = sbs_ac_props;
        sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
        sbs->charger.get_property = sbs_get_ac_property;
        power_supply_register(&sbs->device->dev, &sbs->charger);
-#endif
        printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
               ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
               ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
@@ -876,10 +857,8 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
 
 static void acpi_charger_remove(struct acpi_sbs *sbs)
 {
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (sbs->charger.dev)
                power_supply_unregister(&sbs->charger);
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        if (sbs->charger_entry)
                acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
@@ -900,9 +879,7 @@ static void acpi_sbs_callback(void *context)
                                              ACPI_SBS_NOTIFY_STATUS,
                                              sbs->charger_present);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
                kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
-#endif
        }
        if (sbs->manager_present) {
                for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -919,9 +896,7 @@ static void acpi_sbs_callback(void *context)
                                                      ACPI_SBS_NOTIFY_STATUS,
                                                      bat->present);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
                        kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
-#endif
                }
        }
 }
index b23825ecfa372c192ff92fcf79b36c6534332e9c..2b6c21d86b9885571b41679586636fff3b6c53bb 100644 (file)
@@ -26,6 +26,8 @@ extern struct acpi_device *acpi_root;
 
 #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
 
+static const char *dummy_hid = "device";
+
 static LIST_HEAD(acpi_device_list);
 static LIST_HEAD(acpi_bus_id_list);
 DEFINE_MUTEX(acpi_device_lock);
@@ -49,6 +51,9 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
        int count;
        struct acpi_hardware_id *id;
 
+       if (list_empty(&acpi_dev->pnp.ids))
+               return 0;
+
        len = snprintf(modalias, size, "acpi:");
        size -= len;
 
@@ -202,13 +207,15 @@ static int acpi_device_setup_files(struct acpi_device *dev)
                        goto end;
        }
 
-       result = device_create_file(&dev->dev, &dev_attr_hid);
-       if (result)
-               goto end;
+       if (!list_empty(&dev->pnp.ids)) {
+               result = device_create_file(&dev->dev, &dev_attr_hid);
+               if (result)
+                       goto end;
 
-       result = device_create_file(&dev->dev, &dev_attr_modalias);
-       if (result)
-               goto end;
+               result = device_create_file(&dev->dev, &dev_attr_modalias);
+               if (result)
+                       goto end;
+       }
 
         /*
          * If device has _EJ0, 'eject' file is created that is used to trigger
@@ -316,6 +323,9 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
        struct acpi_device *acpi_dev = to_acpi_device(dev);
        int len;
 
+       if (list_empty(&acpi_dev->pnp.ids))
+               return 0;
+
        if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
        len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
@@ -1010,10 +1020,13 @@ static int acpi_dock_match(struct acpi_device *device)
        return acpi_get_handle(device->handle, "_DCK", &tmp);
 }
 
-char *acpi_device_hid(struct acpi_device *device)
+const char *acpi_device_hid(struct acpi_device *device)
 {
        struct acpi_hardware_id *hid;
 
+       if (list_empty(&device->pnp.ids))
+               return dummy_hid;
+
        hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
        return hid->id;
 }
@@ -1142,16 +1155,6 @@ static void acpi_device_set_id(struct acpi_device *device)
                acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
                break;
        }
-
-       /*
-        * We build acpi_devices for some objects that don't have _HID or _CID,
-        * e.g., PCI bridges and slots.  Drivers can't bind to these objects,
-        * but we do use them indirectly by traversing the acpi_device tree.
-        * This generic ID isn't useful for driver binding, but it provides
-        * the useful property that "every acpi_device has an ID."
-        */
-       if (list_empty(&device->pnp.ids))
-               acpi_add_id(device, "device");
 }
 
 static int acpi_device_set_context(struct acpi_device *device)
@@ -1431,6 +1434,7 @@ EXPORT_SYMBOL(acpi_bus_add);
 int acpi_bus_start(struct acpi_device *device)
 {
        struct acpi_bus_ops ops;
+       int result;
 
        if (!device)
                return -EINVAL;
@@ -1438,7 +1442,11 @@ int acpi_bus_start(struct acpi_device *device)
        memset(&ops, 0, sizeof(ops));
        ops.acpi_op_start = 1;
 
-       return acpi_bus_scan(device->handle, &ops, NULL);
+       result = acpi_bus_scan(device->handle, &ops, NULL);
+
+       acpi_update_gpes();
+
+       return result;
 }
 EXPORT_SYMBOL(acpi_bus_start);
 
@@ -1552,6 +1560,8 @@ int __init acpi_scan_init(void)
 
        if (result)
                acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+       else
+               acpi_update_gpes();
 
        return result;
 }
index 4754ff6e70e6daa25b13df6f115745eb7bfb7e55..721d93b3ceee78c3b271f5f84ffe4fc795e435e1 100644 (file)
@@ -25,7 +25,9 @@
 #include "internal.h"
 #include "sleep.h"
 
-u8 sleep_states[ACPI_S_STATE_COUNT];
+static u8 sleep_states[ACPI_S_STATE_COUNT];
+
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
@@ -79,8 +81,6 @@ static int acpi_sleep_prepare(u32 acpi_state)
 }
 
 #ifdef CONFIG_ACPI_SLEEP
-static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
 /*
  * The ACPI specification wants us to save NVS memory regions during hibernation
  * and to restore them during the subsequent resume.  Windows does that also for
@@ -419,6 +419,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
                },
        },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VPCEB1Z1E",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
+               },
+       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
@@ -562,7 +570,7 @@ int acpi_suspend(u32 acpi_state)
        return -EINVAL;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
 /**
  *     acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *             in the system sleep state given by %acpi_target_sleep_state
@@ -624,7 +632,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
         * can wake the system.  _S0W may be valid, too.
         */
        if (acpi_target_sleep_state == ACPI_STATE_S0 ||
-           (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
+           (device_may_wakeup(dev) &&
             adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
                acpi_status status;
 
@@ -632,7 +640,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
                status = acpi_evaluate_integer(handle, acpi_method, NULL,
                                                &d_max);
                if (ACPI_FAILURE(status)) {
-                       d_max = d_min;
+                       if (acpi_target_sleep_state != ACPI_STATE_S0 ||
+                           status != AE_NOT_FOUND)
+                               d_max = d_min;
                } else if (d_max < d_min) {
                        /* Warn the user of the broken DSDT */
                        printk(KERN_WARNING "ACPI: Wrong value from %s\n",
@@ -646,7 +656,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
                *d_min_p = d_min;
        return d_max;
 }
+#endif /* CONFIG_PM_OPS */
 
+#ifdef CONFIG_PM_SLEEP
 /**
  *     acpi_pm_device_sleep_wake - enable or disable the system wake-up
  *                                  capability of given device
@@ -677,7 +689,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 
        return error;
 }
-#endif
+#endif  /* CONFIG_PM_SLEEP */
 
 static void acpi_power_off_prepare(void)
 {
@@ -702,7 +714,7 @@ static void acpi_power_off(void)
  * paths through the BIOS, so disable _GTS and _BFS by default,
  * but do speak up and offer the option to enable them.
  */
-void __init acpi_gts_bfs_check(void)
+static void __init acpi_gts_bfs_check(void)
 {
        acpi_handle dummy;
 
index d8821805c3bc9ab4637732d5d7ee6f105620b83f..74d59c8f4678a385ccd575816c6f7ad1e1727456 100644 (file)
@@ -1,5 +1,4 @@
 
-extern u8 sleep_states[];
 extern int acpi_suspend(u32 state);
 
 extern void acpi_enable_wakeup_devices(u8 sleep_state);
index 2f8f17131d9fb9b19094284fcfa2dd5f0092f7b8..5a27b0a313151714976f88b2299df0937d29c8be 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
-
 #include <linux/jiffies.h>
 #include <linux/kmod.h>
 #include <linux/reboot.h>
@@ -195,61 +189,6 @@ struct acpi_thermal {
        struct mutex lock;
 };
 
-#ifdef CONFIG_ACPI_PROCFS
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_cooling_mode(struct file *,
-                                              const char __user *, size_t,
-                                              loff_t *);
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
-                                         size_t, loff_t *);
-
-static const struct file_operations acpi_thermal_state_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_thermal_state_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_temp_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_thermal_temp_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_trip_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_thermal_trip_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_cooling_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_thermal_cooling_open_fs,
-       .read = seq_read,
-       .write = acpi_thermal_write_cooling_mode,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_polling_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_thermal_polling_open_fs,
-       .read = seq_read,
-       .write = acpi_thermal_write_polling,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS*/
-
 /* --------------------------------------------------------------------------
                              Thermal Zone Management
    -------------------------------------------------------------------------- */
@@ -957,358 +896,6 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
 }
 
 
-/* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_thermal_dir;
-
-static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_thermal *tz = seq->private;
-
-
-       if (!tz)
-               goto end;
-
-       seq_puts(seq, "state:                   ");
-
-       if (!tz->state.critical && !tz->state.hot && !tz->state.passive
-           && !tz->state.active)
-               seq_puts(seq, "ok\n");
-       else {
-               if (tz->state.critical)
-                       seq_puts(seq, "critical ");
-               if (tz->state.hot)
-                       seq_puts(seq, "hot ");
-               if (tz->state.passive)
-                       seq_puts(seq, "passive ");
-               if (tz->state.active)
-                       seq_printf(seq, "active[%d]", tz->state.active_index);
-               seq_puts(seq, "\n");
-       }
-
-      end:
-       return 0;
-}
-
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
-{
-       int result = 0;
-       struct acpi_thermal *tz = seq->private;
-
-
-       if (!tz)
-               goto end;
-
-       result = acpi_thermal_get_temperature(tz);
-       if (result)
-               goto end;
-
-       seq_printf(seq, "temperature:             %ld C\n",
-                  KELVIN_TO_CELSIUS(tz->temperature));
-
-      end:
-       return 0;
-}
-
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_thermal *tz = seq->private;
-       struct acpi_device *device;
-       acpi_status status;
-
-       int i = 0;
-       int j = 0;
-
-
-       if (!tz)
-               goto end;
-
-       if (tz->trips.critical.flags.valid)
-               seq_printf(seq, "critical (S5):           %ld C%s",
-                          KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
-                          nocrt ? " <disabled>\n" : "\n");
-
-       if (tz->trips.hot.flags.valid)
-               seq_printf(seq, "hot (S4):                %ld C%s",
-                          KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
-                          nocrt ? " <disabled>\n" : "\n");
-
-       if (tz->trips.passive.flags.valid) {
-               seq_printf(seq,
-                          "passive:                 %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
-                          KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
-                          tz->trips.passive.tc1, tz->trips.passive.tc2,
-                          tz->trips.passive.tsp);
-               for (j = 0; j < tz->trips.passive.devices.count; j++) {
-                       status = acpi_bus_get_device(tz->trips.passive.devices.
-                                                    handles[j], &device);
-                       seq_printf(seq, "%4.4s ", status ? "" :
-                                  acpi_device_bid(device));
-               }
-               seq_puts(seq, "\n");
-       } else {
-               seq_printf(seq, "passive (forced):");
-               if (tz->thermal_zone->forced_passive)
-                       seq_printf(seq, "        %i C\n",
-                                  tz->thermal_zone->forced_passive / 1000);
-               else
-                       seq_printf(seq, "<not set>\n");
-       }
-
-       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-               if (!(tz->trips.active[i].flags.valid))
-                       break;
-               seq_printf(seq, "active[%d]:               %ld C: devices=",
-                          i,
-                          KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
-               for (j = 0; j < tz->trips.active[i].devices.count; j++){
-                       status = acpi_bus_get_device(tz->trips.active[i].
-                                                    devices.handles[j],
-                                                    &device);
-                       seq_printf(seq, "%4.4s ", status ? "" :
-                                  acpi_device_bid(device));
-               }
-               seq_puts(seq, "\n");
-       }
-
-      end:
-       return 0;
-}
-
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_thermal *tz = seq->private;
-
-
-       if (!tz)
-               goto end;
-
-       if (!tz->flags.cooling_mode)
-               seq_puts(seq, "<setting not supported>\n");
-       else
-               seq_puts(seq, "0 - Active; 1 - Passive\n");
-
-      end:
-       return 0;
-}
-
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_thermal_cooling_seq_show,
-                          PDE(inode)->data);
-}
-
-static ssize_t
-acpi_thermal_write_cooling_mode(struct file *file,
-                               const char __user * buffer,
-                               size_t count, loff_t * ppos)
-{
-       struct seq_file *m = file->private_data;
-       struct acpi_thermal *tz = m->private;
-       int result = 0;
-       char mode_string[12] = { '\0' };
-
-
-       if (!tz || (count > sizeof(mode_string) - 1))
-               return -EINVAL;
-
-       if (!tz->flags.cooling_mode)
-               return -ENODEV;
-
-       if (copy_from_user(mode_string, buffer, count))
-               return -EFAULT;
-
-       mode_string[count] = '\0';
-
-       result = acpi_thermal_set_cooling_mode(tz,
-                                              simple_strtoul(mode_string, NULL,
-                                                             0));
-       if (result)
-               return result;
-
-       acpi_thermal_check(tz);
-
-       return count;
-}
-
-static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_thermal *tz = seq->private;
-
-
-       if (!tz)
-               goto end;
-
-       if (!tz->thermal_zone->polling_delay) {
-               seq_puts(seq, "<polling disabled>\n");
-               goto end;
-       }
-
-       seq_printf(seq, "polling frequency:       %d seconds\n",
-                  (tz->thermal_zone->polling_delay / 1000));
-
-      end:
-       return 0;
-}
-
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_thermal_polling_seq_show,
-                          PDE(inode)->data);
-}
-
-static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
-{
-       if (!tz)
-               return -EINVAL;
-
-       /* Convert value to deci-seconds */
-       tz->polling_frequency = seconds * 10;
-
-       tz->thermal_zone->polling_delay = seconds * 1000;
-
-       if (tz->tz_enabled)
-               thermal_zone_device_update(tz->thermal_zone);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Polling frequency set to %lu seconds\n",
-                         tz->polling_frequency/10));
-
-       return 0;
-}
-
-static ssize_t
-acpi_thermal_write_polling(struct file *file,
-                          const char __user * buffer,
-                          size_t count, loff_t * ppos)
-{
-       struct seq_file *m = file->private_data;
-       struct acpi_thermal *tz = m->private;
-       int result = 0;
-       char polling_string[12] = { '\0' };
-       int seconds = 0;
-
-
-       if (!tz || (count > sizeof(polling_string) - 1))
-               return -EINVAL;
-
-       if (copy_from_user(polling_string, buffer, count))
-               return -EFAULT;
-
-       polling_string[count] = '\0';
-
-       seconds = simple_strtoul(polling_string, NULL, 0);
-
-       result = acpi_thermal_set_polling(tz, seconds);
-       if (result)
-               return result;
-
-       acpi_thermal_check(tz);
-
-       return count;
-}
-
-static int acpi_thermal_add_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *entry = NULL;
-
-
-       if (!acpi_device_dir(device)) {
-               acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
-                                                    acpi_thermal_dir);
-               if (!acpi_device_dir(device))
-                       return -ENODEV;
-       }
-
-       /* 'state' [R] */
-       entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
-                                S_IRUGO, acpi_device_dir(device),
-                                &acpi_thermal_state_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               return -ENODEV;
-
-       /* 'temperature' [R] */
-       entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
-                                S_IRUGO, acpi_device_dir(device),
-                                &acpi_thermal_temp_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               return -ENODEV;
-
-       /* 'trip_points' [R] */
-       entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
-                                S_IRUGO,
-                                acpi_device_dir(device),
-                                &acpi_thermal_trip_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               return -ENODEV;
-
-       /* 'cooling_mode' [R/W] */
-       entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
-                                S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
-                                &acpi_thermal_cooling_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               return -ENODEV;
-
-       /* 'polling_frequency' [R/W] */
-       entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
-                                S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
-                                &acpi_thermal_polling_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               return -ENODEV;
-       return 0;
-}
-
-static int acpi_thermal_remove_fs(struct acpi_device *device)
-{
-
-       if (acpi_device_dir(device)) {
-               remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
-                                 acpi_device_dir(device));
-               remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
-                                 acpi_device_dir(device));
-               remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-                                 acpi_device_dir(device));
-               remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
-                                 acpi_device_dir(device));
-               remove_proc_entry(ACPI_THERMAL_FILE_STATE,
-                                 acpi_device_dir(device));
-               remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
-               acpi_device_dir(device) = NULL;
-       }
-
-       return 0;
-}
-#else
-static inline int acpi_thermal_add_fs(struct acpi_device *device) { return 0; }
-static inline int acpi_thermal_remove_fs(struct acpi_device *device)
-{
-       return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -1428,17 +1015,11 @@ static int acpi_thermal_add(struct acpi_device *device)
        if (result)
                goto free_memory;
 
-       result = acpi_thermal_add_fs(device);
-       if (result)
-               goto unregister_thermal_zone;
-
        printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
               acpi_device_name(device), acpi_device_bid(device),
               KELVIN_TO_CELSIUS(tz->temperature));
        goto end;
 
-unregister_thermal_zone:
-       thermal_zone_device_unregister(tz->thermal_zone);
 free_memory:
        kfree(tz);
 end:
@@ -1454,7 +1035,6 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
 
        tz = acpi_driver_data(device);
 
-       acpi_thermal_remove_fs(device);
        acpi_thermal_unregister_thermal_zone(tz);
        mutex_destroy(&tz->lock);
        kfree(tz);
@@ -1580,19 +1160,9 @@ static int __init acpi_thermal_init(void)
                return -ENODEV;
        }
 
-#ifdef CONFIG_ACPI_PROCFS
-       acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
-       if (!acpi_thermal_dir)
-               return -ENODEV;
-#endif
-
        result = acpi_bus_register_driver(&acpi_thermal_driver);
-       if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
-               remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
+       if (result < 0)
                return -ENODEV;
-       }
 
        return 0;
 }
@@ -1602,10 +1172,6 @@ static void __exit acpi_thermal_exit(void)
 
        acpi_bus_unregister_driver(&acpi_thermal_driver);
 
-#ifdef CONFIG_ACPI_PROCFS
-       remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
-
        return;
 }
 
index 67dec0c675aae4d59e71c689ccc450ff5896c5c6..5cd0228d2daa0c65d22b8c00c52c50d3124aaa1a 100644 (file)
@@ -30,8 +30,6 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/input.h>
 #include <linux/backlight.h>
 #include <linux/thermal.h>
@@ -152,9 +150,6 @@ struct acpi_video_bus {
        struct acpi_video_bus_flags flags;
        struct list_head video_device_list;
        struct mutex device_list_lock;  /* protects video_device_list */
-#ifdef CONFIG_ACPI_PROCFS
-       struct proc_dir_entry *dir;
-#endif
        struct input_dev *input;
        char phys[32];  /* for input device */
        struct notifier_block pm_nb;
@@ -210,108 +205,6 @@ struct acpi_video_device {
        struct output_device *output_dev;
 };
 
-#ifdef CONFIG_ACPI_PROCFS
-/* bus */
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_info_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_bus_info_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_ROM_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_bus_ROM_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
-                                           struct file *file);
-static const struct file_operations acpi_video_bus_POST_info_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_bus_POST_info_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_POST(struct file *file,
-       const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_POST_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_bus_POST_open_fs,
-       .read = seq_read,
-       .write = acpi_video_bus_write_POST,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_DOS(struct file *file,
-       const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_DOS_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_bus_DOS_open_fs,
-       .read = seq_read,
-       .write = acpi_video_bus_write_DOS,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-/* device */
-static int acpi_video_device_info_open_fs(struct inode *inode,
-                                         struct file *file);
-static const struct file_operations acpi_video_device_info_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_device_info_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_device_state_open_fs(struct inode *inode,
-                                          struct file *file);
-static ssize_t acpi_video_device_write_state(struct file *file,
-       const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_state_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_device_state_open_fs,
-       .read = seq_read,
-       .write = acpi_video_device_write_state,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_device_brightness_open_fs(struct inode *inode,
-                                               struct file *file);
-static ssize_t acpi_video_device_write_brightness(struct file *file,
-       const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_brightness_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_device_brightness_open_fs,
-       .read = seq_read,
-       .write = acpi_video_device_write_brightness,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static int acpi_video_device_EDID_open_fs(struct inode *inode,
-                                         struct file *file);
-static const struct file_operations acpi_video_device_EDID_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_video_device_EDID_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS */
-
 static const char device_decode[][30] = {
        "motherboard VGA device",
        "PCI VGA device",
@@ -1110,646 +1003,6 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
        return status;
 }
 
-/* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_video_dir;
-
-/* video devices */
-
-static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_device *dev = seq->private;
-
-
-       if (!dev)
-               goto end;
-
-       seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
-       seq_printf(seq, "type:         ");
-       if (dev->flags.crt)
-               seq_printf(seq, "CRT\n");
-       else if (dev->flags.lcd)
-               seq_printf(seq, "LCD\n");
-       else if (dev->flags.tvout)
-               seq_printf(seq, "TVOUT\n");
-       else if (dev->flags.dvi)
-               seq_printf(seq, "DVI\n");
-       else
-               seq_printf(seq, "UNKNOWN\n");
-
-       seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
-
-      end:
-       return 0;
-}
-
-static int
-acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_device_info_seq_show,
-                          PDE(inode)->data);
-}
-
-static int
-acpi_video_device_query(struct acpi_video_device *device,
-                       unsigned long long *state)
-{
-       int status;
-
-       status = acpi_evaluate_integer(device->dev->handle, "_DGS",
-                                      NULL, state);
-
-       return status;
-}
-
-static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
-{
-       int status;
-       struct acpi_video_device *dev = seq->private;
-       unsigned long long state;
-
-
-       if (!dev)
-               goto end;
-
-       status = acpi_video_device_get_state(dev, &state);
-       seq_printf(seq, "state:     ");
-       if (ACPI_SUCCESS(status))
-               seq_printf(seq, "0x%02llx\n", state);
-       else
-               seq_printf(seq, "<not supported>\n");
-
-       status = acpi_video_device_query(dev, &state);
-       seq_printf(seq, "query:     ");
-       if (ACPI_SUCCESS(status))
-               seq_printf(seq, "0x%02llx\n", state);
-       else
-               seq_printf(seq, "<not supported>\n");
-
-      end:
-       return 0;
-}
-
-static int
-acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_device_state_seq_show,
-                          PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_state(struct file *file,
-                             const char __user * buffer,
-                             size_t count, loff_t * data)
-{
-       int status;
-       struct seq_file *m = file->private_data;
-       struct acpi_video_device *dev = m->private;
-       char str[12] = { 0 };
-       u32 state = 0;
-
-
-       if (!dev || count >= sizeof(str))
-               return -EINVAL;
-
-       if (copy_from_user(str, buffer, count))
-               return -EFAULT;
-
-       str[count] = 0;
-       state = simple_strtoul(str, NULL, 0);
-       state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
-
-       status = acpi_video_device_set_state(dev, state);
-
-       if (status)
-               return -EFAULT;
-
-       return count;
-}
-
-static int
-acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_device *dev = seq->private;
-       int i;
-
-
-       if (!dev || !dev->brightness) {
-               seq_printf(seq, "<not supported>\n");
-               return 0;
-       }
-
-       seq_printf(seq, "levels: ");
-       for (i = 2; i < dev->brightness->count; i++)
-               seq_printf(seq, " %d", dev->brightness->levels[i]);
-       seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
-
-       return 0;
-}
-
-static int
-acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_device_brightness_seq_show,
-                          PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_brightness(struct file *file,
-                                  const char __user * buffer,
-                                  size_t count, loff_t * data)
-{
-       struct seq_file *m = file->private_data;
-       struct acpi_video_device *dev = m->private;
-       char str[5] = { 0 };
-       unsigned int level = 0;
-       int i;
-
-
-       if (!dev || !dev->brightness || count >= sizeof(str))
-               return -EINVAL;
-
-       if (copy_from_user(str, buffer, count))
-               return -EFAULT;
-
-       str[count] = 0;
-       level = simple_strtoul(str, NULL, 0);
-
-       if (level > 100)
-               return -EFAULT;
-
-       /* validate through the list of available levels */
-       for (i = 2; i < dev->brightness->count; i++)
-               if (level == dev->brightness->levels[i]) {
-                       if (!acpi_video_device_lcd_set_level(dev, level))
-                               return count;
-                       break;
-               }
-
-       return -EINVAL;
-}
-
-static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_device *dev = seq->private;
-       int status;
-       int i;
-       union acpi_object *edid = NULL;
-
-
-       if (!dev)
-               goto out;
-
-       status = acpi_video_device_EDID(dev, &edid, 128);
-       if (ACPI_FAILURE(status)) {
-               status = acpi_video_device_EDID(dev, &edid, 256);
-       }
-
-       if (ACPI_FAILURE(status)) {
-               goto out;
-       }
-
-       if (edid && edid->type == ACPI_TYPE_BUFFER) {
-               for (i = 0; i < edid->buffer.length; i++)
-                       seq_putc(seq, edid->buffer.pointer[i]);
-       }
-
-      out:
-       if (!edid)
-               seq_printf(seq, "<not supported>\n");
-       else
-               kfree(edid);
-
-       return 0;
-}
-
-static int
-acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_device_EDID_seq_show,
-                          PDE(inode)->data);
-}
-
-static int acpi_video_device_add_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *entry, *device_dir;
-       struct acpi_video_device *vid_dev;
-
-       vid_dev = acpi_driver_data(device);
-       if (!vid_dev)
-               return -ENODEV;
-
-       device_dir = proc_mkdir(acpi_device_bid(device),
-                               vid_dev->video->dir);
-       if (!device_dir)
-               return -ENOMEM;
-
-       /* 'info' [R] */
-       entry = proc_create_data("info", S_IRUGO, device_dir,
-                       &acpi_video_device_info_fops, acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_dir;
-
-       /* 'state' [R/W] */
-       entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
-                                device_dir,
-                                &acpi_video_device_state_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_info;
-
-       /* 'brightness' [R/W] */
-       entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
-                                device_dir,
-                                &acpi_video_device_brightness_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_state;
-
-       /* 'EDID' [R] */
-       entry = proc_create_data("EDID", S_IRUGO, device_dir,
-                                &acpi_video_device_EDID_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_brightness;
-
-       acpi_device_dir(device) = device_dir;
-
-       return 0;
-
- err_remove_brightness:
-       remove_proc_entry("brightness", device_dir);
- err_remove_state:
-       remove_proc_entry("state", device_dir);
- err_remove_info:
-       remove_proc_entry("info", device_dir);
- err_remove_dir:
-       remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
-       return -ENOMEM;
-}
-
-static int acpi_video_device_remove_fs(struct acpi_device *device)
-{
-       struct acpi_video_device *vid_dev;
-       struct proc_dir_entry *device_dir;
-
-       vid_dev = acpi_driver_data(device);
-       if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
-               return -ENODEV;
-
-       device_dir = acpi_device_dir(device);
-       if (device_dir) {
-               remove_proc_entry("info", device_dir);
-               remove_proc_entry("state", device_dir);
-               remove_proc_entry("brightness", device_dir);
-               remove_proc_entry("EDID", device_dir);
-               remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
-               acpi_device_dir(device) = NULL;
-       }
-
-       return 0;
-}
-
-/* video bus */
-static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_bus *video = seq->private;
-
-
-       if (!video)
-               goto end;
-
-       seq_printf(seq, "Switching heads:              %s\n",
-                  video->flags.multihead ? "yes" : "no");
-       seq_printf(seq, "Video ROM:                    %s\n",
-                  video->flags.rom ? "yes" : "no");
-       seq_printf(seq, "Device to be POSTed on boot:  %s\n",
-                  video->flags.post ? "yes" : "no");
-
-      end:
-       return 0;
-}
-
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_bus_info_seq_show,
-                          PDE(inode)->data);
-}
-
-static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_bus *video = seq->private;
-
-
-       if (!video)
-               goto end;
-
-       printk(KERN_INFO PREFIX "Please implement %s\n", __func__);
-       seq_printf(seq, "<TODO>\n");
-
-      end:
-       return 0;
-}
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_POST_options(struct acpi_video_bus *video,
-                           unsigned long long *options)
-{
-       int status;
-
-       status = acpi_evaluate_integer(video->device->handle, "_VPO",
-                                      NULL, options);
-       *options &= 3;
-
-       return status;
-}
-
-static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_bus *video = seq->private;
-       unsigned long long options;
-       int status;
-
-
-       if (!video)
-               goto end;
-
-       status = acpi_video_bus_POST_options(video, &options);
-       if (ACPI_SUCCESS(status)) {
-               if (!(options & 1)) {
-                       printk(KERN_WARNING PREFIX
-                              "The motherboard VGA device is not listed as a possible POST device.\n");
-                       printk(KERN_WARNING PREFIX
-                              "This indicates a BIOS bug. Please contact the manufacturer.\n");
-               }
-               printk(KERN_WARNING "%llx\n", options);
-               seq_printf(seq, "can POST: <integrated video>");
-               if (options & 2)
-                       seq_printf(seq, " <PCI video>");
-               if (options & 4)
-                       seq_printf(seq, " <AGP video>");
-               seq_putc(seq, '\n');
-       } else
-               seq_printf(seq, "<not supported>\n");
-      end:
-       return 0;
-}
-
-static int
-acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_bus_POST_info_seq_show,
-                          PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
-{
-       int status;
-
-       status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
-
-       return status;
-}
-
-static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_bus *video = seq->private;
-       int status;
-       unsigned long long id;
-
-
-       if (!video)
-               goto end;
-
-       status = acpi_video_bus_get_POST(video, &id);
-       if (!ACPI_SUCCESS(status)) {
-               seq_printf(seq, "<not supported>\n");
-               goto end;
-       }
-       seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]);
-
-      end:
-       return 0;
-}
-
-static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_video_bus *video = seq->private;
-
-
-       seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
-
-       return 0;
-}
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_bus_POST_seq_show,
-                          PDE(inode)->data);
-}
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
-{
-       int status;
-       unsigned long long tmp;
-       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list args = { 1, &arg0 };
-
-
-       arg0.integer.value = option;
-
-       status = acpi_evaluate_integer(video->device->handle, "_SPD",
-                                      &args, &tmp);
-       if (ACPI_SUCCESS(status))
-               status = tmp ? (-EINVAL) : (AE_OK);
-
-       return status;
-}
-
-static ssize_t
-acpi_video_bus_write_POST(struct file *file,
-                         const char __user * buffer,
-                         size_t count, loff_t * data)
-{
-       int status;
-       struct seq_file *m = file->private_data;
-       struct acpi_video_bus *video = m->private;
-       char str[12] = { 0 };
-       unsigned long long opt, options;
-
-
-       if (!video || count >= sizeof(str))
-               return -EINVAL;
-
-       status = acpi_video_bus_POST_options(video, &options);
-       if (!ACPI_SUCCESS(status))
-               return -EINVAL;
-
-       if (copy_from_user(str, buffer, count))
-               return -EFAULT;
-
-       str[count] = 0;
-       opt = strtoul(str, NULL, 0);
-       if (opt > 3)
-               return -EFAULT;
-
-       /* just in case an OEM 'forgot' the motherboard... */
-       options |= 1;
-
-       if (options & (1ul << opt)) {
-               status = acpi_video_bus_set_POST(video, opt);
-               if (!ACPI_SUCCESS(status))
-                       return -EFAULT;
-
-       }
-
-       return count;
-}
-
-static ssize_t
-acpi_video_bus_write_DOS(struct file *file,
-                        const char __user * buffer,
-                        size_t count, loff_t * data)
-{
-       int status;
-       struct seq_file *m = file->private_data;
-       struct acpi_video_bus *video = m->private;
-       char str[12] = { 0 };
-       unsigned long opt;
-
-
-       if (!video || count >= sizeof(str))
-               return -EINVAL;
-
-       if (copy_from_user(str, buffer, count))
-               return -EFAULT;
-
-       str[count] = 0;
-       opt = strtoul(str, NULL, 0);
-       if (opt > 7)
-               return -EFAULT;
-
-       status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
-
-       if (!ACPI_SUCCESS(status))
-               return -EFAULT;
-
-       return count;
-}
-
-static int acpi_video_bus_add_fs(struct acpi_device *device)
-{
-       struct acpi_video_bus *video = acpi_driver_data(device);
-       struct proc_dir_entry *device_dir;
-       struct proc_dir_entry *entry;
-
-       device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
-       if (!device_dir)
-               return -ENOMEM;
-
-       /* 'info' [R] */
-       entry = proc_create_data("info", S_IRUGO, device_dir,
-                                &acpi_video_bus_info_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_dir;
-
-       /* 'ROM' [R] */
-       entry = proc_create_data("ROM", S_IRUGO, device_dir,
-                                &acpi_video_bus_ROM_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_info;
-
-       /* 'POST_info' [R] */
-       entry = proc_create_data("POST_info", S_IRUGO, device_dir,
-                                &acpi_video_bus_POST_info_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_rom;
-
-       /* 'POST' [R/W] */
-       entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
-                                device_dir,
-                                &acpi_video_bus_POST_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_post_info;
-
-       /* 'DOS' [R/W] */
-       entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
-                                device_dir,
-                                &acpi_video_bus_DOS_fops,
-                                acpi_driver_data(device));
-       if (!entry)
-               goto err_remove_post;
-
-       video->dir = acpi_device_dir(device) = device_dir;
-       return 0;
-
- err_remove_post:
-       remove_proc_entry("POST", device_dir);
- err_remove_post_info:
-       remove_proc_entry("POST_info", device_dir);
- err_remove_rom:
-       remove_proc_entry("ROM", device_dir);
- err_remove_info:
-       remove_proc_entry("info", device_dir);
- err_remove_dir:
-       remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
-       return -ENOMEM;
-}
-
-static int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *device_dir = acpi_device_dir(device);
-
-       if (device_dir) {
-               remove_proc_entry("info", device_dir);
-               remove_proc_entry("ROM", device_dir);
-               remove_proc_entry("POST_info", device_dir);
-               remove_proc_entry("POST", device_dir);
-               remove_proc_entry("DOS", device_dir);
-               remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
-               acpi_device_dir(device) = NULL;
-       }
-
-       return 0;
-}
-#else
-static inline int acpi_video_device_add_fs(struct acpi_device *device)
-{
-       return 0;
-}
-static inline int acpi_video_device_remove_fs(struct acpi_device *device)
-{
-       return 0;
-}
-static inline int acpi_video_bus_add_fs(struct acpi_device *device)
-{
-       return 0;
-}
-static inline int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
-       return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
-
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -1877,8 +1130,6 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
                list_add_tail(&data->entry, &video->video_device_list);
                mutex_unlock(&video->device_list_lock);
 
-               acpi_video_device_add_fs(device);
-
                return 0;
        }
 
@@ -2181,8 +1432,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
        if (!device || !device->video)
                return -ENOENT;
 
-       acpi_video_device_remove_fs(device->dev);
-
        status = acpi_remove_notify_handler(device->dev->handle,
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
@@ -2466,10 +1715,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
        if (error)
                goto err_free_video;
 
-       error = acpi_video_bus_add_fs(device);
-       if (error)
-               goto err_free_video;
-
        mutex_init(&video->device_list_lock);
        INIT_LIST_HEAD(&video->video_device_list);
 
@@ -2522,7 +1767,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
        acpi_video_bus_stop_devices(video);
        acpi_video_bus_put_devices(video);
        kfree(video->attached_array);
-       acpi_video_bus_remove_fs(device);
  err_free_video:
        kfree(video);
        device->driver_data = NULL;
@@ -2544,7 +1788,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
 
        acpi_video_bus_stop_devices(video);
        acpi_video_bus_put_devices(video);
-       acpi_video_bus_remove_fs(device);
 
        input_unregister_device(video->input);
        kfree(video->attached_array);
@@ -2584,17 +1827,9 @@ int acpi_video_register(void)
                return 0;
        }
 
-#ifdef CONFIG_ACPI_PROCFS
-       acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
-       if (!acpi_video_dir)
-               return -ENODEV;
-#endif
-
        result = acpi_bus_register_driver(&acpi_video_bus);
-       if (result < 0) {
-               remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+       if (result < 0)
                return -ENODEV;
-       }
 
        /*
         * When the acpi_video_bus is loaded successfully, increase
@@ -2617,10 +1852,6 @@ void acpi_video_unregister(void)
        }
        acpi_bus_unregister_driver(&acpi_video_bus);
 
-#ifdef CONFIG_ACPI_PROCFS
-       remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
-#endif
-
        register_count = 0;
 
        return;
index ee53558b452fb1076867e595820faf9f07909014..ce012a9c6201ace3fcf143fcf02f424ce0d5c29b 100644 (file)
@@ -160,6 +160,18 @@ static ssize_t node_read_numastat(struct sys_device * dev,
 }
 static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
 
+static ssize_t node_read_vmstat(struct sys_device *dev,
+                               struct sysdev_attribute *attr, char *buf)
+{
+       int nid = dev->id;
+       return sprintf(buf,
+               "nr_written %lu\n"
+               "nr_dirtied %lu\n",
+               node_page_state(nid, NR_WRITTEN),
+               node_page_state(nid, NR_DIRTIED));
+}
+static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
+
 static ssize_t node_read_distance(struct sys_device * dev,
                        struct sysdev_attribute *attr, char * buf)
 {
@@ -243,6 +255,7 @@ int register_node(struct node *node, int num, struct node *parent)
                sysdev_create_file(&node->sysdev, &attr_meminfo);
                sysdev_create_file(&node->sysdev, &attr_numastat);
                sysdev_create_file(&node->sysdev, &attr_distance);
+               sysdev_create_file(&node->sysdev, &attr_vmstat);
 
                scan_unevictable_register_node(node);
 
@@ -267,6 +280,7 @@ void unregister_node(struct node *node)
        sysdev_remove_file(&node->sysdev, &attr_meminfo);
        sysdev_remove_file(&node->sysdev, &attr_numastat);
        sysdev_remove_file(&node->sysdev, &attr_distance);
+       sysdev_remove_file(&node->sysdev, &attr_vmstat);
 
        scan_unevictable_unregister_node(node);
        hugetlb_unregister_node(node);          /* no-op, if memoryless node */
index 3966e62ad01950921c8dd497b233642caaef4a5f..f051cfff18afe2e703bc6383d8b6277cdc652401 100644 (file)
@@ -147,6 +147,7 @@ static void platform_device_release(struct device *dev)
        struct platform_object *pa = container_of(dev, struct platform_object,
                                                  pdev.dev);
 
+       of_device_node_put(&pa->pdev.dev);
        kfree(pa->pdev.dev.platform_data);
        kfree(pa->pdev.resource);
        kfree(pa);
index 1dd8676d7f55705a84ad26ff77544b0518c02723..126ca492dd08fe3694f0e78d823bbb8ec6a692b1 100644 (file)
@@ -503,7 +503,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
         * the resume will actually succeed.
         */
        if (dev->power.no_callbacks && !parent && dev->parent) {
-               spin_lock(&dev->parent->power.lock);
+               spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
                if (dev->parent->power.disable_depth > 0
                    || dev->parent->power.ignore_children
                    || dev->parent->power.runtime_status == RPM_ACTIVE) {
index 6c48b3545f84583d0e32f1e87308c39a42b2133c..450c958b514fea941e5f11de2b248dec6e7477c0 100644 (file)
@@ -101,8 +101,8 @@ static int transfer_none(struct loop_device *lo, int cmd,
        else
                memcpy(raw_buf, loop_buf, size);
 
-       kunmap_atomic(raw_buf, KM_USER0);
        kunmap_atomic(loop_buf, KM_USER1);
+       kunmap_atomic(raw_buf, KM_USER0);
        cond_resched();
        return 0;
 }
@@ -130,8 +130,8 @@ static int transfer_xor(struct loop_device *lo, int cmd,
        for (i = 0; i < size; i++)
                *out++ = *in++ ^ key[(i & 511) % keysize];
 
-       kunmap_atomic(raw_buf, KM_USER0);
        kunmap_atomic(loop_buf, KM_USER1);
+       kunmap_atomic(raw_buf, KM_USER0);
        cond_resched();
        return 0;
 }
index 6e968cd4893caea636246796fac124e7b34d83a6..829161edae53034d0d97ac72a56e6e46f02346ae 100644 (file)
@@ -1225,7 +1225,8 @@ ace_of_probe(struct platform_device *op, const struct of_device_id *match)
                bus_width = ACE_BUS_WIDTH_8;
 
        /* Call the bus-independant setup code */
-       return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+       return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0,
+                                               physaddr, irq, bus_width);
 }
 
 static int __devexit ace_of_remove(struct platform_device *op)
index 627f542827c7069b4352bb1692d0baae2af63d38..8eb56e273e75719f51d617fe3a2ed5c4b9cc06f2 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1)      += hp-agp.o
 obj-$(CONFIG_AGP_PARISC)       += parisc-agp.o
 obj-$(CONFIG_AGP_I460)         += i460-agp.o
 obj-$(CONFIG_AGP_INTEL)                += intel-agp.o
+obj-$(CONFIG_AGP_INTEL)                += intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)       += nvidia-agp.o
 obj-$(CONFIG_AGP_SGI_TIOCA)    += sgi-agp.o
 obj-$(CONFIG_AGP_SIS)          += sis-agp.o
index 120490949997b71c86785d3af5156ea63b3c2330..5259065f3c792b16829b00c6200e73938250d74a 100644 (file)
@@ -121,11 +121,6 @@ struct agp_bridge_driver {
        void (*agp_destroy_pages)(struct agp_memory *);
        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
        void (*chipset_flush)(struct agp_bridge_data *);
-
-       int (*agp_map_page)(struct page *page, dma_addr_t *ret);
-       void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
-       int (*agp_map_memory)(struct agp_memory *mem);
-       void (*agp_unmap_memory)(struct agp_memory *mem);
 };
 
 struct agp_bridge_data {
index b6b1568314c8a5f63a44de50d70ca176b57b8090..b1b4362bc6487c88c8b7fb2e69c828f407727c67 100644 (file)
@@ -309,7 +309,8 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 
        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 
-       if (type != 0 || mem->type != 0)
+       if (type != mem->type ||
+           agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
                return -EINVAL;
 
        if ((pg_start + mem->page_count) > num_entries)
@@ -348,7 +349,8 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        unsigned long __iomem *cur_gatt;
        unsigned long addr;
 
-       if (type != 0 || mem->type != 0)
+       if (type != mem->type ||
+           agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
                return -EINVAL;
 
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
index ee4f855611b676b589046fad44f1e934bd615896..f27d0d0816d3ce5371a9948bc9841e74ba0f533b 100644 (file)
@@ -151,17 +151,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
                }
 
                bridge->scratch_page_page = page;
-               if (bridge->driver->agp_map_page) {
-                       if (bridge->driver->agp_map_page(page,
-                                                        &bridge->scratch_page_dma)) {
-                               dev_err(&bridge->dev->dev,
-                                       "unable to dma-map scratch page\n");
-                               rc = -ENOMEM;
-                               goto err_out_nounmap;
-                       }
-               } else {
-                       bridge->scratch_page_dma = page_to_phys(page);
-               }
+               bridge->scratch_page_dma = page_to_phys(page);
 
                bridge->scratch_page = bridge->driver->mask_memory(bridge,
                                                   bridge->scratch_page_dma, 0);
@@ -204,12 +194,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
        return 0;
 
 err_out:
-       if (bridge->driver->needs_scratch_page &&
-           bridge->driver->agp_unmap_page) {
-               bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-                                              bridge->scratch_page_dma);
-       }
-err_out_nounmap:
        if (bridge->driver->needs_scratch_page) {
                void *va = page_address(bridge->scratch_page_page);
 
@@ -240,10 +224,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
            bridge->driver->needs_scratch_page) {
                void *va = page_address(bridge->scratch_page_page);
 
-               if (bridge->driver->agp_unmap_page)
-                       bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-                                                      bridge->scratch_page_dma);
-
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
        }
index 64255cef8a7db93f780c700d712c5fa4b7fe5907..4956f1c8f9d5da6d0902390e3ffb44e35455e208 100644 (file)
@@ -437,11 +437,6 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
                curr->is_flushed = true;
        }
 
-       if (curr->bridge->driver->agp_map_memory) {
-               ret_val = curr->bridge->driver->agp_map_memory(curr);
-               if (ret_val)
-                       return ret_val;
-       }
        ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
        if (ret_val != 0)
@@ -483,9 +478,6 @@ int agp_unbind_memory(struct agp_memory *curr)
        if (ret_val != 0)
                return ret_val;
 
-       if (curr->bridge->driver->agp_unmap_memory)
-               curr->bridge->driver->agp_unmap_memory(curr);
-
        curr->is_bound = false;
        curr->pg_start = 0;
        spin_lock(&curr->bridge->mapped_lock);
index cd18493c952795317904229197016e40d7c408cd..e72f49d52202da8dcddf2055a366abb31e9029d9 100644 (file)
@@ -12,9 +12,6 @@
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
-#include <linux/intel-gtt.h>
-
-#include "intel-gtt.c"
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
@@ -703,179 +700,37 @@ static const struct agp_bridge_driver intel_7505_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int find_gmch(u16 device)
-{
-       struct pci_dev *gmch_device;
-
-       gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
-       if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
-               gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                            device, gmch_device);
-       }
-
-       if (!gmch_device)
-               return 0;
-
-       intel_private.pcidev = gmch_device;
-       return 1;
-}
-
 /* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
  * driver and gmch_driver must be non-null, and find_gmch will determine
  * which one should be used if a gmch_chip_id is present.
  */
-static const struct intel_driver_description {
+static const struct intel_agp_driver_description {
        unsigned int chip_id;
-       unsigned int gmch_chip_id;
        char *name;
        const struct agp_bridge_driver *driver;
-       const struct agp_bridge_driver *gmch_driver;
 } intel_agp_chipsets[] = {
-       { PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
-               NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
-               NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
-               NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
-               &intel_815_driver, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
-               &intel_830mp_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
-               &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
-               &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
-               &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
-               &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
-               NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
-               NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
-               NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
-               NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
-               NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
-               NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
-               NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
-           "GM45", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
-           "Eaglelake", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
-           "Q45/Q43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
-           "G45/G43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
-           "B43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
-           "B43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
-           "G41", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { 0, 0, NULL, NULL, NULL }
+       { PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
+       { PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
+       { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
+       { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
+       { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
+       { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
+       { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
+       { PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
+       { PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
+       { 0, NULL, NULL }
 };
 
-static int __devinit intel_gmch_probe(struct pci_dev *pdev,
-                                     struct agp_bridge_data *bridge)
-{
-       int i, mask;
-
-       bridge->driver = NULL;
-
-       for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
-               if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
-                       find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
-                       bridge->driver =
-                               intel_agp_chipsets[i].gmch_driver;
-                       break;
-               }
-       }
-
-       if (!bridge->driver)
-               return 0;
-
-       bridge->dev_private_data = &intel_private;
-       bridge->dev = pdev;
-
-       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
-
-       if (bridge->driver->mask_memory == intel_gen6_mask_memory)
-               mask = 40;
-       else if (bridge->driver->mask_memory == intel_i965_mask_memory)
-               mask = 36;
-       else
-               mask = 32;
-
-       if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
-               dev_err(&intel_private.pcidev->dev,
-                       "set gfx device dma mask %d-bit failed!\n", mask);
-       else
-               pci_set_consistent_dma_mask(intel_private.pcidev,
-                                           DMA_BIT_MASK(mask));
-
-       return 1;
-}
-
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -905,7 +760,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                }
        }
 
-       if (intel_agp_chipsets[i].name == NULL) {
+       if (!bridge->driver) {
                if (cap_ptr)
                        dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
                                 pdev->vendor, pdev->device);
@@ -913,14 +768,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       if (!bridge->driver) {
-               if (cap_ptr)
-                       dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
-                                intel_agp_chipsets[i].gmch_chip_id);
-               agp_put_bridge(bridge);
-               return -ENODEV;
-       }
-
        bridge->dev = pdev;
        bridge->dev_private_data = NULL;
 
@@ -972,8 +819,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
 
        agp_remove_bridge(bridge);
 
-       if (intel_private.pcidev)
-               pci_dev_put(intel_private.pcidev);
+       intel_gmch_remove(pdev);
 
        agp_put_bridge(bridge);
 }
@@ -1049,6 +895,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_G45_HB),
        ID(PCI_DEVICE_ID_INTEL_G41_HB),
        ID(PCI_DEVICE_ID_INTEL_B43_HB),
+       ID(PCI_DEVICE_ID_INTEL_B43_1_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
index d09b1ab7e8abeac5bbdf0cc8a8dd5f333f9c22a3..90539df02504ca0ee75ebf1923fd814a50a738bc 100644 (file)
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB           0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG           0x010A
 
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_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_G41_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
-               IS_SNB)
-
+int intel_gmch_probe(struct pci_dev *pdev,
+                              struct agp_bridge_data *bridge);
+void intel_gmch_remove(struct pci_dev *pdev);
 #endif
index 75e0a3497888d295d25dd414bda8a2ce69eee724..6b6760ea2435bac1865325aec74d579f9687f87e 100644 (file)
  * /fairy-tale-mode off
  */
 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/smp.h>
+#include "agp.h"
+#include "intel-agp.h"
+#include <linux/intel-gtt.h>
+#include <drm/intel-gtt.h>
+
 /*
  * If we have Intel graphics, we're not going to have anything other than
  * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
  */
 #ifdef CONFIG_DMAR
 #define USE_PCI_DMA_API 1
+#else
+#define USE_PCI_DMA_API 0
 #endif
 
 /* Max amount of stolen space, anything above will be returned to Linux */
 int intel_max_stolen = 32 * 1024 * 1024;
-EXPORT_SYMBOL(intel_max_stolen);
 
 static const struct aper_size_info_fixed intel_i810_sizes[] =
 {
@@ -55,32 +68,36 @@ static struct gatt_mask intel_i810_masks[] =
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC        3
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT   4
 
-static struct gatt_mask intel_gen6_masks[] =
-{
-       {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED,
-        .type = INTEL_AGP_UNCACHED_MEMORY },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT },
+struct intel_gtt_driver {
+       unsigned int gen : 8;
+       unsigned int is_g33 : 1;
+       unsigned int is_pineview : 1;
+       unsigned int is_ironlake : 1;
+       unsigned int dma_mask_size : 8;
+       /* Chipset specific GTT setup */
+       int (*setup)(void);
+       /* This should undo anything done in ->setup() save the unmapping
+        * of the mmio register file, that's done in the generic code. */
+       void (*cleanup)(void);
+       void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
+       /* Flags is a more or less chipset specific opaque value.
+        * For chipsets that need to support old ums (non-gem) code, this
+        * needs to be identical to the various supported agp memory types! */
+       bool (*check_flags)(unsigned int flags);
+       void (*chipset_flush)(void);
 };
 
 static struct _intel_private {
+       struct intel_gtt base;
+       const struct intel_gtt_driver *driver;
        struct pci_dev *pcidev; /* device one */
+       struct pci_dev *bridge_dev;
        u8 __iomem *registers;
+       phys_addr_t gtt_bus_addr;
+       phys_addr_t gma_bus_addr;
+       phys_addr_t pte_bus_addr;
        u32 __iomem *gtt;               /* I915G */
        int num_dcache_entries;
-       /* gtt_entries is the number of gtt entries that are already mapped
-        * to stolen memory.  Stolen memory is larger than the memory mapped
-        * through gtt_entries, as it includes some reserved space for the BIOS
-        * popup and for the GTT.
-        */
-       int gtt_entries;                        /* i830+ */
-       int gtt_total_size;
        union {
                void __iomem *i9xx_flush_page;
                void *i8xx_flush_page;
@@ -88,23 +105,14 @@ static struct _intel_private {
        struct page *i8xx_page;
        struct resource ifp_resource;
        int resource_valid;
+       struct page *scratch_page;
+       dma_addr_t scratch_page_dma;
 } intel_private;
 
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
-       *ret = pci_map_page(intel_private.pcidev, page, 0,
-                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
-               return -EINVAL;
-       return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
-       pci_unmap_page(intel_private.pcidev, dma,
-                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
+#define INTEL_GTT_GEN  intel_private.driver->gen
+#define IS_G33         intel_private.driver->is_g33
+#define IS_PINEVIEW    intel_private.driver->is_pineview
+#define IS_IRONLAKE    intel_private.driver->is_ironlake
 
 static void intel_agp_free_sglist(struct agp_memory *mem)
 {
@@ -125,6 +133,9 @@ static int intel_agp_map_memory(struct agp_memory *mem)
        struct scatterlist *sg;
        int i;
 
+       if (mem->sg_list)
+               return 0; /* already mapped (for e.g. resume */
+
        DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
 
        if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
@@ -156,70 +167,17 @@ static void intel_agp_unmap_memory(struct agp_memory *mem)
        intel_agp_free_sglist(mem);
 }
 
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       struct scatterlist *sg;
-       int i, j;
-
-       j = pg_start;
-
-       WARN_ON(!mem->num_sg);
-
-       if (mem->num_sg == mem->page_count) {
-               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
-                       writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                       sg_dma_address(sg), mask_type),
-                                       intel_private.gtt+j);
-                       j++;
-               }
-       } else {
-               /* sg may merge pages, but we have to separate
-                * per-page addr for GTT */
-               unsigned int len, m;
-
-               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
-                       len = sg_dma_len(sg) / PAGE_SIZE;
-                       for (m = 0; m < len; m++) {
-                               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
-                                                                      mask_type),
-                                      intel_private.gtt+j);
-                               j++;
-                       }
-               }
-       }
-       readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       int i, j;
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.gtt+j);
-       }
-
-       readl(intel_private.gtt+j-1);
-}
-
-#endif
-
 static int intel_i810_fetch_size(void)
 {
        u32 smram_miscc;
        struct aper_size_info_fixed *values;
 
-       pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+       pci_read_config_dword(intel_private.bridge_dev,
+                             I810_SMRAM_MISCC, &smram_miscc);
        values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
 
        if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
-               dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+               dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
                return 0;
        }
        if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
@@ -284,7 +242,7 @@ static void intel_i810_cleanup(void)
        iounmap(intel_private.registers);
 }
 
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
        return;
 }
@@ -319,34 +277,6 @@ static void i8xx_destroy_pages(struct page *page)
        atomic_dec(&agp_bridge->current_memory_agp);
 }
 
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
-                                       int type)
-{
-       if (type < AGP_USER_TYPES)
-               return type;
-       else if (type == AGP_USER_CACHED_MEMORY)
-               return INTEL_AGP_CACHED_MEMORY;
-       else
-               return 0;
-}
-
-static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge,
-                                       int type)
-{
-       unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT;
-       unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT;
-
-       if (type_mask == AGP_USER_UNCACHED_MEMORY)
-               return INTEL_AGP_UNCACHED_MEMORY;
-       else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC)
-               return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT :
-                             INTEL_AGP_CACHED_MEMORY_LLC_MLC;
-       else /* set 'normal'/'cached' to LLC by default */
-               return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT :
-                             INTEL_AGP_CACHED_MEMORY_LLC;
-}
-
-
 static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
                                int type)
 {
@@ -514,8 +444,33 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
        return addr | bridge->driver->masks[type].mask;
 }
 
-static struct aper_size_info_fixed intel_i830_sizes[] =
+static int intel_gtt_setup_scratch_page(void)
 {
+       struct page *page;
+       dma_addr_t dma_addr;
+
+       page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+       if (page == NULL)
+               return -ENOMEM;
+       get_page(page);
+       set_pages_uc(page, 1);
+
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+               dma_addr = pci_map_page(intel_private.pcidev, page, 0,
+                                   PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+                       return -EINVAL;
+
+               intel_private.scratch_page_dma = dma_addr;
+       } else
+               intel_private.scratch_page_dma = page_to_phys(page);
+
+       intel_private.scratch_page = page;
+
+       return 0;
+}
+
+static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
        {128, 32768, 5},
        /* The 64M mode still requires a 128k gatt */
        {64, 16384, 5},
@@ -523,102 +478,49 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
        {512, 131072, 7},
 };
 
-static void intel_i830_init_gtt_entries(void)
+static unsigned int intel_gtt_stolen_entries(void)
 {
        u16 gmch_ctrl;
-       int gtt_entries = 0;
        u8 rdct;
        int local = 0;
        static const int ddt[4] = { 0, 16, 32, 64 };
-       int size; /* reserved space (in kb) at the top of stolen memory */
+       unsigned int overhead_entries, stolen_entries;
+       unsigned int stolen_size = 0;
 
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       pci_read_config_word(intel_private.bridge_dev,
+                            I830_GMCH_CTRL, &gmch_ctrl);
 
-       if (IS_I965) {
-               u32 pgetbl_ctl;
-               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+       if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
+               overhead_entries = 0;
+       else
+               overhead_entries = intel_private.base.gtt_mappable_entries
+                       / 1024;
 
-               /* The 965 has a field telling us the size of the GTT,
-                * which may be larger than what is necessary to map the
-                * aperture.
-                */
-               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-               case I965_PGETBL_SIZE_128KB:
-                       size = 128;
-                       break;
-               case I965_PGETBL_SIZE_256KB:
-                       size = 256;
-                       break;
-               case I965_PGETBL_SIZE_512KB:
-                       size = 512;
-                       break;
-               case I965_PGETBL_SIZE_1MB:
-                       size = 1024;
-                       break;
-               case I965_PGETBL_SIZE_2MB:
-                       size = 2048;
-                       break;
-               case I965_PGETBL_SIZE_1_5MB:
-                       size = 1024 + 512;
-                       break;
-               default:
-                       dev_info(&intel_private.pcidev->dev,
-                                "unknown page table size, assuming 512KB\n");
-                       size = 512;
-               }
-               size += 4; /* add in BIOS popup space */
-       } else if (IS_G33 && !IS_PINEVIEW) {
-       /* G33's GTT size defined in gmch_ctrl */
-               switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
-               case G33_PGETBL_SIZE_1M:
-                       size = 1024;
-                       break;
-               case G33_PGETBL_SIZE_2M:
-                       size = 2048;
-                       break;
-               default:
-                       dev_info(&agp_bridge->dev->dev,
-                                "unknown page table size 0x%x, assuming 512KB\n",
-                               (gmch_ctrl & G33_PGETBL_SIZE_MASK));
-                       size = 512;
-               }
-               size += 4;
-       } else if (IS_G4X || IS_PINEVIEW) {
-               /* On 4 series hardware, GTT stolen is separate from graphics
-                * stolen, ignore it in stolen gtt entries counting.  However,
-                * 4KB of the stolen memory doesn't get mapped to the GTT.
-                */
-               size = 4;
-       } else {
-               /* On previous hardware, the GTT size was just what was
-                * required to map the aperture.
-                */
-               size = agp_bridge->driver->fetch_size() + 4;
-       }
+       overhead_entries += 1; /* BIOS popup */
 
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+       if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+           intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
                switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
                case I830_GMCH_GMS_STOLEN_512:
-                       gtt_entries = KB(512) - KB(size);
+                       stolen_size = KB(512);
                        break;
                case I830_GMCH_GMS_STOLEN_1024:
-                       gtt_entries = MB(1) - KB(size);
+                       stolen_size = MB(1);
                        break;
                case I830_GMCH_GMS_STOLEN_8192:
-                       gtt_entries = MB(8) - KB(size);
+                       stolen_size = MB(8);
                        break;
                case I830_GMCH_GMS_LOCAL:
                        rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+                       stolen_size = (I830_RDRAM_ND(rdct) + 1) *
                                        MB(ddt[I830_RDRAM_DDT(rdct)]);
                        local = 1;
                        break;
                default:
-                       gtt_entries = 0;
+                       stolen_size = 0;
                        break;
                }
-       } else if (IS_SNB) {
+       } else if (INTEL_GTT_GEN == 6) {
                /*
                 * SandyBridge has new memory control reg at 0x50.w
                 */
@@ -626,149 +528,292 @@ static void intel_i830_init_gtt_entries(void)
                pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
                switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
                case SNB_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
+                       stolen_size = MB(32);
                        break;
                case SNB_GMCH_GMS_STOLEN_64M:
-                       gtt_entries = MB(64) - KB(size);
+                       stolen_size = MB(64);
                        break;
                case SNB_GMCH_GMS_STOLEN_96M:
-                       gtt_entries = MB(96) - KB(size);
+                       stolen_size = MB(96);
                        break;
                case SNB_GMCH_GMS_STOLEN_128M:
-                       gtt_entries = MB(128) - KB(size);
+                       stolen_size = MB(128);
                        break;
                case SNB_GMCH_GMS_STOLEN_160M:
-                       gtt_entries = MB(160) - KB(size);
+                       stolen_size = MB(160);
                        break;
                case SNB_GMCH_GMS_STOLEN_192M:
-                       gtt_entries = MB(192) - KB(size);
+                       stolen_size = MB(192);
                        break;
                case SNB_GMCH_GMS_STOLEN_224M:
-                       gtt_entries = MB(224) - KB(size);
+                       stolen_size = MB(224);
                        break;
                case SNB_GMCH_GMS_STOLEN_256M:
-                       gtt_entries = MB(256) - KB(size);
+                       stolen_size = MB(256);
                        break;
                case SNB_GMCH_GMS_STOLEN_288M:
-                       gtt_entries = MB(288) - KB(size);
+                       stolen_size = MB(288);
                        break;
                case SNB_GMCH_GMS_STOLEN_320M:
-                       gtt_entries = MB(320) - KB(size);
+                       stolen_size = MB(320);
                        break;
                case SNB_GMCH_GMS_STOLEN_352M:
-                       gtt_entries = MB(352) - KB(size);
+                       stolen_size = MB(352);
                        break;
                case SNB_GMCH_GMS_STOLEN_384M:
-                       gtt_entries = MB(384) - KB(size);
+                       stolen_size = MB(384);
                        break;
                case SNB_GMCH_GMS_STOLEN_416M:
-                       gtt_entries = MB(416) - KB(size);
+                       stolen_size = MB(416);
                        break;
                case SNB_GMCH_GMS_STOLEN_448M:
-                       gtt_entries = MB(448) - KB(size);
+                       stolen_size = MB(448);
                        break;
                case SNB_GMCH_GMS_STOLEN_480M:
-                       gtt_entries = MB(480) - KB(size);
+                       stolen_size = MB(480);
                        break;
                case SNB_GMCH_GMS_STOLEN_512M:
-                       gtt_entries = MB(512) - KB(size);
+                       stolen_size = MB(512);
                        break;
                }
        } else {
                switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
                case I855_GMCH_GMS_STOLEN_1M:
-                       gtt_entries = MB(1) - KB(size);
+                       stolen_size = MB(1);
                        break;
                case I855_GMCH_GMS_STOLEN_4M:
-                       gtt_entries = MB(4) - KB(size);
+                       stolen_size = MB(4);
                        break;
                case I855_GMCH_GMS_STOLEN_8M:
-                       gtt_entries = MB(8) - KB(size);
+                       stolen_size = MB(8);
                        break;
                case I855_GMCH_GMS_STOLEN_16M:
-                       gtt_entries = MB(16) - KB(size);
+                       stolen_size = MB(16);
                        break;
                case I855_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
+                       stolen_size = MB(32);
                        break;
                case I915_GMCH_GMS_STOLEN_48M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(48) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(48);
                        break;
                case I915_GMCH_GMS_STOLEN_64M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(64) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(64);
                        break;
                case G33_GMCH_GMS_STOLEN_128M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(128) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(128);
                        break;
                case G33_GMCH_GMS_STOLEN_256M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(256) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(256);
                        break;
                case INTEL_GMCH_GMS_STOLEN_96M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(96) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(96);
                        break;
                case INTEL_GMCH_GMS_STOLEN_160M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(160) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(160);
                        break;
                case INTEL_GMCH_GMS_STOLEN_224M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(224) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(224);
                        break;
                case INTEL_GMCH_GMS_STOLEN_352M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(352) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(352);
                        break;
                default:
-                       gtt_entries = 0;
+                       stolen_size = 0;
                        break;
                }
        }
-       if (!local && gtt_entries > intel_max_stolen) {
-               dev_info(&agp_bridge->dev->dev,
+
+       if (!local && stolen_size > intel_max_stolen) {
+               dev_info(&intel_private.bridge_dev->dev,
                         "detected %dK stolen memory, trimming to %dK\n",
-                        gtt_entries / KB(1), intel_max_stolen / KB(1));
-               gtt_entries = intel_max_stolen / KB(4);
-       } else if (gtt_entries > 0) {
-               dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
-                      gtt_entries / KB(1), local ? "local" : "stolen");
-               gtt_entries /= KB(4);
+                        stolen_size / KB(1), intel_max_stolen / KB(1));
+               stolen_size = intel_max_stolen;
+       } else if (stolen_size > 0) {
+               dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
+                      stolen_size / KB(1), local ? "local" : "stolen");
        } else {
-               dev_info(&agp_bridge->dev->dev,
+               dev_info(&intel_private.bridge_dev->dev,
                       "no pre-allocated video memory detected\n");
-               gtt_entries = 0;
+               stolen_size = 0;
+       }
+
+       stolen_entries = stolen_size/KB(4) - overhead_entries;
+
+       return stolen_entries;
+}
+
+static unsigned int intel_gtt_total_entries(void)
+{
+       int size;
+
+       if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
+               u32 pgetbl_ctl;
+               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+               case I965_PGETBL_SIZE_128KB:
+                       size = KB(128);
+                       break;
+               case I965_PGETBL_SIZE_256KB:
+                       size = KB(256);
+                       break;
+               case I965_PGETBL_SIZE_512KB:
+                       size = KB(512);
+                       break;
+               case I965_PGETBL_SIZE_1MB:
+                       size = KB(1024);
+                       break;
+               case I965_PGETBL_SIZE_2MB:
+                       size = KB(2048);
+                       break;
+               case I965_PGETBL_SIZE_1_5MB:
+                       size = KB(1024 + 512);
+                       break;
+               default:
+                       dev_info(&intel_private.pcidev->dev,
+                                "unknown page table size, assuming 512KB\n");
+                       size = KB(512);
+               }
+
+               return size/4;
+       } else if (INTEL_GTT_GEN == 6) {
+               u16 snb_gmch_ctl;
+
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+               default:
+               case SNB_GTT_SIZE_0M:
+                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+                       size = MB(0);
+                       break;
+               case SNB_GTT_SIZE_1M:
+                       size = MB(1);
+                       break;
+               case SNB_GTT_SIZE_2M:
+                       size = MB(2);
+                       break;
+               }
+               return size/4;
+       } else {
+               /* On previous hardware, the GTT size was just what was
+                * required to map the aperture.
+                */
+               return intel_private.base.gtt_mappable_entries;
+       }
+}
+
+static unsigned int intel_gtt_mappable_entries(void)
+{
+       unsigned int aperture_size;
+
+       if (INTEL_GTT_GEN == 2) {
+               u16 gmch_ctrl;
+
+               pci_read_config_word(intel_private.bridge_dev,
+                                    I830_GMCH_CTRL, &gmch_ctrl);
+
+               if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
+                       aperture_size = MB(64);
+               else
+                       aperture_size = MB(128);
+       } else {
+               /* 9xx supports large sizes, just look at the length */
+               aperture_size = pci_resource_len(intel_private.pcidev, 2);
+       }
+
+       return aperture_size >> PAGE_SHIFT;
+}
+
+static void intel_gtt_teardown_scratch_page(void)
+{
+       set_pages_wb(intel_private.scratch_page, 1);
+       pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       put_page(intel_private.scratch_page);
+       __free_page(intel_private.scratch_page);
+}
+
+static void intel_gtt_cleanup(void)
+{
+       intel_private.driver->cleanup();
+
+       iounmap(intel_private.gtt);
+       iounmap(intel_private.registers);
+       
+       intel_gtt_teardown_scratch_page();
+}
+
+static int intel_gtt_init(void)
+{
+       u32 gtt_map_size;
+       int ret;
+
+       ret = intel_private.driver->setup();
+       if (ret != 0)
+               return ret;
+
+       intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
+       intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+
+       dev_info(&intel_private.bridge_dev->dev,
+                       "detected gtt size: %dK total, %dK mappable\n",
+                       intel_private.base.gtt_total_entries * 4,
+                       intel_private.base.gtt_mappable_entries * 4);
+
+       gtt_map_size = intel_private.base.gtt_total_entries * 4;
+
+       intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+                                   gtt_map_size);
+       if (!intel_private.gtt) {
+               intel_private.driver->cleanup();
+               iounmap(intel_private.registers);
+               return -ENOMEM;
+       }
+
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
+       if (intel_private.base.gtt_stolen_entries == 0) {
+               intel_private.driver->cleanup();
+               iounmap(intel_private.registers);
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       ret = intel_gtt_setup_scratch_page();
+       if (ret != 0) {
+               intel_gtt_cleanup();
+               return ret;
+       }
+
+       return 0;
+}
+
+static int intel_fake_agp_fetch_size(void)
+{
+       int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
+       unsigned int aper_size;
+       int i;
+
+       aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
+                   / MB(1);
+
+       for (i = 0; i < num_sizes; i++) {
+               if (aper_size == intel_fake_agp_sizes[i].size) {
+                       agp_bridge->current_size =
+                               (void *) (intel_fake_agp_sizes + i);
+                       return aper_size;
+               }
        }
 
-       intel_private.gtt_entries = gtt_entries;
+       return 0;
 }
 
-static void intel_i830_fini_flush(void)
+static void i830_cleanup(void)
 {
        kunmap(intel_private.i8xx_page);
        intel_private.i8xx_flush_page = NULL;
-       unmap_page_from_agp(intel_private.i8xx_page);
 
        __free_page(intel_private.i8xx_page);
        intel_private.i8xx_page = NULL;
@@ -780,13 +825,13 @@ static void intel_i830_setup_flush(void)
        if (intel_private.i8xx_page)
                return;
 
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+       intel_private.i8xx_page = alloc_page(GFP_KERNEL);
        if (!intel_private.i8xx_page)
                return;
 
        intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
        if (!intel_private.i8xx_flush_page)
-               intel_i830_fini_flush();
+               i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -799,7 +844,7 @@ static void intel_i830_setup_flush(void)
  * that buffer out, we just fill 1KB and clflush it out, on the assumption
  * that it'll push whatever was in there out.  It appears to work.
  */
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+static void i830_chipset_flush(void)
 {
        unsigned int *pg = intel_private.i8xx_flush_page;
 
@@ -811,169 +856,184 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
                printk(KERN_ERR "Timed out waiting for cache flush.\n");
 }
 
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+static void i830_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
+       u32 pte_flags = I810_PTE_VALID;
+       
+       switch (flags) {
+       case AGP_DCACHE_MEMORY:
+               pte_flags |= I810_PTE_LOCAL;
+               break;
+       case AGP_USER_CACHED_MEMORY:
+               pte_flags |= I830_PTE_SYSTEM_CACHED;
+               break;
+       }
 
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
+       writel(addr | pte_flags, intel_private.gtt + entry);
+}
 
-       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-       temp &= 0xfff80000;
+static void intel_enable_gtt(void)
+{
+       u32 gma_addr;
+       u16 gmch_ctrl;
 
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers)
-               return -ENOMEM;
+       if (INTEL_GTT_GEN == 2)
+               pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
+                                     &gma_addr);
+       else
+               pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
+                                     &gma_addr);
 
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ?? */
+       intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
 
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.registers);
+       pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
+              intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+}
+
+static int i830_setup(void)
+{
+       u32 reg_addr;
+
+       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+       reg_addr &= 0xfff80000;
+
+       intel_private.registers = ioremap(reg_addr, KB(64));
+       if (!intel_private.registers)
                return -ENOMEM;
-       }
 
-       agp_bridge->gatt_table = NULL;
+       intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+       intel_private.pte_bus_addr =
+               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-       agp_bridge->gatt_bus_addr = temp;
+       intel_i830_setup_flush();
 
        return 0;
 }
 
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
 {
+       agp_bridge->gatt_table_real = NULL;
+       agp_bridge->gatt_table = NULL;
+       agp_bridge->gatt_bus_addr = 0;
+
        return 0;
 }
 
-static int intel_i830_fetch_size(void)
+static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
 {
-       u16 gmch_ctrl;
-       struct aper_size_info_fixed *values;
+       return 0;
+}
 
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+static int intel_fake_agp_configure(void)
+{
+       int i;
 
-       if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-           agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-               /* 855GM/852GM/865G has 128MB aperture size */
-               agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       }
+       intel_enable_gtt();
 
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
-       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-               agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       } else {
-               agp_bridge->current_size = (void *) (values + 1);
-               agp_bridge->aperture_size_idx = 1;
-               return values[1].size;
+       for (i = intel_private.base.gtt_stolen_entries;
+                       i < intel_private.base.gtt_total_entries; i++) {
+               intel_private.driver->write_entry(intel_private.scratch_page_dma,
+                                                 i, 0);
        }
+       readl(intel_private.gtt+i-1);   /* PCI Posting. */
+
+       global_cache_flush();
 
        return 0;
 }
 
-static int intel_i830_configure(void)
+static bool i830_check_flags(unsigned int flags)
 {
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
+       switch (flags) {
+       case 0:
+       case AGP_PHYS_MEMORY:
+       case AGP_USER_CACHED_MEMORY:
+       case AGP_USER_MEMORY:
+               return true;
+       }
 
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+       return false;
+}
 
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+                                       unsigned int sg_len,
+                                       unsigned int pg_start,
+                                       unsigned int flags)
+{
+       struct scatterlist *sg;
+       unsigned int len, m;
+       int i, j;
 
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+       j = pg_start;
 
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+       /* sg may merge pages, but we have to separate
+        * per-page addr for GTT */
+       for_each_sg(sg_list, sg, sg_len, i) {
+               len = sg_dma_len(sg) >> PAGE_SHIFT;
+               for (m = 0; m < len; m++) {
+                       dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+                       intel_private.driver->write_entry(addr,
+                                                         j, flags);
+                       j++;
                }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
        }
-
-       global_cache_flush();
-
-       intel_i830_setup_flush();
-       return 0;
-}
-
-static void intel_i830_cleanup(void)
-{
-       iounmap(intel_private.registers);
+       readl(intel_private.gtt+j-1);
 }
 
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static int intel_fake_agp_insert_entries(struct agp_memory *mem,
+                                        off_t pg_start, int type)
 {
-       int i, j, num_entries;
-       void *temp;
+       int i, j;
        int ret = -EINVAL;
-       int mask_type;
 
        if (mem->page_count == 0)
                goto out;
 
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
+       if (pg_start < intel_private.base.gtt_stolen_entries) {
                dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
+                          "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
+                          pg_start, intel_private.base.gtt_stolen_entries);
 
                dev_info(&intel_private.pcidev->dev,
                         "trying to insert into local/stolen memory\n");
                goto out_err;
        }
 
-       if ((pg_start + mem->page_count) > num_entries)
+       if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
                goto out_err;
 
-       /* The i830 can't check the GTT for entries since its read only,
-        * depend on the caller to make the correct offset decisions.
-        */
-
        if (type != mem->type)
                goto out_err;
 
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
+       if (!intel_private.driver->check_flags(type))
                goto out_err;
 
        if (!mem->is_flushed)
                global_cache_flush();
 
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.registers+I810_PTE_BASE+(j*4));
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+               ret = intel_agp_map_memory(mem);
+               if (ret != 0)
+                       return ret;
+
+               intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+                                           pg_start, type);
+       } else {
+               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+                       dma_addr_t addr = page_to_phys(mem->pages[i]);
+                       intel_private.driver->write_entry(addr,
+                                                         j, type);
+               }
+               readl(intel_private.gtt+j-1);
        }
-       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
 
 out:
        ret = 0;
@@ -982,29 +1042,39 @@ out_err:
        return ret;
 }
 
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static int intel_fake_agp_remove_entries(struct agp_memory *mem,
+                                        off_t pg_start, int type)
 {
        int i;
 
        if (mem->page_count == 0)
                return 0;
 
-       if (pg_start < intel_private.gtt_entries) {
+       if (pg_start < intel_private.base.gtt_stolen_entries) {
                dev_info(&intel_private.pcidev->dev,
                         "trying to disable local/stolen memory\n");
                return -EINVAL;
        }
 
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
+               intel_agp_unmap_memory(mem);
+
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               intel_private.driver->write_entry(intel_private.scratch_page_dma,
+                                                 i, 0);
        }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+       readl(intel_private.gtt+i-1);
 
        return 0;
 }
 
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
+{
+       intel_private.driver->chipset_flush();
+}
+
+static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
+                                                      int type)
 {
        if (type == AGP_PHYS_MEMORY)
                return alloc_agpphysmem_i8xx(pg_count, type);
@@ -1015,9 +1085,9 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
 static int intel_alloc_chipset_flush_resource(void)
 {
        int ret;
-       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+       ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
                                     PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-                                    pcibios_align_resource, agp_bridge->dev);
+                                    pcibios_align_resource, intel_private.bridge_dev);
 
        return ret;
 }
@@ -1027,11 +1097,11 @@ static void intel_i915_setup_chipset_flush(void)
        int ret;
        u32 temp;
 
-       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+       pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp);
        if (!(temp & 0x1)) {
                intel_alloc_chipset_flush_resource();
                intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+               pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
        } else {
                temp &= ~1;
 
@@ -1050,17 +1120,17 @@ static void intel_i965_g33_setup_chipset_flush(void)
        u32 temp_hi, temp_lo;
        int ret;
 
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+       pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
+       pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo);
 
        if (!(temp_lo & 0x1)) {
 
                intel_alloc_chipset_flush_resource();
 
                intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+               pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4,
                        upper_32_bits(intel_private.ifp_resource.start));
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+               pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
        } else {
                u64 l64;
 
@@ -1083,7 +1153,7 @@ static void intel_i9xx_setup_flush(void)
        if (intel_private.ifp_resource.start)
                return;
 
-       if (IS_SNB)
+       if (INTEL_GTT_GEN == 6)
                return;
 
        /* setup a resource for this object */
@@ -1091,7 +1161,7 @@ static void intel_i9xx_setup_flush(void)
        intel_private.ifp_resource.flags = IORESOURCE_MEM;
 
        /* Setup chipset flush for 915 */
-       if (IS_I965 || IS_G33 || IS_G4X) {
+       if (IS_G33 || INTEL_GTT_GEN >= 4) {
                intel_i965_g33_setup_chipset_flush();
        } else {
                intel_i915_setup_chipset_flush();
@@ -1104,41 +1174,7 @@ static void intel_i9xx_setup_flush(void)
                        "can't ioremap flush page - no chipset flushing\n");
 }
 
-static int intel_i9xx_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.gtt+i);
-               }
-               readl(intel_private.gtt+i-1);   /* PCI Posting. */
-       }
-
-       global_cache_flush();
-
-       intel_i9xx_setup_flush();
-
-       return 0;
-}
-
-static void intel_i915_cleanup(void)
+static void i9xx_cleanup(void)
 {
        if (intel_private.i9xx_flush_page)
                iounmap(intel_private.i9xx_flush_page);
@@ -1146,320 +1182,93 @@ static void intel_i915_cleanup(void)
                release_resource(&intel_private.ifp_resource);
        intel_private.ifp_resource.start = 0;
        intel_private.resource_valid = 0;
-       iounmap(intel_private.gtt);
-       iounmap(intel_private.registers);
 }
 
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+static void i9xx_chipset_flush(void)
 {
        if (intel_private.i9xx_flush_page)
                writel(1, intel_private.i9xx_flush_page);
 }
 
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       int num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
-
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to insert into local/stolen memory\n");
-               goto out_err;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-       /* The i915 can't check the GTT for entries since it's read only;
-        * depend on the caller to make the correct offset decisions.
-        */
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
-               goto out_err;
-
-       if (!mem->is_flushed)
-               global_cache_flush();
-
-       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
-
- out:
-       ret = 0;
- out_err:
-       mem->is_flushed = true;
-       return ret;
+       /* Shift high bits down */
+       addr |= (addr >> 28) & 0xf0;
+       writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
 }
 
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static bool gen6_check_flags(unsigned int flags)
 {
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to disable local/stolen memory\n");
-               return -EINVAL;
-       }
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++)
-               writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
-       readl(intel_private.gtt+i-1);
-
-       return 0;
+       return true;
 }
 
-/* Return the aperture size by just checking the resource length.  The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
+static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-       int aper_size; /* size in megabytes */
-       int i;
+       unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+       unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+       u32 pte_flags;
 
-       aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
-
-       for (i = 0; i < num_sizes; i++) {
-               if (aper_size == intel_i830_sizes[i].size) {
-                       agp_bridge->current_size = intel_i830_sizes + i;
-                       return aper_size;
-               }
+       if (type_mask == AGP_USER_UNCACHED_MEMORY)
+               pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
+       else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+               pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
+       } else { /* set 'normal'/'cached' to LLC by default */
+               pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
        }
 
-       return 0;
+       /* gen6 has bit11-4 for physical addr bit39-32 */
+       addr |= (addr >> 28) & 0xff0;
+       writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static int intel_i915_get_gtt_size(void)
+static void gen6_cleanup(void)
 {
-       int size;
-
-       if (IS_G33) {
-               u16 gmch_ctrl;
-
-               /* G33's GTT size defined in gmch_ctrl */
-               pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-               case I830_GMCH_GMS_STOLEN_512:
-                       size = 512;
-                       break;
-               case I830_GMCH_GMS_STOLEN_1024:
-                       size = 1024;
-                       break;
-               case I830_GMCH_GMS_STOLEN_8192:
-                       size = 8*1024;
-                       break;
-               default:
-                       dev_info(&agp_bridge->dev->dev,
-                                "unknown page table size 0x%x, assuming 512KB\n",
-                               (gmch_ctrl & I830_GMCH_GMS_MASK));
-                       size = 512;
-               }
-       } else {
-               /* On previous hardware, the GTT size was just what was
-                * required to map the aperture.
-                */
-               size = agp_bridge->driver->fetch_size();
-       }
-
-       return KB(size);
 }
 
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
+static int i9xx_setup(void)
 {
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp, temp2;
-       int gtt_map_size;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
+       u32 reg_addr;
 
-       gtt_map_size = intel_i915_get_gtt_size();
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
 
-       intel_private.gtt = ioremap(temp2, gtt_map_size);
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_map_size / 4;
-
-       temp &= 0xfff80000;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
+       reg_addr &= 0xfff80000;
 
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.gtt);
-               iounmap(intel_private.registers);
+       intel_private.registers = ioremap(reg_addr, 128 * 4096);
+       if (!intel_private.registers)
                return -ENOMEM;
-       }
-
-       agp_bridge->gatt_table = NULL;
 
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* Shift high bits down */
-       addr |= (addr >> 28) & 0xf0;
-
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
+       if (INTEL_GTT_GEN == 3) {
+               u32 gtt_addr;
 
-static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* gen6 has bit11-4 for physical addr bit39-32 */
-       addr |= (addr >> 28) & 0xff0;
-
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
-
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
-{
-       u16 snb_gmch_ctl;
-
-       switch (agp_bridge->dev->device) {
-       case PCI_DEVICE_ID_INTEL_GM45_HB:
-       case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
-       case PCI_DEVICE_ID_INTEL_Q45_HB:
-       case PCI_DEVICE_ID_INTEL_G45_HB:
-       case PCI_DEVICE_ID_INTEL_G41_HB:
-       case PCI_DEVICE_ID_INTEL_B43_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
-               *gtt_offset = *gtt_size = MB(2);
-               break;
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB:
-               *gtt_offset = MB(2);
+               pci_read_config_dword(intel_private.pcidev,
+                                     I915_PTEADDR, &gtt_addr);
+               intel_private.gtt_bus_addr = gtt_addr;
+       } else {
+               u32 gtt_offset;
 
-               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
-               default:
-               case SNB_GTT_SIZE_0M:
-                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
-                       *gtt_size = MB(0);
+               switch (INTEL_GTT_GEN) {
+               case 5:
+               case 6:
+                       gtt_offset = MB(2);
                        break;
-               case SNB_GTT_SIZE_1M:
-                       *gtt_size = MB(1);
-                       break;
-               case SNB_GTT_SIZE_2M:
-                       *gtt_size = MB(2);
+               case 4:
+               default:
+                       gtt_offset =  KB(512);
                        break;
                }
-               break;
-       default:
-               *gtt_offset = *gtt_size = KB(512);
-       }
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
-       int gtt_offset, gtt_size;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
-       temp &= 0xfff00000;
-
-       intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
-
-       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
-
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_size / 4;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.gtt);
-               iounmap(intel_private.registers);
-               return -ENOMEM;
+               intel_private.gtt_bus_addr = reg_addr + gtt_offset;
        }
 
-       agp_bridge->gatt_table = NULL;
+       intel_private.pte_bus_addr =
+               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-       agp_bridge->gatt_bus_addr = temp;
+       intel_i9xx_setup_flush();
 
        return 0;
 }
@@ -1475,7 +1284,7 @@ static const struct agp_bridge_driver intel_810_driver = {
        .cleanup                = intel_i810_cleanup,
        .mask_memory            = intel_i810_mask_memory,
        .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
+       .agp_enable             = intel_fake_agp_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
@@ -1490,161 +1299,282 @@ static const struct agp_bridge_driver intel_810_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_fake_agp_driver = {
        .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
        .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i830_configure,
-       .fetch_size             = intel_i830_fetch_size,
-       .cleanup                = intel_i830_cleanup,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
+       .aperture_sizes         = intel_fake_agp_sizes,
+       .num_aperture_sizes     = ARRAY_SIZE(intel_fake_agp_sizes),
+       .configure              = intel_fake_agp_configure,
+       .fetch_size             = intel_fake_agp_fetch_size,
+       .cleanup                = intel_gtt_cleanup,
+       .agp_enable             = intel_fake_agp_enable,
        .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i830_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i830_insert_entries,
-       .remove_memory          = intel_i830_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
+       .create_gatt_table      = intel_fake_agp_create_gatt_table,
+       .free_gatt_table        = intel_fake_agp_free_gatt_table,
+       .insert_memory          = intel_fake_agp_insert_entries,
+       .remove_memory          = intel_fake_agp_remove_entries,
+       .alloc_by_type          = intel_fake_agp_alloc_by_type,
        .free_by_type           = intel_i810_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i830_chipset_flush,
+       .chipset_flush          = intel_fake_agp_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_915_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i9xx_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i81x_gtt_driver = {
+       .gen = 1,
+       .dma_mask_size = 32,
 };
-
-static const struct agp_bridge_driver intel_i965_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i9xx_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i965_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i8xx_gtt_driver = {
+       .gen = 2,
+       .setup = i830_setup,
+       .cleanup = i830_cleanup,
+       .write_entry = i830_write_entry,
+       .dma_mask_size = 32,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i830_chipset_flush,
 };
-
-static const struct agp_bridge_driver intel_gen6_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i9xx_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .mask_memory            = intel_gen6_mask_memory,
-       .masks                  = intel_gen6_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i965_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_gen6_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i915_gtt_driver = {
+       .gen = 3,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       /* i945 is the last gpu to need phys mem (for overlay and cursors). */
+       .write_entry = i830_write_entry, 
+       .dma_mask_size = 32,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g33_gtt_driver = {
+       .gen = 3,
+       .is_g33 = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver pineview_gtt_driver = {
+       .gen = 3,
+       .is_pineview = 1, .is_g33 = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver i965_gtt_driver = {
+       .gen = 4,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g4x_gtt_driver = {
+       .gen = 5,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver ironlake_gtt_driver = {
+       .gen = 5,
+       .is_ironlake = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver sandybridge_gtt_driver = {
+       .gen = 6,
+       .setup = i9xx_setup,
+       .cleanup = gen6_cleanup,
+       .write_entry = gen6_write_entry,
+       .dma_mask_size = 40,
+       .check_flags = gen6_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_g33_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i9xx_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
+/* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
+ * driver and gmch_driver must be non-null, and find_gmch will determine
+ * which one should be used if a gmch_chip_id is present.
+ */
+static const struct intel_gtt_driver_description {
+       unsigned int gmch_chip_id;
+       char *name;
+       const struct agp_bridge_driver *gmch_driver;
+       const struct intel_gtt_driver *gtt_driver;
+} intel_gtt_chipsets[] = {
+       { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82854_IG, "854",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82865_IG, "865",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G33_IG, "G33",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
+               &intel_fake_agp_driver, &pineview_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
+               &intel_fake_agp_driver, &pineview_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_B43_IG, "B43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G41_IG, "G41",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
+           "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
+           "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { 0, NULL, NULL }
 };
+
+static int find_gmch(u16 device)
+{
+       struct pci_dev *gmch_device;
+
+       gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+       if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
+               gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                            device, gmch_device);
+       }
+
+       if (!gmch_device)
+               return 0;
+
+       intel_private.pcidev = gmch_device;
+       return 1;
+}
+
+int intel_gmch_probe(struct pci_dev *pdev,
+                                     struct agp_bridge_data *bridge)
+{
+       int i, mask;
+       bridge->driver = NULL;
+
+       for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
+               if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+                       bridge->driver =
+                               intel_gtt_chipsets[i].gmch_driver;
+                       intel_private.driver = 
+                               intel_gtt_chipsets[i].gtt_driver;
+                       break;
+               }
+       }
+
+       if (!bridge->driver)
+               return 0;
+
+       bridge->dev_private_data = &intel_private;
+       bridge->dev = pdev;
+
+       intel_private.bridge_dev = pci_dev_get(pdev);
+
+       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+
+       mask = intel_private.driver->dma_mask_size;
+       if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
+               dev_err(&intel_private.pcidev->dev,
+                       "set gfx device dma mask %d-bit failed!\n", mask);
+       else
+               pci_set_consistent_dma_mask(intel_private.pcidev,
+                                           DMA_BIT_MASK(mask));
+
+       if (bridge->driver == &intel_810_driver)
+               return 1;
+
+       if (intel_gtt_init() != 0)
+               return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(intel_gmch_probe);
+
+struct intel_gtt *intel_gtt_get(void)
+{
+       return &intel_private.base;
+}
+EXPORT_SYMBOL(intel_gtt_get);
+
+void intel_gmch_remove(struct pci_dev *pdev)
+{
+       if (intel_private.pcidev)
+               pci_dev_put(intel_private.pcidev);
+       if (intel_private.bridge_dev)
+               pci_dev_put(intel_private.bridge_dev);
+}
+EXPORT_SYMBOL(intel_gmch_remove);
+
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_LICENSE("GPL and additional rights");
index a4eee324eb1ece730780079d0d968b316330a1e6..55b8667f739f64a82731ab926738601825cbb00c 100644 (file)
 #include <linux/bitops.h>
 #include <linux/compat.h>
 #include <linux/clocksource.h>
+#include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
 #include <asm/current.h>
-#include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
 
@@ -81,13 +81,13 @@ static cycle_t read_hpet(struct clocksource *cs)
 }
 
 static struct clocksource clocksource_hpet = {
-        .name           = "hpet",
-        .rating         = 250,
-        .read           = read_hpet,
-        .mask           = CLOCKSOURCE_MASK(64),
-       .mult           = 0, /* to be calculated */
-        .shift          = 10,
-        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .name           = "hpet",
+       .rating         = 250,
+       .read           = read_hpet,
+       .mask           = CLOCKSOURCE_MASK(64),
+       .mult           = 0,            /* to be calculated */
+       .shift          = 10,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 static struct clocksource *hpet_clocksource;
 #endif
@@ -465,6 +465,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
        if (irq) {
                unsigned long irq_flags;
 
+               if (devp->hd_flags & HPET_SHARED_IRQ) {
+                       /*
+                        * To prevent the interrupt handler from seeing an
+                        * unwanted interrupt status bit, program the timer
+                        * so that it will not fire in the near future ...
+                        */
+                       writel(readl(&timer->hpet_config) & ~Tn_TYPE_CNF_MASK,
+                              &timer->hpet_config);
+                       write_counter(read_counter(&hpet->hpet_mc),
+                                     &timer->hpet_compare);
+                       /* ... and clear any left-over status. */
+                       isr = 1 << (devp - devp->hd_hpets->hp_dev);
+                       writel(isr, &hpet->hpet_isr);
+               }
+
                sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
                irq_flags = devp->hd_flags & HPET_SHARED_IRQ
                                                ? IRQF_SHARED : IRQF_DISABLED;
@@ -581,11 +596,10 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
                break;
        case HPET_INFO:
                {
+                       memset(info, 0, sizeof(*info));
                        if (devp->hd_ireqfreq)
                                info->hi_ireqfreq =
                                        hpet_time_div(hpetp, devp->hd_ireqfreq);
-                       else
-                               info->hi_ireqfreq = 0;
                        info->hi_flags =
                            readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
                        info->hi_hpet = hpetp->hp_which;
@@ -811,7 +825,7 @@ int hpet_alloc(struct hpet_data *hdp)
        struct hpets *hpetp;
        size_t siz;
        struct hpet __iomem *hpet;
-       static struct hpets *last = NULL;
+       static struct hpets *last;
        unsigned long period;
        unsigned long long temp;
        u32 remainder;
@@ -1000,6 +1014,8 @@ static int hpet_acpi_add(struct acpi_device *device)
                return -ENODEV;
 
        if (!data.hd_address || !data.hd_nirqs) {
+               if (data.hd_address)
+                       iounmap(data.hd_address);
                printk("%s: no address or irqs in _CRS\n", __func__);
                return -ENODEV;
        }
index 7b01bc609de3497cb0a17c4748d28a57e936e498..c3425bb3a1f6fe2348330d8336c76fd3b60d4b90 100644 (file)
@@ -1303,13 +1303,11 @@ static int __init hvc_iucv_init(void)
        if (rc) {
                pr_err("Registering IUCV handlers failed with error code=%d\n",
                        rc);
-               goto out_error_iucv;
+               goto out_error_hvc;
        }
 
        return 0;
 
-out_error_iucv:
-       iucv_unregister(&hvc_iucv_handler, 0);
 out_error_hvc:
        for (i = 0; i < hvc_iucv_devices; i++)
                if (hvc_iucv_table[i])
index c4efb55cbc03d380fded78b6e5bc61e63406cbcb..7a84a0595477512581b4247f8a0165d775d34aba 100644 (file)
@@ -61,7 +61,8 @@ console_initcall(hvc_tile_console_init);
 
 static int __init hvc_tile_init(void)
 {
-       hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
-       return 0;
+       struct hvc_struct *s;
+       s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+       return IS_ERR(s) ? PTR_ERR(s) : 0;
 }
 device_initcall(hvc_tile_init);
index 60446f82a3fc2653c905adb3a6f944c1686f0863..6b8e6d18a8e6e7c8c44b2644ed7c72beb953f1f5 100644 (file)
@@ -74,7 +74,8 @@ static int __write_console(const char *data, int len)
        wmb();                  /* write ring before updating pointer */
        intf->out_prod = prod;
 
-       notify_daemon();
+       if (sent)
+               notify_daemon();
        return sent;
 }
 
index e537610d2f09475bf321b8652815fb9eaa46c762..b293d57d30a79ee11d6177fb9296a2250c64f1a3 100644 (file)
@@ -1665,6 +1665,17 @@ static int check_hotmod_int_op(const char *curr, const char *option,
        return 0;
 }
 
+static struct smi_info *smi_info_alloc(void)
+{
+       struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+       if (info) {
+               spin_lock_init(&info->si_lock);
+               spin_lock_init(&info->msg_lock);
+       }
+       return info;
+}
+
 static int hotmod_handler(const char *val, struct kernel_param *kp)
 {
        char *str = kstrdup(val, GFP_KERNEL);
@@ -1779,7 +1790,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                }
 
                if (op == HM_ADD) {
-                       info = kzalloc(sizeof(*info), GFP_KERNEL);
+                       info = smi_info_alloc();
                        if (!info) {
                                rv = -ENOMEM;
                                goto out;
@@ -1844,7 +1855,7 @@ static __devinit void hardcode_find_bmc(void)
                if (!ports[i] && !addrs[i])
                        continue;
 
-               info = kzalloc(sizeof(*info), GFP_KERNEL);
+               info = smi_info_alloc();
                if (!info)
                        return;
 
@@ -2027,7 +2038,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
                return -ENODEV;
        }
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = smi_info_alloc();
        if (!info) {
                printk(KERN_ERR PFX "Could not allocate SI data (3)\n");
                return -ENOMEM;
@@ -2137,7 +2148,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
        if (!acpi_dev)
                return -ENODEV;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = smi_info_alloc();
        if (!info)
                return -ENOMEM;
 
@@ -2318,7 +2329,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 {
        struct smi_info *info;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = smi_info_alloc();
        if (!info) {
                printk(KERN_ERR PFX "Could not allocate SI data\n");
                return;
@@ -2425,7 +2436,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
        struct smi_info *info;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = smi_info_alloc();
        if (!info)
                return -ENOMEM;
 
@@ -2566,7 +2577,7 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
                return -EINVAL;
        }
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = smi_info_alloc();
 
        if (!info) {
                dev_err(&dev->dev,
@@ -3013,7 +3024,7 @@ static __devinit void default_find_bmc(void)
                if (check_legacy_ioport(ipmi_defaults[i].port))
                        continue;
 #endif
-               info = kzalloc(sizeof(*info), GFP_KERNEL);
+               info = smi_info_alloc();
                if (!info)
                        return;
 
@@ -3138,9 +3149,6 @@ static int try_smi_init(struct smi_info *new_smi)
                goto out_err;
        }
 
-       spin_lock_init(&(new_smi->si_lock));
-       spin_lock_init(&(new_smi->msg_lock));
-
        /* Do low-level detection first. */
        if (new_smi->handlers->detect(new_smi->si_sm)) {
                if (new_smi->addr_source)
index a7ca75212bfe1a00cc68bce670db9f9d6ce66dc9..e95d7876ca6bd573b110b778ffb52574dda62038 100644 (file)
@@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
  */
 
 struct getset_keycode_data {
-       unsigned int scancode;
-       unsigned int keycode;
+       struct input_keymap_entry ke;
        int error;
 };
 
@@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
 {
        struct getset_keycode_data *d = data;
 
-       d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
+       d->error = input_get_keycode(handle->dev, &d->ke);
 
        return d->error == 0; /* stop as soon as we successfully get one */
 }
 
 int getkeycode(unsigned int scancode)
 {
-       struct getset_keycode_data d = { scancode, 0, -ENODEV };
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = 0,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
 
        input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
 
-       return d.error ?: d.keycode;
+       return d.error ?: d.ke.keycode;
 }
 
 static int setkeycode_helper(struct input_handle *handle, void *data)
 {
        struct getset_keycode_data *d = data;
 
-       d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
+       d->error = input_set_keycode(handle->dev, &d->ke);
 
        return d->error == 0; /* stop as soon as we successfully set one */
 }
 
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-       struct getset_keycode_data d = { scancode, keycode, -ENODEV };
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = keycode,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
 
        input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
 
index e985b1c2730e800db599ad445371a8b100eee506..1256454b2d4364f7fa6ad95b661d30ad62b673b4 100644 (file)
@@ -876,6 +876,10 @@ static int memory_open(struct inode *inode, struct file *filp)
        if (dev->dev_info)
                filp->f_mapping->backing_dev_info = dev->dev_info;
 
+       /* Is /dev/mem or /dev/kmem ? */
+       if (dev->dev_info == &directly_mappable_cdev_bdi)
+               filp->f_mode |= FMODE_UNSIGNED_OFFSET;
+
        if (dev->fops->open)
                return dev->fops->open(inode, filp);
 
index f3019f53e8752becb85b459cc6ad5bc902b986ab..eaa5d3efa79da4cb061b4fbaf9d6acb6f21afd5e 100644 (file)
@@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] =
 static bool sysrq_down;
 static int sysrq_alt_use;
 static int sysrq_alt;
+static DEFINE_SPINLOCK(sysrq_event_lock);
 
 static bool sysrq_filter(struct input_handle *handle, unsigned int type,
                         unsigned int code, int value)
 {
+       bool suppress;
+
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&sysrq_event_lock);
+
        if (type != EV_KEY)
                goto out;
 
@@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type,
        }
 
 out:
-       return sysrq_down;
+       suppress = sysrq_down;
+       spin_unlock(&sysrq_event_lock);
+
+       return suppress;
 }
 
 static int sysrq_connect(struct input_handler *handler,
@@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle)
 }
 
 /*
- * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all
- * keyboards have SysRq ikey predefined and so user may add it to keymap
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
  * later, but we expect all such keyboards to have left alt.
  */
 static const struct input_device_id sysrq_ids[] = {
index 717305d30444479d67130194a7f922173254da75..a44611652282c6c173e70b861910d4bee1610db4 100644 (file)
@@ -308,7 +308,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
         * isr before we end up here.
         */
        if (p->flags & FLAG_CLOCKSOURCE)
-               p->total_cycles += p->match_value;
+               p->total_cycles += p->match_value + 1;
 
        if (!(p->flags & FLAG_REPROGRAM))
                p->next_match_value = p->max_match_value;
@@ -403,7 +403,7 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
        raw = sh_cmt_get_counter(p, &has_wrapped);
 
        if (unlikely(has_wrapped))
-               raw += p->match_value;
+               raw += p->match_value + 1;
        spin_unlock_irqrestore(&p->lock, flags);
 
        return value + raw;
@@ -445,7 +445,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
 
        /* clk_get_rate() needs an enabled clock */
        clk_enable(p->clk);
-       p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+       p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
        clk_disable(p->clk);
 
        /* TODO: calculate good shift from rate and counter bit width */
@@ -478,7 +478,7 @@ static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic)
        ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
 
        if (periodic)
-               sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+               sh_cmt_set_next(p, ((p->rate + HZ/2) / HZ) - 1);
        else
                sh_cmt_set_next(p, p->max_match_value);
 }
@@ -523,9 +523,9 @@ static int sh_cmt_clock_event_next(unsigned long delta,
 
        BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
        if (likely(p->flags & FLAG_IRQCONTEXT))
-               p->next_match_value = delta;
+               p->next_match_value = delta - 1;
        else
-               sh_cmt_set_next(p, delta);
+               sh_cmt_set_next(p, delta - 1);
 
        return 0;
 }
index 199dcb9f0b836da1431a5791b05309d79f9c330c..c63a438237444a0e35fa05bdef9d0d232839c463 100644 (file)
@@ -918,8 +918,8 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu(j, policy->cpus) {
-       if (!cpu_online(j))
-               continue;
+               if (!cpu_online(j))
+                       continue;
                per_cpu(cpufreq_cpu_data, j) = policy;
                per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }
index 7b5093664e49ba4d2172cd208c5d6ae7b7b419ee..c631f27a3dcc754aa8ebe97ab7ef0a351b55a776 100644 (file)
@@ -30,6 +30,8 @@
 
 #define DEF_FREQUENCY_DOWN_DIFFERENTIAL                (10)
 #define DEF_FREQUENCY_UP_THRESHOLD             (80)
+#define DEF_SAMPLING_DOWN_FACTOR               (1)
+#define MAX_SAMPLING_DOWN_FACTOR               (100000)
 #define MICRO_FREQUENCY_DOWN_DIFFERENTIAL      (3)
 #define MICRO_FREQUENCY_UP_THRESHOLD           (95)
 #define MICRO_FREQUENCY_MIN_SAMPLE_RATE                (10000)
@@ -82,6 +84,7 @@ struct cpu_dbs_info_s {
        unsigned int freq_lo;
        unsigned int freq_lo_jiffies;
        unsigned int freq_hi_jiffies;
+       unsigned int rate_mult;
        int cpu;
        unsigned int sample_type:1;
        /*
@@ -108,10 +111,12 @@ static struct dbs_tuners {
        unsigned int up_threshold;
        unsigned int down_differential;
        unsigned int ignore_nice;
+       unsigned int sampling_down_factor;
        unsigned int powersave_bias;
        unsigned int io_is_busy;
 } dbs_tuners_ins = {
        .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+       .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
        .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
        .ignore_nice = 0,
        .powersave_bias = 0,
@@ -259,6 +264,7 @@ static ssize_t show_##file_name                                             \
 show_one(sampling_rate, sampling_rate);
 show_one(io_is_busy, io_is_busy);
 show_one(up_threshold, up_threshold);
+show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
 show_one(powersave_bias, powersave_bias);
 
@@ -340,6 +346,29 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
        return count;
 }
 
+static ssize_t store_sampling_down_factor(struct kobject *a,
+                       struct attribute *b, const char *buf, size_t count)
+{
+       unsigned int input, j;
+       int ret;
+       ret = sscanf(buf, "%u", &input);
+
+       if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+               return -EINVAL;
+       mutex_lock(&dbs_mutex);
+       dbs_tuners_ins.sampling_down_factor = input;
+
+       /* Reset down sampling multiplier in case it was active */
+       for_each_online_cpu(j) {
+               struct cpu_dbs_info_s *dbs_info;
+               dbs_info = &per_cpu(od_cpu_dbs_info, j);
+               dbs_info->rate_mult = 1;
+       }
+       mutex_unlock(&dbs_mutex);
+
+       return count;
+}
+
 static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
                                      const char *buf, size_t count)
 {
@@ -401,6 +430,7 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
 define_one_global_rw(sampling_rate);
 define_one_global_rw(io_is_busy);
 define_one_global_rw(up_threshold);
+define_one_global_rw(sampling_down_factor);
 define_one_global_rw(ignore_nice_load);
 define_one_global_rw(powersave_bias);
 
@@ -409,6 +439,7 @@ static struct attribute *dbs_attributes[] = {
        &sampling_rate_min.attr,
        &sampling_rate.attr,
        &up_threshold.attr,
+       &sampling_down_factor.attr,
        &ignore_nice_load.attr,
        &powersave_bias.attr,
        &io_is_busy.attr,
@@ -562,6 +593,10 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 
        /* Check for frequency increase */
        if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
+               /* If switching to max speed, apply sampling_down_factor */
+               if (policy->cur < policy->max)
+                       this_dbs_info->rate_mult =
+                               dbs_tuners_ins.sampling_down_factor;
                dbs_freq_increase(policy, policy->max);
                return;
        }
@@ -584,6 +619,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
                                (dbs_tuners_ins.up_threshold -
                                 dbs_tuners_ins.down_differential);
 
+               /* No longer fully busy, reset rate_mult */
+               this_dbs_info->rate_mult = 1;
+
                if (freq_next < policy->min)
                        freq_next = policy->min;
 
@@ -607,7 +645,8 @@ static void do_dbs_timer(struct work_struct *work)
        int sample_type = dbs_info->sample_type;
 
        /* We want all CPUs to do sampling nearly on same jiffy */
-       int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+       int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
+               * dbs_info->rate_mult);
 
        if (num_online_cpus() > 1)
                delay -= jiffies % delay;
@@ -711,6 +750,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        }
                }
                this_dbs_info->cpu = cpu;
+               this_dbs_info->rate_mult = 1;
                ondemand_powersave_bias_init_cpu(cpu);
                /*
                 * Start the timerschedule work, when this governor
index 0eac3da566ba23ff8aaf3c33256b5c3ca6280281..a84250a5dd5111f08f79c58c9ff34875b744ff65 100644 (file)
@@ -1467,7 +1467,7 @@ static int ablkcipher_add(unsigned int *drestp, struct scatterlist *dst,
                return -EINVAL;
 
        while (size) {
-               copy = min(drest, min(size, dst->length));
+               copy = min3(drest, size, dst->length);
 
                size -= copy;
                drest -= copy;
@@ -1729,7 +1729,7 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset
                return -EINVAL;
 
        while (size) {
-               copy = min(srest, min(dst->length, size));
+               copy = min3(srest, dst->length, size);
 
                daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
                memcpy(daddr + dst->offset + offset, saddr, copy);
index ce7146677e9b48bf624fa6de659b5b0a506754ec..d7ca43a828bd3fe57b3de1341d7e75d1bed84f0a 100644 (file)
 
 #if PAGE_SHIFT < 20
 #define PAGES_TO_MiB( pages )  ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
+#define MiB_TO_PAGES(mb)       ((mb) >> (20 - PAGE_SHIFT))
 #else                          /* PAGE_SHIFT > 20 */
 #define PAGES_TO_MiB( pages )  ( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define MiB_TO_PAGES(mb)       ((mb) >> (PAGE_SHIFT - 20))
 #endif
 
 #define edac_printk(level, prefix, fmt, arg...) \
@@ -328,7 +330,7 @@ struct csrow_info {
 
 struct mcidev_sysfs_group {
        const char *name;                               /* group name */
-       struct mcidev_sysfs_attribute *mcidev_attr;     /* group attributes */
+       const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
 };
 
 struct mcidev_sysfs_group_kobj {
@@ -336,7 +338,7 @@ struct mcidev_sysfs_group_kobj {
 
        struct kobject kobj;            /* kobj for the group */
 
-       struct mcidev_sysfs_group *grp; /* group description table */
+       const struct mcidev_sysfs_group *grp;   /* group description table */
        struct mem_ctl_info *mci;       /* the parent */
 };
 
@@ -347,7 +349,7 @@ struct mcidev_sysfs_group_kobj {
 struct mcidev_sysfs_attribute {
        /* It should use either attr or grp */
        struct attribute attr;
-       struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
+       const struct mcidev_sysfs_group *grp;   /* Points to a group of attributes */
 
        /* Ops for show/store values at the attribute - not used on group */
         ssize_t (*show)(struct mem_ctl_info *,char *);
@@ -440,7 +442,7 @@ struct mem_ctl_info {
         * If attributes are desired, then set to array of attributes
         * If no attributes are desired, leave NULL
         */
-       struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+       const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
 
        /* work struct for this MC */
        struct delayed_work work;
@@ -810,6 +812,7 @@ extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
 extern void edac_mc_free(struct mem_ctl_info *mci);
 extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *find_mci_by_dev(struct device *dev);
 extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
 extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
                                      unsigned long page);
index 6b21e25f7a84cc99ad6ea710b788745992d1170f..ba6586a69ccce3b000fb22ee21512ab4673b44ac 100644 (file)
@@ -207,6 +207,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
        }
 
        mci->op_state = OP_ALLOC;
+       INIT_LIST_HEAD(&mci->grp_kobj_list);
 
        /*
         * Initialize the 'root' kobj for the edac_mc controller
@@ -234,18 +235,24 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc);
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
+       debugf1("%s()\n", __func__);
+
        edac_mc_unregister_sysfs_main_kobj(mci);
+
+       /* free the mci instance memory here */
+       kfree(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
 
-/*
+/**
  * find_mci_by_dev
  *
  *     scan list of controllers looking for the one that manages
  *     the 'dev' device
+ * @dev: pointer to a struct device related with the MCI
  */
-static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
+struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 {
        struct mem_ctl_info *mci;
        struct list_head *item;
@@ -261,6 +268,7 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(find_mci_by_dev);
 
 /*
  * handler for EDAC to check if NMI type handler has asserted interrupt
index a4135860149b5592e6e73e8036796f63e6f045d4..dce61f7ba38ba9094d9e300f62fe542312a623b1 100644 (file)
@@ -631,9 +631,6 @@ static void edac_mci_control_release(struct kobject *kobj)
 
        /* decrement the module ref count */
        module_put(mci->owner);
-
-       /* free the mci instance memory here */
-       kfree(mci);
 }
 
 static struct kobj_type ktype_mci = {
@@ -713,6 +710,8 @@ fail_out:
  */
 void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 {
+       debugf1("%s()\n", __func__);
+
        /* delete the kobj from the mc_kset */
        kobject_put(&mci->edac_mci_kobj);
 }
@@ -760,8 +759,6 @@ static void edac_inst_grp_release(struct kobject *kobj)
 
        grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
        mci = grp->mci;
-
-       kobject_put(&mci->edac_mci_kobj);
 }
 
 /* Intermediate show/store table */
@@ -784,7 +781,7 @@ static struct kobj_type ktype_inst_grp = {
  * object tree.
  */
 static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
-                               struct mcidev_sysfs_attribute *sysfs_attrib,
+                               const struct mcidev_sysfs_attribute *sysfs_attrib,
                                struct kobject *kobj)
 {
        int err;
@@ -792,6 +789,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
        debugf1("%s()\n", __func__);
 
        while (sysfs_attrib) {
+               debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
                if (sysfs_attrib->grp) {
                        struct mcidev_sysfs_group_kobj *grp_kobj;
 
@@ -799,10 +797,9 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
                        if (!grp_kobj)
                                return -ENOMEM;
 
-                       list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
-
                        grp_kobj->grp = sysfs_attrib->grp;
                        grp_kobj->mci = mci;
+                       list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
 
                        debugf0("%s() grp %s, mci %p\n", __func__,
                                sysfs_attrib->grp->name, mci);
@@ -811,26 +808,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
                                                &ktype_inst_grp,
                                                &mci->edac_mci_kobj,
                                                sysfs_attrib->grp->name);
-                       if (err)
+                       if (err < 0) {
+                               printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
                                return err;
-
+                       }
                        err = edac_create_mci_instance_attributes(mci,
                                        grp_kobj->grp->mcidev_attr,
                                        &grp_kobj->kobj);
 
-                       if (err)
+                       if (err < 0)
                                return err;
                } else if (sysfs_attrib->attr.name) {
                        debugf0("%s() file %s\n", __func__,
                                sysfs_attrib->attr.name);
 
                        err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+                       if (err < 0) {
+                               printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
+                               return err;
+                       }
                } else
                        break;
 
-               if (err) {
-                       return err;
-               }
                sysfs_attrib++;
        }
 
@@ -843,7 +842,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
  *     directory of this mci instance.
  */
 static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
-                               struct mcidev_sysfs_attribute *sysfs_attrib,
+                               const struct mcidev_sysfs_attribute *sysfs_attrib,
                                struct kobject *kobj, int count)
 {
        struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
@@ -855,13 +854,24 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
         * Remove first all the atributes
         */
        while (sysfs_attrib) {
+               debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
                if (sysfs_attrib->grp) {
-                       list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
-                                           list)
-                               if (grp_kobj->grp == sysfs_attrib->grp)
+                       debugf1("%s() seeking for group %s\n",
+                               __func__, sysfs_attrib->grp->name);
+                       list_for_each_entry(grp_kobj,
+                                           &mci->grp_kobj_list, list) {
+                               debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
+                               if (grp_kobj->grp == sysfs_attrib->grp) {
                                        edac_remove_mci_instance_attributes(mci,
                                                    grp_kobj->grp->mcidev_attr,
                                                    &grp_kobj->kobj, count + 1);
+                                       debugf0("%s() group %s\n", __func__,
+                                               sysfs_attrib->grp->name);
+                                       kobject_put(&grp_kobj->kobj);
+                               }
+                       }
+                       debugf1("%s() end of seeking for group %s\n",
+                               __func__, sysfs_attrib->grp->name);
                } else if (sysfs_attrib->attr.name) {
                        debugf0("%s() file %s\n", __func__,
                                sysfs_attrib->attr.name);
@@ -871,15 +881,14 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
                sysfs_attrib++;
        }
 
-       /*
-        * Now that all attributes got removed, it is save to remove all groups
-        */
-       if (!count)
-               list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
-                                        list) {
-                       debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
-                       kobject_put(&grp_kobj->kobj);
-               }
+       /* Remove the group objects */
+       if (count)
+               return;
+       list_for_each_entry_safe(grp_kobj, tmp,
+                                &mci->grp_kobj_list, list) {
+               list_del(&grp_kobj->list);
+               kfree(grp_kobj);
+       }
 }
 
 
@@ -971,6 +980,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
        debugf0("%s()\n", __func__);
 
        /* remove all csrow kobjects */
+       debugf0("%s()  unregister this mci kobj\n", __func__);
        for (i = 0; i < mci->nr_csrows; i++) {
                if (mci->csrows[i].nr_pages > 0) {
                        debugf0("%s()  unreg csrow-%d\n", __func__, i);
@@ -978,20 +988,20 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
                }
        }
 
-       debugf0("%s()  remove_link\n", __func__);
+       /* remove this mci instance's attribtes */
+       if (mci->mc_driver_sysfs_attributes) {
+               debugf0("%s()  unregister mci private attributes\n", __func__);
+               edac_remove_mci_instance_attributes(mci,
+                                               mci->mc_driver_sysfs_attributes,
+                                               &mci->edac_mci_kobj, 0);
+       }
 
        /* remove the symlink */
+       debugf0("%s()  remove_link\n", __func__);
        sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
 
-       debugf0("%s()  remove_mci_instance\n", __func__);
-
-       /* remove this mci instance's attribtes */
-       edac_remove_mci_instance_attributes(mci,
-                                           mci->mc_driver_sysfs_attributes,
-                                           &mci->edac_mci_kobj, 0);
-       debugf0("%s()  unregister this mci kobj\n", __func__);
-
        /* unregister this instance's kobject */
+       debugf0("%s()  remove_mci_instance\n", __func__);
        kobject_put(&mci->edac_mci_kobj);
 }
 
index 0fd5b85a0f756745bd1074ae673e89d6c81a237a..362861c157794aa81561d485607824e87b8216d4 100644 (file)
 
 #include "edac_core.h"
 
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+static int probed;
+
+static int use_pci_fixup;
+module_param(use_pci_fixup, int, 0444);
+MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
 /*
  * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
  * registers start at bus 255, and are not reported by BIOS.
@@ -212,8 +220,8 @@ struct pci_id_descr {
 };
 
 struct pci_id_table {
-       struct pci_id_descr     *descr;
-       int                     n_devs;
+       const struct pci_id_descr       *descr;
+       int                             n_devs;
 };
 
 struct i7core_dev {
@@ -235,8 +243,6 @@ struct i7core_pvt {
        struct i7core_inject    inject;
        struct i7core_channel   channel[NUM_CHANS];
 
-       int             channels; /* Number of active channels */
-
        int             ce_count_available;
        int             csrow_map[NUM_CHANS][MAX_DIMMS];
 
@@ -261,22 +267,22 @@ struct i7core_pvt {
 
        /* Count indicator to show errors not got */
        unsigned                mce_overrun;
-};
 
-/* Static vars */
-static LIST_HEAD(i7core_edac_list);
-static DEFINE_MUTEX(i7core_edac_lock);
+       /* Struct to control EDAC polling */
+       struct edac_pci_ctl_info *i7core_pci;
+};
 
 #define PCI_DESCR(device, function, device_id) \
        .dev = (device),                        \
        .func = (function),                     \
        .dev_id = (device_id)
 
-struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
                /* Memory controller */
        { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR)     },
        { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD)  },
-                       /* Exists only for RDIMM */
+
+               /* Exists only for RDIMM */
        { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1  },
        { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
 
@@ -297,19 +303,9 @@ struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
        { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
        { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
        { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC)   },
-
-               /* Generic Non-core registers */
-       /*
-        * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
-        * On Xeon 55xx, however, it has a different id (8086:2c40). So,
-        * the probing code needs to test for the other address in case of
-        * failure of this one
-        */
-       { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE)  },
-
 };
 
-struct pci_id_descr pci_dev_descr_lynnfield[] = {
+static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
        { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR)         },
        { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD)      },
        { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST)     },
@@ -323,15 +319,9 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = {
        { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
        { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
        { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC)   },
-
-       /*
-        * This is the PCI device has an alternate address on some
-        * processors like Core i7 860
-        */
-       { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)     },
 };
 
-struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
                /* Memory controller */
        { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2)     },
        { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2)  },
@@ -356,17 +346,14 @@ struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
        { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
        { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
        { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2)   },
-
-               /* Generic Non-core registers */
-       { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2)  },
-
 };
 
-#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) }
-struct pci_id_table pci_dev_table[] = {
+#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
+static const struct pci_id_table pci_dev_table[] = {
        PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
        PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
        PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
+       {0,}                    /* 0 terminated list. */
 };
 
 /*
@@ -378,8 +365,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
        {0,}                    /* 0 terminated list. */
 };
 
-static struct edac_pci_ctl_info *i7core_pci;
-
 /****************************************************************************
                        Anciliary status routines
  ****************************************************************************/
@@ -442,6 +427,36 @@ static struct i7core_dev *get_i7core_dev(u8 socket)
        return NULL;
 }
 
+static struct i7core_dev *alloc_i7core_dev(u8 socket,
+                                          const struct pci_id_table *table)
+{
+       struct i7core_dev *i7core_dev;
+
+       i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+       if (!i7core_dev)
+               return NULL;
+
+       i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs,
+                                  GFP_KERNEL);
+       if (!i7core_dev->pdev) {
+               kfree(i7core_dev);
+               return NULL;
+       }
+
+       i7core_dev->socket = socket;
+       i7core_dev->n_devs = table->n_devs;
+       list_add_tail(&i7core_dev->list, &i7core_edac_list);
+
+       return i7core_dev;
+}
+
+static void free_i7core_dev(struct i7core_dev *i7core_dev)
+{
+       list_del(&i7core_dev->list);
+       kfree(i7core_dev->pdev);
+       kfree(i7core_dev);
+}
+
 /****************************************************************************
                        Memory check routines
  ****************************************************************************/
@@ -484,7 +499,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
  * to add a fake description for csrows.
  * So, this driver is attributing one DIMM memory for one csrow.
  */
-static int i7core_get_active_channels(u8 socket, unsigned *channels,
+static int i7core_get_active_channels(const u8 socket, unsigned *channels,
                                      unsigned *csrows)
 {
        struct pci_dev *pdev = NULL;
@@ -545,12 +560,13 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels,
        return 0;
 }
 
-static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+static int get_dimm_config(const struct mem_ctl_info *mci)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
        struct csrow_info *csr;
        struct pci_dev *pdev;
        int i, j;
+       int csrow = 0;
        unsigned long last_page = 0;
        enum edac_type mode;
        enum mem_type mtype;
@@ -664,13 +680,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
                                RANKOFFSET(dimm_dod[j]),
                                banks, ranks, rows, cols);
 
-#if PAGE_SHIFT > 20
-                       npages = size >> (PAGE_SHIFT - 20);
-#else
-                       npages = size << (20 - PAGE_SHIFT);
-#endif
+                       npages = MiB_TO_PAGES(size);
 
-                       csr = &mci->csrows[*csrow];
+                       csr = &mci->csrows[csrow];
                        csr->first_page = last_page + 1;
                        last_page += npages;
                        csr->last_page = last_page;
@@ -678,13 +690,13 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
 
                        csr->page_mask = 0;
                        csr->grain = 8;
-                       csr->csrow_idx = *csrow;
+                       csr->csrow_idx = csrow;
                        csr->nr_channels = 1;
 
                        csr->channels[0].chan_idx = i;
                        csr->channels[0].ce_count = 0;
 
-                       pvt->csrow_map[i][j] = *csrow;
+                       pvt->csrow_map[i][j] = csrow;
 
                        switch (banks) {
                        case 4:
@@ -703,7 +715,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
                        csr->edac_mode = mode;
                        csr->mtype = mtype;
 
-                       (*csrow)++;
+                       csrow++;
                }
 
                pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
@@ -736,7 +748,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
    we're disabling error injection on all write calls to the sysfs nodes that
    controls the error code injection.
  */
-static int disable_inject(struct mem_ctl_info *mci)
+static int disable_inject(const struct mem_ctl_info *mci)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
 
@@ -921,7 +933,7 @@ DECLARE_ADDR_MATCH(bank, 32);
 DECLARE_ADDR_MATCH(page, 0x10000);
 DECLARE_ADDR_MATCH(col, 0x4000);
 
-static int write_and_test(struct pci_dev *dev, int where, u32 val)
+static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
 {
        u32 read;
        int count;
@@ -1120,35 +1132,34 @@ DECLARE_COUNTER(2);
  * Sysfs struct
  */
 
-
-static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
        ATTR_ADDR_MATCH(channel),
        ATTR_ADDR_MATCH(dimm),
        ATTR_ADDR_MATCH(rank),
        ATTR_ADDR_MATCH(bank),
        ATTR_ADDR_MATCH(page),
        ATTR_ADDR_MATCH(col),
-       { .attr = { .name = NULL } }
+       { } /* End of list */
 };
 
-static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
        .name  = "inject_addrmatch",
        .mcidev_attr = i7core_addrmatch_attrs,
 };
 
-static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
        ATTR_COUNTER(0),
        ATTR_COUNTER(1),
        ATTR_COUNTER(2),
        { .attr = { .name = NULL } }
 };
 
-static struct mcidev_sysfs_group i7core_udimm_counters = {
+static const struct mcidev_sysfs_group i7core_udimm_counters = {
        .name  = "all_channel_counts",
        .mcidev_attr = i7core_udimm_counters_attrs,
 };
 
-static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
        {
                .attr = {
                        .name = "inject_section",
@@ -1180,8 +1191,44 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
                .show  = i7core_inject_enable_show,
                .store = i7core_inject_enable_store,
        },
-       { .attr = { .name = NULL } },   /* Reserved for udimm counters */
-       { .attr = { .name = NULL } }
+       { }     /* End of list */
+};
+
+static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
+       {
+               .attr = {
+                       .name = "inject_section",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show  = i7core_inject_section_show,
+               .store = i7core_inject_section_store,
+       }, {
+               .attr = {
+                       .name = "inject_type",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show  = i7core_inject_type_show,
+               .store = i7core_inject_type_store,
+       }, {
+               .attr = {
+                       .name = "inject_eccmask",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show  = i7core_inject_eccmask_show,
+               .store = i7core_inject_eccmask_store,
+       }, {
+               .grp = &i7core_inject_addrmatch,
+       }, {
+               .attr = {
+                       .name = "inject_enable",
+                       .mode = (S_IRUGO | S_IWUSR)
+               },
+               .show  = i7core_inject_enable_show,
+               .store = i7core_inject_enable_store,
+       }, {
+               .grp = &i7core_udimm_counters,
+       },
+       { }     /* End of list */
 };
 
 /****************************************************************************
@@ -1189,7 +1236,7 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
  ****************************************************************************/
 
 /*
- *     i7core_put_devices      'put' all the devices that we have
+ *     i7core_put_all_devices  'put' all the devices that we have
  *                             reserved via 'get'
  */
 static void i7core_put_devices(struct i7core_dev *i7core_dev)
@@ -1206,23 +1253,23 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev)
                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
                pci_dev_put(pdev);
        }
-       kfree(i7core_dev->pdev);
-       list_del(&i7core_dev->list);
-       kfree(i7core_dev);
 }
 
 static void i7core_put_all_devices(void)
 {
        struct i7core_dev *i7core_dev, *tmp;
 
-       list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list)
+       list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
                i7core_put_devices(i7core_dev);
+               free_i7core_dev(i7core_dev);
+       }
 }
 
-static void __init i7core_xeon_pci_fixup(struct pci_id_table *table)
+static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table)
 {
        struct pci_dev *pdev = NULL;
        int i;
+
        /*
         * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
         * aren't announced by acpi. So, we need to use a legacy scan probing
@@ -1257,16 +1304,18 @@ static unsigned i7core_pci_lastbus(void)
 }
 
 /*
- *     i7core_get_devices      Find and perform 'get' operation on the MCH's
+ *     i7core_get_all_devices  Find and perform 'get' operation on the MCH's
  *                     device/functions we want to reference for this driver
  *
  *                     Need to 'get' device 16 func 1 and func 2
  */
-int i7core_get_onedevice(struct pci_dev **prev, int devno,
-                        struct pci_id_descr *dev_descr, unsigned n_devs,
-                        unsigned last_bus)
+static int i7core_get_onedevice(struct pci_dev **prev,
+                               const struct pci_id_table *table,
+                               const unsigned devno,
+                               const unsigned last_bus)
 {
        struct i7core_dev *i7core_dev;
+       const struct pci_id_descr *dev_descr = &table->descr[devno];
 
        struct pci_dev *pdev = NULL;
        u8 bus = 0;
@@ -1275,20 +1324,6 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                              dev_descr->dev_id, *prev);
 
-       /*
-        * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
-        * is at addr 8086:2c40, instead of 8086:2c41. So, we need
-        * to probe for the alternate address in case of failure
-        */
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
-               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                     PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
-
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
-               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                     PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
-                                     *prev);
-
        if (!pdev) {
                if (*prev) {
                        *prev = pdev;
@@ -1315,18 +1350,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
 
        i7core_dev = get_i7core_dev(socket);
        if (!i7core_dev) {
-               i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
-               if (!i7core_dev)
-                       return -ENOMEM;
-               i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs,
-                                          GFP_KERNEL);
-               if (!i7core_dev->pdev) {
-                       kfree(i7core_dev);
+               i7core_dev = alloc_i7core_dev(socket, table);
+               if (!i7core_dev) {
+                       pci_dev_put(pdev);
                        return -ENOMEM;
                }
-               i7core_dev->socket = socket;
-               i7core_dev->n_devs = n_devs;
-               list_add_tail(&i7core_dev->list, &i7core_edac_list);
        }
 
        if (i7core_dev->pdev[devno]) {
@@ -1368,27 +1396,31 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
                dev_descr->func,
                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
+       /*
+        * As stated on drivers/pci/search.c, the reference count for
+        * @from is always decremented if it is not %NULL. So, as we need
+        * to get all devices up to null, we need to do a get for the device
+        */
+       pci_dev_get(pdev);
+
        *prev = pdev;
 
        return 0;
 }
 
-static int i7core_get_devices(struct pci_id_table *table)
+static int i7core_get_all_devices(void)
 {
        int i, rc, last_bus;
        struct pci_dev *pdev = NULL;
-       struct pci_id_descr *dev_descr;
+       const struct pci_id_table *table = pci_dev_table;
 
        last_bus = i7core_pci_lastbus();
 
        while (table && table->descr) {
-               dev_descr = table->descr;
                for (i = 0; i < table->n_devs; i++) {
                        pdev = NULL;
                        do {
-                               rc = i7core_get_onedevice(&pdev, i,
-                                                         &dev_descr[i],
-                                                         table->n_devs,
+                               rc = i7core_get_onedevice(&pdev, table, i,
                                                          last_bus);
                                if (rc < 0) {
                                        if (i == 0) {
@@ -1404,7 +1436,6 @@ static int i7core_get_devices(struct pci_id_table *table)
        }
 
        return 0;
-       return 0;
 }
 
 static int mci_bind_devs(struct mem_ctl_info *mci,
@@ -1414,10 +1445,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
        struct pci_dev *pdev;
        int i, func, slot;
 
-       /* Associates i7core_dev and mci for future usage */
-       pvt->i7core_dev = i7core_dev;
-       i7core_dev->mci = mci;
-
        pvt->is_registered = 0;
        for (i = 0; i < i7core_dev->n_devs; i++) {
                pdev = i7core_dev->pdev[i];
@@ -1448,15 +1475,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
                        pvt->is_registered = 1;
        }
 
-       /*
-        * Add extra nodes to count errors on udimm
-        * For registered memory, this is not needed, since the counters
-        * are already displayed at the standard locations
-        */
-       if (!pvt->is_registered)
-               i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp =
-                       &i7core_udimm_counters;
-
        return 0;
 
 error:
@@ -1470,7 +1488,9 @@ error:
                        Error check routines
  ****************************************************************************/
 static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
-                                        int chan, int dimm, int add)
+                                     const int chan,
+                                     const int dimm,
+                                     const int add)
 {
        char *msg;
        struct i7core_pvt *pvt = mci->pvt_info;
@@ -1487,7 +1507,10 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
 }
 
 static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
-                       int chan, int new0, int new1, int new2)
+                                        const int chan,
+                                        const int new0,
+                                        const int new1,
+                                        const int new2)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
        int add0 = 0, add1 = 0, add2 = 0;
@@ -1641,7 +1664,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
  * fields
  */
 static void i7core_mce_output_error(struct mem_ctl_info *mci,
-                                   struct mce *m)
+                                   const struct mce *m)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
        char *type, *optype, *err, *msg;
@@ -1845,28 +1868,85 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
        return 1;
 }
 
-static int i7core_register_mci(struct i7core_dev *i7core_dev,
-                              int num_channels, int num_csrows)
+static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
+{
+       pvt->i7core_pci = edac_pci_create_generic_ctl(
+                                               &pvt->i7core_dev->pdev[0]->dev,
+                                               EDAC_MOD_STR);
+       if (unlikely(!pvt->i7core_pci))
+               pr_warn("Unable to setup PCI error report via EDAC\n");
+}
+
+static void i7core_pci_ctl_release(struct i7core_pvt *pvt)
+{
+       if (likely(pvt->i7core_pci))
+               edac_pci_release_generic_ctl(pvt->i7core_pci);
+       else
+               i7core_printk(KERN_ERR,
+                               "Couldn't find mem_ctl_info for socket %d\n",
+                               pvt->i7core_dev->socket);
+       pvt->i7core_pci = NULL;
+}
+
+static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
+{
+       struct mem_ctl_info *mci = i7core_dev->mci;
+       struct i7core_pvt *pvt;
+
+       if (unlikely(!mci || !mci->pvt_info)) {
+               debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
+                       __func__, &i7core_dev->pdev[0]->dev);
+
+               i7core_printk(KERN_ERR, "Couldn't find mci handler\n");
+               return;
+       }
+
+       pvt = mci->pvt_info;
+
+       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+               __func__, mci, &i7core_dev->pdev[0]->dev);
+
+       /* Disable MCE NMI handler */
+       edac_mce_unregister(&pvt->edac_mce);
+
+       /* Disable EDAC polling */
+       i7core_pci_ctl_release(pvt);
+
+       /* Remove MC sysfs nodes */
+       edac_mc_del_mc(mci->dev);
+
+       debugf1("%s: free mci struct\n", mci->ctl_name);
+       kfree(mci->ctl_name);
+       edac_mc_free(mci);
+       i7core_dev->mci = NULL;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev)
 {
        struct mem_ctl_info *mci;
        struct i7core_pvt *pvt;
-       int csrow = 0;
-       int rc;
+       int rc, channels, csrows;
+
+       /* Check the number of active and not disabled channels */
+       rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows);
+       if (unlikely(rc < 0))
+               return rc;
 
        /* allocate a new MC control structure */
-       mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels,
-                           i7core_dev->socket);
+       mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket);
        if (unlikely(!mci))
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
-
-       /* record ptr to the generic device */
-       mci->dev = &i7core_dev->pdev[0]->dev;
+       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+               __func__, mci, &i7core_dev->pdev[0]->dev);
 
        pvt = mci->pvt_info;
        memset(pvt, 0, sizeof(*pvt));
 
+       /* Associates i7core_dev and mci for future usage */
+       pvt->i7core_dev = i7core_dev;
+       i7core_dev->mci = mci;
+
        /*
         * FIXME: how to handle RDDR3 at MCI level? It is possible to have
         * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
@@ -1881,17 +1961,23 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
                                  i7core_dev->socket);
        mci->dev_name = pci_name(i7core_dev->pdev[0]);
        mci->ctl_page_to_phys = NULL;
-       mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs;
-       /* Set the function pointer to an actual operation function */
-       mci->edac_check = i7core_check_error;
 
        /* Store pci devices at mci for faster access */
        rc = mci_bind_devs(mci, i7core_dev);
        if (unlikely(rc < 0))
-               goto fail;
+               goto fail0;
+
+       if (pvt->is_registered)
+               mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
+       else
+               mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
 
        /* Get dimm basic config */
-       get_dimm_config(mci, &csrow);
+       get_dimm_config(mci);
+       /* record ptr to the generic device */
+       mci->dev = &i7core_dev->pdev[0]->dev;
+       /* Set the function pointer to an actual operation function */
+       mci->edac_check = i7core_check_error;
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (unlikely(edac_mc_add_mc(mci))) {
@@ -1902,19 +1988,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
                 */
 
                rc = -EINVAL;
-               goto fail;
-       }
-
-       /* allocating generic PCI control info */
-       i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev,
-                                                EDAC_MOD_STR);
-       if (unlikely(!i7core_pci)) {
-               printk(KERN_WARNING
-                       "%s(): Unable to create PCI control\n",
-                       __func__);
-               printk(KERN_WARNING
-                       "%s(): PCI error report via EDAC not setup\n",
-                       __func__);
+               goto fail0;
        }
 
        /* Default error mask is any memory */
@@ -1925,19 +1999,28 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
        pvt->inject.page = -1;
        pvt->inject.col = -1;
 
+       /* allocating generic PCI control info */
+       i7core_pci_ctl_create(pvt);
+
        /* Registers on edac_mce in order to receive memory errors */
        pvt->edac_mce.priv = mci;
        pvt->edac_mce.check_error = i7core_mce_check_error;
-
        rc = edac_mce_register(&pvt->edac_mce);
        if (unlikely(rc < 0)) {
                debugf0("MC: " __FILE__
                        ": %s(): failed edac_mce_register()\n", __func__);
+               goto fail1;
        }
 
-fail:
-       if (rc < 0)
-               edac_mc_free(mci);
+       return 0;
+
+fail1:
+       i7core_pci_ctl_release(pvt);
+       edac_mc_del_mc(mci->dev);
+fail0:
+       kfree(mci->ctl_name);
+       edac_mc_free(mci);
+       i7core_dev->mci = NULL;
        return rc;
 }
 
@@ -1949,8 +2032,6 @@ fail:
  *             < 0 for error code
  */
 
-static int probed = 0;
-
 static int __devinit i7core_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *id)
 {
@@ -1965,25 +2046,16 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
         */
        if (unlikely(probed >= 1)) {
                mutex_unlock(&i7core_edac_lock);
-               return -EINVAL;
+               return -ENODEV;
        }
        probed++;
 
-       rc = i7core_get_devices(pci_dev_table);
+       rc = i7core_get_all_devices();
        if (unlikely(rc < 0))
                goto fail0;
 
        list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
-               int channels;
-               int csrows;
-
-               /* Check the number of active and not disabled channels */
-               rc = i7core_get_active_channels(i7core_dev->socket,
-                                               &channels, &csrows);
-               if (unlikely(rc < 0))
-                       goto fail1;
-
-               rc = i7core_register_mci(i7core_dev, channels, csrows);
+               rc = i7core_register_mci(i7core_dev);
                if (unlikely(rc < 0))
                        goto fail1;
        }
@@ -1994,6 +2066,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        return 0;
 
 fail1:
+       list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+               i7core_unregister_mci(i7core_dev);
+
        i7core_put_all_devices();
 fail0:
        mutex_unlock(&i7core_edac_lock);
@@ -2006,14 +2081,10 @@ fail0:
  */
 static void __devexit i7core_remove(struct pci_dev *pdev)
 {
-       struct mem_ctl_info *mci;
-       struct i7core_dev *i7core_dev, *tmp;
+       struct i7core_dev *i7core_dev;
 
        debugf0(__FILE__ ": %s()\n", __func__);
 
-       if (i7core_pci)
-               edac_pci_release_generic_ctl(i7core_pci);
-
        /*
         * we have a trouble here: pdev value for removal will be wrong, since
         * it will point to the X58 register used to detect that the machine
@@ -2023,22 +2094,18 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
         */
 
        mutex_lock(&i7core_edac_lock);
-       list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
-               mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
-               if (mci) {
-                       struct i7core_pvt *pvt = mci->pvt_info;
-
-                       i7core_dev = pvt->i7core_dev;
-                       edac_mce_unregister(&pvt->edac_mce);
-                       kfree(mci->ctl_name);
-                       edac_mc_free(mci);
-                       i7core_put_devices(i7core_dev);
-               } else {
-                       i7core_printk(KERN_ERR,
-                                     "Couldn't find mci for socket %d\n",
-                                     i7core_dev->socket);
-               }
+
+       if (unlikely(!probed)) {
+               mutex_unlock(&i7core_edac_lock);
+               return;
        }
+
+       list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+               i7core_unregister_mci(i7core_dev);
+
+       /* Release PCI resources */
+       i7core_put_all_devices();
+
        probed--;
 
        mutex_unlock(&i7core_edac_lock);
@@ -2070,7 +2137,8 @@ static int __init i7core_init(void)
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
 
-       i7core_xeon_pci_fixup(pci_dev_table);
+       if (use_pci_fixup)
+               i7core_xeon_pci_fixup(pci_dev_table);
 
        pci_rc = pci_register_driver(&i7core_driver);
 
index fcf3ea28340b2fefae057f40eef0f8de23f1fdd9..40a222e19b2d08c7d0bbdef96b0170cd483e444d 100644 (file)
@@ -3,9 +3,6 @@ menu "IEEE 1394 (FireWire) support"
        # firewire-core does not depend on PCI but is
        # not useful without PCI controller driver
 
-comment "You can enable one or both FireWire driver stacks."
-comment "The newer stack is recommended."
-
 config FIREWIRE
        tristate "FireWire driver stack"
        select CRC_ITU_T
@@ -64,8 +61,6 @@ config FIREWIRE_NET
          To compile this driver as a module, say M here:  The module will be
          called firewire-net.
 
-source "drivers/ieee1394/Kconfig"
-
 config FIREWIRE_NOSY
        tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
        depends on PCI
index 3c6a7fb20aa79f2b18b38709ec0651654227c427..e3870d5c43ddeac5d89b35702b181bbf151ed891 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
 obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
 obj-$(CONFIG_FIREWIRE_NET)  += firewire-net.o
 obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
+obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/firewire/init_ohci1394_dma.c b/drivers/firewire/init_ohci1394_dma.c
new file mode 100644 (file)
index 0000000..a9a347a
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers
+ *
+ * Copyright (C) 2006-2007      Bernhard Kaindl <bk@suse.de>
+ *
+ * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c
+ * this file has functions to:
+ * - scan the PCI very early on boot for all OHCI 1394-compliant controllers
+ * - reset and initialize them and make them join the IEEE1394 bus and
+ * - enable physical DMA on them to allow remote debugging
+ *
+ * All code and data is marked as __init and __initdata, respective as
+ * during boot, all OHCI1394 controllers may be claimed by the firewire
+ * stack and at this point, this code should not touch them anymore.
+ *
+ * To use physical DMA after the initialization of the firewire stack,
+ * be sure that the stack enables it and (re-)attach after the bus reset
+ * which may be caused by the firewire stack initialization.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>         /* for PCI defines */
+#include <linux/string.h>
+
+#include <asm/pci-direct.h>    /* for direct PCI config space access */
+#include <asm/fixmap.h>
+
+#include <linux/init_ohci1394_dma.h>
+#include "ohci.h"
+
+int __initdata init_ohci1394_dma_early;
+
+struct ohci {
+       void __iomem *registers;
+};
+
+static inline void reg_write(const struct ohci *ohci, int offset, u32 data)
+{
+       writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct ohci *ohci, int offset)
+{
+       return readl(ohci->registers + offset);
+}
+
+#define OHCI_LOOP_COUNT                100     /* Number of loops for reg read waits */
+
+/* Reads a PHY register of an OHCI-1394 controller */
+static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr)
+{
+       int i;
+       u32 r;
+
+       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
+
+       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+               if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
+                       break;
+               mdelay(1);
+       }
+       r = reg_read(ohci, OHCI1394_PhyControl);
+
+       return (r & 0x00ff0000) >> 16;
+}
+
+/* Writes to a PHY register of an OHCI-1394 controller */
+static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data)
+{
+       int i;
+
+       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
+
+       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+               if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000))
+                       break;
+               mdelay(1);
+       }
+}
+
+/* Resets an OHCI-1394 controller (for sane state before initialization) */
+static inline void __init init_ohci1394_soft_reset(struct ohci *ohci)
+{
+       int i;
+
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+               if (!(reg_read(ohci, OHCI1394_HCControlSet)
+                                  & OHCI1394_HCControl_softReset))
+                       break;
+               mdelay(1);
+       }
+}
+
+#define OHCI1394_MAX_AT_REQ_RETRIES    0xf
+#define OHCI1394_MAX_AT_RESP_RETRIES   0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
+/* Basic OHCI-1394 register and port inititalization */
+static inline void __init init_ohci1394_initialize(struct ohci *ohci)
+{
+       u32 bus_options;
+       int num_ports, i;
+
+       /* Put some defaults to these undefined bus options */
+       bus_options = reg_read(ohci, OHCI1394_BusOptions);
+       bus_options |=  0x60000000; /* Enable CMC and ISC */
+       bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
+       bus_options &= ~0x18000000; /* Disable PMC and BMC */
+       reg_write(ohci, OHCI1394_BusOptions, bus_options);
+
+       /* Set the bus number */
+       reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
+
+       /* Enable posted writes */
+       reg_write(ohci, OHCI1394_HCControlSet,
+                       OHCI1394_HCControl_postedWriteEnable);
+
+       /* Clear link control register */
+       reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
+
+       /* enable phys */
+       reg_write(ohci, OHCI1394_LinkControlSet,
+                       OHCI1394_LinkControl_rcvPhyPkt);
+
+       /* Don't accept phy packets into AR request context */
+       reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
+
+       /* Clear the Isochonouys interrupt masks */
+       reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
+       reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
+       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
+
+       /* Accept asyncronous transfer requests from all nodes for now */
+       reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+       /* Specify asyncronous transfer retries */
+       reg_write(ohci, OHCI1394_ATRetries,
+                 OHCI1394_MAX_AT_REQ_RETRIES |
+                 (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+                 (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
+
+       /* We don't want hardware swapping */
+       reg_write(ohci, OHCI1394_HCControlClear,
+                 OHCI1394_HCControl_noByteSwapData);
+
+       /* Enable link */
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
+
+       /* If anything is connected to a port, make sure it is enabled */
+       num_ports = get_phy_reg(ohci, 2) & 0xf;
+       for (i = 0; i < num_ports; i++) {
+               unsigned int status;
+
+               set_phy_reg(ohci, 7, i);
+               status = get_phy_reg(ohci, 8);
+
+               if (status & 0x20)
+                       set_phy_reg(ohci, 8, status & ~1);
+       }
+}
+
+/**
+ * init_ohci1394_wait_for_busresets - wait until bus resets are completed
+ *
+ * OHCI1394 initialization itself and any device going on- or offline
+ * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec
+ * specifies that physical DMA is disabled on each bus reset and it
+ * has to be enabled after each bus reset when needed. We resort
+ * to polling here because on early boot, we have no interrupts.
+ */
+static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci)
+{
+       int i, events;
+
+       for (i = 0; i < 9; i++) {
+               mdelay(200);
+               events = reg_read(ohci, OHCI1394_IntEventSet);
+               if (events & OHCI1394_busReset)
+                       reg_write(ohci, OHCI1394_IntEventClear,
+                                       OHCI1394_busReset);
+       }
+}
+
+/**
+ * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging
+ * This enables remote DMA access over IEEE1394 from every host for the low
+ * 4GB of address space. DMA accesses above 4GB are not available currently.
+ */
+static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci)
+{
+       reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+       reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+       reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
+}
+
+/**
+ * init_ohci1394_reset_and_init_dma - init controller and enable DMA
+ * This initializes the given controller and enables physical DMA engine in it.
+ */
+static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci)
+{
+       /* Start off with a soft reset, clears everything to a sane state. */
+       init_ohci1394_soft_reset(ohci);
+
+       /* Accessing some registers without LPS enabled may cause lock up */
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
+
+       /* Disable and clear interrupts */
+       reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+       reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+
+       mdelay(50); /* Wait 50msec to make sure we have full link enabled */
+
+       init_ohci1394_initialize(ohci);
+       /*
+        * The initialization causes at least one IEEE1394 bus reset. Enabling
+        * physical DMA only works *after* *all* bus resets have calmed down:
+        */
+       init_ohci1394_wait_for_busresets(ohci);
+
+       /* We had to wait and do this now if we want to debug early problems */
+       init_ohci1394_enable_physical_dma(ohci);
+}
+
+/**
+ * init_ohci1394_controller - Map the registers of the controller and init DMA
+ * This maps the registers of the specified controller and initializes it
+ */
+static inline void __init init_ohci1394_controller(int num, int slot, int func)
+{
+       unsigned long ohci_base;
+       struct ohci ohci;
+
+       printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
+                        " at %02x:%02x.%x\n", num, slot, func);
+
+       ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2))
+                                                  & PCI_BASE_ADDRESS_MEM_MASK;
+
+       set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
+
+       ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE);
+
+       init_ohci1394_reset_and_init_dma(&ohci);
+}
+
+/**
+ * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them
+ * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them
+ */
+void __init init_ohci1394_dma_on_all_controllers(void)
+{
+       int num, slot, func;
+       u32 class;
+
+       if (!early_pci_allowed())
+               return;
+
+       /* Poor man's PCI discovery, the only thing we can do at early boot */
+       for (num = 0; num < 32; num++) {
+               for (slot = 0; slot < 32; slot++) {
+                       for (func = 0; func < 8; func++) {
+                               class = read_pci_config(num, slot, func,
+                                                       PCI_CLASS_REVISION);
+                               if (class == 0xffffffff)
+                                       continue; /* No device at this func */
+
+                               if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
+                                       continue; /* Not an OHCI-1394 device */
+
+                               init_ohci1394_controller(num, slot, func);
+                               break; /* Assume one controller per device */
+                       }
+               }
+       }
+       printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n");
+}
+
+/**
+ * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization
+ */
+static int __init setup_ohci1394_dma(char *opt)
+{
+       if (!strcmp(opt, "early"))
+               init_ohci1394_dma_early = 1;
+       return 0;
+}
+
+/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */
+early_param("ohci1394_dma", setup_ohci1394_dma);
index a2b12aa1f2b93920b55b255efbf60ad037a4c0d0..501866662e055131bc3dad3f4a5fb0b104913060 100644 (file)
@@ -345,7 +345,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 
        do {
                level = __ffs(pending);
-               handle_nested_irq(level + chip->irq_base);
+               generic_handle_irq(level + chip->irq_base);
 
                pending &= ~(1 << level);
        } while (pending);
@@ -360,7 +360,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        struct pca953x_platform_data *pdata = client->dev.platform_data;
        int ret;
 
-       if (pdata->irq_base && (id->driver_data & PCA953X_INT)) {
+       if (pdata->irq_base != -1
+                       && (id->driver_data & PCA953X_INT)) {
                int lvl;
 
                ret = pca953x_read_reg(chip, PCA953X_INPUT,
@@ -383,7 +384,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                        set_irq_chip_data(irq, chip);
                        set_irq_chip_and_handler(irq, &pca953x_irq_chip,
                                                 handle_edge_irq);
-                       set_irq_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                        set_irq_flags(irq, IRQF_VALID);
 #else
@@ -394,6 +394,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                ret = request_threaded_irq(client->irq,
                                           NULL,
                                           pca953x_irq_handler,
+                                          IRQF_TRIGGER_RISING |
                                           IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                           dev_name(&client->dev), chip);
                if (ret) {
@@ -408,13 +409,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        return 0;
 
 out_failed:
-       chip->irq_base = 0;
+       chip->irq_base = -1;
        return ret;
 }
 
 static void pca953x_irq_teardown(struct pca953x_chip *chip)
 {
-       if (chip->irq_base)
+       if (chip->irq_base != -1)
                free_irq(chip->client->irq, chip);
 }
 #else /* CONFIG_GPIO_PCA953X_IRQ */
@@ -424,7 +425,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        struct i2c_client *client = chip->client;
        struct pca953x_platform_data *pdata = client->dev.platform_data;
 
-       if (pdata->irq_base && (id->driver_data & PCA953X_INT))
+       if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
                dev_warn(&client->dev, "interrupt support not compiled in\n");
 
        return 0;
index 709690995d0d729efd8994a342f06bc402fff0cd..846fbd5e31bfffd55e616a89f192cc62e84bb719 100644 (file)
@@ -171,13 +171,13 @@ static int __devinit xgpio_of_probe(struct device_node *np)
        /* Update GPIO state shadow register with default value */
        tree_info = of_get_property(np, "xlnx,dout-default", NULL);
        if (tree_info)
-               chip->gpio_state = *tree_info;
+               chip->gpio_state = be32_to_cpup(tree_info);
 
        /* Update GPIO direction shadow register with default value */
        chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
        tree_info = of_get_property(np, "xlnx,tri-default", NULL);
        if (tree_info)
-               chip->gpio_dir = *tree_info;
+               chip->gpio_dir = be32_to_cpup(tree_info);
 
        /* Check device node and parent device node for device width */
        chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
@@ -186,7 +186,7 @@ static int __devinit xgpio_of_probe(struct device_node *np)
                tree_info = of_get_property(np->parent,
                                            "xlnx,gpio-width", NULL);
        if (tree_info)
-               chip->mmchip.gc.ngpio = *tree_info;
+               chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
 
        spin_lock_init(&chip->gpio_lock);
 
index 30879df3daead6c3e208cfed0e8e7d191d31eaa9..cc9277885dd071b2da83edeae9250b6ea5985020 100644 (file)
@@ -1 +1 @@
-obj-y                  += drm/ vga/
+obj-y                  += drm/ vga/ stub/
index f3a23a329f4e29e7817755bf7f9f367cbdd74d0a..997c43d0490947cd927bb9e1be7a1182776a3d65 100644 (file)
@@ -5,7 +5,7 @@
 ccflags-y := -Iinclude/drm
 
 drm-y       := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
-               drm_context.o drm_dma.o drm_drawable.o \
+               drm_context.o drm_dma.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 \
index ba38e0147220e7b199b73b9d0d13804ff80254f3..252fdb98b73a62b77fd812bb69823a38037010a7 100644 (file)
@@ -193,7 +193,7 @@ int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
  * \return zero on success or a negative number on failure.
  *
  * Verifies the AGP device is present and has been acquired, allocates the
- * memory via alloc_agp() and creates a drm_agp_mem entry for it.
+ * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
  */
 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
 {
@@ -211,7 +211,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
 
        pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
        type = (u32) request->type;
-       if (!(memory = drm_alloc_agp(dev, pages, type))) {
+       if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) {
                kfree(entry);
                return -ENOMEM;
        }
@@ -423,38 +423,6 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
        return head;
 }
 
-/** Calls agp_allocate_memory() */
-DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data * bridge,
-                                    size_t pages, u32 type)
-{
-       return agp_allocate_memory(bridge, pages, type);
-}
-
-/** Calls agp_free_memory() */
-int drm_agp_free_memory(DRM_AGP_MEM * handle)
-{
-       if (!handle)
-               return 0;
-       agp_free_memory(handle);
-       return 1;
-}
-
-/** Calls agp_bind_memory() */
-int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
-{
-       if (!handle)
-               return -EINVAL;
-       return agp_bind_memory(handle, start);
-}
-
-/** Calls agp_unbind_memory() */
-int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
-{
-       if (!handle)
-               return -EINVAL;
-       return agp_unbind_memory(handle);
-}
-
 /**
  * Binds a collection of pages into AGP memory at the given offset, returning
  * the AGP memory structure containing them.
@@ -474,7 +442,7 @@ drm_agp_bind_pages(struct drm_device *dev,
 
        DRM_DEBUG("\n");
 
-       mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
+       mem = agp_allocate_memory(dev->agp->bridge, num_pages,
                                      type);
        if (mem == NULL) {
                DRM_ERROR("Failed to allocate memory for %ld pages\n",
@@ -487,7 +455,7 @@ drm_agp_bind_pages(struct drm_device *dev,
        mem->page_count = num_pages;
 
        mem->is_flushed = true;
-       ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
+       ret = agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
        if (ret != 0) {
                DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
                agp_free_memory(mem);
index 2607753a320bfb84b7bf8caafafe7856f4cfc0b8..6d440fb894cf2acba53c863d20d10b16ccfa14b5 100644 (file)
@@ -333,14 +333,6 @@ int drm_addctx(struct drm_device *dev, void *data,
                return -ENOMEM;
        }
 
-       if (ctx->handle != DRM_KERNEL_CONTEXT) {
-               if (dev->driver->context_ctor)
-                       if (!dev->driver->context_ctor(dev, ctx->handle)) {
-                               DRM_DEBUG("Running out of ctxs or memory.\n");
-                               return -ENOMEM;
-                       }
-       }
-
        ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
        if (!ctx_entry) {
                DRM_DEBUG("out of memory\n");
index 37e0b4fa482a810afc9eded6fda136a90bcc5cc0..6985cb1da72cbc232919ab2bb93a52f26304a345 100644 (file)
@@ -1854,7 +1854,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        }
 
        if (fb->funcs->dirty) {
-               ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips);
+               ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
+                                      clips, num_clips);
        } else {
                ret = -ENOSYS;
                goto out_err2;
index 677b275fa721affe2fec2508e780c1b1970f4f73..9d8c892d07c93b1d4e855adc839e28bea5959aab 100644 (file)
@@ -48,7 +48,6 @@ static struct drm_info_list drm_debugfs_list[] = {
        {"queues", drm_queues_info, 0},
        {"bufs", drm_bufs_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
-       {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
        {"vma", drm_vma_info, 0},
 #endif
diff --git a/drivers/gpu/drm/drm_drawable.c b/drivers/gpu/drm/drm_drawable.c
deleted file mode 100644 (file)
index c53c976..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * \file drm_drawable.c
- * IOCTLs for drawables
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- * \author Michel Dänzer <michel@tungstengraphics.com>
- */
-
-/*
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
- * 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, 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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 "drmP.h"
-
-/**
- * Allocate drawable ID and memory to store information about it.
- */
-int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-       unsigned long irqflags;
-       struct drm_draw *draw = data;
-       int new_id = 0;
-       int ret;
-
-again:
-       if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
-               DRM_ERROR("Out of memory expanding drawable idr\n");
-               return -ENOMEM;
-       }
-
-       spin_lock_irqsave(&dev->drw_lock, irqflags);
-       ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
-       if (ret == -EAGAIN) {
-               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-               goto again;
-       }
-
-       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
-       draw->handle = new_id;
-
-       DRM_DEBUG("%d\n", draw->handle);
-
-       return 0;
-}
-
-/**
- * Free drawable ID and memory to store information about it.
- */
-int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-       struct drm_draw *draw = data;
-       unsigned long irqflags;
-       struct drm_drawable_info *info;
-
-       spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-       info = drm_get_drawable_info(dev, draw->handle);
-       if (info == NULL) {
-               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-               return -EINVAL;
-       }
-       kfree(info->rects);
-       kfree(info);
-
-       idr_remove(&dev->drw_idr, draw->handle);
-
-       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-       DRM_DEBUG("%d\n", draw->handle);
-       return 0;
-}
-
-int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-       struct drm_update_draw *update = data;
-       unsigned long irqflags;
-       struct drm_clip_rect *rects;
-       struct drm_drawable_info *info;
-       int err;
-
-       info = idr_find(&dev->drw_idr, update->handle);
-       if (!info) {
-               info = kzalloc(sizeof(*info), GFP_KERNEL);
-               if (!info)
-                       return -ENOMEM;
-               if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
-                       DRM_ERROR("No such drawable %d\n", update->handle);
-                       kfree(info);
-                       return -EINVAL;
-               }
-       }
-
-       switch (update->type) {
-       case DRM_DRAWABLE_CLIPRECTS:
-               if (update->num == 0)
-                       rects = NULL;
-               else if (update->num != info->num_rects) {
-                       rects = kmalloc(update->num *
-                                       sizeof(struct drm_clip_rect),
-                                       GFP_KERNEL);
-               } else
-                       rects = info->rects;
-
-               if (update->num && !rects) {
-                       DRM_ERROR("Failed to allocate cliprect memory\n");
-                       err = -ENOMEM;
-                       goto error;
-               }
-
-               if (update->num && DRM_COPY_FROM_USER(rects,
-                                                    (struct drm_clip_rect __user *)
-                                                    (unsigned long)update->data,
-                                                    update->num *
-                                                    sizeof(*rects))) {
-                       DRM_ERROR("Failed to copy cliprects from userspace\n");
-                       err = -EFAULT;
-                       goto error;
-               }
-
-               spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-               if (rects != info->rects) {
-                       kfree(info->rects);
-               }
-
-               info->rects = rects;
-               info->num_rects = update->num;
-
-               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
-               DRM_DEBUG("Updated %d cliprects for drawable %d\n",
-                         info->num_rects, update->handle);
-               break;
-       default:
-               DRM_ERROR("Invalid update type %d\n", update->type);
-               return -EINVAL;
-       }
-
-       return 0;
-
-error:
-       if (rects != info->rects)
-               kfree(rects);
-
-       return err;
-}
-
-/**
- * Caller must hold the drawable spinlock!
- */
-struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
-{
-       return idr_find(&dev->drw_idr, id);
-}
-EXPORT_SYMBOL(drm_get_drawable_info);
-
-static int drm_drawable_free(int idr, void *p, void *data)
-{
-       struct drm_drawable_info *info = p;
-
-       if (info) {
-               kfree(info->rects);
-               kfree(info);
-       }
-
-       return 0;
-}
-
-void drm_drawable_free_all(struct drm_device *dev)
-{
-       idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
-       idr_remove_all(&dev->drw_idr);
-}
index ff6690f4fc87a2593c4e350bad8aaf030daee164..271835a71570aaf073c807bc3002f5cb3a0cdaaa 100644 (file)
@@ -91,8 +91,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
 
-       DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
        DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
@@ -127,7 +127,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 
        DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
 
-       DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
        DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
@@ -180,10 +180,6 @@ int drm_lastclose(struct drm_device * dev)
 
        mutex_lock(&dev->struct_mutex);
 
-       /* Free drawable information memory */
-       drm_drawable_free_all(dev);
-       del_timer(&dev->timer);
-
        /* Clear AGP information */
        if (drm_core_has_AGP(dev) && dev->agp &&
                        !drm_core_check_feature(dev, DRIVER_MODESET)) {
index 96e96310822513bfd9c984054a913eac7b5acc50..c1a26217a5305ee65a07b85fa77e4c15db77436b 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
@@ -1268,34 +1267,51 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 }
 
 #define HDMI_IDENTIFIER 0x000C03
+#define AUDIO_BLOCK    0x01
 #define VENDOR_BLOCK    0x03
+#define EDID_BASIC_AUDIO       (1 << 6)
+
 /**
- * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
- * @edid: monitor EDID information
- *
- * Parse the CEA extension according to CEA-861-B.
- * Return true if HDMI, false if not or unknown.
+ * Search EDID for CEA extension block.
  */
-bool drm_detect_hdmi_monitor(struct edid *edid)
+static u8 *drm_find_cea_extension(struct edid *edid)
 {
-       char *edid_ext = NULL;
-       int i, hdmi_id;
-       int start_offset, end_offset;
-       bool is_hdmi = false;
+       u8 *edid_ext = NULL;
+       int i;
 
        /* No EDID or EDID extensions */
        if (edid == NULL || edid->extensions == 0)
-               goto end;
+               return NULL;
 
        /* Find CEA extension */
        for (i = 0; i < edid->extensions; i++) {
-               edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
-               /* This block is CEA extension */
-               if (edid_ext[0] == 0x02)
+               edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+               if (edid_ext[0] == CEA_EXT)
                        break;
        }
 
        if (i == edid->extensions)
+               return NULL;
+
+       return edid_ext;
+}
+
+/**
+ * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
+ * @edid: monitor EDID information
+ *
+ * Parse the CEA extension according to CEA-861-B.
+ * Return true if HDMI, false if not or unknown.
+ */
+bool drm_detect_hdmi_monitor(struct edid *edid)
+{
+       u8 *edid_ext;
+       int i, hdmi_id;
+       int start_offset, end_offset;
+       bool is_hdmi = false;
+
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
                goto end;
 
        /* Data block offset in CEA extension block */
@@ -1325,6 +1341,53 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_hdmi_monitor);
 
+/**
+ * drm_detect_monitor_audio - check monitor audio capability
+ *
+ * Monitor should have CEA extension block.
+ * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
+ * audio' only. If there is any audio extension block and supported
+ * audio format, assume at least 'basic audio' support, even if 'basic
+ * audio' is not defined in EDID.
+ *
+ */
+bool drm_detect_monitor_audio(struct edid *edid)
+{
+       u8 *edid_ext;
+       int i, j;
+       bool has_audio = false;
+       int start_offset, end_offset;
+
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
+               goto end;
+
+       has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0);
+
+       if (has_audio) {
+               DRM_DEBUG_KMS("Monitor has basic audio support\n");
+               goto end;
+       }
+
+       /* Data block offset in CEA extension block */
+       start_offset = 4;
+       end_offset = edid_ext[2];
+
+       for (i = start_offset; i < end_offset;
+                       i += ((edid_ext[i] & 0x1f) + 1)) {
+               if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
+                       has_audio = true;
+                       for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
+                               DRM_DEBUG_KMS("CEA audio format %d\n",
+                                             (edid_ext[i + j] >> 3) & 0xf);
+                       goto end;
+               }
+       }
+end:
+       return has_audio;
+}
+EXPORT_SYMBOL(drm_detect_monitor_audio);
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
index 6a5e403f9aa160b54caad1bca22ba93dd27415e6..d2849e4ea4d00a45b6f9dfdfe3da1f0da7824533 100644 (file)
@@ -242,6 +242,30 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
        return 0;
 }
 
+static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
+{
+       uint16_t *r_base, *g_base, *b_base;
+       int i;
+
+       r_base = crtc->gamma_store;
+       g_base = r_base + crtc->gamma_size;
+       b_base = g_base + crtc->gamma_size;
+
+       for (i = 0; i < crtc->gamma_size; i++)
+               helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
+}
+
+static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
+{
+       uint16_t *r_base, *g_base, *b_base;
+
+       r_base = crtc->gamma_store;
+       g_base = r_base + crtc->gamma_size;
+       b_base = g_base + crtc->gamma_size;
+
+       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+}
+
 int drm_fb_helper_debug_enter(struct fb_info *info)
 {
        struct drm_fb_helper *helper = info->par;
@@ -260,11 +284,12 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
                                continue;
 
                        funcs = mode_set->crtc->helper_private;
+                       drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
                        funcs->mode_set_base_atomic(mode_set->crtc,
                                                    mode_set->fb,
                                                    mode_set->x,
-                                                   mode_set->y);
-
+                                                   mode_set->y,
+                                                   ENTER_ATOMIC_MODE_SET);
                }
        }
 
@@ -308,8 +333,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
                        continue;
                }
 
+               drm_fb_helper_restore_lut_atomic(mode_set->crtc);
                funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
-                                           crtc->y);
+                                           crtc->y, LEAVE_ATOMIC_MODE_SET);
        }
 
        return 0;
index 5663d2719063de9231ca6cc153b63b30422e17aa..ea1c4b019ebf96290c0768202d7277cda47ba0f9 100644 (file)
@@ -92,12 +92,6 @@ drm_gem_init(struct drm_device *dev)
 
        spin_lock_init(&dev->object_name_lock);
        idr_init(&dev->object_name_idr);
-       atomic_set(&dev->object_count, 0);
-       atomic_set(&dev->object_memory, 0);
-       atomic_set(&dev->pin_count, 0);
-       atomic_set(&dev->pin_memory, 0);
-       atomic_set(&dev->gtt_count, 0);
-       atomic_set(&dev->gtt_memory, 0);
 
        mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
        if (!mm) {
@@ -151,9 +145,6 @@ int drm_gem_object_init(struct drm_device *dev,
        atomic_set(&obj->handle_count, 0);
        obj->size = size;
 
-       atomic_inc(&dev->object_count);
-       atomic_add(obj->size, &dev->object_memory);
-
        return 0;
 }
 EXPORT_SYMBOL(drm_gem_object_init);
@@ -180,8 +171,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
        return obj;
 fput:
        /* Object_init mangles the global counters - readjust them. */
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
        fput(obj->filp);
 free:
        kfree(obj);
@@ -436,10 +425,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
-       struct drm_device *dev = obj->dev;
        fput(obj->filp);
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
index 974e970ce3f81ce014170b90ad1b8adc8a1dd5a9..3cdbaf379bb51324110d5d0ace0c9dc2dd24059e 100644 (file)
@@ -270,20 +270,6 @@ int drm_gem_name_info(struct seq_file *m, void *data)
        return 0;
 }
 
-int drm_gem_object_info(struct seq_file *m, void* data)
-{
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-
-       seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
-       seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
-       seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
-       seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
-       seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
-       seq_printf(m, "%d gtt total\n", dev->gtt_total);
-       return 0;
-}
-
 #if DRM_DEBUG_CODE
 
 int drm_vma_info(struct seq_file *m, void *data)
index 9bf93bc9a32c27798791684ab73512a046e92a9c..632ae243ede0b9f1df4b42f2e96b30479be4e05a 100644 (file)
@@ -37,6 +37,8 @@
 
 static int drm_notifier(void *priv);
 
+static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
+
 /**
  * Lock ioctl.
  *
@@ -124,9 +126,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
        }
 
-       if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
-               dev->driver->dma_ready(dev);
-
        if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
        {
                if (dev->driver->dma_quiescent(dev)) {
@@ -136,12 +135,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                }
        }
 
-       if (dev->driver->kernel_context_switch &&
-           dev->last_context != lock->context) {
-               dev->driver->kernel_context_switch(dev, dev->last_context,
-                                                  lock->context);
-       }
-
        return 0;
 }
 
@@ -169,15 +162,8 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
-       /* kernel_context_switch isn't used by any of the x86 drm
-        * modules but is required by the Sparc driver.
-        */
-       if (dev->driver->kernel_context_switch_unlock)
-               dev->driver->kernel_context_switch_unlock(dev);
-       else {
-               if (drm_lock_free(&master->lock, lock->context)) {
-                       /* FIXME: Should really bail out here. */
-               }
+       if (drm_lock_free(&master->lock, lock->context)) {
+               /* FIXME: Should really bail out here. */
        }
 
        unblock_all_signals();
@@ -193,6 +179,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
  *
  * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
  */
+static
 int drm_lock_take(struct drm_lock_data *lock_data,
                  unsigned int context)
 {
@@ -229,7 +216,6 @@ int drm_lock_take(struct drm_lock_data *lock_data,
        }
        return 0;
 }
-EXPORT_SYMBOL(drm_lock_take);
 
 /**
  * This takes a lock forcibly and hands it to context. Should ONLY be used
@@ -297,7 +283,6 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
        wake_up_interruptible(&lock_data->lock_queue);
        return 0;
 }
-EXPORT_SYMBOL(drm_lock_free);
 
 /**
  * If we get here, it means that the process has called DRM_IOCTL_LOCK
@@ -360,7 +345,6 @@ void drm_idlelock_take(struct drm_lock_data *lock_data)
        }
        spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_take);
 
 void drm_idlelock_release(struct drm_lock_data *lock_data)
 {
@@ -380,8 +364,6 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
        }
        spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_release);
-
 
 int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
 {
@@ -390,5 +372,3 @@ int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
                _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
                master->lock.file_priv == file_priv);
 }
-
-EXPORT_SYMBOL(drm_i_have_hw_lock);
index 7732268eced2564d37f229eefdd7c38ead97dcfd..c9b805000a11e827c1677c0d81ccb33c5be1442c 100644 (file)
@@ -99,29 +99,23 @@ static void *agp_remap(unsigned long offset, unsigned long size,
        return addr;
 }
 
-/** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(struct drm_device * dev, int pages, u32 type)
-{
-       return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
-}
-
 /** Wrapper around agp_free_memory() */
-int drm_free_agp(DRM_AGP_MEM * handle, int pages)
+void drm_free_agp(DRM_AGP_MEM * handle, int pages)
 {
-       return drm_agp_free_memory(handle) ? 0 : -EINVAL;
+       agp_free_memory(handle);
 }
 EXPORT_SYMBOL(drm_free_agp);
 
 /** Wrapper around agp_bind_memory() */
 int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
 {
-       return drm_agp_bind_memory(handle, start);
+       return agp_bind_memory(handle, start);
 }
 
 /** Wrapper around agp_unbind_memory() */
 int drm_unbind_agp(DRM_AGP_MEM * handle)
 {
-       return drm_agp_unbind_memory(handle);
+       return agp_unbind_memory(handle);
 }
 EXPORT_SYMBOL(drm_unbind_agp);
 
index a9ba6b69ad3526dacce63039457f0c48f961e3db..9e5b07efebb72172ef97894ec2fa42a7548bd896 100644 (file)
@@ -55,7 +55,6 @@ static struct drm_info_list drm_proc_list[] = {
        {"queues", drm_queues_info, 0},
        {"bufs", drm_bufs_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
-       {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
        {"vma", drm_vma_info, 0},
 #endif
@@ -151,7 +150,6 @@ fail:
 int drm_proc_init(struct drm_minor *minor, int minor_id,
                  struct proc_dir_entry *root)
 {
-       struct drm_device *dev = minor->dev;
        char name[64];
        int ret;
 
@@ -172,14 +170,6 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
                return ret;
        }
 
-       if (dev->driver->proc_init) {
-               ret = dev->driver->proc_init(minor);
-               if (ret) {
-                       DRM_ERROR("DRM: Driver failed to initialize "
-                                 "/proc/dri.\n");
-                       return ret;
-               }
-       }
        return 0;
 }
 
@@ -216,15 +206,11 @@ int drm_proc_remove_files(struct drm_info_list *files, int count,
  */
 int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
 {
-       struct drm_device *dev = minor->dev;
        char name[64];
 
        if (!root || !minor->proc_root)
                return 0;
 
-       if (dev->driver->proc_cleanup)
-               dev->driver->proc_cleanup(minor);
-
        drm_proc_remove_files(drm_proc_list, DRM_PROC_ENTRIES, minor);
 
        sprintf(name, "%d", minor->index);
index 9034c4c6100dd2352c78b8b6d207001b0ce53bb5..d15e09b0ae0bf8c322712d5e3101f7dc8d53eb6a 100644 (file)
@@ -184,8 +184,6 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
        drm_sg_cleanup(entry);
        return -ENOMEM;
 }
-EXPORT_SYMBOL(drm_sg_alloc);
-
 
 int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
index d1ad57450df1543af9cc502a281b23661075b331..cdc89ee042cc22b83ebe610ddd67d01cf86ea048 100644 (file)
@@ -240,14 +240,10 @@ int drm_fill_in_dev(struct drm_device *dev,
        INIT_LIST_HEAD(&dev->vblank_event_list);
 
        spin_lock_init(&dev->count_lock);
-       spin_lock_init(&dev->drw_lock);
        spin_lock_init(&dev->event_lock);
-       init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
 
-       idr_init(&dev->drw_idr);
-
        if (drm_ht_create(&dev->map_hash, 12)) {
                return -ENOMEM;
        }
index 5df450683aab8649511aaa96aaa759452b022fc0..2c3fcbdfd8ff64f8c5a53ff35884f59ce51bd621 100644 (file)
@@ -523,14 +523,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
-{
-       return map->offset;
-}
-
-EXPORT_SYMBOL(drm_core_get_map_ofs);
-
-resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
+static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 {
 #ifdef __alpha__
        return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -539,8 +532,6 @@ resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 #endif
 }
 
-EXPORT_SYMBOL(drm_core_get_reg_ofs);
-
 /**
  * mmap DMA memory.
  *
@@ -627,7 +618,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 #endif
        case _DRM_FRAME_BUFFER:
        case _DRM_REGISTERS:
-               offset = dev->driver->get_reg_ofs(dev);
+               offset = drm_core_get_reg_ofs(dev);
                vma->vm_flags |= VM_IO; /* not in core dump */
                vma->vm_page_prot = drm_io_prot(map->type, vma);
 #if !defined(__arm__)
index fe69914ce507b3df89ed8193fb32ca58c4a73c0c..88bcd331e7c53f5f6a68d8925f1a0947132ed1c8 100644 (file)
@@ -52,8 +52,6 @@ static struct drm_driver driver = {
        .device_is_agp = i810_driver_device_is_agp,
        .reclaim_buffers_locked = i810_driver_reclaim_buffers_locked,
        .dma_quiescent = i810_driver_dma_quiescent,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = i810_ioctls,
        .fops = {
                 .owner = THIS_MODULE,
index 5b6298b24e249960bcf6053cb4d29c4573a285d3..f655ab7977da2091a4b6975e6499324267d2da17 100644 (file)
@@ -57,8 +57,6 @@ static struct drm_driver driver = {
        .device_is_agp = i830_driver_device_is_agp,
        .reclaim_buffers_locked = i830_driver_reclaim_buffers_locked,
        .dma_quiescent = i830_driver_dma_quiescent,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
 #if USE_IRQS
        .irq_preinstall = i830_driver_irq_preinstall,
        .irq_postinstall = i830_driver_irq_postinstall,
index 5c8e53458edbfee1c37e54b7b982d49e747d563e..fdc833d5cc7b473eb2f69cb2e856aaf8811215ce 100644 (file)
@@ -26,15 +26,17 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          intel_dvo.o \
          intel_ringbuffer.o \
          intel_overlay.o \
+         intel_opregion.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
 
+i915-$(CONFIG_ACPI)    += intel_acpi.o
+
 obj-$(CONFIG_DRM_I915)  += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index 14d59804acd77b00637ee68c0662a1183cdbca87..af70337567ce35a0167ffb193d8b1ffae769fedd 100644 (file)
@@ -165,67 +165,44 @@ struct ch7017_priv {
 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)
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
 {
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-       u8 out_buf[2];
-       u8 in_buf[2];
-
        struct i2c_msg msgs[] = {
                {
                        .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
-                       .buf = out_buf,
+                       .buf = &addr,
                },
                {
                        .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
-                       .buf = in_buf,
+                       .buf = val,
                }
        };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
-               *val= in_buf[0];
-               return true;
-       };
-
-       return false;
+       return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
 }
 
-static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
 {
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-       uint8_t out_buf[2];
+       uint8_t buf[2] = { addr, val };
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
-               .buf = out_buf,
+               .buf = buf,
        };
-
-       out_buf[0] = addr;
-       out_buf[1] = val;
-
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
-               return true;
-
-       return false;
+       return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
 }
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
                        struct i2c_adapter *adapter)
 {
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        struct ch7017_priv *priv;
-       uint8_t val;
+       const char *str;
+       u8 val;
 
        priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
        if (priv == NULL)
@@ -237,16 +214,27 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
        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) {
+       switch (val) {
+       case CH7017_DEVICE_ID_VALUE:
+               str = "ch7017";
+               break;
+       case CH7018_DEVICE_ID_VALUE:
+               str = "ch7018";
+               break;
+       case CH7019_DEVICE_ID_VALUE:
+               str = "ch7019";
+               break;
+       default:
                DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
-                               "Slave %d.\n",
-                         val, i2cbus->adapter.name,dvo->slave_addr);
+                             "slave %d.\n",
+                             val, adapter->name,dvo->slave_addr);
                goto fail;
        }
 
+       DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+                     str, adapter->name, dvo->slave_addr);
        return true;
+
 fail:
        kfree(priv);
        return false;
@@ -368,7 +356,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
        }
 
        /* XXX: Should actually wait for update power status somehow */
-       udelay(20000);
+       msleep(20);
 }
 
 static void ch7017_dump_regs(struct intel_dvo_device *dvo)
index 6f1944b244416c03475e8883a94a4c358fe8d881..7eaa94e4ff061b5450c9d769f70f02fb6459db2a 100644 (file)
@@ -113,7 +113,6 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -135,14 +134,14 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -152,7 +151,6 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -164,12 +162,12 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index a2ec3f4872023fbe3510ce0bc54c673c5e4ec56b..a12ed9414cc7358e462dfa78766fe6f16948eacd 100644 (file)
@@ -167,7 +167,6 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[1];
        u8 in_buf[2];
 
@@ -193,7 +192,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 
        out_buf[0] = addr;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+       if (i2c_transfer(adapter, msgs, 3) == 3) {
                *data = (in_buf[1] << 8) | in_buf[0];
                return true;
        };
@@ -201,7 +200,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
        if (!priv->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from "
                                "%s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -211,7 +210,6 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[3];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -224,12 +222,12 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
        out_buf[1] = data & 0xff;
        out_buf[2] = data >> 8;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!priv->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 9b8e6765cf260fa8f91f2fa1a9f4432fce2b0287..e4b4091df942faf1196e4c32c057dff77e4a467e 100644 (file)
@@ -69,7 +69,6 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct sil164_priv *sil = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -91,14 +90,14 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!sil->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -107,7 +106,6 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct sil164_priv *sil= dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -119,12 +117,12 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!sil->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 56f66426207f0a1a293dcb073360985d328fd85e..8ab2855bb544ae88851e4d90ce107382165e5442 100644 (file)
@@ -94,7 +94,6 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -116,14 +115,14 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!tfp->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -132,7 +131,6 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -144,12 +142,12 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!tfp->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 048149748fdc9457f48ee5884f74d5cb849e43c0..1f4f3ceb63c715cdeb46a121df5dbebdd5e4fef1 100644 (file)
 
 #if defined(CONFIG_DEBUG_FS)
 
-#define ACTIVE_LIST    1
-#define FLUSHING_LIST  2
-#define INACTIVE_LIST  3
+enum {
+       ACTIVE_LIST,
+       FLUSHING_LIST,
+       INACTIVE_LIST,
+       PINNED_LIST,
+       DEFERRED_FREE_LIST,
+};
+
+static const char *yesno(int v)
+{
+       return v ? "yes" : "no";
+}
+
+static int i915_capabilities(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       const struct intel_device_info *info = INTEL_INFO(dev);
+
+       seq_printf(m, "gen: %d\n", info->gen);
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+       B(is_mobile);
+       B(is_i85x);
+       B(is_i915g);
+       B(is_i945gm);
+       B(is_g33);
+       B(need_gfx_hws);
+       B(is_g4x);
+       B(is_pineview);
+       B(is_broadwater);
+       B(is_crestline);
+       B(has_fbc);
+       B(has_rc6);
+       B(has_pipe_cxsr);
+       B(has_hotplug);
+       B(cursor_needs_physical);
+       B(has_overlay);
+       B(overlay_needs_physical);
+       B(supports_tv);
+       B(has_bsd_ring);
+       B(has_blt_ring);
+#undef B
+
+       return 0;
+}
 
 static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
 {
@@ -64,6 +106,29 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
     }
 }
 
+static void
+describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
+{
+       seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+                  &obj->base,
+                  get_pin_flag(obj),
+                  get_tiling_flag(obj),
+                  obj->base.size,
+                  obj->base.read_domains,
+                  obj->base.write_domain,
+                  obj->last_rendering_seqno,
+                  obj->dirty ? " dirty" : "",
+                  obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
+       if (obj->base.name)
+               seq_printf(m, " (name: %d)", obj->base.name);
+       if (obj->fence_reg != I915_FENCE_REG_NONE)
+               seq_printf(m, " (fence: %d)", obj->fence_reg);
+       if (obj->gtt_space != NULL)
+               seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+       if (obj->ring != NULL)
+               seq_printf(m, " (%s)", obj->ring->name);
+}
+
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -72,56 +137,80 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
-       spinlock_t *lock = NULL;
+       size_t total_obj_size, total_gtt_size;
+       int count, ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        switch (list) {
        case ACTIVE_LIST:
                seq_printf(m, "Active:\n");
-               lock = &dev_priv->mm.active_list_lock;
-               head = &dev_priv->render_ring.active_list;
+               head = &dev_priv->mm.active_list;
                break;
        case INACTIVE_LIST:
                seq_printf(m, "Inactive:\n");
                head = &dev_priv->mm.inactive_list;
                break;
+       case PINNED_LIST:
+               seq_printf(m, "Pinned:\n");
+               head = &dev_priv->mm.pinned_list;
+               break;
        case FLUSHING_LIST:
                seq_printf(m, "Flushing:\n");
                head = &dev_priv->mm.flushing_list;
                break;
+       case DEFERRED_FREE_LIST:
+               seq_printf(m, "Deferred free:\n");
+               head = &dev_priv->mm.deferred_free_list;
+               break;
        default:
-               DRM_INFO("Ooops, unexpected list\n");
-               return 0;
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
        }
 
-       if (lock)
-               spin_lock(lock);
-       list_for_each_entry(obj_priv, head, list)
-       {
-               seq_printf(m, "    %p: %s %8zd %08x %08x %d%s%s",
-                          &obj_priv->base,
-                          get_pin_flag(obj_priv),
-                          obj_priv->base.size,
-                          obj_priv->base.read_domains,
-                          obj_priv->base.write_domain,
-                          obj_priv->last_rendering_seqno,
-                          obj_priv->dirty ? " dirty" : "",
-                          obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : "");
-
-               if (obj_priv->base.name)
-                       seq_printf(m, " (name: %d)", obj_priv->base.name);
-               if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
-               if (obj_priv->gtt_space != NULL)
-                       seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
-
+       total_obj_size = total_gtt_size = count = 0;
+       list_for_each_entry(obj_priv, head, mm_list) {
+               seq_printf(m, "   ");
+               describe_obj(m, obj_priv);
                seq_printf(m, "\n");
+               total_obj_size += obj_priv->base.size;
+               total_gtt_size += obj_priv->gtt_space->size;
+               count++;
        }
+       mutex_unlock(&dev->struct_mutex);
 
-       if (lock)
-           spin_unlock(lock);
+       seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+                  count, total_obj_size, total_gtt_size);
        return 0;
 }
 
+static int i915_gem_object_info(struct seq_file *m, void* data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
+       seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
+       seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
+       seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+       seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
+       seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
+       seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -176,6 +265,11 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_request *gem_request;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        seq_printf(m, "Request:\n");
        list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
@@ -184,6 +278,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
                           gem_request->seqno,
                           (int) (jiffies - gem_request->emitted_jiffies));
        }
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -192,16 +288,24 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (dev_priv->render_ring.status_page.page_addr != NULL) {
                seq_printf(m, "Current sequence: %d\n",
-                          i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
        } else {
                seq_printf(m, "Current sequence: hws uninitialized\n");
        }
        seq_printf(m, "Waiter sequence:  %d\n",
                        dev_priv->mm.waiting_gem_seqno);
        seq_printf(m, "IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -211,6 +315,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (!HAS_PCH_SPLIT(dev)) {
                seq_printf(m, "Interrupt enable:    %08x\n",
@@ -247,7 +356,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                   atomic_read(&dev_priv->irq_received));
        if (dev_priv->render_ring.status_page.page_addr != NULL) {
                seq_printf(m, "Current sequence:    %d\n",
-                          i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
        } else {
                seq_printf(m, "Current sequence:    hws uninitialized\n");
        }
@@ -255,6 +364,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                   dev_priv->mm.waiting_gem_seqno);
        seq_printf(m, "IRQ sequence:        %d\n",
                   dev_priv->mm.irq_gem_seqno);
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -263,7 +374,11 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int i;
+       int i, ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
        seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
@@ -289,6 +404,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
                        seq_printf(m, "\n");
                }
        }
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -313,16 +429,19 @@ static int i915_hws_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
+static void i915_dump_object(struct seq_file *m,
+                            struct io_mapping *mapping,
+                            struct drm_i915_gem_object *obj_priv)
 {
-       int page, i;
-       uint32_t *mem;
+       int page, page_count, i;
 
+       page_count = obj_priv->base.size / PAGE_SIZE;
        for (page = 0; page < page_count; page++) {
-               mem = kmap_atomic(pages[page], KM_USER0);
+               u32 *mem = io_mapping_map_wc(mapping,
+                                            obj_priv->gtt_offset + page * PAGE_SIZE);
                for (i = 0; i < PAGE_SIZE; i += 4)
                        seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-               kunmap_atomic(mem, KM_USER0);
+               io_mapping_unmap(mem);
        }
 }
 
@@ -335,27 +454,20 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
        struct drm_i915_gem_object *obj_priv;
        int ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
-       list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
-                       list) {
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                obj = &obj_priv->base;
                if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
-                   ret = i915_gem_object_get_pages(obj, 0);
-                   if (ret) {
-                           DRM_ERROR("Failed to get pages: %d\n", ret);
-                           spin_unlock(&dev_priv->mm.active_list_lock);
-                           return ret;
-                   }
-
-                   seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
-                   i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
-
-                   i915_gem_object_put_pages(obj);
+                   seq_printf(m, "--- gtt_offset = 0x%08x\n",
+                              obj_priv->gtt_offset);
+                   i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
                }
        }
 
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -365,20 +477,24 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u8 *virt;
-       uint32_t *ptr, off;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (!dev_priv->render_ring.gem_object) {
                seq_printf(m, "No ringbuffer setup\n");
-               return 0;
-       }
-
-       virt = dev_priv->render_ring.virtual_start;
+       } else {
+               u8 *virt = dev_priv->render_ring.virtual_start;
+               uint32_t off;
 
-       for (off = 0; off < dev_priv->render_ring.size; off += 4) {
-               ptr = (uint32_t *)(virt + off);
-               seq_printf(m, "%08x :  %08x\n", off, *ptr);
+               for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+                       uint32_t *ptr = (uint32_t *)(virt + off);
+                       seq_printf(m, "%08x :  %08x\n", off, *ptr);
+               }
        }
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -396,7 +512,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        seq_printf(m, "RingHead :  %08x\n", head);
        seq_printf(m, "RingTail :  %08x\n", tail);
        seq_printf(m, "RingSize :  %08lx\n", dev_priv->render_ring.size);
-       seq_printf(m, "Acthd :     %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
+       seq_printf(m, "Acthd :     %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
 
        return 0;
 }
@@ -458,7 +574,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
        seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
        seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
        seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
                seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
        }
@@ -642,6 +758,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        } else {
                seq_printf(m, "FBC disabled: ");
                switch (dev_priv->no_fbc_reason) {
+               case FBC_NO_OUTPUT:
+                       seq_printf(m, "no outputs");
+                       break;
                case FBC_STOLEN_TOO_SMALL:
                        seq_printf(m, "not enough stolen memory");
                        break;
@@ -675,15 +794,17 @@ static int i915_sr_status(struct seq_file *m, void *unused)
        drm_i915_private_t *dev_priv = dev->dev_private;
        bool sr_enabled = false;
 
-       if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev))
+       if (IS_GEN5(dev))
+               sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
+       else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
                sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
        else if (IS_I915GM(dev))
                sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
        else if (IS_PINEVIEW(dev))
                sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
 
-       seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
-                  "disabled");
+       seq_printf(m, "self-refresh: %s\n",
+                  sr_enabled ? "enabled" : "disabled");
 
        return 0;
 }
@@ -694,10 +815,16 @@ static int i915_emon_status(struct seq_file *m, void *unused)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        unsigned long temp, chipset, gfx;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        temp = i915_mch_val(dev_priv);
        chipset = i915_chipset_val(dev_priv);
        gfx = i915_gfx_val(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
 
        seq_printf(m, "GMCH temp: %ld\n", temp);
        seq_printf(m, "Chipset power: %ld\n", chipset);
@@ -718,6 +845,68 @@ static int i915_gfxec(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_opregion(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (opregion->header)
+               seq_write(m, opregion->header, OPREGION_SIZE);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_fbdev *ifbdev;
+       struct intel_framebuffer *fb;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+       if (ret)
+               return ret;
+
+       ifbdev = dev_priv->fbdev;
+       fb = to_intel_framebuffer(ifbdev->helper.fb);
+
+       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+                  fb->base.width,
+                  fb->base.height,
+                  fb->base.depth,
+                  fb->base.bits_per_pixel);
+       describe_obj(m, to_intel_bo(fb->obj));
+       seq_printf(m, "\n");
+
+       list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
+               if (&fb->base == ifbdev->helper.fb)
+                       continue;
+
+               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+                          fb->base.width,
+                          fb->base.height,
+                          fb->base.depth,
+                          fb->base.bits_per_pixel);
+               describe_obj(m, to_intel_bo(fb->obj));
+               seq_printf(m, "\n");
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
                 struct file *filp)
@@ -741,6 +930,9 @@ i915_wedged_read(struct file *filp,
                       "wedged :  %d\n",
                       atomic_read(&dev_priv->mm.wedged));
 
+       if (len > sizeof (buf))
+               len = sizeof (buf);
+
        return simple_read_from_buffer(ubuf, max, ppos, buf, len);
 }
 
@@ -770,7 +962,7 @@ i915_wedged_write(struct file *filp,
 
        atomic_set(&dev_priv->mm.wedged, val);
        if (val) {
-               DRM_WAKEUP(&dev_priv->irq_queue);
+               wake_up_all(&dev_priv->irq_queue);
                queue_work(dev_priv->wq, &dev_priv->error_work);
        }
 
@@ -824,9 +1016,13 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
 }
 
 static struct drm_info_list i915_debugfs_list[] = {
+       {"i915_capabilities", i915_capabilities, 0, 0},
+       {"i915_gem_objects", i915_gem_object_info, 0},
        {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
        {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
        {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+       {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
+       {"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
        {"i915_gem_pageflip", i915_gem_pageflip_info, 0},
        {"i915_gem_request", i915_gem_request_info, 0},
        {"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -846,6 +1042,8 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_gfxec", i915_gfxec, 0},
        {"i915_fbc_status", i915_fbc_status, 0},
        {"i915_sr_status", i915_sr_status, 0},
+       {"i915_opregion", i915_opregion, 0},
+       {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
index 2dd2c93ebfa35dace7916b38c6df18c835161978..7a26f4dd21ae0a055036f78ce588ea4def08d73a 100644 (file)
@@ -40,8 +40,7 @@
 #include <linux/pnp.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
-
-extern int intel_max_stolen; /* from AGP driver */
+#include <acpi/video.h>
 
 /**
  * Sets up the hardware status page for devices that need a physical address
@@ -64,7 +63,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
 
        memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
                                             0xf0;
 
@@ -133,8 +132,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
 
        mutex_lock(&dev->struct_mutex);
        intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-       if (HAS_BSD(dev))
-               intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
        mutex_unlock(&dev->struct_mutex);
 
        /* Clear the HWS virtual address at teardown */
@@ -222,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev)
        DRM_DEBUG_DRIVER("hw status page @ %p\n",
                                ring->status_page.page_addr);
        if (ring->status_page.gfx_addr != 0)
-               ring->setup_status_page(dev, ring);
+               intel_ring_setup_status_page(dev, ring);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 
@@ -377,7 +376,7 @@ i915_emit_box(struct drm_device *dev,
                return -EINVAL;
        }
 
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                BEGIN_LP_RING(4);
                OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
                OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
@@ -481,7 +480,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 
                if (!IS_I830(dev) && !IS_845G(dev)) {
                        BEGIN_LP_RING(2);
-                       if (IS_I965G(dev)) {
+                       if (INTEL_INFO(dev)->gen >= 4) {
                                OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
                                OUT_RING(batch->start);
                        } else {
@@ -500,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
        }
 
 
-       if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+       if (IS_G4X(dev) || IS_GEN5(dev)) {
                BEGIN_LP_RING(2);
                OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
                OUT_RING(MI_NOOP);
@@ -765,6 +764,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_BSD:
                value = HAS_BSD(dev);
                break;
+       case I915_PARAM_HAS_BLT:
+               value = HAS_BLT(dev);
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@ -888,12 +890,12 @@ static int
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp_lo, temp_hi = 0;
        u64 mchbar_addr;
        int ret;
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
        pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
@@ -920,7 +922,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
                return ret;
        }
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
                                       upper_32_bits(dev_priv->mch_res.start));
 
@@ -934,7 +936,7 @@ static void
 intel_setup_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
        bool enabled;
 
@@ -971,7 +973,7 @@ static void
 intel_teardown_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
 
        if (dev_priv->mchbar_need_disable) {
@@ -990,174 +992,6 @@ intel_teardown_mchbar(struct drm_device *dev)
                release_resource(&dev_priv->mch_res);
 }
 
-/**
- * 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, uint32_t *aperture_size,
-                         uint32_t *preallocated_size,
-                         uint32_t *start)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u16 tmp = 0;
-       unsigned long overhead;
-       unsigned long stolen;
-
-       /* Get the fb aperture size and "stolen" memory amount. */
-       pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
-
-       *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) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
-               overhead = 4096;
-       else
-               overhead = (*aperture_size / 1024) + 4096;
-
-       if (IS_GEN6(dev)) {
-               /* SNB has memory control reg at 0x50.w */
-               pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
-
-               switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
-               case INTEL_855_GMCH_GMS_DISABLED:
-                       DRM_ERROR("video memory is disabled\n");
-                       return -1;
-               case SNB_GMCH_GMS_STOLEN_32M:
-                       stolen = 32 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_64M:
-                       stolen = 64 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_96M:
-                       stolen = 96 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_128M:
-                       stolen = 128 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_160M:
-                       stolen = 160 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_192M:
-                       stolen = 192 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_224M:
-                       stolen = 224 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_256M:
-                       stolen = 256 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_288M:
-                       stolen = 288 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_320M:
-                       stolen = 320 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_352M:
-                       stolen = 352 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_384M:
-                       stolen = 384 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_416M:
-                       stolen = 416 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_448M:
-                       stolen = 448 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_480M:
-                       stolen = 480 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_512M:
-                       stolen = 512 * 1024 * 1024;
-                       break;
-               default:
-                       DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-                                 tmp & SNB_GMCH_GMS_STOLEN_MASK);
-                       return -1;
-               }
-       } else {
-               switch (tmp & INTEL_GMCH_GMS_MASK) {
-               case INTEL_855_GMCH_GMS_DISABLED:
-                       DRM_ERROR("video memory is disabled\n");
-                       return -1;
-               case INTEL_855_GMCH_GMS_STOLEN_1M:
-                       stolen = 1 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_4M:
-                       stolen = 4 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_8M:
-                       stolen = 8 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_16M:
-                       stolen = 16 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_32M:
-                       stolen = 32 * 1024 * 1024;
-                       break;
-               case INTEL_915G_GMCH_GMS_STOLEN_48M:
-                       stolen = 48 * 1024 * 1024;
-                       break;
-               case INTEL_915G_GMCH_GMS_STOLEN_64M:
-                       stolen = 64 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_128M:
-                       stolen = 128 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_256M:
-                       stolen = 256 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_96M:
-                       stolen = 96 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_160M:
-                       stolen = 160 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_224M:
-                       stolen = 224 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_352M:
-                       stolen = 352 * 1024 * 1024;
-                       break;
-               default:
-                       DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-                                 tmp & INTEL_GMCH_GMS_MASK);
-                       return -1;
-               }
-       }
-
-       *preallocated_size = stolen - overhead;
-       *start = overhead;
-
-       return 0;
-}
-
 #define PTE_ADDRESS_MASK               0xfffff000
 #define PTE_ADDRESS_MASK_HIGH          0x000000f0 /* i915+ */
 #define PTE_MAPPING_TYPE_UNCACHED      (0 << 1)
@@ -1181,11 +1015,11 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
 {
        unsigned long *gtt;
        unsigned long entry, phys;
-       int gtt_bar = IS_I9XX(dev) ? 0 : 1;
+       int gtt_bar = IS_GEN2(dev) ? 1 : 0;
        int gtt_offset, gtt_size;
 
-       if (IS_I965G(dev)) {
-               if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
                        gtt_offset = 2*1024*1024;
                        gtt_size = 2*1024*1024;
                } else {
@@ -1210,10 +1044,8 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
        DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
 
        /* Mask out these reserved bits on this hardware. */
-       if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
-           IS_I945G(dev) || IS_I945GM(dev)) {
+       if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
                entry &= ~PTE_ADDRESS_MASK_HIGH;
-       }
 
        /* If it's not a mapping type we know, then bail. */
        if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
@@ -1252,7 +1084,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
        unsigned long ll_base = 0;
 
        /* Leave 1M for line length buffer & misc. */
-       compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
+       compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
        if (!compressed_fb) {
                dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                i915_warn_stolen(dev);
@@ -1273,7 +1105,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
        }
 
        if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
-               compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
+               compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
                                                    4096, 0);
                if (!compressed_llb) {
                        i915_warn_stolen(dev);
@@ -1343,10 +1175,8 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
                /* i915 resume handler doesn't set to D0 */
                pci_set_power_state(dev->pdev, PCI_D0);
                i915_resume(dev);
-               drm_kms_helper_poll_enable(dev);
        } else {
                printk(KERN_ERR "i915: switched off\n");
-               drm_kms_helper_poll_disable(dev);
                i915_suspend(dev, pmm);
        }
 }
@@ -1363,23 +1193,14 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 }
 
 static int i915_load_modeset_init(struct drm_device *dev,
-                                 unsigned long prealloc_start,
                                  unsigned long prealloc_size,
                                  unsigned long agp_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int fb_bar = IS_I9XX(dev) ? 2 : 0;
        int ret = 0;
 
-       dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
-               0xff000000;
-
-       /* Basic memrange allocator for stolen space (aka vram) */
-       drm_mm_init(&dev_priv->vram, 0, prealloc_size);
-       DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
-
-       /* We're off and running w/KMS */
-       dev_priv->mm.suspended = 0;
+       /* Basic memrange allocator for stolen space (aka mm.vram) */
+       drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
 
        /* Let GEM Manage from end of prealloc space to end of aperture.
         *
@@ -1414,7 +1235,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
         */
        dev_priv->allow_batchbuffer = 1;
 
-       ret = intel_init_bios(dev);
+       ret = intel_parse_bios(dev);
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
 
@@ -1423,6 +1244,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                goto cleanup_ringbuffer;
 
+       intel_register_dsm_handler();
+
        ret = vga_switcheroo_register_client(dev->pdev,
                                             i915_switcheroo_set_state,
                                             i915_switcheroo_can_switch);
@@ -1443,17 +1266,15 @@ static int i915_load_modeset_init(struct drm_device *dev,
        /* 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));
-
        ret = intel_fbdev_init(dev);
        if (ret)
                goto cleanup_irq;
 
        drm_kms_helper_poll_init(dev);
+
+       /* We're off and running w/KMS */
+       dev_priv->mm.suspended = 0;
+
        return 0;
 
 cleanup_irq:
@@ -1907,7 +1728,7 @@ static struct drm_i915_private *i915_mch_dev;
  *   - dev_priv->fmax
  *   - dev_priv->gpu_busy
  */
-DEFINE_SPINLOCK(mchdev_lock);
+static DEFINE_SPINLOCK(mchdev_lock);
 
 /**
  * i915_read_mch_val - return value for IPS use
@@ -2062,7 +1883,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        struct drm_i915_private *dev_priv;
        resource_size_t base, size;
        int ret = 0, mmio_bar;
-       uint32_t agp_size, prealloc_size, prealloc_start;
+       uint32_t agp_size, prealloc_size;
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
@@ -2079,7 +1900,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->info = (struct intel_device_info *) flags;
 
        /* Add register map (needed for suspend/resume) */
-       mmio_bar = IS_I9XX(dev) ? 0 : 1;
+       mmio_bar = IS_GEN2(dev) ? 1 : 0;
        base = pci_resource_start(dev->pdev, mmio_bar);
        size = pci_resource_len(dev->pdev, mmio_bar);
 
@@ -2121,17 +1942,32 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                         "performance may suffer.\n");
        }
 
-       ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
-       if (ret)
+       dev_priv->mm.gtt = intel_gtt_get();
+       if (!dev_priv->mm.gtt) {
+               DRM_ERROR("Failed to initialize GTT\n");
+               ret = -ENODEV;
                goto out_iomapfree;
-
-       if (prealloc_size > intel_max_stolen) {
-               DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
-                        prealloc_size >> 20, intel_max_stolen >> 20);
-               prealloc_size = intel_max_stolen;
        }
 
-       dev_priv->wq = create_singlethread_workqueue("i915");
+       prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+       agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+       /* The i915 workqueue is primarily used for batched retirement of
+        * requests (and thus managing bo) once the task has been completed
+        * by the GPU. i915_gem_retire_requests() is called directly when we
+        * need high-priority retirement, such as waiting for an explicit
+        * bo.
+        *
+        * It is also used for periodic low-priority events, such as
+        * idle-timers and hangcheck.
+        *
+        * All tasks on the workqueue are expected to acquire the dev mutex
+        * so there is no point in running more than one instance of the
+        * workqueue at any time: max_active = 1 and NON_REENTRANT.
+        */
+       dev_priv->wq = alloc_workqueue("i915",
+                                      WQ_UNBOUND | WQ_NON_REENTRANT,
+                                      1);
        if (dev_priv->wq == NULL) {
                DRM_ERROR("Failed to create our workqueue.\n");
                ret = -ENOMEM;
@@ -2159,13 +1995,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-       if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+       if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
 
        /* Try to make sure MCHBAR is enabled before poking at it */
        intel_setup_mchbar(dev);
+       intel_setup_gmbus(dev);
+       intel_opregion_setup(dev);
+
+       /* Make sure the bios did its job and set up vital registers */
+       intel_setup_bios(dev);
 
        i915_gem_load(dev);
 
@@ -2178,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        if (IS_PINEVIEW(dev))
                i915_pineview_get_mem_freq(dev);
-       else if (IS_IRONLAKE(dev))
+       else if (IS_GEN5(dev))
                i915_ironlake_get_mem_freq(dev);
 
        /* On the 945G/GM, the chipset reports the MSI capability on the
@@ -2212,8 +2053,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev, prealloc_start,
-                                            prealloc_size, agp_size);
+               ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
                if (ret < 0) {
                        DRM_ERROR("failed to init modeset\n");
                        goto out_workqueue_free;
@@ -2221,7 +2061,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        /* Must be done after probing outputs */
-       intel_opregion_init(dev, 0);
+       intel_opregion_init(dev);
+       acpi_video_register();
 
        setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
                    (unsigned long) dev);
@@ -2231,9 +2072,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->mchdev_lock = &mchdev_lock;
        spin_unlock(&mchdev_lock);
 
-       /* XXX Prevent module unload due to memory corruption bugs. */
-       __module_get(THIS_MODULE);
-
        return 0;
 
 out_workqueue_free:
@@ -2252,15 +2090,20 @@ free_priv:
 int i915_driver_unload(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-
-       i915_destroy_error_state(dev);
+       int ret;
 
        spin_lock(&mchdev_lock);
        i915_mch_dev = NULL;
        spin_unlock(&mchdev_lock);
 
-       destroy_workqueue(dev_priv->wq);
-       del_timer_sync(&dev_priv->hangcheck_timer);
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_gpu_idle(dev);
+       if (ret)
+               DRM_ERROR("failed to idle hardware: %d\n", ret);
+       mutex_unlock(&dev->struct_mutex);
+
+       /* Cancel the retire work handler, which should be idle now. */
+       cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
        io_mapping_free(dev_priv->mm.gtt_mapping);
        if (dev_priv->mm.gtt_mtrr >= 0) {
@@ -2269,7 +2112,10 @@ int i915_driver_unload(struct drm_device *dev)
                dev_priv->mm.gtt_mtrr = -1;
        }
 
+       acpi_video_unregister();
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               intel_fbdev_fini(dev);
                intel_modeset_cleanup(dev);
 
                /*
@@ -2281,20 +2127,25 @@ int i915_driver_unload(struct drm_device *dev)
                        dev_priv->child_dev = NULL;
                        dev_priv->child_dev_num = 0;
                }
-               drm_irq_uninstall(dev);
+
                vga_switcheroo_unregister_client(dev->pdev);
                vga_client_register(dev->pdev, NULL, NULL, NULL);
        }
 
+       /* Free error state after interrupts are fully disabled. */
+       del_timer_sync(&dev_priv->hangcheck_timer);
+       cancel_work_sync(&dev_priv->error_work);
+       i915_destroy_error_state(dev);
+
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
 
-       if (dev_priv->regs != NULL)
-               iounmap(dev_priv->regs);
-
-       intel_opregion_free(dev, 0);
+       intel_opregion_fini(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Flush any outstanding unpin_work. */
+               flush_workqueue(dev_priv->wq);
+
                i915_gem_free_all_phys_object(dev);
 
                mutex_lock(&dev->struct_mutex);
@@ -2302,34 +2153,41 @@ int i915_driver_unload(struct drm_device *dev)
                mutex_unlock(&dev->struct_mutex);
                if (I915_HAS_FBC(dev) && i915_powersave)
                        i915_cleanup_compression(dev);
-               drm_mm_takedown(&dev_priv->vram);
-               i915_gem_lastclose(dev);
+               drm_mm_takedown(&dev_priv->mm.vram);
 
                intel_cleanup_overlay(dev);
+
+               if (!I915_NEED_GFX_HWS(dev))
+                       i915_free_hws(dev);
        }
 
+       if (dev_priv->regs != NULL)
+               iounmap(dev_priv->regs);
+
+       intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
 
+       destroy_workqueue(dev_priv->wq);
+
        pci_dev_put(dev_priv->bridge_dev);
        kfree(dev->dev_private);
 
        return 0;
 }
 
-int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+int i915_driver_open(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv;
+       struct drm_i915_file_private *file_priv;
 
        DRM_DEBUG_DRIVER("\n");
-       i915_file_priv = (struct drm_i915_file_private *)
-           kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
-
-       if (!i915_file_priv)
+       file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+       if (!file_priv)
                return -ENOMEM;
 
-       file_priv->driver_priv = i915_file_priv;
+       file->driver_priv = file_priv;
 
-       INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
+       spin_lock_init(&file_priv->mm.lock);
+       INIT_LIST_HEAD(&file_priv->mm.request_list);
 
        return 0;
 }
@@ -2372,11 +2230,11 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
                i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
-void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
 
-       kfree(i915_file_priv);
+       kfree(file_priv);
 }
 
 struct drm_ioctl_desc i915_ioctls[] = {
index 895ab896e336c660c279622a6b79bfe138a24a5d..3467dd420760fa51084a2ba00d097b90d6c214a2 100644 (file)
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #include <linux/console.h>
 #include "drm_crtc_helper.h"
@@ -61,86 +62,110 @@ extern int intel_agp_enabled;
        .driver_data = (unsigned long) info }
 
 static const struct intel_device_info intel_i830_info = {
-       .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+       .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_845g_info = {
-       .gen = 2, .is_i8xx = 1,
+       .gen = 2,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-       .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+       .gen = 2, .is_i85x = 1, .is_mobile = 1,
        .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-       .gen = 2, .is_i8xx = 1,
+       .gen = 2,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i915g_info = {
-       .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
+       .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-       .gen = 3, .is_i9xx = 1,  .is_mobile = 1,
+       .gen = 3, .is_mobile = 1,
        .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
+       .supports_tv = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-       .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
+       .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-       .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
+       .gen = 3, .is_i945gm = 1, .is_mobile = 1,
        .has_hotplug = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
+       .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_i965g_info = {
-       .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 4, .is_broadwater = 1,
        .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-       .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
+       .gen = 4, .is_crestline = 1,
        .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .has_overlay = 1,
+       .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-       .gen = 3, .is_g33 = 1, .is_i9xx = 1,
+       .gen = 3, .is_g33 = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_g45_info = {
-       .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+       .gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-       .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
+       .gen = 4, .is_g4x = 1,
        .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .supports_tv = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
-       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
+       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
-       .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 5,
        .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-       .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 5, .is_mobile = 1,
        .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
-       .gen = 6, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 6,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-       .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1,
+       .gen = 6, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
@@ -237,7 +262,7 @@ static int i915_drm_freeze(struct drm_device *dev)
 
        i915_save_state(dev);
 
-       intel_opregion_free(dev, 1);
+       intel_opregion_fini(dev);
 
        /* Modeset on resume, not lid events */
        dev_priv->modeset_on_lid = 0;
@@ -258,6 +283,8 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
        if (state.event == PM_EVENT_PRETHAW)
                return 0;
 
+       drm_kms_helper_poll_disable(dev);
+
        error = i915_drm_freeze(dev);
        if (error)
                return error;
@@ -277,8 +304,7 @@ static int i915_drm_thaw(struct drm_device *dev)
        int error = 0;
 
        i915_restore_state(dev);
-
-       intel_opregion_init(dev, 1);
+       intel_opregion_setup(dev);
 
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -294,6 +320,8 @@ static int i915_drm_thaw(struct drm_device *dev)
                drm_helper_resume_force_mode(dev);
        }
 
+       intel_opregion_init(dev);
+
        dev_priv->modeset_on_lid = 0;
 
        return error;
@@ -301,12 +329,79 @@ static int i915_drm_thaw(struct drm_device *dev)
 
 int i915_resume(struct drm_device *dev)
 {
+       int ret;
+
        if (pci_enable_device(dev->pdev))
                return -EIO;
 
        pci_set_master(dev->pdev);
 
-       return i915_drm_thaw(dev);
+       ret = i915_drm_thaw(dev);
+       if (ret)
+               return ret;
+
+       drm_kms_helper_poll_enable(dev);
+       return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_I85X(dev))
+               return -ENODEV;
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       if (IS_I830(dev) || IS_845G(dev)) {
+               I915_WRITE(DEBUG_RESET_I830,
+                          DEBUG_RESET_DISPLAY |
+                          DEBUG_RESET_RENDER |
+                          DEBUG_RESET_FULL);
+               POSTING_READ(DEBUG_RESET_I830);
+               msleep(1);
+
+               I915_WRITE(DEBUG_RESET_I830, 0);
+               POSTING_READ(DEBUG_RESET_I830);
+       }
+
+       msleep(1);
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+       u8 gdrst;
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       return gdrst & 0x1;
+}
+
+static int i965_do_reset(struct drm_device *dev, u8 flags)
+{
+       u8 gdrst;
+
+       /*
+        * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+        * well as the reset bit (GR/bit 0).  Setting the GR bit
+        * triggers the reset; when done, the hardware will clear it.
+        */
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+
+       return wait_for(i965_reset_complete(dev), 500);
+}
+
+static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+       return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
 }
 
 /**
@@ -325,54 +420,39 @@ int i915_resume(struct drm_device *dev)
  *   - re-init interrupt state
  *   - re-init display
  */
-int i965_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev, u8 flags)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       unsigned long timeout;
-       u8 gdrst;
        /*
         * We really should only reset the display subsystem if we actually
         * need to
         */
        bool need_display = true;
+       int ret;
 
        mutex_lock(&dev->struct_mutex);
 
-       /*
-        * Clear request list
-        */
-       i915_gem_retire_requests(dev);
-
-       if (need_display)
-               i915_save_display(dev);
-
-       if (IS_I965G(dev) || IS_G4X(dev)) {
-               /*
-                * Set the domains we want to reset, then the reset bit (bit 0).
-                * Clear the reset bit after a while and wait for hardware status
-                * bit (bit 1) to be set
-                */
-               pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-               pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
-               udelay(50);
-               pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe);
-
-               /* ...we don't want to loop forever though, 500ms should be plenty */
-              timeout = jiffies + msecs_to_jiffies(500);
-               do {
-                       udelay(100);
-                       pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-               } while ((gdrst & 0x1) && time_after(timeout, jiffies));
-
-               if (gdrst & 0x1) {
-                       WARN(true, "i915: Failed to reset chip\n");
-                       mutex_unlock(&dev->struct_mutex);
-                       return -EIO;
-               }
-       } else {
-               DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+       i915_gem_reset(dev);
+
+       ret = -ENODEV;
+       if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+               DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
+       } else switch (INTEL_INFO(dev)->gen) {
+       case 5:
+               ret = ironlake_do_reset(dev, flags);
+               break;
+       case 4:
+               ret = i965_do_reset(dev, flags);
+               break;
+       case 2:
+               ret = i8xx_do_reset(dev, flags);
+               break;
+       }
+       dev_priv->last_gpu_reset = get_seconds();
+       if (ret) {
+               DRM_ERROR("Failed to reset chip.\n");
                mutex_unlock(&dev->struct_mutex);
-               return -ENODEV;
+               return ret;
        }
 
        /* Ok, now get things going again... */
@@ -400,13 +480,19 @@ int i965_reset(struct drm_device *dev, u8 flags)
                mutex_lock(&dev->struct_mutex);
        }
 
+       mutex_unlock(&dev->struct_mutex);
+
        /*
-        * Display needs restore too...
+        * Perform a full modeset as on later generations, e.g. Ironlake, we may
+        * need to retrain the display link and cannot just restore the register
+        * values.
         */
-       if (need_display)
-               i915_restore_display(dev);
+       if (need_display) {
+               mutex_lock(&dev->mode_config.mutex);
+               drm_helper_resume_force_mode(dev);
+               mutex_unlock(&dev->mode_config.mutex);
+       }
 
-       mutex_unlock(&dev->struct_mutex);
        return 0;
 }
 
@@ -524,8 +610,6 @@ static struct drm_driver driver = {
        .irq_uninstall = i915_driver_irq_uninstall,
        .irq_handler = i915_driver_irq_handler,
        .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,
 #if defined(CONFIG_DEBUG_FS)
index af4a263cf25782a6906f80a1d0783841000ac9b1..2c2c19b6285ecf331edbac9c53e0bdd44b2093ad 100644 (file)
@@ -34,6 +34,8 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/i2c.h>
+#include <drm/intel-gtt.h>
 
 /* General customization:
  */
@@ -73,11 +75,9 @@ enum plane {
 #define DRIVER_PATCHLEVEL      0
 
 #define WATCH_COHERENCY        0
-#define WATCH_BUF      0
 #define WATCH_EXEC     0
-#define WATCH_LRU      0
 #define WATCH_RELOC    0
-#define WATCH_INACTIVE 0
+#define WATCH_LISTS    0
 #define WATCH_PWRITE   0
 
 #define I915_GEM_PHYS_CURSOR_0 1
@@ -110,8 +110,9 @@ struct intel_opregion {
        struct opregion_acpi *acpi;
        struct opregion_swsci *swsci;
        struct opregion_asle *asle;
-       int enabled;
+       void *vbt;
 };
+#define OPREGION_SIZE            (8*1024)
 
 struct intel_overlay;
 struct intel_overlay_error_state;
@@ -125,13 +126,16 @@ struct drm_i915_master_private {
 struct drm_i915_fence_reg {
        struct drm_gem_object *obj;
        struct list_head lru_list;
+       bool gpu;
 };
 
 struct sdvo_device_mapping {
+       u8 initialized;
        u8 dvo_port;
        u8 slave_addr;
        u8 dvo_wiring;
-       u8 initialized;
+       u8 i2c_pin;
+       u8 i2c_speed;
        u8 ddc_pin;
 };
 
@@ -193,28 +197,29 @@ struct drm_i915_display_funcs {
 struct intel_device_info {
        u8 gen;
        u8 is_mobile : 1;
-       u8 is_i8xx : 1;
        u8 is_i85x : 1;
        u8 is_i915g : 1;
-       u8 is_i9xx : 1;
        u8 is_i945gm : 1;
-       u8 is_i965g : 1;
-       u8 is_i965gm : 1;
        u8 is_g33 : 1;
        u8 need_gfx_hws : 1;
        u8 is_g4x : 1;
        u8 is_pineview : 1;
        u8 is_broadwater : 1;
        u8 is_crestline : 1;
-       u8 is_ironlake : 1;
        u8 has_fbc : 1;
        u8 has_rc6 : 1;
        u8 has_pipe_cxsr : 1;
        u8 has_hotplug : 1;
        u8 cursor_needs_physical : 1;
+       u8 has_overlay : 1;
+       u8 overlay_needs_physical : 1;
+       u8 supports_tv : 1;
+       u8 has_bsd_ring : 1;
+       u8 has_blt_ring : 1;
 };
 
 enum no_fbc_reason {
+       FBC_NO_OUTPUT, /* no outputs enabled to compress */
        FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
        FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
        FBC_MODE_TOO_LARGE, /* mode too large for compression */
@@ -241,9 +246,16 @@ typedef struct drm_i915_private {
 
        void __iomem *regs;
 
+       struct intel_gmbus {
+               struct i2c_adapter adapter;
+               struct i2c_adapter *force_bit;
+               u32 reg0;
+       } *gmbus;
+
        struct pci_dev *bridge_dev;
        struct intel_ring_buffer render_ring;
        struct intel_ring_buffer bsd_ring;
+       struct intel_ring_buffer blt_ring;
        uint32_t next_seqno;
 
        drm_dma_handle_t *status_page_dmah;
@@ -263,6 +275,9 @@ typedef struct drm_i915_private {
        int front_offset;
        int current_page;
        int page_flipping;
+#define I915_DEBUG_READ (1<<0)
+#define I915_DEBUG_WRITE (1<<1)
+       unsigned long debug_flags;
 
        wait_queue_head_t irq_queue;
        atomic_t irq_received;
@@ -289,24 +304,21 @@ typedef struct drm_i915_private {
        unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
        int vblank_pipe;
        int num_pipe;
-       u32 flush_rings;
-#define FLUSH_RENDER_RING      0x1
-#define FLUSH_BSD_RING         0x2
 
        /* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
+#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
        struct timer_list hangcheck_timer;
        int hangcheck_count;
        uint32_t last_acthd;
        uint32_t last_instdone;
        uint32_t last_instdone1;
 
-       struct drm_mm vram;
-
        unsigned long cfb_size;
        unsigned long cfb_pitch;
+       unsigned long cfb_offset;
        int cfb_fence;
        int cfb_plane;
+       int cfb_y;
 
        int irq_enabled;
 
@@ -316,8 +328,7 @@ typedef struct drm_i915_private {
        struct intel_overlay *overlay;
 
        /* LVDS info */
-       int backlight_duty_cycle;  /* restore backlight to this value */
-       bool panel_wants_dither;
+       int backlight_level;  /* restore backlight to this value */
        struct drm_display_mode *panel_fixed_mode;
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -328,13 +339,23 @@ typedef struct drm_i915_private {
        unsigned int lvds_vbt:1;
        unsigned int int_crt_support:1;
        unsigned int lvds_use_ssc:1;
-       unsigned int edp_support:1;
        int lvds_ssc_freq;
-       int edp_bpp;
+       struct {
+               int rate;
+               int lanes;
+               int preemphasis;
+               int vswing;
+
+               bool initialized;
+               bool support;
+               int bpp;
+               struct edp_power_seq pps;
+       } edp;
+       bool no_aux_handshake;
 
        struct notifier_block lid_notifier;
 
-       int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
+       int crt_ddc_pin;
        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 */
@@ -344,6 +365,7 @@ typedef struct drm_i915_private {
        spinlock_t error_lock;
        struct drm_i915_error_state *first_error;
        struct work_struct error_work;
+       struct completion error_completion;
        struct workqueue_struct *wq;
 
        /* Display functions */
@@ -507,6 +529,11 @@ typedef struct drm_i915_private {
        u32 saveMCHBAR_RENDER_STANDBY;
 
        struct {
+               /** Bridge to intel-gtt-ko */
+               struct intel_gtt *gtt;
+               /** Memory allocator for GTT stolen memory */
+               struct drm_mm vram;
+               /** Memory allocator for GTT */
                struct drm_mm gtt_space;
 
                struct io_mapping *gtt_mapping;
@@ -521,7 +548,16 @@ typedef struct drm_i915_private {
                 */
                struct list_head shrink_list;
 
-               spinlock_t active_list_lock;
+               /**
+                * List of objects currently involved in rendering.
+                *
+                * Includes buffers having the contents of their GPU caches
+                * flushed, not necessarily primitives.  last_rendering_seqno
+                * represents when the rendering involved will be completed.
+                *
+                * A reference is held on the buffer while on this list.
+                */
+               struct list_head active_list;
 
                /**
                 * List of objects which are not in the ringbuffer but which
@@ -534,15 +570,6 @@ typedef struct drm_i915_private {
                 */
                struct list_head flushing_list;
 
-               /**
-                * List of objects currently pending a GPU write flush.
-                *
-                * All elements on this list will belong to either the
-                * active_list or flushing_list, last_rendering_seqno can
-                * be used to differentiate between the two elements.
-                */
-               struct list_head gpu_write_list;
-
                /**
                 * LRU list of objects which are not in the ringbuffer and
                 * are ready to unbind, but are still in the GTT.
@@ -555,6 +582,12 @@ typedef struct drm_i915_private {
                 */
                struct list_head inactive_list;
 
+               /**
+                * LRU list of objects which are not in the ringbuffer but
+                * are still pinned in the GTT.
+                */
+               struct list_head pinned_list;
+
                /** LRU list of objects with fence regs on them. */
                struct list_head fence_list;
 
@@ -611,6 +644,17 @@ typedef struct drm_i915_private {
 
                /* storage for physical objects */
                struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+               uint32_t flush_rings;
+
+               /* accounting, useful for userland debugging */
+               size_t object_memory;
+               size_t pin_memory;
+               size_t gtt_memory;
+               size_t gtt_total;
+               u32 object_count;
+               u32 pin_count;
+               u32 gtt_count;
        } mm;
        struct sdvo_device_mapping sdvo_mappings[2];
        /* indicate whether the LVDS_BORDER should be enabled or not */
@@ -626,8 +670,6 @@ typedef struct drm_i915_private {
        /* Reclocking support */
        bool render_reclock_avail;
        bool lvds_downclock_avail;
-       /* indicate whether the LVDS EDID is OK */
-       bool lvds_edid_good;
        /* indicates the reduced downclock for LVDS*/
        int lvds_downclock;
        struct work_struct idle_work;
@@ -661,6 +703,8 @@ typedef struct drm_i915_private {
        struct drm_mm_node *compressed_fb;
        struct drm_mm_node *compressed_llb;
 
+       unsigned long last_gpu_reset;
+
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 } drm_i915_private_t;
@@ -673,7 +717,8 @@ struct drm_i915_gem_object {
        struct drm_mm_node *gtt_space;
 
        /** This object's place on the active/flushing/inactive lists */
-       struct list_head list;
+       struct list_head ring_list;
+       struct list_head mm_list;
        /** This object's place on GPU write list */
        struct list_head gpu_write_list;
        /** This object's place on eviction list */
@@ -816,12 +861,14 @@ struct drm_i915_gem_request {
        /** global list entry for this request */
        struct list_head list;
 
+       struct drm_i915_file_private *file_priv;
        /** file_priv list entry for this request */
        struct list_head client_list;
 };
 
 struct drm_i915_file_private {
        struct {
+               struct spinlock lock;
                struct list_head request_list;
        } mm;
 };
@@ -862,7 +909,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
 extern int i915_emit_box(struct drm_device *dev,
                         struct drm_clip_rect *boxes,
                         int i, int DR1, int DR4);
-extern int i965_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev, u8 flags);
 extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -871,7 +918,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
-void i915_destroy_error_state(struct drm_device *dev);
 extern int i915_irq_emit(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -908,6 +954,12 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 
 void intel_enable_asle (struct drm_device *dev);
 
+#ifdef CONFIG_DEBUG_FS
+extern void i915_destroy_error_state(struct drm_device *dev);
+#else
+#define i915_destroy_error_state(x)
+#endif
+
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -922,6 +974,7 @@ extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(struct drm_device * dev,
                             struct drm_file *file_priv, struct mem_block *heap);
 /* i915_gem.c */
+int i915_gem_check_is_wedged(struct drm_device *dev);
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -972,13 +1025,22 @@ void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
-bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+       return (int32_t)(seq1 - seq2) >= 0;
+}
+
+int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+                                 bool interruptible);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+                                 bool interruptible);
 void i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_reset(struct drm_device *dev);
 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,
@@ -990,16 +1052,18 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
 int i915_gpu_idle(struct drm_device *dev);
 int i915_gem_idle(struct drm_device *dev);
 uint32_t i915_add_request(struct drm_device *dev,
-               struct drm_file *file_priv,
-               uint32_t flush_domains,
-               struct intel_ring_buffer *ring);
+                         struct drm_file *file_priv,
+                         struct drm_i915_gem_request *request,
+                         struct intel_ring_buffer *ring);
 int i915_do_wait_request(struct drm_device *dev,
-               uint32_t seqno, int interruptible,
-               struct intel_ring_buffer *ring);
+                        uint32_t seqno,
+                        bool interruptible,
+                        struct intel_ring_buffer *ring);
 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);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+                                        bool pipelined);
 int i915_gem_attach_phys_object(struct drm_device *dev,
                                struct drm_gem_object *obj,
                                int id,
@@ -1007,10 +1071,7 @@ int i915_gem_attach_phys_object(struct drm_device *dev,
 void i915_gem_detach_phys_object(struct drm_device *dev,
                                 struct drm_gem_object *obj);
 void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void i915_gem_object_put_pages(struct drm_gem_object *obj);
 void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
 
 void i915_gem_shrinker_init(void);
 void i915_gem_shrinker_exit(void);
@@ -1032,15 +1093,14 @@ bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
 /* i915_gem_debug.c */
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
                          const char *where, uint32_t mark);
-#if WATCH_INACTIVE
-void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#if WATCH_LISTS
+int i915_verify_lists(struct drm_device *dev);
 #else
-#define i915_verify_inactive(dev, file, line)
+#define i915_verify_lists(dev) 0
 #endif
 void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
                          const char *where, uint32_t mark);
-void i915_dump_lru(struct drm_device *dev, const char *where);
 
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
@@ -1054,21 +1114,42 @@ extern int i915_restore_state(struct drm_device *dev);
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
+/* intel_i2c.c */
+extern int intel_setup_gmbus(struct drm_device *dev);
+extern void intel_teardown_gmbus(struct drm_device *dev);
+extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+       return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
+}
+extern void intel_i2c_reset(struct drm_device *dev);
+
+/* intel_opregion.c */
+extern int intel_opregion_setup(struct drm_device *dev);
 #ifdef CONFIG_ACPI
-/* i915_opregion.c */
-extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev, int suspend);
-extern void opregion_asle_intr(struct drm_device *dev);
-extern void ironlake_opregion_gse_intr(struct drm_device *dev);
-extern void opregion_enable_asle(struct drm_device *dev);
+extern void intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_fini(struct drm_device *dev);
+extern void intel_opregion_asle_intr(struct drm_device *dev);
+extern void intel_opregion_gse_intr(struct drm_device *dev);
+extern void intel_opregion_enable_asle(struct drm_device *dev);
 #else
-static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
-static inline void opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void opregion_enable_asle(struct drm_device *dev) { return; }
+static inline void intel_opregion_init(struct drm_device *dev) { return; }
+static inline void intel_opregion_fini(struct drm_device *dev) { return; }
+static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
+/* intel_acpi.c */
+#ifdef CONFIG_ACPI
+extern void intel_register_dsm_handler(void);
+extern void intel_unregister_dsm_handler(void);
+#else
+static inline void intel_register_dsm_handler(void) { return; }
+static inline void intel_unregister_dsm_handler(void) { return; }
+#endif /* CONFIG_ACPI */
+
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1084,8 +1165,10 @@ extern void intel_detect_pch (struct drm_device *dev);
 extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
 
 /* overlay */
+#ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+#endif
 
 /**
  * Lock test for when it's just for synchronization of ring access.
@@ -1099,8 +1182,26 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
                LOCK_TEST_WITH_RETURN(dev, file_priv);                  \
 } while (0)
 
-#define I915_READ(reg)          readl(dev_priv->regs + (reg))
-#define I915_WRITE(reg, val)     writel(val, dev_priv->regs + (reg))
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+       u32 val;
+
+       val = readl(dev_priv->regs + reg);
+       if (dev_priv->debug_flags & I915_DEBUG_READ)
+               printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+       return val;
+}
+
+static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
+                             u32 val)
+{
+       writel(val, dev_priv->regs + reg);
+       if (dev_priv->debug_flags & I915_DEBUG_WRITE)
+               printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+}
+
+#define I915_READ(reg)          i915_read(dev_priv, (reg))
+#define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
 #define I915_READ16(reg)       readw(dev_priv->regs + (reg))
 #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
 #define I915_READ8(reg)                readb(dev_priv->regs + (reg))
@@ -1110,6 +1211,11 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define POSTING_READ(reg)      (void)I915_READ(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16(reg)
 
+#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
+                               I915_DEBUG_WRITE)
+#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
+                                                           I915_DEBUG_WRITE))
+
 #define I915_VERBOSE 0
 
 #define BEGIN_LP_RING(n)  do { \
@@ -1166,8 +1272,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_I915GM(dev)         ((dev)->pci_device == 0x2592)
 #define IS_I945G(dev)          ((dev)->pci_device == 0x2772)
 #define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
-#define IS_I965G(dev)          (INTEL_INFO(dev)->is_i965g)
-#define IS_I965GM(dev)         (INTEL_INFO(dev)->is_i965gm)
 #define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
 #define IS_GM45(dev)           ((dev)->pci_device == 0x2A42)
@@ -1178,8 +1282,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
 #define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
-#define IS_IRONLAKE(dev)       (INTEL_INFO(dev)->is_ironlake)
-#define IS_I9XX(dev)           (INTEL_INFO(dev)->is_i9xx)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 
 #define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
@@ -1188,33 +1290,34 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
 
-#define HAS_BSD(dev)            (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
+#define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
+#define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
+
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
-#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (IS_I9XX(dev) && !IS_PINEVIEW(dev))
-#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IRONLAKE(dev))
-#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IRONLAKE(dev))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_GEN5(dev))
 #define SUPPORTS_EDP(dev)              (IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev)               (IS_I9XX(dev) && IS_MOBILE(dev) && \
-                                       !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
-                                       !IS_GEN6(dev))
+#define SUPPORTS_TV(dev)               (INTEL_INFO(dev)->supports_tv)
 #define I915_HAS_HOTPLUG(dev)           (INTEL_INFO(dev)->has_hotplug)
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
 
-#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev))
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
 
-#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) ||        \
-                           IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
 
 #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
index 90b1d6753b9d493d3ed8d2c45153bf2047b54d8f..8eb8453208b5ce491e77c1c06c77c1c0a2da41bc 100644 (file)
@@ -37,7 +37,9 @@
 #include <linux/intel-gtt.h>
 
 static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
+
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+                                                 bool pipelined);
 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_cpu_domain(struct drm_gem_object *obj,
@@ -46,7 +48,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
                                                     uint64_t offset,
                                                     uint64_t size);
 static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+                                         bool interruptible);
 static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
                                           unsigned alignment);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
@@ -55,9 +58,111 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *o
                                struct drm_file *file_priv);
 static void i915_gem_free_object_tail(struct drm_gem_object *obj);
 
+static int
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+                         gfp_t gfpmask);
+
+static void
+i915_gem_object_put_pages(struct drm_gem_object *obj);
+
 static LIST_HEAD(shrink_list);
 static DEFINE_SPINLOCK(shrink_list_lock);
 
+/* some bookkeeping */
+static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.object_count++;
+       dev_priv->mm.object_memory += size;
+}
+
+static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.object_count--;
+       dev_priv->mm.object_memory -= size;
+}
+
+static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.gtt_count++;
+       dev_priv->mm.gtt_memory += size;
+}
+
+static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.gtt_count--;
+       dev_priv->mm.gtt_memory -= size;
+}
+
+static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.pin_count++;
+       dev_priv->mm.pin_memory += size;
+}
+
+static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.pin_count--;
+       dev_priv->mm.pin_memory -= size;
+}
+
+int
+i915_gem_check_is_wedged(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct completion *x = &dev_priv->error_completion;
+       unsigned long flags;
+       int ret;
+
+       if (!atomic_read(&dev_priv->mm.wedged))
+               return 0;
+
+       ret = wait_for_completion_interruptible(x);
+       if (ret)
+               return ret;
+
+       /* Success, we reset the GPU! */
+       if (!atomic_read(&dev_priv->mm.wedged))
+               return 0;
+
+       /* GPU is hung, bump the completion count to account for
+        * the token we just consumed so that we never hit zero and
+        * end up waiting upon a subsequent completion event that
+        * will never happen.
+        */
+       spin_lock_irqsave(&x->wait.lock, flags);
+       x->done++;
+       spin_unlock_irqrestore(&x->wait.lock, flags);
+       return -EIO;
+}
+
+static int i915_mutex_lock_interruptible(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (atomic_read(&dev_priv->mm.wedged)) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EAGAIN;
+       }
+
+       WARN_ON(i915_verify_lists(dev));
+       return 0;
+}
+
 static inline bool
 i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
 {
@@ -66,7 +171,8 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
                obj_priv->pin_count == 0;
 }
 
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+int i915_gem_do_init(struct drm_device *dev,
+                    unsigned long start,
                     unsigned long end)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -80,7 +186,7 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
        drm_mm_init(&dev_priv->mm.gtt_space, start,
                    end - start);
 
-       dev->gtt_total = (uint32_t) (end - start);
+       dev_priv->mm.gtt_total = end - start;
 
        return 0;
 }
@@ -103,14 +209,16 @@ int
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_get_aperture *args = data;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       args->aper_size = dev->gtt_total;
-       args->aper_available_size = (args->aper_size -
-                                    atomic_read(&dev->pin_memory));
+       mutex_lock(&dev->struct_mutex);
+       args->aper_size = dev_priv->mm.gtt_total;
+       args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -136,12 +244,17 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
                return -ENOMEM;
 
        ret = drm_gem_handle_create(file_priv, obj, &handle);
-       /* drop reference from allocate - handle holds it now */
-       drm_gem_object_unreference_unlocked(obj);
        if (ret) {
+               drm_gem_object_release(obj);
+               i915_gem_info_remove_obj(dev->dev_private, obj->size);
+               kfree(obj);
                return ret;
        }
 
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_unreference(obj);
+       trace_i915_gem_object_create(obj);
+
        args->handle = handle;
        return 0;
 }
@@ -152,19 +265,14 @@ fast_shmem_read(struct page **pages,
                char __user *data,
                int length)
 {
-       char __iomem *vaddr;
-       int unwritten;
-
-       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
-       if (vaddr == NULL)
-               return -ENOMEM;
-       unwritten = __copy_to_user_inatomic(data, vaddr + page_offset, length);
-       kunmap_atomic(vaddr, KM_USER0);
+       char *vaddr;
+       int ret;
 
-       if (unwritten)
-               return -EFAULT;
+       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+       ret = __copy_to_user_inatomic(data, vaddr + page_offset, length);
+       kunmap_atomic(vaddr);
 
-       return 0;
+       return ret;
 }
 
 static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
@@ -258,22 +366,10 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
        loff_t offset, page_base;
        char __user *user_data;
        int page_offset, page_length;
-       int ret;
 
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
 
-       mutex_lock(&dev->struct_mutex);
-
-       ret = i915_gem_object_get_pages(obj, 0);
-       if (ret != 0)
-               goto fail_unlock;
-
-       ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
-                                                       args->size);
-       if (ret != 0)
-               goto fail_put_pages;
-
        obj_priv = to_intel_bo(obj);
        offset = args->offset;
 
@@ -290,23 +386,17 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
 
-               ret = fast_shmem_read(obj_priv->pages,
-                                     page_base, page_offset,
-                                     user_data, page_length);
-               if (ret)
-                       goto fail_put_pages;
+               if (fast_shmem_read(obj_priv->pages,
+                                   page_base, page_offset,
+                                   user_data, page_length))
+                       return -EFAULT;
 
                remain -= page_length;
                user_data += page_length;
                offset += page_length;
        }
 
-fail_put_pages:
-       i915_gem_object_put_pages(obj);
-fail_unlock:
-       mutex_unlock(&dev->struct_mutex);
-
-       return ret;
+       return 0;
 }
 
 static int
@@ -367,31 +457,28 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
        last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
        num_pages = last_data_page - first_data_page + 1;
 
-       user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+       user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
        if (user_pages == NULL)
                return -ENOMEM;
 
+       mutex_unlock(&dev->struct_mutex);
        down_read(&mm->mmap_sem);
        pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
                                      num_pages, 1, 0, user_pages, NULL);
        up_read(&mm->mmap_sem);
+       mutex_lock(&dev->struct_mutex);
        if (pinned_pages < num_pages) {
                ret = -EFAULT;
-               goto fail_put_user_pages;
+               goto out;
        }
 
-       do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
-       mutex_lock(&dev->struct_mutex);
-
-       ret = i915_gem_object_get_pages_or_evict(obj);
+       ret = i915_gem_object_set_cpu_read_domain_range(obj,
+                                                       args->offset,
+                                                       args->size);
        if (ret)
-               goto fail_unlock;
+               goto out;
 
-       ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
-                                                       args->size);
-       if (ret != 0)
-               goto fail_put_pages;
+       do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
        obj_priv = to_intel_bo(obj);
        offset = args->offset;
@@ -436,11 +523,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
                offset += page_length;
        }
 
-fail_put_pages:
-       i915_gem_object_put_pages(obj);
-fail_unlock:
-       mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
        for (i = 0; i < pinned_pages; i++) {
                SetPageDirty(user_pages[i]);
                page_cache_release(user_pages[i]);
@@ -462,37 +545,64 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_pread *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-       int ret;
+       int ret = 0;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (obj == NULL)
-               return -ENOENT;
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
        obj_priv = to_intel_bo(obj);
 
        /* Bounds check source.  */
        if (args->offset > obj->size || args->size > obj->size - args->offset) {
                ret = -EINVAL;
-               goto err;
+               goto out;
        }
 
+       if (args->size == 0)
+               goto out;
+
        if (!access_ok(VERIFY_WRITE,
                       (char __user *)(uintptr_t)args->data_ptr,
                       args->size)) {
                ret = -EFAULT;
-               goto err;
+               goto out;
        }
 
-       if (i915_gem_object_needs_bit17_swizzle(obj)) {
-               ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
-       } else {
-               ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
-               if (ret != 0)
-                       ret = i915_gem_shmem_pread_slow(dev, obj, args,
-                                                       file_priv);
+       ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+                                      args->size);
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
        }
 
-err:
-       drm_gem_object_unreference_unlocked(obj);
+       ret = i915_gem_object_get_pages_or_evict(obj);
+       if (ret)
+               goto out;
+
+       ret = i915_gem_object_set_cpu_read_domain_range(obj,
+                                                       args->offset,
+                                                       args->size);
+       if (ret)
+               goto out_put;
+
+       ret = -EFAULT;
+       if (!i915_gem_object_needs_bit17_swizzle(obj))
+               ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
+       if (ret == -EFAULT)
+               ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
+
+out_put:
+       i915_gem_object_put_pages(obj);
+out:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -509,13 +619,11 @@ fast_user_write(struct io_mapping *mapping,
        char *vaddr_atomic;
        unsigned long unwritten;
 
-       vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0);
+       vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
        unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
                                                      user_data, length);
-       io_mapping_unmap_atomic(vaddr_atomic, KM_USER0);
-       if (unwritten)
-               return -EFAULT;
-       return 0;
+       io_mapping_unmap_atomic(vaddr_atomic);
+       return unwritten;
 }
 
 /* Here's the write path which can sleep for
@@ -548,18 +656,14 @@ fast_shmem_write(struct page **pages,
                 char __user *data,
                 int length)
 {
-       char __iomem *vaddr;
-       unsigned long unwritten;
+       char *vaddr;
+       int ret;
 
-       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
-       if (vaddr == NULL)
-               return -ENOMEM;
-       unwritten = __copy_from_user_inatomic(vaddr + page_offset, data, length);
-       kunmap_atomic(vaddr, KM_USER0);
+       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+       ret = __copy_from_user_inatomic(vaddr + page_offset, data, length);
+       kunmap_atomic(vaddr);
 
-       if (unwritten)
-               return -EFAULT;
-       return 0;
+       return ret;
 }
 
 /**
@@ -577,22 +681,10 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
        loff_t offset, page_base;
        char __user *user_data;
        int page_offset, page_length;
-       int ret;
 
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
 
-
-       mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_object_pin(obj, 0);
-       if (ret) {
-               mutex_unlock(&dev->struct_mutex);
-               return ret;
-       }
-       ret = i915_gem_object_set_to_gtt_domain(obj, 1);
-       if (ret)
-               goto fail;
-
        obj_priv = to_intel_bo(obj);
        offset = obj_priv->gtt_offset + args->offset;
 
@@ -609,26 +701,21 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
 
-               ret = fast_user_write (dev_priv->mm.gtt_mapping, page_base,
-                                      page_offset, user_data, page_length);
-
                /* If we get a fault while copying data, then (presumably) our
                 * source page isn't available.  Return the error and we'll
                 * retry in the slow path.
                 */
-               if (ret)
-                       goto fail;
+               if (fast_user_write(dev_priv->mm.gtt_mapping, page_base,
+                                   page_offset, user_data, page_length))
+
+                       return -EFAULT;
 
                remain -= page_length;
                user_data += page_length;
                offset += page_length;
        }
 
-fail:
-       i915_gem_object_unpin(obj);
-       mutex_unlock(&dev->struct_mutex);
-
-       return ret;
+       return 0;
 }
 
 /**
@@ -665,27 +752,24 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
        last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
        num_pages = last_data_page - first_data_page + 1;
 
-       user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+       user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
        if (user_pages == NULL)
                return -ENOMEM;
 
+       mutex_unlock(&dev->struct_mutex);
        down_read(&mm->mmap_sem);
        pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
                                      num_pages, 0, 0, user_pages, NULL);
        up_read(&mm->mmap_sem);
+       mutex_lock(&dev->struct_mutex);
        if (pinned_pages < num_pages) {
                ret = -EFAULT;
                goto out_unpin_pages;
        }
 
-       mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_object_pin(obj, 0);
-       if (ret)
-               goto out_unlock;
-
        ret = i915_gem_object_set_to_gtt_domain(obj, 1);
        if (ret)
-               goto out_unpin_object;
+               goto out_unpin_pages;
 
        obj_priv = to_intel_bo(obj);
        offset = obj_priv->gtt_offset + args->offset;
@@ -721,10 +805,6 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
                data_ptr += page_length;
        }
 
-out_unpin_object:
-       i915_gem_object_unpin(obj);
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
 out_unpin_pages:
        for (i = 0; i < pinned_pages; i++)
                page_cache_release(user_pages[i]);
@@ -747,21 +827,10 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
        loff_t offset, page_base;
        char __user *user_data;
        int page_offset, page_length;
-       int ret;
 
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
 
-       mutex_lock(&dev->struct_mutex);
-
-       ret = i915_gem_object_get_pages(obj, 0);
-       if (ret != 0)
-               goto fail_unlock;
-
-       ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-       if (ret != 0)
-               goto fail_put_pages;
-
        obj_priv = to_intel_bo(obj);
        offset = args->offset;
        obj_priv->dirty = 1;
@@ -779,23 +848,17 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
 
-               ret = fast_shmem_write(obj_priv->pages,
+               if (fast_shmem_write(obj_priv->pages,
                                       page_base, page_offset,
-                                      user_data, page_length);
-               if (ret)
-                       goto fail_put_pages;
+                                      user_data, page_length))
+                       return -EFAULT;
 
                remain -= page_length;
                user_data += page_length;
                offset += page_length;
        }
 
-fail_put_pages:
-       i915_gem_object_put_pages(obj);
-fail_unlock:
-       mutex_unlock(&dev->struct_mutex);
-
-       return ret;
+       return 0;
 }
 
 /**
@@ -833,30 +896,26 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
        last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
        num_pages = last_data_page - first_data_page + 1;
 
-       user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+       user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
        if (user_pages == NULL)
                return -ENOMEM;
 
+       mutex_unlock(&dev->struct_mutex);
        down_read(&mm->mmap_sem);
        pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
                                      num_pages, 0, 0, user_pages, NULL);
        up_read(&mm->mmap_sem);
+       mutex_lock(&dev->struct_mutex);
        if (pinned_pages < num_pages) {
                ret = -EFAULT;
-               goto fail_put_user_pages;
+               goto out;
        }
 
-       do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
-       mutex_lock(&dev->struct_mutex);
-
-       ret = i915_gem_object_get_pages_or_evict(obj);
+       ret = i915_gem_object_set_to_cpu_domain(obj, 1);
        if (ret)
-               goto fail_unlock;
+               goto out;
 
-       ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-       if (ret != 0)
-               goto fail_put_pages;
+       do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
        obj_priv = to_intel_bo(obj);
        offset = args->offset;
@@ -902,11 +961,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
                offset += page_length;
        }
 
-fail_put_pages:
-       i915_gem_object_put_pages(obj);
-fail_unlock:
-       mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
        for (i = 0; i < pinned_pages; i++)
                page_cache_release(user_pages[i]);
        drm_free_large(user_pages);
@@ -921,29 +976,46 @@ fail_put_user_pages:
  */
 int
 i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv)
+                     struct drm_file *file)
 {
        struct drm_i915_gem_pwrite *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
        int ret = 0;
 
-       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (obj == NULL)
-               return -ENOENT;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+
+       obj = drm_gem_object_lookup(dev, file, args->handle);
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
        obj_priv = to_intel_bo(obj);
 
+
        /* Bounds check destination. */
        if (args->offset > obj->size || args->size > obj->size - args->offset) {
                ret = -EINVAL;
-               goto err;
+               goto out;
        }
 
+       if (args->size == 0)
+               goto out;
+
        if (!access_ok(VERIFY_READ,
                       (char __user *)(uintptr_t)args->data_ptr,
                       args->size)) {
                ret = -EFAULT;
-               goto err;
+               goto out;
+       }
+
+       ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+                                     args->size);
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
        }
 
        /* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -953,32 +1025,47 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
         * perspective, requiring manual detiling by the client.
         */
        if (obj_priv->phys_obj)
-               ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
+               ret = i915_gem_phys_pwrite(dev, obj, args, file);
        else if (obj_priv->tiling_mode == I915_TILING_NONE &&
-                dev->gtt_total != 0 &&
+                obj_priv->gtt_space &&
                 obj->write_domain != I915_GEM_DOMAIN_CPU) {
-               ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
-               if (ret == -EFAULT) {
-                       ret = i915_gem_gtt_pwrite_slow(dev, obj, args,
-                                                      file_priv);
-               }
-       } else if (i915_gem_object_needs_bit17_swizzle(obj)) {
-               ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file_priv);
+               ret = i915_gem_object_pin(obj, 0);
+               if (ret)
+                       goto out;
+
+               ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+               if (ret)
+                       goto out_unpin;
+
+               ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
+               if (ret == -EFAULT)
+                       ret = i915_gem_gtt_pwrite_slow(dev, obj, args, file);
+
+out_unpin:
+               i915_gem_object_unpin(obj);
        } else {
-               ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file_priv);
-               if (ret == -EFAULT) {
-                       ret = i915_gem_shmem_pwrite_slow(dev, obj, args,
-                                                        file_priv);
-               }
-       }
+               ret = i915_gem_object_get_pages_or_evict(obj);
+               if (ret)
+                       goto out;
 
-#if WATCH_PWRITE
-       if (ret)
-               DRM_INFO("pwrite failed %d\n", ret);
-#endif
+               ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+               if (ret)
+                       goto out_put;
 
-err:
-       drm_gem_object_unreference_unlocked(obj);
+               ret = -EFAULT;
+               if (!i915_gem_object_needs_bit17_swizzle(obj))
+                       ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
+               if (ret == -EFAULT)
+                       ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+
+out_put:
+               i915_gem_object_put_pages(obj);
+       }
+
+out:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
@@ -1014,19 +1101,19 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        if (write_domain != 0 && read_domains != write_domain)
                return -EINVAL;
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (obj == NULL)
-               return -ENOENT;
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
        obj_priv = to_intel_bo(obj);
 
-       mutex_lock(&dev->struct_mutex);
-
        intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-       DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
-                obj, obj->size, read_domains, write_domain);
-#endif
        if (read_domains & I915_GEM_DOMAIN_GTT) {
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
 
@@ -1050,12 +1137,12 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
        }
 
-       
        /* Maintain LRU order of "inactive" objects */
        if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
-               list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+               list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
 
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
 }
@@ -1069,30 +1156,27 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_sw_finish *args = data;
        struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
        int ret = 0;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
-               mutex_unlock(&dev->struct_mutex);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto unlock;
        }
 
-#if WATCH_BUF
-       DRM_INFO("%s: sw_finish %d (%p %zd)\n",
-                __func__, args->handle, obj, obj->size);
-#endif
-       obj_priv = to_intel_bo(obj);
-
        /* Pinned buffers may be scanout, so flush the cache */
-       if (obj_priv->pin_count)
+       if (to_intel_bo(obj)->pin_count)
                i915_gem_object_flush_cpu_write_domain(obj);
 
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
 }
@@ -1181,13 +1265,13 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        /* Need a new fence register? */
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence_reg(obj);
+               ret = i915_gem_object_get_fence_reg(obj, true);
                if (ret)
                        goto unlock;
        }
 
        if (i915_gem_object_is_inactive(obj_priv))
-               list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+               list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
 
        pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
                page_offset;
@@ -1246,7 +1330,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
                                                    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;
+               ret = -ENOSPC;
                goto out_free_list;
        }
 
@@ -1258,9 +1342,9 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
        }
 
        list->hash.key = list->file_offset_node->start;
-       if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+       ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+       if (ret) {
                DRM_ERROR("failed to add to map hash\n");
-               ret = -ENOMEM;
                goto out_free_mm;
        }
 
@@ -1345,14 +1429,14 @@ i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
         * 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)
+       if (INTEL_INFO(dev)->gen >= 4 || 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))
+       if (INTEL_INFO(dev)->gen == 3)
                start = 1024*1024;
        else
                start = 512*1024;
@@ -1390,29 +1474,27 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (obj == NULL)
-               return -ENOENT;
-
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
        obj_priv = to_intel_bo(obj);
 
        if (obj_priv->madv != I915_MADV_WILLNEED) {
                DRM_ERROR("Attempting to mmap a purgeable buffer\n");
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
-
        if (!obj_priv->mmap_offset) {
                ret = i915_gem_create_mmap_offset(obj);
-               if (ret) {
-                       drm_gem_object_unreference(obj);
-                       mutex_unlock(&dev->struct_mutex);
-                       return ret;
-               }
+               if (ret)
+                       goto out;
        }
 
        args->offset = obj_priv->mmap_offset;
@@ -1423,20 +1505,18 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
         */
        if (!obj_priv->agp_mem) {
                ret = i915_gem_object_bind_to_gtt(obj, 0);
-               if (ret) {
-                       drm_gem_object_unreference(obj);
-                       mutex_unlock(&dev->struct_mutex);
-                       return ret;
-               }
+               if (ret)
+                       goto out;
        }
 
+out:
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
-
-       return 0;
+       return ret;
 }
 
-void
+static void
 i915_gem_object_put_pages(struct drm_gem_object *obj)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1470,13 +1550,25 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
        obj_priv->pages = NULL;
 }
 
+static uint32_t
+i915_gem_next_request_seqno(struct drm_device *dev,
+                           struct intel_ring_buffer *ring)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       ring->outstanding_lazy_request = true;
+       return dev_priv->next_seqno;
+}
+
 static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+i915_gem_object_move_to_active(struct drm_gem_object *obj,
                               struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = obj->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
+
        BUG_ON(ring == NULL);
        obj_priv->ring = ring;
 
@@ -1485,10 +1577,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
                drm_gem_object_reference(obj);
                obj_priv->active = 1;
        }
+
        /* Move from whatever list we were on to the tail of execution. */
-       spin_lock(&dev_priv->mm.active_list_lock);
-       list_move_tail(&obj_priv->list, &ring->active_list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       list_move_tail(&obj_priv->mm_list, &dev_priv->mm.active_list);
+       list_move_tail(&obj_priv->ring_list, &ring->active_list);
        obj_priv->last_rendering_seqno = seqno;
 }
 
@@ -1500,7 +1592,8 @@ i915_gem_object_move_to_flushing(struct drm_gem_object *obj)
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
        BUG_ON(!obj_priv->active);
-       list_move_tail(&obj_priv->list, &dev_priv->mm.flushing_list);
+       list_move_tail(&obj_priv->mm_list, &dev_priv->mm.flushing_list);
+       list_del_init(&obj_priv->ring_list);
        obj_priv->last_rendering_seqno = 0;
 }
 
@@ -1538,11 +1631,11 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
        if (obj_priv->pin_count != 0)
-               list_del_init(&obj_priv->list);
+               list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list);
        else
-               list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+               list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+       list_del_init(&obj_priv->ring_list);
 
        BUG_ON(!list_empty(&obj_priv->gpu_write_list));
 
@@ -1552,30 +1645,28 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
                obj_priv->active = 0;
                drm_gem_object_unreference(obj);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 }
 
 static void
 i915_gem_process_flushing_list(struct drm_device *dev,
-                              uint32_t flush_domains, uint32_t seqno,
+                              uint32_t flush_domains,
                               struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv, *next;
 
        list_for_each_entry_safe(obj_priv, next,
-                                &dev_priv->mm.gpu_write_list,
+                                &ring->gpu_write_list,
                                 gpu_write_list) {
                struct drm_gem_object *obj = &obj_priv->base;
 
-               if ((obj->write_domain & flush_domains) ==
-                   obj->write_domain &&
-                   obj_priv->ring->ring_flag == ring->ring_flag) {
+               if (obj->write_domain & flush_domains) {
                        uint32_t old_write_domain = obj->write_domain;
 
                        obj->write_domain = 0;
                        list_del_init(&obj_priv->gpu_write_list);
-                       i915_gem_object_move_to_active(obj, seqno, ring);
+                       i915_gem_object_move_to_active(obj, ring);
 
                        /* update the fence lru list */
                        if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1593,23 +1684,27 @@ i915_gem_process_flushing_list(struct drm_device *dev,
 }
 
 uint32_t
-i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
-                uint32_t flush_domains, struct intel_ring_buffer *ring)
+i915_add_request(struct drm_device *dev,
+                struct drm_file *file,
+                struct drm_i915_gem_request *request,
+                struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_file_private *i915_file_priv = NULL;
-       struct drm_i915_gem_request *request;
+       struct drm_i915_file_private *file_priv = NULL;
        uint32_t seqno;
        int was_empty;
 
-       if (file_priv != NULL)
-               i915_file_priv = file_priv->driver_priv;
+       if (file != NULL)
+               file_priv = file->driver_priv;
 
-       request = kzalloc(sizeof(*request), GFP_KERNEL);
-       if (request == NULL)
-               return 0;
+       if (request == NULL) {
+               request = kzalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return 0;
+       }
 
-       seqno = ring->add_request(dev, ring, file_priv, flush_domains);
+       seqno = ring->add_request(dev, ring, 0);
+       ring->outstanding_lazy_request = false;
 
        request->seqno = seqno;
        request->ring = ring;
@@ -1617,23 +1712,20 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
        was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
 
-       if (i915_file_priv) {
+       if (file_priv) {
+               spin_lock(&file_priv->mm.lock);
+               request->file_priv = file_priv;
                list_add_tail(&request->client_list,
-                             &i915_file_priv->mm.request_list);
-       } else {
-               INIT_LIST_HEAD(&request->client_list);
+                             &file_priv->mm.request_list);
+               spin_unlock(&file_priv->mm.lock);
        }
 
-       /* Associate any objects on the flushing list matching the write
-        * domain we're flushing with our flush.
-        */
-       if (flush_domains != 0) 
-               i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
-
        if (!dev_priv->mm.suspended) {
-               mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+               mod_timer(&dev_priv->hangcheck_timer,
+                         jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
                if (was_empty)
-                       queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+                       queue_delayed_work(dev_priv->wq,
+                                          &dev_priv->mm.retire_work, HZ);
        }
        return seqno;
 }
@@ -1644,91 +1736,105 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
  * Ensures that all commands in the ring are finished
  * before signalling the CPU
  */
-static uint32_t
+static void
 i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
 {
        uint32_t flush_domains = 0;
 
        /* The sampler always gets flushed on i965 (sigh) */
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                flush_domains |= I915_GEM_DOMAIN_SAMPLER;
 
        ring->flush(dev, ring,
                        I915_GEM_DOMAIN_COMMAND, flush_domains);
-       return flush_domains;
 }
 
-/**
- * Moves buffers associated only with the given active seqno from the active
- * to inactive list, potentially freeing them.
- */
-static void
-i915_gem_retire_request(struct drm_device *dev,
-                       struct drm_i915_gem_request *request)
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *file_priv = request->file_priv;
 
-       trace_i915_gem_request_retire(dev, request->seqno);
+       if (!file_priv)
+               return;
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate.
-        */
-       spin_lock(&dev_priv->mm.active_list_lock);
-       while (!list_empty(&request->ring->active_list)) {
-               struct drm_gem_object *obj;
-               struct drm_i915_gem_object *obj_priv;
+       spin_lock(&file_priv->mm.lock);
+       list_del(&request->client_list);
+       request->file_priv = NULL;
+       spin_unlock(&file_priv->mm.lock);
+}
 
-               obj_priv = list_first_entry(&request->ring->active_list,
-                                           struct drm_i915_gem_object,
-                                           list);
-               obj = &obj_priv->base;
+static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
+                                     struct intel_ring_buffer *ring)
+{
+       while (!list_empty(&ring->request_list)) {
+               struct drm_i915_gem_request *request;
 
-               /* If the seqno being retired doesn't match the oldest in the
-                * list, then the oldest in the list must still be newer than
-                * this seqno.
-                */
-               if (obj_priv->last_rendering_seqno != request->seqno)
-                       goto out;
+               request = list_first_entry(&ring->request_list,
+                                          struct drm_i915_gem_request,
+                                          list);
 
-#if WATCH_LRU
-               DRM_INFO("%s: retire %d moves to inactive list %p\n",
-                        __func__, request->seqno, obj);
-#endif
+               list_del(&request->list);
+               i915_gem_request_remove_from_client(request);
+               kfree(request);
+       }
 
-               if (obj->write_domain != 0)
-                       i915_gem_object_move_to_flushing(obj);
-               else {
-                       /* Take a reference on the object so it won't be
-                        * freed while the spinlock is held.  The list
-                        * protection for this spinlock is safe when breaking
-                        * the lock like this since the next thing we do
-                        * is just get the head of the list again.
-                        */
-                       drm_gem_object_reference(obj);
-                       i915_gem_object_move_to_inactive(obj);
-                       spin_unlock(&dev_priv->mm.active_list_lock);
-                       drm_gem_object_unreference(obj);
-                       spin_lock(&dev_priv->mm.active_list_lock);
-               }
+       while (!list_empty(&ring->active_list)) {
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = list_first_entry(&ring->active_list,
+                                           struct drm_i915_gem_object,
+                                           ring_list);
+
+               obj_priv->base.write_domain = 0;
+               list_del_init(&obj_priv->gpu_write_list);
+               i915_gem_object_move_to_inactive(&obj_priv->base);
        }
-out:
-       spin_unlock(&dev_priv->mm.active_list_lock);
 }
 
-/**
- * Returns true if seq1 is later than seq2.
- */
-bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+void i915_gem_reset(struct drm_device *dev)
 {
-       return (int32_t)(seq1 - seq2) >= 0;
-}
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv;
+       int i;
 
-uint32_t
-i915_get_gem_seqno(struct drm_device *dev,
-                  struct intel_ring_buffer *ring)
-{
-       return ring->get_gem_seqno(dev, ring);
+       i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
+       i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
+       i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring);
+
+       /* Remove anything from the flushing lists. The GPU cache is likely
+        * to be lost on reset along with the data, so simply move the
+        * lost bo to the inactive list.
+        */
+       while (!list_empty(&dev_priv->mm.flushing_list)) {
+               obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+                                           struct drm_i915_gem_object,
+                                           mm_list);
+
+               obj_priv->base.write_domain = 0;
+               list_del_init(&obj_priv->gpu_write_list);
+               i915_gem_object_move_to_inactive(&obj_priv->base);
+       }
+
+       /* Move everything out of the GPU domains to ensure we do any
+        * necessary invalidation upon reuse.
+        */
+       list_for_each_entry(obj_priv,
+                           &dev_priv->mm.inactive_list,
+                           mm_list)
+       {
+               obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+       }
+
+       /* The fence registers are invalidated so clear them out */
+       for (i = 0; i < 16; i++) {
+               struct drm_i915_fence_reg *reg;
+
+               reg = &dev_priv->fence_regs[i];
+               if (!reg->obj)
+                       continue;
+
+               i915_gem_clear_fence_reg(reg->obj);
+       }
 }
 
 /**
@@ -1741,38 +1847,58 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t seqno;
 
-       if (!ring->status_page.page_addr
-                       || list_empty(&ring->request_list))
+       if (!ring->status_page.page_addr ||
+           list_empty(&ring->request_list))
                return;
 
-       seqno = i915_get_gem_seqno(dev, ring);
+       WARN_ON(i915_verify_lists(dev));
 
+       seqno = ring->get_seqno(dev, ring);
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
-               uint32_t retiring_seqno;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
                                           list);
-               retiring_seqno = request->seqno;
 
-               if (i915_seqno_passed(seqno, retiring_seqno) ||
-                   atomic_read(&dev_priv->mm.wedged)) {
-                       i915_gem_retire_request(dev, request);
+               if (!i915_seqno_passed(seqno, request->seqno))
+                       break;
+
+               trace_i915_gem_request_retire(dev, request->seqno);
+
+               list_del(&request->list);
+               i915_gem_request_remove_from_client(request);
+               kfree(request);
+       }
 
-                       list_del(&request->list);
-                       list_del(&request->client_list);
-                       kfree(request);
-               } else
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_gem_object *obj;
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = list_first_entry(&ring->active_list,
+                                           struct drm_i915_gem_object,
+                                           ring_list);
+
+               if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
                        break;
+
+               obj = &obj_priv->base;
+               if (obj->write_domain != 0)
+                       i915_gem_object_move_to_flushing(obj);
+               else
+                       i915_gem_object_move_to_inactive(obj);
        }
 
        if (unlikely (dev_priv->trace_irq_seqno &&
                      i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-
                ring->user_irq_put(dev, ring);
                dev_priv->trace_irq_seqno = 0;
        }
+
+       WARN_ON(i915_verify_lists(dev));
 }
 
 void
@@ -1790,16 +1916,16 @@ i915_gem_retire_requests(struct drm_device *dev)
             */
            list_for_each_entry_safe(obj_priv, tmp,
                                     &dev_priv->mm.deferred_free_list,
-                                    list)
+                                    mm_list)
                    i915_gem_free_object_tail(&obj_priv->base);
        }
 
        i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
-       if (HAS_BSD(dev))
-               i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+       i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+       i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring);
 }
 
-void
+static void
 i915_gem_retire_work_handler(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv;
@@ -1809,20 +1935,25 @@ i915_gem_retire_work_handler(struct work_struct *work)
                                mm.retire_work.work);
        dev = dev_priv->dev;
 
-       mutex_lock(&dev->struct_mutex);
+       /* Come back later if the device is busy... */
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+               return;
+       }
+
        i915_gem_retire_requests(dev);
 
        if (!dev_priv->mm.suspended &&
                (!list_empty(&dev_priv->render_ring.request_list) ||
-                       (HAS_BSD(dev) &&
-                        !list_empty(&dev_priv->bsd_ring.request_list))))
+                !list_empty(&dev_priv->bsd_ring.request_list) ||
+                !list_empty(&dev_priv->blt_ring.request_list)))
                queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
        mutex_unlock(&dev->struct_mutex);
 }
 
 int
 i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
-               int interruptible, struct intel_ring_buffer *ring)
+                    bool interruptible, struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 ier;
@@ -1831,9 +1962,16 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
        BUG_ON(seqno == 0);
 
        if (atomic_read(&dev_priv->mm.wedged))
-               return -EIO;
+               return -EAGAIN;
+
+       if (ring->outstanding_lazy_request) {
+               seqno = i915_add_request(dev, NULL, NULL, ring);
+               if (seqno == 0)
+                       return -ENOMEM;
+       }
+       BUG_ON(seqno == dev_priv->next_seqno);
 
-       if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
+       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
                if (HAS_PCH_SPLIT(dev))
                        ier = I915_READ(DEIER) | I915_READ(GTIER);
                else
@@ -1852,12 +1990,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
                if (interruptible)
                        ret = wait_event_interruptible(ring->irq_queue,
                                i915_seqno_passed(
-                                       ring->get_gem_seqno(dev, ring), seqno)
+                                       ring->get_seqno(dev, ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
                else
                        wait_event(ring->irq_queue,
                                i915_seqno_passed(
-                                       ring->get_gem_seqno(dev, ring), seqno)
+                                       ring->get_seqno(dev, ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
 
                ring->user_irq_put(dev, ring);
@@ -1866,11 +2004,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
                trace_i915_gem_request_wait_end(dev, seqno);
        }
        if (atomic_read(&dev_priv->mm.wedged))
-               ret = -EIO;
+               ret = -EAGAIN;
 
        if (ret && ret != -ERESTARTSYS)
-               DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
-                         __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
+               DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
+                         __func__, ret, seqno, ring->get_seqno(dev, ring),
+                         dev_priv->next_seqno);
 
        /* Directly dispatch request retiring.  While we have the work queue
         * to handle this, the waiter on a request often wants an associated
@@ -1889,27 +2028,48 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
  */
 static int
 i915_wait_request(struct drm_device *dev, uint32_t seqno,
-               struct intel_ring_buffer *ring)
+                 struct intel_ring_buffer *ring)
 {
        return i915_do_wait_request(dev, seqno, 1, ring);
 }
 
+static void
+i915_gem_flush_ring(struct drm_device *dev,
+                   struct drm_file *file_priv,
+                   struct intel_ring_buffer *ring,
+                   uint32_t invalidate_domains,
+                   uint32_t flush_domains)
+{
+       ring->flush(dev, ring, invalidate_domains, flush_domains);
+       i915_gem_process_flushing_list(dev, flush_domains, ring);
+}
+
 static void
 i915_gem_flush(struct drm_device *dev,
+              struct drm_file *file_priv,
               uint32_t invalidate_domains,
-              uint32_t flush_domains)
+              uint32_t flush_domains,
+              uint32_t flush_rings)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+
        if (flush_domains & I915_GEM_DOMAIN_CPU)
                drm_agp_chipset_flush(dev);
-       dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
-                       invalidate_domains,
-                       flush_domains);
-
-       if (HAS_BSD(dev))
-               dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
-                               invalidate_domains,
-                               flush_domains);
+
+       if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+               if (flush_rings & RING_RENDER)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           &dev_priv->render_ring,
+                                           invalidate_domains, flush_domains);
+               if (flush_rings & RING_BSD)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           &dev_priv->bsd_ring,
+                                           invalidate_domains, flush_domains);
+               if (flush_rings & RING_BLT)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           &dev_priv->blt_ring,
+                                           invalidate_domains, flush_domains);
+       }
 }
 
 /**
@@ -1917,7 +2077,8 @@ i915_gem_flush(struct drm_device *dev,
  * safe to unbind from the GTT or access from the CPU.
  */
 static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+                              bool interruptible)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1932,13 +2093,11 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
         * it.
         */
        if (obj_priv->active) {
-#if WATCH_BUF
-               DRM_INFO("%s: object %p wait for seqno %08x\n",
-                         __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-               ret = i915_wait_request(dev,
-                               obj_priv->last_rendering_seqno, obj_priv->ring);
-               if (ret != 0)
+               ret = i915_do_wait_request(dev,
+                                          obj_priv->last_rendering_seqno,
+                                          interruptible,
+                                          obj_priv->ring);
+               if (ret)
                        return ret;
        }
 
@@ -1952,14 +2111,10 @@ int
 i915_gem_object_unbind(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret = 0;
 
-#if WATCH_BUF
-       DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
-       DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
-#endif
        if (obj_priv->gtt_space == NULL)
                return 0;
 
@@ -1984,33 +2139,27 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
         * should be safe and we need to cleanup or else we might
         * cause memory corruption through use-after-free.
         */
+       if (ret) {
+               i915_gem_clflush_object(obj);
+               obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+       }
 
        /* release the fence reg _after_ flushing */
        if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
                i915_gem_clear_fence_reg(obj);
 
-       if (obj_priv->agp_mem != NULL) {
-               drm_unbind_agp(obj_priv->agp_mem);
-               drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
-               obj_priv->agp_mem = NULL;
-       }
+       drm_unbind_agp(obj_priv->agp_mem);
+       drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
 
        i915_gem_object_put_pages(obj);
        BUG_ON(obj_priv->pages_refcount);
 
-       if (obj_priv->gtt_space) {
-               atomic_dec(&dev->gtt_count);
-               atomic_sub(obj->size, &dev->gtt_memory);
-
-               drm_mm_put_block(obj_priv->gtt_space);
-               obj_priv->gtt_space = NULL;
-       }
+       i915_gem_info_remove_gtt(dev_priv, obj->size);
+       list_del_init(&obj_priv->mm_list);
 
-       /* Remove ourselves from the LRU list if present. */
-       spin_lock(&dev_priv->mm.active_list_lock);
-       if (!list_empty(&obj_priv->list))
-               list_del_init(&obj_priv->list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       drm_mm_put_block(obj_priv->gtt_space);
+       obj_priv->gtt_space = NULL;
+       obj_priv->gtt_offset = 0;
 
        if (i915_gem_object_is_purgeable(obj_priv))
                i915_gem_object_truncate(obj);
@@ -2020,48 +2169,50 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        return ret;
 }
 
+static int i915_ring_idle(struct drm_device *dev,
+                         struct intel_ring_buffer *ring)
+{
+       if (list_empty(&ring->gpu_write_list))
+               return 0;
+
+       i915_gem_flush_ring(dev, NULL, ring,
+                           I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       return i915_wait_request(dev,
+                                i915_gem_next_request_seqno(dev, ring),
+                                ring);
+}
+
 int
 i915_gpu_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        bool lists_empty;
-       uint32_t seqno1, seqno2;
        int ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
-                      (!HAS_BSD(dev) ||
-                       list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
+                      list_empty(&dev_priv->bsd_ring.active_list) &&
+                      list_empty(&dev_priv->blt_ring.active_list));
        if (lists_empty)
                return 0;
 
        /* Flush everything onto the inactive list. */
-       i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
-       seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-                       &dev_priv->render_ring);
-       if (seqno1 == 0)
-               return -ENOMEM;
-       ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
-
-       if (HAS_BSD(dev)) {
-               seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-                               &dev_priv->bsd_ring);
-               if (seqno2 == 0)
-                       return -ENOMEM;
+       ret = i915_ring_idle(dev, &dev_priv->render_ring);
+       if (ret)
+               return ret;
 
-               ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
-               if (ret)
-                       return ret;
-       }
+       ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
+       if (ret)
+               return ret;
 
+       ret = i915_ring_idle(dev, &dev_priv->blt_ring);
+       if (ret)
+               return ret;
 
-       return ret;
+       return 0;
 }
 
-int
+static int
 i915_gem_object_get_pages(struct drm_gem_object *obj,
                          gfp_t gfpmask)
 {
@@ -2241,7 +2392,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
        I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
 }
 
-static int i915_find_fence_reg(struct drm_device *dev)
+static int i915_find_fence_reg(struct drm_device *dev,
+                              bool interruptible)
 {
        struct drm_i915_fence_reg *reg = NULL;
        struct drm_i915_gem_object *obj_priv = NULL;
@@ -2286,7 +2438,7 @@ static int i915_find_fence_reg(struct drm_device *dev)
         * private reference to obj like the other callers of put_fence_reg
         * (set_tiling ioctl) do. */
        drm_gem_object_reference(obj);
-       ret = i915_gem_object_put_fence_reg(obj);
+       ret = i915_gem_object_put_fence_reg(obj, interruptible);
        drm_gem_object_unreference(obj);
        if (ret != 0)
                return ret;
@@ -2308,7 +2460,8 @@ static int i915_find_fence_reg(struct drm_device *dev)
  * and tiling format.
  */
 int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+                             bool interruptible)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2343,7 +2496,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
                break;
        }
 
-       ret = i915_find_fence_reg(dev);
+       ret = i915_find_fence_reg(dev, interruptible);
        if (ret < 0)
                return ret;
 
@@ -2421,15 +2574,19 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
  * i915_gem_object_put_fence_reg - waits on outstanding fenced access
  * to the buffer to finish, and then resets the fence register.
  * @obj: tiled object holding a fence register.
+ * @bool: whether the wait upon the fence is interruptible
  *
  * Zeroes out the fence register itself and clears out the associated
  * data structures in dev_priv and obj_priv.
  */
 int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+                             bool interruptible)
 {
        struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       struct drm_i915_fence_reg *reg;
 
        if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
                return 0;
@@ -2444,20 +2601,23 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
         * therefore we must wait for any outstanding access to complete
         * before clearing the fence.
         */
-       if (!IS_I965G(dev)) {
+       reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+       if (reg->gpu) {
                int ret;
 
-               ret = i915_gem_object_flush_gpu_write_domain(obj);
-               if (ret != 0)
+               ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+               if (ret)
                        return ret;
 
-               ret = i915_gem_object_wait_rendering(obj);
-               if (ret != 0)
+               ret = i915_gem_object_wait_rendering(obj, interruptible);
+               if (ret)
                        return ret;
+
+               reg->gpu = false;
        }
 
        i915_gem_object_flush_gtt_write_domain(obj);
-       i915_gem_clear_fence_reg (obj);
+       i915_gem_clear_fence_reg(obj);
 
        return 0;
 }
@@ -2490,7 +2650,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
-       if (obj->size > dev->gtt_total) {
+       if (obj->size > dev_priv->mm.gtt_total) {
                DRM_ERROR("Attempting to bind an object larger than the aperture\n");
                return -E2BIG;
        }
@@ -2498,19 +2658,13 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
  search_free:
        free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
                                        obj->size, alignment, 0);
-       if (free_space != NULL) {
+       if (free_space != NULL)
                obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
                                                       alignment);
-               if (obj_priv->gtt_space != NULL)
-                       obj_priv->gtt_offset = obj_priv->gtt_space->start;
-       }
        if (obj_priv->gtt_space == NULL) {
                /* If the gtt is empty and we're still having trouble
                 * fitting our object in, we're out of memory.
                 */
-#if WATCH_LRU
-               DRM_INFO("%s: GTT full, evicting something\n", __func__);
-#endif
                ret = i915_gem_evict_something(dev, obj->size, alignment);
                if (ret)
                        return ret;
@@ -2518,10 +2672,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                goto search_free;
        }
 
-#if WATCH_BUF
-       DRM_INFO("Binding object of size %zd at 0x%08x\n",
-                obj->size, obj_priv->gtt_offset);
-#endif
        ret = i915_gem_object_get_pages(obj, gfpmask);
        if (ret) {
                drm_mm_put_block(obj_priv->gtt_space);
@@ -2553,7 +2703,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        obj_priv->agp_mem = drm_agp_bind_pages(dev,
                                               obj_priv->pages,
                                               obj->size >> PAGE_SHIFT,
-                                              obj_priv->gtt_offset,
+                                              obj_priv->gtt_space->start,
                                               obj_priv->agp_type);
        if (obj_priv->agp_mem == NULL) {
                i915_gem_object_put_pages(obj);
@@ -2566,11 +2716,10 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
 
                goto search_free;
        }
-       atomic_inc(&dev->gtt_count);
-       atomic_add(obj->size, &dev->gtt_memory);
 
        /* keep track of bounds object by adding it to the inactive list */
-       list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+       list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+       i915_gem_info_add_gtt(dev_priv, obj->size);
 
        /* Assert that the object is not currently in any GPU domain. As it
         * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2579,6 +2728,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
        BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
+       obj_priv->gtt_offset = obj_priv->gtt_space->start;
        trace_i915_gem_object_bind(obj, obj_priv->gtt_offset);
 
        return 0;
@@ -2603,25 +2753,30 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
 
 /** Flushes any GPU write domain for the object if it's dirty. */
 static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+                                      bool pipelined)
 {
        struct drm_device *dev = obj->dev;
        uint32_t old_write_domain;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
        if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
 
        /* Queue the GPU write cache flushing we need. */
        old_write_domain = obj->write_domain;
-       i915_gem_flush(dev, 0, obj->write_domain);
-       if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
-               return -ENOMEM;
+       i915_gem_flush_ring(dev, NULL,
+                           to_intel_bo(obj)->ring,
+                           0, obj->write_domain);
+       BUG_ON(obj->write_domain);
 
        trace_i915_gem_object_change_domain(obj,
                                            obj->read_domains,
                                            old_write_domain);
-       return 0;
+
+       if (pipelined)
+               return 0;
+
+       return i915_gem_object_wait_rendering(obj, true);
 }
 
 /** Flushes the GTT write domain for the object if it's dirty. */
@@ -2665,26 +2820,6 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
                                            old_write_domain);
 }
 
-int
-i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
-{
-       int ret = 0;
-
-       switch (obj->write_domain) {
-       case I915_GEM_DOMAIN_GTT:
-               i915_gem_object_flush_gtt_write_domain(obj);
-               break;
-       case I915_GEM_DOMAIN_CPU:
-               i915_gem_object_flush_cpu_write_domain(obj);
-               break;
-       default:
-               ret = i915_gem_object_flush_gpu_write_domain(obj);
-               break;
-       }
-
-       return ret;
-}
-
 /**
  * Moves a single object to the GTT read, and possibly write domain.
  *
@@ -2702,32 +2837,28 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
        if (obj_priv->gtt_space == NULL)
                return -EINVAL;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
 
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
-       if (ret != 0)
-               return ret;
+       i915_gem_object_flush_cpu_write_domain(obj);
+
+       if (write) {
+               ret = i915_gem_object_wait_rendering(obj, true);
+               if (ret)
+                       return ret;
+       }
 
        old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
 
-       /* If we're writing through the GTT domain, then CPU and GPU caches
-        * will need to be invalidated at next use.
-        */
-       if (write)
-               obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
-       i915_gem_object_flush_cpu_write_domain(obj);
-
        /* It should now be out of any other write domains, and we can update
         * the domain values for our changes.
         */
        BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
        obj->read_domains |= I915_GEM_DOMAIN_GTT;
        if (write) {
+               obj->read_domains = I915_GEM_DOMAIN_GTT;
                obj->write_domain = I915_GEM_DOMAIN_GTT;
                obj_priv->dirty = 1;
        }
@@ -2744,51 +2875,36 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
  * wait, as in modesetting process we're not supposed to be interrupted.
  */
 int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+                                    bool pipelined)
 {
-       struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       uint32_t old_write_domain, old_read_domains;
+       uint32_t old_read_domains;
        int ret;
 
        /* Not valid to be called on unbound objects. */
        if (obj_priv->gtt_space == NULL)
                return -EINVAL;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, true);
        if (ret)
                return ret;
 
-       /* Wait on any GPU rendering and flushing to occur. */
-       if (obj_priv->active) {
-#if WATCH_BUF
-               DRM_INFO("%s: object %p wait for seqno %08x\n",
-                         __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-               ret = i915_do_wait_request(dev,
-                               obj_priv->last_rendering_seqno,
-                               0,
-                               obj_priv->ring);
-               if (ret != 0)
+       /* Currently, we are always called from an non-interruptible context. */
+       if (!pipelined) {
+               ret = i915_gem_object_wait_rendering(obj, false);
+               if (ret)
                        return ret;
        }
 
        i915_gem_object_flush_cpu_write_domain(obj);
 
-       old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
-
-       /* It should now be out of any other write domains, and we can update
-        * the domain values for our changes.
-        */
-       BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-       obj->read_domains = I915_GEM_DOMAIN_GTT;
-       obj->write_domain = I915_GEM_DOMAIN_GTT;
-       obj_priv->dirty = 1;
+       obj->read_domains |= I915_GEM_DOMAIN_GTT;
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
-                                           old_write_domain);
+                                           obj->write_domain);
 
        return 0;
 }
@@ -2805,12 +2921,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
-       if (ret)
-               return ret;
-
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
 
@@ -2821,6 +2932,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
         */
        i915_gem_object_set_to_full_cpu_read_domain(obj);
 
+       if (write) {
+               ret = i915_gem_object_wait_rendering(obj, true);
+               if (ret)
+                       return ret;
+       }
+
        old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
 
@@ -2840,7 +2957,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
         * need to be invalidated at next use.
         */
        if (write) {
-               obj->read_domains &= I915_GEM_DOMAIN_CPU;
+               obj->read_domains = I915_GEM_DOMAIN_CPU;
                obj->write_domain = I915_GEM_DOMAIN_CPU;
        }
 
@@ -2963,26 +3080,18 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
  *             drm_agp_chipset_flush
  */
 static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
+i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
+                                 struct intel_ring_buffer *ring)
 {
        struct drm_device               *dev = obj->dev;
-       drm_i915_private_t              *dev_priv = dev->dev_private;
+       struct drm_i915_private         *dev_priv = dev->dev_private;
        struct drm_i915_gem_object      *obj_priv = to_intel_bo(obj);
        uint32_t                        invalidate_domains = 0;
        uint32_t                        flush_domains = 0;
        uint32_t                        old_read_domains;
 
-       BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
-       BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
-
        intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-       DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
-                __func__, obj,
-                obj->read_domains, obj->pending_read_domains,
-                obj->write_domain, obj->pending_write_domain);
-#endif
        /*
         * If the object isn't moving to a new write domain,
         * let the object stay in multiple read domains
@@ -3009,13 +3118,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
         * stale data. That is, any new read domains.
         */
        invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
-       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
-#if WATCH_BUF
-               DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
-                        __func__, flush_domains, invalidate_domains);
-#endif
+       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
                i915_gem_clflush_object(obj);
-       }
 
        old_read_domains = obj->read_domains;
 
@@ -3029,21 +3133,12 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
                obj->pending_write_domain = obj->write_domain;
        obj->read_domains = obj->pending_read_domains;
 
-       if (flush_domains & I915_GEM_GPU_DOMAINS) {
-               if (obj_priv->ring == &dev_priv->render_ring)
-                       dev_priv->flush_rings |= FLUSH_RENDER_RING;
-               else if (obj_priv->ring == &dev_priv->bsd_ring)
-                       dev_priv->flush_rings |= FLUSH_BSD_RING;
-       }
-
        dev->invalidate_domains |= invalidate_domains;
        dev->flush_domains |= flush_domains;
-#if WATCH_BUF
-       DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
-                __func__,
-                obj->read_domains, obj->write_domain,
-                dev->invalidate_domains, dev->flush_domains);
-#endif
+       if (flush_domains & I915_GEM_GPU_DOMAINS)
+               dev_priv->mm.flush_rings |= obj_priv->ring->id;
+       if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+               dev_priv->mm.flush_rings |= ring->id;
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -3106,12 +3201,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
        if (offset == 0 && size == obj->size)
                return i915_gem_object_set_to_cpu_domain(obj, 0);
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
-       if (ret)
-               return ret;
-
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
        i915_gem_object_flush_gtt_write_domain(obj);
@@ -3164,66 +3254,42 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
  * Pin an object to the GTT and evaluate the relocations landing in it.
  */
 static int
-i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
-                                struct drm_file *file_priv,
-                                struct drm_i915_gem_exec_object2 *entry,
-                                struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_execbuffer_relocate(struct drm_i915_gem_object *obj,
+                            struct drm_file *file_priv,
+                            struct drm_i915_gem_exec_object2 *entry)
 {
-       struct drm_device *dev = obj->dev;
+       struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       int i, ret;
-       void __iomem *reloc_page;
-       bool need_fence;
-
-       need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-                    obj_priv->tiling_mode != I915_TILING_NONE;
-
-       /* Check fence reg constraints and rebind if necessary */
-       if (need_fence &&
-           !i915_gem_object_fence_offset_ok(obj,
-                                            obj_priv->tiling_mode)) {
-               ret = i915_gem_object_unbind(obj);
-               if (ret)
-                       return ret;
-       }
+       struct drm_i915_gem_relocation_entry __user *user_relocs;
+       struct drm_gem_object *target_obj = NULL;
+       uint32_t target_handle = 0;
+       int i, ret = 0;
 
-       /* Choose the GTT offset for our buffer and put it there. */
-       ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
-       if (ret)
-               return ret;
+       user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+       for (i = 0; i < entry->relocation_count; i++) {
+               struct drm_i915_gem_relocation_entry reloc;
+               uint32_t target_offset;
 
-       /*
-        * Pre-965 chips need a fence register set up in order to
-        * properly handle blits to/from tiled surfaces.
-        */
-       if (need_fence) {
-               ret = i915_gem_object_get_fence_reg(obj);
-               if (ret != 0) {
-                       i915_gem_object_unpin(obj);
-                       return ret;
+               if (__copy_from_user_inatomic(&reloc,
+                                             user_relocs+i,
+                                             sizeof(reloc))) {
+                       ret = -EFAULT;
+                       break;
                }
-       }
 
-       entry->offset = obj_priv->gtt_offset;
+               if (reloc.target_handle != target_handle) {
+                       drm_gem_object_unreference(target_obj);
 
-       /* Apply the relocations, using the GTT aperture to avoid cache
-        * flushing requirements.
-        */
-       for (i = 0; i < entry->relocation_count; i++) {
-               struct drm_i915_gem_relocation_entry *reloc= &relocs[i];
-               struct drm_gem_object *target_obj;
-               struct drm_i915_gem_object *target_obj_priv;
-               uint32_t reloc_val, reloc_offset;
-               uint32_t __iomem *reloc_entry;
-
-               target_obj = drm_gem_object_lookup(obj->dev, file_priv,
-                                                  reloc->target_handle);
-               if (target_obj == NULL) {
-                       i915_gem_object_unpin(obj);
-                       return -ENOENT;
+                       target_obj = drm_gem_object_lookup(dev, file_priv,
+                                                          reloc.target_handle);
+                       if (target_obj == NULL) {
+                               ret = -ENOENT;
+                               break;
+                       }
+
+                       target_handle = reloc.target_handle;
                }
-               target_obj_priv = to_intel_bo(target_obj);
+               target_offset = to_intel_bo(target_obj)->gtt_offset;
 
 #if WATCH_RELOC
                DRM_INFO("%s: obj %p offset %08x target %d "
@@ -3231,268 +3297,266 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                         "presumed %08x delta %08x\n",
                         __func__,
                         obj,
-                        (int) reloc->offset,
-                        (int) reloc->target_handle,
-                        (int) reloc->read_domains,
-                        (int) reloc->write_domain,
-                        (int) target_obj_priv->gtt_offset,
-                        (int) reloc->presumed_offset,
-                        reloc->delta);
+                        (int) reloc.offset,
+                        (int) reloc.target_handle,
+                        (int) reloc.read_domains,
+                        (int) reloc.write_domain,
+                        (int) target_offset,
+                        (int) reloc.presumed_offset,
+                        reloc.delta);
 #endif
 
                /* The target buffer should have appeared before us in the
                 * exec_object list, so it should have a GTT space bound by now.
                 */
-               if (target_obj_priv->gtt_space == NULL) {
+               if (target_offset == 0) {
                        DRM_ERROR("No GTT space found for object %d\n",
-                                 reloc->target_handle);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 reloc.target_handle);
+                       ret = -EINVAL;
+                       break;
                }
 
                /* Validate that the target is in a valid r/w GPU domain */
-               if (reloc->write_domain & (reloc->write_domain - 1)) {
+               if (reloc.write_domain & (reloc.write_domain - 1)) {
                        DRM_ERROR("reloc with multiple write domains: "
                                  "obj %p target %d offset %d "
                                  "read %08x write %08x",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->offset,
-                                 reloc->read_domains,
-                                 reloc->write_domain);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset,
+                                 reloc.read_domains,
+                                 reloc.write_domain);
+                       ret = -EINVAL;
+                       break;
                }
-               if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
-                   reloc->read_domains & I915_GEM_DOMAIN_CPU) {
+               if (reloc.write_domain & I915_GEM_DOMAIN_CPU ||
+                   reloc.read_domains & I915_GEM_DOMAIN_CPU) {
                        DRM_ERROR("reloc with read/write CPU domains: "
                                  "obj %p target %d offset %d "
                                  "read %08x write %08x",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->offset,
-                                 reloc->read_domains,
-                                 reloc->write_domain);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset,
+                                 reloc.read_domains,
+                                 reloc.write_domain);
+                       ret = -EINVAL;
+                       break;
                }
-               if (reloc->write_domain && target_obj->pending_write_domain &&
-                   reloc->write_domain != target_obj->pending_write_domain) {
+               if (reloc.write_domain && target_obj->pending_write_domain &&
+                   reloc.write_domain != target_obj->pending_write_domain) {
                        DRM_ERROR("Write domain conflict: "
                                  "obj %p target %d offset %d "
                                  "new %08x old %08x\n",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->offset,
-                                 reloc->write_domain,
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset,
+                                 reloc.write_domain,
                                  target_obj->pending_write_domain);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       break;
                }
 
-               target_obj->pending_read_domains |= reloc->read_domains;
-               target_obj->pending_write_domain |= reloc->write_domain;
+               target_obj->pending_read_domains |= reloc.read_domains;
+               target_obj->pending_write_domain |= reloc.write_domain;
 
                /* If the relocation already has the right value in it, no
                 * more work needs to be done.
                 */
-               if (target_obj_priv->gtt_offset == reloc->presumed_offset) {
-                       drm_gem_object_unreference(target_obj);
+               if (target_offset == reloc.presumed_offset)
                        continue;
-               }
 
                /* Check that the relocation address is valid... */
-               if (reloc->offset > obj->size - 4) {
+               if (reloc.offset > obj->base.size - 4) {
                        DRM_ERROR("Relocation beyond object bounds: "
                                  "obj %p target %d offset %d size %d.\n",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->offset, (int) obj->size);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset, (int) obj->base.size);
+                       ret = -EINVAL;
+                       break;
                }
-               if (reloc->offset & 3) {
+               if (reloc.offset & 3) {
                        DRM_ERROR("Relocation not 4-byte aligned: "
                                  "obj %p target %d offset %d.\n",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->offset);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset);
+                       ret = -EINVAL;
+                       break;
                }
 
                /* and points to somewhere within the target object. */
-               if (reloc->delta >= target_obj->size) {
+               if (reloc.delta >= target_obj->size) {
                        DRM_ERROR("Relocation beyond target object bounds: "
                                  "obj %p target %d delta %d size %d.\n",
-                                 obj, reloc->target_handle,
-                                 (int) reloc->delta, (int) target_obj->size);
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
-               }
-
-               ret = i915_gem_object_set_to_gtt_domain(obj, 1);
-               if (ret != 0) {
-                       drm_gem_object_unreference(target_obj);
-                       i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                                 obj, reloc.target_handle,
+                                 (int) reloc.delta, (int) target_obj->size);
+                       ret = -EINVAL;
+                       break;
                }
 
-               /* Map the page containing the relocation we're going to
-                * perform.
-                */
-               reloc_offset = obj_priv->gtt_offset + reloc->offset;
-               reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-                                                     (reloc_offset &
-                                                      ~(PAGE_SIZE - 1)),
-                                                     KM_USER0);
-               reloc_entry = (uint32_t __iomem *)(reloc_page +
-                                                  (reloc_offset & (PAGE_SIZE - 1)));
-               reloc_val = target_obj_priv->gtt_offset + reloc->delta;
-
-#if WATCH_BUF
-               DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
-                         obj, (unsigned int) reloc->offset,
-                         readl(reloc_entry), reloc_val);
-#endif
-               writel(reloc_val, reloc_entry);
-               io_mapping_unmap_atomic(reloc_page, KM_USER0);
-
-               /* The updated presumed offset for this entry will be
-                * copied back out to the user.
-                */
-               reloc->presumed_offset = target_obj_priv->gtt_offset;
-
-               drm_gem_object_unreference(target_obj);
-       }
-
-#if WATCH_BUF
-       if (0)
-               i915_gem_dump_object(obj, 128, __func__, ~0);
-#endif
-       return 0;
-}
-
-/* Throttle our rendering by waiting until the ring has completed our requests
- * emitted over 20 msec ago.
- *
- * Note that if we were to use the current jiffies each time around the loop,
- * we wouldn't escape the function with any frames outstanding if the time to
- * render a frame was over 20ms.
- *
- * This should get us reasonable parallelism between CPU and GPU but also
- * relatively low latency when blocking on a particular request to finish.
- */
-static int
-i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
-{
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
-       int ret = 0;
-       unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+               reloc.delta += target_offset;
+               if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+                       uint32_t page_offset = reloc.offset & ~PAGE_MASK;
+                       char *vaddr;
 
-       mutex_lock(&dev->struct_mutex);
-       while (!list_empty(&i915_file_priv->mm.request_list)) {
-               struct drm_i915_gem_request *request;
+                       vaddr = kmap_atomic(obj->pages[reloc.offset >> PAGE_SHIFT]);
+                       *(uint32_t *)(vaddr + page_offset) = reloc.delta;
+                       kunmap_atomic(vaddr);
+               } else {
+                       uint32_t __iomem *reloc_entry;
+                       void __iomem *reloc_page;
 
-               request = list_first_entry(&i915_file_priv->mm.request_list,
-                                          struct drm_i915_gem_request,
-                                          client_list);
+                       ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
+                       if (ret)
+                               break;
 
-               if (time_after_eq(request->emitted_jiffies, recent_enough))
-                       break;
+                       /* Map the page containing the relocation we're going to perform.  */
+                       reloc.offset += obj->gtt_offset;
+                       reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+                                                             reloc.offset & PAGE_MASK);
+                       reloc_entry = (uint32_t __iomem *)
+                               (reloc_page + (reloc.offset & ~PAGE_MASK));
+                       iowrite32(reloc.delta, reloc_entry);
+                       io_mapping_unmap_atomic(reloc_page);
+               }
 
-               ret = i915_wait_request(dev, request->seqno, request->ring);
-               if (ret != 0)
-                       break;
+               /* and update the user's relocation entry */
+               reloc.presumed_offset = target_offset;
+               if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
+                                             &reloc.presumed_offset,
+                                             sizeof(reloc.presumed_offset))) {
+                   ret = -EFAULT;
+                   break;
+               }
        }
-       mutex_unlock(&dev->struct_mutex);
 
+       drm_gem_object_unreference(target_obj);
        return ret;
 }
 
 static int
-i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *exec_list,
-                             uint32_t buffer_count,
-                             struct drm_i915_gem_relocation_entry **relocs)
+i915_gem_execbuffer_pin(struct drm_device *dev,
+                       struct drm_file *file,
+                       struct drm_gem_object **object_list,
+                       struct drm_i915_gem_exec_object2 *exec_list,
+                       int count)
 {
-       uint32_t reloc_count = 0, reloc_index = 0, i;
-       int ret;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret, i, retry;
 
-       *relocs = NULL;
-       for (i = 0; i < buffer_count; i++) {
-               if (reloc_count + exec_list[i].relocation_count < reloc_count)
-                       return -EINVAL;
-               reloc_count += exec_list[i].relocation_count;
-       }
+       /* attempt to pin all of the buffers into the GTT */
+       for (retry = 0; retry < 2; retry++) {
+               ret = 0;
+               for (i = 0; i < count; i++) {
+                       struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
+                       struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]);
+                       bool need_fence =
+                               entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+                               obj->tiling_mode != I915_TILING_NONE;
+
+                       /* Check fence reg constraints and rebind if necessary */
+                       if (need_fence &&
+                           !i915_gem_object_fence_offset_ok(&obj->base,
+                                                            obj->tiling_mode)) {
+                               ret = i915_gem_object_unbind(&obj->base);
+                               if (ret)
+                                       break;
+                       }
 
-       *relocs = drm_calloc_large(reloc_count, sizeof(**relocs));
-       if (*relocs == NULL) {
-               DRM_ERROR("failed to alloc relocs, count %d\n", reloc_count);
-               return -ENOMEM;
-       }
+                       ret = i915_gem_object_pin(&obj->base, entry->alignment);
+                       if (ret)
+                               break;
 
-       for (i = 0; i < buffer_count; i++) {
-               struct drm_i915_gem_relocation_entry __user *user_relocs;
+                       /*
+                        * Pre-965 chips need a fence register set up in order
+                        * to properly handle blits to/from tiled surfaces.
+                        */
+                       if (need_fence) {
+                               ret = i915_gem_object_get_fence_reg(&obj->base, true);
+                               if (ret) {
+                                       i915_gem_object_unpin(&obj->base);
+                                       break;
+                               }
 
-               user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+                               dev_priv->fence_regs[obj->fence_reg].gpu = true;
+                       }
 
-               ret = copy_from_user(&(*relocs)[reloc_index],
-                                    user_relocs,
-                                    exec_list[i].relocation_count *
-                                    sizeof(**relocs));
-               if (ret != 0) {
-                       drm_free_large(*relocs);
-                       *relocs = NULL;
-                       return -EFAULT;
+                       entry->offset = obj->gtt_offset;
                }
 
-               reloc_index += exec_list[i].relocation_count;
+               while (i--)
+                       i915_gem_object_unpin(object_list[i]);
+
+               if (ret == 0)
+                       break;
+
+               if (ret != -ENOSPC || retry)
+                       return ret;
+
+               ret = i915_gem_evict_everything(dev);
+               if (ret)
+                       return ret;
        }
 
        return 0;
 }
 
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * Note that if we were to use the current jiffies each time around the loop,
+ * we wouldn't escape the function with any frames outstanding if the time to
+ * render a frame was over 20ms.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
 static int
-i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list,
-                           uint32_t buffer_count,
-                           struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
 {
-       uint32_t reloc_count = 0, i;
-       int ret = 0;
-
-       if (relocs == NULL)
-           return 0;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
+       unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+       struct drm_i915_gem_request *request;
+       struct intel_ring_buffer *ring = NULL;
+       u32 seqno = 0;
+       int ret;
 
-       for (i = 0; i < buffer_count; i++) {
-               struct drm_i915_gem_relocation_entry __user *user_relocs;
-               int unwritten;
+       spin_lock(&file_priv->mm.lock);
+       list_for_each_entry(request, &file_priv->mm.request_list, client_list) {
+               if (time_after_eq(request->emitted_jiffies, recent_enough))
+                       break;
 
-               user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+               ring = request->ring;
+               seqno = request->seqno;
+       }
+       spin_unlock(&file_priv->mm.lock);
 
-               unwritten = copy_to_user(user_relocs,
-                                        &relocs[reloc_count],
-                                        exec_list[i].relocation_count *
-                                        sizeof(*relocs));
+       if (seqno == 0)
+               return 0;
 
-               if (unwritten) {
-                       ret = -EFAULT;
-                       goto err;
-               }
+       ret = 0;
+       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+               /* And wait for the seqno passing without holding any locks and
+                * causing extra latency for others. This is safe as the irq
+                * generation is designed to be run atomically and so is
+                * lockless.
+                */
+               ring->user_irq_get(dev, ring);
+               ret = wait_event_interruptible(ring->irq_queue,
+                                              i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+                                              || atomic_read(&dev_priv->mm.wedged));
+               ring->user_irq_put(dev, ring);
 
-               reloc_count += exec_list[i].relocation_count;
+               if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+                       ret = -EIO;
        }
 
-err:
-       drm_free_large(relocs);
+       if (ret == 0)
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
        return ret;
 }
 
 static int
-i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
-                          uint64_t exec_offset)
+i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec,
+                         uint64_t exec_offset)
 {
        uint32_t exec_start, exec_len;
 
@@ -3509,44 +3573,32 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
 }
 
 static int
-i915_gem_wait_for_pending_flip(struct drm_device *dev,
-                              struct drm_gem_object **object_list,
-                              int count)
+validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+                  int count)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj_priv;
-       DEFINE_WAIT(wait);
-       int i, ret = 0;
+       int i;
 
-       for (;;) {
-               prepare_to_wait(&dev_priv->pending_flip_queue,
-                               &wait, TASK_INTERRUPTIBLE);
-               for (i = 0; i < count; i++) {
-                       obj_priv = to_intel_bo(object_list[i]);
-                       if (atomic_read(&obj_priv->pending_flip) > 0)
-                               break;
-               }
-               if (i == count)
-                       break;
+       for (i = 0; i < count; i++) {
+               char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+               size_t length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry);
 
-               if (!signal_pending(current)) {
-                       mutex_unlock(&dev->struct_mutex);
-                       schedule();
-                       mutex_lock(&dev->struct_mutex);
-                       continue;
-               }
-               ret = -ERESTARTSYS;
-               break;
+               if (!access_ok(VERIFY_READ, ptr, length))
+                       return -EFAULT;
+
+               /* we may also need to update the presumed offsets */
+               if (!access_ok(VERIFY_WRITE, ptr, length))
+                       return -EFAULT;
+
+               if (fault_in_pages_readable(ptr, length))
+                       return -EFAULT;
        }
-       finish_wait(&dev_priv->pending_flip_queue, &wait);
 
-       return ret;
+       return 0;
 }
 
-
-int
+static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv,
+                      struct drm_file *file,
                       struct drm_i915_gem_execbuffer2 *args,
                       struct drm_i915_gem_exec_object2 *exec_list)
 {
@@ -3555,26 +3607,47 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        struct drm_gem_object *batch_obj;
        struct drm_i915_gem_object *obj_priv;
        struct drm_clip_rect *cliprects = NULL;
-       struct drm_i915_gem_relocation_entry *relocs = NULL;
-       int ret = 0, ret2, i, pinned = 0;
+       struct drm_i915_gem_request *request = NULL;
+       int ret, i, flips;
        uint64_t exec_offset;
-       uint32_t seqno, flush_domains, reloc_index;
-       int pin_tries, flips;
 
        struct intel_ring_buffer *ring = NULL;
 
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
+
+       ret = validate_exec_list(exec_list, args->buffer_count);
+       if (ret)
+               return ret;
+
 #if WATCH_EXEC
        DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
                  (int) args->buffers_ptr, args->buffer_count, args->batch_len);
 #endif
-       if (args->flags & I915_EXEC_BSD) {
+       switch (args->flags & I915_EXEC_RING_MASK) {
+       case I915_EXEC_DEFAULT:
+       case I915_EXEC_RENDER:
+               ring = &dev_priv->render_ring;
+               break;
+       case I915_EXEC_BSD:
                if (!HAS_BSD(dev)) {
-                       DRM_ERROR("execbuf with wrong flag\n");
+                       DRM_ERROR("execbuf with invalid ring (BSD)\n");
                        return -EINVAL;
                }
                ring = &dev_priv->bsd_ring;
-       } else {
-               ring = &dev_priv->render_ring;
+               break;
+       case I915_EXEC_BLT:
+               if (!HAS_BLT(dev)) {
+                       DRM_ERROR("execbuf with invalid ring (BLT)\n");
+                       return -EINVAL;
+               }
+               ring = &dev_priv->blt_ring;
+               break;
+       default:
+               DRM_ERROR("execbuf with unknown ring: %d\n",
+                         (int)(args->flags & I915_EXEC_RING_MASK));
+               return -EINVAL;
        }
 
        if (args->buffer_count < 1) {
@@ -3609,20 +3682,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                }
        }
 
-       ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
-                                           &relocs);
-       if (ret != 0)
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL) {
+               ret = -ENOMEM;
                goto pre_mutex_err;
+       }
 
-       mutex_lock(&dev->struct_mutex);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
-       if (atomic_read(&dev_priv->mm.wedged)) {
-               mutex_unlock(&dev->struct_mutex);
-               ret = -EIO;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
                goto pre_mutex_err;
-       }
 
        if (dev_priv->mm.suspended) {
                mutex_unlock(&dev->struct_mutex);
@@ -3631,9 +3699,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
 
        /* Look up object handles */
-       flips = 0;
        for (i = 0; i < args->buffer_count; i++) {
-               object_list[i] = drm_gem_object_lookup(dev, file_priv,
+               object_list[i] = drm_gem_object_lookup(dev, file,
                                                       exec_list[i].handle);
                if (object_list[i] == NULL) {
                        DRM_ERROR("Invalid object handle %d at index %d\n",
@@ -3654,75 +3721,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        goto err;
                }
                obj_priv->in_execbuffer = true;
-               flips += atomic_read(&obj_priv->pending_flip);
-       }
-
-       if (flips > 0) {
-               ret = i915_gem_wait_for_pending_flip(dev, object_list,
-                                                    args->buffer_count);
-               if (ret)
-                       goto err;
        }
 
-       /* Pin and relocate */
-       for (pin_tries = 0; ; pin_tries++) {
-               ret = 0;
-               reloc_index = 0;
-
-               for (i = 0; i < args->buffer_count; i++) {
-                       object_list[i]->pending_read_domains = 0;
-                       object_list[i]->pending_write_domain = 0;
-                       ret = i915_gem_object_pin_and_relocate(object_list[i],
-                                                              file_priv,
-                                                              &exec_list[i],
-                                                              &relocs[reloc_index]);
-                       if (ret)
-                               break;
-                       pinned = i + 1;
-                       reloc_index += exec_list[i].relocation_count;
-               }
-               /* success */
-               if (ret == 0)
-                       break;
-
-               /* error other than GTT full, or we've already tried again */
-               if (ret != -ENOSPC || pin_tries >= 1) {
-                       if (ret != -ERESTARTSYS) {
-                               unsigned long long total_size = 0;
-                               int num_fences = 0;
-                               for (i = 0; i < args->buffer_count; i++) {
-                                       obj_priv = to_intel_bo(object_list[i]);
-
-                                       total_size += object_list[i]->size;
-                                       num_fences +=
-                                               exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE &&
-                                               obj_priv->tiling_mode != I915_TILING_NONE;
-                               }
-                               DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n",
-                                         pinned+1, args->buffer_count,
-                                         total_size, num_fences,
-                                         ret);
-                               DRM_ERROR("%d objects [%d pinned], "
-                                         "%d object bytes [%d pinned], "
-                                         "%d/%d gtt bytes\n",
-                                         atomic_read(&dev->object_count),
-                                         atomic_read(&dev->pin_count),
-                                         atomic_read(&dev->object_memory),
-                                         atomic_read(&dev->pin_memory),
-                                         atomic_read(&dev->gtt_memory),
-                                         dev->gtt_total);
-                       }
-                       goto err;
-               }
-
-               /* unpin all of our buffers */
-               for (i = 0; i < pinned; i++)
-                       i915_gem_object_unpin(object_list[i]);
-               pinned = 0;
+       /* Move the objects en-masse into the GTT, evicting if necessary. */
+       ret = i915_gem_execbuffer_pin(dev, file,
+                                     object_list, exec_list,
+                                     args->buffer_count);
+       if (ret)
+               goto err;
 
-               /* evict everyone we can from the aperture */
-               ret = i915_gem_evict_everything(dev);
-               if (ret && ret != -ENOSPC)
+       /* The objects are in their final locations, apply the relocations. */
+       for (i = 0; i < args->buffer_count; i++) {
+               struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+               obj->base.pending_read_domains = 0;
+               obj->base.pending_write_domain = 0;
+               ret = i915_gem_execbuffer_relocate(obj, file, &exec_list[i]);
+               if (ret)
                        goto err;
        }
 
@@ -3735,33 +3749,29 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
        batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
 
-       /* Sanity check the batch buffer, prior to moving objects */
-       exec_offset = exec_list[args->buffer_count - 1].offset;
-       ret = i915_gem_check_execbuffer (args, exec_offset);
+       /* Sanity check the batch buffer */
+       exec_offset = to_intel_bo(batch_obj)->gtt_offset;
+       ret = i915_gem_check_execbuffer(args, exec_offset);
        if (ret != 0) {
                DRM_ERROR("execbuf with invalid offset/length\n");
                goto err;
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
        /* Zero the global flush/invalidate flags. These
         * will be modified as new domains are computed
         * for each object
         */
        dev->invalidate_domains = 0;
        dev->flush_domains = 0;
-       dev_priv->flush_rings = 0;
+       dev_priv->mm.flush_rings = 0;
 
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
 
                /* Compute new gpu domains and update invalidate/flush */
-               i915_gem_object_set_to_gpu_domain(obj);
+               i915_gem_object_set_to_gpu_domain(obj, ring);
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
        if (dev->invalidate_domains | dev->flush_domains) {
 #if WATCH_EXEC
                DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
@@ -3769,38 +3779,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                         dev->invalidate_domains,
                         dev->flush_domains);
 #endif
-               i915_gem_flush(dev,
+               i915_gem_flush(dev, file,
                               dev->invalidate_domains,
-                              dev->flush_domains);
-               if (dev_priv->flush_rings & FLUSH_RENDER_RING)
-                       (void)i915_add_request(dev, file_priv,
-                                              dev->flush_domains,
-                                              &dev_priv->render_ring);
-               if (dev_priv->flush_rings & FLUSH_BSD_RING)
-                       (void)i915_add_request(dev, file_priv,
-                                              dev->flush_domains,
-                                              &dev_priv->bsd_ring);
+                              dev->flush_domains,
+                              dev_priv->mm.flush_rings);
        }
 
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
-               struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
                uint32_t old_write_domain = obj->write_domain;
-
                obj->write_domain = obj->pending_write_domain;
-               if (obj->write_domain)
-                       list_move_tail(&obj_priv->gpu_write_list,
-                                      &dev_priv->mm.gpu_write_list);
-               else
-                       list_del_init(&obj_priv->gpu_write_list);
-
                trace_i915_gem_object_change_domain(obj,
                                                    obj->read_domains,
                                                    old_write_domain);
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
 #if WATCH_COHERENCY
        for (i = 0; i < args->buffer_count; i++) {
                i915_gem_object_check_coherency(object_list[i],
@@ -3815,9 +3808,38 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                              ~0);
 #endif
 
+       /* Check for any pending flips. As we only maintain a flip queue depth
+        * of 1, we can simply insert a WAIT for the next display flip prior
+        * to executing the batch and avoid stalling the CPU.
+        */
+       flips = 0;
+       for (i = 0; i < args->buffer_count; i++) {
+               if (object_list[i]->write_domain)
+                       flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
+       }
+       if (flips) {
+               int plane, flip_mask;
+
+               for (plane = 0; flips >> plane; plane++) {
+                       if (((flips >> plane) & 1) == 0)
+                               continue;
+
+                       if (plane)
+                               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+                       else
+                               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+                       intel_ring_begin(dev, ring, 2);
+                       intel_ring_emit(dev, ring,
+                                       MI_WAIT_FOR_EVENT | flip_mask);
+                       intel_ring_emit(dev, ring, MI_NOOP);
+                       intel_ring_advance(dev, ring);
+               }
+       }
+
        /* Exec the batchbuffer */
        ret = ring->dispatch_gem_execbuffer(dev, ring, args,
-                       cliprects, exec_offset);
+                                           cliprects, exec_offset);
        if (ret) {
                DRM_ERROR("dispatch failed %d\n", ret);
                goto err;
@@ -3827,38 +3849,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
         * Ensure that the commands in the batch buffer are
         * finished before the interrupt fires
         */
-       flush_domains = i915_retire_commands(dev, ring);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       i915_retire_commands(dev, ring);
 
-       /*
-        * Get a seqno representing the execution of the current buffer,
-        * which we can wait on.  We would like to mitigate these interrupts,
-        * likely by only creating seqnos occasionally (so that we have
-        * *some* interrupts representing completion of buffers that we can
-        * wait on when trying to clear up gtt space).
-        */
-       seqno = i915_add_request(dev, file_priv, flush_domains, ring);
-       BUG_ON(seqno == 0);
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
-               obj_priv = to_intel_bo(obj);
 
-               i915_gem_object_move_to_active(obj, seqno, ring);
-#if WATCH_LRU
-               DRM_INFO("%s: move to exec list %p\n", __func__, obj);
-#endif
+               i915_gem_object_move_to_active(obj, ring);
+               if (obj->write_domain)
+                       list_move_tail(&to_intel_bo(obj)->gpu_write_list,
+                                      &ring->gpu_write_list);
        }
-#if WATCH_LRU
-       i915_dump_lru(dev, __func__);
-#endif
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       i915_add_request(dev, file, request, ring);
+       request = NULL;
 
 err:
-       for (i = 0; i < pinned; i++)
-               i915_gem_object_unpin(object_list[i]);
-
        for (i = 0; i < args->buffer_count; i++) {
                if (object_list[i]) {
                        obj_priv = to_intel_bo(object_list[i]);
@@ -3870,22 +3875,9 @@ err:
        mutex_unlock(&dev->struct_mutex);
 
 pre_mutex_err:
-       /* Copy the updated relocations out regardless of current error
-        * state.  Failure to update the relocs would mean that the next
-        * time userland calls execbuf, it would do so with presumed offset
-        * state that didn't match the actual object state.
-        */
-       ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count,
-                                          relocs);
-       if (ret2 != 0) {
-               DRM_ERROR("Failed to copy relocations back out: %d\n", ret2);
-
-               if (ret == 0)
-                       ret = ret2;
-       }
-
        drm_free_large(object_list);
        kfree(cliprects);
+       kfree(request);
 
        return ret;
 }
@@ -3942,7 +3934,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
                exec2_list[i].alignment = exec_list[i].alignment;
                exec2_list[i].offset = exec_list[i].offset;
-               if (!IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen < 4)
                        exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
                else
                        exec2_list[i].flags = 0;
@@ -4039,12 +4031,12 @@ int
 i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
 {
        struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
        BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 
        if (obj_priv->gtt_space != NULL) {
                if (alignment == 0)
@@ -4072,14 +4064,13 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
         * remove it from the inactive list
         */
        if (obj_priv->pin_count == 1) {
-               atomic_inc(&dev->pin_count);
-               atomic_add(obj->size, &dev->pin_memory);
-               if (!obj_priv->active &&
-                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-                       list_del_init(&obj_priv->list);
+               i915_gem_info_add_pin(dev_priv, obj->size);
+               if (!obj_priv->active)
+                       list_move_tail(&obj_priv->mm_list,
+                                      &dev_priv->mm.pinned_list);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
 
+       WARN_ON(i915_verify_lists(dev));
        return 0;
 }
 
@@ -4090,7 +4081,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
        obj_priv->pin_count--;
        BUG_ON(obj_priv->pin_count < 0);
        BUG_ON(obj_priv->gtt_space == NULL);
@@ -4100,14 +4091,12 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
         * the inactive list
         */
        if (obj_priv->pin_count == 0) {
-               if (!obj_priv->active &&
-                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-                       list_move_tail(&obj_priv->list,
+               if (!obj_priv->active)
+                       list_move_tail(&obj_priv->mm_list,
                                       &dev_priv->mm.inactive_list);
-               atomic_dec(&dev->pin_count);
-               atomic_sub(obj->size, &dev->pin_memory);
+               i915_gem_info_remove_pin(dev_priv, obj->size);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 }
 
 int
@@ -4119,41 +4108,36 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *obj_priv;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
-               DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
-                         args->handle);
-               mutex_unlock(&dev->struct_mutex);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto unlock;
        }
        obj_priv = to_intel_bo(obj);
 
        if (obj_priv->madv != I915_MADV_WILLNEED) {
                DRM_ERROR("Attempting to pin a purgeable buffer\n");
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        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);
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        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;
-               }
+               if (ret)
+                       goto out;
        }
 
        /* XXX - flush the CPU caches for pinned objects
@@ -4161,10 +4145,11 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
         */
        i915_gem_object_flush_cpu_write_domain(obj);
        args->offset = obj_priv->gtt_offset;
+out:
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
-
-       return 0;
+       return ret;
 }
 
 int
@@ -4174,24 +4159,24 @@ 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;
+       int ret;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
-               DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
-                         args->handle);
-               mutex_unlock(&dev->struct_mutex);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto unlock;
        }
-
        obj_priv = to_intel_bo(obj);
+
        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;
+               ret = -EINVAL;
+               goto out;
        }
        obj_priv->user_pin_count--;
        if (obj_priv->user_pin_count == 0) {
@@ -4199,9 +4184,11 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
                i915_gem_object_unpin(obj);
        }
 
+out:
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
-       return 0;
+       return ret;
 }
 
 int
@@ -4211,22 +4198,24 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_busy *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
+       int ret;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
-               DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
-                         args->handle);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto unlock;
        }
-
-       mutex_lock(&dev->struct_mutex);
+       obj_priv = to_intel_bo(obj);
 
        /* Count all active objects as busy, even if they are currently not used
         * by the gpu. Users of this interface expect objects to eventually
         * become non-busy without any further actions, therefore emit any
         * necessary flushes here.
         */
-       obj_priv = to_intel_bo(obj);
        args->busy = obj_priv->active;
        if (args->busy) {
                /* Unconditionally flush objects, even when the gpu still uses this
@@ -4234,10 +4223,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                 * use this buffer rather sooner than later, so issuing the required
                 * flush earlier is beneficial.
                 */
-               if (obj->write_domain) {
-                       i915_gem_flush(dev, 0, obj->write_domain);
-                       (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
-               }
+               if (obj->write_domain & I915_GEM_GPU_DOMAINS)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           obj_priv->ring,
+                                           0, obj->write_domain);
 
                /* Update the active list for the hardware's current position.
                 * Otherwise this only updates on a delayed timer or when irqs
@@ -4250,8 +4239,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
        }
 
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
-       return 0;
+       return ret;
 }
 
 int
@@ -4268,6 +4258,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_madvise *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
+       int ret;
 
        switch (args->madv) {
        case I915_MADV_DONTNEED:
@@ -4277,22 +4268,20 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
            return -EINVAL;
        }
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
-               DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
-                         args->handle);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto unlock;
        }
-
-       mutex_lock(&dev->struct_mutex);
        obj_priv = to_intel_bo(obj);
 
        if (obj_priv->pin_count) {
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
-
-               DRM_ERROR("Attempted i915_gem_madvise_ioctl() on a pinned object\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        if (obj_priv->madv != __I915_MADV_PURGED)
@@ -4305,15 +4294,17 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 
        args->retained = obj_priv->madv != __I915_MADV_PURGED;
 
+out:
        drm_gem_object_unreference(obj);
+unlock:
        mutex_unlock(&dev->struct_mutex);
-
-       return 0;
+       return ret;
 }
 
 struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
                                              size_t size)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
        obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -4325,18 +4316,19 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
                return NULL;
        }
 
+       i915_gem_info_add_obj(dev_priv, size);
+
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
        obj->agp_type = AGP_USER_MEMORY;
        obj->base.driver_private = NULL;
        obj->fence_reg = I915_FENCE_REG_NONE;
-       INIT_LIST_HEAD(&obj->list);
+       INIT_LIST_HEAD(&obj->mm_list);
+       INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->gpu_write_list);
        obj->madv = I915_MADV_WILLNEED;
 
-       trace_i915_gem_object_create(&obj->base);
-
        return &obj->base;
 }
 
@@ -4356,7 +4348,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
 
        ret = i915_gem_object_unbind(obj);
        if (ret == -ERESTARTSYS) {
-               list_move(&obj_priv->list,
+               list_move(&obj_priv->mm_list,
                          &dev_priv->mm.deferred_free_list);
                return;
        }
@@ -4365,6 +4357,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
                i915_gem_free_mmap_offset(obj);
 
        drm_gem_object_release(obj);
+       i915_gem_info_remove_obj(dev_priv, obj->size);
 
        kfree(obj_priv->page_cpu_valid);
        kfree(obj_priv->bit_17);
@@ -4395,10 +4388,7 @@ i915_gem_idle(struct drm_device *dev)
 
        mutex_lock(&dev->struct_mutex);
 
-       if (dev_priv->mm.suspended ||
-                       (dev_priv->render_ring.gem_object == NULL) ||
-                       (HAS_BSD(dev) &&
-                        dev_priv->bsd_ring.gem_object == NULL)) {
+       if (dev_priv->mm.suspended) {
                mutex_unlock(&dev->struct_mutex);
                return 0;
        }
@@ -4423,7 +4413,7 @@ i915_gem_idle(struct drm_device *dev)
         * And not confound mm.suspended!
         */
        dev_priv->mm.suspended = 1;
-       del_timer(&dev_priv->hangcheck_timer);
+       del_timer_sync(&dev_priv->hangcheck_timer);
 
        i915_kernel_lost_context(dev);
        i915_gem_cleanup_ringbuffer(dev);
@@ -4503,36 +4493,34 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
-       dev_priv->render_ring = render_ring;
-
-       if (!I915_NEED_GFX_HWS(dev)) {
-               dev_priv->render_ring.status_page.page_addr
-                       = dev_priv->status_page_dmah->vaddr;
-               memset(dev_priv->render_ring.status_page.page_addr,
-                               0, PAGE_SIZE);
-       }
-
        if (HAS_PIPE_CONTROL(dev)) {
                ret = i915_gem_init_pipe_control(dev);
                if (ret)
                        return ret;
        }
 
-       ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+       ret = intel_init_render_ring_buffer(dev);
        if (ret)
                goto cleanup_pipe_control;
 
        if (HAS_BSD(dev)) {
-               dev_priv->bsd_ring = bsd_ring;
-               ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+               ret = intel_init_bsd_ring_buffer(dev);
                if (ret)
                        goto cleanup_render_ring;
        }
 
+       if (HAS_BLT(dev)) {
+               ret = intel_init_blt_ring_buffer(dev);
+               if (ret)
+                       goto cleanup_bsd_ring;
+       }
+
        dev_priv->next_seqno = 1;
 
        return 0;
 
+cleanup_bsd_ring:
+       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
 cleanup_render_ring:
        intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
 cleanup_pipe_control:
@@ -4547,8 +4535,8 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-       if (HAS_BSD(dev))
-               intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
        if (HAS_PIPE_CONTROL(dev))
                i915_gem_cleanup_pipe_control(dev);
 }
@@ -4577,15 +4565,15 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
                return ret;
        }
 
-       spin_lock(&dev_priv->mm.active_list_lock);
+       BUG_ON(!list_empty(&dev_priv->mm.active_list));
        BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
-       BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
+       BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list));
+       BUG_ON(!list_empty(&dev_priv->blt_ring.active_list));
        BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
        BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
        BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
-       BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
+       BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list));
+       BUG_ON(!list_empty(&dev_priv->blt_ring.request_list));
        mutex_unlock(&dev->struct_mutex);
 
        ret = drm_irq_install(dev);
@@ -4627,28 +4615,34 @@ i915_gem_lastclose(struct drm_device *dev)
                DRM_ERROR("failed to idle hardware: %d\n", ret);
 }
 
+static void
+init_ring_lists(struct intel_ring_buffer *ring)
+{
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       INIT_LIST_HEAD(&ring->gpu_write_list);
+}
+
 void
 i915_gem_load(struct drm_device *dev)
 {
        int i;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       spin_lock_init(&dev_priv->mm.active_list_lock);
+       INIT_LIST_HEAD(&dev_priv->mm.active_list);
        INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
-       INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
        INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
        INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
-       INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
-       INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
-       if (HAS_BSD(dev)) {
-               INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list);
-               INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list);
-       }
+       init_ring_lists(&dev_priv->render_ring);
+       init_ring_lists(&dev_priv->bsd_ring);
+       init_ring_lists(&dev_priv->blt_ring);
        for (i = 0; i < 16; i++)
                INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
        INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
                          i915_gem_retire_work_handler);
+       init_completion(&dev_priv->error_completion);
        spin_lock(&shrink_list_lock);
        list_add(&dev_priv->mm.shrink_list, &shrink_list);
        spin_unlock(&shrink_list_lock);
@@ -4667,21 +4661,30 @@ i915_gem_load(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                dev_priv->fence_reg_start = 3;
 
-       if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+       if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                dev_priv->num_fence_regs = 16;
        else
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       if (IS_I965G(dev)) {
+       switch (INTEL_INFO(dev)->gen) {
+       case 6:
+               for (i = 0; i < 16; i++)
+                       I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
+               break;
+       case 5:
+       case 4:
                for (i = 0; i < 16; i++)
                        I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-       } else {
-               for (i = 0; i < 8; i++)
-                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               break;
+       case 3:
                if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                        for (i = 0; i < 8; i++)
                                I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+       case 2:
+               for (i = 0; i < 8; i++)
+                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               break;
        }
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4691,8 +4694,8 @@ i915_gem_load(struct drm_device *dev)
  * Create a physically contiguous memory object for this object
  * e.g. for cursor + overlay regs
  */
-int i915_gem_init_phys_object(struct drm_device *dev,
-                             int id, int size, int align)
+static int i915_gem_init_phys_object(struct drm_device *dev,
+                                    int id, int size, int align)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
@@ -4724,7 +4727,7 @@ kfree_obj:
        return ret;
 }
 
-void i915_gem_free_phys_object(struct drm_device *dev, int id)
+static void i915_gem_free_phys_object(struct drm_device *dev, int id)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
@@ -4772,11 +4775,11 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
        page_count = obj->size / PAGE_SIZE;
 
        for (i = 0; i < page_count; i++) {
-               char *dst = kmap_atomic(obj_priv->pages[i], KM_USER0);
+               char *dst = kmap_atomic(obj_priv->pages[i]);
                char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
 
                memcpy(dst, src, PAGE_SIZE);
-               kunmap_atomic(dst, KM_USER0);
+               kunmap_atomic(dst);
        }
        drm_clflush_pages(obj_priv->pages, page_count);
        drm_agp_chipset_flush(dev);
@@ -4833,11 +4836,11 @@ i915_gem_attach_phys_object(struct drm_device *dev,
        page_count = obj->size / PAGE_SIZE;
 
        for (i = 0; i < page_count; i++) {
-               char *src = kmap_atomic(obj_priv->pages[i], KM_USER0);
+               char *src = kmap_atomic(obj_priv->pages[i]);
                char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
 
                memcpy(dst, src, PAGE_SIZE);
-               kunmap_atomic(src, KM_USER0);
+               kunmap_atomic(src);
        }
 
        i915_gem_object_put_pages(obj);
@@ -4869,18 +4872,25 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
        return 0;
 }
 
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
 
        /* Clean up our request list when the client is going away, so that
         * later retire_requests won't dereference our soon-to-be-gone
         * file_priv.
         */
-       mutex_lock(&dev->struct_mutex);
-       while (!list_empty(&i915_file_priv->mm.request_list))
-               list_del_init(i915_file_priv->mm.request_list.next);
-       mutex_unlock(&dev->struct_mutex);
+       spin_lock(&file_priv->mm.lock);
+       while (!list_empty(&file_priv->mm.request_list)) {
+               struct drm_i915_gem_request *request;
+
+               request = list_first_entry(&file_priv->mm.request_list,
+                                          struct drm_i915_gem_request,
+                                          client_list);
+               list_del(&request->client_list);
+               request->file_priv = NULL;
+       }
+       spin_unlock(&file_priv->mm.lock);
 }
 
 static int
@@ -4889,12 +4899,10 @@ i915_gpu_is_active(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int lists_empty;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
-                     list_empty(&dev_priv->render_ring.active_list);
-       if (HAS_BSD(dev))
-               lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
+                     list_empty(&dev_priv->render_ring.active_list) &&
+                     list_empty(&dev_priv->bsd_ring.active_list) &&
+                     list_empty(&dev_priv->blt_ring.active_list);
 
        return !lists_empty;
 }
@@ -4916,7 +4924,7 @@ i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
                        if (mutex_trylock(&dev->struct_mutex)) {
                                list_for_each_entry(obj_priv,
                                                    &dev_priv->mm.inactive_list,
-                                                   list)
+                                                   mm_list)
                                        cnt++;
                                mutex_unlock(&dev->struct_mutex);
                        }
@@ -4942,7 +4950,7 @@ rescan:
 
                list_for_each_entry_safe(obj_priv, next_obj,
                                         &dev_priv->mm.inactive_list,
-                                        list) {
+                                        mm_list) {
                        if (i915_gem_object_is_purgeable(obj_priv)) {
                                i915_gem_object_unbind(&obj_priv->base);
                                if (--nr_to_scan <= 0)
@@ -4971,7 +4979,7 @@ rescan:
 
                list_for_each_entry_safe(obj_priv, next_obj,
                                         &dev_priv->mm.inactive_list,
-                                        list) {
+                                        mm_list) {
                        if (nr_to_scan > 0) {
                                i915_gem_object_unbind(&obj_priv->base);
                                nr_to_scan--;
index 80f380b1d951fe8875260b90849cbf78ced35d5a..48644b840a8dc08dfac36c6d5570265427324f6a 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#if WATCH_INACTIVE
-void
-i915_verify_inactive(struct drm_device *dev, char *file, int line)
+#if WATCH_LISTS
+int
+i915_verify_lists(struct drm_device *dev)
 {
+       static int warned;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
-
-       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-               obj = &obj_priv->base;
-               if (obj_priv->pin_count || obj_priv->active ||
-                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-                                          I915_GEM_DOMAIN_GTT)))
-                       DRM_ERROR("inactive %p (p %d a %d w %x)  %s:%d\n",
+       struct drm_i915_gem_object *obj;
+       int err = 0;
+
+       if (warned)
+               return 0;
+
+       list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed render active %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) {
+                       DRM_ERROR("invalid render active %p (a %d r %x)\n",
+                                 obj,
+                                 obj->active,
+                                 obj->base.read_domains);
+                       err++;
+               } else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) {
+                       DRM_ERROR("invalid render active %p (w %x, gwl %d)\n",
+                                 obj,
+                                 obj->base.write_domain,
+                                 !list_empty(&obj->gpu_write_list));
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed flushing %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 ||
+                          list_empty(&obj->gpu_write_list)){
+                       DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n",
                                  obj,
-                                 obj_priv->pin_count, obj_priv->active,
-                                 obj->write_domain, file, line);
+                                 obj->active,
+                                 obj->base.write_domain,
+                                 !list_empty(&obj->gpu_write_list));
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed gpu write %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) {
+                       DRM_ERROR("invalid gpu write %p (a %d w %x)\n",
+                                 obj,
+                                 obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed inactive %p\n", obj);
+                       err++;
+                       break;
+               } else if (obj->pin_count || obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+                       DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n",
+                                 obj,
+                                 obj->pin_count, obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
        }
+
+       list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed pinned %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->pin_count || obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+                       DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
+                                 obj,
+                                 obj->pin_count, obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
+       }
+
+       return warned = err;
 }
 #endif /* WATCH_INACTIVE */
 
 
-#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+#if WATCH_EXEC | WATCH_PWRITE
 static void
 i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
                   uint32_t bias, uint32_t mark)
@@ -97,41 +180,6 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
 }
 #endif
 
-#if WATCH_LRU
-void
-i915_dump_lru(struct drm_device *dev, const char *where)
-{
-       drm_i915_private_t              *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object      *obj_priv;
-
-       DRM_INFO("active list %s {\n", where);
-       spin_lock(&dev_priv->mm.active_list_lock);
-       list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
-                           list)
-       {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       spin_unlock(&dev_priv->mm.active_list_lock);
-       DRM_INFO("}\n");
-       DRM_INFO("flushing list %s {\n", where);
-       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
-                           list)
-       {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       DRM_INFO("}\n");
-       DRM_INFO("inactive %s {\n", where);
-       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       DRM_INFO("}\n");
-}
-#endif
-
-
 #if WATCH_COHERENCY
 void
 i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
index 5c428fa3e0b34049e94786184b646a98ee87c06d..43a4013f53fa24e212849af68940384b777d30a1 100644 (file)
 #include "i915_drv.h"
 #include "i915_drm.h"
 
-static struct drm_i915_gem_object *
-i915_gem_next_active_object(struct drm_device *dev,
-                           struct list_head **render_iter,
-                           struct list_head **bsd_iter)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL;
-
-       if (*render_iter != &dev_priv->render_ring.active_list)
-               render_obj = list_entry(*render_iter,
-                                       struct drm_i915_gem_object,
-                                       list);
-
-       if (HAS_BSD(dev)) {
-               if (*bsd_iter != &dev_priv->bsd_ring.active_list)
-                       bsd_obj = list_entry(*bsd_iter,
-                                            struct drm_i915_gem_object,
-                                            list);
-
-               if (render_obj == NULL) {
-                       *bsd_iter = (*bsd_iter)->next;
-                       return bsd_obj;
-               }
-
-               if (bsd_obj == NULL) {
-                       *render_iter = (*render_iter)->next;
-                       return render_obj;
-               }
-
-               /* XXX can we handle seqno wrapping? */
-               if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) {
-                       *render_iter = (*render_iter)->next;
-                       return render_obj;
-               } else {
-                       *bsd_iter = (*bsd_iter)->next;
-                       return bsd_obj;
-               }
-       } else {
-               *render_iter = (*render_iter)->next;
-               return render_obj;
-       }
-}
-
 static bool
 mark_free(struct drm_i915_gem_object *obj_priv,
           struct list_head *unwind)
@@ -83,18 +40,12 @@ mark_free(struct drm_i915_gem_object *obj_priv,
        return drm_mm_scan_add_block(obj_priv->gtt_space);
 }
 
-#define i915_for_each_active_object(OBJ, R, B) \
-       *(R) = dev_priv->render_ring.active_list.next; \
-       *(B) = dev_priv->bsd_ring.active_list.next; \
-       while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL)
-
 int
 i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct list_head eviction_list, unwind_list;
        struct drm_i915_gem_object *obj_priv;
-       struct list_head *render_iter, *bsd_iter;
        int ret = 0;
 
        i915_gem_retire_requests(dev);
@@ -131,13 +82,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
        drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
 
        /* First see if there is a large enough contiguous idle region... */
-       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
                if (mark_free(obj_priv, &unwind_list))
                        goto found;
        }
 
        /* Now merge in the soon-to-be-expired objects... */
-       i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                /* Does the object require an outstanding flush? */
                if (obj_priv->base.write_domain || obj_priv->pin_count)
                        continue;
@@ -147,14 +98,14 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
        }
 
        /* Finally add anything with a pending flush (in order of retirement) */
-       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
                if (obj_priv->pin_count)
                        continue;
 
                if (mark_free(obj_priv, &unwind_list))
                        goto found;
        }
-       i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                if (! obj_priv->base.write_domain || obj_priv->pin_count)
                        continue;
 
@@ -212,14 +163,11 @@ i915_gem_evict_everything(struct drm_device *dev)
        int ret;
        bool lists_empty;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
-                      (!HAS_BSD(dev)
-                       || list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
+                      list_empty(&dev_priv->bsd_ring.active_list) &&
+                      list_empty(&dev_priv->blt_ring.active_list));
        if (lists_empty)
                return -ENOSPC;
 
@@ -234,13 +182,11 @@ i915_gem_evict_everything(struct drm_device *dev)
        if (ret)
                return ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
-                      (!HAS_BSD(dev)
-                       || list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
+                      list_empty(&dev_priv->bsd_ring.active_list) &&
+                      list_empty(&dev_priv->blt_ring.active_list));
        BUG_ON(!lists_empty);
 
        return 0;
@@ -258,7 +204,7 @@ i915_gem_evict_inactive(struct drm_device *dev)
 
                obj = &list_first_entry(&dev_priv->mm.inactive_list,
                                        struct drm_i915_gem_object,
-                                       list)->base;
+                                       mm_list)->base;
 
                ret = i915_gem_object_unbind(obj);
                if (ret != 0) {
index 710eca70b323953e376d3c214a33e78996bed1d2..af352de70be199d8eb8a3be49a138d279f80f9e3 100644 (file)
@@ -92,13 +92,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
-       if (IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+       if (IS_GEN5(dev) || IS_GEN6(dev)) {
                /* On Ironlake whatever DRAM config, GPU always do
                 * same swizzling setup.
                 */
                swizzle_x = I915_BIT_6_SWIZZLE_9_10;
                swizzle_y = I915_BIT_6_SWIZZLE_9;
-       } else if (!IS_I9XX(dev)) {
+       } else if (IS_GEN2(dev)) {
                /* As far as we know, the 865 doesn't have these bit 6
                 * swizzling issues.
                 */
@@ -190,19 +190,19 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
-       if (!IS_I9XX(dev) ||
+       if (IS_GEN2(dev) ||
            (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
                tile_width = 128;
        else
                tile_width = 512;
 
        /* check maximum stride & object size */
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                /* i965 stores the end address of the gtt mapping in the fence
                 * reg, so dont bother to check the size */
                if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
                        return false;
-       } else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+       } else {
                if (stride > 8192)
                        return false;
 
@@ -216,7 +216,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        }
 
        /* 965+ just needs multiples of tile width */
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                if (stride & (tile_width - 1))
                        return false;
                return true;
@@ -244,16 +244,18 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
-       if (!IS_I965G(dev)) {
-               if (obj_priv->gtt_offset & (obj->size - 1))
+       if (INTEL_INFO(dev)->gen >= 4)
+               return true;
+
+       if (obj_priv->gtt_offset & (obj->size - 1))
+               return false;
+
+       if (IS_GEN3(dev)) {
+               if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+                       return false;
+       } else {
+               if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
                        return false;
-               if (IS_I9XX(dev)) {
-                       if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
-                               return false;
-               } else {
-                       if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
-                               return false;
-               }
        }
 
        return true;
@@ -271,7 +273,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-       int ret = 0;
+       int ret;
+
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
@@ -328,7 +334,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
                        ret = i915_gem_object_unbind(obj);
                else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       ret = i915_gem_object_put_fence_reg(obj);
+                       ret = i915_gem_object_put_fence_reg(obj, true);
                else
                        i915_gem_release_mmap(obj);
 
@@ -399,16 +405,14 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
  * bit 17 of its physical address and therefore being interpreted differently
  * by the GPU.
  */
-static int
+static void
 i915_gem_swizzle_page(struct page *page)
 {
+       char temp[64];
        char *vaddr;
        int i;
-       char temp[64];
 
        vaddr = kmap(page);
-       if (vaddr == NULL)
-               return -ENOMEM;
 
        for (i = 0; i < PAGE_SIZE; i += 128) {
                memcpy(temp, &vaddr[i], 64);
@@ -417,8 +421,6 @@ i915_gem_swizzle_page(struct page *page)
        }
 
        kunmap(page);
-
-       return 0;
 }
 
 void
@@ -440,11 +442,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
                char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
                if ((new_bit_17 & 0x1) !=
                    (test_bit(i, obj_priv->bit_17) != 0)) {
-                       int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
-                       if (ret != 0) {
-                               DRM_ERROR("Failed to swizzle page\n");
-                               return;
-                       }
+                       i915_gem_swizzle_page(obj_priv->pages[i]);
                        set_page_dirty(obj_priv->pages[i]);
                }
        }
index 744225ebb4b25d5988fab454441de95d7db94115..729fd0c91d7b2c1f30de2afacae4227238ccdbd5 100644 (file)
@@ -85,7 +85,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
 }
 
 /* For display hotplug interrupt */
-void
+static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
        if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -172,7 +172,7 @@ void intel_enable_asle (struct drm_device *dev)
        else {
                i915_enable_pipestat(dev_priv, 1,
                                     PIPE_LEGACY_BLC_EVENT_ENABLE);
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        i915_enable_pipestat(dev_priv, 0,
                                             PIPE_LEGACY_BLC_EVENT_ENABLE);
        }
@@ -191,12 +191,7 @@ static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
-       if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
-               return 1;
-
-       return 0;
+       return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -207,10 +202,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
-       u32 high1, high2, low, count;
-
-       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+       u32 high1, high2, low;
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -218,23 +210,23 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
                return 0;
        }
 
+       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
        /*
         * High & low register fields aren't synchronized, so make sure
         * we get a low value that's stable across two reads of the high
         * register.
         */
        do {
-               high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-                        PIPE_FRAME_HIGH_SHIFT);
-               low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
-                       PIPE_FRAME_LOW_SHIFT);
-               high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-                        PIPE_FRAME_HIGH_SHIFT);
+               high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
+               low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
+               high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
        } while (high1 != high2);
 
-       count = (high1 << 8) | low;
-
-       return count;
+       high1 >>= PIPE_FRAME_HIGH_SHIFT;
+       low >>= PIPE_FRAME_LOW_SHIFT;
+       return (high1 << 8) | low;
 }
 
 u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -260,16 +252,12 @@ static void i915_hotplug_work_func(struct work_struct *work)
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
-
-       if (mode_config->num_encoder) {
-               list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-                       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       
-                       if (intel_encoder->hot_plug)
-                               (*intel_encoder->hot_plug) (intel_encoder);
-               }
-       }
+       struct intel_encoder *encoder;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->hot_plug)
+                       encoder->hot_plug(encoder);
+
        /* Just fire off a uevent and let userspace tell us what to do */
        drm_helper_hpd_irq_event(dev);
 }
@@ -305,13 +293,30 @@ static void i915_handle_rps_change(struct drm_device *dev)
        return;
 }
 
-irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+static void notify_ring(struct drm_device *dev,
+                       struct intel_ring_buffer *ring)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 seqno = ring->get_seqno(dev, ring);
+       ring->irq_gem_seqno = seqno;
+       trace_i915_gem_request_complete(dev, seqno);
+       wake_up_all(&ring->irq_queue);
+       dev_priv->hangcheck_count = 0;
+       mod_timer(&dev_priv->hangcheck_timer,
+                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+}
+
+static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir;
+       u32 hotplug_mask;
        struct drm_i915_master_private *master_priv;
-       struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+       u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+       if (IS_GEN6(dev))
+               bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
        /* disable master interrupt before clearing iir  */
        de_ier = I915_READ(DEIER);
@@ -325,6 +330,11 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
                goto done;
 
+       if (HAS_PCH_CPT(dev))
+               hotplug_mask = SDE_HOTPLUG_MASK_CPT;
+       else
+               hotplug_mask = SDE_HOTPLUG_MASK;
+
        ret = IRQ_HANDLED;
 
        if (dev->primary->master) {
@@ -334,29 +344,24 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                                READ_BREADCRUMB(dev_priv);
        }
 
-       if (gt_iir & GT_PIPE_NOTIFY) {
-               u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
-               render_ring->irq_gem_seqno = seqno;
-               trace_i915_gem_request_complete(dev, seqno);
-               DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
-               dev_priv->hangcheck_count = 0;
-               mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
-       }
-       if (gt_iir & GT_BSD_USER_INTERRUPT)
-               DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
+       if (gt_iir & GT_PIPE_NOTIFY)
+               notify_ring(dev, &dev_priv->render_ring);
+       if (gt_iir & bsd_usr_interrupt)
+               notify_ring(dev, &dev_priv->bsd_ring);
+       if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->blt_ring);
 
        if (de_iir & DE_GSE)
-               ironlake_opregion_gse_intr(dev);
+               intel_opregion_gse_intr(dev);
 
        if (de_iir & DE_PLANEA_FLIP_DONE) {
                intel_prepare_page_flip(dev, 0);
-               intel_finish_page_flip(dev, 0);
+               intel_finish_page_flip_plane(dev, 0);
        }
 
        if (de_iir & DE_PLANEB_FLIP_DONE) {
                intel_prepare_page_flip(dev, 1);
-               intel_finish_page_flip(dev, 1);
+               intel_finish_page_flip_plane(dev, 1);
        }
 
        if (de_iir & DE_PIPEA_VBLANK)
@@ -366,10 +371,8 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                drm_handle_vblank(dev, 1);
 
        /* check event from PCH */
-       if ((de_iir & DE_PCH_EVENT) &&
-           (pch_iir & SDE_HOTPLUG_MASK)) {
+       if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
                queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-       }
 
        if (de_iir & DE_PCU_EVENT) {
                I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
@@ -404,23 +407,20 @@ static void i915_error_work_func(struct work_struct *work)
        char *reset_event[] = { "RESET=1", NULL };
        char *reset_done_event[] = { "ERROR=0", NULL };
 
-       DRM_DEBUG_DRIVER("generating error event\n");
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
        if (atomic_read(&dev_priv->mm.wedged)) {
-               if (IS_I965G(dev)) {
-                       DRM_DEBUG_DRIVER("resetting chip\n");
-                       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
-                       if (!i965_reset(dev, GDRST_RENDER)) {
-                               atomic_set(&dev_priv->mm.wedged, 0);
-                               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
-                       }
-               } else {
-                       DRM_DEBUG_DRIVER("reboot required\n");
+               DRM_DEBUG_DRIVER("resetting chip\n");
+               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+               if (!i915_reset(dev, GRDOM_RENDER)) {
+                       atomic_set(&dev_priv->mm.wedged, 0);
+                       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
                }
+               complete_all(&dev_priv->error_completion);
        }
 }
 
+#ifdef CONFIG_DEBUG_FS
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_device *dev,
                         struct drm_gem_object *src)
@@ -456,10 +456,9 @@ i915_error_object_create(struct drm_device *dev,
 
                local_irq_save(flags);
                s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-                                            reloc_offset,
-                                            KM_IRQ0);
+                                            reloc_offset);
                memcpy_fromio(d, s, PAGE_SIZE);
-               io_mapping_unmap_atomic(s, KM_IRQ0);
+               io_mapping_unmap_atomic(s);
                local_irq_restore(flags);
 
                dst->pages[page] = d;
@@ -511,7 +510,7 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring)
 
        if (IS_I830(dev) || IS_845G(dev))
                cmd = MI_BATCH_BUFFER;
-       else if (IS_I965G(dev))
+       else if (INTEL_INFO(dev)->gen >= 4)
                cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
                       MI_BATCH_NON_SECURE_I965);
        else
@@ -584,13 +583,16 @@ static void i915_capture_error_state(struct drm_device *dev)
                return;
        }
 
-       error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
+       DRM_DEBUG_DRIVER("generating error event\n");
+
+       error->seqno =
+               dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
        error->pipeastat = I915_READ(PIPEASTAT);
        error->pipebstat = I915_READ(PIPEBSTAT);
        error->instpm = I915_READ(INSTPM);
-       if (!IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen < 4) {
                error->ipeir = I915_READ(IPEIR);
                error->ipehr = I915_READ(IPEHR);
                error->instdone = I915_READ(INSTDONE);
@@ -612,9 +614,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        batchbuffer[0] = NULL;
        batchbuffer[1] = NULL;
        count = 0;
-       list_for_each_entry(obj_priv,
-                       &dev_priv->render_ring.active_list, list) {
-
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                struct drm_gem_object *obj = &obj_priv->base;
 
                if (batchbuffer[0] == NULL &&
@@ -631,7 +631,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        }
        /* Scan the other lists for completeness for those bizarre errors. */
        if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-               list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        if (batchbuffer[0] == NULL &&
@@ -649,7 +649,7 @@ static void i915_capture_error_state(struct drm_device *dev)
                }
        }
        if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-               list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        if (batchbuffer[0] == NULL &&
@@ -668,7 +668,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        }
 
        /* We need to copy these to an anonymous buffer as the simplest
-        * method to avoid being overwritten by userpace.
+        * method to avoid being overwritten by userspace.
         */
        error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
        if (batchbuffer[1] != batchbuffer[0])
@@ -690,8 +690,7 @@ static void i915_capture_error_state(struct drm_device *dev)
 
        if (error->active_bo) {
                int i = 0;
-               list_for_each_entry(obj_priv,
-                               &dev_priv->render_ring.active_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        error->active_bo[i].size = obj->size;
@@ -744,6 +743,9 @@ void i915_destroy_error_state(struct drm_device *dev)
        if (error)
                i915_error_state_free(dev, error);
 }
+#else
+#define i915_capture_error_state(x)
+#endif
 
 static void i915_report_and_clear_eir(struct drm_device *dev)
 {
@@ -785,7 +787,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                }
        }
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (eir & I915_ERROR_PAGE_TABLE) {
                        u32 pgtbl_err = I915_READ(PGTBL_ER);
                        printk(KERN_ERR "page table error\n");
@@ -811,7 +813,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                printk(KERN_ERR "instruction error\n");
                printk(KERN_ERR "  INSTPM: 0x%08x\n",
                       I915_READ(INSTPM));
-               if (!IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen < 4) {
                        u32 ipeir = I915_READ(IPEIR);
 
                        printk(KERN_ERR "  IPEIR: 0x%08x\n",
@@ -876,12 +878,17 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
        i915_report_and_clear_eir(dev);
 
        if (wedged) {
+               INIT_COMPLETION(dev_priv->error_completion);
                atomic_set(&dev_priv->mm.wedged, 1);
 
                /*
                 * Wakeup waiting processes so they don't hang
                 */
-               DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+               wake_up_all(&dev_priv->render_ring.irq_queue);
+               if (HAS_BSD(dev))
+                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
+               if (HAS_BLT(dev))
+                       wake_up_all(&dev_priv->blt_ring.irq_queue);
        }
 
        queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -912,7 +919,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
 
        /* Potential stall - if we see that the flip has happened, assume a missed interrupt */
        obj_priv = to_intel_bo(work->pending_flip_obj);
-       if(IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
                stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
        } else {
@@ -942,7 +949,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
        unsigned long irqflags;
        int irq_received;
        int ret = IRQ_NONE;
-       struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -951,7 +957,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
        iir = I915_READ(IIR);
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
        else
                vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
@@ -1019,18 +1025,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                        READ_BREADCRUMB(dev_priv);
                }
 
-               if (iir & I915_USER_INTERRUPT) {
-                       u32 seqno =
-                               render_ring->get_gem_seqno(dev, render_ring);
-                       render_ring->irq_gem_seqno = seqno;
-                       trace_i915_gem_request_complete(dev, seqno);
-                       DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
-                       dev_priv->hangcheck_count = 0;
-                       mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
-               }
-
+               if (iir & I915_USER_INTERRUPT)
+                       notify_ring(dev, &dev_priv->render_ring);
                if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
-                       DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+                       notify_ring(dev, &dev_priv->bsd_ring);
 
                if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
                        intel_prepare_page_flip(dev, 0);
@@ -1065,7 +1063,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
                    (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
                    (iir & I915_ASLE_INTERRUPT))
-                       opregion_asle_intr(dev);
+                       intel_opregion_asle_intr(dev);
 
                /* With MSI, interrupts are only generated when iir
                 * transitions from zero to nonzero.  If another bit got
@@ -1207,18 +1205,15 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       u32 pipeconf;
 
-       pipeconf = I915_READ(pipeconf_reg);
-       if (!(pipeconf & PIPEACONF_ENABLE))
+       if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        if (HAS_PCH_SPLIT(dev))
                ironlake_enable_display_irq(dev_priv, (pipe == 0) ? 
                                            DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else if (IS_I965G(dev))
+       else if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
        else
@@ -1252,7 +1247,7 @@ void i915_enable_interrupt (struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!HAS_PCH_SPLIT(dev))
-               opregion_enable_asle(dev);
+               intel_opregion_enable_asle(dev);
        dev_priv->irq_enabled = 1;
 }
 
@@ -1311,7 +1306,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        return -EINVAL;
 }
 
-struct drm_i915_gem_request *
+static struct drm_i915_gem_request *
 i915_get_tail_request(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1331,11 +1326,7 @@ void i915_hangcheck_elapsed(unsigned long data)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t acthd, instdone, instdone1;
 
-       /* No reset support on this chip yet. */
-       if (IS_GEN6(dev))
-               return;
-
-       if (!IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen < 4) {
                acthd = I915_READ(ACTHD);
                instdone = I915_READ(INSTDONE);
                instdone1 = 0;
@@ -1347,9 +1338,8 @@ void i915_hangcheck_elapsed(unsigned long data)
 
        /* If all work is done then ACTHD clearly hasn't advanced. */
        if (list_empty(&dev_priv->render_ring.request_list) ||
-               i915_seqno_passed(i915_get_gem_seqno(dev,
-                               &dev_priv->render_ring),
-                       i915_get_tail_request(dev)->seqno)) {
+               i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
+                                 i915_get_tail_request(dev)->seqno)) {
                bool missed_wakeup = false;
 
                dev_priv->hangcheck_count = 0;
@@ -1357,13 +1347,19 @@ void i915_hangcheck_elapsed(unsigned long data)
                /* Issue a wake-up to catch stuck h/w. */
                if (dev_priv->render_ring.waiting_gem_seqno &&
                    waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-                       DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+                       wake_up_all(&dev_priv->render_ring.irq_queue);
                        missed_wakeup = true;
                }
 
                if (dev_priv->bsd_ring.waiting_gem_seqno &&
                    waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-                       DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
+                       missed_wakeup = true;
+               }
+
+               if (dev_priv->blt_ring.waiting_gem_seqno &&
+                   waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
+                       wake_up_all(&dev_priv->blt_ring.irq_queue);
                        missed_wakeup = true;
                }
 
@@ -1377,6 +1373,21 @@ void i915_hangcheck_elapsed(unsigned long data)
            dev_priv->last_instdone1 == instdone1) {
                if (dev_priv->hangcheck_count++ > 1) {
                        DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+
+                       if (!IS_GEN2(dev)) {
+                               /* Is the chip hanging on a WAIT_FOR_EVENT?
+                                * If so we can simply poke the RB_WAIT bit
+                                * and break the hang. This should work on
+                                * all but the second generation chipsets.
+                                */
+                               u32 tmp = I915_READ(PRB0_CTL);
+                               if (tmp & RING_WAIT) {
+                                       I915_WRITE(PRB0_CTL, tmp);
+                                       POSTING_READ(PRB0_CTL);
+                                       goto out;
+                               }
+                       }
+
                        i915_handle_error(dev, true);
                        return;
                }
@@ -1388,8 +1399,10 @@ void i915_hangcheck_elapsed(unsigned long data)
                dev_priv->last_instdone1 = instdone1;
        }
 
+out:
        /* Reset timer case chip hangs without another request being added */
-       mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+       mod_timer(&dev_priv->hangcheck_timer,
+                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
 /* drm_dma.h hooks
@@ -1424,8 +1437,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                           DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
        u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
-       u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
-                          SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+       u32 hotplug_mask;
 
        dev_priv->irq_mask_reg = ~display_mask;
        dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
@@ -1436,20 +1448,35 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
        (void) I915_READ(DEIER);
 
-       /* Gen6 only needs render pipe_control now */
-       if (IS_GEN6(dev))
-               render_mask = GT_PIPE_NOTIFY;
+       if (IS_GEN6(dev)) {
+               render_mask =
+                       GT_PIPE_NOTIFY |
+                       GT_GEN6_BSD_USER_INTERRUPT |
+                       GT_BLT_USER_INTERRUPT;
+       }
 
        dev_priv->gt_irq_mask_reg = ~render_mask;
        dev_priv->gt_irq_enable_reg = render_mask;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
-       if (IS_GEN6(dev))
+       if (IS_GEN6(dev)) {
                I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+               I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+               I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT);
+       }
+
        I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
        (void) I915_READ(GTIER);
 
+       if (HAS_PCH_CPT(dev)) {
+               hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT  |
+                              SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ;
+       } else {
+               hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
+                              SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+       }
+
        dev_priv->pch_irq_mask_reg = ~hotplug_mask;
        dev_priv->pch_irq_enable_reg = hotplug_mask;
 
@@ -1506,9 +1533,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        u32 error_mask;
 
        DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
-
        if (HAS_BSD(dev))
                DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue);
 
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
@@ -1578,7 +1606,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
                I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
        }
 
-       opregion_enable_asle(dev);
+       intel_opregion_enable_asle(dev);
 
        return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
deleted file mode 100644 (file)
index ea5d3fe..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * Copyright 2008 Intel Corporation <hong.liu@intel.com>
- * Copyright 2008 Red Hat <mjg@redhat.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 INTEL AND/OR ITS SUPPLIERS 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/acpi.h>
-#include <acpi/video.h>
-
-#include "drmP.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-
-#define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
-#define PCI_ASLS 0xfc
-
-#define OPREGION_SZ            (8*1024)
-#define OPREGION_HEADER_OFFSET 0
-#define OPREGION_ACPI_OFFSET   0x100
-#define OPREGION_SWSCI_OFFSET  0x200
-#define OPREGION_ASLE_OFFSET   0x300
-#define OPREGION_VBT_OFFSET    0x1000
-
-#define OPREGION_SIGNATURE "IntelGraphicsMem"
-#define MBOX_ACPI      (1<<0)
-#define MBOX_SWSCI     (1<<1)
-#define MBOX_ASLE      (1<<2)
-
-struct opregion_header {
-       u8 signature[16];
-       u32 size;
-       u32 opregion_ver;
-       u8 bios_ver[32];
-       u8 vbios_ver[16];
-       u8 driver_ver[16];
-       u32 mboxes;
-       u8 reserved[164];
-} __attribute__((packed));
-
-/* OpRegion mailbox #1: public ACPI methods */
-struct opregion_acpi {
-       u32 drdy;       /* driver readiness */
-       u32 csts;       /* notification status */
-       u32 cevt;       /* current event */
-       u8 rsvd1[20];
-       u32 didl[8];    /* supported display devices ID list */
-       u32 cpdl[8];    /* currently presented display list */
-       u32 cadl[8];    /* currently active display list */
-       u32 nadl[8];    /* next active devices list */
-       u32 aslp;       /* ASL sleep time-out */
-       u32 tidx;       /* toggle table index */
-       u32 chpd;       /* current hotplug enable indicator */
-       u32 clid;       /* current lid state*/
-       u32 cdck;       /* current docking state */
-       u32 sxsw;       /* Sx state resume */
-       u32 evts;       /* ASL supported events */
-       u32 cnot;       /* current OS notification */
-       u32 nrdy;       /* driver status */
-       u8 rsvd2[60];
-} __attribute__((packed));
-
-/* OpRegion mailbox #2: SWSCI */
-struct opregion_swsci {
-       u32 scic;       /* SWSCI command|status|data */
-       u32 parm;       /* command parameters */
-       u32 dslp;       /* driver sleep time-out */
-       u8 rsvd[244];
-} __attribute__((packed));
-
-/* OpRegion mailbox #3: ASLE */
-struct opregion_asle {
-       u32 ardy;       /* driver readiness */
-       u32 aslc;       /* ASLE interrupt command */
-       u32 tche;       /* technology enabled indicator */
-       u32 alsi;       /* current ALS illuminance reading */
-       u32 bclp;       /* backlight brightness to set */
-       u32 pfit;       /* panel fitting state */
-       u32 cblv;       /* current brightness level */
-       u16 bclm[20];   /* backlight level duty cycle mapping table */
-       u32 cpfm;       /* current panel fitting mode */
-       u32 epfm;       /* enabled panel fitting modes */
-       u8 plut[74];    /* panel LUT and identifier */
-       u32 pfmb;       /* PWM freq and min brightness */
-       u8 rsvd[102];
-} __attribute__((packed));
-
-/* ASLE irq request bits */
-#define ASLE_SET_ALS_ILLUM     (1 << 0)
-#define ASLE_SET_BACKLIGHT     (1 << 1)
-#define ASLE_SET_PFIT          (1 << 2)
-#define ASLE_SET_PWM_FREQ      (1 << 3)
-#define ASLE_REQ_MSK           0xf
-
-/* response bits of ASLE irq request */
-#define ASLE_ALS_ILLUM_FAILED  (1<<10)
-#define ASLE_BACKLIGHT_FAILED  (1<<12)
-#define ASLE_PFIT_FAILED       (1<<14)
-#define ASLE_PWM_FREQ_FAILED   (1<<16)
-
-/* ASLE backlight brightness to set */
-#define ASLE_BCLP_VALID                (1<<31)
-#define ASLE_BCLP_MSK          (~(1<<31))
-
-/* ASLE panel fitting request */
-#define ASLE_PFIT_VALID         (1<<31)
-#define ASLE_PFIT_CENTER (1<<0)
-#define ASLE_PFIT_STRETCH_TEXT (1<<1)
-#define ASLE_PFIT_STRETCH_GFX (1<<2)
-
-/* PWM frequency and minimum brightness */
-#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
-#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
-#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
-#define ASLE_PFMB_PWM_VALID (1<<31)
-
-#define ASLE_CBLV_VALID         (1<<31)
-
-#define ACPI_OTHER_OUTPUT (0<<8)
-#define ACPI_VGA_OUTPUT (1<<8)
-#define ACPI_TV_OUTPUT (2<<8)
-#define ACPI_DIGITAL_OUTPUT (3<<8)
-#define ACPI_LVDS_OUTPUT (4<<8)
-
-static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 blc_pwm_ctl, blc_pwm_ctl2;
-       u32 max_backlight, level, shift;
-
-       if (!(bclp & ASLE_BCLP_VALID))
-               return ASLE_BACKLIGHT_FAILED;
-
-       bclp &= ASLE_BCLP_MSK;
-       if (bclp < 0 || bclp > 255)
-               return ASLE_BACKLIGHT_FAILED;
-
-       blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-       blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-       if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-               pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-       else {
-               if (IS_PINEVIEW(dev)) {
-                       blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-                       max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-                                       BACKLIGHT_MODULATION_FREQ_SHIFT;
-                       shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-               } else {
-                       blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-                       max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-                                       BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-                       shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-               }
-               level = (bclp * max_backlight) / 255;
-               I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-       }
-       asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-       return 0;
-}
-
-static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
-{
-       /* alsi is the current ALS reading in lux. 0 indicates below sensor
-          range, 0xffff indicates above sensor range. 1-0xfffe are valid */
-       return 0;
-}
-
-static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       if (pfmb & ASLE_PFMB_PWM_VALID) {
-               u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-               u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
-               blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
-               pwm = pwm >> 9;
-               /* FIXME - what do we do with the PWM? */
-       }
-       return 0;
-}
-
-static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
-{
-       /* Panel fitting is currently controlled by the X code, so this is a
-          noop until modesetting support works fully */
-       if (!(pfit & ASLE_PFIT_VALID))
-               return ASLE_PFIT_FAILED;
-       return 0;
-}
-
-void opregion_asle_intr(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 asle_stat = 0;
-       u32 asle_req;
-
-       if (!asle)
-               return;
-
-       asle_req = asle->aslc & ASLE_REQ_MSK;
-
-       if (!asle_req) {
-               DRM_DEBUG_DRIVER("non asle set request??\n");
-               return;
-       }
-
-       if (asle_req & ASLE_SET_ALS_ILLUM)
-               asle_stat |= asle_set_als_illum(dev, asle->alsi);
-
-       if (asle_req & ASLE_SET_BACKLIGHT)
-               asle_stat |= asle_set_backlight(dev, asle->bclp);
-
-       if (asle_req & ASLE_SET_PFIT)
-               asle_stat |= asle_set_pfit(dev, asle->pfit);
-
-       if (asle_req & ASLE_SET_PWM_FREQ)
-               asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
-
-       asle->aslc = asle_stat;
-}
-
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 cpu_pwm_ctl, pch_pwm_ctl2;
-       u32 max_backlight, level;
-
-       if (!(bclp & ASLE_BCLP_VALID))
-               return ASLE_BACKLIGHT_FAILED;
-
-       bclp &= ASLE_BCLP_MSK;
-       if (bclp < 0 || bclp > 255)
-               return ASLE_BACKLIGHT_FAILED;
-
-       cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-       pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-       /* get the max PWM frequency */
-       max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-       /* calculate the expected PMW frequency */
-       level = (bclp * max_backlight) / 255;
-       /* reserve the high 16 bits */
-       cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-       /* write the updated PWM frequency */
-       I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-       asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-       return 0;
-}
-
-void ironlake_opregion_gse_intr(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 asle_stat = 0;
-       u32 asle_req;
-
-       if (!asle)
-               return;
-
-       asle_req = asle->aslc & ASLE_REQ_MSK;
-
-       if (!asle_req) {
-               DRM_DEBUG_DRIVER("non asle set request??\n");
-               return;
-       }
-
-       if (asle_req & ASLE_SET_ALS_ILLUM) {
-               DRM_DEBUG_DRIVER("Illum is not supported\n");
-               asle_stat |= ASLE_ALS_ILLUM_FAILED;
-       }
-
-       if (asle_req & ASLE_SET_BACKLIGHT)
-               asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
-
-       if (asle_req & ASLE_SET_PFIT) {
-               DRM_DEBUG_DRIVER("Pfit is not supported\n");
-               asle_stat |= ASLE_PFIT_FAILED;
-       }
-
-       if (asle_req & ASLE_SET_PWM_FREQ) {
-               DRM_DEBUG_DRIVER("PWM freq is not supported\n");
-               asle_stat |= ASLE_PWM_FREQ_FAILED;
-       }
-
-       asle->aslc = asle_stat;
-}
-#define ASLE_ALS_EN    (1<<0)
-#define ASLE_BLC_EN    (1<<1)
-#define ASLE_PFIT_EN   (1<<2)
-#define ASLE_PFMB_EN   (1<<3)
-
-void opregion_enable_asle(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-
-       if (asle) {
-               if (IS_MOBILE(dev)) {
-                       unsigned long irqflags;
-
-                       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-                       intel_enable_asle(dev);
-                       spin_unlock_irqrestore(&dev_priv->user_irq_lock,
-                                              irqflags);
-               }
-
-               asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
-                       ASLE_PFMB_EN;
-               asle->ardy = 1;
-       }
-}
-
-#define ACPI_EV_DISPLAY_SWITCH (1<<0)
-#define ACPI_EV_LID            (1<<1)
-#define ACPI_EV_DOCK           (1<<2)
-
-static struct intel_opregion *system_opregion;
-
-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
-          Linux, these are handled by the dock, button and video drivers.
-          We might want to fix the video driver to be opregion-aware in
-          future, but right now we just indicate to the firmware that the
-          request has been handled */
-
-       struct opregion_acpi *acpi;
-
-       if (!system_opregion)
-               return NOTIFY_DONE;
-
-       acpi = system_opregion->acpi;
-       acpi->csts = 0;
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block intel_opregion_notifier = {
-       .notifier_call = intel_opregion_video_event,
-};
-
-/*
- * Initialise the DIDL field in opregion. This passes a list of devices to
- * the firmware. Values are defined by section B.4.2 of the ACPI specification
- * (version 3)
- */
-
-static void intel_didl_outputs(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_opregion *opregion = &dev_priv->opregion;
-       struct drm_connector *connector;
-       acpi_handle handle;
-       struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
-       unsigned long long device_id;
-       acpi_status status;
-       int i = 0;
-
-       handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
-       if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
-               return;
-
-       if (acpi_is_video_device(acpi_dev))
-               acpi_video_bus = acpi_dev;
-       else {
-               list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
-                       if (acpi_is_video_device(acpi_cdev)) {
-                               acpi_video_bus = acpi_cdev;
-                               break;
-                       }
-               }
-       }
-
-       if (!acpi_video_bus) {
-               printk(KERN_WARNING "No ACPI video bus found\n");
-               return;
-       }
-
-       list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
-               if (i >= 8) {
-                       dev_printk (KERN_ERR, &dev->pdev->dev,
-                                   "More than 8 outputs detected\n");
-                       return;
-               }
-               status =
-                       acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
-                                               NULL, &device_id);
-               if (ACPI_SUCCESS(status)) {
-                       if (!device_id)
-                               goto blind_set;
-                       opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
-                       i++;
-               }
-       }
-
-end:
-       /* If fewer than 8 outputs, the list must be null terminated */
-       if (i < 8)
-               opregion->acpi->didl[i] = 0;
-       return;
-
-blind_set:
-       i = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               int output_type = ACPI_OTHER_OUTPUT;
-               if (i >= 8) {
-                       dev_printk (KERN_ERR, &dev->pdev->dev,
-                                   "More than 8 outputs detected\n");
-                       return;
-               }
-               switch (connector->connector_type) {
-               case DRM_MODE_CONNECTOR_VGA:
-               case DRM_MODE_CONNECTOR_DVIA:
-                       output_type = ACPI_VGA_OUTPUT;
-                       break;
-               case DRM_MODE_CONNECTOR_Composite:
-               case DRM_MODE_CONNECTOR_SVIDEO:
-               case DRM_MODE_CONNECTOR_Component:
-               case DRM_MODE_CONNECTOR_9PinDIN:
-                       output_type = ACPI_TV_OUTPUT;
-                       break;
-               case DRM_MODE_CONNECTOR_DVII:
-               case DRM_MODE_CONNECTOR_DVID:
-               case DRM_MODE_CONNECTOR_DisplayPort:
-               case DRM_MODE_CONNECTOR_HDMIA:
-               case DRM_MODE_CONNECTOR_HDMIB:
-                       output_type = ACPI_DIGITAL_OUTPUT;
-                       break;
-               case DRM_MODE_CONNECTOR_LVDS:
-                       output_type = ACPI_LVDS_OUTPUT;
-                       break;
-               }
-               opregion->acpi->didl[i] |= (1<<31) | output_type | i;
-               i++;
-       }
-       goto end;
-}
-
-int intel_opregion_init(struct drm_device *dev, int resume)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_opregion *opregion = &dev_priv->opregion;
-       void *base;
-       u32 asls, mboxes;
-       int err = 0;
-
-       pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
-       DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
-       if (asls == 0) {
-               DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
-               return -ENOTSUPP;
-       }
-
-       base = ioremap(asls, OPREGION_SZ);
-       if (!base)
-               return -ENOMEM;
-
-       opregion->header = base;
-       if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
-               DRM_DEBUG_DRIVER("opregion signature mismatch\n");
-               err = -EINVAL;
-               goto err_out;
-       }
-
-       mboxes = opregion->header->mboxes;
-       if (mboxes & MBOX_ACPI) {
-               DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
-               opregion->acpi = base + OPREGION_ACPI_OFFSET;
-               if (drm_core_check_feature(dev, DRIVER_MODESET))
-                       intel_didl_outputs(dev);
-       } else {
-               DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
-               err = -ENOTSUPP;
-               goto err_out;
-       }
-       opregion->enabled = 1;
-
-       if (mboxes & MBOX_SWSCI) {
-               DRM_DEBUG_DRIVER("SWSCI supported\n");
-               opregion->swsci = base + OPREGION_SWSCI_OFFSET;
-       }
-       if (mboxes & MBOX_ASLE) {
-               DRM_DEBUG_DRIVER("ASLE supported\n");
-               opregion->asle = base + OPREGION_ASLE_OFFSET;
-               opregion_enable_asle(dev);
-       }
-
-       if (!resume)
-               acpi_video_register();
-
-
-       /* Notify BIOS we are ready to handle ACPI video ext notifs.
-        * Right now, all the events are handled by the ACPI video module.
-        * We don't actually need to do anything with them. */
-       opregion->acpi->csts = 0;
-       opregion->acpi->drdy = 1;
-
-       system_opregion = opregion;
-       register_acpi_notifier(&intel_opregion_notifier);
-
-       return 0;
-
-err_out:
-       iounmap(opregion->header);
-       opregion->header = NULL;
-       acpi_video_register();
-       return err;
-}
-
-void intel_opregion_free(struct drm_device *dev, int suspend)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_opregion *opregion = &dev_priv->opregion;
-
-       if (!opregion->enabled)
-               return;
-
-       if (!suspend)
-               acpi_video_unregister();
-
-       opregion->acpi->drdy = 0;
-
-       system_opregion = NULL;
-       unregister_acpi_notifier(&intel_opregion_notifier);
-
-       /* just clear all opregion memory pointers now */
-       iounmap(opregion->header);
-       opregion->header = NULL;
-       opregion->acpi = NULL;
-       opregion->swsci = NULL;
-       opregion->asle = NULL;
-
-       opregion->enabled = 0;
-}
index 4f5e15577e89e3e6f7005cd92f9f87ab0636b4eb..25ed911a31127256b753970d2b2fca22d67f755d 100644 (file)
 #ifndef _I915_REG_H_
 #define _I915_REG_H_
 
+#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+
 /*
  * The Bridge device's PCI config space has information about the
  * fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
  */
 #define INTEL_GMCH_CTRL                0x52
 #define INTEL_GMCH_VGA_DISABLE  (1 << 1)
-#define INTEL_GMCH_ENABLED     0x4
-#define INTEL_GMCH_MEM_MASK    0x1
-#define INTEL_GMCH_MEM_64M     0x1
-#define INTEL_GMCH_MEM_128M    0
-
-#define INTEL_GMCH_GMS_MASK            (0xf << 4)
-#define INTEL_855_GMCH_GMS_DISABLED    (0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M   (0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M   (0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M   (0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M  (0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M  (0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
-#define INTEL_GMCH_GMS_STOLEN_128M     (0x8 << 4)
-#define INTEL_GMCH_GMS_STOLEN_256M     (0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
-
-#define SNB_GMCH_CTRL  0x50
-#define SNB_GMCH_GMS_STOLEN_MASK       0xF8
-#define SNB_GMCH_GMS_STOLEN_32M                (1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M                (2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M                (3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M       (4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M       (5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M       (6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M       (7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M       (8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M       (9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M       (0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M       (0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M       (0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M       (0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M       (0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M       (0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M       (0x10 << 3)
 
 /* PCI config space */
 
 #define   I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
 #define   I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
 #define LBB    0xf4
-#define GDRST 0xc0
-#define  GDRST_FULL    (0<<2)
-#define  GDRST_RENDER  (1<<2)
-#define  GDRST_MEDIA   (3<<2)
+
+/* Graphics reset regs */
+#define I965_GDRST 0xc0 /* PCI config register */
+#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define  GRDOM_FULL    (0<<2)
+#define  GRDOM_RENDER  (1<<2)
+#define  GRDOM_MEDIA   (3<<2)
 
 /* VGA stuff */
 
 #define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
 #define MI_LOAD_REGISTER_IMM   MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW            MI_INSTR(0x26, 2) /* for GEN6 */
 #define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE  (1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define MI_BATCH_BUFFER_START  MI_INSTR(0x31, 0)
-
 /*
  * 3D instructions used by the kernel
  */
 #define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
 #define   PIPE_CONTROL_STALL_EN        (1<<1) /* in addr word, Ironlake+ only */
 
+
+/*
+ * Reset registers
+ */
+#define DEBUG_RESET_I830               0x6070
+#define  DEBUG_RESET_FULL              (1<<7)
+#define  DEBUG_RESET_RENDER            (1<<8)
+#define  DEBUG_RESET_DISPLAY           (1<<9)
+
+
 /*
  * Fence registers
  */
 #define PRB0_HEAD      0x02034
 #define PRB0_START     0x02038
 #define PRB0_CTL       0x0203c
+#define RENDER_RING_BASE       0x02000
+#define BSD_RING_BASE          0x04000
+#define GEN6_BSD_RING_BASE     0x12000
+#define BLT_RING_BASE          0x22000
+#define RING_TAIL(base)                ((base)+0x30)
+#define RING_HEAD(base)                ((base)+0x34)
+#define RING_START(base)       ((base)+0x38)
+#define RING_CTL(base)         ((base)+0x3c)
+#define RING_HWS_PGA(base)     ((base)+0x80)
+#define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
+#define RING_ACTHD(base)       ((base)+0x74)
 #define   TAIL_ADDR            0x001FFFF8
 #define   HEAD_WRAP_COUNT      0xFFE00000
 #define   HEAD_WRAP_ONE                0x00200000
 #define   RING_VALID_MASK      0x00000001
 #define   RING_VALID           0x00000001
 #define   RING_INVALID         0x00000000
+#define   RING_WAIT_I8XX       (1<<0) /* gen2, PRBx_HEAD */
+#define   RING_WAIT            (1<<11) /* gen3+, PRBx_CTL */
 #define PRB1_TAIL      0x02040 /* 915+ only */
 #define PRB1_HEAD      0x02044 /* 915+ only */
 #define PRB1_START     0x02048 /* 915+ only */
 #define INSTDONE1      0x0207c /* 965+ only */
 #define ACTHD_I965     0x02074
 #define HWS_PGA                0x02080
-#define HWS_PGA_GEN6   0x04080
 #define HWS_ADDRESS_MASK       0xfffff000
 #define HWS_START_ADDRESS_SHIFT        4
 #define PWRCTXA                0x2088 /* 965GM+ only */
 #define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR     (1 << 25)
 #define   GEN6_BLITTER_SYNC_STATUS                     (1 << 24)
 #define   GEN6_BLITTER_USER_INTERRUPT                  (1 << 22)
-/*
- * BSD (bit stream decoder instruction and interrupt control register defines
- * (G4X and Ironlake only)
- */
 
-#define BSD_RING_TAIL          0x04030
-#define BSD_RING_HEAD          0x04034
-#define BSD_RING_START         0x04038
-#define BSD_RING_CTL           0x0403c
-#define BSD_RING_ACTHD         0x04074
-#define BSD_HWS_PGA            0x04080
+#define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK      (1 << 16)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE          (1 << 0)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE           0
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR                   (1 << 3)
+
+#define GEN6_BSD_IMR                   0x120a8
+#define   GEN6_BSD_IMR_USER_INTERRUPT  (1 << 12)
+
+#define GEN6_BSD_RNCID                 0x12198
 
 /*
  * Framebuffer compression (915+ only)
 # define GPIO_DATA_VAL_IN              (1 << 12)
 # define GPIO_DATA_PULLUP_DISABLE      (1 << 13)
 
-#define GMBUS0                 0x5100
-#define GMBUS1                 0x5104
-#define GMBUS2                 0x5108
-#define GMBUS3                 0x510c
-#define GMBUS4                 0x5110
-#define GMBUS5                 0x5120
+#define GMBUS0                 0x5100 /* clock/port select */
+#define   GMBUS_RATE_100KHZ    (0<<8)
+#define   GMBUS_RATE_50KHZ     (1<<8)
+#define   GMBUS_RATE_400KHZ    (2<<8) /* reserved on Pineview */
+#define   GMBUS_RATE_1MHZ      (3<<8) /* reserved on Pineview */
+#define   GMBUS_HOLD_EXT       (1<<7) /* 300ns hold time, rsvd on Pineview */
+#define   GMBUS_PORT_DISABLED  0
+#define   GMBUS_PORT_SSC       1
+#define   GMBUS_PORT_VGADDC    2
+#define   GMBUS_PORT_PANEL     3
+#define   GMBUS_PORT_DPC       4 /* HDMIC */
+#define   GMBUS_PORT_DPB       5 /* SDVO, HDMIB */
+                                 /* 6 reserved */
+#define   GMBUS_PORT_DPD       7 /* HDMID */
+#define   GMBUS_NUM_PORTS       8
+#define GMBUS1                 0x5104 /* command/status */
+#define   GMBUS_SW_CLR_INT     (1<<31)
+#define   GMBUS_SW_RDY         (1<<30)
+#define   GMBUS_ENT            (1<<29) /* enable timeout */
+#define   GMBUS_CYCLE_NONE     (0<<25)
+#define   GMBUS_CYCLE_WAIT     (1<<25)
+#define   GMBUS_CYCLE_INDEX    (2<<25)
+#define   GMBUS_CYCLE_STOP     (4<<25)
+#define   GMBUS_BYTE_COUNT_SHIFT 16
+#define   GMBUS_SLAVE_INDEX_SHIFT 8
+#define   GMBUS_SLAVE_ADDR_SHIFT 1
+#define   GMBUS_SLAVE_READ     (1<<0)
+#define   GMBUS_SLAVE_WRITE    (0<<0)
+#define GMBUS2                 0x5108 /* status */
+#define   GMBUS_INUSE          (1<<15)
+#define   GMBUS_HW_WAIT_PHASE  (1<<14)
+#define   GMBUS_STALL_TIMEOUT  (1<<13)
+#define   GMBUS_INT            (1<<12)
+#define   GMBUS_HW_RDY         (1<<11)
+#define   GMBUS_SATOER         (1<<10)
+#define   GMBUS_ACTIVE         (1<<9)
+#define GMBUS3                 0x510c /* data buffer bytes 3-0 */
+#define GMBUS4                 0x5110 /* interrupt mask (Pineview+) */
+#define   GMBUS_SLAVE_TIMEOUT_EN (1<<4)
+#define   GMBUS_NAK_EN         (1<<3)
+#define   GMBUS_IDLE_EN                (1<<2)
+#define   GMBUS_HW_WAIT_EN     (1<<1)
+#define   GMBUS_HW_RDY_EN      (1<<0)
+#define GMBUS5                 0x5120 /* byte index */
+#define   GMBUS_2BYTE_INDEX_EN (1<<31)
 
 /*
  * Clock control & power management
 #define   VGA1_PD_P1_MASK      (0x1f << 8)
 #define DPLL_A 0x06014
 #define DPLL_B 0x06018
+#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
 #define   DPLL_VCO_ENABLE              (1 << 31)
 #define   DPLL_DVO_HIGH_SPEED          (1 << 30)
 #define   DPLL_SYNCLOCK_ENABLE         (1 << 29)
 #define LVDS                   0x61180
 #define LVDS_ON                        (1<<31)
 
-#define ADPA                   0x61100
-#define ADPA_DPMS_MASK         (~(3<<10))
-#define ADPA_DPMS_ON           (0<<10)
-#define ADPA_DPMS_SUSPEND      (1<<10)
-#define ADPA_DPMS_STANDBY      (2<<10)
-#define ADPA_DPMS_OFF          (3<<10)
-
-#define RING_TAIL              0x00
-#define TAIL_ADDR              0x001FFFF8
-#define RING_HEAD              0x04
-#define HEAD_WRAP_COUNT                0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START             0x08
-#define START_ADDR             0xFFFFF000
-#define RING_LEN               0x0C
-#define RING_NR_PAGES          0x001FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K                0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK                0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
-
 /* Scratch pad debug 0 reg:
  */
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830     0x001f0000
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK      0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT     0
 #define DPLL_B_MD 0x06020 /* 965+ only */
+#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
 #define FPA0   0x06040
 #define FPA1   0x06044
 #define FPB0   0x06048
 #define FPB1   0x0604c
+#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
+#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
 #define   FP_N_DIV_MASK                0x003f0000
 #define   FP_N_PINEVIEW_DIV_MASK       0x00ff0000
 #define   FP_N_DIV_SHIFT               16
 #define   DPLLA_TEST_M_BYPASS          (1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE    (1 << 0)
 #define D_STATE                0x6104
+#define  DSTATE_GFX_RESET_I830                 (1<<6)
 #define  DSTATE_PLL_D3_OFF                     (1<<3)
 #define  DSTATE_GFX_CLOCK_GATING               (1<<1)
 #define  DSTATE_DOT_CLOCK_GATING               (1<<0)
 #define CLKCFG_MEM_800                                 (3 << 4)
 #define CLKCFG_MEM_MASK                                        (7 << 4)
 
+#define TSC1                   0x11001
+#define   TSE                  (1<<0)
 #define TR1                    0x11006
 #define TSFS                   0x11020
 #define   TSFS_SLOPE_MASK      0x0000ff00
 #define   MEMSTAT_SRC_CTL_STDBY 3
 #define RCPREVBSYTUPAVG                0x113b8
 #define RCPREVBSYTDNAVG                0x113bc
+#define PMMISC                 0x11214
+#define   MCPPCE_EN            (1<<0) /* enable PM_MSG from PCH->MPC */
 #define SDEW                   0x1124c
 #define CSIEW0                 0x11250
 #define CSIEW1                 0x11254
 #define PIPEBSRC       0x6101c
 #define BCLRPAT_B      0x61020
 
+#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
+#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
+#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
+#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
+#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
+#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
+#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
+
 /* VGA port control */
 #define ADPA                   0x61100
 #define   ADPA_DAC_ENABLE      (1<<31)
 #define   ADPA_DPMS_STANDBY    (2<<10)
 #define   ADPA_DPMS_OFF                (3<<10)
 
+
 /* Hotplug control (945+ only) */
 #define PORT_HOTPLUG_EN                0x61110
 #define   HDMIB_HOTPLUG_INT_EN                 (1 << 29)
 #define   LVDS_B0B3_POWER_DOWN         (0 << 2)
 #define   LVDS_B0B3_POWER_UP           (3 << 2)
 
+/* Video Data Island Packet control */
+#define VIDEO_DIP_DATA         0x61178
+#define VIDEO_DIP_CTL          0x61170
+#define   VIDEO_DIP_ENABLE             (1 << 31)
+#define   VIDEO_DIP_PORT_B             (1 << 29)
+#define   VIDEO_DIP_PORT_C             (2 << 29)
+#define   VIDEO_DIP_ENABLE_AVI         (1 << 21)
+#define   VIDEO_DIP_ENABLE_VENDOR      (2 << 21)
+#define   VIDEO_DIP_ENABLE_SPD         (8 << 21)
+#define   VIDEO_DIP_SELECT_AVI         (0 << 19)
+#define   VIDEO_DIP_SELECT_VENDOR      (1 << 19)
+#define   VIDEO_DIP_SELECT_SPD         (3 << 19)
+#define   VIDEO_DIP_FREQ_ONCE          (0 << 16)
+#define   VIDEO_DIP_FREQ_VSYNC         (1 << 16)
+#define   VIDEO_DIP_FREQ_2VSYNC                (2 << 16)
+
 /* Panel power sequencing */
 #define PP_STATUS      0x61200
 #define   PP_ON                (1 << 31)
 #define   PP_SEQUENCE_ON       (1 << 28)
 #define   PP_SEQUENCE_OFF      (2 << 28)
 #define   PP_SEQUENCE_MASK     0x30000000
+#define   PP_CYCLE_DELAY_ACTIVE        (1 << 27)
+#define   PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
+#define   PP_SEQUENCE_STATE_MASK 0x0000000f
 #define PP_CONTROL     0x61204
 #define   POWER_TARGET_ON      (1 << 0)
 #define PP_ON_DELAYS   0x61208
 # define TV_TEST_MODE_MASK             (7 << 0)
 
 #define TV_DAC                 0x68004
+# define TV_DAC_SAVE           0x00ffff00
 /**
  * Reports that DAC state change logic has reported change (RO).
  *
 
 /* Display & cursor control */
 
-/* dithering flag on Ironlake */
-#define PIPE_ENABLE_DITHER             (1 << 4)
-#define PIPE_DITHER_TYPE_MASK          (3 << 2)
-#define PIPE_DITHER_TYPE_SPATIAL       (0 << 2)
-#define PIPE_DITHER_TYPE_ST01          (1 << 2)
 /* Pipe A */
 #define PIPEADSL               0x70000
-#define   DSL_LINEMASK         0x00000fff
+#define   DSL_LINEMASK         0x00000fff
 #define PIPEACONF              0x70008
-#define   PIPEACONF_ENABLE     (1<<31)
-#define   PIPEACONF_DISABLE    0
-#define   PIPEACONF_DOUBLE_WIDE        (1<<30)
+#define   PIPECONF_ENABLE      (1<<31)
+#define   PIPECONF_DISABLE     0
+#define   PIPECONF_DOUBLE_WIDE (1<<30)
 #define   I965_PIPECONF_ACTIVE (1<<30)
-#define   PIPEACONF_SINGLE_WIDE        0
-#define   PIPEACONF_PIPE_UNLOCKED 0
-#define   PIPEACONF_PIPE_LOCKED        (1<<25)
-#define   PIPEACONF_PALETTE    0
-#define   PIPEACONF_GAMMA              (1<<24)
+#define   PIPECONF_SINGLE_WIDE 0
+#define   PIPECONF_PIPE_UNLOCKED 0
+#define   PIPECONF_PIPE_LOCKED (1<<25)
+#define   PIPECONF_PALETTE     0
+#define   PIPECONF_GAMMA               (1<<24)
 #define   PIPECONF_FORCE_BORDER        (1<<25)
 #define   PIPECONF_PROGRESSIVE (0 << 21)
 #define   PIPECONF_INTERLACE_W_FIELD_INDICATION        (6 << 21)
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY              (7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
+#define   PIPECONF_BPP_MASK    (0x000000e0)
+#define   PIPECONF_BPP_8       (0<<5)
+#define   PIPECONF_BPP_10      (1<<5)
+#define   PIPECONF_BPP_6       (2<<5)
+#define   PIPECONF_BPP_12      (3<<5)
+#define   PIPECONF_DITHER_EN   (1<<4)
+#define   PIPECONF_DITHER_TYPE_MASK (0x0000000c)
+#define   PIPECONF_DITHER_TYPE_SP (0<<2)
+#define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
+#define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
+#define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 #define PIPEASTAT              0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS            (1UL<<31)
 #define   PIPE_CRC_ERROR_ENABLE                        (1UL<<29)
 #define   PIPE_START_VBLANK_INTERRUPT_STATUS   (1UL<<2) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_STATUS         (1UL<<1)
 #define   PIPE_OVERLAY_UPDATED_STATUS          (1UL<<0)
-#define   PIPE_BPC_MASK                        (7 << 5) /* Ironlake */
+#define   PIPE_BPC_MASK                                (7 << 5) /* Ironlake */
 #define   PIPE_8BPC                            (0 << 5)
 #define   PIPE_10BPC                           (1 << 5)
 #define   PIPE_6BPC                            (2 << 5)
 #define   PIPE_12BPC                           (3 << 5)
 
+#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
+#define PIPEDSL(pipe)  _PIPE(pipe, PIPEADSL, PIPEBDSL)
+
 #define DSPARB                 0x70030
 #define   DSPARB_CSTART_MASK   (0x7f << 7)
 #define   DSPARB_CSTART_SHIFT  7
 #define  WM1_LP_SR_EN          (1<<31)
 #define  WM1_LP_LATENCY_SHIFT  24
 #define  WM1_LP_LATENCY_MASK   (0x7f<<24)
-#define  WM1_LP_FBC_LP1_MASK   (0xf<<20)
-#define  WM1_LP_FBC_LP1_SHIFT  20
+#define  WM1_LP_FBC_MASK       (0xf<<20)
+#define  WM1_LP_FBC_SHIFT      20
 #define  WM1_LP_SR_MASK                (0x1ff<<8)
 #define  WM1_LP_SR_SHIFT       8
 #define  WM1_LP_CURSOR_MASK    (0x3f)
 #define DSPASURF               0x7019C /* 965+ only */
 #define DSPATILEOFF            0x701A4 /* 965+ only */
 
+#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
+#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
+#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
+#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
+#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
+#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
+#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
+
 /* VBIOS flags */
 #define SWF00                  0x71410
 #define SWF01                  0x71414
 #define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
 
 #define FDI_PLL_BIOS_0  0x46000
+#define  FDI_PLL_FB_CLOCK_MASK  0xff
 #define FDI_PLL_BIOS_1  0x46004
 #define FDI_PLL_BIOS_2  0x46008
 #define DISPLAY_PORT_PLL_BIOS_0         0x4600c
 #define PIPEA_DATA_M1           0x60030
 #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
 #define  TU_SIZE_MASK           0x7e000000
-#define  PIPEA_DATA_M1_OFFSET   0
+#define  PIPE_DATA_M1_OFFSET    0
 #define PIPEA_DATA_N1           0x60034
-#define  PIPEA_DATA_N1_OFFSET   0
+#define  PIPE_DATA_N1_OFFSET    0
 
 #define PIPEA_DATA_M2           0x60038
-#define  PIPEA_DATA_M2_OFFSET   0
+#define  PIPE_DATA_M2_OFFSET    0
 #define PIPEA_DATA_N2           0x6003c
-#define  PIPEA_DATA_N2_OFFSET   0
+#define  PIPE_DATA_N2_OFFSET    0
 
 #define PIPEA_LINK_M1           0x60040
-#define  PIPEA_LINK_M1_OFFSET   0
+#define  PIPE_LINK_M1_OFFSET    0
 #define PIPEA_LINK_N1           0x60044
-#define  PIPEA_LINK_N1_OFFSET   0
+#define  PIPE_LINK_N1_OFFSET    0
 
 #define PIPEA_LINK_M2           0x60048
-#define  PIPEA_LINK_M2_OFFSET   0
+#define  PIPE_LINK_M2_OFFSET    0
 #define PIPEA_LINK_N2           0x6004c
-#define  PIPEA_LINK_N2_OFFSET   0
+#define  PIPE_LINK_N2_OFFSET    0
 
 /* PIPEB timing regs are same start from 0x61000 */
 
 #define PIPEB_DATA_M1           0x61030
-#define  PIPEB_DATA_M1_OFFSET   0
 #define PIPEB_DATA_N1           0x61034
-#define  PIPEB_DATA_N1_OFFSET   0
 
 #define PIPEB_DATA_M2           0x61038
-#define  PIPEB_DATA_M2_OFFSET   0
 #define PIPEB_DATA_N2           0x6103c
-#define  PIPEB_DATA_N2_OFFSET   0
 
 #define PIPEB_LINK_M1           0x61040
-#define  PIPEB_LINK_M1_OFFSET   0
 #define PIPEB_LINK_N1           0x61044
-#define  PIPEB_LINK_N1_OFFSET   0
 
 #define PIPEB_LINK_M2           0x61048
-#define  PIPEB_LINK_M2_OFFSET   0
 #define PIPEB_LINK_N2           0x6104c
-#define  PIPEB_LINK_N2_OFFSET   0
+
+#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
+#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
+#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
+#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
+#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
+#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
+#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
+#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
 
 /* CPU panel fitter */
 #define PFA_CTL_1               0x68080
 #define GT_SYNC_STATUS          (1 << 2)
 #define GT_USER_INTERRUPT       (1 << 0)
 #define GT_BSD_USER_INTERRUPT   (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT     (1 << 12)
+#define GT_BLT_USER_INTERRUPT  (1 << 22)
 
 #define GTISR   0x44010
 #define GTIMR   0x44014
 #define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
 #define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
 #define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
+#define SDE_HOTPLUG_MASK_CPT   (SDE_CRT_HOTPLUG_CPT |          \
+                                SDE_PORTD_HOTPLUG_CPT |        \
+                                SDE_PORTC_HOTPLUG_CPT |        \
+                                SDE_PORTB_HOTPLUG_CPT)
 
 #define SDEISR  0xc4000
 #define SDEIMR  0xc4004
 
 #define PCH_DPLL_A              0xc6014
 #define PCH_DPLL_B              0xc6018
+#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
 
 #define PCH_FPA0                0xc6040
 #define PCH_FPA1                0xc6044
 #define PCH_FPB0                0xc6048
 #define PCH_FPB1                0xc604c
+#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
+#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
 
 #define PCH_DPLL_TEST           0xc606c
 
 #define TRANS_VBLANK_B          0xe1010
 #define TRANS_VSYNC_B           0xe1014
 
+#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
+#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
+#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
+#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
+#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
+#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
+
 #define TRANSB_DATA_M1          0xe1030
 #define TRANSB_DATA_N1          0xe1034
 #define TRANSB_DATA_M2          0xe1038
 
 #define TRANSACONF              0xf0008
 #define TRANSBCONF              0xf1008
+#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
 #define FDI_RXA_CHICKEN         0xc200c
 #define FDI_RXB_CHICKEN         0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, FDI_RXA_CHICKEN, FDI_RXB_CHICKEN)
+
+#define SOUTH_DSPCLK_GATE_D    0xc2020
+#define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
 
 /* CPU: FDI_TX */
 #define FDI_TXA_CTL             0x60100
 #define FDI_TXB_CTL             0x61100
+#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
 #define  FDI_TX_DISABLE         (0<<31)
 #define  FDI_TX_ENABLE          (1<<31)
 #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
 /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 #define FDI_RXA_CTL             0xf000c
 #define FDI_RXB_CTL             0xf100c
+#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
-#define  FDI_RX_DISABLE         (0<<31)
 /* train, dp width same as FDI_TX */
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
 #define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
-#define  FDI_SEL_RAWCLK                 (0<<4)
-#define  FDI_SEL_PCDCLK                 (1<<4)
+#define  FDI_PCDCLK                    (1<<4)
 /* CPT */
 #define  FDI_AUTO_TRAINING                     (1<<10)
 #define  FDI_LINK_TRAIN_PATTERN_1_CPT          (0<<8)
 #define FDI_RXA_TUSIZE2         0xf0038
 #define FDI_RXB_TUSIZE1         0xf1030
 #define FDI_RXB_TUSIZE2         0xf1038
+#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
+#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
 
 /* FDI_RX interrupt register format */
 #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
 #define FDI_RXA_IMR             0xf0018
 #define FDI_RXB_IIR             0xf1014
 #define FDI_RXB_IMR             0xf1018
+#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
 
 #define FDI_PLL_CTL_1           0xfe000
 #define FDI_PLL_CTL_2           0xfe004
 #define TRANS_DP_CTL_A         0xe0300
 #define TRANS_DP_CTL_B         0xe1300
 #define TRANS_DP_CTL_C         0xe2300
+#define TRANS_DP_CTL(pipe)     (TRANS_DP_CTL_A + (pipe) * 0x01000)
 #define  TRANS_DP_OUTPUT_ENABLE        (1<<31)
 #define  TRANS_DP_PORT_SEL_B   (0<<29)
 #define  TRANS_DP_PORT_SEL_C   (1<<29)
index 31f08581e93a46dbdc2ca1cfa563faec31e9ffc5..989c19d2d959b6bc6c54a0e4bf31d9aee093efe6 100644 (file)
@@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
                dev_priv->saveFPA1 = I915_READ(FPA1);
                dev_priv->saveDPLL_A = I915_READ(DPLL_A);
        }
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
        dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
        dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
@@ -294,7 +294,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
        dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
        dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
        dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                dev_priv->saveDSPASURF = I915_READ(DSPASURF);
                dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
        }
@@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
                dev_priv->saveFPB1 = I915_READ(FPB1);
                dev_priv->saveDPLL_B = I915_READ(DPLL_B);
        }
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
        dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
        dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
@@ -351,7 +351,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
        dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
        dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
        dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
-       if (IS_I965GM(dev) || IS_GM45(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
                dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
        }
@@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
        POSTING_READ(dpll_a_reg);
        udelay(150);
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
                POSTING_READ(DPLL_A_MD);
        }
@@ -448,7 +448,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
        I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
        I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
                I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
        }
@@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
        POSTING_READ(dpll_b_reg);
        udelay(150);
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
                POSTING_READ(DPLL_B_MD);
        }
@@ -517,7 +517,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
        I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
        I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
                I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
        }
@@ -550,7 +550,7 @@ void i915_save_display(struct drm_device *dev)
        dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
        dev_priv->saveCURBPOS = I915_READ(CURBPOS);
        dev_priv->saveCURBBASE = I915_READ(CURBBASE);
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                dev_priv->saveCURSIZE = I915_READ(CURSIZE);
 
        /* CRT state */
@@ -573,7 +573,7 @@ void i915_save_display(struct drm_device *dev)
                dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
                dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
                dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
                if (IS_MOBILE(dev) && !IS_I830(dev))
                        dev_priv->saveLVDS = I915_READ(LVDS);
@@ -664,7 +664,7 @@ void i915_restore_display(struct drm_device *dev)
        I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
        I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
        I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
 
        /* CRT state */
@@ -674,7 +674,7 @@ void i915_restore_display(struct drm_device *dev)
                I915_WRITE(ADPA, dev_priv->saveADPA);
 
        /* LVDS state */
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
 
        if (HAS_PCH_SPLIT(dev)) {
@@ -878,9 +878,7 @@ int i915_restore_state(struct drm_device *dev)
        for (i = 0; i < 3; i++)
                I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
 
-       /* I2C state */
-       intel_i2c_reset_gmbus(dev);
+       intel_i2c_reset(dev);
 
        return 0;
 }
-
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
new file mode 100644 (file)
index 0000000..65c88f9
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Intel ACPI functions
+ *
+ * _DSM related code stolen from nouveau_acpi.c.
+ */
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/vga_switcheroo.h>
+#include <acpi/acpi_drivers.h>
+
+#include "drmP.h"
+
+#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
+
+#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
+#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
+
+static struct intel_dsm_priv {
+       acpi_handle dhandle;
+} intel_dsm_priv;
+
+static const u8 intel_dsm_guid[] = {
+       0xd3, 0x73, 0xd8, 0x7e,
+       0xd0, 0xc2,
+       0x4f, 0x4e,
+       0xa8, 0x54,
+       0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
+};
+
+static int intel_dsm(acpi_handle handle, int func, int arg)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       u32 result;
+       int ret = 0;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = arg;
+
+       ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               return ret;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       result = 0;
+       switch (obj->type) {
+       case ACPI_TYPE_INTEGER:
+               result = obj->integer.value;
+               break;
+
+       case ACPI_TYPE_BUFFER:
+               if (obj->buffer.length == 4) {
+                       result =(obj->buffer.pointer[0] |
+                               (obj->buffer.pointer[1] <<  8) |
+                               (obj->buffer.pointer[2] << 16) |
+                               (obj->buffer.pointer[3] << 24));
+                       break;
+               }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       if (result == 0x80000002)
+               ret = -ENODEV;
+
+       kfree(output.pointer);
+       return ret;
+}
+
+static char *intel_dsm_port_name(u8 id)
+{
+       switch (id) {
+       case 0:
+               return "Reserved";
+       case 1:
+               return "Analog VGA";
+       case 2:
+               return "LVDS";
+       case 3:
+               return "Reserved";
+       case 4:
+               return "HDMI/DVI_B";
+       case 5:
+               return "HDMI/DVI_C";
+       case 6:
+               return "HDMI/DVI_D";
+       case 7:
+               return "DisplayPort_A";
+       case 8:
+               return "DisplayPort_B";
+       case 9:
+               return "DisplayPort_C";
+       case 0xa:
+               return "DisplayPort_D";
+       case 0xb:
+       case 0xc:
+       case 0xd:
+               return "Reserved";
+       case 0xe:
+               return "WiDi";
+       default:
+               return "bad type";
+       }
+}
+
+static char *intel_dsm_mux_type(u8 type)
+{
+       switch (type) {
+       case 0:
+               return "unknown";
+       case 1:
+               return "No MUX, iGPU only";
+       case 2:
+               return "No MUX, dGPU only";
+       case 3:
+               return "MUXed between iGPU and dGPU";
+       default:
+               return "bad type";
+       }
+}
+
+static void intel_dsm_platform_mux_info(void)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *pkg;
+       int i, ret;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = 0;
+
+       ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
+                                  &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               goto out;
+       }
+
+       pkg = (union acpi_object *)output.pointer;
+
+       if (pkg->type == ACPI_TYPE_PACKAGE) {
+               union acpi_object *connector_count = &pkg->package.elements[0];
+               DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
+                         (unsigned long long)connector_count->integer.value);
+               for (i = 1; i < pkg->package.count; i++) {
+                       union acpi_object *obj = &pkg->package.elements[i];
+                       union acpi_object *connector_id =
+                               &obj->package.elements[0];
+                       union acpi_object *info = &obj->package.elements[1];
+                       DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
+                                 (unsigned long long)connector_id->integer.value);
+                       DRM_DEBUG_DRIVER("  port id: %s\n",
+                              intel_dsm_port_name(info->buffer.pointer[0]));
+                       DRM_DEBUG_DRIVER("  display mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[1]));
+                       DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[2]));
+                       DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[3]));
+               }
+       } else {
+               DRM_ERROR("MUX INFO call failed\n");
+       }
+
+out:
+       kfree(output.pointer);
+}
+
+static int intel_dsm_switchto(enum vga_switcheroo_client_id id)
+{
+       return 0;
+}
+
+static int intel_dsm_power_state(enum vga_switcheroo_client_id id,
+                                enum vga_switcheroo_state state)
+{
+       return 0;
+}
+
+static int intel_dsm_init(void)
+{
+       return 0;
+}
+
+static int intel_dsm_get_client_id(struct pci_dev *pdev)
+{
+       if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+               return VGA_SWITCHEROO_IGD;
+       else
+               return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler intel_dsm_handler = {
+       .switchto = intel_dsm_switchto,
+       .power_state = intel_dsm_power_state,
+       .init = intel_dsm_init,
+       .get_client_id = intel_dsm_get_client_id,
+};
+
+static bool intel_dsm_pci_probe(struct pci_dev *pdev)
+{
+       acpi_handle dhandle, intel_handle;
+       acpi_status status;
+       int ret;
+
+       dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!dhandle)
+               return false;
+
+       status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
+       if (ACPI_FAILURE(status)) {
+               DRM_DEBUG_KMS("no _DSM method for intel device\n");
+               return false;
+       }
+
+       ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
+       if (ret < 0) {
+               DRM_ERROR("failed to get supported _DSM functions\n");
+               return false;
+       }
+
+       intel_dsm_priv.dhandle = dhandle;
+
+       intel_dsm_platform_mux_info();
+       return true;
+}
+
+static bool intel_dsm_detect(void)
+{
+       char acpi_method_name[255] = { 0 };
+       struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+       struct pci_dev *pdev = NULL;
+       bool has_dsm = false;
+       int vga_count = 0;
+
+       while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+               vga_count++;
+               has_dsm |= intel_dsm_pci_probe(pdev);
+       }
+
+       if (vga_count == 2 && has_dsm) {
+               acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+               DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+                                acpi_method_name);
+               return true;
+       }
+
+       return false;
+}
+
+void intel_register_dsm_handler(void)
+{
+       if (!intel_dsm_detect())
+               return;
+
+       vga_switcheroo_register_handler(&intel_dsm_handler);
+}
+
+void intel_unregister_dsm_handler(void)
+{
+       vga_switcheroo_unregister_handler();
+}
index 96f75d7f663319c77ed5f77d279c8cc4794591d2..b0b1200ed6500055b05bc1e51a932df26b6600ef 100644 (file)
@@ -24,6 +24,7 @@
  *    Eric Anholt <eric@anholt.net>
  *
  */
+#include <drm/drm_dp_helper.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
@@ -129,10 +130,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        int i, temp_downclock;
        struct drm_display_mode *temp_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;
@@ -140,6 +137,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        dev_priv->lvds_dither = lvds_options->pixel_dither;
        if (lvds_options->panel_type == 0xff)
                return;
+
        panel_type = lvds_options->panel_type;
 
        lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
@@ -169,6 +167,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                        ((unsigned char *)entry + dvo_timing_offset);
 
        panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+       if (!panel_fixed_mode)
+               return;
 
        fill_detail_timing_data(panel_fixed_mode, dvo_timing);
 
@@ -230,8 +230,6 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
        struct lvds_dvo_timing *dvo_timing;
        struct drm_display_mode *panel_fixed_mode;
 
-       dev_priv->sdvo_lvds_vbt_mode = NULL;
-
        sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
        if (!sdvo_lvds_options)
                return;
@@ -260,10 +258,6 @@ parse_general_features(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        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;
@@ -271,10 +265,10 @@ parse_general_features(struct drm_i915_private *dev_priv,
                dev_priv->lvds_use_ssc = general->enable_ssc;
 
                if (dev_priv->lvds_use_ssc) {
-                       if (IS_I85X(dev_priv->dev))
+                       if (IS_I85X(dev))
                                dev_priv->lvds_ssc_freq =
                                        general->ssc_freq ? 66 : 48;
-                       else if (IS_IRONLAKE(dev_priv->dev) || IS_GEN6(dev))
+                       else if (IS_GEN5(dev) || IS_GEN6(dev))
                                dev_priv->lvds_ssc_freq =
                                        general->ssc_freq ? 100 : 120;
                        else
@@ -289,14 +283,6 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                          struct bdb_header *bdb)
 {
        struct bdb_general_definitions *general;
-       const int crt_bus_map_table[] = {
-               GPIOB,
-               GPIOA,
-               GPIOC,
-               GPIOD,
-               GPIOE,
-               GPIOF,
-       };
 
        general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (general) {
@@ -304,10 +290,8 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                if (block_size >= sizeof(*general)) {
                        int bus_pin = general->crt_ddc_gmbus_pin;
                        DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
-                       if ((bus_pin >= 1) && (bus_pin <= 6)) {
-                               dev_priv->crt_ddc_bus =
-                                       crt_bus_map_table[bus_pin-1];
-                       }
+                       if (bus_pin >= 1 && bus_pin <= 6)
+                               dev_priv->crt_ddc_pin = bus_pin;
                } else {
                        DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
                                  block_size);
@@ -317,7 +301,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
 
 static void
 parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
-                      struct bdb_header *bdb)
+                         struct bdb_header *bdb)
 {
        struct sdvo_device_mapping *p_mapping;
        struct bdb_general_definitions *p_defs;
@@ -327,7 +311,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
-               DRM_DEBUG_KMS("No general definition block is found\n");
+               DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
                return;
        }
        /* judge whether the size of child device meets the requirements.
@@ -377,7 +361,16 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
                        p_mapping->slave_addr = p_child->slave_addr;
                        p_mapping->dvo_wiring = p_child->dvo_wiring;
                        p_mapping->ddc_pin = p_child->ddc_pin;
+                       p_mapping->i2c_pin = p_child->i2c_pin;
+                       p_mapping->i2c_speed = p_child->i2c_speed;
                        p_mapping->initialized = 1;
+                       DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
+                                     p_mapping->dvo_port,
+                                     p_mapping->slave_addr,
+                                     p_mapping->dvo_wiring,
+                                     p_mapping->ddc_pin,
+                                     p_mapping->i2c_pin,
+                                     p_mapping->i2c_speed);
                } else {
                        DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
                                         "two SDVO device.\n");
@@ -409,14 +402,11 @@ parse_driver_features(struct drm_i915_private *dev_priv,
        if (!driver)
                return;
 
-       if (driver && SUPPORTS_EDP(dev) &&
-           driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
-               dev_priv->edp_support = 1;
-       } else {
-               dev_priv->edp_support = 0;
-       }
+       if (SUPPORTS_EDP(dev) &&
+           driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+               dev_priv->edp.support = 1;
 
-       if (driver && driver->dual_frequency)
+       if (driver->dual_frequency)
                dev_priv->render_reclock_avail = true;
 }
 
@@ -424,27 +414,78 @@ static void
 parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
        struct bdb_edp *edp;
+       struct edp_power_seq *edp_pps;
+       struct edp_link_params *edp_link_params;
 
        edp = find_section(bdb, BDB_EDP);
        if (!edp) {
-               if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+               if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
                        DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
-                                     "supported, assume 18bpp panel color "
-                                     "depth.\n");
-                       dev_priv->edp_bpp = 18;
+                                     "supported, assume %dbpp panel color "
+                                     "depth.\n",
+                                     dev_priv->edp.bpp);
                }
                return;
        }
 
        switch ((edp->color_depth >> (panel_type * 2)) & 3) {
        case EDP_18BPP:
-               dev_priv->edp_bpp = 18;
+               dev_priv->edp.bpp = 18;
                break;
        case EDP_24BPP:
-               dev_priv->edp_bpp = 24;
+               dev_priv->edp.bpp = 24;
                break;
        case EDP_30BPP:
-               dev_priv->edp_bpp = 30;
+               dev_priv->edp.bpp = 30;
+               break;
+       }
+
+       /* Get the eDP sequencing and link info */
+       edp_pps = &edp->power_seqs[panel_type];
+       edp_link_params = &edp->link_params[panel_type];
+
+       dev_priv->edp.pps = *edp_pps;
+
+       dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+               DP_LINK_BW_1_62;
+       switch (edp_link_params->lanes) {
+       case 0:
+               dev_priv->edp.lanes = 1;
+               break;
+       case 1:
+               dev_priv->edp.lanes = 2;
+               break;
+       case 3:
+       default:
+               dev_priv->edp.lanes = 4;
+               break;
+       }
+       switch (edp_link_params->preemphasis) {
+       case 0:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+               break;
+       case 1:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+               break;
+       case 2:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+               break;
+       case 3:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+               break;
+       }
+       switch (edp_link_params->vswing) {
+       case 0:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+               break;
+       case 1:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+               break;
+       case 2:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+               break;
+       case 3:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
                break;
        }
 }
@@ -460,7 +501,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
-               DRM_DEBUG_KMS("No general definition block is found\n");
+               DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
                return;
        }
        /* judge whether the size of child device meets the requirements.
@@ -513,50 +554,83 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
        }
        return;
 }
+
+static void
+init_vbt_defaults(struct drm_i915_private *dev_priv)
+{
+       dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+
+       /* LFP panel data */
+       dev_priv->lvds_dither = 1;
+       dev_priv->lvds_vbt = 0;
+
+       /* SDVO panel data */
+       dev_priv->sdvo_lvds_vbt_mode = NULL;
+
+       /* general features */
+       dev_priv->int_tv_support = 1;
+       dev_priv->int_crt_support = 1;
+       dev_priv->lvds_use_ssc = 0;
+
+       /* eDP data */
+       dev_priv->edp.bpp = 18;
+}
+
 /**
- * intel_init_bios - initialize VBIOS settings & find VBT
+ * intel_parse_bios - find VBT and initialize settings from the BIOS
  * @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)
+intel_parse_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;
-               }
+       struct bdb_header *bdb = NULL;
+       u8 __iomem *bios = NULL;
+
+       init_vbt_defaults(dev_priv);
+
+       /* XXX Should this validation be moved to intel_opregion.c? */
+       if (dev_priv->opregion.vbt) {
+               struct vbt_header *vbt = dev_priv->opregion.vbt;
+               if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+                       DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
+                                        vbt->signature);
+                       bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+               } else
+                       dev_priv->opregion.vbt = NULL;
        }
 
-       if (!vbt) {
-               DRM_ERROR("VBT signature missing\n");
-               pci_unmap_rom(pdev, bios);
-               return -1;
-       }
+       if (bdb == NULL) {
+               struct vbt_header *vbt = NULL;
+               size_t size;
+               int i;
 
-       bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+               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);
@@ -568,7 +642,25 @@ intel_init_bios(struct drm_device *dev)
        parse_driver_features(dev_priv, bdb);
        parse_edp(dev_priv, bdb);
 
-       pci_unmap_rom(pdev, bios);
+       if (bios)
+               pci_unmap_rom(pdev, bios);
 
        return 0;
 }
+
+/* Ensure that vital registers have been initialised, even if the BIOS
+ * is absent or just failing to do its job.
+ */
+void intel_setup_bios(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+        /* Set the Panel Power On/Off timings if uninitialized. */
+       if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
+               /* Set T2 to 40ms and T5 to 200ms */
+               I915_WRITE(PP_ON_DELAYS, 0x019007d0);
+
+               /* Set T3 to 35ms and Tx to 200ms */
+               I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
+       }
+}
index 4c18514f6f80f469d15a039ef47d37bd0e249ce4..5f8e4edcbbb901937a20a522f60057ea762a0a9d 100644 (file)
@@ -197,7 +197,8 @@ struct bdb_general_features {
 struct child_device_config {
        u16 handle;
        u16 device_type;
-       u8  device_id[10]; /* See DEVICE_TYPE_* above */
+       u8  i2c_speed;
+       u8  rsvd[9];
        u16 addin_offset;
        u8  dvo_port; /* See Device_PORT_* above */
        u8  i2c_pin;
@@ -466,7 +467,8 @@ struct bdb_edp {
        struct edp_link_params link_params[16];
 } __attribute__ ((packed));
 
-bool intel_init_bios(struct drm_device *dev);
+void intel_setup_bios(struct drm_device *dev);
+bool intel_parse_bios(struct drm_device *dev);
 
 /*
  * Driver<->VBIOS interaction occurs through scratch bits in
index 197d4f32585a59b5b336328b470fa038bc922781..c55c77043357cb0243a4b368a1e6d63b7a4af398 100644 (file)
@@ -79,7 +79,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
        if (mode->clock < 25000)
                return MODE_CLOCK_LOW;
 
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                max_clock = 350000;
        else
                max_clock = 400000;
@@ -123,7 +123,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
         * 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) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                dpll_md = I915_READ(dpll_md_reg);
                I915_WRITE(dpll_md_reg,
                           dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -187,11 +187,12 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
        I915_WRITE(PCH_ADPA, adpa);
 
        if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
-                    1000, 1))
+                    1000))
                DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
 
        if (turn_off_dac) {
-               I915_WRITE(PCH_ADPA, temp);
+               /* Make sure hotplug is enabled */
+               I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
                (void)I915_READ(PCH_ADPA);
        }
 
@@ -244,7 +245,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
                /* wait for FORCE_DETECT to go off */
                if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
                              CRT_HOTPLUG_FORCE_DETECT) == 0,
-                            1000, 1))
+                            1000))
                        DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
        }
 
@@ -261,21 +262,47 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        return ret;
 }
 
+static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
+{
+       u8 buf;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0xA0,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &buf,
+               },
+       };
+       /* DDC monitor detect: Does it ACK a write to 0xA0? */
+       return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
+}
+
 static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 
        /* CRT should always be at 0, but check anyway */
        if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
                return false;
 
-       return intel_ddc_probe(intel_encoder);
+       if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
+               DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n");
+               return true;
+       }
+
+       if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+               DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+               return true;
+       }
+
+       return false;
 }
 
 static enum drm_connector_status
 intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
 {
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -295,6 +322,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
        uint8_t st00;
        enum drm_connector_status status;
 
+       DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
        if (pipe == 0) {
                bclrpat_reg = BCLRPAT_A;
                vtotal_reg = VTOTAL_A;
@@ -324,9 +353,10 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
        /* Set the border color to purple. */
        I915_WRITE(bclrpat_reg, 0x500050);
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                uint32_t pipeconf = I915_READ(pipeconf_reg);
                I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+               POSTING_READ(pipeconf_reg);
                /* Wait for next Vblank to substitue
                 * border color for Color info */
                intel_wait_for_vblank(dev, pipe);
@@ -404,34 +434,37 @@ static enum drm_connector_status
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_encoder *encoder = intel_attached_encoder(connector);
        struct drm_crtc *crtc;
        int dpms_mode;
        enum drm_connector_status status;
 
-       if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
-               if (intel_crt_detect_hotplug(connector))
+       if (I915_HAS_HOTPLUG(dev)) {
+               if (intel_crt_detect_hotplug(connector)) {
+                       DRM_DEBUG_KMS("CRT detected via hotplug\n");
                        return connector_status_connected;
-               else
+               else
                        return connector_status_disconnected;
        }
 
-       if (intel_crt_detect_ddc(encoder))
+       if (intel_crt_detect_ddc(&encoder->base))
                return connector_status_connected;
 
        if (!force)
                return connector->status;
 
        /* for pre-945g platforms use load detect */
-       if (encoder->crtc && encoder->crtc->enabled) {
-               status = intel_crt_load_detect(encoder->crtc, intel_encoder);
+       if (encoder->base.crtc && encoder->base.crtc->enabled) {
+               status = intel_crt_load_detect(encoder->base.crtc, encoder);
        } else {
-               crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+               crtc = intel_get_load_detect_pipe(encoder, connector,
                                                  NULL, &dpms_mode);
                if (crtc) {
-                       status = intel_crt_load_detect(crtc, intel_encoder);
-                       intel_release_load_detect_pipe(intel_encoder,
+                       if (intel_crt_detect_ddc(&encoder->base))
+                               status = connector_status_connected;
+                       else
+                               status = intel_crt_load_detect(crtc, encoder);
+                       intel_release_load_detect_pipe(encoder,
                                                       connector, dpms_mode);
                } else
                        status = connector_status_unknown;
@@ -449,32 +482,18 @@ static void intel_crt_destroy(struct drm_connector *connector)
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
-       int ret;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct i2c_adapter *ddc_bus;
        struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-
-       ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+       ret = intel_ddc_get_modes(connector,
+                                &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
        if (ret || !IS_G4X(dev))
-               goto end;
+               return ret;
 
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
-       ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
-
-       if (!ddc_bus) {
-               dev_printk(KERN_ERR, &connector->dev->pdev->dev,
-                          "DDC bus registration failed for CRTDDC_D.\n");
-               goto end;
-       }
-       /* Try to get modes by GPIOD port */
-       ret = intel_ddc_get_modes(connector, ddc_bus);
-       intel_i2c_destroy(ddc_bus);
-
-end:
-       return ret;
-
+       return intel_ddc_get_modes(connector,
+                                  &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,7 +526,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
 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_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -520,7 +539,6 @@ void intel_crt_init(struct drm_device *dev)
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 i2c_reg;
 
        intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
        if (!intel_encoder)
@@ -536,27 +554,10 @@ void intel_crt_init(struct drm_device *dev)
        drm_connector_init(dev, &intel_connector->base,
                           &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
                         DRM_MODE_ENCODER_DAC);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
-
-       /* Set up the DDC bus. */
-       if (HAS_PCH_SPLIT(dev))
-               i2c_reg = PCH_GPIOA;
-       else {
-               i2c_reg = GPIOA;
-               /* Use VBT information for CRT DDC if available */
-               if (dev_priv->crt_ddc_bus != 0)
-                       i2c_reg = dev_priv->crt_ddc_bus;
-       }
-       intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
-       if (!intel_encoder->ddc_bus) {
-               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-                          "failed.\n");
-               return;
-       }
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
 
        intel_encoder->type = INTEL_OUTPUT_ANALOG;
        intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
@@ -566,7 +567,7 @@ void intel_crt_init(struct drm_device *dev)
        connector->interlace_allowed = 1;
        connector->doublescan_allowed = 0;
 
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);
index 979228594599a28ac7737762679f1c97fd5981bf..990f065374b22eacfc2fcddd68c873a5081ee773 100644 (file)
@@ -43,8 +43,8 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
     /* given values */
@@ -342,6 +342,16 @@ static bool
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
                           int target, int refclk, intel_clock_t *best_clock);
 
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+       if (IS_GEN5(dev)) {
+               struct drm_i915_private *dev_priv = dev->dev_private;
+               return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+       } else
+               return 27;
+}
+
 static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
@@ -701,16 +711,16 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
                limit = intel_ironlake_limit(crtc);
        else if (IS_G4X(dev)) {
                limit = intel_g4x_limit(crtc);
-       } else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) {
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits_i9xx_lvds;
-               else
-                       limit = &intel_limits_i9xx_sdvo;
        } else if (IS_PINEVIEW(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_pineview_lvds;
                else
                        limit = &intel_limits_pineview_sdvo;
+       } else if (!IS_GEN2(dev)) {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits_i9xx_lvds;
+               else
+                       limit = &intel_limits_i9xx_sdvo;
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
@@ -744,20 +754,17 @@ static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *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)
+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_encoder *l_entry;
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
 
-    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
-           if (l_entry && l_entry->crtc == crtc) {
-                   struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
-                   if (intel_encoder->type == type)
-                           return true;
-           }
-    }
-    return false;
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->base.crtc == crtc && encoder->type == type)
+                       return true;
+
+       return false;
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -928,10 +935,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        intel_clock_t clock;
 
-       /* return directly when it is eDP */
-       if (HAS_eDP)
-               return true;
-
        if (target < 200000) {
                clock.n = 1;
                clock.p1 = 2;
@@ -955,26 +958,26 @@ static bool
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
                      int target, int refclk, intel_clock_t *best_clock)
 {
-    intel_clock_t clock;
-    if (target < 200000) {
-       clock.p1 = 2;
-       clock.p2 = 10;
-       clock.n = 2;
-       clock.m1 = 23;
-       clock.m2 = 8;
-    } else {
-       clock.p1 = 1;
-       clock.p2 = 10;
-       clock.n = 1;
-       clock.m1 = 14;
-       clock.m2 = 2;
-    }
-    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
-    clock.p = (clock.p1 * clock.p2);
-    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
-    clock.vco = 0;
-    memcpy(best_clock, &clock, sizeof(intel_clock_t));
-    return true;
+       intel_clock_t clock;
+       if (target < 200000) {
+               clock.p1 = 2;
+               clock.p2 = 10;
+               clock.n = 2;
+               clock.m1 = 23;
+               clock.m2 = 8;
+       } else {
+               clock.p1 = 1;
+               clock.p2 = 10;
+               clock.n = 1;
+               clock.m1 = 14;
+               clock.m2 = 2;
+       }
+       clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+       clock.p = (clock.p1 * clock.p2);
+       clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+       clock.vco = 0;
+       memcpy(best_clock, &clock, sizeof(intel_clock_t));
+       return true;
 }
 
 /**
@@ -1007,9 +1010,9 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
                   I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
 
        /* Wait for vblank interrupt bit to set */
-       if (wait_for((I915_READ(pipestat_reg) &
-                     PIPE_VBLANK_INTERRUPT_STATUS),
-                    50, 0))
+       if (wait_for(I915_READ(pipestat_reg) &
+                    PIPE_VBLANK_INTERRUPT_STATUS,
+                    50))
                DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
@@ -1028,36 +1031,35 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
  * Otherwise:
  *   wait for the display line value to settle (it usually
  *   ends up stopping at the start of the next frame).
- *  
+ *
  */
-static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
+void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (INTEL_INFO(dev)->gen >= 4) {
-               int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);
+               int reg = PIPECONF(pipe);
 
                /* Wait for the Pipe State to go off */
-               if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
-                            100, 0))
+               if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
+                            100))
                        DRM_DEBUG_KMS("pipe_off wait timed out\n");
        } else {
                u32 last_line;
-               int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
+               int reg = PIPEDSL(pipe);
                unsigned long timeout = jiffies + msecs_to_jiffies(100);
 
                /* Wait for the display line to settle */
                do {
-                       last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+                       last_line = I915_READ(reg) & DSL_LINEMASK;
                        mdelay(5);
-               } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
+               } while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
                         time_after(timeout, jiffies));
                if (time_after(jiffies, timeout))
                        DRM_DEBUG_KMS("pipe_off wait timed out\n");
        }
 }
 
-/* Parameters have changed, update FBC info */
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct drm_device *dev = crtc->dev;
@@ -1069,6 +1071,14 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        int plane, i;
        u32 fbc_ctl, fbc_ctl2;
 
+       if (fb->pitch == dev_priv->cfb_pitch &&
+           obj_priv->fence_reg == dev_priv->cfb_fence &&
+           intel_crtc->plane == dev_priv->cfb_plane &&
+           I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+               return;
+
+       i8xx_disable_fbc(dev);
+
        dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
 
        if (fb->pitch < dev_priv->cfb_pitch)
@@ -1102,7 +1112,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-                 dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+                     dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
 void i8xx_disable_fbc(struct drm_device *dev)
@@ -1110,19 +1120,16 @@ void i8xx_disable_fbc(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 fbc_ctl;
 
-       if (!I915_HAS_FBC(dev))
-               return;
-
-       if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
-               return; /* Already off, just return */
-
        /* Disable compression */
        fbc_ctl = I915_READ(FBC_CONTROL);
+       if ((fbc_ctl & FBC_CTL_EN) == 0)
+               return;
+
        fbc_ctl &= ~FBC_CTL_EN;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        /* Wait for compressing bit to clear */
-       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
                DRM_DEBUG_KMS("FBC idle timed out\n");
                return;
        }
@@ -1145,14 +1152,27 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
-                    DPFC_CTL_PLANEB);
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_y = crtc->y;
 
        dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1162,7 +1182,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1181,10 +1200,12 @@ void g4x_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1202,16 +1223,30 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
-                                              DPFC_CTL_PLANEB;
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_offset == obj_priv->gtt_offset &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(ILK_DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_offset = obj_priv->gtt_offset;
+       dev_priv->cfb_y = crtc->y;
 
-       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
        dpfc_ctl &= DPFC_RESERVED;
        dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1221,15 +1256,13 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
        I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
        /* enable it... */
-       I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
-                  DPFC_CTL_EN);
+       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
@@ -1241,10 +1274,12 @@ void ironlake_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1286,8 +1321,7 @@ void intel_disable_fbc(struct drm_device *dev)
 
 /**
  * intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
  *
  * Set up the framebuffer compression hardware at mode set time.  We
  * enable it if possible:
@@ -1304,18 +1338,14 @@ void intel_disable_fbc(struct drm_device *dev)
  *
  * We need to enable/disable FBC on a global basis.
  */
-static void intel_update_fbc(struct drm_crtc *crtc,
-                            struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       struct intel_crtc *intel_crtc;
+       struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj_priv;
-       struct drm_crtc *tmp_crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = intel_crtc->plane;
-       int crtcs_enabled = 0;
 
        DRM_DEBUG_KMS("\n");
 
@@ -1325,12 +1355,6 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (!I915_HAS_FBC(dev))
                return;
 
-       if (!crtc->fb)
-               return;
-
-       intel_fb = to_intel_framebuffer(fb);
-       obj_priv = to_intel_bo(intel_fb->obj);
-
        /*
         * If FBC is already on, we just have to verify that we can
         * keep it that way...
@@ -1341,35 +1365,47 @@ static void intel_update_fbc(struct drm_crtc *crtc,
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
        list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-               if (tmp_crtc->enabled)
-                       crtcs_enabled++;
+               if (tmp_crtc->enabled) {
+                       if (crtc) {
+                               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+                               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+                               goto out_disable;
+                       }
+                       crtc = tmp_crtc;
+               }
        }
-       DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
-       if (crtcs_enabled > 1) {
-               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+       if (!crtc || crtc->fb == NULL) {
+               DRM_DEBUG_KMS("no output, disabling\n");
+               dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
                goto out_disable;
        }
+
+       intel_crtc = to_intel_crtc(crtc);
+       fb = crtc->fb;
+       intel_fb = to_intel_framebuffer(fb);
+       obj_priv = to_intel_bo(intel_fb->obj);
+
        if (intel_fb->obj->size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
-                               "compression\n");
+                             "compression\n");
                dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                goto out_disable;
        }
-       if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
-           (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+       if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+           (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
                DRM_DEBUG_KMS("mode incompatible with compression, "
-                               "disabling\n");
+                             "disabling\n");
                dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
                goto out_disable;
        }
-       if ((mode->hdisplay > 2048) ||
-           (mode->vdisplay > 1536)) {
+       if ((crtc->mode.hdisplay > 2048) ||
+           (crtc->mode.vdisplay > 1536)) {
                DRM_DEBUG_KMS("mode too large for compression, disabling\n");
                dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
                goto out_disable;
        }
-       if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
+       if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
                dev_priv->no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
@@ -1384,18 +1420,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (in_dbg_master())
                goto out_disable;
 
-       if (intel_fbc_enabled(dev)) {
-               /* We can re-enable it in this case, but need to update pitch */
-               if ((fb->pitch > dev_priv->cfb_pitch) ||
-                   (obj_priv->fence_reg != dev_priv->cfb_fence) ||
-                   (plane != dev_priv->cfb_plane))
-                       intel_disable_fbc(dev);
-       }
-
-       /* Now try to turn it back on if possible */
-       if (!intel_fbc_enabled(dev))
-               intel_enable_fbc(crtc, 500);
-
+       intel_enable_fbc(crtc, 500);
        return;
 
 out_disable:
@@ -1407,7 +1432,9 @@ out_disable:
 }
 
 int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+                          struct drm_gem_object *obj,
+                          bool pipelined)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        u32 alignment;
@@ -1417,7 +1444,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        case I915_TILING_NONE:
                if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
                        alignment = 128 * 1024;
-               else if (IS_I965G(dev))
+               else if (INTEL_INFO(dev)->gen >= 4)
                        alignment = 4 * 1024;
                else
                        alignment = 64 * 1024;
@@ -1435,9 +1462,13 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        }
 
        ret = i915_gem_object_pin(obj, alignment);
-       if (ret != 0)
+       if (ret)
                return ret;
 
+       ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+       if (ret)
+               goto err_unpin;
+
        /* Install a fence for tiled scan-out. Pre-i965 always needs a
         * fence, whereas 965+ only requires a fence if using
         * framebuffer compression.  For simplicity, we always install
@@ -1445,20 +1476,22 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
         */
        if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
            obj_priv->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence_reg(obj);
-               if (ret != 0) {
-                       i915_gem_object_unpin(obj);
-                       return ret;
-               }
+               ret = i915_gem_object_get_fence_reg(obj, false);
+               if (ret)
+                       goto err_unpin;
        }
 
        return 0;
+
+err_unpin:
+       i915_gem_object_unpin(obj);
+       return ret;
 }
 
 /* Assume fb object is pinned & idle & fenced and just update base pointers */
 static int
 intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                          int x, int y)
+                          int x, int y, enum mode_set_atomic state)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1468,12 +1501,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct drm_gem_object *obj;
        int plane = intel_crtc->plane;
        unsigned long Start, Offset;
-       int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
-       int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
-       int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
-       int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
        u32 dspcntr;
+       u32 reg;
 
        switch (plane) {
        case 0:
@@ -1488,7 +1517,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        obj = intel_fb->obj;
        obj_priv = to_intel_bo(obj);
 
-       dspcntr = I915_READ(dspcntr_reg);
+       reg = DSPCNTR(plane);
+       dspcntr = I915_READ(reg);
        /* Mask out pixel format bits in case we change it */
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->bits_per_pixel) {
@@ -1509,7 +1539,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                DRM_ERROR("Unknown color depth\n");
                return -EINVAL;
        }
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                if (obj_priv->tiling_mode != I915_TILING_NONE)
                        dspcntr |= DISPPLANE_TILED;
                else
@@ -1520,28 +1550,24 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                /* must disable */
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(reg, dspcntr);
 
        Start = obj_priv->gtt_offset;
        Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      Start, Offset, x, y, fb->pitch);
-       I915_WRITE(dspstride, fb->pitch);
-       if (IS_I965G(dev)) {
-               I915_WRITE(dspsurf, Start);
-               I915_WRITE(dsptileoff, (y << 16) | x);
-               I915_WRITE(dspbase, Offset);
-       } else {
-               I915_WRITE(dspbase, Start + Offset);
-       }
-       POSTING_READ(dspbase);
+       I915_WRITE(DSPSTRIDE(plane), fb->pitch);
+       if (INTEL_INFO(dev)->gen >= 4) {
+               I915_WRITE(DSPSURF(plane), Start);
+               I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+               I915_WRITE(DSPADDR(plane), Offset);
+       } else
+               I915_WRITE(DSPADDR(plane), Start + Offset);
+       POSTING_READ(reg);
 
-       if (IS_I965G(dev) || plane == 0)
-               intel_update_fbc(crtc, &crtc->mode);
-
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-       intel_increase_pllclock(crtc, true);
+       intel_update_fbc(dev);
+       intel_increase_pllclock(crtc);
 
        return 0;
 }
@@ -1553,11 +1579,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_device *dev = crtc->dev;
        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;
-       int plane = intel_crtc->plane;
        int ret;
 
        /* no fb bound */
@@ -1566,45 +1587,42 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return 0;
        }
 
-       switch (plane) {
+       switch (intel_crtc->plane) {
        case 0:
        case 1:
                break;
        default:
-               DRM_ERROR("Can't update plane %d in SAREA\n", plane);
                return -EINVAL;
        }
 
-       intel_fb = to_intel_framebuffer(crtc->fb);
-       obj = intel_fb->obj;
-       obj_priv = to_intel_bo(obj);
-
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
+       ret = intel_pin_and_fence_fb_obj(dev,
+                                        to_intel_framebuffer(crtc->fb)->obj,
+                                        false);
        if (ret != 0) {
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       ret = i915_gem_object_set_to_display_plane(obj);
-       if (ret != 0) {
-               i915_gem_object_unpin(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return ret;
+       if (old_fb) {
+               struct drm_i915_private *dev_priv = dev->dev_private;
+               struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
+               struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+               wait_event(dev_priv->pending_flip_queue,
+                          atomic_read(&obj_priv->pending_flip) == 0);
        }
 
-       ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
+       ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
+                                        LEAVE_ATOMIC_MODE_SET);
        if (ret) {
-               i915_gem_object_unpin(obj);
+               i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       if (old_fb) {
-               intel_fb = to_intel_framebuffer(old_fb);
-               obj_priv = to_intel_bo(intel_fb->obj);
-               i915_gem_object_unpin(intel_fb->obj);
-       }
+       if (old_fb)
+               i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
 
        mutex_unlock(&dev->struct_mutex);
 
@@ -1615,7 +1633,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        if (!master_priv->sarea_priv)
                return 0;
 
-       if (pipe) {
+       if (intel_crtc->pipe) {
                master_priv->sarea_priv->pipeB_x = x;
                master_priv->sarea_priv->pipeB_y = y;
        } else {
@@ -1626,7 +1644,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1659,6 +1677,7 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
        }
        I915_WRITE(DP_A, dpa_ctl);
 
+       POSTING_READ(DP_A);
        udelay(500);
 }
 
@@ -1669,84 +1688,109 @@ static void ironlake_fdi_link_train(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;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-       u32 temp, tries = 0;
+       u32 reg, temp, tries;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+       I915_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~(7 << 19);
        temp |= (intel_crtc->fdi_lanes - 1) << 19;
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_1;
-       I915_WRITE(fdi_tx_reg, temp);
-       I915_READ(fdi_tx_reg);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_1;
-       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-       I915_READ(fdi_rx_reg);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
+       /* Ironlake workaround, enable clock pointer after FDI enable*/
+       I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE);
+
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if ((temp & FDI_RX_BIT_LOCK)) {
                        DRM_DEBUG_KMS("FDI train 1 done.\n");
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_BIT_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_rx_reg, temp);
-       udelay(150);
+       I915_WRITE(reg, temp);
 
-       tries = 0;
+       POSTING_READ(reg);
+       udelay(150);
 
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_SYMBOL_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_SYMBOL_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+               DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done\n");
+
+       /* enable normal train */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE;
+       }
+       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+       /* wait one idle pattern time */
+       POSTING_READ(reg);
+       udelay(1000);
 }
 
-static int snb_b_fdi_train_param [] = {
+static const int const snb_b_fdi_train_param [] = {
        FDI_LINK_TRAIN_400MV_0DB_SNB_B,
        FDI_LINK_TRAIN_400MV_6DB_SNB_B,
        FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -1760,24 +1804,22 @@ static void gen6_fdi_link_train(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;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-       u32 temp, i;
+       u32 reg, temp, i;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~(7 << 19);
        temp |= (intel_crtc->fdi_lanes - 1) << 19;
        temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1785,10 +1827,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
        /* SNB-B */
        temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-       I915_WRITE(fdi_tx_reg, temp);
-       I915_READ(fdi_tx_reg);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1796,32 +1838,37 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
        }
-       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-       I915_READ(fdi_rx_reg);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_BIT_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_BIT_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
                        DRM_DEBUG_KMS("FDI train 1 done.\n");
                        break;
                }
        }
        if (i == 4)
-               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
        if (IS_GEN6(dev)) {
@@ -1829,9 +1876,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                /* SNB-B */
                temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
        }
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1839,535 +1887,593 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_2;
        }
-       I915_WRITE(fdi_rx_reg, temp);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_SYMBOL_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_SYMBOL_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
        }
        if (i == 4)
-               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+               DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(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 pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
-       int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
-       int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
-       int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
-       int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
-       int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
-       int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
-       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-       u32 temp;
-       u32 pipe_bpc;
-
-       temp = I915_READ(pipeconf_reg);
-       pipe_bpc = temp & PIPE_BPC_MASK;
+       u32 reg, temp;
 
-       /* 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:
-               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+       /* Write the TU size bits so error detection works */
+       I915_WRITE(FDI_RX_TUSIZE1(pipe),
+                  I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
-                       if ((temp & LVDS_PORT_EN) == 0) {
-                               I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-                               POSTING_READ(PCH_LVDS);
-                       }
-               }
+       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~((0x7 << 19) | (0x7 << 16));
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
-               if (!HAS_eDP) {
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-                       temp = I915_READ(fdi_rx_reg);
-                       /*
-                        * make the BPC in FDI Rx be consistent with that in
-                        * pipeconf reg.
-                        */
-                       temp &= ~(0x7 << 16);
-                       temp |= (pipe_bpc << 11);
-                       temp &= ~(7 << 19);
-                       temp |= (intel_crtc->fdi_lanes - 1) << 19;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
+       /* Switch from Rawclk to PCDclk */
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp | FDI_PCDCLK);
 
-                       /* Switch from Rawclk to PCDclk */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* Enable CPU FDI TX PLL, always on for Ironlake */
-                       temp = I915_READ(fdi_tx_reg);
-                       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-                               I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                               I915_READ(fdi_tx_reg);
-                               udelay(100);
-                       }
-               }
+       /* Enable CPU FDI TX PLL, always on for Ironlake */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+               I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
-               /* Enable panel fitting for LVDS */
-               if (dev_priv->pch_pf_size &&
-                   (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-                   || HAS_eDP || intel_pch_has_edp(crtc))) {
-                       /* Force use of hard-coded filter coefficients
-                        * as some pre-programmed values are broken,
-                        * e.g. x201.
-                        */
-                       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
-                                  PF_ENABLE | PF_FILTER_MED_3x3);
-                       I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-                                  dev_priv->pch_pf_pos);
-                       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-                                  dev_priv->pch_pf_size);
-               }
+               POSTING_READ(reg);
+               udelay(100);
+       }
+}
 
-               /* Enable CPU pipe */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) == 0) {
-                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-                       udelay(100);
-               }
+static void intel_flush_display_plane(struct drm_device *dev,
+                                     int plane)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = DSPADDR(plane);
+       I915_WRITE(reg, I915_READ(reg));
+}
 
-               /* configure and enable CPU 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));
-               }
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
 
-               if (!HAS_eDP) {
-                       /* For PCH output, training FDI link */
-                       if (IS_GEN6(dev))
-                               gen6_fdi_link_train(crtc);
-                       else
-                               ironlake_fdi_link_train(crtc);
+       if (IS_GEN2(dev))
+               /* Can't break the hang on i8xx */
+               return;
 
-                       /* enable PCH DPLL */
-                       temp = I915_READ(pch_dpll_reg);
-                       if ((temp & DPLL_VCO_ENABLE) == 0) {
-                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-                               I915_READ(pch_dpll_reg);
-                       }
-                       udelay(200);
+       tmp = I915_READ(PRB0_CTL);
+       if (tmp & RING_WAIT) {
+               I915_WRITE(PRB0_CTL, tmp);
+               POSTING_READ(PRB0_CTL);
+       }
+}
 
-                       if (HAS_PCH_CPT(dev)) {
-                               /* Be sure PCH DPLL SEL is set */
-                               temp = I915_READ(PCH_DPLL_SEL);
-                               if (trans_dpll_sel == 0 &&
-                                               (temp & TRANSA_DPLL_ENABLE) == 0)
-                                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-                               else if (trans_dpll_sel == 1 &&
-                                               (temp & TRANSB_DPLL_ENABLE) == 0)
-                                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-                               I915_WRITE(PCH_DPLL_SEL, temp);
-                               I915_READ(PCH_DPLL_SEL);
-                       }
+static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+{
+       struct drm_i915_gem_object *obj_priv;
+       struct drm_i915_private *dev_priv;
 
-                       /* set transcoder timing */
-                       I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-                       I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-                       I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
-
-                       I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-                       I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-                       I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
-
-                       /* enable normal train */
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_TX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       if (HAS_PCH_CPT(dev)) {
-                               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-                               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-                       } else {
-                               temp &= ~FDI_LINK_TRAIN_NONE;
-                               temp |= FDI_LINK_TRAIN_NONE;
-                       }
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_rx_reg);
+       if (crtc->fb == NULL)
+               return;
 
-                       /* wait one idle pattern time */
-                       udelay(100);
+       obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+       dev_priv = crtc->dev->dev_private;
+       wait_event(dev_priv->pending_flip_queue,
+                  atomic_read(&obj_priv->pending_flip) == 0);
+}
 
-                       /* For PCH DP, enable TRANS_DP_CTL */
-                       if (HAS_PCH_CPT(dev) &&
-                           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
-                               int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-                               int reg;
-
-                               reg = I915_READ(trans_dp_ctl);
-                               reg &= ~(TRANS_DP_PORT_SEL_MASK |
-                                        TRANS_DP_SYNC_MASK);
-                               reg |= (TRANS_DP_OUTPUT_ENABLE |
-                                       TRANS_DP_ENH_FRAMING);
-
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
-                                     reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
-                                     reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
-
-                               switch (intel_trans_dp_port_sel(crtc)) {
-                               case PCH_DP_B:
-                                       reg |= TRANS_DP_PORT_SEL_B;
-                                       break;
-                               case PCH_DP_C:
-                                       reg |= TRANS_DP_PORT_SEL_C;
-                                       break;
-                               case PCH_DP_D:
-                                       reg |= TRANS_DP_PORT_SEL_D;
-                                       break;
-                               default:
-                                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
-                                       reg |= TRANS_DP_PORT_SEL_B;
-                                       break;
-                               }
+static void ironlake_crtc_enable(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 pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
 
-                               I915_WRITE(trans_dp_ctl, reg);
-                               POSTING_READ(trans_dp_ctl);
-                       }
+       if (intel_crtc->active)
+               return;
 
-                       /* enable PCH transcoder */
-                       temp = I915_READ(transconf_reg);
-                       /*
-                        * make the BPC in transcoder be consistent with
-                        * that in pipeconf reg.
-                        */
-                       temp &= ~PIPE_BPC_MASK;
-                       temp |= pipe_bpc;
-                       I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-                       I915_READ(transconf_reg);
+       intel_crtc->active = true;
+       intel_update_watermarks(dev);
 
-                       if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
-                               DRM_ERROR("failed to enable transcoder\n");
-               }
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if ((temp & LVDS_PORT_EN) == 0)
+                       I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+       }
 
-               intel_crtc_load_lut(crtc);
+       ironlake_fdi_enable(crtc);
 
-               intel_update_fbc(crtc, &crtc->mode);
-               break;
+       /* Enable panel fitting for LVDS */
+       if (dev_priv->pch_pf_size &&
+           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+               /* Force use of hard-coded filter coefficients
+                * as some pre-programmed values are broken,
+                * e.g. x201.
+                */
+               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+                          PF_ENABLE | PF_FILTER_MED_3x3);
+               I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+                          dev_priv->pch_pf_pos);
+               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+                          dev_priv->pch_pf_size);
+       }
+
+       /* Enable CPU pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0) {
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
+               POSTING_READ(reg);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
+       /* configure and enable CPU plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
+
+       /* For PCH output, training FDI link */
+       if (IS_GEN6(dev))
+               gen6_fdi_link_train(crtc);
+       else
+               ironlake_fdi_link_train(crtc);
+
+       /* enable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+               POSTING_READ(reg);
+               udelay(200);
+       }
 
-       case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+       if (HAS_PCH_CPT(dev)) {
+               /* Be sure PCH DPLL SEL is set */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
 
-               drm_vblank_off(dev, pipe);
-               /* 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);
+       /* set transcoder timing */
+       I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+       I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+       I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
+
+       I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+       I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+       I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
+
+       /* For PCH DP, enable TRANS_DP_CTL */
+       if (HAS_PCH_CPT(dev) &&
+           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_PORT_SEL_MASK |
+                         TRANS_DP_SYNC_MASK);
+               temp |= (TRANS_DP_OUTPUT_ENABLE |
+                        TRANS_DP_ENH_FRAMING);
+
+               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+                       temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+                       temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+               switch (intel_trans_dp_port_sel(crtc)) {
+               case PCH_DP_B:
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
+               case PCH_DP_C:
+                       temp |= TRANS_DP_PORT_SEL_C;
+                       break;
+               case PCH_DP_D:
+                       temp |= TRANS_DP_PORT_SEL_D;
+                       break;
+               default:
+                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
                }
 
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
+               I915_WRITE(reg, temp);
+       }
+
+       /* enable PCH transcoder */
+       reg = TRANSCONF(pipe);
+       temp = I915_READ(reg);
+       /*
+        * make the BPC in transcoder be consistent with
+        * that in pipeconf reg.
+        */
+       temp &= ~PIPE_BPC_MASK;
+       temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+       I915_WRITE(reg, temp | TRANS_ENABLE);
+       if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+               DRM_ERROR("failed to enable transcoder %d\n", pipe);
 
-               /* disable cpu pipe, disable after all planes disabled */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+       intel_crtc_update_cursor(crtc, true);
+}
 
-                       /* wait for cpu pipe off, pipe state */
-                       if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
-                               DRM_ERROR("failed to turn off cpu pipe\n");
-               } else
-                       DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+static void ironlake_crtc_disable(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 pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
 
-               udelay(100);
+       if (!intel_crtc->active)
+               return;
 
-               /* Disable PF */
-               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
-               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+       intel_crtc_wait_for_pending_flips(crtc);
+       drm_vblank_off(dev, pipe);
+       intel_crtc_update_cursor(crtc, false);
 
-               /* disable CPU FDI tx and PCH FDI rx */
-               temp = I915_READ(fdi_tx_reg);
-               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
-               I915_READ(fdi_tx_reg);
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
 
-               temp = I915_READ(fdi_rx_reg);
-               /* BPC in FDI rx is consistent with that in pipeconf */
-               temp &= ~(0x07 << 16);
-               temp |= (pipe_bpc << 11);
-               I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
-               I915_READ(fdi_rx_reg);
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
 
-               udelay(100);
+       /* disable cpu pipe, disable after all planes disabled */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+               POSTING_READ(reg);
+               /* wait for cpu pipe off, pipe state */
+               intel_wait_for_pipe_off(dev, intel_crtc->pipe);
+       }
+
+       /* Disable PF */
+       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+       /* disable CPU FDI tx and PCH FDI rx */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+       POSTING_READ(reg);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(0x7 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(100);
+
+       /* Ironlake workaround, disable clock pointer after downing FDI */
+       I915_WRITE(FDI_RX_CHICKEN(pipe),
+                  I915_READ(FDI_RX_CHICKEN(pipe) &
+                            ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
+       /* still set train pattern 1 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(reg, temp);
 
-               /* still set train pattern 1 */
-               temp = I915_READ(fdi_tx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       } else {
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
-               I915_WRITE(fdi_tx_reg, temp);
-               POSTING_READ(fdi_tx_reg);
-
-               temp = I915_READ(fdi_rx_reg);
-               if (HAS_PCH_CPT(dev)) {
-                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-               } else {
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-               }
-               I915_WRITE(fdi_rx_reg, temp);
-               POSTING_READ(fdi_rx_reg);
+       }
+       /* BPC in FDI rx is consistent with that in PIPECONF */
+       temp &= ~(0x07 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp);
 
-               udelay(100);
+       POSTING_READ(reg);
+       udelay(100);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if (temp & LVDS_PORT_EN) {
                        I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-                       I915_READ(PCH_LVDS);
+                       POSTING_READ(PCH_LVDS);
                        udelay(100);
                }
+       }
 
-               /* disable PCH transcoder */
-               temp = I915_READ(transconf_reg);
-               if ((temp & TRANS_ENABLE) != 0) {
-                       I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+       /* disable PCH transcoder */
+       reg = TRANSCONF(plane);
+       temp = I915_READ(reg);
+       if (temp & TRANS_ENABLE) {
+               I915_WRITE(reg, temp & ~TRANS_ENABLE);
+               /* wait for PCH transcoder off, transcoder state */
+               if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+                       DRM_ERROR("failed to disable transcoder\n");
+       }
 
-                       /* wait for PCH transcoder off, transcoder state */
-                       if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
-                               DRM_ERROR("failed to disable transcoder\n");
-               }
+       if (HAS_PCH_CPT(dev)) {
+               /* disable TRANS_DP_CTL */
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+               I915_WRITE(reg, temp);
 
-               temp = I915_READ(transconf_reg);
-               /* BPC in transcoder is consistent with that in pipeconf */
-               temp &= ~PIPE_BPC_MASK;
-               temp |= pipe_bpc;
-               I915_WRITE(transconf_reg, temp);
-               I915_READ(transconf_reg);
-               udelay(100);
+               /* disable DPLL_SEL */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0)
+                       temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+               else
+                       temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
 
-               if (HAS_PCH_CPT(dev)) {
-                       /* disable TRANS_DP_CTL */
-                       int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-                       int reg;
+       /* disable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-                       reg = I915_READ(trans_dp_ctl);
-                       reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
-                       I915_WRITE(trans_dp_ctl, reg);
-                       POSTING_READ(trans_dp_ctl);
+       /* Switch from PCDclk to Rawclk */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_PCDCLK);
 
-                       /* disable DPLL_SEL */
-                       temp = I915_READ(PCH_DPLL_SEL);
-                       if (trans_dpll_sel == 0)
-                               temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
-                       else
-                               temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-                       I915_WRITE(PCH_DPLL_SEL, temp);
-                       I915_READ(PCH_DPLL_SEL);
+       /* Disable CPU FDI TX PLL */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
 
-               }
+       POSTING_READ(reg);
+       udelay(100);
 
-               /* disable PCH DPLL */
-               temp = I915_READ(pch_dpll_reg);
-               I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-               I915_READ(pch_dpll_reg);
-
-               /* Switch from PCDclk to Rawclk */
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_SEL_PCDCLK;
-               I915_WRITE(fdi_rx_reg, temp);
-               I915_READ(fdi_rx_reg);
-
-               /* Disable CPU FDI TX PLL */
-               temp = I915_READ(fdi_tx_reg);
-               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-               I915_READ(fdi_tx_reg);
-               udelay(100);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
 
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_RX_PLL_ENABLE;
-               I915_WRITE(fdi_rx_reg, temp);
-               I915_READ(fdi_rx_reg);
+       /* Wait for the clocks to turn off. */
+       POSTING_READ(reg);
+       udelay(100);
 
-               /* Wait for the clocks to turn off. */
-               udelay(100);
+       intel_crtc->active = false;
+       intel_update_watermarks(dev);
+       intel_update_fbc(dev);
+       intel_clear_scanline_wait(dev);
+}
+
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+
+       /* 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:
+               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+               ironlake_crtc_enable(crtc);
+               break;
+
+       case DRM_MODE_DPMS_OFF:
+               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+               ironlake_crtc_disable(crtc);
                break;
        }
 }
 
 static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 {
-       struct intel_overlay *overlay;
-       int ret;
-
        if (!enable && intel_crtc->overlay) {
-               overlay = intel_crtc->overlay;
-               mutex_lock(&overlay->dev->struct_mutex);
-               for (;;) {
-                       ret = intel_overlay_switch_off(overlay);
-                       if (ret == 0)
-                               break;
+               struct drm_device *dev = intel_crtc->base.dev;
 
-                       ret = intel_overlay_recover_from_interrupt(overlay, 0);
-                       if (ret != 0) {
-                               /* overlay doesn't react anymore. Usually
-                                * results in a black screen and an unkillable
-                                * X server. */
-                               BUG();
-                               overlay->hw_wedged = HW_WEDGED;
-                               break;
-                       }
-               }
-               mutex_unlock(&overlay->dev->struct_mutex);
+               mutex_lock(&dev->struct_mutex);
+               (void) intel_overlay_switch_off(intel_crtc->overlay, false);
+               mutex_unlock(&dev->struct_mutex);
        }
-       /* Let userspace switch the overlay on again. In most cases userspace
-        * has to recompute where to put it anyway. */
 
-       return;
+       /* Let userspace switch the overlay on again. In most cases userspace
+        * has to recompute where to put it anyway.
+        */
 }
 
-static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void i9xx_crtc_enable(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 pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       u32 temp;
+       u32 reg, temp;
 
-       /* 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);
-               }
+       if (intel_crtc->active)
+               return;
 
-               /* 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->active = true;
+       intel_update_watermarks(dev);
 
-               intel_crtc_load_lut(crtc);
+       /* Enable the DPLL */
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp);
 
-               if ((IS_I965G(dev) || plane == 0))
-                       intel_update_fbc(crtc, &crtc->mode);
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
 
-               /* Give the overlay scaler a chance to enable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, true);
-       break;
-       case DRM_MODE_DPMS_OFF:
-               /* Give the overlay scaler a chance to disable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, false);
-               drm_vblank_off(dev, pipe);
-
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
-
-               /* 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);
-               }
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+       }
+
+       /* Enable the pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0)
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
+
+       /* Enable the plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
+
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+
+       /* Give the overlay scaler a chance to enable if it's on this pipe */
+       intel_crtc_dpms_overlay(intel_crtc, true);
+       intel_crtc_update_cursor(crtc, true);
+}
 
-               /* Don't disable pipe A or pipe A PLLs if needed */
-               if (pipeconf_reg == PIPEACONF &&
-                   (dev_priv->quirks & QUIRK_PIPEA_FORCE)) {
-                       /* Wait for vblank for the disable to take effect */
+static void i9xx_crtc_disable(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 pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
+
+       if (!intel_crtc->active)
+               return;
+
+       /* Give the overlay scaler a chance to disable if it's on this pipe */
+       intel_crtc_wait_for_pending_flips(crtc);
+       drm_vblank_off(dev, pipe);
+       intel_crtc_dpms_overlay(intel_crtc, false);
+       intel_crtc_update_cursor(crtc, false);
+
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
+
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               intel_flush_display_plane(dev, plane);
+
+               /* Wait for vblank for the disable to take effect */
+               if (IS_GEN2(dev))
                        intel_wait_for_vblank(dev, pipe);
-                       goto skip_pipe_off;
-               }
+       }
 
-               /* 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);
-               }
+       /* Don't disable pipe A or pipe A PLLs if needed */
+       if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+               goto done;
+
+       /* Next, disable display pipes */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 
                /* Wait for the pipe to turn off */
+               POSTING_READ(reg);
                intel_wait_for_pipe_off(dev, pipe);
+       }
+
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if (temp & DPLL_VCO_ENABLE) {
+               I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-               temp = I915_READ(dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-               }
-       skip_pipe_off:
                /* Wait for the clocks to turn off. */
+               POSTING_READ(reg);
                udelay(150);
+       }
+
+done:
+       intel_crtc->active = false;
+       intel_update_fbc(dev);
+       intel_update_watermarks(dev);
+       intel_clear_scanline_wait(dev);
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       /* 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:
+               i9xx_crtc_enable(crtc);
+               break;
+       case DRM_MODE_DPMS_OFF:
+               i9xx_crtc_disable(crtc);
                break;
        }
 }
@@ -2388,26 +2494,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                return;
 
        intel_crtc->dpms_mode = mode;
-       intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
-       /* When switching on the display, ensure that SR is disabled
-        * with multiple pipes prior to enabling to new pipe.
-        *
-        * When switching off the display, make sure the cursor is
-        * properly hidden prior to disabling the pipe.
-        */
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_update_watermarks(dev);
-       else
-               intel_crtc_update_cursor(crtc);
 
        dev_priv->display.dpms(crtc, mode);
 
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_crtc_update_cursor(crtc);
-       else
-               intel_update_watermarks(dev);
-
        if (!dev->primary->master)
                return;
 
@@ -2432,16 +2521,46 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        }
 }
 
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+static void intel_crtc_disable(struct drm_crtc *crtc)
 {
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       struct drm_device *dev = crtc->dev;
+
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+       if (crtc->fb) {
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+               mutex_unlock(&dev->struct_mutex);
+       }
+}
+
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here.  We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
+{
+       i9xx_crtc_disable(crtc);
 }
 
-static void intel_crtc_commit (struct drm_crtc *crtc)
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+       i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+       ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+       ironlake_crtc_enable(crtc);
 }
 
 void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2460,13 +2579,7 @@ void intel_encoder_commit (struct drm_encoder *encoder)
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
        drm_encoder_cleanup(encoder);
        kfree(intel_encoder);
@@ -2557,33 +2670,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
        return 133000;
 }
 
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-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;
-}
-
 struct fdi_m_n {
        u32        tu;
        u32        gmch_m;
@@ -2902,7 +2988,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
                size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2919,7 +3005,7 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2934,8 +3020,8 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 2; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A",
-                 size);
+                     plane ? "B" : "A",
+                     size);
 
        return size;
 }
@@ -2950,14 +3036,14 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
 
 static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
-                         int planeb_clock, int sr_hdisplay, int unused,
-                         int pixel_size)
+                              int planeb_clock, int sr_hdisplay, int unused,
+                              int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct cxsr_latency *latency;
@@ -3069,13 +3155,13 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 
                entries_required = (((sr_latency_ns / line_time_us) +
                                     1000) / 1000) * pixel_size * 64;
                entries_required = DIV_ROUND_UP(entries_required,
-                                          g4x_cursor_wm_info.cacheline_size);
+                                               g4x_cursor_wm_info.cacheline_size);
                cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 
                if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3087,7 +3173,7 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
        } else {
                /* Turn off self refresh if both pipes are enabled */
                I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-                                       & ~FW_BLC_SELF_EN);
+                          & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3125,7 +3211,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
                DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
                srwm = I965_FIFO_SIZE - sr_entries;
@@ -3134,11 +3220,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                srwm &= 0x1ff;
 
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                            pixel_size * 64;
+                       pixel_size * 64;
                sr_entries = DIV_ROUND_UP(sr_entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
-                           (sr_entries + i965_cursor_wm_info.guard_size);
+                       (sr_entries + i965_cursor_wm_info.guard_size);
 
                if (cursor_sr > i965_cursor_wm_info.max_wm)
                        cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3146,11 +3232,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
                              "cursor %d\n", srwm, cursor_sr);
 
-               if (IS_I965GM(dev))
+               if (IS_CRESTLINE(dev))
                        I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
        } else {
                /* Turn off self refresh if both pipes are enabled */
-               if (IS_I965GM(dev))
+               if (IS_CRESTLINE(dev))
                        I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
                                   & ~FW_BLC_SELF_EN);
        }
@@ -3180,9 +3266,9 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        int sr_clock, sr_entries = 0;
 
        /* Create copies of the base settings for each pipe */
-       if (IS_I965GM(dev) || IS_I945GM(dev))
+       if (IS_CRESTLINE(dev) || IS_I945GM(dev))
                planea_params = planeb_params = i945_wm_info;
-       else if (IS_I9XX(dev))
+       else if (!IS_GEN2(dev))
                planea_params = planeb_params = i915_wm_info;
        else
                planea_params = planeb_params = i855_wm_info;
@@ -3217,7 +3303,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
                DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
                srwm = total_size - sr_entries;
@@ -3242,7 +3328,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-                 planea_wm, planeb_wm, cwm, srwm);
+                     planea_wm, planeb_wm, cwm, srwm);
 
        fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
        fwater_hi = (cwm & 0x1f);
@@ -3276,146 +3362,130 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
 #define ILK_LP0_PLANE_LATENCY          700
 #define ILK_LP0_CURSOR_LATENCY         1300
 
-static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
-                      int planeb_clock, int sr_hdisplay, int sr_htotal,
-                      int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+                                int pipe,
+                                int *plane_wm,
+                                int *cursor_wm)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-       int sr_wm, cursor_wm;
-       unsigned long line_time_us;
-       int sr_clock, entries_required;
-       u32 reg_value;
-       int line_count;
-       int planea_htotal = 0, planeb_htotal = 0;
        struct drm_crtc *crtc;
+       int htotal, hdisplay, clock, pixel_size = 0;
+       int line_time_us, line_count, entries;
 
-       /* Need htotal for all active display plane */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
-                       if (intel_crtc->plane == 0)
-                               planea_htotal = crtc->mode.htotal;
-                       else
-                               planeb_htotal = crtc->mode.htotal;
-               }
-       }
-
-       /* Calculate and update the watermark for plane A */
-       if (planea_clock) {
-               entries_required = ((planea_clock / 1000) * pixel_size *
-                                    ILK_LP0_PLANE_LATENCY) / 1000;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_wm_info.cacheline_size);
-               planea_wm = entries_required +
-                           ironlake_display_wm_info.guard_size;
-
-               if (planea_wm > (int)ironlake_display_wm_info.max_wm)
-                       planea_wm = ironlake_display_wm_info.max_wm;
-
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planea_htotal * 1000) / planea_clock;
-
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-               /* calculate the cursor watermark for cursor A */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursora_wm > ironlake_cursor_wm_info.max_wm)
-                       cursora_wm = ironlake_cursor_wm_info.max_wm;
-
-               reg_value = I915_READ(WM0_PIPEA_ILK);
-               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
-                            (cursora_wm & WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEA_ILK, reg_value);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
-                               "cursor: %d\n", planea_wm, cursora_wm);
-       }
-       /* Calculate and update the watermark for plane B */
-       if (planeb_clock) {
-               entries_required = ((planeb_clock / 1000) * pixel_size *
-                                    ILK_LP0_PLANE_LATENCY) / 1000;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_wm_info.cacheline_size);
-               planeb_wm = entries_required +
-                           ironlake_display_wm_info.guard_size;
-
-               if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
-                       planeb_wm = ironlake_display_wm_info.max_wm;
+       crtc = intel_get_crtc_for_pipe(dev, pipe);
+       if (crtc->fb == NULL || !crtc->enabled)
+               return false;
 
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planeb_htotal * 1000) / planeb_clock;
+       htotal = crtc->mode.htotal;
+       hdisplay = crtc->mode.hdisplay;
+       clock = crtc->mode.clock;
+       pixel_size = crtc->fb->bits_per_pixel / 8;
+
+       /* Use the small buffer method to calculate plane watermark */
+       entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_display_wm_info.cacheline_size);
+       *plane_wm = entries + ironlake_display_wm_info.guard_size;
+       if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+               *plane_wm = ironlake_display_wm_info.max_wm;
+
+       /* Use the large buffer method to calculate cursor watermark */
+       line_time_us = ((htotal * 1000) / clock);
+       line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       entries = line_count * 64 * pixel_size;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_cursor_wm_info.cacheline_size);
+       *cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+       if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+               *cursor_wm = ironlake_cursor_wm_info.max_wm;
 
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       return true;
+}
 
-               /* calculate the cursor watermark for cursor B */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
-                       cursorb_wm = ironlake_cursor_wm_info.max_wm;
+static void ironlake_update_wm(struct drm_device *dev,
+                              int planea_clock, int planeb_clock,
+                              int sr_hdisplay, int sr_htotal,
+                              int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int plane_wm, cursor_wm, enabled;
+       int tmp;
+
+       enabled = 0;
+       if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEA_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+                             " plane %d, " "cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
+       }
 
-               reg_value = I915_READ(WM0_PIPEB_ILK);
-               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
-                            (cursorb_wm & WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEB_ILK, reg_value);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
-                               "cursor: %d\n", planeb_wm, cursorb_wm);
+       if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEB_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+                             " plane %d, cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
        }
 
        /*
         * Calculate and update the self-refresh watermark only when one
         * display plane is used.
         */
-       if (!planea_clock || !planeb_clock) {
-
+       tmp = 0;
+       if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+               unsigned long line_time_us;
+               int small, large, plane_fbc;
+               int sr_clock, entries;
+               int line_count, line_size;
                /* Read the self-refresh latency. The unit is 0.5us */
                int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_htotal * 1000) / sr_clock);
+               line_time_us = (sr_htotal * 1000) / sr_clock;
 
                /* Use ns/us then divide to preserve precision */
                line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
-                              / 1000;
+                       / 1000;
+               line_size = sr_hdisplay * pixel_size;
 
-               /* calculate the self-refresh watermark for display plane */
-               entries_required = line_count * sr_hdisplay * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_srwm_info.cacheline_size);
-               sr_wm = entries_required +
-                       ironlake_display_srwm_info.guard_size;
+               /* Use the minimum of the small and large buffer method for primary */
+               small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+               large = line_count * line_size;
 
-               /* calculate the self-refresh watermark for display cursor */
-               entries_required = line_count * pixel_size * 64;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_srwm_info.cacheline_size);
-               cursor_wm = entries_required +
-                           ironlake_cursor_srwm_info.guard_size;
+               entries = DIV_ROUND_UP(min(small, large),
+                                      ironlake_display_srwm_info.cacheline_size);
 
-               /* configure watermark and enable self-refresh */
-               reg_value = I915_READ(WM1_LP_ILK);
-               reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
-                              WM1_LP_CURSOR_MASK);
-               reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
-                            (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+               plane_fbc = entries * 64;
+               plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
 
-               I915_WRITE(WM1_LP_ILK, reg_value);
-               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
-                               "cursor %d\n", sr_wm, cursor_wm);
+               plane_wm = entries + ironlake_display_srwm_info.guard_size;
+               if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+                       plane_wm = ironlake_display_srwm_info.max_wm;
 
-       } else {
-               /* Turn off self refresh if both pipes are enabled */
-               I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
-       }
+               /* calculate the self-refresh watermark for display cursor */
+               entries = line_count * pixel_size * 64;
+               entries = DIV_ROUND_UP(entries,
+                                      ironlake_cursor_srwm_info.cacheline_size);
+
+               cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+               if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+                       cursor_wm = ironlake_cursor_srwm_info.max_wm;
+
+               /* configure watermark and enable self-refresh */
+               tmp = (WM1_LP_SR_EN |
+                      (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+                      (plane_fbc << WM1_LP_FBC_SHIFT) |
+                      (plane_wm << WM1_LP_SR_SHIFT) |
+                      cursor_wm);
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+                             " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
+       }
+       I915_WRITE(WM1_LP_ILK, tmp);
+       /* XXX setup WM2 and WM3 */
 }
+
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -3447,7 +3517,7 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
  *
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
 */
+ */
 static void intel_update_watermarks(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3463,15 +3533,15 @@ static void intel_update_watermarks(struct drm_device *dev)
        /* Get the clock config from both planes */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+               if (intel_crtc->active) {
                        enabled++;
                        if (intel_crtc->plane == 0) {
                                DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planea_clock = crtc->mode.clock;
                        } else {
                                DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planeb_clock = crtc->mode.clock;
                        }
                        sr_hdisplay = crtc->mode.hdisplay;
@@ -3502,62 +3572,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       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 = (plane == 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 = (plane == 0) ? DSPASIZE : DSPBSIZE;
-       int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
-       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       u32 fp_reg, dpll_reg;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
-       u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        struct intel_encoder *has_edp_encoder = NULL;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
        struct fdi_m_n m_n = {0};
-       int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
-       int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
-       int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
-       int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
-       int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
-       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-       int lvds_reg = LVDS;
-       u32 temp;
-       int sdvo_pixel_multiply;
+       u32 reg, temp;
        int target_clock;
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-               struct intel_encoder *intel_encoder;
-
-               if (encoder->crtc != crtc)
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
                        continue;
 
-               intel_encoder = enc_to_intel_encoder(encoder);
-               switch (intel_encoder->type) {
+               switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
                case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
-                       if (intel_encoder->needs_tv_clock)
+                       if (encoder->needs_tv_clock)
                                is_tv = true;
                        break;
                case INTEL_OUTPUT_DVO:
@@ -3573,7 +3616,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        is_dp = true;
                        break;
                case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = intel_encoder;
+                       has_edp_encoder = encoder;
                        break;
                }
 
@@ -3583,15 +3626,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
                refclk = dev_priv->lvds_ssc_freq * 1000;
                DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                                       refclk / 1000);
-       } else if (IS_I9XX(dev)) {
+                             refclk / 1000);
+       } else if (!IS_GEN2(dev)) {
                refclk = 96000;
-               if (HAS_PCH_SPLIT(dev))
+               if (HAS_PCH_SPLIT(dev) &&
+                   (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
                        refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
        }
-       
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -3607,13 +3650,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                has_reduced_clock = limit->find_pll(limit, crtc,
-                                                           dev_priv->lvds_downclock,
-                                                           refclk,
-                                                           &reduced_clock);
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &reduced_clock);
                if (has_reduced_clock && (clock.p != reduced_clock.p)) {
                        /*
                         * If the different P is found, it means that we can't
@@ -3622,7 +3665,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                         * feature.
                         */
                        DRM_DEBUG_KMS("Different P is found for "
-                                               "LVDS clock/downclock\n");
+                                     "LVDS clock/downclock\n");
                        has_reduced_clock = 0;
                }
        }
@@ -3630,14 +3673,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
           this mirrors vbios setting. */
        if (is_sdvo && is_tv) {
                if (adjusted_mode->clock >= 100000
-                               && adjusted_mode->clock < 140500) {
+                   && adjusted_mode->clock < 140500) {
                        clock.p1 = 2;
                        clock.p2 = 10;
                        clock.n = 3;
                        clock.m1 = 16;
                        clock.m2 = 8;
                } else if (adjusted_mode->clock >= 140500
-                               && adjusted_mode->clock <= 200000) {
+                          && adjusted_mode->clock <= 200000) {
                        clock.p1 = 1;
                        clock.p2 = 10;
                        clock.n = 6;
@@ -3649,34 +3692,41 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* FDI link */
        if (HAS_PCH_SPLIT(dev)) {
                int lane = 0, link_bw, bpp;
-               /* eDP doesn't require FDI link, so just set DP M/N
+               /* CPU eDP doesn't require FDI link, so just set DP M/N
                   according to current link config */
-               if (has_edp_encoder) {
+               if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
                        target_clock = mode->clock;
                        intel_edp_link_config(has_edp_encoder,
                                              &lane, &link_bw);
                } else {
-                       /* DP over FDI requires target mode clock
+                       /* [e]DP over FDI requires target mode clock
                           instead of link clock */
-                       if (is_dp)
+                       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
-                       link_bw = 270000;
+
+                       /* FDI is a binary signal running at ~2.7GHz, encoding
+                        * each output octet as 10 bits. The actual frequency
+                        * is stored as a divider into a 100MHz clock, and the
+                        * mode pixel clock is stored in units of 1KHz.
+                        * Hence the bw of each lane in terms of the mode signal
+                        * is:
+                        */
+                       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
                }
 
                /* determine panel color depth */
-               temp = I915_READ(pipeconf_reg);
+               temp = I915_READ(PIPECONF(pipe));
                temp &= ~PIPE_BPC_MASK;
                if (is_lvds) {
-                       int lvds_reg = I915_READ(PCH_LVDS);
                        /* the BPC will be 6 if it is 18-bit LVDS panel */
-                       if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
                                temp |= PIPE_8BPC;
                        else
                                temp |= PIPE_6BPC;
-               } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
-                       switch (dev_priv->edp_bpp/3) {
+               } else if (has_edp_encoder) {
+                       switch (dev_priv->edp.bpp/3) {
                        case 8:
                                temp |= PIPE_8BPC;
                                break;
@@ -3692,8 +3742,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        }
                } else
                        temp |= PIPE_8BPC;
-               I915_WRITE(pipeconf_reg, temp);
-               I915_READ(pipeconf_reg);
+               I915_WRITE(PIPECONF(pipe), temp);
 
                switch (temp & PIPE_BPC_MASK) {
                case PIPE_8BPC:
@@ -3738,33 +3787,39 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* Always enable nonspread source */
                temp &= ~DREF_NONSPREAD_SOURCE_MASK;
                temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-
                temp &= ~DREF_SSC_SOURCE_MASK;
                temp |= DREF_SSC_SOURCE_ENABLE;
                I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
 
+               POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
                if (has_edp_encoder) {
                        if (dev_priv->lvds_use_ssc) {
                                temp |= DREF_SSC1_ENABLE;
                                I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
-
-                               udelay(200);
 
-                               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
                                POSTING_READ(PCH_DREF_CONTROL);
+                               udelay(200);
+                       }
+                       temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+                       /* Enable CPU source on CPU attached eDP */
+                       if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                               if (dev_priv->lvds_use_ssc)
+                                       temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                               else
+                                       temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
                        } else {
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
+                               /* Enable SSC on PCH eDP if needed */
+                               if (dev_priv->lvds_use_ssc) {
+                                       DRM_ERROR("enabling SSC on PCH\n");
+                                       temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                               }
                        }
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
                }
        }
 
@@ -3780,23 +3835,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
+       dpll = 0;
        if (!HAS_PCH_SPLIT(dev))
                dpll = DPLL_VGA_MODE_DIS;
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (is_lvds)
                        dpll |= DPLLB_MODE_LVDS;
                else
                        dpll |= DPLLB_MODE_DAC_SERIAL;
                if (is_sdvo) {
+                       int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+                       if (pixel_multiplier > 1) {
+                               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                                       dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+                               else if (HAS_PCH_SPLIT(dev))
+                                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+                       }
                        dpll |= DPLL_DVO_HIGH_SPEED;
-                       sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-                       if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                               dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                       else if (HAS_PCH_SPLIT(dev))
-                               dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
-               if (is_dp)
+               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
                        dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
@@ -3824,7 +3882,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -3851,7 +3909,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        /* setup pipeconf */
-       pipeconf = I915_READ(pipeconf_reg);
+       pipeconf = I915_READ(PIPECONF(pipe));
 
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3865,7 +3923,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dspcntr |= DISPPLANE_SEL_PIPE_B;
        }
 
-       if (pipe == 0 && !IS_I965G(dev)) {
+       if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
                 * core speed.
                 *
@@ -3874,51 +3932,47 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 */
                if (mode->clock >
                    dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-                       pipeconf |= PIPEACONF_DOUBLE_WIDE;
+                       pipeconf |= PIPECONF_DOUBLE_WIDE;
                else
-                       pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
        dspcntr |= DISPLAY_PLANE_ENABLE;
-       pipeconf |= PIPEACONF_ENABLE;
+       pipeconf |= PIPECONF_ENABLE;
        dpll |= DPLL_VCO_ENABLE;
 
-
-       /* Disable the panel fitter if it was on our pipe */
-       if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
-               I915_WRITE(PFIT_CONTROL, 0);
-
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
        /* assign to Ironlake registers */
        if (HAS_PCH_SPLIT(dev)) {
-               fp_reg = pch_fp_reg;
-               dpll_reg = pch_dpll_reg;
+               fp_reg = PCH_FP0(pipe);
+               dpll_reg = PCH_DPLL(pipe);
+       } else {
+               fp_reg = FP0(pipe);
+               dpll_reg = DPLL(pipe);
        }
 
-       if (!has_edp_encoder) {
+       /* PCH eDP needs FDI, but CPU eDP does not */
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-               I915_READ(dpll_reg);
+
+               POSTING_READ(dpll_reg);
                udelay(150);
        }
 
        /* enable transcoder DPLL */
        if (HAS_PCH_CPT(dev)) {
                temp = I915_READ(PCH_DPLL_SEL);
-               if (trans_dpll_sel == 0)
-                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               if (pipe == 0)
+                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
                else
-                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
                I915_WRITE(PCH_DPLL_SEL, temp);
-               I915_READ(PCH_DPLL_SEL);
-               udelay(150);
-       }
 
-       if (HAS_PCH_SPLIT(dev)) {
-               pipeconf &= ~PIPE_ENABLE_DITHER;
-               pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+               POSTING_READ(PCH_DPLL_SEL);
+               udelay(150);
        }
 
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3926,58 +3980,60 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
         * things on.
         */
        if (is_lvds) {
-               u32 lvds;
-
+               reg = LVDS;
                if (HAS_PCH_SPLIT(dev))
-                       lvds_reg = PCH_LVDS;
+                       reg = PCH_LVDS;
 
-               lvds = I915_READ(lvds_reg);
-               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               temp = I915_READ(reg);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                if (pipe == 1) {
                        if (HAS_PCH_CPT(dev))
-                               lvds |= PORT_TRANS_B_SEL_CPT;
+                               temp |= PORT_TRANS_B_SEL_CPT;
                        else
-                               lvds |= LVDS_PIPEB_SELECT;
+                               temp |= LVDS_PIPEB_SELECT;
                } else {
                        if (HAS_PCH_CPT(dev))
-                               lvds &= ~PORT_TRANS_SEL_MASK;
+                               temp &= ~PORT_TRANS_SEL_MASK;
                        else
-                               lvds &= ~LVDS_PIPEB_SELECT;
+                               temp &= ~LVDS_PIPEB_SELECT;
                }
                /* set the corresponsding LVDS_BORDER bit */
-               lvds |= dev_priv->lvds_border_bits;
+               temp |= dev_priv->lvds_border_bits;
                /* 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;
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
                else
-                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+                       temp &= ~(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.
                 */
-               /* set the dithering flag */
-               if (IS_I965G(dev)) {
-                       if (dev_priv->lvds_dither) {
-                               if (HAS_PCH_SPLIT(dev)) {
-                                       pipeconf |= PIPE_ENABLE_DITHER;
-                                       pipeconf |= PIPE_DITHER_TYPE_ST01;
-                               } else
-                                       lvds |= LVDS_ENABLE_DITHER;
-                       } else {
-                               if (!HAS_PCH_SPLIT(dev)) {
-                                       lvds &= ~LVDS_ENABLE_DITHER;
-                               }
-                       }
+               /* set the dithering flag on non-PCH LVDS as needed */
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+                       if (dev_priv->lvds_dither)
+                               temp |= LVDS_ENABLE_DITHER;
+                       else
+                               temp &= ~LVDS_ENABLE_DITHER;
+               }
+               I915_WRITE(reg, temp);
+       }
+
+       /* set the dithering flag and clear for anything other than a panel. */
+       if (HAS_PCH_SPLIT(dev)) {
+               pipeconf &= ~PIPECONF_DITHER_EN;
+               pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+               if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+                       pipeconf |= PIPECONF_DITHER_EN;
+                       pipeconf |= PIPECONF_DITHER_TYPE_ST1;
                }
-               I915_WRITE(lvds_reg, lvds);
-               I915_READ(lvds_reg);
        }
-       if (is_dp)
+
+       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       else if (HAS_PCH_SPLIT(dev)) {
+       else if (HAS_PCH_SPLIT(dev)) {
                /* For non-DP output, clear any trans DP clock recovery setting.*/
                if (pipe == 0) {
                        I915_WRITE(TRANSA_DATA_M1, 0);
@@ -3992,29 +4048,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       if (!has_edp_encoder) {
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll);
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
 
-               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+                       temp = 0;
                        if (is_sdvo) {
-                               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
-                               I915_WRITE(dpll_md_reg, 0);
+                               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+                               if (temp > 1)
+                                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                               else
+                                       temp = 0;
+                       }
+                       I915_WRITE(DPLL_MD(pipe), temp);
                } else {
                        /* write it again -- the BIOS does, after all */
                        I915_WRITE(dpll_reg, dpll);
                }
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
        }
 
+       intel_crtc->lowfreq_avail = false;
        if (is_lvds && has_reduced_clock && i915_powersave) {
                I915_WRITE(fp_reg + 4, fp2);
                intel_crtc->lowfreq_avail = true;
@@ -4024,7 +4086,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        } else {
                I915_WRITE(fp_reg + 4, fp);
-               intel_crtc->lowfreq_avail = false;
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4043,70 +4104,62 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else
                pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
 
-       I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
-       I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
                   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
                   ((adjusted_mode->crtc_hsync_end - 1) << 16));
-       I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
                   ((adjusted_mode->crtc_vtotal - 1) << 16));
-       I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
                   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+       I915_WRITE(VSYNC(pipe),
+                  (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.
+
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
         */
        if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
-                               (mode->hdisplay - 1));
-               I915_WRITE(dsppos_reg, 0);
+               I915_WRITE(DSPSIZE(plane),
+                          ((mode->vdisplay - 1) << 16) |
+                          (mode->hdisplay - 1));
+               I915_WRITE(DSPPOS(plane), 0);
        }
-       I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
        if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
-               I915_WRITE(link_m1_reg, m_n.link_m);
-               I915_WRITE(link_n1_reg, m_n.link_n);
+               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
-               if (has_edp_encoder) {
+               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                        ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-               } else {
-                       /* enable FDI RX PLL too */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
-
-                       /* enable FDI TX PLL too */
-                       temp = I915_READ(fdi_tx_reg);
-                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       /* enable FDI RX PCDCLK */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
                }
        }
 
-       I915_WRITE(pipeconf_reg, pipeconf);
-       I915_READ(pipeconf_reg);
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
 
        intel_wait_for_vblank(dev, pipe);
 
-       if (IS_IRONLAKE(dev)) {
+       if (IS_GEN5(dev)) {
                /* enable address swizzle for tiling buffer */
                temp = I915_READ(DISP_ARB_CTL);
                I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
        }
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(DSPCNTR(plane), dspcntr);
 
-       /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
        intel_update_watermarks(dev);
@@ -4199,7 +4252,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 }
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+                                    bool on)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4212,7 +4266,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc)
 
        pos = 0;
 
-       if (intel_crtc->cursor_on && crtc->fb) {
+       if (on && crtc->enabled && crtc->fb) {
                base = intel_crtc->cursor_addr;
                if (x > (int) crtc->fb->width)
                        base = 0;
@@ -4324,7 +4378,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                addr = obj_priv->phys_obj->handle->busaddr;
        }
 
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                I915_WRITE(CURSIZE, (height << 12) | width);
 
  finish:
@@ -4344,7 +4398,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 fail_unpin:
@@ -4363,7 +4417,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 }
@@ -4432,7 +4486,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
        struct drm_crtc *supported_crtc =NULL;
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4513,7 +4567,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                    struct drm_connector *connector, int dpms_mode)
 {
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4559,7 +4613,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
        }
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (IS_PINEVIEW(dev))
                        clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
                                DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
@@ -4663,8 +4717,6 @@ static void intel_gpu_idle_timer(unsigned long arg)
        struct drm_device *dev = (struct drm_device *)arg;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
        dev_priv->busy = false;
 
        queue_work(dev_priv->wq, &dev_priv->idle_work);
@@ -4678,14 +4730,12 @@ static void intel_crtc_idle_timer(unsigned long arg)
        struct drm_crtc *crtc = &intel_crtc->base;
        drm_i915_private_t *dev_priv = crtc->dev->dev_private;
 
-       DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
        intel_crtc->busy = false;
 
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4720,9 +4770,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
        }
 
        /* Schedule downclock */
-       if (schedule)
-               mod_timer(&intel_crtc->idle_timer, jiffies +
-                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+       mod_timer(&intel_crtc->idle_timer, jiffies +
+                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4858,7 +4907,7 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
                                        I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
                                }
                                /* Non-busy -> busy, upclock */
-                               intel_increase_pllclock(crtc, true);
+                               intel_increase_pllclock(crtc);
                                intel_crtc->busy = true;
                        } else {
                                /* Busy -> busy, put off timer */
@@ -4872,8 +4921,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct intel_unpin_work *work;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (work) {
+               cancel_work_sync(&work->work);
+               kfree(work);
+       }
 
        drm_crtc_cleanup(crtc);
+
        kfree(intel_crtc);
 }
 
@@ -4928,12 +4991,11 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       obj_priv = to_intel_bo(work->pending_flip_obj);
-
-       /* Initial scanout buffer will have a 0 pending flip count */
-       if ((atomic_read(&obj_priv->pending_flip) == 0) ||
-           atomic_dec_and_test(&obj_priv->pending_flip))
-               DRM_WAKEUP(&dev_priv->pending_flip_queue);
+       obj_priv = to_intel_bo(work->old_fb_obj);
+       atomic_clear_mask(1 << intel_crtc->plane,
+                         &obj_priv->pending_flip.counter);
+       if (atomic_read(&obj_priv->pending_flip) == 0)
+               wake_up(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
 
        trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5014,7 +5076,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        obj = intel_fb->obj;
 
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
+       ret = intel_pin_and_fence_fb_obj(dev, obj, true);
        if (ret)
                goto cleanup_work;
 
@@ -5023,29 +5085,33 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        drm_gem_object_reference(obj);
 
        crtc->fb = fb;
-       ret = i915_gem_object_flush_write_domain(obj);
-       if (ret)
-               goto cleanup_objs;
 
        ret = drm_vblank_get(dev, intel_crtc->pipe);
        if (ret)
                goto cleanup_objs;
 
-       obj_priv = to_intel_bo(obj);
-       atomic_inc(&obj_priv->pending_flip);
+       /* Block clients from rendering to the new back buffer until
+        * the flip occurs and the object is no longer visible.
+        */
+       atomic_add(1 << intel_crtc->plane,
+                  &to_intel_bo(work->old_fb_obj)->pending_flip);
+
        work->pending_flip_obj = obj;
+       obj_priv = to_intel_bo(obj);
 
        if (IS_GEN3(dev) || IS_GEN2(dev)) {
                u32 flip_mask;
 
+               /* Can't queue multiple flips, so wait for the previous
+                * one to finish before executing the next.
+                */
+               BEGIN_LP_RING(2);
                if (intel_crtc->plane)
                        flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
                else
                        flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
-               BEGIN_LP_RING(2);
                OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
-               OUT_RING(0);
+               OUT_RING(MI_NOOP);
                ADVANCE_LP_RING();
        }
 
@@ -5126,15 +5192,14 @@ cleanup_work:
        return ret;
 }
 
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static 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,
        .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .prepare = intel_crtc_prepare,
-       .commit = intel_crtc_commit,
        .load_lut = intel_crtc_load_lut,
+       .disable = intel_crtc_disable,
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -5160,8 +5225,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-       intel_crtc->pipe = pipe;
-       intel_crtc->plane = pipe;
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
                intel_crtc->lut_g[i] = i;
@@ -5171,9 +5234,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        /* Swap pipes & planes for FBC on pre-965 */
        intel_crtc->pipe = pipe;
        intel_crtc->plane = pipe;
-       if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-               intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+               intel_crtc->plane = !pipe;
        }
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5183,6 +5246,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        intel_crtc->cursor_addr = 0;
        intel_crtc->dpms_mode = -1;
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+       if (HAS_PCH_SPLIT(dev)) {
+               intel_helper_funcs.prepare = ironlake_crtc_prepare;
+               intel_helper_funcs.commit = ironlake_crtc_commit;
+       } else {
+               intel_helper_funcs.prepare = i9xx_crtc_prepare;
+               intel_helper_funcs.commit = i9xx_crtc_commit;
+       }
+
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
        intel_crtc->busy = false;
@@ -5218,38 +5291,25 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
        return 0;
 }
 
-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_encoder_clones(struct drm_device *dev, int type_mask)
 {
+       struct intel_encoder *encoder;
        int index_mask = 0;
-       struct drm_encoder *encoder;
        int entry = 0;
 
-        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-               if (type_mask & intel_encoder->clone_mask)
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               if (type_mask & encoder->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
        }
+
        return index_mask;
 }
 
-
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        bool dpd_is_edp = false;
 
        if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -5338,12 +5398,10 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-               encoder->possible_crtcs = intel_encoder->crtc_mask;
-               encoder->possible_clones = intel_encoder_clones(dev,
-                                               intel_encoder->clone_mask);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               encoder->base.possible_crtcs = encoder->crtc_mask;
+               encoder->base.possible_clones =
+                       intel_encoder_clones(dev, encoder->clone_mask);
        }
 }
 
@@ -5377,8 +5435,25 @@ int intel_framebuffer_init(struct drm_device *dev,
                           struct drm_mode_fb_cmd *mode_cmd,
                           struct drm_gem_object *obj)
 {
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               return -EINVAL;
+
+       if (mode_cmd->pitch & 63)
+               return -EINVAL;
+
+       switch (mode_cmd->bpp) {
+       case 8:
+       case 16:
+       case 24:
+       case 32:
+               break;
+       default:
+               return -EINVAL;
+       }
+
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
                DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5487,6 +5562,10 @@ void ironlake_enable_drps(struct drm_device *dev)
        u32 rgvmodectl = I915_READ(MEMMODECTL);
        u8 fmax, fmin, fstart, vstart;
 
+       /* Enable temp reporting */
+       I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+       I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
        /* 100ms RC evaluation intervals */
        I915_WRITE(RCUPEI, 100000);
        I915_WRITE(RCDNEI, 100000);
@@ -5529,7 +5608,7 @@ void ironlake_enable_drps(struct drm_device *dev)
        rgvmodectl |= MEMMODE_SWMODE_EN;
        I915_WRITE(MEMMODECTL, rgvmodectl);
 
-       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
                DRM_ERROR("stuck trying to change perf mode\n");
        msleep(1);
 
@@ -5660,7 +5739,7 @@ void intel_init_clock_gating(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev)) {
                uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
 
-               if (IS_IRONLAKE(dev)) {
+               if (IS_GEN5(dev)) {
                        /* Required for FBC */
                        dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
                        /* Required for CxSR */
@@ -5673,6 +5752,13 @@ void intel_init_clock_gating(struct drm_device *dev)
 
                I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
+               /*
+                * On Ibex Peak and Cougar Point, we need to disable clock
+                * gating for the panel power sequencer or it will fail to
+                * start up when no ports are active.
+                */
+               I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+
                /*
                 * According to the spec the following bits should be set in
                 * order to enable memory self-refresh
@@ -5680,7 +5766,7 @@ void intel_init_clock_gating(struct drm_device *dev)
                 * The bit 5 of 0x42020
                 * The bit 15 of 0x45000
                 */
-               if (IS_IRONLAKE(dev)) {
+               if (IS_GEN5(dev)) {
                        I915_WRITE(ILK_DISPLAY_CHICKEN2,
                                        (I915_READ(ILK_DISPLAY_CHICKEN2) |
                                        ILK_DPARB_GATE | ILK_VSDPFD_FULL));
@@ -5728,20 +5814,20 @@ void intel_init_clock_gating(struct drm_device *dev)
                if (IS_GM45(dev))
                        dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
                I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-       } else if (IS_I965GM(dev)) {
+       } else if (IS_CRESTLINE(dev)) {
                I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
                I915_WRITE(RENCLK_GATE_D2, 0);
                I915_WRITE(DSPCLK_GATE_D, 0);
                I915_WRITE(RAMCLK_GATE_D, 0);
                I915_WRITE16(DEUC, 0);
-       } else if (IS_I965G(dev)) {
+       } else if (IS_BROADWATER(dev)) {
                I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
                       I965_RCC_CLOCK_GATE_DISABLE |
                       I965_RCPB_CLOCK_GATE_DISABLE |
                       I965_ISC_CLOCK_GATE_DISABLE |
                       I965_FBC_CLOCK_GATE_DISABLE);
                I915_WRITE(RENCLK_GATE_D2, 0);
-       } else if (IS_I9XX(dev)) {
+       } else if (IS_GEN3(dev)) {
                u32 dstate = I915_READ(D_STATE);
 
                dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
@@ -5823,7 +5909,7 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
                        dev_priv->display.enable_fbc = g4x_enable_fbc;
                        dev_priv->display.disable_fbc = g4x_disable_fbc;
-               } else if (IS_I965GM(dev)) {
+               } else if (IS_CRESTLINE(dev)) {
                        dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
                        dev_priv->display.enable_fbc = i8xx_enable_fbc;
                        dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -5856,7 +5942,7 @@ static void intel_init_display(struct drm_device *dev)
 
        /* For FIFO watermark updates */
        if (HAS_PCH_SPLIT(dev)) {
-               if (IS_IRONLAKE(dev)) {
+               if (IS_GEN5(dev)) {
                        if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
                                dev_priv->display.update_wm = ironlake_update_wm;
                        else {
@@ -5883,9 +5969,9 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.update_wm = pineview_update_wm;
        } else if (IS_G4X(dev))
                dev_priv->display.update_wm = g4x_update_wm;
-       else if (IS_I965G(dev))
+       else if (IS_GEN4(dev))
                dev_priv->display.update_wm = i965_update_wm;
-       else if (IS_I9XX(dev)) {
+       else if (IS_GEN3(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
        } else if (IS_I85X(dev)) {
@@ -5999,24 +6085,24 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_display(dev);
 
-       if (IS_I965G(dev)) {
-               dev->mode_config.max_width = 8192;
-               dev->mode_config.max_height = 8192;
-       } else if (IS_I9XX(dev)) {
+       if (IS_GEN2(dev)) {
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
+       } else if (IS_GEN3(dev)) {
                dev->mode_config.max_width = 4096;
                dev->mode_config.max_height = 4096;
        } else {
-               dev->mode_config.max_width = 2048;
-               dev->mode_config.max_height = 2048;
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
        }
 
        /* set memory base */
-       if (IS_I9XX(dev))
-               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
-       else
+       if (IS_GEN2(dev))
                dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+       else
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
 
-       if (IS_MOBILE(dev) || IS_I9XX(dev))
+       if (IS_MOBILE(dev) || !IS_GEN2(dev))
                dev_priv->num_pipe = 2;
        else
                dev_priv->num_pipe = 1;
@@ -6052,10 +6138,11 @@ void intel_modeset_cleanup(struct drm_device *dev)
        struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
 
+       drm_kms_helper_poll_fini(dev);
        mutex_lock(&dev->struct_mutex);
 
-       drm_kms_helper_poll_fini(dev);
-       intel_fbdev_fini(dev);
+       intel_unregister_dsm_handler();
+
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
@@ -6063,12 +6150,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
                        continue;
 
                intel_crtc = to_intel_crtc(crtc);
-               intel_increase_pllclock(crtc, false);
-               del_timer_sync(&intel_crtc->idle_timer);
+               intel_increase_pllclock(crtc);
        }
 
-       del_timer_sync(&dev_priv->idle_timer);
-
        if (dev_priv->display.disable_fbc)
                dev_priv->display.disable_fbc(dev);
 
@@ -6097,33 +6181,36 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        mutex_unlock(&dev->struct_mutex);
 
+       /* Disable the irq before mode object teardown, for the irq might
+        * enqueue unpin/hotplug work. */
+       drm_irq_uninstall(dev);
+       cancel_work_sync(&dev_priv->hotplug_work);
+
+       /* Shut off idle work before the crtcs get freed. */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+               del_timer_sync(&intel_crtc->idle_timer);
+       }
+       del_timer_sync(&dev_priv->idle_timer);
+       cancel_work_sync(&dev_priv->idle_work);
+
        drm_mode_config_cleanup(dev);
 }
 
-
 /*
  * Return which encoder is currently attached for connector.
  */
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 {
-       struct drm_mode_object *obj;
-       struct drm_encoder *encoder;
-       int i;
-
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               if (connector->encoder_ids[i] == 0)
-                       break;
-
-               obj = drm_mode_object_find(connector->dev,
-                                           connector->encoder_ids[i],
-                                           DRM_MODE_OBJECT_ENCODER);
-               if (!obj)
-                       continue;
+       return &intel_attached_encoder(connector)->base;
+}
 
-               encoder = obj_to_encoder(obj);
-               return encoder;
-       }
-       return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+                                   struct intel_encoder *encoder)
+{
+       connector->encoder = encoder;
+       drm_mode_connector_attach_encoder(&connector->base,
+                                         &encoder->base);
 }
 
 /*
index 9ab8708ac6ba1370cea75680d6a660daa5f9b147..891f4f1d63b11570b7ede1c4e5e49814f2dcb5d0 100644 (file)
 
 #define DP_LINK_CONFIGURATION_SIZE     9
 
-#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP)
-#define IS_PCH_eDP(i) ((i)->is_pch_edp)
-
 struct intel_dp {
        struct intel_encoder base;
        uint32_t output_reg;
        uint32_t DP;
        uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
        bool has_audio;
+       int force_audio;
        int dpms_mode;
        uint8_t link_bw;
        uint8_t lane_count;
@@ -58,14 +56,69 @@ struct intel_dp {
        struct i2c_adapter adapter;
        struct i2c_algo_dp_aux_data algo;
        bool is_pch_edp;
+       uint8_t train_set[4];
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+       struct drm_property *force_audio_property;
 };
 
+/**
+ * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+ * @intel_dp: DP struct
+ *
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
+ * will return true, and false otherwise.
+ */
+static bool is_edp(struct intel_dp *intel_dp)
+{
+       return intel_dp->base.type == INTEL_OUTPUT_EDP;
+}
+
+/**
+ * is_pch_edp - is the port on the PCH and attached to an eDP panel?
+ * @intel_dp: DP struct
+ *
+ * Returns true if the given DP struct corresponds to a PCH DP port attached
+ * to an eDP panel, false otherwise.  Helpful for determining whether we
+ * may need FDI resources for a given DP output or not.
+ */
+static bool is_pch_edp(struct intel_dp *intel_dp)
+{
+       return intel_dp->is_pch_edp;
+}
+
 static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base);
+       return container_of(encoder, struct intel_dp, base.base);
+}
+
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_dp, base);
+}
+
+/**
+ * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
+ * @encoder: DRM encoder
+ *
+ * Return true if @encoder corresponds to a PCH attached eDP panel.  Needed
+ * by intel_display.c.
+ */
+bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
+{
+       struct intel_dp *intel_dp;
+
+       if (!encoder)
+               return false;
+
+       intel_dp = enc_to_intel_dp(encoder);
+
+       return is_pch_edp(intel_dp);
 }
 
-static void intel_dp_link_train(struct intel_dp *intel_dp);
+static void intel_dp_start_link_train(struct intel_dp *intel_dp);
+static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
 
 void
@@ -129,8 +182,8 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-               return (pixel_clock * dev_priv->edp_bpp) / 8;
+       if (is_edp(intel_dp))
+               return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
        else
                return pixel_clock * 3;
 }
@@ -145,15 +198,13 @@ static int
 intel_dp_mode_valid(struct drm_connector *connector,
                    struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
        int max_lanes = intel_dp_max_lane_count(intel_dp);
 
-       if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-           dev_priv->panel_fixed_mode) {
+       if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
                if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
                        return MODE_PANEL;
 
@@ -163,7 +214,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
 
        /* only refuse the mode on non eDP since we have seen some wierd eDP panels
           which are outside spec tolerances but somehow work by magic */
-       if (!IS_eDP(intel_dp) &&
+       if (!is_edp(intel_dp) &&
            (intel_dp_link_required(connector->dev, intel_dp, mode->clock)
             > intel_dp_max_data_rate(max_link_clock, max_lanes)))
                return MODE_CLOCK_HIGH;
@@ -233,7 +284,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                uint8_t *recv, int recv_size)
 {
        uint32_t output_reg = intel_dp->output_reg;
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t ch_ctl = output_reg + 0x10;
        uint32_t ch_data = ch_ctl + 4;
@@ -246,8 +297,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        /* The clock divider is based off the hrawclk,
         * and would like to run at 2MHz. So, take the
         * hrawclk value and divide by 2 and use that
+        *
+        * Note that PCH attached eDP panels should use a 125MHz input
+        * clock divider.
         */
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
                if (IS_GEN6(dev))
                        aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
                else
@@ -519,8 +573,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
        int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
        static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
 
-       if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-           dev_priv->panel_fixed_mode) {
+       if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
                intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
                intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
                                        mode, adjusted_mode);
@@ -531,6 +584,17 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                mode->clock = dev_priv->panel_fixed_mode->clock;
        }
 
+       /* Just use VBT values for eDP */
+       if (is_edp(intel_dp)) {
+               intel_dp->lane_count = dev_priv->edp.lanes;
+               intel_dp->link_bw = dev_priv->edp.rate;
+               adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
+               DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
+                             intel_dp->link_bw, intel_dp->lane_count,
+                             adjusted_mode->clock);
+               return true;
+       }
+
        for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
                for (clock = 0; clock <= max_clock; clock++) {
                        int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
@@ -549,19 +613,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                }
        }
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
-               /* okay we failed just pick the highest */
-               intel_dp->lane_count = max_lane_count;
-               intel_dp->link_bw = bws[max_clock];
-               adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
-               DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
-                             "count %d clock %d\n",
-                             intel_dp->link_bw, intel_dp->lane_count,
-                             adjusted_mode->clock);
-
-               return true;
-       }
-
        return false;
 }
 
@@ -598,25 +649,6 @@ intel_dp_compute_m_n(int bpp,
        intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
-bool intel_pch_has_edp(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-               struct intel_dp *intel_dp;
-
-               if (encoder->crtc != crtc)
-                       continue;
-
-               intel_dp = enc_to_intel_dp(encoder);
-               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
-                       return intel_dp->is_pch_edp;
-       }
-       return false;
-}
-
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode)
@@ -641,8 +673,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                intel_dp = enc_to_intel_dp(encoder);
                if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
                        lane_count = intel_dp->lane_count;
-                       if (IS_PCH_eDP(intel_dp))
-                               bpp = dev_priv->edp_bpp;
+                       break;
+               } else if (is_edp(intel_dp)) {
+                       lane_count = dev_priv->edp.lanes;
+                       bpp = dev_priv->edp.bpp;
                        break;
                }
        }
@@ -698,7 +732,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 {
        struct drm_device *dev = encoder->dev;
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_crtc *crtc = intel_dp->base.enc.crtc;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        intel_dp->DP = (DP_VOLTAGE_0_4 |
@@ -709,7 +743,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                intel_dp->DP |= DP_SYNC_VS_HIGH;
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
        else
                intel_dp->DP |= DP_LINK_TRAIN_OFF;
@@ -744,7 +778,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
                intel_dp->DP |= DP_PIPEB_SELECT;
 
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
                /* don't miss out required setting for eDP */
                intel_dp->DP |= DP_PLL_ENABLE;
                if (adjusted_mode->clock < 200000)
@@ -754,13 +788,15 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        }
 }
 
-static void ironlake_edp_panel_on (struct drm_device *dev)
+/* Returns true if the panel was already on when called */
+static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
 {
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp;
+       u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
 
        if (I915_READ(PCH_PP_STATUS) & PP_ON)
-               return;
+               return true;
 
        pp = I915_READ(PCH_PP_CONTROL);
 
@@ -771,21 +807,30 @@ static void ironlake_edp_panel_on (struct drm_device *dev)
 
        pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
+
+       /* Ouch. We need to wait here for some panels, like Dell e6510
+        * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+        */
+       msleep(300);
 
-       if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+       if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask,
+                    5000))
                DRM_ERROR("panel on wait timed out: 0x%08x\n",
                          I915_READ(PCH_PP_STATUS));
 
-       pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
        pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
+
+       return false;
 }
 
 static void ironlake_edp_panel_off (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp;
+       u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
+               PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
 
        pp = I915_READ(PCH_PP_CONTROL);
 
@@ -796,15 +841,20 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
 
        pp &= ~POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
 
-       if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+       if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
                DRM_ERROR("panel off wait timed out: 0x%08x\n",
                          I915_READ(PCH_PP_STATUS));
 
-       /* Make sure VDD is enabled so DP AUX will work */
-       pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */
+       pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
+
+       /* Ouch. We need to wait here for some panels, like Dell e6510
+        * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+        */
+       msleep(300);
 }
 
 static void ironlake_edp_backlight_on (struct drm_device *dev)
@@ -813,6 +863,13 @@ static void ironlake_edp_backlight_on (struct drm_device *dev)
        u32 pp;
 
        DRM_DEBUG_KMS("\n");
+       /*
+        * If we enable the backlight right away following a panel power
+        * on, we may see slight flicker as the panel syncs with the eDP
+        * link.  So delay a bit to make sure the image is solid before
+        * allowing it to appear.
+        */
+       msleep(300);
        pp = I915_READ(PCH_PP_CONTROL);
        pp |= EDP_BLC_ENABLE;
        I915_WRITE(PCH_PP_CONTROL, pp);
@@ -837,8 +894,10 @@ static void ironlake_edp_pll_on(struct drm_encoder *encoder)
 
        DRM_DEBUG_KMS("\n");
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl &= ~DP_PLL_ENABLE;
+       dpa_ctl |= DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
+       POSTING_READ(DP_A);
+       udelay(200);
 }
 
 static void ironlake_edp_pll_off(struct drm_encoder *encoder)
@@ -848,8 +907,9 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
        u32 dpa_ctl;
 
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl |= DP_PLL_ENABLE;
+       dpa_ctl &= ~DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
+       POSTING_READ(DP_A);
        udelay(200);
 }
 
@@ -857,29 +917,31 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                ironlake_edp_backlight_off(dev);
-               ironlake_edp_panel_on(dev);
-               ironlake_edp_pll_on(encoder);
+               ironlake_edp_panel_on(intel_dp);
+               if (!is_pch_edp(intel_dp))
+                       ironlake_edp_pll_on(encoder);
+               else
+                       ironlake_edp_pll_off(encoder);
        }
-       if (dp_reg & DP_PORT_EN)
-               intel_dp_link_down(intel_dp);
+       intel_dp_link_down(intel_dp);
 }
 
 static void intel_dp_commit(struct drm_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-       if (!(dp_reg & DP_PORT_EN)) {
-               intel_dp_link_train(intel_dp);
-       }
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+       intel_dp_start_link_train(intel_dp);
+
+       if (is_edp(intel_dp))
+               ironlake_edp_panel_on(intel_dp);
+
+       intel_dp_complete_link_train(intel_dp);
+
+       if (is_edp(intel_dp))
                ironlake_edp_backlight_on(dev);
 }
 
@@ -892,22 +954,22 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
        if (mode != DRM_MODE_DPMS_ON) {
-               if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+               if (is_edp(intel_dp))
                        ironlake_edp_backlight_off(dev);
+               intel_dp_link_down(intel_dp);
+               if (is_edp(intel_dp))
                        ironlake_edp_panel_off(dev);
-               }
-               if (dp_reg & DP_PORT_EN)
-                       intel_dp_link_down(intel_dp);
-               if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+               if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
                        ironlake_edp_pll_off(encoder);
        } else {
+               if (is_edp(intel_dp))
+                       ironlake_edp_panel_on(intel_dp);
                if (!(dp_reg & DP_PORT_EN)) {
-                       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-                               ironlake_edp_panel_on(dev);
-                       intel_dp_link_train(intel_dp);
-                       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-                               ironlake_edp_backlight_on(dev);
+                       intel_dp_start_link_train(intel_dp);
+                       intel_dp_complete_link_train(intel_dp);
                }
+               if (is_edp(intel_dp))
+                       ironlake_edp_backlight_on(dev);
        }
        intel_dp->dpms_mode = mode;
 }
@@ -917,14 +979,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
  * link status information
  */
 static bool
-intel_dp_get_link_status(struct intel_dp *intel_dp,
-                        uint8_t link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp)
 {
        int ret;
 
        ret = intel_dp_aux_native_read(intel_dp,
                                       DP_LANE0_1_STATUS,
-                                      link_status, DP_LINK_STATUS_SIZE);
+                                      intel_dp->link_status, DP_LINK_STATUS_SIZE);
        if (ret != DP_LINK_STATUS_SIZE)
                return false;
        return true;
@@ -999,18 +1060,15 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing)
 }
 
 static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-                      uint8_t link_status[DP_LINK_STATUS_SIZE],
-                      int lane_count,
-                      uint8_t train_set[4])
+intel_get_adjust_train(struct intel_dp *intel_dp)
 {
        uint8_t v = 0;
        uint8_t p = 0;
        int lane;
 
-       for (lane = 0; lane < lane_count; lane++) {
-               uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
-               uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+               uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
 
                if (this_v > v)
                        v = this_v;
@@ -1025,15 +1083,25 @@ intel_get_adjust_train(struct intel_dp *intel_dp,
                p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
        for (lane = 0; lane < 4; lane++)
-               train_set[lane] = v | p;
+               intel_dp->train_set[lane] = v | p;
 }
 
 static uint32_t
-intel_dp_signal_levels(uint8_t train_set, int lane_count)
+intel_dp_signal_levels(struct intel_dp *intel_dp)
 {
-       uint32_t        signal_levels = 0;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t signal_levels = 0;
+       u8 train_set = intel_dp->train_set[0];
+       u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
+       u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
+
+       if (is_edp(intel_dp)) {
+               vswing = dev_priv->edp.vswing;
+               preemphasis = dev_priv->edp.preemphasis;
+       }
 
-       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       switch (vswing) {
        case DP_TRAIN_VOLTAGE_SWING_400:
        default:
                signal_levels |= DP_VOLTAGE_0_4;
@@ -1048,7 +1116,7 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count)
                signal_levels |= DP_VOLTAGE_1_2;
                break;
        }
-       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       switch (preemphasis) {
        case DP_TRAIN_PRE_EMPHASIS_0:
        default:
                signal_levels |= DP_PRE_EMPHASIS_0;
@@ -1116,178 +1184,213 @@ intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count
                         DP_LANE_CHANNEL_EQ_DONE|\
                         DP_LANE_SYMBOL_LOCKED)
 static bool
-intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+intel_channel_eq_ok(struct intel_dp *intel_dp)
 {
        uint8_t lane_align;
        uint8_t lane_status;
        int lane;
 
-       lane_align = intel_dp_link_status(link_status,
+       lane_align = intel_dp_link_status(intel_dp->link_status,
                                          DP_LANE_ALIGN_STATUS_UPDATED);
        if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
                return false;
-       for (lane = 0; lane < lane_count; lane++) {
-               lane_status = intel_get_lane_status(link_status, lane);
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               lane_status = intel_get_lane_status(intel_dp->link_status, lane);
                if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
                        return false;
        }
        return true;
 }
 
+static bool
+intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
+               return false;
+
+       return true;
+}
+
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
                        uint32_t dp_reg_value,
-                       uint8_t dp_train_pat,
-                       uint8_t train_set[4])
+                       uint8_t dp_train_pat)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        I915_WRITE(intel_dp->output_reg, dp_reg_value);
        POSTING_READ(intel_dp->output_reg);
 
+       if (!intel_dp_aux_handshake_required(intel_dp))
+               return true;
+
        intel_dp_aux_native_write_1(intel_dp,
                                    DP_TRAINING_PATTERN_SET,
                                    dp_train_pat);
 
        ret = intel_dp_aux_native_write(intel_dp,
-                                       DP_TRAINING_LANE0_SET, train_set, 4);
+                                       DP_TRAINING_LANE0_SET,
+                                       intel_dp->train_set, 4);
        if (ret != 4)
                return false;
 
        return true;
 }
 
+/* Enable corresponding port and start training pattern 1 */
 static void
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint8_t train_set[4];
-       uint8_t link_status[DP_LINK_STATUS_SIZE];
+       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
        int i;
        uint8_t voltage;
        bool clock_recovery = false;
-       bool channel_eq = false;
        int tries;
        u32 reg;
        uint32_t DP = intel_dp->DP;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
 
        /* Enable output, wait for it to become active */
        I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-       /* Write the link configuration data */
-       intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
-                                 intel_dp->link_configuration,
-                                 DP_LINK_CONFIGURATION_SIZE);
+       if (intel_dp_aux_handshake_required(intel_dp))
+               /* Write the link configuration data */
+               intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
+                                         intel_dp->link_configuration,
+                                         DP_LINK_CONFIGURATION_SIZE);
 
        DP |= DP_PORT_EN;
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
        else
                DP &= ~DP_LINK_TRAIN_MASK;
-       memset(train_set, 0, 4);
+       memset(intel_dp->train_set, 0, 4);
        voltage = 0xff;
        tries = 0;
        clock_recovery = false;
        for (;;) {
-               /* Use train_set[0] to set the voltage and pre emphasis values */
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
-               if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+               if (IS_GEN6(dev) && is_edp(intel_dp)) {
+                       signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+               if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                        reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
                else
                        reg = DP | DP_LINK_TRAIN_PAT_1;
 
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_1, train_set))
+                                            DP_TRAINING_PATTERN_1))
                        break;
                /* Set training pattern 1 */
 
-               udelay(100);
-               if (!intel_dp_get_link_status(intel_dp, link_status))
+               udelay(500);
+               if (intel_dp_aux_handshake_required(intel_dp)) {
                        break;
+               } else {
+                       if (!intel_dp_get_link_status(intel_dp))
+                               break;
 
-               if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
-                       clock_recovery = true;
-                       break;
-               }
-
-               /* Check to see if we've tried the max voltage */
-               for (i = 0; i < intel_dp->lane_count; i++)
-                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                       if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+                               clock_recovery = true;
                                break;
-               if (i == intel_dp->lane_count)
-                       break;
+                       }
 
-               /* Check to see if we've tried the same voltage 5 times */
-               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++tries;
-                       if (tries == 5)
+                       /* Check to see if we've tried the max voltage */
+                       for (i = 0; i < intel_dp->lane_count; i++)
+                               if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                                       break;
+                       if (i == intel_dp->lane_count)
                                break;
-               } else
-                       tries = 0;
-               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
-               /* Compute new train_set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+                       /* Check to see if we've tried the same voltage 5 times */
+                       if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                               ++tries;
+                               if (tries == 5)
+                                       break;
+                       } else
+                               tries = 0;
+                       voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+                       /* Compute new intel_dp->train_set as requested by target */
+                       intel_get_adjust_train(intel_dp);
+               }
        }
 
+       intel_dp->DP = DP;
+}
+
+static void
+intel_dp_complete_link_train(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool channel_eq = false;
+       int tries;
+       u32 reg;
+       uint32_t DP = intel_dp->DP;
+
        /* channel equalization */
        tries = 0;
        channel_eq = false;
        for (;;) {
-               /* Use train_set[0] to set the voltage and pre emphasis values */
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
 
-               if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+               if (IS_GEN6(dev) && is_edp(intel_dp)) {
+                       signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+               if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                        reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
                else
                        reg = DP | DP_LINK_TRAIN_PAT_2;
 
                /* channel eq pattern */
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_2, train_set))
+                                            DP_TRAINING_PATTERN_2))
                        break;
 
-               udelay(400);
-               if (!intel_dp_get_link_status(intel_dp, link_status))
-                       break;
+               udelay(500);
 
-               if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) {
-                       channel_eq = true;
+               if (!intel_dp_aux_handshake_required(intel_dp)) {
                        break;
-               }
+               } else {
+                       if (!intel_dp_get_link_status(intel_dp))
+                               break;
 
-               /* Try 5 times */
-               if (tries > 5)
-                       break;
+                       if (intel_channel_eq_ok(intel_dp)) {
+                               channel_eq = true;
+                               break;
+                       }
 
-               /* Compute new train_set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
-               ++tries;
-       }
+                       /* Try 5 times */
+                       if (tries > 5)
+                               break;
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+                       /* Compute new intel_dp->train_set as requested by target */
+                       intel_get_adjust_train(intel_dp);
+                       ++tries;
+               }
+       }
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                reg = DP | DP_LINK_TRAIN_OFF_CPT;
        else
                reg = DP | DP_LINK_TRAIN_OFF;
@@ -1301,32 +1404,31 @@ intel_dp_link_train(struct intel_dp *intel_dp)
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t DP = intel_dp->DP;
 
        DRM_DEBUG_KMS("\n");
 
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                DP &= ~DP_PLL_ENABLE;
                I915_WRITE(intel_dp->output_reg, DP);
                POSTING_READ(intel_dp->output_reg);
                udelay(100);
        }
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
-               POSTING_READ(intel_dp->output_reg);
        } else {
                DP &= ~DP_LINK_TRAIN_MASK;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
-               POSTING_READ(intel_dp->output_reg);
        }
+       POSTING_READ(intel_dp->output_reg);
 
-       udelay(17000);
+       msleep(17);
 
-       if (IS_eDP(intel_dp))
+       if (is_edp(intel_dp))
                DP |= DP_LINK_TRAIN_OFF;
        I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
        POSTING_READ(intel_dp->output_reg);
@@ -1344,32 +1446,34 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
-       uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-       if (!intel_dp->base.enc.crtc)
+       if (!intel_dp->base.base.crtc)
                return;
 
-       if (!intel_dp_get_link_status(intel_dp, link_status)) {
+       if (!intel_dp_get_link_status(intel_dp)) {
                intel_dp_link_down(intel_dp);
                return;
        }
 
-       if (!intel_channel_eq_ok(link_status, intel_dp->lane_count))
-               intel_dp_link_train(intel_dp);
+       if (!intel_channel_eq_ok(intel_dp)) {
+               intel_dp_start_link_train(intel_dp);
+               intel_dp_complete_link_train(intel_dp);
+       }
 }
 
 static enum drm_connector_status
-ironlake_dp_detect(struct drm_connector *connector)
+ironlake_dp_detect(struct intel_dp *intel_dp)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        enum drm_connector_status status;
 
+       /* Can't disconnect eDP */
+       if (is_edp(intel_dp))
+               return connector_status_connected;
+
        status = connector_status_disconnected;
        if (intel_dp_aux_native_read(intel_dp,
                                     0x000, intel_dp->dpcd,
-                                    sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
-       {
+                                    sizeof (intel_dp->dpcd))
+           == sizeof(intel_dp->dpcd)) {
                if (intel_dp->dpcd[0] != 0)
                        status = connector_status_connected;
        }
@@ -1378,26 +1482,13 @@ ironlake_dp_detect(struct drm_connector *connector)
        return status;
 }
 
-/**
- * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
- *
- * \return true if DP port is connected.
- * \return false if DP port is disconnected.
- */
 static enum drm_connector_status
-intel_dp_detect(struct drm_connector *connector, bool force)
+g4x_dp_detect(struct intel_dp *intel_dp)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t temp, bit;
        enum drm_connector_status status;
-
-       intel_dp->has_audio = false;
-
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_dp_detect(connector);
+       uint32_t temp, bit;
 
        switch (intel_dp->output_reg) {
        case DP_B:
@@ -1419,31 +1510,66 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                return connector_status_disconnected;
 
        status = connector_status_disconnected;
-       if (intel_dp_aux_native_read(intel_dp,
-                                    0x000, intel_dp->dpcd,
+       if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
                                     sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
        {
                if (intel_dp->dpcd[0] != 0)
                        status = connector_status_connected;
        }
-       return status;
+
+       return bit;
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector, bool force)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct drm_device *dev = intel_dp->base.base.dev;
+       enum drm_connector_status status;
+       struct edid *edid = NULL;
+
+       intel_dp->has_audio = false;
+
+       if (HAS_PCH_SPLIT(dev))
+               status = ironlake_dp_detect(intel_dp);
+       else
+               status = g4x_dp_detect(intel_dp);
+       if (status != connector_status_connected)
+               return status;
+
+       if (intel_dp->force_audio) {
+               intel_dp->has_audio = intel_dp->force_audio > 0;
+       } else {
+               edid = drm_get_edid(connector, &intel_dp->adapter);
+               if (edid) {
+                       intel_dp->has_audio = drm_detect_monitor_audio(edid);
+                       connector->display_info.raw_edid = NULL;
+                       kfree(edid);
+               }
+       }
+
+       return connector_status_connected;
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        /* We should parse the EDID data and find out if it has an audio sink
         */
 
-       ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
+       ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
        if (ret) {
-               if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-                   !dev_priv->panel_fixed_mode) {
+               if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
                        struct drm_display_mode *newmode;
                        list_for_each_entry(newmode, &connector->probed_modes,
                                            head) {
@@ -1459,7 +1585,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        }
 
        /* if eDP has no EDID, try to use fixed panel mode from VBT */
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                if (dev_priv->panel_fixed_mode != NULL) {
                        struct drm_display_mode *mode;
                        mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -1470,6 +1596,46 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        return 0;
 }
 
+static int
+intel_dp_set_property(struct drm_connector *connector,
+                     struct drm_property *property,
+                     uint64_t val)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       int ret;
+
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret)
+               return ret;
+
+       if (property == intel_dp->force_audio_property) {
+               if (val == intel_dp->force_audio)
+                       return 0;
+
+               intel_dp->force_audio = val;
+
+               if (val > 0 && intel_dp->has_audio)
+                       return 0;
+               if (val < 0 && !intel_dp->has_audio)
+                       return 0;
+
+               intel_dp->has_audio = val > 0;
+               goto done;
+       }
+
+       return -EINVAL;
+
+done:
+       if (intel_dp->base.base.crtc) {
+               struct drm_crtc *crtc = intel_dp->base.base.crtc;
+               drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                        crtc->x, crtc->y,
+                                        crtc->fb);
+       }
+
+       return 0;
+}
+
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
@@ -1478,6 +1644,15 @@ intel_dp_destroy (struct drm_connector *connector)
        kfree(connector);
 }
 
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+       i2c_del_adapter(&intel_dp->adapter);
+       drm_encoder_cleanup(encoder);
+       kfree(intel_dp);
+}
+
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
        .dpms = intel_dp_dpms,
        .mode_fixup = intel_dp_mode_fixup,
@@ -1490,20 +1665,21 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = intel_dp_set_property,
        .destroy = intel_dp_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
        .get_modes = intel_dp_get_modes,
        .mode_valid = intel_dp_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
-       .destroy = intel_encoder_destroy,
+       .destroy = intel_dp_encoder_destroy,
 };
 
-void
+static void
 intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 {
        struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -1554,6 +1730,20 @@ bool intel_dpd_is_edp(struct drm_device *dev)
        return false;
 }
 
+static void
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+
+       intel_dp->force_audio_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+       if (intel_dp->force_audio_property) {
+               intel_dp->force_audio_property->values[0] = -1;
+               intel_dp->force_audio_property->values[1] = 1;
+               drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
+       }
+}
+
 void
 intel_dp_init(struct drm_device *dev, int output_reg)
 {
@@ -1580,7 +1770,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                if (intel_dpd_is_edp(dev))
                        intel_dp->is_pch_edp = true;
 
-       if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+       if (output_reg == DP_A || is_pch_edp(intel_dp)) {
                type = DRM_MODE_CONNECTOR_eDP;
                intel_encoder->type = INTEL_OUTPUT_EDP;
        } else {
@@ -1601,7 +1791,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        else if (output_reg == DP_D || output_reg == PCH_DP_D)
                intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
 
-       if (IS_eDP(intel_dp))
+       if (is_edp(intel_dp))
                intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
 
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
@@ -1612,12 +1802,11 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        intel_dp->has_audio = false;
        intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
                         DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
 
        /* Set up the DDC bus. */
@@ -1647,10 +1836,29 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
        intel_dp_i2c_init(intel_dp, intel_connector, name);
 
-       intel_encoder->ddc_bus = &intel_dp->adapter;
+       /* Cache some DPCD data in the eDP case */
+       if (is_edp(intel_dp)) {
+               int ret;
+               bool was_on;
+
+               was_on = ironlake_edp_panel_on(intel_dp);
+               ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
+                                              intel_dp->dpcd,
+                                              sizeof(intel_dp->dpcd));
+               if (ret == sizeof(intel_dp->dpcd)) {
+                       if (intel_dp->dpcd[0] >= 0x11)
+                               dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
+                                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+               } else {
+                       DRM_ERROR("failed to retrieve link info\n");
+               }
+               if (!was_on)
+                       ironlake_edp_panel_off(dev);
+       }
+
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
-       if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                /* initialize panel mode from VBT if available for eDP */
                if (dev_priv->lfp_lvds_vbt_mode) {
                        dev_priv->panel_fixed_mode =
@@ -1662,6 +1870,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                }
        }
 
+       intel_dp_add_properties(intel_dp, connector);
+
        /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
         * 0xd.  Failure to do so will result in spurious interrupts being
         * generated on the port when a cable is not attached.
index 8828b3ac6414eabff93134e34a41ae5c38d1cd34..9af9f86a8765c82833706aa1320ca9baed3fa416 100644 (file)
 #define __INTEL_DRV_H__
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/i2c-algo-bit.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
-
 #include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
 
-#define wait_for(COND, MS, W) ({ \
+#define _wait_for(COND, MS, W) ({ \
        unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
        int ret__ = 0;                                                  \
        while (! (COND)) {                                              \
                        ret__ = -ETIMEDOUT;                             \
                        break;                                          \
                }                                                       \
-               if (W) msleep(W);                                       \
+               if (W && !in_dbg_master()) msleep(W);                   \
        }                                                               \
        ret__;                                                          \
 })
 
+#define wait_for(COND, MS) _wait_for(COND, MS, 1)
+#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+
+#define MSLEEP(x) do { \
+       if (in_dbg_master()) \
+               mdelay(x); \
+       else \
+               msleep(x); \
+} while(0)
+
+#define KHz(x) (1000*x)
+#define MHz(x) KHz(1000*x)
+
 /*
  * Display related stuff
  */
 #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;
-};
+/* drm_display_mode->private_flags */
+#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
+#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+
+static inline void
+intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
+                               int multiplier)
+{
+       mode->clock *= multiplier;
+       mode->private_flags |= multiplier;
+}
+
+static inline int
+intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
+{
+       return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
+}
 
 struct intel_framebuffer {
        struct drm_framebuffer base;
        struct drm_gem_object *obj;
 };
 
+struct intel_fbdev {
+       struct drm_fb_helper helper;
+       struct intel_framebuffer ifb;
+       struct list_head fbdev_list;
+       struct drm_display_mode *our_mode;
+};
 
 struct intel_encoder {
-       struct drm_encoder enc;
+       struct drm_encoder base;
        int type;
-       struct i2c_adapter *i2c_bus;
-       struct i2c_adapter *ddc_bus;
        bool load_detect_temp;
        bool needs_tv_clock;
        void (*hot_plug)(struct intel_encoder *);
@@ -123,32 +149,7 @@ struct intel_encoder {
 
 struct intel_connector {
        struct drm_connector base;
-};
-
-struct intel_crtc;
-struct intel_overlay {
-       struct drm_device *dev;
-       struct intel_crtc *crtc;
-       struct drm_i915_gem_object *vid_bo;
-       struct drm_i915_gem_object *old_vid_bo;
-       int active;
-       int pfit_active;
-       u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
-       u32 color_key;
-       u32 brightness, contrast, saturation;
-       u32 old_xscale, old_yscale;
-       /* register access */
-       u32 flip_addr;
-       struct drm_i915_gem_object *reg_bo;
-       void *virt_addr;
-       /* flip handling */
-       uint32_t last_flip_req;
-       int hw_wedged;
-#define HW_WEDGED              1
-#define NEEDS_WAIT_FOR_FLIP    2
-#define RELEASE_OLD_VID                3
-#define SWITCH_OFF_STAGE_1     4
-#define SWITCH_OFF_STAGE_2     5
+       struct intel_encoder *encoder;
 };
 
 struct intel_crtc {
@@ -157,6 +158,7 @@ struct intel_crtc {
        enum plane plane;
        u8 lut_r[256], lut_g[256], lut_b[256];
        int dpms_mode;
+       bool active; /* is the crtc on? independent of the dpms mode */
        bool busy; /* is scanout buffer being updated frequently? */
        struct timer_list idle_timer;
        bool lowfreq_avail;
@@ -168,14 +170,53 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_x, cursor_y;
        int16_t cursor_width, cursor_height;
-       bool cursor_visible, cursor_on;
+       bool cursor_visible;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
-#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+#define DIP_TYPE_AVI    0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI     13
+
+struct dip_infoframe {
+       uint8_t type;           /* HB0 */
+       uint8_t ver;            /* HB1 */
+       uint8_t len;            /* HB2 - body len, not including checksum */
+       uint8_t ecc;            /* Header ECC */
+       uint8_t checksum;       /* PB0 */
+       union {
+               struct {
+                       /* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */
+                       uint8_t Y_A_B_S;
+                       /* PB2 - C 7:6, M 5:4, R 3:0 */
+                       uint8_t C_M_R;
+                       /* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */
+                       uint8_t ITC_EC_Q_SC;
+                       /* PB4 - VIC 6:0 */
+                       uint8_t VIC;
+                       /* PB5 - PR 3:0 */
+                       uint8_t PR;
+                       /* PB6 to PB13 */
+                       uint16_t top_bar_end;
+                       uint16_t bottom_bar_start;
+                       uint16_t left_bar_end;
+                       uint16_t right_bar_start;
+               } avi;
+               uint8_t payload[27];
+       } __attribute__ ((packed)) body;
+} __attribute__((packed));
+
+static inline struct drm_crtc *
+intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       return dev_priv->pipe_to_crtc_mapping[pipe];
+}
+
 struct intel_unpin_work {
        struct work_struct work;
        struct drm_device *dev;
@@ -186,16 +227,12 @@ struct intel_unpin_work {
        bool enable_stall_check;
 };
 
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                    const char *name);
-void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
-void intel_i2c_reset_gmbus(struct drm_device *dev);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
 extern bool 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);
@@ -205,32 +242,41 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode);
-extern bool intel_pch_has_edp(struct drm_crtc *crtc);
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
+extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
 
-
+/* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                                   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct drm_device *dev,
                                    int fitting_mode,
                                    struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode);
+extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
+extern u32 intel_panel_get_backlight(struct drm_device *dev);
+extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
-extern int intel_panel_fitter_pipe (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 void intel_encoder_destroy(struct drm_encoder *encoder);
 
-extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
+static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
+{
+       return to_intel_connector(connector)->encoder;
+}
+
+extern void intel_connector_attach_encoder(struct intel_connector *connector,
+                                          struct intel_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);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
                                                   struct drm_connector *connector,
                                                   struct drm_display_mode *mode,
@@ -252,7 +298,8 @@ extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
-                                     struct drm_gem_object *obj);
+                                     struct drm_gem_object *obj,
+                                     bool pipelined);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
@@ -267,9 +314,8 @@ extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 
 extern void intel_setup_overlay(struct drm_device *dev);
 extern void intel_cleanup_overlay(struct drm_device *dev);
-extern int intel_overlay_switch_off(struct intel_overlay *overlay);
-extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-                                               int interruptible);
+extern int intel_overlay_switch_off(struct intel_overlay *overlay,
+                                   bool interruptible);
 extern int intel_overlay_put_image(struct drm_device *dev, void *data,
                                   struct drm_file *file_priv);
 extern int intel_overlay_attrs(struct drm_device *dev, void *data,
index 7c9ec1472d46ab3cbb08f6bffc8257af952a64b0..ea373283c93be6e16edabd4714ae0eb1c89b0da9 100644 (file)
@@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
                .name = "ch7017",
                .dvo_reg = DVOC,
                .slave_addr = 0x75,
-               .gpio = GPIOE,
+               .gpio = GMBUS_PORT_DPB,
                .dev_ops = &ch7017_ops,
        }
 };
@@ -88,7 +88,13 @@ struct intel_dvo {
 
 static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
+       return container_of(encoder, struct intel_dvo, base.base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_dvo, base);
 }
 
 static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
@@ -112,8 +118,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
 static int intel_dvo_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -224,23 +229,22 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
 static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
 }
 
 static int intel_dvo_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
        /* 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(connector, intel_dvo->base.ddc_bus);
+       intel_ddc_get_modes(connector,
+                           &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
        if (!list_empty(&connector->probed_modes))
                return 1;
 
@@ -281,7 +285,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
 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_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
@@ -311,8 +315,7 @@ 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 drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
        struct drm_display_mode *mode = NULL;
 
@@ -323,7 +326,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
                struct drm_crtc *crtc;
                int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
-               crtc = intel_get_crtc_from_pipe(dev, pipe);
+               crtc = intel_get_crtc_for_pipe(dev, pipe);
                if (crtc) {
                        mode = intel_crtc_mode_get(dev, crtc);
                        if (mode) {
@@ -341,11 +344,10 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
 
 void intel_dvo_init(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_dvo *intel_dvo;
        struct intel_connector *intel_connector;
-       struct i2c_adapter *i2cbus = NULL;
-       int ret = 0;
        int i;
        int encoder_type = DRM_MODE_ENCODER_NONE;
 
@@ -360,16 +362,14 @@ void intel_dvo_init(struct drm_device *dev)
        }
 
        intel_encoder = &intel_dvo->base;
-
-       /* Set up the DDC bus */
-       intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
-       if (!intel_encoder->ddc_bus)
-               goto free_intel;
+       drm_encoder_init(dev, &intel_encoder->base,
+                        &intel_dvo_enc_funcs, encoder_type);
 
        /* Now, try to find a controller */
        for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
                struct drm_connector *connector = &intel_connector->base;
                const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+               struct i2c_adapter *i2c;
                int gpio;
 
                /* Allow the I2C driver info to specify the GPIO to be used in
@@ -379,24 +379,18 @@ void intel_dvo_init(struct drm_device *dev)
                if (dvo->gpio != 0)
                        gpio = dvo->gpio;
                else if (dvo->type == INTEL_DVO_CHIP_LVDS)
-                       gpio = GPIOB;
+                       gpio = GMBUS_PORT_SSC;
                else
-                       gpio = GPIOE;
+                       gpio = GMBUS_PORT_DPB;
 
                /* 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 (i2cbus != NULL)
-                       intel_i2c_destroy(i2cbus);
-               if (!(i2cbus = intel_i2c_create(dev, gpio,
-                       gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-                       continue;
-               }
+               i2c = &dev_priv->gmbus[gpio].adapter;
 
                intel_dvo->dev = *dvo;
-               ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
-               if (!ret)
+               if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
                        continue;
 
                intel_encoder->type = INTEL_OUTPUT_DVO;
@@ -427,13 +421,10 @@ void intel_dvo_init(struct drm_device *dev)
                connector->interlace_allowed = false;
                connector->doublescan_allowed = false;
 
-               drm_encoder_init(dev, &intel_encoder->enc,
-                                &intel_dvo_enc_funcs, encoder_type);
-               drm_encoder_helper_add(&intel_encoder->enc,
+               drm_encoder_helper_add(&intel_encoder->base,
                                       &intel_dvo_helper_funcs);
 
-               drm_mode_connector_attach_encoder(&intel_connector->base,
-                                                 &intel_encoder->enc);
+               intel_connector_attach_encoder(intel_connector, intel_encoder);
                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.
@@ -451,11 +442,7 @@ void intel_dvo_init(struct drm_device *dev)
                return;
        }
 
-       intel_i2c_destroy(intel_encoder->ddc_bus);
-       /* Didn't find a chip, so tear down. */
-       if (i2cbus != NULL)
-               intel_i2c_destroy(i2cbus);
-free_intel:
+       drm_encoder_cleanup(&intel_encoder->base);
        kfree(intel_dvo);
        kfree(intel_connector);
 }
index b61966c126d3e3839d33be6c8df2c0170c5d1376..af2a1dddc28e2e908529db44a24cea44ff10d387 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-struct intel_fbdev {
-       struct drm_fb_helper helper;
-       struct intel_framebuffer ifb;
-       struct list_head fbdev_list;
-       struct drm_display_mode *our_mode;
-};
-
 static struct fb_ops intelfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
@@ -75,7 +68,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
        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;
+       int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
 
        /* we don't do packed 24bpp */
        if (sizes->surface_bpp == 24)
@@ -100,19 +93,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
 
        mutex_lock(&dev->struct_mutex);
 
-       ret = intel_pin_and_fence_fb_obj(dev, fbo);
+       /* Flush everything out, we'll be doing GTT only from now on */
+       ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
        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 */
-       ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
-       if (ret) {
-               DRM_ERROR("failed to bind fb: %d.\n", ret);
-               goto out_unpin;
-       }
-
        info = framebuffer_alloc(0, device);
        if (!info) {
                ret = -ENOMEM;
@@ -142,7 +129,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
                goto out_unpin;
        }
        info->apertures->ranges[0].base = dev->mode_config.fb_base;
-       if (IS_I9XX(dev))
+       if (!IS_GEN2(dev))
                info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
        else
                info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
@@ -219,8 +206,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
        .fb_probe = intel_fb_find_or_create_single,
 };
 
-int intel_fbdev_destroy(struct drm_device *dev,
-                       struct intel_fbdev *ifbdev)
+static void intel_fbdev_destroy(struct drm_device *dev,
+                               struct intel_fbdev *ifbdev)
 {
        struct fb_info *info;
        struct intel_framebuffer *ifb = &ifbdev->ifb;
@@ -238,11 +225,9 @@ int intel_fbdev_destroy(struct drm_device *dev,
 
        drm_framebuffer_cleanup(&ifb->base);
        if (ifb->obj) {
-               drm_gem_object_unreference(ifb->obj);
+               drm_gem_object_unreference_unlocked(ifb->obj);
                ifb->obj = NULL;
        }
-
-       return 0;
 }
 
 int intel_fbdev_init(struct drm_device *dev)
index 926934a482ec085c63256567e27f0309b51b24cf..0d0273e7b029296725032098d26eeb08fb8b5bc6 100644 (file)
 struct intel_hdmi {
        struct intel_encoder base;
        u32 sdvox_reg;
+       int ddc_bus;
        bool has_hdmi_sink;
+       bool has_audio;
+       int force_audio;
+       struct drm_property *force_audio_property;
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
+       return container_of(encoder, struct intel_hdmi, base.base);
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_hdmi, base);
+}
+
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if)
+{
+       uint8_t *data = (uint8_t *)avi_if;
+       uint8_t sum = 0;
+       unsigned i;
+
+       avi_if->checksum = 0;
+       avi_if->ecc = 0;
+
+       for (i = 0; i < sizeof(*avi_if); i++)
+               sum += data[i];
+
+       avi_if->checksum = 0x100 - sum;
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+       struct dip_infoframe avi_if = {
+               .type = DIP_TYPE_AVI,
+               .ver = DIP_VERSION_AVI,
+               .len = DIP_LEN_AVI,
+       };
+       uint32_t *data = (uint32_t *)&avi_if;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 port;
+       unsigned i;
+
+       if (!intel_hdmi->has_hdmi_sink)
+               return;
+
+       /* XXX first guess at handling video port, is this corrent? */
+       if (intel_hdmi->sdvox_reg == SDVOB)
+               port = VIDEO_DIP_PORT_B;
+       else if (intel_hdmi->sdvox_reg == SDVOC)
+               port = VIDEO_DIP_PORT_C;
+       else
+               return;
+
+       I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+                  VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+
+       intel_dip_infoframe_csum(&avi_if);
+       for (i = 0; i < sizeof(avi_if); i += 4) {
+               I915_WRITE(VIDEO_DIP_DATA, *data);
+               data++;
+       }
+
+       I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+                  VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
+                  VIDEO_DIP_ENABLE_AVI);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -65,10 +129,13 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
 
-       if (intel_hdmi->has_hdmi_sink) {
+       /* Required on CPT */
+       if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
+               sdvox |= HDMI_MODE_SELECT;
+
+       if (intel_hdmi->has_audio) {
                sdvox |= SDVO_AUDIO_ENABLE;
-               if (HAS_PCH_CPT(dev))
-                       sdvox |= HDMI_MODE_SELECT;
+               sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
        }
 
        if (intel_crtc->pipe == 1) {
@@ -80,6 +147,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 
        I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
        POSTING_READ(intel_hdmi->sdvox_reg);
+
+       intel_hdmi_set_avi_infoframe(encoder);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -141,36 +210,85 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-       struct edid *edid = NULL;
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct edid *edid;
        enum drm_connector_status status = connector_status_disconnected;
 
        intel_hdmi->has_hdmi_sink = false;
-       edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
+       intel_hdmi->has_audio = false;
+       edid = drm_get_edid(connector,
+                           &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 
        if (edid) {
                if (edid->input & DRM_EDID_INPUT_DIGITAL) {
                        status = connector_status_connected;
                        intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+                       intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
                }
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
 
+       if (status == connector_status_connected) {
+               if (intel_hdmi->force_audio)
+                       intel_hdmi->has_audio = intel_hdmi->force_audio > 0;
+       }
+
        return status;
 }
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
        /* We should parse the EDID data and find out if it's an HDMI sink so
         * we can send audio to it.
         */
 
-       return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
+       return intel_ddc_get_modes(connector,
+                                  &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+}
+
+static int
+intel_hdmi_set_property(struct drm_connector *connector,
+                     struct drm_property *property,
+                     uint64_t val)
+{
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       int ret;
+
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret)
+               return ret;
+
+       if (property == intel_hdmi->force_audio_property) {
+               if (val == intel_hdmi->force_audio)
+                       return 0;
+
+               intel_hdmi->force_audio = val;
+
+               if (val > 0 && intel_hdmi->has_audio)
+                       return 0;
+               if (val < 0 && !intel_hdmi->has_audio)
+                       return 0;
+
+               intel_hdmi->has_audio = val > 0;
+               goto done;
+       }
+
+       return -EINVAL;
+
+done:
+       if (intel_hdmi->base.base.crtc) {
+               struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
+               drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                        crtc->x, crtc->y,
+                                        crtc->fb);
+       }
+
+       return 0;
 }
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -192,19 +310,34 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = intel_hdmi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = intel_hdmi_set_property,
        .destroy = intel_hdmi_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
        .get_modes = intel_hdmi_get_modes,
        .mode_valid = intel_hdmi_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
        .destroy = intel_encoder_destroy,
 };
 
+static void
+intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+
+       intel_hdmi->force_audio_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+       if (intel_hdmi->force_audio_property) {
+               intel_hdmi->force_audio_property->values[0] = -1;
+               intel_hdmi->force_audio_property->values[1] = 1;
+               drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
+       }
+}
+
 void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -224,6 +357,9 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        }
 
        intel_encoder = &intel_hdmi->base;
+       drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
        connector = &intel_connector->base;
        drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
                           DRM_MODE_CONNECTOR_HDMIA);
@@ -239,39 +375,33 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        /* Set up the DDC bus. */
        if (sdvox_reg == SDVOB) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
                dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == SDVOC) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
                dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIB) {
                intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
-                                                               "HDMIB");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
                dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIC) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
-                                                               "HDMIC");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
                dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMID) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
-                                                               "HDMID");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
                dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
        }
-       if (!intel_encoder->ddc_bus)
-               goto err_connector;
 
        intel_hdmi->sdvox_reg = sdvox_reg;
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
-                        DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+
+       intel_hdmi_add_properties(intel_hdmi, connector);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
 
        /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -282,13 +412,4 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
                u32 temp = I915_READ(PEG_BAND_GAP_DATA);
                I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
        }
-
-       return;
-
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(intel_hdmi);
-       kfree(intel_connector);
-
-       return;
 }
index c2649c7df14c7e654aba8eb495c3874c698707b5..2be4f728ed0c7b250550613cc93259462db9735a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2008 Intel Corporation
+ * Copyright © 2006-2008,2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  *
  * Authors:
  *     Eric Anholt <eric@anholt.net>
+ *     Chris Wilson <chris@chris-wilson.co.uk>
  */
 #include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
+/* Intel GPIO access functions */
+
+#define I2C_RISEFALL_TIME 20
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+       return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+struct intel_gpio {
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+       struct drm_i915_private *dev_priv;
+       u32 reg;
+};
+
+void
+intel_i2c_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       if (HAS_PCH_SPLIT(dev))
+               I915_WRITE(PCH_GMBUS0, 0);
+       else
+               I915_WRITE(GMBUS0, 0);
+}
+
+static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
+{
+       u32 val;
 
        /* When using bit bashing for I2C, this bit needs to be set to 1 */
-       if (!IS_PINEVIEW(dev))
+       if (!IS_PINEVIEW(dev_priv->dev))
                return;
+
+       val = I915_READ(DSPCLK_GATE_D);
        if (enable)
-               I915_WRITE(DSPCLK_GATE_D,
-                       I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
+               val |= DPCUNIT_CLOCK_GATE_DISABLE;
        else
-               I915_WRITE(DSPCLK_GATE_D,
-                       I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+               val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, val);
 }
 
-/*
- * Intel GPIO access functions
- */
+static u32 get_reserved(struct intel_gpio *gpio)
+{
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       struct drm_device *dev = dev_priv->dev;
+       u32 reserved = 0;
 
-#define I2C_RISEFALL_TIME 20
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       return reserved;
+}
 
 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);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+       I915_WRITE(gpio->reg, reserved);
+       return (I915_READ(gpio->reg) & 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);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+       I915_WRITE(gpio->reg, reserved);
+       return (I915_READ(gpio->reg) & 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);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       u32 clock_bits;
 
        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 */
+
+       I915_WRITE(gpio->reg, reserved | clock_bits);
+       POSTING_READ(gpio->reg);
 }
 
 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);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       u32 data_bits;
 
        if (state_high)
                data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
@@ -115,109 +141,313 @@ static void set_data(void *data, int state_high)
                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 */
+       I915_WRITE(gpio->reg, reserved | data_bits);
+       POSTING_READ(gpio->reg);
 }
 
-/* Clears the GMBUS setup.  Our driver doesn't make use of the GMBUS I2C
- * engine, but if the BIOS leaves it enabled, then that can break our use
- * of the bit-banging I2C interfaces.  This is notably the case with the
- * Mac Mini in EFI mode.
- */
-void
-intel_i2c_reset_gmbus(struct drm_device *dev)
+static struct i2c_adapter *
+intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       static const int map_pin_to_reg[] = {
+               0,
+               GPIOB,
+               GPIOA,
+               GPIOC,
+               GPIOD,
+               GPIOE,
+               0,
+               GPIOF,
+       };
+       struct intel_gpio *gpio;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_GMBUS0, 0);
-       } else {
-               I915_WRITE(GMBUS0, 0);
+       if (pin < 1 || pin > 7)
+               return NULL;
+
+       gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
+       if (gpio == NULL)
+               return NULL;
+
+       gpio->reg = map_pin_to_reg[pin];
+       if (HAS_PCH_SPLIT(dev_priv->dev))
+               gpio->reg += PCH_GPIOA - GPIOA;
+       gpio->dev_priv = dev_priv;
+
+       snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+       gpio->adapter.owner = THIS_MODULE;
+       gpio->adapter.algo_data = &gpio->algo;
+       gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
+       gpio->algo.setsda = set_data;
+       gpio->algo.setscl = set_clock;
+       gpio->algo.getsda = get_data;
+       gpio->algo.getscl = get_clock;
+       gpio->algo.udelay = I2C_RISEFALL_TIME;
+       gpio->algo.timeout = usecs_to_jiffies(2200);
+       gpio->algo.data = gpio;
+
+       if (i2c_bit_add_bus(&gpio->adapter))
+               goto out_free;
+
+       return &gpio->adapter;
+
+out_free:
+       kfree(gpio);
+       return NULL;
+}
+
+static int
+intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
+                    struct i2c_adapter *adapter,
+                    struct i2c_msg *msgs,
+                    int num)
+{
+       struct intel_gpio *gpio = container_of(adapter,
+                                              struct intel_gpio,
+                                              adapter);
+       int ret;
+
+       intel_i2c_reset(dev_priv->dev);
+
+       intel_i2c_quirk_set(dev_priv, true);
+       set_data(gpio, 1);
+       set_clock(gpio, 1);
+       udelay(I2C_RISEFALL_TIME);
+
+       ret = adapter->algo->master_xfer(adapter, msgs, num);
+
+       set_data(gpio, 1);
+       set_clock(gpio, 1);
+       intel_i2c_quirk_set(dev_priv, false);
+
+       return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter,
+          struct i2c_msg *msgs,
+          int num)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = adapter->algo_data;
+       int i, reg_offset;
+
+       if (bus->force_bit)
+               return intel_i2c_quirk_xfer(dev_priv,
+                                           bus->force_bit, msgs, num);
+
+       reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+
+       I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+
+       for (i = 0; i < num; i++) {
+               u16 len = msgs[i].len;
+               u8 *buf = msgs[i].buf;
+
+               if (msgs[i].flags & I2C_M_RD) {
+                       I915_WRITE(GMBUS1 + reg_offset,
+                                  GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+                                  (len << GMBUS_BYTE_COUNT_SHIFT) |
+                                  (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                                  GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+                       POSTING_READ(GMBUS2+reg_offset);
+                       do {
+                               u32 val, loop = 0;
+
+                               if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                                       goto timeout;
+                               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                                       return 0;
+
+                               val = I915_READ(GMBUS3 + reg_offset);
+                               do {
+                                       *buf++ = val & 0xff;
+                                       val >>= 8;
+                               } while (--len && ++loop < 4);
+                       } while (len);
+               } else {
+                       u32 val, loop;
+
+                       val = loop = 0;
+                       do {
+                               val |= *buf++ << (8 * loop);
+                       } while (--len && ++loop < 4);
+
+                       I915_WRITE(GMBUS3 + reg_offset, val);
+                       I915_WRITE(GMBUS1 + reg_offset,
+                                  (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+                                  (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
+                                  (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                                  GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+                       POSTING_READ(GMBUS2+reg_offset);
+
+                       while (len) {
+                               if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                                       goto timeout;
+                               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                                       return 0;
+
+                               val = loop = 0;
+                               do {
+                                       val |= *buf++ << (8 * loop);
+                               } while (--len && ++loop < 4);
+
+                               I915_WRITE(GMBUS3 + reg_offset, val);
+                               POSTING_READ(GMBUS2+reg_offset);
+                       }
+               }
+
+               if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+                       goto timeout;
+               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                       return 0;
        }
+
+       return num;
+
+timeout:
+       DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
+                bus->reg0 & 0xff, bus->adapter.name);
+       /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+       bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
+       if (!bus->force_bit)
+               return -ENOMEM;
+
+       return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
 }
 
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+
+       if (bus->force_bit)
+               bus->force_bit->algo->functionality(bus->force_bit);
+
+       return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+               /* I2C_FUNC_10BIT_ADDR | */
+               I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+               I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
+}
+
+static const struct i2c_algorithm gmbus_algorithm = {
+       .master_xfer    = gmbus_xfer,
+       .functionality  = gmbus_func
+};
+
 /**
- * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
  * @dev: DRM device
- * @output: driver specific output device
- * @reg: GPIO reg to use
- * @name: name for this bus
- * @slave_addr: slave address (if fixed)
- *
- * 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 i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                    const char *name)
+int intel_setup_gmbus(struct drm_device *dev)
 {
-       struct intel_i2c_chan *chan;
+       static const char *names[GMBUS_NUM_PORTS] = {
+               "disabled",
+               "ssc",
+               "vga",
+               "panel",
+               "dpc",
+               "dpb",
+               "reserved"
+               "dpd",
+       };
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret, i;
 
-       chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
-       if (!chan)
-               goto out_free;
+       dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+                                 GFP_KERNEL);
+       if (dev_priv->gmbus == NULL)
+               return -ENOMEM;
 
-       chan->drm_dev = dev;
-       chan->reg = reg;
-       snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
-       chan->adapter.owner = THIS_MODULE;
-       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;
+       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
 
-       intel_i2c_reset_gmbus(dev);
+               bus->adapter.owner = THIS_MODULE;
+               bus->adapter.class = I2C_CLASS_DDC;
+               snprintf(bus->adapter.name,
+                        I2C_NAME_SIZE,
+                        "gmbus %s",
+                        names[i]);
 
-       /* JJJ:  raise SCL and SDA? */
-       intel_i2c_quirk_set(dev, true);
-       set_data(chan, 1);
-       set_clock(chan, 1);
-       intel_i2c_quirk_set(dev, false);
-       udelay(20);
+               bus->adapter.dev.parent = &dev->pdev->dev;
+               bus->adapter.algo_data  = dev_priv;
 
-       return &chan->adapter;
+               bus->adapter.algo = &gmbus_algorithm;
+               ret = i2c_add_adapter(&bus->adapter);
+               if (ret)
+                       goto err;
 
-out_free:
-       kfree(chan);
-       return NULL;
+               /* By default use a conservative clock rate */
+               bus->reg0 = i | GMBUS_RATE_100KHZ;
+
+               /* XXX force bit banging until GMBUS is fully debugged */
+               bus->force_bit = intel_gpio_create(dev_priv, i);
+       }
+
+       intel_i2c_reset(dev_priv->dev);
+
+       return 0;
+
+err:
+       while (--i) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+               i2c_del_adapter(&bus->adapter);
+       }
+       kfree(dev_priv->gmbus);
+       dev_priv->gmbus = NULL;
+       return ret;
 }
 
-/**
- * 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 i2c_adapter *adapter)
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       /* speed:
+        * 0x0 = 100 KHz
+        * 0x1 = 50 KHz
+        * 0x2 = 400 KHz
+        * 0x3 = 1000 Khz
+        */
+       bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8);
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       if (force_bit) {
+               if (bus->force_bit == NULL) {
+                       struct drm_i915_private *dev_priv = adapter->algo_data;
+                       bus->force_bit = intel_gpio_create(dev_priv,
+                                                          bus->reg0 & 0xff);
+               }
+       } else {
+               if (bus->force_bit) {
+                       i2c_del_adapter(bus->force_bit);
+                       kfree(bus->force_bit);
+                       bus->force_bit = NULL;
+               }
+       }
+}
+
+void intel_teardown_gmbus(struct drm_device *dev)
 {
-       struct intel_i2c_chan *chan;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
 
-       if (!adapter)
+       if (dev_priv->gmbus == NULL)
                return;
 
-       chan = container_of(adapter,
-                           struct intel_i2c_chan,
-                           adapter);
-       i2c_del_adapter(&chan->adapter);
-       kfree(chan);
+       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+               if (bus->force_bit) {
+                       i2c_del_adapter(bus->force_bit);
+                       kfree(bus->force_bit);
+               }
+               i2c_del_adapter(&bus->adapter);
+       }
+
+       kfree(dev_priv->gmbus);
+       dev_priv->gmbus = NULL;
 }
index 6ec39a86ed06d2bd6e716611f3ab4d384d950636..f1a649990ea9e61d5f7ff6f8b15e127d6fcc2f17 100644 (file)
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
        struct intel_encoder base;
+
+       struct edid *edid;
+
        int fitting_mode;
        u32 pfit_control;
        u32 pfit_pgm_ratios;
+       bool pfit_dirty;
+
+       struct drm_display_mode *fixed_mode;
 };
 
-static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
-}
-
-/**
- * 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, reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_CPU_CTL;
-       else
-               reg = BLC_PWM_CTL;
-
-       blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(reg, (blc_pwm_ctl |
-                                (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+       return container_of(encoder, struct intel_lvds, base.base);
 }
 
-/**
- * Returns the maximum level of the backlight duty cycle field.
- */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_PCH_CTL2;
-       else
-               reg = BLC_PWM_CTL;
-
-       return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-               BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_lvds, base);
 }
 
 /**
  * Sets the power state for the panel.
  */
-static void intel_lvds_set_power(struct drm_device *dev, bool on)
+static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
 {
+       struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, status_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
-               status_reg = PCH_PP_STATUS;
                lvds_reg = PCH_LVDS;
        } else {
                ctl_reg = PP_CONTROL;
-               status_reg = PP_STATUS;
                lvds_reg = LVDS;
        }
 
        if (on) {
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
-               POSTING_READ(lvds_reg);
-
-               I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
-                          POWER_TARGET_ON);
-               if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
-                       DRM_ERROR("timed out waiting to enable LVDS pipe");
-
-               intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+               intel_panel_set_backlight(dev, dev_priv->backlight_level);
        } else {
-               intel_lvds_set_backlight(dev, 0);
+               dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+               intel_panel_set_backlight(dev, 0);
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
 
-               I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
-                          ~POWER_TARGET_ON);
-               if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
-                       DRM_ERROR("timed out waiting for LVDS pipe to turn off");
+               if (intel_lvds->pfit_control) {
+                       if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+                               DRM_ERROR("timed out waiting for panel to power off\n");
+                       I915_WRITE(PFIT_CONTROL, 0);
+                       intel_lvds->pfit_control = 0;
+                       intel_lvds->pfit_dirty = false;
+               }
 
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
-               POSTING_READ(lvds_reg);
        }
+       POSTING_READ(lvds_reg);
 }
 
 static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 {
-       struct drm_device *dev = encoder->dev;
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
        if (mode == DRM_MODE_DPMS_ON)
-               intel_lvds_set_power(dev, true);
+               intel_lvds_set_power(intel_lvds, true);
        else
-               intel_lvds_set_power(dev, false);
+               intel_lvds_set_power(intel_lvds, false);
 
        /* XXX: We never power down the LVDS pairs. */
 }
@@ -146,16 +120,13 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 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;
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+       struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
 
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-       }
+       if (mode->hdisplay > fixed_mode->hdisplay)
+               return MODE_PANEL;
+       if (mode->vdisplay > fixed_mode->vdisplay)
+               return MODE_PANEL;
 
        return MODE_OK;
 }
@@ -223,12 +194,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        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_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
        struct drm_encoder *tmp_encoder;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 
        /* Should never happen!! */
-       if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+       if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
                DRM_ERROR("Can't support LVDS on pipe A\n");
                return false;
        }
@@ -241,9 +212,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                        return false;
                }
        }
-       /* If we don't have a panel mode, there is nothing we can do */
-       if (dev_priv->panel_fixed_mode == NULL)
-               return true;
 
        /*
         * We have timings from the BIOS for the panel, put them in
@@ -251,7 +219,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
         * with the panel scaling set up to source from the H/VDisplay
         * of the original mode.
         */
-       intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+       intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
 
        if (HAS_PCH_SPLIT(dev)) {
                intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -260,8 +228,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
        /* Make sure pre-965s set dither correctly */
-       if (!IS_I965G(dev)) {
-               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+       if (INTEL_INFO(dev)->gen < 4) {
+               if (dev_priv->lvds_dither)
                        pfit_control |= PANEL_8TO6_DITHER_ENABLE;
        }
 
@@ -271,7 +239,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                goto out;
 
        /* 965+ wants fuzzy fitting */
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
                                 PFIT_FILTER_FUZZY);
 
@@ -297,7 +265,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 
        case DRM_MODE_SCALE_ASPECT:
                /* Scale but preserve the aspect ratio */
-               if (IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen >= 4) {
                        u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
                        u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 
@@ -356,7 +324,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                 * Fortunately this is all done for us in hw.
                 */
                pfit_control |= PFIT_ENABLE;
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        pfit_control |= PFIT_SCALING_AUTO;
                else
                        pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -369,8 +337,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
 out:
-       intel_lvds->pfit_control = pfit_control;
-       intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+       if (pfit_control != intel_lvds->pfit_control ||
+           pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
+               intel_lvds->pfit_control = pfit_control;
+               intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+               intel_lvds->pfit_dirty = true;
+       }
        dev_priv->lvds_border_bits = border;
 
        /*
@@ -386,30 +358,60 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_CPU_CTL;
-       else
-               reg = BLC_PWM_CTL;
-
-       dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-                                      BACKLIGHT_DUTY_CYCLE_MASK);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+       dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+       /* We try to do the minimum that is necessary in order to unlock
+        * the registers for mode setting.
+        *
+        * On Ironlake, this is quite simple as we just set the unlock key
+        * and ignore all subtleties. (This may cause some issues...)
+        *
+        * Prior to Ironlake, we must disable the pipe if we want to adjust
+        * the panel fitter. However at all other times we can just reset
+        * the registers regardless.
+        */
 
-       intel_lvds_set_power(dev, false);
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else if (intel_lvds->pfit_dirty) {
+               I915_WRITE(PP_CONTROL,
+                          (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
+                          & ~POWER_TARGET_ON);
+       } else {
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+       }
 }
 
-static void intel_lvds_commit( struct drm_encoder *encoder)
+static void intel_lvds_commit(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       if (dev_priv->backlight_duty_cycle == 0)
-               dev_priv->backlight_duty_cycle =
-                       intel_lvds_get_max_backlight(dev);
+       if (dev_priv->backlight_level == 0)
+               dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+
+       /* Undo any unlocking done in prepare to prevent accidental
+        * adjustment of the registers.
+        */
+       if (HAS_PCH_SPLIT(dev)) {
+               u32 val = I915_READ(PCH_PP_CONTROL);
+               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+                       I915_WRITE(PCH_PP_CONTROL, val & 0x3);
+       } else {
+               u32 val = I915_READ(PP_CONTROL);
+               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+                       I915_WRITE(PP_CONTROL, val & 0x3);
+       }
 
-       intel_lvds_set_power(dev, true);
+       /* Always do a full power on as we do not know what state
+        * we were left in.
+        */
+       intel_lvds_set_power(intel_lvds, true);
 }
 
 static void intel_lvds_mode_set(struct drm_encoder *encoder,
@@ -418,7 +420,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
        /*
         * The LVDS pin pair will already have been turned on in the
@@ -429,13 +431,23 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
        if (HAS_PCH_SPLIT(dev))
                return;
 
+       if (!intel_lvds->pfit_dirty)
+               return;
+
        /*
         * 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.
         */
+       DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+                     intel_lvds->pfit_control,
+                     intel_lvds->pfit_pgm_ratios);
+       if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
+
        I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
        I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+       intel_lvds->pfit_dirty = false;
 }
 
 /**
@@ -465,38 +477,22 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = 0;
-
-       if (dev_priv->lvds_edid_good) {
-               ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+       struct drm_display_mode *mode;
 
-               if (ret)
-                       return ret;
+       if (intel_lvds->edid) {
+               drm_mode_connector_update_edid_property(connector,
+                                                       intel_lvds->edid);
+               return drm_add_edid_modes(connector, intel_lvds->edid);
        }
 
-       /* 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;
-
-               mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
-               drm_mode_probed_add(connector, mode);
-
-               return 1;
-       }
+       mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+       if (mode == 0)
+               return 0;
 
-       return 0;
+       drm_mode_probed_add(connector, mode);
+       return 1;
 }
 
 static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
@@ -587,18 +583,17 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                   struct drm_property *property,
                                   uint64_t value)
 {
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
        struct drm_device *dev = connector->dev;
 
-       if (property == dev->mode_config.scaling_mode_property &&
-                               connector->encoder) {
-               struct drm_crtc *crtc = connector->encoder->crtc;
-               struct drm_encoder *encoder = connector->encoder;
-               struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       if (property == dev->mode_config.scaling_mode_property) {
+               struct drm_crtc *crtc = intel_lvds->base.base.crtc;
 
                if (value == DRM_MODE_SCALE_NONE) {
                        DRM_DEBUG_KMS("no scaling not supported\n");
-                       return 0;
+                       return -EINVAL;
                }
+
                if (intel_lvds->fitting_mode == value) {
                        /* the LVDS scaling property is not changed */
                        return 0;
@@ -628,7 +623,7 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
 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_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
@@ -726,16 +721,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
  * Find the reduced downclock for LVDS in EDID.
  */
 static void intel_find_lvds_downclock(struct drm_device *dev,
-                               struct drm_connector *connector)
+                                     struct drm_display_mode *fixed_mode,
+                                     struct drm_connector *connector)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *scan, *panel_fixed_mode;
+       struct drm_display_mode *scan;
        int temp_downclock;
 
-       panel_fixed_mode = dev_priv->panel_fixed_mode;
-       temp_downclock = panel_fixed_mode->clock;
-
-       mutex_lock(&dev->mode_config.mutex);
+       temp_downclock = fixed_mode->clock;
        list_for_each_entry(scan, &connector->probed_modes, head) {
                /*
                 * If one mode has the same resolution with the fixed_panel
@@ -744,14 +737,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
                 * case we can set the different FPx0/1 to dynamically select
                 * between low and high frequency.
                 */
-               if (scan->hdisplay == panel_fixed_mode->hdisplay &&
-                       scan->hsync_start == panel_fixed_mode->hsync_start &&
-                       scan->hsync_end == panel_fixed_mode->hsync_end &&
-                       scan->htotal == panel_fixed_mode->htotal &&
-                       scan->vdisplay == panel_fixed_mode->vdisplay &&
-                       scan->vsync_start == panel_fixed_mode->vsync_start &&
-                       scan->vsync_end == panel_fixed_mode->vsync_end &&
-                       scan->vtotal == panel_fixed_mode->vtotal) {
+               if (scan->hdisplay == fixed_mode->hdisplay &&
+                   scan->hsync_start == fixed_mode->hsync_start &&
+                   scan->hsync_end == fixed_mode->hsync_end &&
+                   scan->htotal == fixed_mode->htotal &&
+                   scan->vdisplay == fixed_mode->vdisplay &&
+                   scan->vsync_start == fixed_mode->vsync_start &&
+                   scan->vsync_end == fixed_mode->vsync_end &&
+                   scan->vtotal == fixed_mode->vtotal) {
                        if (scan->clock < temp_downclock) {
                                /*
                                 * The downclock is already found. But we
@@ -761,17 +754,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
                        }
                }
        }
-       mutex_unlock(&dev->mode_config.mutex);
-       if (temp_downclock < panel_fixed_mode->clock &&
-           i915_lvds_downclock) {
+       if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
                /* We found the downclock for LVDS. */
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
                DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
-                               "Normal clock %dKhz, downclock %dKhz\n",
-                               panel_fixed_mode->clock, temp_downclock);
+                             "Normal clock %dKhz, downclock %dKhz\n",
+                             fixed_mode->clock, temp_downclock);
        }
-       return;
 }
 
 /*
@@ -780,38 +770,67 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
  * If it is present, return 1.
  * If it is not present, return false.
  * If no child dev is parsed from VBT, it assumes that the LVDS is present.
- * Note: The addin_offset should also be checked for LVDS panel.
- * Only when it is non-zero, it is assumed that it is present.
  */
-static int lvds_is_present_in_vbt(struct drm_device *dev)
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+                                  u8 *i2c_pin)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct child_device_config *p_child;
-       int i, ret;
+       int i;
 
        if (!dev_priv->child_dev_num)
-               return 1;
+               return true;
 
-       ret = 0;
        for (i = 0; i < dev_priv->child_dev_num; i++) {
-               p_child = dev_priv->child_dev + i;
-               /*
-                * If the device type is not LFP, continue.
-                * If the device type is 0x22, it is also regarded as LFP.
+               struct child_device_config *child = dev_priv->child_dev + i;
+
+               /* If the device type is not LFP, continue.
+                * We have to check both the new identifiers as well as the
+                * old for compatibility with some BIOSes.
                 */
-               if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
-                       p_child->device_type != DEVICE_TYPE_LFP)
+               if (child->device_type != DEVICE_TYPE_INT_LFP &&
+                   child->device_type != DEVICE_TYPE_LFP)
                        continue;
 
-               /* The addin_offset should be checked. Only when it is
-                * non-zero, it is regarded as present.
+               if (child->i2c_pin)
+                   *i2c_pin = child->i2c_pin;
+
+               /* However, we cannot trust the BIOS writers to populate
+                * the VBT correctly.  Since LVDS requires additional
+                * information from AIM blocks, a non-zero addin offset is
+                * a good indicator that the LVDS is actually present.
                 */
-               if (p_child->addin_offset) {
-                       ret = 1;
-                       break;
-               }
+               if (child->addin_offset)
+                       return true;
+
+               /* But even then some BIOS writers perform some black magic
+                * and instantiate the device without reference to any
+                * additional data.  Trust that if the VBT was written into
+                * the OpRegion then they have validated the LVDS's existence.
+                */
+               if (dev_priv->opregion.vbt)
+                       return true;
        }
-       return ret;
+
+       return false;
+}
+
+static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 buf = 0;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0xA0,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &buf,
+               },
+       };
+       struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter;
+       /* XXX this only appears to work when using GMBUS */
+       if (intel_gmbus_is_forced_bit(i2c))
+               return true;
+       return i2c_transfer(i2c, msgs, 1) == 1;
 }
 
 /**
@@ -832,13 +851,15 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
        u32 lvds;
-       int pipe, gpio = GPIOC;
+       int pipe;
+       u8 pin;
 
        /* Skip init on machines we know falsely report LVDS */
        if (dmi_check_system(intel_no_lvds))
                return;
 
-       if (!lvds_is_present_in_vbt(dev)) {
+       pin = GMBUS_PORT_PANEL;
+       if (!lvds_is_present_in_vbt(dev, &pin)) {
                DRM_DEBUG_KMS("LVDS is not present in VBT\n");
                return;
        }
@@ -846,11 +867,15 @@ void intel_lvds_init(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev)) {
                if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
                        return;
-               if (dev_priv->edp_support) {
+               if (dev_priv->edp.support) {
                        DRM_DEBUG_KMS("disable LVDS for eDP support\n");
                        return;
                }
-               gpio = PCH_GPIOC;
+       }
+
+       if (!intel_lvds_ddc_probe(dev, pin)) {
+               DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
+               return;
        }
 
        intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
@@ -864,16 +889,20 @@ void intel_lvds_init(struct drm_device *dev)
                return;
        }
 
+       if (!HAS_PCH_SPLIT(dev)) {
+               intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
+       }
+
        intel_encoder = &intel_lvds->base;
-       encoder = &intel_encoder->enc;
+       encoder = &intel_encoder->base;
        connector = &intel_connector->base;
        drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
                           DRM_MODE_CONNECTOR_LVDS);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
                         DRM_MODE_ENCODER_LVDS);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
 
        intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
@@ -904,43 +933,41 @@ void intel_lvds_init(struct drm_device *dev)
         *    if closed, act like it's not there for now
         */
 
-       /* Set up the DDC bus. */
-       intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
-       if (!intel_encoder->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.
         */
-       dev_priv->lvds_edid_good = true;
+       intel_lvds->edid = drm_get_edid(connector,
+                                       &dev_priv->gmbus[pin].adapter);
 
-       if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
-               dev_priv->lvds_edid_good = false;
+       if (!intel_lvds->edid) {
+               /* 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;
+       }
 
        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 =
+                       intel_lvds->fixed_mode =
                                drm_mode_duplicate(dev, scan);
-                       mutex_unlock(&dev->mode_config.mutex);
-                       intel_find_lvds_downclock(dev, connector);
+                       intel_find_lvds_downclock(dev,
+                                                 intel_lvds->fixed_mode,
+                                                 connector);
                        goto out;
                }
-               mutex_unlock(&dev->mode_config.mutex);
        }
 
        /* Failed to get EDID, what about VBT? */
        if (dev_priv->lfp_lvds_vbt_mode) {
-               mutex_lock(&dev->mode_config.mutex);
-               dev_priv->panel_fixed_mode =
+               intel_lvds->fixed_mode =
                        drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
-               mutex_unlock(&dev->mode_config.mutex);
-               if (dev_priv->panel_fixed_mode) {
-                       dev_priv->panel_fixed_mode->type |=
+               if (intel_lvds->fixed_mode) {
+                       intel_lvds->fixed_mode->type |=
                                DRM_MODE_TYPE_PREFERRED;
                        goto out;
                }
@@ -958,19 +985,19 @@ void intel_lvds_init(struct drm_device *dev)
 
        lvds = I915_READ(LVDS);
        pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-       crtc = intel_get_crtc_from_pipe(dev, pipe);
+       crtc = intel_get_crtc_for_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 |=
+               intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+               if (intel_lvds->fixed_mode) {
+                       intel_lvds->fixed_mode->type |=
                                DRM_MODE_TYPE_PREFERRED;
                        goto out;
                }
        }
 
        /* If we still don't have a mode after all that, give up. */
-       if (!dev_priv->panel_fixed_mode)
+       if (!intel_lvds->fixed_mode)
                goto failed;
 
 out:
@@ -997,8 +1024,6 @@ out:
 
 failed:
        DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
        kfree(intel_lvds);
index 4b1fd3d9c73cb7b5b6d70c2576f4262e8b01fc02..f70b7cf32bffc43a4325233e0ba11ab5726ce64f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2007, 2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * intel_ddc_probe
  *
  */
-bool intel_ddc_probe(struct intel_encoder *intel_encoder)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 {
+       struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
        u8 out_buf[] = { 0x0, 0x0};
        u8 buf[2];
-       int ret;
        struct i2c_msg msgs[] = {
                {
                        .addr = 0x50,
@@ -54,13 +54,7 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
                }
        };
 
-       intel_i2c_quirk_set(intel_encoder->enc.dev, true);
-       ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
-       intel_i2c_quirk_set(intel_encoder->enc.dev, false);
-       if (ret == 2)
-               return true;
-
-       return false;
+       return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
 }
 
 /**
@@ -76,9 +70,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
        struct edid *edid;
        int ret = 0;
 
-       intel_i2c_quirk_set(connector->dev, true);
        edid = drm_get_edid(connector, adapter);
-       intel_i2c_quirk_set(connector->dev, false);
        if (edid) {
                drm_mode_connector_update_edid_property(connector, edid);
                ret = drm_add_edid_modes(connector, edid);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
new file mode 100644 (file)
index 0000000..917c7dc
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2008 Intel Corporation <hong.liu@intel.com>
+ * Copyright 2008 Red Hat <mjg@redhat.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 INTEL AND/OR ITS SUPPLIERS 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/acpi.h>
+#include <acpi/video.h>
+
+#include "drmP.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+#define PCI_ASLE 0xe4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET   0x100
+#define OPREGION_SWSCI_OFFSET  0x200
+#define OPREGION_ASLE_OFFSET   0x300
+#define OPREGION_VBT_OFFSET    0x400
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI      (1<<0)
+#define MBOX_SWSCI     (1<<1)
+#define MBOX_ASLE      (1<<2)
+
+struct opregion_header {
+       u8 signature[16];
+       u32 size;
+       u32 opregion_ver;
+       u8 bios_ver[32];
+       u8 vbios_ver[16];
+       u8 driver_ver[16];
+       u32 mboxes;
+       u8 reserved[164];
+} __attribute__((packed));
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+       u32 drdy;       /* driver readiness */
+       u32 csts;       /* notification status */
+       u32 cevt;       /* current event */
+       u8 rsvd1[20];
+       u32 didl[8];    /* supported display devices ID list */
+       u32 cpdl[8];    /* currently presented display list */
+       u32 cadl[8];    /* currently active display list */
+       u32 nadl[8];    /* next active devices list */
+       u32 aslp;       /* ASL sleep time-out */
+       u32 tidx;       /* toggle table index */
+       u32 chpd;       /* current hotplug enable indicator */
+       u32 clid;       /* current lid state*/
+       u32 cdck;       /* current docking state */
+       u32 sxsw;       /* Sx state resume */
+       u32 evts;       /* ASL supported events */
+       u32 cnot;       /* current OS notification */
+       u32 nrdy;       /* driver status */
+       u8 rsvd2[60];
+} __attribute__((packed));
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+       u32 scic;       /* SWSCI command|status|data */
+       u32 parm;       /* command parameters */
+       u32 dslp;       /* driver sleep time-out */
+       u8 rsvd[244];
+} __attribute__((packed));
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+       u32 ardy;       /* driver readiness */
+       u32 aslc;       /* ASLE interrupt command */
+       u32 tche;       /* technology enabled indicator */
+       u32 alsi;       /* current ALS illuminance reading */
+       u32 bclp;       /* backlight brightness to set */
+       u32 pfit;       /* panel fitting state */
+       u32 cblv;       /* current brightness level */
+       u16 bclm[20];   /* backlight level duty cycle mapping table */
+       u32 cpfm;       /* current panel fitting mode */
+       u32 epfm;       /* enabled panel fitting modes */
+       u8 plut[74];    /* panel LUT and identifier */
+       u32 pfmb;       /* PWM freq and min brightness */
+       u8 rsvd[102];
+} __attribute__((packed));
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM     (1 << 0)
+#define ASLE_SET_BACKLIGHT     (1 << 1)
+#define ASLE_SET_PFIT          (1 << 2)
+#define ASLE_SET_PWM_FREQ      (1 << 3)
+#define ASLE_REQ_MSK           0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED  (1<<10)
+#define ASLE_BACKLIGHT_FAILED  (1<<12)
+#define ASLE_PFIT_FAILED       (1<<14)
+#define ASLE_PWM_FREQ_FAILED   (1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID                (1<<31)
+#define ASLE_BCLP_MSK          (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID         (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID         (1<<31)
+
+#define ACPI_OTHER_OUTPUT (0<<8)
+#define ACPI_VGA_OUTPUT (1<<8)
+#define ACPI_TV_OUTPUT (2<<8)
+#define ACPI_DIGITAL_OUTPUT (3<<8)
+#define ACPI_LVDS_OUTPUT (4<<8)
+
+#ifdef CONFIG_ACPI
+static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+       u32 max;
+
+       if (!(bclp & ASLE_BCLP_VALID))
+               return ASLE_BACKLIGHT_FAILED;
+
+       bclp &= ASLE_BCLP_MSK;
+       if (bclp > 255)
+               return ASLE_BACKLIGHT_FAILED;
+
+       max = intel_panel_get_max_backlight(dev);
+       intel_panel_set_backlight(dev, bclp * max / 255);
+       asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+       return 0;
+}
+
+static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
+{
+       /* alsi is the current ALS reading in lux. 0 indicates below sensor
+          range, 0xffff indicates above sensor range. 1-0xfffe are valid */
+       return 0;
+}
+
+static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (pfmb & ASLE_PFMB_PWM_VALID) {
+               u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+               u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
+               blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
+               pwm = pwm >> 9;
+               /* FIXME - what do we do with the PWM? */
+       }
+       return 0;
+}
+
+static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
+{
+       /* Panel fitting is currently controlled by the X code, so this is a
+          noop until modesetting support works fully */
+       if (!(pfit & ASLE_PFIT_VALID))
+               return ASLE_PFIT_FAILED;
+       return 0;
+}
+
+void intel_opregion_asle_intr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+       u32 asle_stat = 0;
+       u32 asle_req;
+
+       if (!asle)
+               return;
+
+       asle_req = asle->aslc & ASLE_REQ_MSK;
+
+       if (!asle_req) {
+               DRM_DEBUG_DRIVER("non asle set request??\n");
+               return;
+       }
+
+       if (asle_req & ASLE_SET_ALS_ILLUM)
+               asle_stat |= asle_set_als_illum(dev, asle->alsi);
+
+       if (asle_req & ASLE_SET_BACKLIGHT)
+               asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+       if (asle_req & ASLE_SET_PFIT)
+               asle_stat |= asle_set_pfit(dev, asle->pfit);
+
+       if (asle_req & ASLE_SET_PWM_FREQ)
+               asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+
+       asle->aslc = asle_stat;
+}
+
+/* Only present on Ironlake+ */
+void intel_opregion_gse_intr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+       u32 asle_stat = 0;
+       u32 asle_req;
+
+       if (!asle)
+               return;
+
+       asle_req = asle->aslc & ASLE_REQ_MSK;
+
+       if (!asle_req) {
+               DRM_DEBUG_DRIVER("non asle set request??\n");
+               return;
+       }
+
+       if (asle_req & ASLE_SET_ALS_ILLUM) {
+               DRM_DEBUG_DRIVER("Illum is not supported\n");
+               asle_stat |= ASLE_ALS_ILLUM_FAILED;
+       }
+
+       if (asle_req & ASLE_SET_BACKLIGHT)
+               asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+       if (asle_req & ASLE_SET_PFIT) {
+               DRM_DEBUG_DRIVER("Pfit is not supported\n");
+               asle_stat |= ASLE_PFIT_FAILED;
+       }
+
+       if (asle_req & ASLE_SET_PWM_FREQ) {
+               DRM_DEBUG_DRIVER("PWM freq is not supported\n");
+               asle_stat |= ASLE_PWM_FREQ_FAILED;
+       }
+
+       asle->aslc = asle_stat;
+}
+#define ASLE_ALS_EN    (1<<0)
+#define ASLE_BLC_EN    (1<<1)
+#define ASLE_PFIT_EN   (1<<2)
+#define ASLE_PFMB_EN   (1<<3)
+
+void intel_opregion_enable_asle(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+
+       if (asle) {
+               if (IS_MOBILE(dev)) {
+                       unsigned long irqflags;
+
+                       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+                       intel_enable_asle(dev);
+                       spin_unlock_irqrestore(&dev_priv->user_irq_lock,
+                                              irqflags);
+               }
+
+               asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+                       ASLE_PFMB_EN;
+               asle->ardy = 1;
+       }
+}
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID            (1<<1)
+#define ACPI_EV_DOCK           (1<<2)
+
+static struct intel_opregion *system_opregion;
+
+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
+          Linux, these are handled by the dock, button and video drivers.
+          We might want to fix the video driver to be opregion-aware in
+          future, but right now we just indicate to the firmware that the
+          request has been handled */
+
+       struct opregion_acpi *acpi;
+
+       if (!system_opregion)
+               return NOTIFY_DONE;
+
+       acpi = system_opregion->acpi;
+       acpi->csts = 0;
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block intel_opregion_notifier = {
+       .notifier_call = intel_opregion_video_event,
+};
+
+/*
+ * Initialise the DIDL field in opregion. This passes a list of devices to
+ * the firmware. Values are defined by section B.4.2 of the ACPI specification
+ * (version 3)
+ */
+
+static void intel_didl_outputs(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       struct drm_connector *connector;
+       acpi_handle handle;
+       struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
+       unsigned long long device_id;
+       acpi_status status;
+       int i = 0;
+
+       handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
+       if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
+               return;
+
+       if (acpi_is_video_device(acpi_dev))
+               acpi_video_bus = acpi_dev;
+       else {
+               list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
+                       if (acpi_is_video_device(acpi_cdev)) {
+                               acpi_video_bus = acpi_cdev;
+                               break;
+                       }
+               }
+       }
+
+       if (!acpi_video_bus) {
+               printk(KERN_WARNING "No ACPI video bus found\n");
+               return;
+       }
+
+       list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
+               if (i >= 8) {
+                       dev_printk (KERN_ERR, &dev->pdev->dev,
+                                   "More than 8 outputs detected\n");
+                       return;
+               }
+               status =
+                       acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
+                                               NULL, &device_id);
+               if (ACPI_SUCCESS(status)) {
+                       if (!device_id)
+                               goto blind_set;
+                       opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+                       i++;
+               }
+       }
+
+end:
+       /* If fewer than 8 outputs, the list must be null terminated */
+       if (i < 8)
+               opregion->acpi->didl[i] = 0;
+       return;
+
+blind_set:
+       i = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               int output_type = ACPI_OTHER_OUTPUT;
+               if (i >= 8) {
+                       dev_printk (KERN_ERR, &dev->pdev->dev,
+                                   "More than 8 outputs detected\n");
+                       return;
+               }
+               switch (connector->connector_type) {
+               case DRM_MODE_CONNECTOR_VGA:
+               case DRM_MODE_CONNECTOR_DVIA:
+                       output_type = ACPI_VGA_OUTPUT;
+                       break;
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Component:
+               case DRM_MODE_CONNECTOR_9PinDIN:
+                       output_type = ACPI_TV_OUTPUT;
+                       break;
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_DVID:
+               case DRM_MODE_CONNECTOR_DisplayPort:
+               case DRM_MODE_CONNECTOR_HDMIA:
+               case DRM_MODE_CONNECTOR_HDMIB:
+                       output_type = ACPI_DIGITAL_OUTPUT;
+                       break;
+               case DRM_MODE_CONNECTOR_LVDS:
+                       output_type = ACPI_LVDS_OUTPUT;
+                       break;
+               }
+               opregion->acpi->didl[i] |= (1<<31) | output_type | i;
+               i++;
+       }
+       goto end;
+}
+
+void intel_opregion_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       intel_didl_outputs(dev);
+
+               /* Notify BIOS we are ready to handle ACPI video ext notifs.
+                * Right now, all the events are handled by the ACPI video module.
+                * We don't actually need to do anything with them. */
+               opregion->acpi->csts = 0;
+               opregion->acpi->drdy = 1;
+
+               system_opregion = opregion;
+               register_acpi_notifier(&intel_opregion_notifier);
+       }
+
+       if (opregion->asle)
+               intel_opregion_enable_asle(dev);
+}
+
+void intel_opregion_fini(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               opregion->acpi->drdy = 0;
+
+               system_opregion = NULL;
+               unregister_acpi_notifier(&intel_opregion_notifier);
+       }
+
+       /* just clear all opregion memory pointers now */
+       iounmap(opregion->header);
+       opregion->header = NULL;
+       opregion->acpi = NULL;
+       opregion->swsci = NULL;
+       opregion->asle = NULL;
+       opregion->vbt = NULL;
+}
+#endif
+
+int intel_opregion_setup(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       void *base;
+       u32 asls, mboxes;
+       int err = 0;
+
+       pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
+       DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
+       if (asls == 0) {
+               DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
+               return -ENOTSUPP;
+       }
+
+       base = ioremap(asls, OPREGION_SIZE);
+       if (!base)
+               return -ENOMEM;
+
+       if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+               DRM_DEBUG_DRIVER("opregion signature mismatch\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+       opregion->header = base;
+       opregion->vbt = base + OPREGION_VBT_OFFSET;
+
+       mboxes = opregion->header->mboxes;
+       if (mboxes & MBOX_ACPI) {
+               DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
+               opregion->acpi = base + OPREGION_ACPI_OFFSET;
+       }
+
+       if (mboxes & MBOX_SWSCI) {
+               DRM_DEBUG_DRIVER("SWSCI supported\n");
+               opregion->swsci = base + OPREGION_SWSCI_OFFSET;
+       }
+       if (mboxes & MBOX_ASLE) {
+               DRM_DEBUG_DRIVER("ASLE supported\n");
+               opregion->asle = base + OPREGION_ASLE_OFFSET;
+       }
+
+       return 0;
+
+err_out:
+       iounmap(opregion->header);
+       return err;
+}
index 1d306a458be6463c8e1f6636d69ebf515d845889..afb96d25219afe473b116802f30616c0edb1cf86 100644 (file)
@@ -170,57 +170,143 @@ struct overlay_registers {
     u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
 };
 
-/* overlay flip addr flag */
-#define OFC_UPDATE             0x1
-
-#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
-
+struct intel_overlay {
+       struct drm_device *dev;
+       struct intel_crtc *crtc;
+       struct drm_i915_gem_object *vid_bo;
+       struct drm_i915_gem_object *old_vid_bo;
+       int active;
+       int pfit_active;
+       u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
+       u32 color_key;
+       u32 brightness, contrast, saturation;
+       u32 old_xscale, old_yscale;
+       /* register access */
+       u32 flip_addr;
+       struct drm_i915_gem_object *reg_bo;
+       /* flip handling */
+       uint32_t last_flip_req;
+       void (*flip_tail)(struct intel_overlay *);
+};
 
-static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+static struct overlay_registers *
+intel_overlay_map_regs(struct intel_overlay *overlay)
 {
         drm_i915_private_t *dev_priv = overlay->dev->dev_private;
        struct overlay_registers *regs;
 
-       /* no recursive mappings */
-       BUG_ON(overlay->virt_addr);
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
+                                        overlay->reg_bo->gtt_offset);
 
-       if (OVERLAY_NONPHYSICAL(overlay->dev)) {
-               regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-                                               overlay->reg_bo->gtt_offset,
-                                               KM_USER0);
+       return regs;
+}
 
-               if (!regs) {
-                       DRM_ERROR("failed to map overlay regs in GTT\n");
-                       return NULL;
-               }
-       } else
-               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
+                                    struct overlay_registers *regs)
+{
+       if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               io_mapping_unmap(regs);
+}
+
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+                                        struct drm_i915_gem_request *request,
+                                        bool interruptible,
+                                        void (*tail)(struct intel_overlay *))
+{
+       struct drm_device *dev = overlay->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
 
-       return overlay->virt_addr = regs;
+       BUG_ON(overlay->last_flip_req);
+       overlay->last_flip_req =
+               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       if (overlay->last_flip_req == 0)
+               return -ENOMEM;
+
+       overlay->flip_tail = tail;
+       ret = i915_do_wait_request(dev,
+                                  overlay->last_flip_req, true,
+                                  &dev_priv->render_ring);
+       if (ret)
+               return ret;
+
+       overlay->last_flip_req = 0;
+       return 0;
 }
 
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
 {
-       if (OVERLAY_NONPHYSICAL(overlay->dev))
-               io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+       struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_display_mode vesa_640x480 = {
+               DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                        752, 800, 0, 480, 489, 492, 525, 0,
+                        DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+       }, *mode;
+
+       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+       if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+               return 0;
 
-       overlay->virt_addr = NULL;
+       /* most i8xx have pipe a forced on, so don't trust dpms mode */
+       if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
+               return 0;
 
-       return;
+       crtc_funcs = crtc->base.helper_private;
+       if (crtc_funcs->dpms == NULL)
+               return 0;
+
+       DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+       mode = drm_mode_duplicate(dev, &vesa_640x480);
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       if(!drm_crtc_helper_set_mode(&crtc->base, mode,
+                                      crtc->base.x, crtc->base.y,
+                                      crtc->base.fb))
+               return 0;
+
+       crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+       return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
+       struct drm_i915_gem_request *request;
+       int pipe_a_quirk = 0;
        int ret;
-       drm_i915_private_t *dev_priv = dev->dev_private;
 
        BUG_ON(overlay->active);
-
        overlay->active = 1;
-       overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
+
+       if (IS_I830(dev)) {
+               pipe_a_quirk = i830_activate_pipe_a(dev);
+               if (pipe_a_quirk < 0)
+                       return pipe_a_quirk;
+       }
+
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
@@ -229,32 +315,30 @@ static int intel_overlay_on(struct intel_overlay *overlay)
        OUT_RING(MI_NOOP);
        ADVANCE_LP_RING();
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev,
-                       overlay->last_flip_req, 1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
+       ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
+out:
+       if (pipe_a_quirk)
+               i830_deactivate_pipe_a(dev);
 
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return 0;
+       return ret;
 }
 
 /* overlay needs to be enabled in OCMD reg */
-static void intel_overlay_continue(struct intel_overlay *overlay,
-                           bool load_polyphase_filter)
+static int intel_overlay_continue(struct intel_overlay *overlay,
+                                 bool load_polyphase_filter)
 {
        struct drm_device *dev = overlay->dev;
         drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_request *request;
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
 
        BUG_ON(!overlay->active);
 
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL)
+               return -ENOMEM;
+
        if (load_polyphase_filter)
                flip_addr |= OFC_UPDATE;
 
@@ -269,220 +353,132 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
         ADVANCE_LP_RING();
 
        overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
+               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       return 0;
 }
 
-static int intel_overlay_wait_flip(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 {
-       struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
-       u32 tmp;
-
-       if (overlay->last_flip_req != 0) {
-               ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                               1, &dev_priv->render_ring);
-               if (ret == 0) {
-                       overlay->last_flip_req = 0;
-
-                       tmp = I915_READ(ISR);
+       struct drm_gem_object *obj = &overlay->old_vid_bo->base;
 
-                       if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
-                               return 0;
-               }
-       }
+       i915_gem_object_unpin(obj);
+       drm_gem_object_unreference(obj);
 
-       /* synchronous slowpath */
-       overlay->hw_wedged = RELEASE_OLD_VID;
+       overlay->old_vid_bo = NULL;
+}
 
-       BEGIN_LP_RING(2);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
+static void intel_overlay_off_tail(struct intel_overlay *overlay)
+{
+       struct drm_gem_object *obj;
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
+       /* never have the overlay hw on without showing a frame */
+       BUG_ON(!overlay->vid_bo);
+       obj = &overlay->vid_bo->base;
 
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
+       i915_gem_object_unpin(obj);
+       drm_gem_object_unreference(obj);
+       overlay->vid_bo = NULL;
 
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return 0;
+       overlay->crtc->overlay = NULL;
+       overlay->crtc = NULL;
+       overlay->active = 0;
 }
 
 /* overlay needs to be disabled in OCMD reg */
-static int intel_overlay_off(struct intel_overlay *overlay)
+static int intel_overlay_off(struct intel_overlay *overlay,
+                            bool interruptible)
 {
-       u32 flip_addr = overlay->flip_addr;
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
+       u32 flip_addr = overlay->flip_addr;
+       struct drm_i915_gem_request *request;
 
        BUG_ON(!overlay->active);
 
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL)
+               return -ENOMEM;
+
        /* According to intel docs the overlay hw may hang (when switching
         * off) without loading the filter coeffs. It is however unclear whether
         * this applies to the disabling of the overlay or to the switching off
         * of the hw. Do it in both cases */
        flip_addr |= OFC_UPDATE;
 
+       BEGIN_LP_RING(6);
        /* wait for overlay to go idle */
-       overlay->hw_wedged = SWITCH_OFF_STAGE_1;
-
-       BEGIN_LP_RING(4);
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
        OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
-
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
-
+       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        /* turn overlay off */
-       overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-       BEGIN_LP_RING(4);
-        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+       OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
        OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
+       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        ADVANCE_LP_RING();
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
-
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return ret;
-}
-
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
-{
-       struct drm_gem_object *obj;
-
-       /* never have the overlay hw on without showing a frame */
-       BUG_ON(!overlay->vid_bo);
-       obj = &overlay->vid_bo->base;
-
-       i915_gem_object_unpin(obj);
-       drm_gem_object_unreference(obj);
-       overlay->vid_bo = NULL;
-
-       overlay->crtc->overlay = NULL;
-       overlay->crtc = NULL;
-       overlay->active = 0;
+       return intel_overlay_do_wait_request(overlay, request, interruptible,
+                                            intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
  * We have to be careful not to repeat work forever an make forward progess. */
-int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-                                        int interruptible)
+static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
+                                               bool interruptible)
 {
        struct drm_device *dev = overlay->dev;
-       struct drm_gem_object *obj;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 flip_addr;
        int ret;
 
-       if (overlay->hw_wedged == HW_WEDGED)
-               return -EIO;
-
-       if (overlay->last_flip_req == 0) {
-               overlay->last_flip_req =
-                       i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-               if (overlay->last_flip_req == 0)
-                       return -ENOMEM;
-       }
+       if (overlay->last_flip_req == 0)
+               return 0;
 
        ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       interruptible, &dev_priv->render_ring);
-       if (ret != 0)
+                                  interruptible, &dev_priv->render_ring);
+       if (ret)
                return ret;
 
-       switch (overlay->hw_wedged) {
-               case RELEASE_OLD_VID:
-                       obj = &overlay->old_vid_bo->base;
-                       i915_gem_object_unpin(obj);
-                       drm_gem_object_unreference(obj);
-                       overlay->old_vid_bo = NULL;
-                       break;
-               case SWITCH_OFF_STAGE_1:
-                       flip_addr = overlay->flip_addr;
-                       flip_addr |= OFC_UPDATE;
-
-                       overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-                       BEGIN_LP_RING(4);
-                       OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-                       OUT_RING(flip_addr);
-                       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-                       OUT_RING(MI_NOOP);
-                       ADVANCE_LP_RING();
-
-                       overlay->last_flip_req = i915_add_request(dev, NULL,
-                                       0, &dev_priv->render_ring);
-                       if (overlay->last_flip_req == 0)
-                               return -ENOMEM;
-
-                       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                                       interruptible, &dev_priv->render_ring);
-                       if (ret != 0)
-                               return ret;
-
-               case SWITCH_OFF_STAGE_2:
-                       intel_overlay_off_tail(overlay);
-                       break;
-               default:
-                       BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
-       }
+       if (overlay->flip_tail)
+               overlay->flip_tail(overlay);
 
-       overlay->hw_wedged = 0;
        overlay->last_flip_req = 0;
        return 0;
 }
 
 /* Wait for pending overlay flip and release old frame.
  * Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs_atomic */
+ * via intel_overlay_(un)map_regs
+ */
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
+       struct drm_device *dev = overlay->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
-       struct drm_gem_object *obj;
 
-       /* only wait if there is actually an old frame to release to
-        * guarantee forward progress */
+       /* Only wait if there is actually an old frame to release to
+        * guarantee forward progress.
+        */
        if (!overlay->old_vid_bo)
                return 0;
 
-       ret = intel_overlay_wait_flip(overlay);
-       if (ret != 0)
-               return ret;
+       if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
+               struct drm_i915_gem_request *request;
 
-       obj = &overlay->old_vid_bo->base;
-       i915_gem_object_unpin(obj);
-       drm_gem_object_unreference(obj);
-       overlay->old_vid_bo = NULL;
+               /* synchronous slowpath */
+               request = kzalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return -ENOMEM;
 
+               BEGIN_LP_RING(2);
+               OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+               OUT_RING(MI_NOOP);
+               ADVANCE_LP_RING();
+
+               ret = intel_overlay_do_wait_request(overlay, request, true,
+                                                   intel_overlay_release_old_vid_tail);
+               if (ret)
+                       return ret;
+       }
+
+       intel_overlay_release_old_vid_tail(overlay);
        return 0;
 }
 
@@ -506,65 +502,65 @@ struct put_image_params {
 static int packed_depth_bytes(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-                       return 4;
-               case I915_OVERLAY_YUV411:
-                       /* return 6; not implemented */
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+               return 4;
+       case I915_OVERLAY_YUV411:
+               /* return 6; not implemented */
+       default:
+               return -EINVAL;
        }
 }
 
 static int packed_width_bytes(u32 format, short width)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-                       return width << 1;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+               return width << 1;
+       default:
+               return -EINVAL;
        }
 }
 
 static int uv_hsubsampling(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-               case I915_OVERLAY_YUV420:
-                       return 2;
-               case I915_OVERLAY_YUV411:
-               case I915_OVERLAY_YUV410:
-                       return 4;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+       case I915_OVERLAY_YUV420:
+               return 2;
+       case I915_OVERLAY_YUV411:
+       case I915_OVERLAY_YUV410:
+               return 4;
+       default:
+               return -EINVAL;
        }
 }
 
 static int uv_vsubsampling(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV420:
-               case I915_OVERLAY_YUV410:
-                       return 2;
-               case I915_OVERLAY_YUV422:
-               case I915_OVERLAY_YUV411:
-                       return 1;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV420:
+       case I915_OVERLAY_YUV410:
+               return 2;
+       case I915_OVERLAY_YUV422:
+       case I915_OVERLAY_YUV411:
+               return 1;
+       default:
+               return -EINVAL;
        }
 }
 
 static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
 {
        u32 mask, shift, ret;
-       if (IS_I9XX(dev)) {
-               mask = 0x3f;
-               shift = 6;
-       } else {
+       if (IS_GEN2(dev)) {
                mask = 0x1f;
                shift = 5;
+       } else {
+               mask = 0x3f;
+               shift = 6;
        }
        ret = ((offset + width + mask) >> shift) - (offset >> shift);
-       if (IS_I9XX(dev))
+       if (!IS_GEN2(dev))
                ret <<= 1;
        ret -=1;
        return ret << 2;
@@ -587,7 +583,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
        0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
        0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
        0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
-       0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
+       0xb000, 0x3000, 0x0800, 0x3000, 0xb000
+};
+
 static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
        0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
        0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
@@ -597,7 +595,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
        0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
        0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
        0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
-       0x3000, 0x0800, 0x3000};
+       0x3000, 0x0800, 0x3000
+};
 
 static void update_polyphase_filter(struct overlay_registers *regs)
 {
@@ -630,29 +629,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
                yscale = 1 << FP_SHIFT;
 
        /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
-               xscale_UV = xscale/uv_hscale;
-               yscale_UV = yscale/uv_vscale;
-               /* make the Y scale to UV scale ratio an exact multiply */
-               xscale = xscale_UV * uv_hscale;
-               yscale = yscale_UV * uv_vscale;
+       xscale_UV = xscale/uv_hscale;
+       yscale_UV = yscale/uv_vscale;
+       /* make the Y scale to UV scale ratio an exact multiply */
+       xscale = xscale_UV * uv_hscale;
+       yscale = yscale_UV * uv_vscale;
        /*} else {
-               xscale_UV = 0;
-               yscale_UV = 0;
-       }*/
+         xscale_UV = 0;
+         yscale_UV = 0;
+         }*/
 
        if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
                scale_changed = true;
        overlay->old_xscale = xscale;
        overlay->old_yscale = yscale;
 
-       regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
-               | ((xscale >> FP_SHIFT) << 16)
-               | ((xscale & FRACT_MASK) << 3);
-       regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
-               | ((xscale_UV >> FP_SHIFT) << 16)
-               | ((xscale_UV & FRACT_MASK) << 3);
-       regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
-               | ((yscale_UV >> FP_SHIFT) << 0);
+       regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
+                          ((xscale >> FP_SHIFT)  << 16) |
+                          ((xscale & FRACT_MASK) << 3));
+
+       regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
+                        ((xscale_UV >> FP_SHIFT)  << 16) |
+                        ((xscale_UV & FRACT_MASK) << 3));
+
+       regs->UVSCALEV = ((((yscale    >> FP_SHIFT) << 16) |
+                          ((yscale_UV >> FP_SHIFT) << 0)));
 
        if (scale_changed)
                update_polyphase_filter(regs);
@@ -664,22 +665,28 @@ static void update_colorkey(struct intel_overlay *overlay,
                            struct overlay_registers *regs)
 {
        u32 key = overlay->color_key;
+
        switch (overlay->crtc->base.fb->bits_per_pixel) {
-               case 8:
-                       regs->DCLRKV = 0;
-                       regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
-               case 16:
-                       if (overlay->crtc->base.fb->depth == 15) {
-                               regs->DCLRKV = RGB15_TO_COLORKEY(key);
-                               regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
-                       } else {
-                               regs->DCLRKV = RGB16_TO_COLORKEY(key);
-                               regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
-                       }
-               case 24:
-               case 32:
-                       regs->DCLRKV = key;
-                       regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+       case 8:
+               regs->DCLRKV = 0;
+               regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+               break;
+
+       case 16:
+               if (overlay->crtc->base.fb->depth == 15) {
+                       regs->DCLRKV = RGB15_TO_COLORKEY(key);
+                       regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+               } else {
+                       regs->DCLRKV = RGB16_TO_COLORKEY(key);
+                       regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+               }
+               break;
+
+       case 24:
+       case 32:
+               regs->DCLRKV = key;
+               regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+               break;
        }
 }
 
@@ -689,48 +696,48 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
 
        if (params->format & I915_OVERLAY_YUV_PLANAR) {
                switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-                       case I915_OVERLAY_YUV422:
-                               cmd |= OCMD_YUV_422_PLANAR;
-                               break;
-                       case I915_OVERLAY_YUV420:
-                               cmd |= OCMD_YUV_420_PLANAR;
-                               break;
-                       case I915_OVERLAY_YUV411:
-                       case I915_OVERLAY_YUV410:
-                               cmd |= OCMD_YUV_410_PLANAR;
-                               break;
+               case I915_OVERLAY_YUV422:
+                       cmd |= OCMD_YUV_422_PLANAR;
+                       break;
+               case I915_OVERLAY_YUV420:
+                       cmd |= OCMD_YUV_420_PLANAR;
+                       break;
+               case I915_OVERLAY_YUV411:
+               case I915_OVERLAY_YUV410:
+                       cmd |= OCMD_YUV_410_PLANAR;
+                       break;
                }
        } else { /* YUV packed */
                switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-                       case I915_OVERLAY_YUV422:
-                               cmd |= OCMD_YUV_422_PACKED;
-                               break;
-                       case I915_OVERLAY_YUV411:
-                               cmd |= OCMD_YUV_411_PACKED;
-                               break;
+               case I915_OVERLAY_YUV422:
+                       cmd |= OCMD_YUV_422_PACKED;
+                       break;
+               case I915_OVERLAY_YUV411:
+                       cmd |= OCMD_YUV_411_PACKED;
+                       break;
                }
 
                switch (params->format & I915_OVERLAY_SWAP_MASK) {
-                       case I915_OVERLAY_NO_SWAP:
-                               break;
-                       case I915_OVERLAY_UV_SWAP:
-                               cmd |= OCMD_UV_SWAP;
-                               break;
-                       case I915_OVERLAY_Y_SWAP:
-                               cmd |= OCMD_Y_SWAP;
-                               break;
-                       case I915_OVERLAY_Y_AND_UV_SWAP:
-                               cmd |= OCMD_Y_AND_UV_SWAP;
-                               break;
+               case I915_OVERLAY_NO_SWAP:
+                       break;
+               case I915_OVERLAY_UV_SWAP:
+                       cmd |= OCMD_UV_SWAP;
+                       break;
+               case I915_OVERLAY_Y_SWAP:
+                       cmd |= OCMD_Y_SWAP;
+                       break;
+               case I915_OVERLAY_Y_AND_UV_SWAP:
+                       cmd |= OCMD_Y_AND_UV_SWAP;
+                       break;
                }
        }
 
        return cmd;
 }
 
-int intel_overlay_do_put_image(struct intel_overlay *overlay,
-                              struct drm_gem_object *new_bo,
-                              struct put_image_params *params)
+static int intel_overlay_do_put_image(struct intel_overlay *overlay,
+                                     struct drm_gem_object *new_bo,
+                                     struct put_image_params *params)
 {
        int ret, tmp_width;
        struct overlay_registers *regs;
@@ -755,24 +762,24 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
                goto out_unpin;
 
        if (!overlay->active) {
-               regs = intel_overlay_map_regs_atomic(overlay);
+               regs = intel_overlay_map_regs(overlay);
                if (!regs) {
                        ret = -ENOMEM;
                        goto out_unpin;
                }
                regs->OCONFIG = OCONF_CC_OUT_8BIT;
-               if (IS_I965GM(overlay->dev))
+               if (IS_GEN4(overlay->dev))
                        regs->OCONFIG |= OCONF_CSC_MODE_BT709;
                regs->OCONFIG |= overlay->crtc->pipe == 0 ?
                        OCONF_PIPE_A : OCONF_PIPE_B;
-               intel_overlay_unmap_regs_atomic(overlay);
+               intel_overlay_unmap_regs(overlay, regs);
 
                ret = intel_overlay_on(overlay);
                if (ret != 0)
                        goto out_unpin;
        }
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        if (!regs) {
                ret = -ENOMEM;
                goto out_unpin;
@@ -788,7 +795,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        regs->SWIDTH = params->src_w;
        regs->SWIDTHSW = calc_swidthsw(overlay->dev,
-                       params->offset_Y, tmp_width);
+                                      params->offset_Y, tmp_width);
        regs->SHEIGHT = params->src_h;
        regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
        regs->OSTRIDE = params->stride_Y;
@@ -799,9 +806,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
                u32 tmp_U, tmp_V;
                regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
                tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
-                               params->src_w/uv_hscale);
+                                     params->src_w/uv_hscale);
                tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
-                               params->src_w/uv_hscale);
+                                     params->src_w/uv_hscale);
                regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
                regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
                regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
@@ -815,9 +822,11 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        regs->OCMD = overlay_cmd_reg(params);
 
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
-       intel_overlay_continue(overlay, scale_changed);
+       ret = intel_overlay_continue(overlay, scale_changed);
+       if (ret)
+               goto out_unpin;
 
        overlay->old_vid_bo = overlay->vid_bo;
        overlay->vid_bo = to_intel_bo(new_bo);
@@ -829,20 +838,19 @@ out_unpin:
        return ret;
 }
 
-int intel_overlay_switch_off(struct intel_overlay *overlay)
+int intel_overlay_switch_off(struct intel_overlay *overlay,
+                            bool interruptible)
 {
-       int ret;
        struct overlay_registers *regs;
        struct drm_device *dev = overlay->dev;
+       int ret;
 
        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
        BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
-       if (overlay->hw_wedged) {
-               ret = intel_overlay_recover_from_interrupt(overlay, 1);
-               if (ret != 0)
-                       return ret;
-       }
+       ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
+       if (ret != 0)
+               return ret;
 
        if (!overlay->active)
                return 0;
@@ -851,33 +859,29 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
        if (ret != 0)
                return ret;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        regs->OCMD = 0;
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
-       ret = intel_overlay_off(overlay);
+       ret = intel_overlay_off(overlay, interruptible);
        if (ret != 0)
                return ret;
 
        intel_overlay_off_tail(overlay);
-
        return 0;
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
                                          struct intel_crtc *crtc)
 {
-        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
-       u32 pipeconf;
-       int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
+       drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 
-       if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!crtc->active)
                return -EINVAL;
 
-       pipeconf = I915_READ(pipeconf_reg);
-
        /* can't use the overlay with double wide pipe */
-       if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
+       if (INTEL_INFO(overlay->dev)->gen < 4 &&
+           (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
                return -EINVAL;
 
        return 0;
@@ -886,20 +890,22 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 ratio;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        u32 pfit_control = I915_READ(PFIT_CONTROL);
+       u32 ratio;
 
        /* XXX: This is not the same logic as in the xorg driver, but more in
-        * line with the intel documentation for the i965 */
-       if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
-               ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
-       } else { /* on i965 use the PGM reg to read out the autoscaler values */
-               ratio = I915_READ(PFIT_PGM_RATIOS);
-               if (IS_I965G(dev))
-                       ratio >>= PFIT_VERT_SCALE_SHIFT_965;
+        * line with the intel documentation for the i965
+        */
+       if (INTEL_INFO(dev)->gen >= 4) {
+               /* on i965 use the PGM reg to read out the autoscaler values */
+               ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
+       } else {
+               if (pfit_control & VERT_AUTO_SCALE)
+                       ratio = I915_READ(PFIT_AUTO_RATIOS);
                else
-                       ratio >>= PFIT_VERT_SCALE_SHIFT;
+                       ratio = I915_READ(PFIT_PGM_RATIOS);
+               ratio >>= PFIT_VERT_SCALE_SHIFT;
        }
 
        overlay->pfit_vscale_ratio = ratio;
@@ -910,12 +916,10 @@ static int check_overlay_dst(struct intel_overlay *overlay,
 {
        struct drm_display_mode *mode = &overlay->crtc->base.mode;
 
-       if ((rec->dst_x < mode->crtc_hdisplay)
-           && (rec->dst_x + rec->dst_width
-                   <= mode->crtc_hdisplay)
-           && (rec->dst_y < mode->crtc_vdisplay)
-           && (rec->dst_y + rec->dst_height
-                   <= mode->crtc_vdisplay))
+       if (rec->dst_x < mode->crtc_hdisplay &&
+           rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
+           rec->dst_y < mode->crtc_vdisplay &&
+           rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
                return 0;
        else
                return -EINVAL;
@@ -940,53 +944,57 @@ static int check_overlay_src(struct drm_device *dev,
                             struct drm_intel_overlay_put_image *rec,
                             struct drm_gem_object *new_bo)
 {
-       u32 stride_mask;
-       int depth;
        int uv_hscale = uv_hsubsampling(rec->flags);
        int uv_vscale = uv_vsubsampling(rec->flags);
-       size_t tmp;
+       u32 stride_mask, depth, tmp;
 
        /* check src dimensions */
        if (IS_845G(dev) || IS_I830(dev)) {
-               if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
-                   || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
+               if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
+                   rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
                        return -EINVAL;
        } else {
-               if (rec->src_height > IMAGE_MAX_HEIGHT
-                   || rec->src_width > IMAGE_MAX_WIDTH)
+               if (rec->src_height > IMAGE_MAX_HEIGHT ||
+                   rec->src_width  > IMAGE_MAX_WIDTH)
                        return -EINVAL;
        }
+
        /* better safe than sorry, use 4 as the maximal subsampling ratio */
-       if (rec->src_height < N_VERT_Y_TAPS*4
-           || rec->src_width < N_HORIZ_Y_TAPS*4)
+       if (rec->src_height < N_VERT_Y_TAPS*4 ||
+           rec->src_width  < N_HORIZ_Y_TAPS*4)
                return -EINVAL;
 
        /* check alignment constraints */
        switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-               case I915_OVERLAY_RGB:
-                       /* not implemented */
+       case I915_OVERLAY_RGB:
+               /* not implemented */
+               return -EINVAL;
+
+       case I915_OVERLAY_YUV_PACKED:
+               if (uv_vscale != 1)
                        return -EINVAL;
-               case I915_OVERLAY_YUV_PACKED:
-                       depth = packed_depth_bytes(rec->flags);
-                       if (uv_vscale != 1)
-                               return -EINVAL;
-                       if (depth < 0)
-                               return depth;
-                       /* ignore UV planes */
-                       rec->stride_UV = 0;
-                       rec->offset_U = 0;
-                       rec->offset_V = 0;
-                       /* check pixel alignment */
-                       if (rec->offset_Y % depth)
-                               return -EINVAL;
-                       break;
-               case I915_OVERLAY_YUV_PLANAR:
-                       if (uv_vscale < 0 || uv_hscale < 0)
-                               return -EINVAL;
-                       /* no offset restrictions for planar formats */
-                       break;
-               default:
+
+               depth = packed_depth_bytes(rec->flags);
+               if (depth < 0)
+                       return depth;
+
+               /* ignore UV planes */
+               rec->stride_UV = 0;
+               rec->offset_U = 0;
+               rec->offset_V = 0;
+               /* check pixel alignment */
+               if (rec->offset_Y % depth)
                        return -EINVAL;
+               break;
+
+       case I915_OVERLAY_YUV_PLANAR:
+               if (uv_vscale < 0 || uv_hscale < 0)
+                       return -EINVAL;
+               /* no offset restrictions for planar formats */
+               break;
+
+       default:
+               return -EINVAL;
        }
 
        if (rec->src_width % uv_hscale)
@@ -1000,47 +1008,74 @@ static int check_overlay_src(struct drm_device *dev,
 
        if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
                return -EINVAL;
-       if (IS_I965G(dev) && rec->stride_Y < 512)
+       if (IS_GEN4(dev) && rec->stride_Y < 512)
                return -EINVAL;
 
        tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
-               4 : 8;
-       if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
+               4096 : 8192;
+       if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
                return -EINVAL;
 
        /* check buffer dimensions */
        switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-               case I915_OVERLAY_RGB:
-               case I915_OVERLAY_YUV_PACKED:
-                       /* always 4 Y values per depth pixels */
-                       if (packed_width_bytes(rec->flags, rec->src_width)
-                                       > rec->stride_Y)
-                               return -EINVAL;
-
-                       tmp = rec->stride_Y*rec->src_height;
-                       if (rec->offset_Y + tmp > new_bo->size)
-                               return -EINVAL;
-                       break;
-               case I915_OVERLAY_YUV_PLANAR:
-                       if (rec->src_width > rec->stride_Y)
-                               return -EINVAL;
-                       if (rec->src_width/uv_hscale > rec->stride_UV)
-                               return -EINVAL;
-
-                       tmp = rec->stride_Y*rec->src_height;
-                       if (rec->offset_Y + tmp > new_bo->size)
-                               return -EINVAL;
-                       tmp = rec->stride_UV*rec->src_height;
-                       tmp /= uv_vscale;
-                       if (rec->offset_U + tmp > new_bo->size
-                           || rec->offset_V + tmp > new_bo->size)
-                               return -EINVAL;
-                       break;
+       case I915_OVERLAY_RGB:
+       case I915_OVERLAY_YUV_PACKED:
+               /* always 4 Y values per depth pixels */
+               if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
+                       return -EINVAL;
+
+               tmp = rec->stride_Y*rec->src_height;
+               if (rec->offset_Y + tmp > new_bo->size)
+                       return -EINVAL;
+               break;
+
+       case I915_OVERLAY_YUV_PLANAR:
+               if (rec->src_width > rec->stride_Y)
+                       return -EINVAL;
+               if (rec->src_width/uv_hscale > rec->stride_UV)
+                       return -EINVAL;
+
+               tmp = rec->stride_Y * rec->src_height;
+               if (rec->offset_Y + tmp > new_bo->size)
+                       return -EINVAL;
+
+               tmp = rec->stride_UV * (rec->src_height / uv_vscale);
+               if (rec->offset_U + tmp > new_bo->size ||
+                   rec->offset_V + tmp > new_bo->size)
+                       return -EINVAL;
+               break;
        }
 
        return 0;
 }
 
+/**
+ * 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_GEN4(dev))
+               return (pfit_control >> 29) & 0x3;
+
+       /* older chips can only use pipe 1 */
+       return 1;
+}
+
 int intel_overlay_put_image(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
@@ -1068,7 +1103,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                mutex_lock(&dev->mode_config.mutex);
                mutex_lock(&dev->struct_mutex);
 
-               ret = intel_overlay_switch_off(overlay);
+               ret = intel_overlay_switch_off(overlay, true);
 
                mutex_unlock(&dev->struct_mutex);
                mutex_unlock(&dev->mode_config.mutex);
@@ -1081,7 +1116,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                return -ENOMEM;
 
        drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
-                        DRM_MODE_OBJECT_CRTC);
+                                          DRM_MODE_OBJECT_CRTC);
        if (!drmmode_obj) {
                ret = -ENOENT;
                goto out_free;
@@ -1089,7 +1124,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
 
        new_bo = drm_gem_object_lookup(dev, file_priv,
-                       put_image_rec->bo_handle);
+                                      put_image_rec->bo_handle);
        if (!new_bo) {
                ret = -ENOENT;
                goto out_free;
@@ -1098,15 +1133,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        mutex_lock(&dev->mode_config.mutex);
        mutex_lock(&dev->struct_mutex);
 
-       if (overlay->hw_wedged) {
-               ret = intel_overlay_recover_from_interrupt(overlay, 1);
-               if (ret != 0)
-                       goto out_unlock;
-       }
+       ret = intel_overlay_recover_from_interrupt(overlay, true);
+       if (ret != 0)
+               goto out_unlock;
 
        if (overlay->crtc != crtc) {
                struct drm_display_mode *mode = &crtc->base.mode;
-               ret = intel_overlay_switch_off(overlay);
+               ret = intel_overlay_switch_off(overlay, true);
                if (ret != 0)
                        goto out_unlock;
 
@@ -1117,9 +1150,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                overlay->crtc = crtc;
                crtc->overlay = overlay;
 
-               if (intel_panel_fitter_pipe(dev) == crtc->pipe
-                   /* and line to wide, i.e. one-line-mode */
-                   && mode->hdisplay > 1024) {
+               /* line too wide, i.e. one-line-mode */
+               if (mode->hdisplay > 1024 &&
+                   intel_panel_fitter_pipe(dev) == crtc->pipe) {
                        overlay->pfit_active = 1;
                        update_pfit_vscale_ratio(overlay);
                } else
@@ -1132,10 +1165,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 
        if (overlay->pfit_active) {
                params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
-                       overlay->pfit_vscale_ratio);
+                                overlay->pfit_vscale_ratio);
                /* shifting right rounds downwards, so add 1 */
                params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
-                       overlay->pfit_vscale_ratio) + 1;
+                                overlay->pfit_vscale_ratio) + 1;
        } else {
                params->dst_y = put_image_rec->dst_y;
                params->dst_h = put_image_rec->dst_height;
@@ -1147,8 +1180,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        params->src_h = put_image_rec->src_height;
        params->src_scan_w = put_image_rec->src_scan_width;
        params->src_scan_h = put_image_rec->src_scan_height;
-       if (params->src_scan_h > params->src_h
-           || params->src_scan_w > params->src_w) {
+       if (params->src_scan_h > params->src_h ||
+           params->src_scan_w > params->src_w) {
                ret = -EINVAL;
                goto out_unlock;
        }
@@ -1204,7 +1237,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
                return false;
 
        for (i = 0; i < 3; i++) {
-               if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
+               if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
                        return false;
        }
 
@@ -1225,16 +1258,18 @@ static bool check_gamma5_errata(u32 gamma5)
 
 static int check_gamma(struct drm_intel_overlay_attrs *attrs)
 {
-       if (!check_gamma_bounds(0, attrs->gamma0)
-           || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
-           || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
-           || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
-           || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
-           || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
-           || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
+       if (!check_gamma_bounds(0, attrs->gamma0) ||
+           !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
+           !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
+           !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
+           !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
+           !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
+           !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
                return -EINVAL;
+
        if (!check_gamma5_errata(attrs->gamma5))
                return -EINVAL;
+
        return 0;
 }
 
@@ -1261,13 +1296,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
        mutex_lock(&dev->mode_config.mutex);
        mutex_lock(&dev->struct_mutex);
 
+       ret = -EINVAL;
        if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
-               attrs->color_key = overlay->color_key;
+               attrs->color_key  = overlay->color_key;
                attrs->brightness = overlay->brightness;
-               attrs->contrast = overlay->contrast;
+               attrs->contrast   = overlay->contrast;
                attrs->saturation = overlay->saturation;
 
-               if (IS_I9XX(dev)) {
+               if (!IS_GEN2(dev)) {
                        attrs->gamma0 = I915_READ(OGAMC0);
                        attrs->gamma1 = I915_READ(OGAMC1);
                        attrs->gamma2 = I915_READ(OGAMC2);
@@ -1275,29 +1311,20 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        attrs->gamma4 = I915_READ(OGAMC4);
                        attrs->gamma5 = I915_READ(OGAMC5);
                }
-               ret = 0;
        } else {
-               overlay->color_key = attrs->color_key;
-               if (attrs->brightness >= -128 && attrs->brightness <= 127) {
-                       overlay->brightness = attrs->brightness;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->brightness < -128 || attrs->brightness > 127)
                        goto out_unlock;
-               }
-               if (attrs->contrast <= 255) {
-                       overlay->contrast = attrs->contrast;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->contrast > 255)
                        goto out_unlock;
-               }
-               if (attrs->saturation <= 1023) {
-                       overlay->saturation = attrs->saturation;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->saturation > 1023)
                        goto out_unlock;
-               }
 
-               regs = intel_overlay_map_regs_atomic(overlay);
+               overlay->color_key  = attrs->color_key;
+               overlay->brightness = attrs->brightness;
+               overlay->contrast   = attrs->contrast;
+               overlay->saturation = attrs->saturation;
+
+               regs = intel_overlay_map_regs(overlay);
                if (!regs) {
                        ret = -ENOMEM;
                        goto out_unlock;
@@ -1305,13 +1332,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 
                update_reg_attrs(overlay, regs);
 
-               intel_overlay_unmap_regs_atomic(overlay);
+               intel_overlay_unmap_regs(overlay, regs);
 
                if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
-                       if (!IS_I9XX(dev)) {
-                               ret = -EINVAL;
+                       if (IS_GEN2(dev))
                                goto out_unlock;
-                       }
 
                        if (overlay->active) {
                                ret = -EBUSY;
@@ -1319,7 +1344,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        }
 
                        ret = check_gamma(attrs);
-                       if (ret != 0)
+                       if (ret)
                                goto out_unlock;
 
                        I915_WRITE(OGAMC0, attrs->gamma0);
@@ -1329,9 +1354,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        I915_WRITE(OGAMC4, attrs->gamma4);
                        I915_WRITE(OGAMC5, attrs->gamma5);
                }
-               ret = 0;
        }
 
+       ret = 0;
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        mutex_unlock(&dev->mode_config.mutex);
@@ -1347,7 +1372,7 @@ void intel_setup_overlay(struct drm_device *dev)
        struct overlay_registers *regs;
        int ret;
 
-       if (!OVERLAY_EXISTS(dev))
+       if (!HAS_OVERLAY(dev))
                return;
 
        overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
@@ -1360,22 +1385,28 @@ void intel_setup_overlay(struct drm_device *dev)
                goto out_free;
        overlay->reg_bo = to_intel_bo(reg_bo);
 
-       if (OVERLAY_NONPHYSICAL(dev)) {
-               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
-               if (ret) {
-                        DRM_ERROR("failed to pin overlay register bo\n");
-                        goto out_free_bo;
-                }
-               overlay->flip_addr = overlay->reg_bo->gtt_offset;
-       } else {
+       if (OVERLAY_NEEDS_PHYSICAL(dev)) {
                ret = i915_gem_attach_phys_object(dev, reg_bo,
                                                  I915_GEM_PHYS_OVERLAY_REGS,
-                                                 0);
+                                                 PAGE_SIZE);
                 if (ret) {
                         DRM_ERROR("failed to attach phys overlay regs\n");
                         goto out_free_bo;
                 }
                overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+       } else {
+               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+               if (ret) {
+                        DRM_ERROR("failed to pin overlay register bo\n");
+                        goto out_free_bo;
+                }
+               overlay->flip_addr = overlay->reg_bo->gtt_offset;
+
+               ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
+               if (ret) {
+                        DRM_ERROR("failed to move overlay register bo into the GTT\n");
+                        goto out_unpin_bo;
+                }
        }
 
        /* init all values */
@@ -1384,21 +1415,22 @@ void intel_setup_overlay(struct drm_device *dev)
        overlay->contrast = 75;
        overlay->saturation = 146;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        if (!regs)
                goto out_free_bo;
 
        memset(regs, 0, sizeof(struct overlay_registers));
        update_polyphase_filter(regs);
-
        update_reg_attrs(overlay, regs);
 
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
        dev_priv->overlay = overlay;
        DRM_INFO("initialized overlay support\n");
        return;
 
+out_unpin_bo:
+       i915_gem_object_unpin(reg_bo);
 out_free_bo:
        drm_gem_object_unreference(reg_bo);
 out_free:
@@ -1408,18 +1440,23 @@ out_free:
 
 void intel_cleanup_overlay(struct drm_device *dev)
 {
-        drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
-       if (dev_priv->overlay) {
-               /* The bo's should be free'd by the generic code already.
-                * Furthermore modesetting teardown happens beforehand so the
-                * hardware should be off already */
-               BUG_ON(dev_priv->overlay->active);
+       if (!dev_priv->overlay)
+               return;
 
-               kfree(dev_priv->overlay);
-       }
+       /* The bo's should be free'd by the generic code already.
+        * Furthermore modesetting teardown happens beforehand so the
+        * hardware should be off already */
+       BUG_ON(dev_priv->overlay->active);
+
+       drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+       kfree(dev_priv->overlay);
 }
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
 struct intel_overlay_error_state {
        struct overlay_registers regs;
        unsigned long base;
@@ -1427,6 +1464,29 @@ struct intel_overlay_error_state {
        u32 isr;
 };
 
+static struct overlay_registers *
+intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+{
+       drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+       struct overlay_registers *regs;
+
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+                                               overlay->reg_bo->gtt_offset);
+
+       return regs;
+}
+
+static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
+                                           struct overlay_registers *regs)
+{
+       if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               io_mapping_unmap_atomic(regs);
+}
+
+
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_device *dev)
 {
@@ -1444,17 +1504,17 @@ intel_overlay_capture_error_state(struct drm_device *dev)
 
        error->dovsta = I915_READ(DOVSTA);
        error->isr = I915_READ(ISR);
-       if (OVERLAY_NONPHYSICAL(overlay->dev))
-               error->base = (long) overlay->reg_bo->gtt_offset;
-       else
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
                error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               error->base = (long) overlay->reg_bo->gtt_offset;
 
        regs = intel_overlay_map_regs_atomic(overlay);
        if (!regs)
                goto err;
 
        memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs_atomic(overlay, regs);
 
        return error;
 
@@ -1515,3 +1575,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s
        P(UVSCALEV);
 #undef P
 }
+#endif
index e7f5299d9d5740177ca8722db99892b2a7a856f5..92ff8f38527810657f94ad2f4439732e8dae8fa9 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "intel_drv.h"
 
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
@@ -109,3 +111,110 @@ done:
        dev_priv->pch_pf_pos = (x << 16) | y;
        dev_priv->pch_pf_size = (width << 16) | height;
 }
+
+static int is_backlight_combination_mode(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+
+       if (IS_GEN2(dev))
+               return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+       return 0;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 max;
+
+       if (HAS_PCH_SPLIT(dev)) {
+               max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+       } else {
+               max = I915_READ(BLC_PWM_CTL);
+               if (IS_PINEVIEW(dev)) {
+                       max >>= 17;
+               } else {
+                       max >>= 16;
+                       if (INTEL_INFO(dev)->gen < 4)
+                               max &= ~1;
+               }
+
+               if (is_backlight_combination_mode(dev))
+                       max *= 0xff;
+       }
+
+       if (max == 0) {
+               /* XXX add code here to query mode clock or hardware clock
+                * and program max PWM appropriately.
+                */
+               DRM_ERROR("fixme: max PWM is zero.\n");
+               max = 1;
+       }
+
+       DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+       return max;
+}
+
+u32 intel_panel_get_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val;
+
+       if (HAS_PCH_SPLIT(dev)) {
+               val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+       } else {
+               val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+               if (IS_PINEVIEW(dev))
+                       val >>= 1;
+
+               if (is_backlight_combination_mode(dev)){
+                       u8 lbpc;
+
+                       val &= ~1;
+                       pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+                       val *= lbpc;
+                       val >>= 1;
+               }
+       }
+
+       DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+       return val;
+}
+
+static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+}
+
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+       if (HAS_PCH_SPLIT(dev))
+               return intel_pch_panel_set_backlight(dev, level);
+
+       if (is_backlight_combination_mode(dev)){
+               u32 max = intel_panel_get_max_backlight(dev);
+               u8 lpbc;
+
+               lpbc = level * 0xfe / max + 1;
+               level /= lpbc;
+               pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+       }
+
+       tmp = I915_READ(BLC_PWM_CTL);
+       if (IS_PINEVIEW(dev)) {
+               tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+               level <<= 1;
+       } else
+               tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
index cb3508f78bc350735e16962f8283e598c53deca6..09f2dc353ae239f0d2a6f86a5940c1d7b27656e4 100644 (file)
@@ -32,6 +32,7 @@
 #include "i915_drv.h"
 #include "i915_drm.h"
 #include "i915_trace.h"
+#include "intel_drv.h"
 
 static u32 i915_gem_get_seqno(struct drm_device *dev)
 {
@@ -49,9 +50,9 @@ static u32 i915_gem_get_seqno(struct drm_device *dev)
 
 static void
 render_ring_flush(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               u32     invalidate_domains,
-               u32     flush_domains)
+                 struct intel_ring_buffer *ring,
+                 u32   invalidate_domains,
+                 u32   flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 cmd;
@@ -97,7 +98,7 @@ render_ring_flush(struct drm_device *dev,
                if ((invalidate_domains|flush_domains) &
                    I915_GEM_DOMAIN_RENDER)
                        cmd &= ~MI_NO_WRITE_FLUSH;
-               if (!IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen < 4) {
                        /*
                         * On the 965, the sampler cache always gets flushed
                         * and this bit is reserved.
@@ -118,38 +119,26 @@ render_ring_flush(struct drm_device *dev,
        }
 }
 
-static unsigned int render_ring_get_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(PRB0_HEAD) & HEAD_ADDR;
-}
-
-static unsigned int render_ring_get_tail(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+static void ring_write_tail(struct drm_device *dev,
+                           struct intel_ring_buffer *ring,
+                           u32 value)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(PRB0_TAIL) & TAIL_ADDR;
+       I915_WRITE_TAIL(ring, value);
 }
 
-static unsigned int render_ring_get_active_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct drm_device *dev,
+                              struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+       u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+                       RING_ACTHD(ring->mmio_base) : ACTHD;
 
        return I915_READ(acthd_reg);
 }
 
-static void render_ring_advance_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(PRB0_TAIL, ring->tail);
-}
-
 static int init_ring_common(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        u32 head;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -157,57 +146,57 @@ static int init_ring_common(struct drm_device *dev,
        obj_priv = to_intel_bo(ring->gem_object);
 
        /* Stop the ring if it's running. */
-       I915_WRITE(ring->regs.ctl, 0);
-       I915_WRITE(ring->regs.head, 0);
-       I915_WRITE(ring->regs.tail, 0);
+       I915_WRITE_CTL(ring, 0);
+       I915_WRITE_HEAD(ring, 0);
+       ring->write_tail(dev, ring, 0);
 
        /* Initialize the ring. */
-       I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
-       head = ring->get_head(dev, ring);
+       I915_WRITE_START(ring, obj_priv->gtt_offset);
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
        /* G45 ring initialization fails to reset head to zero */
        if (head != 0) {
                DRM_ERROR("%s head not reset to zero "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
 
-               I915_WRITE(ring->regs.head, 0);
+               I915_WRITE_HEAD(ring, 0);
 
                DRM_ERROR("%s head forced to zero "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
        }
 
-       I915_WRITE(ring->regs.ctl,
+       I915_WRITE_CTL(ring,
                        ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_NO_REPORT | RING_VALID);
 
-       head = I915_READ(ring->regs.head) & HEAD_ADDR;
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
        /* If the head is still not zero, the ring is dead */
        if (head != 0) {
                DRM_ERROR("%s initialization failed "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
                return -EIO;
        }
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_kernel_lost_context(dev);
        else {
-               ring->head = ring->get_head(dev, ring);
-               ring->tail = ring->get_tail(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
@@ -216,13 +205,13 @@ static int init_ring_common(struct drm_device *dev,
 }
 
 static int init_render_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret = init_ring_common(dev, ring);
        int mode;
 
-       if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+       if (INTEL_INFO(dev)->gen > 3) {
                mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
                if (IS_GEN6(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
@@ -250,9 +239,8 @@ do {                                                                        \
  */
 static u32
 render_ring_add_request(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_file *file_priv,
-               u32 flush_domains)
+                       struct intel_ring_buffer *ring,
+                       u32 flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 seqno;
@@ -315,8 +303,8 @@ render_ring_add_request(struct drm_device *dev,
 }
 
 static u32
-render_ring_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct drm_device *dev,
+                     struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        if (HAS_PIPE_CONTROL(dev))
@@ -327,7 +315,7 @@ render_ring_get_gem_seqno(struct drm_device *dev,
 
 static void
 render_ring_get_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
@@ -344,7 +332,7 @@ render_ring_get_user_irq(struct drm_device *dev,
 
 static void
 render_ring_put_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
@@ -360,21 +348,23 @@ render_ring_put_user_irq(struct drm_device *dev,
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
-static void render_setup_status_page(struct drm_device *dev,
-       struct  intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        if (IS_GEN6(dev)) {
-               I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
-               I915_READ(HWS_PGA_GEN6); /* posting read */
+               I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
+                          ring->status_page.gfx_addr);
+               I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
        } else {
-               I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
-               I915_READ(HWS_PGA); /* posting read */
+               I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+                          ring->status_page.gfx_addr);
+               I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
        }
 
 }
 
-void
+static void
 bsd_ring_flush(struct drm_device *dev,
                struct intel_ring_buffer *ring,
                u32     invalidate_domains,
@@ -386,45 +376,16 @@ bsd_ring_flush(struct drm_device *dev,
        intel_ring_advance(dev, ring);
 }
 
-static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_ACTHD);
-}
-
-static inline void bsd_ring_advance_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(BSD_RING_TAIL, ring->tail);
-}
-
 static int init_bsd_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        return init_ring_common(dev, ring);
 }
 
 static u32
-bsd_ring_add_request(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_file *file_priv,
-               u32 flush_domains)
+ring_add_request(struct drm_device *dev,
+                struct intel_ring_buffer *ring,
+                u32 flush_domains)
 {
        u32 seqno;
 
@@ -443,40 +404,32 @@ bsd_ring_add_request(struct drm_device *dev,
        return seqno;
 }
 
-static void bsd_setup_status_page(struct drm_device *dev,
-               struct  intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
-       I915_READ(BSD_HWS_PGA);
-}
-
 static void
 bsd_ring_get_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                     struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 static void
 bsd_ring_put_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                     struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 
 static u32
-bsd_ring_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+ring_status_page_get_seqno(struct drm_device *dev,
+                          struct intel_ring_buffer *ring)
 {
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
 static int
-bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_i915_gem_execbuffer2 *exec,
-               struct drm_clip_rect *cliprects,
-               uint64_t exec_offset)
+ring_dispatch_gem_execbuffer(struct drm_device *dev,
+                            struct intel_ring_buffer *ring,
+                            struct drm_i915_gem_execbuffer2 *exec,
+                            struct drm_clip_rect *cliprects,
+                            uint64_t exec_offset)
 {
        uint32_t exec_start;
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
@@ -488,13 +441,12 @@ bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
        return 0;
 }
 
-
 static int
 render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_i915_gem_execbuffer2 *exec,
-               struct drm_clip_rect *cliprects,
-               uint64_t exec_offset)
+                                   struct intel_ring_buffer *ring,
+                                   struct drm_i915_gem_execbuffer2 *exec,
+                                   struct drm_clip_rect *cliprects,
+                                   uint64_t exec_offset)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int nbox = exec->num_cliprects;
@@ -523,8 +475,8 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
                        intel_ring_emit(dev, ring, exec_start + exec_len - 4);
                        intel_ring_emit(dev, ring, 0);
                } else {
-                       intel_ring_begin(dev, ring, 4);
-                       if (IS_I965G(dev)) {
+                       intel_ring_begin(dev, ring, 2);
+                       if (INTEL_INFO(dev)->gen >= 4) {
                                intel_ring_emit(dev, ring,
                                                MI_BATCH_BUFFER_START | (2 << 6)
                                                | MI_BATCH_NON_SECURE_I965);
@@ -539,7 +491,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
                intel_ring_advance(dev, ring);
        }
 
-       if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+       if (IS_G4X(dev) || IS_GEN5(dev)) {
                intel_ring_begin(dev, ring, 2);
                intel_ring_emit(dev, ring, MI_FLUSH |
                                MI_NO_WRITE_FLUSH |
@@ -553,7 +505,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
 }
 
 static void cleanup_status_page(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                               struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
@@ -573,7 +525,7 @@ static void cleanup_status_page(struct drm_device *dev,
 }
 
 static int init_status_page(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
@@ -603,7 +555,7 @@ static int init_status_page(struct drm_device *dev,
        ring->status_page.obj = obj;
        memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-       ring->setup_status_page(dev, ring);
+       intel_ring_setup_status_page(dev, ring);
        DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
                        ring->name, ring->status_page.gfx_addr);
 
@@ -617,15 +569,18 @@ err:
        return ret;
 }
 
-
 int intel_init_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                          struct intel_ring_buffer *ring)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
        struct drm_gem_object *obj;
        int ret;
 
        ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       INIT_LIST_HEAD(&ring->gpu_write_list);
 
        if (I915_NEED_GFX_HWS(dev)) {
                ret = init_status_page(dev, ring);
@@ -642,7 +597,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
 
        ring->gem_object = obj;
 
-       ret = i915_gem_object_pin(obj, ring->alignment);
+       ret = i915_gem_object_pin(obj, PAGE_SIZE);
        if (ret)
                goto err_unref;
 
@@ -668,14 +623,12 @@ int intel_init_ring_buffer(struct drm_device *dev,
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_kernel_lost_context(dev);
        else {
-               ring->head = ring->get_head(dev, ring);
-               ring->tail = ring->get_tail(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
        }
-       INIT_LIST_HEAD(&ring->active_list);
-       INIT_LIST_HEAD(&ring->request_list);
        return ret;
 
 err_unmap:
@@ -691,7 +644,7 @@ err_hws:
 }
 
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                              struct intel_ring_buffer *ring)
 {
        if (ring->gem_object == NULL)
                return;
@@ -704,8 +657,8 @@ void intel_cleanup_ring_buffer(struct drm_device *dev,
        cleanup_status_page(dev, ring);
 }
 
-int intel_wrap_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring)
 {
        unsigned int *virt;
        int rem;
@@ -731,14 +684,15 @@ int intel_wrap_ring_buffer(struct drm_device *dev,
 }
 
 int intel_wait_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n)
+                          struct intel_ring_buffer *ring, int n)
 {
        unsigned long end;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
        trace_i915_ring_wait_begin (dev);
        end = jiffies + 3 * HZ;
        do {
-               ring->head = ring->get_head(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
@@ -753,14 +707,15 @@ int intel_wait_ring_buffer(struct drm_device *dev,
                                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
                }
 
-               yield();
+               msleep(1);
        } while (!time_after(jiffies, end));
        trace_i915_ring_wait_end (dev);
        return -EBUSY;
 }
 
 void intel_ring_begin(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int num_dwords)
+                     struct intel_ring_buffer *ring,
+                     int num_dwords)
 {
        int n = 4*num_dwords;
        if (unlikely(ring->tail + n > ring->size))
@@ -772,97 +727,181 @@ void intel_ring_begin(struct drm_device *dev,
 }
 
 void intel_ring_advance(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                       struct intel_ring_buffer *ring)
 {
        ring->tail &= ring->size - 1;
-       ring->advance_ring(dev, ring);
-}
-
-void intel_fill_struct(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               void *data,
-               unsigned int len)
-{
-       unsigned int *virt = ring->virtual_start + ring->tail;
-       BUG_ON((len&~(4-1)) != 0);
-       intel_ring_begin(dev, ring, len/4);
-       memcpy(virt, data, len);
-       ring->tail += len;
-       ring->tail &= ring->size - 1;
-       ring->space -= len;
-       intel_ring_advance(dev, ring);
+       ring->write_tail(dev, ring, ring->tail);
 }
 
-struct intel_ring_buffer render_ring = {
+static const struct intel_ring_buffer render_ring = {
        .name                   = "render ring",
-       .regs                   = {
-               .ctl = PRB0_CTL,
-               .head = PRB0_HEAD,
-               .tail = PRB0_TAIL,
-               .start = PRB0_START
-       },
-       .ring_flag              = I915_EXEC_RENDER,
+       .id                     = RING_RENDER,
+       .mmio_base              = RENDER_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .alignment              = PAGE_SIZE,
-       .virtual_start          = NULL,
-       .dev                    = NULL,
-       .gem_object             = NULL,
-       .head                   = 0,
-       .tail                   = 0,
-       .space                  = 0,
-       .user_irq_refcount      = 0,
-       .irq_gem_seqno          = 0,
-       .waiting_gem_seqno      = 0,
-       .setup_status_page      = render_setup_status_page,
        .init                   = init_render_ring,
-       .get_head               = render_ring_get_head,
-       .get_tail               = render_ring_get_tail,
-       .get_active_head        = render_ring_get_active_head,
-       .advance_ring           = render_ring_advance_ring,
+       .write_tail             = ring_write_tail,
        .flush                  = render_ring_flush,
        .add_request            = render_ring_add_request,
-       .get_gem_seqno          = render_ring_get_gem_seqno,
+       .get_seqno              = render_ring_get_seqno,
        .user_irq_get           = render_ring_get_user_irq,
        .user_irq_put           = render_ring_put_user_irq,
        .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
-       .status_page            = {NULL, 0, NULL},
-       .map                    = {0,}
 };
 
 /* ring buffer for bit-stream decoder */
 
-struct intel_ring_buffer bsd_ring = {
+static const struct intel_ring_buffer bsd_ring = {
        .name                   = "bsd ring",
-       .regs                   = {
-               .ctl = BSD_RING_CTL,
-               .head = BSD_RING_HEAD,
-               .tail = BSD_RING_TAIL,
-               .start = BSD_RING_START
-       },
-       .ring_flag              = I915_EXEC_BSD,
+       .id                     = RING_BSD,
+       .mmio_base              = BSD_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .alignment              = PAGE_SIZE,
-       .virtual_start          = NULL,
-       .dev                    = NULL,
-       .gem_object             = NULL,
-       .head                   = 0,
-       .tail                   = 0,
-       .space                  = 0,
-       .user_irq_refcount      = 0,
-       .irq_gem_seqno          = 0,
-       .waiting_gem_seqno      = 0,
-       .setup_status_page      = bsd_setup_status_page,
        .init                   = init_bsd_ring,
-       .get_head               = bsd_ring_get_head,
-       .get_tail               = bsd_ring_get_tail,
-       .get_active_head        = bsd_ring_get_active_head,
-       .advance_ring           = bsd_ring_advance_ring,
+       .write_tail             = ring_write_tail,
        .flush                  = bsd_ring_flush,
-       .add_request            = bsd_ring_add_request,
-       .get_gem_seqno          = bsd_ring_get_gem_seqno,
+       .add_request            = ring_add_request,
+       .get_seqno              = ring_status_page_get_seqno,
        .user_irq_get           = bsd_ring_get_user_irq,
        .user_irq_put           = bsd_ring_put_user_irq,
-       .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
-       .status_page            = {NULL, 0, NULL},
-       .map                    = {0,}
+       .dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer,
 };
+
+
+static void gen6_bsd_ring_write_tail(struct drm_device *dev,
+                                    struct intel_ring_buffer *ring,
+                                    u32 value)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Every tail move must follow the sequence below */
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
+       I915_WRITE(GEN6_BSD_RNCID, 0x0);
+
+       if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+                               GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+                       50))
+               DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+       I915_WRITE_TAIL(ring, value);
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+}
+
+static void gen6_ring_flush(struct drm_device *dev,
+                           struct intel_ring_buffer *ring,
+                           u32 invalidate_domains,
+                           u32 flush_domains)
+{
+       intel_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_FLUSH_DW);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring,
+                                 struct drm_i915_gem_execbuffer2 *exec,
+                                 struct drm_clip_rect *cliprects,
+                                 uint64_t exec_offset)
+{
+       uint32_t exec_start;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+
+       intel_ring_begin(dev, ring, 2);
+       intel_ring_emit(dev, ring,
+                      MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+       /* bit0-7 is the length on GEN6+ */
+       intel_ring_emit(dev, ring, exec_start);
+       intel_ring_advance(dev, ring);
+
+       return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+static const struct intel_ring_buffer gen6_bsd_ring = {
+       .name                   = "gen6 bsd ring",
+       .id                     = RING_BSD,
+       .mmio_base              = GEN6_BSD_RING_BASE,
+       .size                   = 32 * PAGE_SIZE,
+       .init                   = init_bsd_ring,
+       .write_tail             = gen6_bsd_ring_write_tail,
+       .flush                  = gen6_ring_flush,
+       .add_request            = ring_add_request,
+       .get_seqno              = ring_status_page_get_seqno,
+       .user_irq_get           = bsd_ring_get_user_irq,
+       .user_irq_put           = bsd_ring_put_user_irq,
+       .dispatch_gem_execbuffer        = gen6_ring_dispatch_gem_execbuffer,
+};
+
+/* Blitter support (SandyBridge+) */
+
+static void
+blt_ring_get_user_irq(struct drm_device *dev,
+                     struct intel_ring_buffer *ring)
+{
+       /* do nothing */
+}
+static void
+blt_ring_put_user_irq(struct drm_device *dev,
+                     struct intel_ring_buffer *ring)
+{
+       /* do nothing */
+}
+
+static const struct intel_ring_buffer gen6_blt_ring = {
+       .name                   = "blt ring",
+       .id                     = RING_BLT,
+       .mmio_base              = BLT_RING_BASE,
+       .size                   = 32 * PAGE_SIZE,
+       .init                   = init_ring_common,
+       .write_tail             = ring_write_tail,
+       .flush                  = gen6_ring_flush,
+       .add_request            = ring_add_request,
+       .get_seqno              = ring_status_page_get_seqno,
+       .user_irq_get           = blt_ring_get_user_irq,
+       .user_irq_put           = blt_ring_put_user_irq,
+       .dispatch_gem_execbuffer        = gen6_ring_dispatch_gem_execbuffer,
+};
+
+int intel_init_render_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       dev_priv->render_ring = render_ring;
+
+       if (!I915_NEED_GFX_HWS(dev)) {
+               dev_priv->render_ring.status_page.page_addr
+                       = dev_priv->status_page_dmah->vaddr;
+               memset(dev_priv->render_ring.status_page.page_addr,
+                               0, PAGE_SIZE);
+       }
+
+       return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+}
+
+int intel_init_bsd_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (IS_GEN6(dev))
+               dev_priv->bsd_ring = gen6_bsd_ring;
+       else
+               dev_priv->bsd_ring = bsd_ring;
+
+       return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+}
+
+int intel_init_blt_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       dev_priv->blt_ring = gen6_blt_ring;
+
+       return intel_init_ring_buffer(dev, &dev_priv->blt_ring);
+}
index 525e7d3edda801582ac5a779de31a8fe43844ae0..a05aff0e5764d67e421a5a4995f2b0b92dfcd925 100644 (file)
@@ -7,25 +7,32 @@ struct  intel_hw_status_page {
        struct          drm_gem_object *obj;
 };
 
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+
 struct drm_i915_gem_execbuffer2;
 struct  intel_ring_buffer {
        const char      *name;
-       struct          ring_regs {
-                       u32 ctl;
-                       u32 head;
-                       u32 tail;
-                       u32 start;
-       } regs;
-       unsigned int    ring_flag;
+       enum intel_ring_id {
+               RING_RENDER = 0x1,
+               RING_BSD = 0x2,
+               RING_BLT = 0x4,
+       } id;
+       u32             mmio_base;
        unsigned long   size;
-       unsigned int    alignment;
        void            *virtual_start;
        struct          drm_device *dev;
        struct          drm_gem_object *gem_object;
 
        unsigned int    head;
        unsigned int    tail;
-       unsigned int    space;
+       int             space;
        struct intel_hw_status_page status_page;
 
        u32             irq_gem_seqno;          /* last seq seem at irq time */
@@ -35,30 +42,22 @@ struct  intel_ring_buffer {
                        struct intel_ring_buffer *ring);
        void            (*user_irq_put)(struct drm_device *dev,
                        struct intel_ring_buffer *ring);
-       void            (*setup_status_page)(struct drm_device *dev,
-                       struct  intel_ring_buffer *ring);
 
        int             (*init)(struct drm_device *dev,
                        struct intel_ring_buffer *ring);
 
-       unsigned int    (*get_head)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       unsigned int    (*get_tail)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       unsigned int    (*get_active_head)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       void            (*advance_ring)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       void            (*write_tail)(struct drm_device *dev,
+                                     struct intel_ring_buffer *ring,
+                                     u32 value);
        void            (*flush)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
                        u32     invalidate_domains,
                        u32     flush_domains);
        u32             (*add_request)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
-                       struct drm_file *file_priv,
                        u32 flush_domains);
-       u32             (*get_gem_seqno)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       u32             (*get_seqno)(struct drm_device *dev,
+                                    struct intel_ring_buffer *ring);
        int             (*dispatch_gem_execbuffer)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
                        struct drm_i915_gem_execbuffer2 *exec,
@@ -83,6 +82,20 @@ struct  intel_ring_buffer {
         */
        struct list_head request_list;
 
+       /**
+        * List of objects currently pending a GPU write flush.
+        *
+        * All elements on this list will belong to either the
+        * active_list or flushing_list, last_rendering_seqno can
+        * be used to differentiate between the two elements.
+        */
+       struct list_head gpu_write_list;
+
+       /**
+        * Do we have some not yet emitted requests outstanding?
+        */
+       bool outstanding_lazy_request;
+
        wait_queue_head_t irq_queue;
        drm_local_map_t map;
 };
@@ -96,15 +109,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
 }
 
 int intel_init_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                          struct intel_ring_buffer *ring);
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                              struct intel_ring_buffer *ring);
 int intel_wait_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n);
-int intel_wrap_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                          struct intel_ring_buffer *ring, int n);
 void intel_ring_begin(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n);
+                     struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct drm_device *dev,
                                   struct intel_ring_buffer *ring,
@@ -115,17 +126,19 @@ static inline void intel_ring_emit(struct drm_device *dev,
        ring->tail += 4;
 }
 
-void intel_fill_struct(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               void *data,
-               unsigned int len);
 void intel_ring_advance(struct drm_device *dev,
                struct intel_ring_buffer *ring);
 
 u32 intel_ring_get_seqno(struct drm_device *dev,
                struct intel_ring_buffer *ring);
 
-extern struct intel_ring_buffer render_ring;
-extern struct intel_ring_buffer bsd_ring;
+int intel_init_render_ring_buffer(struct drm_device *dev);
+int intel_init_bsd_ring_buffer(struct drm_device *dev);
+int intel_init_blt_ring_buffer(struct drm_device *dev);
+
+u32 intel_ring_get_active_head(struct drm_device *dev,
+                              struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring);
 
 #endif /* _INTEL_RINGBUFFER_H_ */
index ee73e428a84a800dd8d70a1747457033f7e8da8e..de158b76bcd572da1e261713c66d43fa4428f72c 100644 (file)
@@ -65,8 +65,11 @@ static const char *tv_format_names[] = {
 struct intel_sdvo {
        struct intel_encoder base;
 
+       struct i2c_adapter *i2c;
        u8 slave_addr;
 
+       struct i2c_adapter ddc;
+
        /* Register for the SDVO device: SDVOB or SDVOC */
        int sdvo_reg;
 
@@ -104,34 +107,24 @@ struct intel_sdvo {
         * This is set if we treat the device as HDMI, instead of DVI.
         */
        bool is_hdmi;
+       bool has_audio;
 
        /**
-        * This is set if we detect output of sdvo device as LVDS.
+        * This is set if we detect output of sdvo device as LVDS and
+        * have a valid fixed mode to use with the panel.
         */
        bool is_lvds;
 
-       /**
-        * This is sdvo flags for input timing.
-        */
-       uint8_t sdvo_flags;
-
        /**
         * This is sdvo fixed pannel mode pointer
         */
        struct drm_display_mode *sdvo_lvds_fixed_mode;
 
-       /*
-        * supported encoding mode, used to determine whether HDMI is
-        * supported
-        */
-       struct intel_sdvo_encode encode;
-
        /* DDC bus used by this SDVO encoder */
        uint8_t ddc_bus;
 
-       /* Mac mini hack -- use the same DDC as the analog connector */
-       struct i2c_adapter *analog_ddc_bus;
-
+       /* Input timings for adjusted_mode */
+       struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -140,11 +133,15 @@ struct intel_sdvo_connector {
        /* Mark the type of connector */
        uint16_t output_flag;
 
+       int force_audio;
+
        /* This contains all current supported TV format */
        u8 tv_format_supported[TV_FORMAT_NUM];
        int   format_supported_num;
        struct drm_property *tv_format;
 
+       struct drm_property *force_audio_property;
+
        /* add the property for the SDVO-TV */
        struct drm_property *left;
        struct drm_property *right;
@@ -186,9 +183,15 @@ struct intel_sdvo_connector {
        u32     cur_dot_crawl,  max_dot_crawl;
 };
 
-static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct intel_sdvo, base.base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base);
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_sdvo, base);
 }
 
 static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -213,7 +216,7 @@ intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
  */
 static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 bval = val, cval = val;
        int i;
@@ -245,49 +248,29 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 
 static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
 {
-       u8 out_buf[2] = { addr, 0 };
-       u8 buf[2];
        struct i2c_msg msgs[] = {
                {
-                       .addr = intel_sdvo->slave_addr >> 1,
+                       .addr = intel_sdvo->slave_addr,
                        .flags = 0,
                        .len = 1,
-                       .buf = out_buf,
+                       .buf = &addr,
                },
                {
-                       .addr = intel_sdvo->slave_addr >> 1,
+                       .addr = intel_sdvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
-                       .buf = buf,
+                       .buf = ch,
                }
        };
        int ret;
 
-       if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
-       {
-               *ch = buf[0];
+       if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
                return true;
-       }
 
        DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
        return false;
 }
 
-static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch)
-{
-       u8 out_buf[2] = { addr, ch };
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 2,
-                       .buf = out_buf,
-               }
-       };
-
-       return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
-}
-
 #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
 /** Mapping of command numbers to names, for debug output */
 static const struct _sdvo_cmd_name {
@@ -432,22 +415,6 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
        DRM_LOG_KMS("\n");
 }
 
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                const void *args, int args_len)
-{
-       int i;
-
-       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
-       for (i = 0; i < args_len; i++) {
-               if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i,
-                                          ((u8*)args)[i]))
-                       return false;
-       }
-
-       return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd);
-}
-
 static const char *cmd_status_names[] = {
        "Power on",
        "Success",
@@ -458,54 +425,115 @@ static const char *cmd_status_names[] = {
        "Scaling not supported"
 };
 
-static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo,
-                                     void *response, int response_len,
-                                     u8 status)
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                const void *args, int args_len)
 {
-       int i;
+       u8 buf[args_len*2 + 2], status;
+       struct i2c_msg msgs[args_len + 3];
+       int i, ret;
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
-       for (i = 0; i < response_len; i++)
-               DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
-       for (; i < 8; i++)
-               DRM_LOG_KMS("   ");
-       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
-       else
-               DRM_LOG_KMS("(??? %d)", status);
-       DRM_LOG_KMS("\n");
+       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+       for (i = 0; i < args_len; i++) {
+               msgs[i].addr = intel_sdvo->slave_addr;
+               msgs[i].flags = 0;
+               msgs[i].len = 2;
+               msgs[i].buf = buf + 2 *i;
+               buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+               buf[2*i + 1] = ((u8*)args)[i];
+       }
+       msgs[i].addr = intel_sdvo->slave_addr;
+       msgs[i].flags = 0;
+       msgs[i].len = 2;
+       msgs[i].buf = buf + 2*i;
+       buf[2*i + 0] = SDVO_I2C_OPCODE;
+       buf[2*i + 1] = cmd;
+
+       /* the following two are to read the response */
+       status = SDVO_I2C_CMD_STATUS;
+       msgs[i+1].addr = intel_sdvo->slave_addr;
+       msgs[i+1].flags = 0;
+       msgs[i+1].len = 1;
+       msgs[i+1].buf = &status;
+
+       msgs[i+2].addr = intel_sdvo->slave_addr;
+       msgs[i+2].flags = I2C_M_RD;
+       msgs[i+2].len = 1;
+       msgs[i+2].buf = &status;
+
+       ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+               return false;
+       }
+       if (ret != i+3) {
+               /* failure in I2C transfer */
+               DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+               return false;
+       }
+
+       i = 3;
+       while (status == SDVO_CMD_STATUS_PENDING && i--) {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_CMD_STATUS,
+                                         &status))
+                       return false;
+       }
+       if (status != SDVO_CMD_STATUS_SUCCESS) {
+               DRM_DEBUG_KMS("command returns response %s [%d]\n",
+                             status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
+                             status);
+               return false;
+       }
+
+       return true;
 }
 
 static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
                                     void *response, int response_len)
 {
-       int i;
+       u8 retry = 5;
        u8 status;
-       u8 retry = 50;
-
-       while (retry--) {
-               /* Read the command response */
-               for (i = 0; i < response_len; i++) {
-                       if (!intel_sdvo_read_byte(intel_sdvo,
-                                                 SDVO_I2C_RETURN_0 + i,
-                                                 &((u8 *)response)[i]))
-                               return false;
-               }
+       int i;
 
-               /* read the return status */
-               if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS,
+       /*
+        * The documentation states that all commands will be
+        * processed within 15µs, and that we need only poll
+        * the status byte a maximum of 3 times in order for the
+        * command to be complete.
+        *
+        * Check 5 times in case the hardware failed to read the docs.
+        */
+       do {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_CMD_STATUS,
                                          &status))
                        return false;
+       } while (status == SDVO_CMD_STATUS_PENDING && --retry);
 
-               intel_sdvo_debug_response(intel_sdvo, response, response_len,
-                                         status);
-               if (status != SDVO_CMD_STATUS_PENDING)
-                       break;
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+       else
+               DRM_LOG_KMS("(??? %d)", status);
 
-               mdelay(50);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               goto log_fail;
+
+       /* Read the command response */
+       for (i = 0; i < response_len; i++) {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_RETURN_0 + i,
+                                         &((u8 *)response)[i]))
+                       goto log_fail;
+               DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
        }
+       DRM_LOG_KMS("\n");
+       return true;
 
-       return status == SDVO_CMD_STATUS_SUCCESS;
+log_fail:
+       DRM_LOG_KMS("\n");
+       return false;
 }
 
 static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
@@ -518,71 +546,17 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
                return 4;
 }
 
-/**
- * Try to read the response after issuie the DDC switch command. But it
- * is noted that we must do the action of reading response and issuing DDC
- * switch command in one I2C transaction. Otherwise when we try to start
- * another I2C transaction after issuing the DDC bus switch, it will be
- * switched to the internal SDVO register.
- */
-static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
-                                             u8 target)
+static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+                                             u8 ddc_bus)
 {
-       u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 2,
-                       .buf = out_buf,
-               },
-               /* the following two are to read the response */
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = cmd_buf,
-               },
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = ret_value,
-               },
-       };
-
-       intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
-                                       &target, 1);
-       /* write the DDC switch command argument */
-       intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target);
-
-       out_buf[0] = SDVO_I2C_OPCODE;
-       out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
-       cmd_buf[0] = SDVO_I2C_CMD_STATUS;
-       cmd_buf[1] = 0;
-       ret_value[0] = 0;
-       ret_value[1] = 0;
-
-       ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
-       if (ret != 3) {
-               /* failure in I2C transfer */
-               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
-               return;
-       }
-       if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("DDC switch command returns response %d\n",
-                                       ret_value[0]);
-               return;
-       }
-       return;
+       return intel_sdvo_write_cmd(intel_sdvo,
+                                   SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+                                   &ddc_bus, 1);
 }
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
-               return false;
-
-       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+       return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
 }
 
 static bool
@@ -819,17 +793,13 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
                mode->flags |= DRM_MODE_FLAG_PVSYNC;
 }
 
-static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo,
-                                      struct intel_sdvo_encode *encode)
+static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
 {
-       if (intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_SUPP_ENCODE,
-                                 encode, sizeof(*encode)))
-               return true;
+       struct intel_sdvo_encode encode;
 
-       /* non-support means DVI */
-       memset(encode, 0, sizeof(*encode));
-       return false;
+       return intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_SUPP_ENCODE,
+                                 &encode, sizeof(encode));
 }
 
 static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
@@ -874,115 +844,33 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
 }
 #endif
 
-static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo,
-                                   int index,
-                                   uint8_t *data, int8_t size, uint8_t tx_rate)
-{
-    uint8_t set_buf_index[2];
-
-    set_buf_index[0] = index;
-    set_buf_index[1] = 0;
-
-    if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
-                             set_buf_index, 2))
-           return false;
-
-    for (; size > 0; size -= 8) {
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8))
-               return false;
-
-       data += 8;
-    }
-
-    return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
-}
-
-static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
-{
-       uint8_t csum = 0;
-       int i;
-
-       for (i = 0; i < size; i++)
-               csum += data[i];
-
-       return 0x100 - csum;
-}
-
-#define DIP_TYPE_AVI   0x82
-#define DIP_VERSION_AVI        0x2
-#define DIP_LEN_AVI    13
-
-struct dip_infoframe {
-       uint8_t type;
-       uint8_t version;
-       uint8_t len;
-       uint8_t checksum;
-       union {
-               struct {
-                       /* Packet Byte #1 */
-                       uint8_t S:2;
-                       uint8_t B:2;
-                       uint8_t A:1;
-                       uint8_t Y:2;
-                       uint8_t rsvd1:1;
-                       /* Packet Byte #2 */
-                       uint8_t R:4;
-                       uint8_t M:2;
-                       uint8_t C:2;
-                       /* Packet Byte #3 */
-                       uint8_t SC:2;
-                       uint8_t Q:2;
-                       uint8_t EC:3;
-                       uint8_t ITC:1;
-                       /* Packet Byte #4 */
-                       uint8_t VIC:7;
-                       uint8_t rsvd2:1;
-                       /* Packet Byte #5 */
-                       uint8_t PR:4;
-                       uint8_t rsvd3:4;
-                       /* Packet Byte #6~13 */
-                       uint16_t top_bar_end;
-                       uint16_t bottom_bar_start;
-                       uint16_t left_bar_end;
-                       uint16_t right_bar_start;
-               } avi;
-               struct {
-                       /* Packet Byte #1 */
-                       uint8_t channel_count:3;
-                       uint8_t rsvd1:1;
-                       uint8_t coding_type:4;
-                       /* Packet Byte #2 */
-                       uint8_t sample_size:2; /* SS0, SS1 */
-                       uint8_t sample_frequency:3;
-                       uint8_t rsvd2:3;
-                       /* Packet Byte #3 */
-                       uint8_t coding_type_private:5;
-                       uint8_t rsvd3:3;
-                       /* Packet Byte #4 */
-                       uint8_t channel_allocation;
-                       /* Packet Byte #5 */
-                       uint8_t rsvd4:3;
-                       uint8_t level_shift:4;
-                       uint8_t downmix_inhibit:1;
-               } audio;
-               uint8_t payload[28];
-       } __attribute__ ((packed)) u;
-} __attribute__((packed));
-
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-                                        struct drm_display_mode * mode)
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 {
        struct dip_infoframe avi_if = {
                .type = DIP_TYPE_AVI,
-               .version = DIP_VERSION_AVI,
+               .ver = DIP_VERSION_AVI,
                .len = DIP_LEN_AVI,
        };
+       uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
+       uint8_t set_buf_index[2] = { 1, 0 };
+       uint64_t *data = (uint64_t *)&avi_if;
+       unsigned i;
+
+       intel_dip_infoframe_csum(&avi_if);
+
+       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+                                 set_buf_index, 2))
+               return false;
 
-       avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
-                                                   4 + avi_if.len);
-       return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if,
-                                      4 + avi_if.len,
-                                      SDVO_HBUF_TX_VSYNC);
+       for (i = 0; i < sizeof(avi_if); i += 8) {
+               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+                                         data, 8))
+                       return false;
+               data++;
+       }
+
+       return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+                                   &tx_rate, 1);
 }
 
 static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
@@ -1022,8 +910,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
                                        struct drm_display_mode *mode,
                                        struct drm_display_mode *adjusted_mode)
 {
-       struct intel_sdvo_dtd input_dtd;
-
        /* Reset the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return false;
@@ -1035,14 +921,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
                return false;
 
        if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-                                                  &input_dtd))
+                                                  &intel_sdvo->input_dtd))
                return false;
 
-       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-       intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
+       intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
 
        drm_mode_set_crtcinfo(adjusted_mode, 0);
-       mode->clock = adjusted_mode->clock;
        return true;
 }
 
@@ -1050,7 +934,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+       int multiplier;
 
        /* We need to construct preferred input timings based on our
         * output timings.  To do that, we have to set the output
@@ -1065,10 +950,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                                             mode,
                                                             adjusted_mode);
        } else if (intel_sdvo->is_lvds) {
-               drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
-
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-                                                           intel_sdvo->sdvo_lvds_fixed_mode))
+                                                            intel_sdvo->sdvo_lvds_fixed_mode))
                        return false;
 
                (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +960,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
        }
 
        /* Make the CRTC code factor in the SDVO pixel multiplier.  The
-        * SDVO device will be told of the multiplier during mode_set.
+        * SDVO device will factor out the multiplier during mode_set.
         */
-       adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+       multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
+       intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
 
        return true;
 }
@@ -1092,11 +976,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        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_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       u32 sdvox = 0;
-       int sdvo_pixel_multiply, rate;
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+       u32 sdvox;
        struct intel_sdvo_in_out_map in_out;
        struct intel_sdvo_dtd input_dtd;
+       int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+       int rate;
 
        if (!mode)
                return;
@@ -1114,28 +999,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                             SDVO_CMD_SET_IN_OUT_MAP,
                             &in_out, sizeof(in_out));
 
-       if (intel_sdvo->is_hdmi) {
-               if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
-                       return;
-
-               sdvox |= SDVO_AUDIO_ENABLE;
-       }
+       /* Set the output timings to the screen */
+       if (!intel_sdvo_set_target_output(intel_sdvo,
+                                         intel_sdvo->attached_output))
+               return;
 
        /* We have tried to get input timing in mode_fixup, and filled into
-          adjusted_mode */
-       intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-       if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
-               input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
-
-       /* If it's a TV, we already set the output timing in mode_fixup.
-        * Otherwise, the output timing is equal to the input timing.
+        * adjusted_mode.
         */
-       if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
+       if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
+               input_dtd = intel_sdvo->input_dtd;
+       } else {
                /* Set the output timing to the screen */
                if (!intel_sdvo_set_target_output(intel_sdvo,
                                                  intel_sdvo->attached_output))
                        return;
 
+               intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
                (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
        }
 
@@ -1143,31 +1023,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return;
 
-       if (intel_sdvo->is_tv) {
-               if (!intel_sdvo_set_tv_format(intel_sdvo))
-                       return;
-       }
+       if (intel_sdvo->is_hdmi &&
+           !intel_sdvo_set_avi_infoframe(intel_sdvo))
+               return;
 
-       /* We would like to use intel_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.
-        */
-#if 0
-       success = intel_sdvo_create_preferred_input_timing(encoder, clock,
-                                                          width, height);
-       if (success) {
-               struct intel_sdvo_dtd *input_dtd;
+       if (intel_sdvo->is_tv &&
+           !intel_sdvo_set_tv_format(intel_sdvo))
+               return;
 
-               intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
-               intel_sdvo_set_input_timing(encoder, &input_dtd);
-       }
-#else
        (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
-#endif
 
-       sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
-       switch (sdvo_pixel_multiply) {
+       switch (pixel_multiplier) {
+       default:
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
        case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
        case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1176,14 +1043,14 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                return;
 
        /* Set the SDVO control regs. */
-       if (IS_I965G(dev)) {
-               sdvox |= SDVO_BORDER_ENABLE;
+       if (INTEL_INFO(dev)->gen >= 4) {
+               sdvox = SDVO_BORDER_ENABLE;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                        sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                        sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
        } else {
-               sdvox |= I915_READ(intel_sdvo->sdvo_reg);
+               sdvox = I915_READ(intel_sdvo->sdvo_reg);
                switch (intel_sdvo->sdvo_reg) {
                case SDVOB:
                        sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1063,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        }
        if (intel_crtc->pipe == 1)
                sdvox |= SDVO_PIPE_B_SELECT;
+       if (intel_sdvo->has_audio)
+               sdvox |= SDVO_AUDIO_ENABLE;
 
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                /* done in crtc_mode_set as the dpll_md reg must be written early */
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                /* done in crtc_mode_set as it lives inside the dpll register */
        } else {
-               sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+               sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
-       if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
+       if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
                sdvox |= SDVO_STALL_SELECT;
        intel_sdvo_write_sdvox(intel_sdvo, sdvox);
 }
@@ -1214,7 +1083,7 @@ 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_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        u32 temp;
 
@@ -1260,8 +1129,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -1285,7 +1153,38 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
 
 static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
 {
-       return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps));
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_DEVICE_CAPS,
+                                 caps, sizeof(*caps)))
+               return false;
+
+       DRM_DEBUG_KMS("SDVO capabilities:\n"
+                     "  vendor_id: %d\n"
+                     "  device_id: %d\n"
+                     "  device_rev_id: %d\n"
+                     "  sdvo_version_major: %d\n"
+                     "  sdvo_version_minor: %d\n"
+                     "  sdvo_inputs_mask: %d\n"
+                     "  smooth_scaling: %d\n"
+                     "  sharp_scaling: %d\n"
+                     "  up_scaling: %d\n"
+                     "  down_scaling: %d\n"
+                     "  stall_support: %d\n"
+                     "  output_flags: %d\n",
+                     caps->vendor_id,
+                     caps->device_id,
+                     caps->device_rev_id,
+                     caps->sdvo_version_major,
+                     caps->sdvo_version_minor,
+                     caps->sdvo_inputs_mask,
+                     caps->smooth_scaling,
+                     caps->sharp_scaling,
+                     caps->up_scaling,
+                     caps->down_scaling,
+                     caps->stall_support,
+                     caps->output_flags);
+
+       return true;
 }
 
 /* No use! */
@@ -1389,22 +1288,33 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
        return (caps > 1);
 }
 
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
+{
+       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+       return drm_get_edid(connector, &sdvo->ddc);
+}
+
 static struct drm_connector *
 intel_find_analog_connector(struct drm_device *dev)
 {
        struct drm_connector *connector;
-       struct drm_encoder *encoder;
-       struct intel_sdvo *intel_sdvo;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               intel_sdvo = enc_to_intel_sdvo(encoder);
-               if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) {
-                       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                               if (encoder == intel_attached_encoder(connector))
+       struct intel_sdvo *encoder;
+
+       list_for_each_entry(encoder,
+                           &dev->mode_config.encoder_list,
+                           base.base.head) {
+               if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
+                       list_for_each_entry(connector,
+                                           &dev->mode_config.connector_list,
+                                           head) {
+                               if (&encoder->base ==
+                                   intel_attached_encoder(connector))
                                        return connector;
                        }
                }
        }
+
        return NULL;
 }
 
@@ -1424,64 +1334,72 @@ intel_analog_is_connected(struct drm_device *dev)
        return true;
 }
 
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+
+       if (!intel_analog_is_connected(connector->dev))
+               return NULL;
+
+       return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+}
+
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-       enum drm_connector_status status = connector_status_connected;
-       struct edid *edid = NULL;
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       enum drm_connector_status status;
+       struct edid *edid;
 
-       edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
+       edid = intel_sdvo_get_edid(connector);
 
-       /* This is only applied to SDVO cards with multiple outputs */
        if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
-               uint8_t saved_ddc, temp_ddc;
-               saved_ddc = intel_sdvo->ddc_bus;
-               temp_ddc = intel_sdvo->ddc_bus >> 1;
+               u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
                /*
                 * Don't use the 1 as the argument of DDC bus switch to get
                 * the EDID. It is used for SDVO SPD ROM.
                 */
-               while(temp_ddc > 1) {
-                       intel_sdvo->ddc_bus = temp_ddc;
-                       edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
-                       if (edid) {
-                               /*
-                                * When we can get the EDID, maybe it is the
-                                * correct DDC bus. Update it.
-                                */
-                               intel_sdvo->ddc_bus = temp_ddc;
+               for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+                       intel_sdvo->ddc_bus = ddc;
+                       edid = intel_sdvo_get_edid(connector);
+                       if (edid)
                                break;
-                       }
-                       temp_ddc >>= 1;
                }
+               /*
+                * If we found the EDID on the other bus,
+                * assume that is the correct DDC bus.
+                */
                if (edid == NULL)
                        intel_sdvo->ddc_bus = saved_ddc;
        }
-       /* when there is no edid and no monitor is connected with VGA
-        * port, try to use the CRT ddc to read the EDID for DVI-connector
+
+       /*
+        * When there is no edid and no monitor is connected with VGA
+        * port, try to use the CRT ddc to read the EDID for DVI-connector.
         */
-       if (edid == NULL && intel_sdvo->analog_ddc_bus &&
-           !intel_analog_is_connected(connector->dev))
-               edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
 
+       status = connector_status_unknown;
        if (edid != NULL) {
-               bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
-               bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK);
-
                /* DDC bus is shared, match EDID to connector type */
-               if (is_digital && need_digital)
+               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+                       status = connector_status_connected;
                        intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
-               else if (is_digital != need_digital)
-                       status = connector_status_disconnected;
-
+                       intel_sdvo->has_audio = drm_detect_monitor_audio(edid);
+               }
                connector->display_info.raw_edid = NULL;
-       } else
-               status = connector_status_disconnected;
-       
-       kfree(edid);
+               kfree(edid);
+       }
+
+       if (status == connector_status_connected) {
+               struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+               if (intel_sdvo_connector->force_audio)
+                       intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0;
+       }
 
        return status;
 }
@@ -1490,13 +1408,12 @@ static enum drm_connector_status
 intel_sdvo_detect(struct drm_connector *connector, bool force)
 {
        uint16_t response;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
        enum drm_connector_status ret;
 
        if (!intel_sdvo_write_cmd(intel_sdvo,
-                            SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
+                                 SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
                return connector_status_unknown;
        if (intel_sdvo->is_tv) {
                /* add 30ms delay when the output type is SDVO-TV */
@@ -1505,7 +1422,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
        if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
                return connector_status_unknown;
 
-       DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
+       DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+                     response & 0xff, response >> 8,
+                     intel_sdvo_connector->output_flag);
 
        if (response == 0)
                return connector_status_disconnected;
@@ -1538,12 +1457,10 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       int num_modes;
+       struct edid *edid;
 
        /* set the bus switch and get the modes */
-       num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+       edid = intel_sdvo_get_edid(connector);
 
        /*
         * Mac mini hack.  On this device, the DVI-I connector shares one DDC
@@ -1551,12 +1468,14 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
         * DDC fails, check to see if the analog output is disconnected, in
         * which case we'll look there for the digital DDC data.
         */
-       if (num_modes == 0 &&
-           intel_sdvo->analog_ddc_bus &&
-           !intel_analog_is_connected(connector->dev)) {
-               /* Switch to the analog ddc bus and try that
-                */
-               (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
+
+       if (edid != NULL) {
+               drm_mode_connector_update_edid_property(connector, edid);
+               drm_add_edid_modes(connector, edid);
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
        }
 }
 
@@ -1627,8 +1546,7 @@ struct drm_display_mode sdvo_tv_modes[] = {
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_sdtv_resolution_request tv_res;
        uint32_t reply = 0, format_map = 0;
        int i;
@@ -1644,7 +1562,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
                return;
 
        BUILD_BUG_ON(sizeof(tv_res) != 3);
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+       if (!intel_sdvo_write_cmd(intel_sdvo,
+                                 SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
                                  &tv_res, sizeof(tv_res)))
                return;
        if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
@@ -1662,8 +1581,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct drm_display_mode *newmode;
 
@@ -1672,7 +1590,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         * Assume that the preferred modes are
         * arranged in priority order.
         */
-       intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+       intel_ddc_get_modes(connector, intel_sdvo->i2c);
        if (list_empty(&connector->probed_modes) == false)
                goto end;
 
@@ -1693,6 +1611,10 @@ end:
                if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
                        intel_sdvo->sdvo_lvds_fixed_mode =
                                drm_mode_duplicate(connector->dev, newmode);
+
+                       drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
+                                             0);
+
                        intel_sdvo->is_lvds = true;
                        break;
                }
@@ -1775,8 +1697,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
                        uint64_t val)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
        uint16_t temp_value;
        uint8_t cmd;
@@ -1786,6 +1707,21 @@ intel_sdvo_set_property(struct drm_connector *connector,
        if (ret)
                return ret;
 
+       if (property == intel_sdvo_connector->force_audio_property) {
+               if (val == intel_sdvo_connector->force_audio)
+                       return 0;
+
+               intel_sdvo_connector->force_audio = val;
+
+               if (val > 0 && intel_sdvo->has_audio)
+                       return 0;
+               if (val < 0 && !intel_sdvo->has_audio)
+                       return 0;
+
+               intel_sdvo->has_audio = val > 0;
+               goto done;
+       }
+
 #define CHECK_PROPERTY(name, NAME) \
        if (intel_sdvo_connector->name == property) { \
                if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
@@ -1879,9 +1815,8 @@ set_value:
 
 
 done:
-       if (encoder->crtc) {
-               struct drm_crtc *crtc = encoder->crtc;
-
+       if (intel_sdvo->base.base.crtc) {
+               struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
                drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
                                         crtc->y, crtc->fb);
        }
@@ -1909,20 +1844,18 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 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_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-
-       if (intel_sdvo->analog_ddc_bus)
-               intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 
        if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
                drm_mode_destroy(encoder->dev,
                                 intel_sdvo->sdvo_lvds_fixed_mode);
 
+       i2c_del_adapter(&intel_sdvo->ddc);
        intel_encoder_destroy(encoder);
 }
 
@@ -1990,53 +1923,48 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
                intel_sdvo_guess_ddc_bus(sdvo);
 }
 
-static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+                         struct intel_sdvo *sdvo, u32 reg)
 {
-       return intel_sdvo_set_target_output(intel_sdvo,
-                                           device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) &&
-               intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
-                                    &intel_sdvo->is_hdmi, 1);
-}
+       struct sdvo_device_mapping *mapping;
+       u8 pin, speed;
 
-static struct intel_sdvo *
-intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan)
-{
-       struct drm_device *dev = chan->drm_dev;
-       struct drm_encoder *encoder;
+       if (IS_SDVOB(reg))
+               mapping = &dev_priv->sdvo_mappings[0];
+       else
+               mapping = &dev_priv->sdvo_mappings[1];
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-               if (intel_sdvo->base.ddc_bus == &chan->adapter)
-                       return intel_sdvo;
+       pin = GMBUS_PORT_DPB;
+       speed = GMBUS_RATE_1MHZ >> 8;
+       if (mapping->initialized) {
+               pin = mapping->i2c_pin;
+               speed = mapping->i2c_speed;
        }
 
-       return NULL;
+       sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+       intel_gmbus_set_speed(sdvo->i2c, speed);
+       intel_gmbus_force_bit(sdvo->i2c, true);
 }
 
-static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
-                                 struct i2c_msg msgs[], int num)
+static bool
+intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
 {
-       struct intel_sdvo *intel_sdvo;
-       struct i2c_algo_bit_data *algo_data;
-       const struct i2c_algorithm *algo;
+       int is_hdmi;
 
-       algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
-       intel_sdvo =
-               intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *)
-                                             (algo_data->data));
-       if (intel_sdvo == NULL)
-               return -EINVAL;
+       if (!intel_sdvo_check_supp_encode(intel_sdvo))
+               return false;
 
-       algo = intel_sdvo->base.i2c_bus->algo;
+       if (!intel_sdvo_set_target_output(intel_sdvo,
+                                         device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1))
+               return false;
 
-       intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus);
-       return algo->master_xfer(i2c_adap, msgs, num);
-}
+       is_hdmi = 0;
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1))
+               return false;
 
-static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
-       .master_xfer    = intel_sdvo_master_xfer,
-};
+       return !!is_hdmi;
+}
 
 static u8
 intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
@@ -2076,26 +2004,44 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
 }
 
 static void
-intel_sdvo_connector_init(struct drm_encoder *encoder,
-                         struct drm_connector *connector)
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+                         struct intel_sdvo *encoder)
 {
-       drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
-                          connector->connector_type);
+       drm_connector_init(encoder->base.base.dev,
+                          &connector->base.base,
+                          &intel_sdvo_connector_funcs,
+                          connector->base.base.connector_type);
+
+       drm_connector_helper_add(&connector->base.base,
+                                &intel_sdvo_connector_helper_funcs);
+
+       connector->base.base.interlace_allowed = 0;
+       connector->base.base.doublescan_allowed = 0;
+       connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
-       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+       intel_connector_attach_encoder(&connector->base, &encoder->base);
+       drm_sysfs_connector_add(&connector->base.base);
+}
 
-       connector->interlace_allowed = 0;
-       connector->doublescan_allowed = 0;
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+static void
+intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
+{
+       struct drm_device *dev = connector->base.base.dev;
 
-       drm_mode_connector_attach_encoder(connector, encoder);
-       drm_sysfs_connector_add(connector);
+       connector->force_audio_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+       if (connector->force_audio_property) {
+               connector->force_audio_property->values[0] = -1;
+               connector->force_audio_property->values[1] = 1;
+               drm_connector_attach_property(&connector->base.base,
+                                             connector->force_audio_property, 0);
+       }
 }
 
 static bool
 intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 {
-       struct drm_encoder *encoder = &intel_sdvo->base.enc;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
        struct drm_connector *connector;
        struct intel_connector *intel_connector;
        struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2118,19 +2064,20 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
        encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
        connector->connector_type = DRM_MODE_CONNECTOR_DVID;
 
-       if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode)
-               && intel_sdvo_get_digital_encoding_mode(intel_sdvo, device)
-               && intel_sdvo->is_hdmi) {
+       if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
                /* enable hdmi encoding mode if supported */
                intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
                intel_sdvo_set_colorimetry(intel_sdvo,
                                           SDVO_COLORIMETRY_RGB256);
                connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+               intel_sdvo->is_hdmi = true;
        }
        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
                                       (1 << INTEL_ANALOG_CLONE_BIT));
 
-       intel_sdvo_connector_init(encoder, connector);
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+
+       intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
 
        return true;
 }
@@ -2138,36 +2085,36 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 static bool
 intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
                return false;
 
        intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+       connector = &intel_connector->base;
+       encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 
-        intel_sdvo->controlled_output |= type;
-        intel_sdvo_connector->output_flag = type;
+       intel_sdvo->controlled_output |= type;
+       intel_sdvo_connector->output_flag = type;
 
-        intel_sdvo->is_tv = true;
-        intel_sdvo->base.needs_tv_clock = true;
-        intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+       intel_sdvo->is_tv = true;
+       intel_sdvo->base.needs_tv_clock = true;
+       intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
 
-        intel_sdvo_connector_init(encoder, connector);
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
 
-        if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+       if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
                goto err;
 
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
-        return true;
+       return true;
 
 err:
        intel_sdvo_destroy(connector);
@@ -2177,43 +2124,44 @@ err:
 static bool
 intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
                return false;
 
        intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
+       connector = &intel_connector->base;
        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-        encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-        }
-
-        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+       encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+       }
+
+       intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
                                       (1 << INTEL_ANALOG_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        return true;
+       intel_sdvo_connector_init(intel_sdvo_connector,
+                                 intel_sdvo);
+       return true;
 }
 
 static bool
 intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
@@ -2221,22 +2169,22 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 
        intel_connector = &intel_sdvo_connector->base;
        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-        connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-        }
-
-        intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+       encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+       connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+       }
+
+       intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
                                       (1 << INTEL_SDVO_LVDS_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
        return true;
@@ -2307,7 +2255,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
                                          struct intel_sdvo_connector *intel_sdvo_connector,
                                          int type)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct intel_sdvo_tv_format format;
        uint32_t format_map, i;
 
@@ -2373,7 +2321,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
                                      struct intel_sdvo_connector *intel_sdvo_connector,
                                      struct intel_sdvo_enhancements_reply enhancements)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_connector *connector = &intel_sdvo_connector->base.base;
        uint16_t response, data_value[2];
 
@@ -2502,7 +2450,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
                                        struct intel_sdvo_connector *intel_sdvo_connector,
                                        struct intel_sdvo_enhancements_reply enhancements)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_connector *connector = &intel_sdvo_connector->base.base;
        uint16_t response, data_value[2];
 
@@ -2535,7 +2483,43 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
                return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
        else
                return true;
+}
+
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+                                    struct i2c_msg *msgs,
+                                    int num)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
 
+       if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+               return -EIO;
+
+       return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
+
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+       .master_xfer    = intel_sdvo_ddc_proxy_xfer,
+       .functionality  = intel_sdvo_ddc_proxy_func
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+                         struct drm_device *dev)
+{
+       sdvo->ddc.owner = THIS_MODULE;
+       sdvo->ddc.class = I2C_CLASS_DDC;
+       snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+       sdvo->ddc.dev.parent = &dev->pdev->dev;
+       sdvo->ddc.algo_data = sdvo;
+       sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
+
+       return i2c_add_adapter(&sdvo->ddc) == 0;
 }
 
 bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
@@ -2543,95 +2527,66 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_sdvo *intel_sdvo;
-       u8 ch[0x40];
        int i;
-       u32 i2c_reg, ddc_reg, analog_ddc_reg;
 
        intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
        if (!intel_sdvo)
                return false;
 
+       if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
+               kfree(intel_sdvo);
+               return false;
+       }
+
        intel_sdvo->sdvo_reg = sdvo_reg;
 
        intel_encoder = &intel_sdvo->base;
        intel_encoder->type = INTEL_OUTPUT_SDVO;
+       /* encoder type will be decided later */
+       drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               i2c_reg = PCH_GPIOE;
-               ddc_reg = PCH_GPIOE;
-               analog_ddc_reg = PCH_GPIOA;
-       } else {
-               i2c_reg = GPIOE;
-               ddc_reg = GPIOE;
-               analog_ddc_reg = GPIOA;
-       }
-
-       /* setup the DDC bus. */
-       if (IS_SDVOB(sdvo_reg))
-               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
-       else
-               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
-
-       if (!intel_encoder->i2c_bus)
-               goto err_inteloutput;
-
-       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
-
-       /* Save the bit-banging i2c functionality for use by the DDC wrapper */
-       intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
+       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
 
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
-               if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
+               u8 byte;
+
+               if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
                        DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
                                      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-                       goto err_i2c;
+                       goto err;
                }
        }
 
-       /* setup the DDC bus. */
-       if (IS_SDVOB(sdvo_reg)) {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
-               intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-                                               "SDVOB/VGA DDC BUS");
+       if (IS_SDVOB(sdvo_reg))
                dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-       } else {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
-               intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-                                               "SDVOC/VGA DDC BUS");
+       else
                dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
-       }
-       if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
-               goto err_i2c;
 
-       /* Wrap with our custom algo which switches to DDC mode */
-       intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
-
-       /* encoder type will be decided later */
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-               goto err_enc;
+               goto err;
 
        if (intel_sdvo_output_setup(intel_sdvo,
                                    intel_sdvo->caps.output_flags) != true) {
                DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
                              IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-               goto err_enc;
+               goto err;
        }
 
        intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
        /* Set the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
-               goto err_enc;
+               goto err;
 
        if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
                                                    &intel_sdvo->pixel_clock_min,
                                                    &intel_sdvo->pixel_clock_max))
-               goto err_enc;
+               goto err;
 
        DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
                        "clock range %dMHz - %dMHz, "
@@ -2651,16 +2606,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
                        (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
        return true;
 
-err_enc:
-       drm_encoder_cleanup(&intel_encoder->enc);
-err_i2c:
-       if (intel_sdvo->analog_ddc_bus != NULL)
-               intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
-       if (intel_encoder->ddc_bus != NULL)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-       if (intel_encoder->i2c_bus != NULL)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
+       drm_encoder_cleanup(&intel_encoder->base);
+       i2c_del_adapter(&intel_sdvo->ddc);
        kfree(intel_sdvo);
 
        return false;
index 4a117e318a73a0a44c7ae4cc0be3447d11a403da..2f7681989316643149f2c11de896eef6936d884a 100644 (file)
@@ -48,7 +48,7 @@ struct intel_tv {
        struct intel_encoder base;
 
        int type;
-       char *tv_format;
+       const char *tv_format;
        int margin[4];
        u32 save_TV_H_CTL_1;
        u32 save_TV_H_CTL_2;
@@ -350,7 +350,7 @@ static const struct video_levels component_levels = {
 
 
 struct tv_mode {
-       char *name;
+       const char *name;
        int clock;
        int refresh; /* in millihertz (for precision) */
        u32 oversample;
@@ -900,7 +900,14 @@ static const struct tv_mode tv_modes[] = {
 
 static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base);
+       return container_of(encoder, struct intel_tv, base.base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_tv,
+                           base);
 }
 
 static void
@@ -922,7 +929,7 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode)
 }
 
 static const struct tv_mode *
-intel_tv_mode_lookup (char *tv_format)
+intel_tv_mode_lookup(const char *tv_format)
 {
        int i;
 
@@ -936,22 +943,23 @@ intel_tv_mode_lookup (char *tv_format)
 }
 
 static const struct tv_mode *
-intel_tv_mode_find (struct intel_tv *intel_tv)
+intel_tv_mode_find(struct intel_tv *intel_tv)
 {
        return intel_tv_mode_lookup(intel_tv->tv_format);
 }
 
 static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+intel_tv_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
        /* Ensure TV refresh is close to desired refresh */
        if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
                                < 1000)
                return MODE_OK;
+
        return MODE_CLOCK_RANGE;
 }
 
@@ -1131,7 +1139,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                           color_conversion->av);
        }
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                I915_WRITE(TV_CLR_KNOBS, 0x00404000);
        else
                I915_WRITE(TV_CLR_KNOBS, 0x00606000);
@@ -1157,12 +1165,12 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
 
                /* Wait for vblank for the disable to take effect */
-               if (!IS_I9XX(dev))
+               if (IS_GEN2(dev))
                        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
                /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
+               intel_wait_for_pipe_off(dev, intel_crtc->pipe);
 
                /* Filter ctl must be set before TV_WIN_SIZE */
                I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
@@ -1196,7 +1204,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                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_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
        I915_WRITE(TV_CTL, tv_ctl);
 }
 
@@ -1228,15 +1236,13 @@ static const struct drm_display_mode reported_modes[] = {
 static int
 intel_tv_detect_type (struct intel_tv *intel_tv)
 {
-       struct drm_encoder *encoder = &intel_tv->base.enc;
+       struct drm_encoder *encoder = &intel_tv->base.base;
        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);
+       int type;
 
        /* Disable TV interrupts around load detect or we'll recurse */
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
@@ -1244,19 +1250,14 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
                              PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 
-       /*
-        * Detect TV by polling)
-        */
-       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;
+       save_tv_dac = tv_dac = I915_READ(TV_DAC);
+       save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+       /* Poll for TV detection */
+       tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
        tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-       tv_dac &= ~TVDAC_SENSE_MASK;
-       tv_dac &= ~DAC_A_MASK;
-       tv_dac &= ~DAC_B_MASK;
-       tv_dac &= ~DAC_C_MASK;
+
+       tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
        tv_dac |= (TVDAC_STATE_CHG_EN |
                   TVDAC_A_SENSE_CTL |
                   TVDAC_B_SENSE_CTL |
@@ -1265,37 +1266,40 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
                   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);
        POSTING_READ(TV_DAC);
-       msleep(20);
 
-       tv_dac = I915_READ(TV_DAC);
-       I915_WRITE(TV_DAC, save_tv_dac);
-       I915_WRITE(TV_CTL, save_tv_ctl);
-       POSTING_READ(TV_CTL);
-       msleep(20);
+       intel_wait_for_vblank(intel_tv->base.base.dev,
+                             to_intel_crtc(intel_tv->base.base.crtc)->pipe);
 
-       /*
-        *  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_KMS("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_KMS("Detected S-Video TV connection\n");
-               type = DRM_MODE_CONNECTOR_SVIDEO;
-       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
-               DRM_DEBUG_KMS("Detected Component TV connection\n");
-               type = DRM_MODE_CONNECTOR_Component;
-       } else {
-               DRM_DEBUG_KMS("No TV connection detected\n");
-               type = -1;
+       type = -1;
+       if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
+               DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+               /*
+                *  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_KMS("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_KMS("Detected S-Video TV connection\n");
+                       type = DRM_MODE_CONNECTOR_SVIDEO;
+               } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+                       DRM_DEBUG_KMS("Detected Component TV connection\n");
+                       type = DRM_MODE_CONNECTOR_Component;
+               } else {
+                       DRM_DEBUG_KMS("Unrecognised TV connection\n");
+               }
        }
 
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+
        /* Restore interrupt config */
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
@@ -1311,8 +1315,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
  */
 static void intel_tv_find_better_format(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        int i;
 
@@ -1344,14 +1347,13 @@ static enum drm_connector_status
 intel_tv_detect(struct drm_connector *connector, bool force)
 {
        struct drm_display_mode mode;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        int type;
 
        mode = reported_modes[0];
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-       if (encoder->crtc && encoder->crtc->enabled) {
+       if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
                type = intel_tv_detect_type(intel_tv);
        } else if (force) {
                struct drm_crtc *crtc;
@@ -1375,11 +1377,10 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        return connector_status_connected;
 }
 
-static struct input_res {
-       char *name;
+static const struct input_res {
+       const char *name;
        int w, h;
-} input_res_table[] =
-{
+} input_res_table[] = {
        {"640x480", 640, 480},
        {"800x600", 800, 600},
        {"1024x768", 1024, 768},
@@ -1396,8 +1397,7 @@ static void
 intel_tv_chose_preferred_modes(struct drm_connector *connector,
                               struct drm_display_mode *mode_ptr)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
        if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1422,15 +1422,14 @@ static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
        struct drm_display_mode *mode_ptr;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        int j, count = 0;
        u64 tmp;
 
        for (j = 0; j < ARRAY_SIZE(input_res_table);
             j++) {
-               struct input_res *input = &input_res_table[j];
+               const struct input_res *input = &input_res_table[j];
                unsigned int hactive_s = input->w;
                unsigned int vactive_s = input->h;
 
@@ -1488,9 +1487,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
                      uint64_t val)
 {
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
-       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
+       struct drm_crtc *crtc = intel_tv->base.base.crtc;
        int ret = 0;
        bool changed = false;
 
@@ -1555,7 +1553,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
 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_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1607,7 +1605,7 @@ intel_tv_init(struct drm_device *dev)
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        u32 tv_dac_on, tv_dac_off, save_tv_dac;
-       char **tv_format_names;
+       char *tv_format_names[ARRAY_SIZE(tv_modes)];
        int i, initial_mode = 0;
 
        if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1661,15 +1659,15 @@ intel_tv_init(struct drm_device *dev)
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
                         DRM_MODE_ENCODER_TVDAC);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
        intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
-       intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
-       intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+       intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+       intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
        /* BIOS margin values */
@@ -1678,21 +1676,19 @@ intel_tv_init(struct drm_device *dev)
        intel_tv->margin[TV_MARGIN_RIGHT] = 46;
        intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
 
-       intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+       intel_tv->tv_format = tv_modes[initial_mode].name;
 
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &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 = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
-                                 GFP_KERNEL);
-       if (!tv_format_names)
-               goto out;
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
-               tv_format_names[i] = tv_modes[i].name;
-       drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
+               tv_format_names[i] = (char *)tv_modes[i].name;
+       drm_mode_create_tv_properties(dev,
+                                     ARRAY_SIZE(tv_modes),
+                                     tv_format_names);
 
        drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
                                   initial_mode);
@@ -1708,6 +1704,5 @@ intel_tv_init(struct drm_device *dev)
        drm_connector_attach_property(connector,
                                   dev->mode_config.tv_bottom_margin_property,
                                   intel_tv->margin[TV_MARGIN_BOTTOM]);
-out:
        drm_sysfs_connector_add(connector);
 }
index ac64f0b0392edb32e57a3b0da85c4185ad4efa59..0aaf5f67a43647e5cc37a903e4fb46706cb1f90f 100644 (file)
@@ -60,8 +60,6 @@ static struct drm_driver driver = {
        .irq_uninstall = mga_driver_irq_uninstall,
        .irq_handler = mga_driver_irq_handler,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = mga_ioctls,
        .dma_ioctl = mga_dma_buffers,
        .fops = {
index d2d28048efb23e1759c4368a2dbb2a64ac12675e..72730e9ca06c8e30f7f6f415c6074e60941eef18 100644 (file)
@@ -10,6 +10,7 @@ config DRM_NOUVEAU
        select FB
        select FRAMEBUFFER_CONSOLE if !EMBEDDED
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
+       select ACPI_VIDEO if ACPI
        help
          Choose this option for open-source nVidia support.
 
index e9b06e4ef2a242921bb023f69bf093eb9da68334..23fa82d667d6f060e70eba35a2834e671441c8d7 100644 (file)
@@ -9,7 +9,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
              nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
              nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
-             nouveau_dp.o \
+             nouveau_dp.o nouveau_ramht.o \
+            nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
              nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
@@ -23,7 +24,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
              nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
              nv10_gpio.o nv50_gpio.o \
-            nv50_calc.o
+            nv50_calc.o \
+            nv04_pm.o nv50_pm.o nva3_pm.o
 
 nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
index c17a055ee3e57c3a356f2fd4d3b85d4432f7d4e5..119152606e4c97af9583b451415954637d1a4d74 100644 (file)
@@ -292,6 +292,6 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
        if (ret < 0)
                return ret;
 
-       nv_connector->edid = edid;
+       nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
        return 0;
 }
index 974b0f8ae0483cc462b1be9a81795413e7a7a0c1..5f21030a293bbc3f373a76631a5e092a0075ea3f 100644 (file)
@@ -43,9 +43,6 @@
 #define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
 #define LOG_OLD_VALUE(x)
 
-#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
-#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
-
 struct init_exec {
        bool execute;
        bool repeat;
@@ -272,12 +269,6 @@ struct init_tbl_entry {
        int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
 };
 
-struct bit_entry {
-       uint8_t id[2];
-       uint16_t length;
-       uint16_t offset;
-};
-
 static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
 
 #define MACRO_INDEX_SIZE       2
@@ -1231,7 +1222,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                        return 3;
                }
 
-               if (cond & 1)
+               if (!(cond & 1))
                        iexec->execute = false;
        }
                break;
@@ -2167,11 +2158,11 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb,
 
        if (off < pci_resource_len(dev->pdev, 1)) {
                uint8_t __iomem *p =
-                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
 
                val = ioread32(p + (off & ~PAGE_MASK));
 
-               io_mapping_unmap_atomic(p, KM_USER0);
+               io_mapping_unmap_atomic(p);
        }
 
        return val;
@@ -2183,12 +2174,12 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb,
 {
        if (off < pci_resource_len(dev->pdev, 1)) {
                uint8_t __iomem *p =
-                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+                       io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
 
                iowrite32(val, p + (off & ~PAGE_MASK));
                wmb();
 
-               io_mapping_unmap_atomic(p, KM_USER0);
+               io_mapping_unmap_atomic(p);
        }
 }
 
@@ -4675,6 +4666,92 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
        return 0;
 }
 
+struct pll_mapping {
+       u8  type;
+       u32 reg;
+};
+
+static struct pll_mapping nv04_pll_mapping[] = {
+       { PLL_CORE  , NV_PRAMDAC_NVPLL_COEFF },
+       { PLL_MEMORY, NV_PRAMDAC_MPLL_COEFF },
+       { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+       { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+       {}
+};
+
+static struct pll_mapping nv40_pll_mapping[] = {
+       { PLL_CORE  , 0x004000 },
+       { PLL_MEMORY, 0x004020 },
+       { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+       { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+       {}
+};
+
+static struct pll_mapping nv50_pll_mapping[] = {
+       { PLL_CORE  , 0x004028 },
+       { PLL_SHADER, 0x004020 },
+       { PLL_UNK03 , 0x004000 },
+       { PLL_MEMORY, 0x004008 },
+       { PLL_UNK40 , 0x00e810 },
+       { PLL_UNK41 , 0x00e818 },
+       { PLL_UNK42 , 0x00e824 },
+       { PLL_VPLL0 , 0x614100 },
+       { PLL_VPLL1 , 0x614900 },
+       {}
+};
+
+static struct pll_mapping nv84_pll_mapping[] = {
+       { PLL_CORE  , 0x004028 },
+       { PLL_SHADER, 0x004020 },
+       { PLL_MEMORY, 0x004008 },
+       { PLL_UNK05 , 0x004030 },
+       { PLL_UNK41 , 0x00e818 },
+       { PLL_VPLL0 , 0x614100 },
+       { PLL_VPLL1 , 0x614900 },
+       {}
+};
+
+u32
+get_pll_register(struct drm_device *dev, enum pll_types type)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct pll_mapping *map;
+       int i;
+
+       if (dev_priv->card_type < NV_40)
+               map = nv04_pll_mapping;
+       else
+       if (dev_priv->card_type < NV_50)
+               map = nv40_pll_mapping;
+       else {
+               u8 *plim = &bios->data[bios->pll_limit_tbl_ptr];
+
+               if (plim[0] >= 0x30) {
+                       u8 *entry = plim + plim[1];
+                       for (i = 0; i < plim[3]; i++, entry += plim[2]) {
+                               if (entry[0] == type)
+                                       return ROM32(entry[3]);
+                       }
+
+                       return 0;
+               }
+
+               if (dev_priv->chipset == 0x50)
+                       map = nv50_pll_mapping;
+               else
+                       map = nv84_pll_mapping;
+       }
+
+       while (map->reg) {
+               if (map->type == type)
+                       return map->reg;
+               map++;
+       }
+
+       return 0;
+}
+
 int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim)
 {
        /*
@@ -4750,6 +4827,17 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
        /* initialize all members to zero */
        memset(pll_lim, 0, sizeof(struct pll_lims));
 
+       /* if we were passed a type rather than a register, figure
+        * out the register and store it
+        */
+       if (limit_match > PLL_MAX)
+               pll_lim->reg = limit_match;
+       else {
+               pll_lim->reg = get_pll_register(dev, limit_match);
+               if (!pll_lim->reg)
+                       return -ENOENT;
+       }
+
        if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
                uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];
 
@@ -4785,7 +4873,6 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                pll_lim->max_usable_log2p = 0x6;
        } else if (pll_lim_ver == 0x20 || pll_lim_ver == 0x21) {
                uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen;
-               uint32_t reg = 0; /* default match */
                uint8_t *pll_rec;
                int i;
 
@@ -4797,37 +4884,22 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                        NV_WARN(dev, "Default PLL limit entry has non-zero "
                                       "register field\n");
 
-               if (limit_match > MAX_PLL_TYPES)
-                       /* we've been passed a reg as the match */
-                       reg = limit_match;
-               else /* limit match is a pll type */
-                       for (i = 1; i < entries && !reg; i++) {
-                               uint32_t cmpreg = ROM32(bios->data[plloffs + recordlen * i]);
-
-                               if (limit_match == NVPLL &&
-                                   (cmpreg == NV_PRAMDAC_NVPLL_COEFF || cmpreg == 0x4000))
-                                       reg = cmpreg;
-                               if (limit_match == MPLL &&
-                                   (cmpreg == NV_PRAMDAC_MPLL_COEFF || cmpreg == 0x4020))
-                                       reg = cmpreg;
-                               if (limit_match == VPLL1 &&
-                                   (cmpreg == NV_PRAMDAC_VPLL_COEFF || cmpreg == 0x4010))
-                                       reg = cmpreg;
-                               if (limit_match == VPLL2 &&
-                                   (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018))
-                                       reg = cmpreg;
-                       }
-
                for (i = 1; i < entries; i++)
-                       if (ROM32(bios->data[plloffs + recordlen * i]) == reg) {
+                       if (ROM32(bios->data[plloffs + recordlen * i]) == pll_lim->reg) {
                                pllindex = i;
                                break;
                        }
 
+               if ((dev_priv->card_type >= NV_50) && (pllindex == 0)) {
+                       NV_ERROR(dev, "Register 0x%08x not found in PLL "
+                                "limits table", pll_lim->reg);
+                       return -ENOENT;
+               }
+
                pll_rec = &bios->data[plloffs + recordlen * pllindex];
 
                BIOSLOG(bios, "Loading PLL limits for reg 0x%08x\n",
-                       pllindex ? reg : 0);
+                       pllindex ? pll_lim->reg : 0);
 
                /*
                 * Frequencies are stored in tables in MHz, kHz are more
@@ -4877,8 +4949,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                if (cv == 0x51 && !pll_lim->refclk) {
                        uint32_t sel_clk = bios_rd32(bios, NV_PRAMDAC_SEL_CLK);
 
-                       if (((limit_match == NV_PRAMDAC_VPLL_COEFF || limit_match == VPLL1) && sel_clk & 0x20) ||
-                           ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) {
+                       if ((pll_lim->reg == NV_PRAMDAC_VPLL_COEFF && sel_clk & 0x20) ||
+                           (pll_lim->reg == NV_RAMDAC_VPLL2 && sel_clk & 0x80)) {
                                if (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_CHIP_ID_INDEX) < 0xa3)
                                        pll_lim->refclk = 200000;
                                else
@@ -4891,10 +4963,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                int i;
 
                BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-                       limit_match);
+                       pll_lim->reg);
 
                for (i = 0; i < entries; i++, entry += recordlen) {
-                       if (ROM32(entry[3]) == limit_match) {
+                       if (ROM32(entry[3]) == pll_lim->reg) {
                                record = &bios->data[ROM16(entry[1])];
                                break;
                        }
@@ -4902,7 +4974,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
 
                if (!record) {
                        NV_ERROR(dev, "Register 0x%08x not found in PLL "
-                                "limits table", limit_match);
+                                "limits table", pll_lim->reg);
                        return -ENOENT;
                }
 
@@ -4931,10 +5003,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                int i;
 
                BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-                       limit_match);
+                       pll_lim->reg);
 
                for (i = 0; i < entries; i++, entry += recordlen) {
-                       if (ROM32(entry[3]) == limit_match) {
+                       if (ROM32(entry[3]) == pll_lim->reg) {
                                record = &bios->data[ROM16(entry[1])];
                                break;
                        }
@@ -4942,7 +5014,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
 
                if (!record) {
                        NV_ERROR(dev, "Register 0x%08x not found in PLL "
-                                "limits table", limit_match);
+                                "limits table", pll_lim->reg);
                        return -ENOENT;
                }
 
@@ -5293,7 +5365,7 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
        if (bitentry->length < 0x5)
                return 0;
 
-       if (bitentry->id[1] < 2) {
+       if (bitentry->version < 2) {
                bios->ram_restrict_group_count = bios->data[bitentry->offset + 2];
                bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
        } else {
@@ -5403,27 +5475,40 @@ struct bit_table {
 
 #define BIT_TABLE(id, funcid) ((struct bit_table){ id, parse_bit_##funcid##_tbl_entry })
 
+int
+bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvbios *bios = &dev_priv->vbios;
+       u8 entries, *entry;
+
+       entries = bios->data[bios->offset + 10];
+       entry   = &bios->data[bios->offset + 12];
+       while (entries--) {
+               if (entry[0] == id) {
+                       bit->id = entry[0];
+                       bit->version = entry[1];
+                       bit->length = ROM16(entry[2]);
+                       bit->offset = ROM16(entry[4]);
+                       bit->data = ROMPTR(bios, entry[4]);
+                       return 0;
+               }
+
+               entry += bios->data[bios->offset + 9];
+       }
+
+       return -ENOENT;
+}
+
 static int
 parse_bit_table(struct nvbios *bios, const uint16_t bitoffset,
                struct bit_table *table)
 {
        struct drm_device *dev = bios->dev;
-       uint8_t maxentries = bios->data[bitoffset + 4];
-       int i, offset;
        struct bit_entry bitentry;
 
-       for (i = 0, offset = bitoffset + 6; i < maxentries; i++, offset += 6) {
-               bitentry.id[0] = bios->data[offset];
-
-               if (bitentry.id[0] != table->id)
-                       continue;
-
-               bitentry.id[1] = bios->data[offset + 1];
-               bitentry.length = ROM16(bios->data[offset + 2]);
-               bitentry.offset = ROM16(bios->data[offset + 4]);
-
+       if (bit_table(dev, table->id, &bitentry) == 0)
                return table->parse_fn(dev, bios, &bitentry);
-       }
 
        NV_INFO(dev, "BIT table '%c' not found\n", table->id);
        return -ENOSYS;
@@ -5683,8 +5768,14 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len)
 static struct dcb_gpio_entry *
 new_gpio_entry(struct nvbios *bios)
 {
+       struct drm_device *dev = bios->dev;
        struct dcb_gpio_table *gpio = &bios->dcb.gpio;
 
+       if (gpio->entries >= DCB_MAX_NUM_GPIO_ENTRIES) {
+               NV_ERROR(dev, "exceeded maximum number of gpio entries!!\n");
+               return NULL;
+       }
+
        return &gpio->entry[gpio->entries++];
 }
 
@@ -5705,114 +5796,91 @@ nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag)
        return NULL;
 }
 
-static void
-parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
-       struct dcb_gpio_entry *gpio;
-       uint16_t ent = ROM16(bios->data[offset]);
-       uint8_t line = ent & 0x1f,
-               tag = ent >> 5 & 0x3f,
-               flags = ent >> 11 & 0x1f;
-
-       if (tag == 0x3f)
-               return;
-
-       gpio = new_gpio_entry(bios);
-
-       gpio->tag = tag;
-       gpio->line = line;
-       gpio->invert = flags != 4;
-       gpio->entry = ent;
-}
-
-static void
-parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
-       uint32_t entry = ROM32(bios->data[offset]);
-       struct dcb_gpio_entry *gpio;
-
-       if ((entry & 0x0000ff00) == 0x0000ff00)
-               return;
-
-       gpio = new_gpio_entry(bios);
-       gpio->tag = (entry & 0x0000ff00) >> 8;
-       gpio->line = (entry & 0x0000001f) >> 0;
-       gpio->state_default = (entry & 0x01000000) >> 24;
-       gpio->state[0] = (entry & 0x18000000) >> 27;
-       gpio->state[1] = (entry & 0x60000000) >> 29;
-       gpio->entry = entry;
-}
-
 static void
 parse_dcb_gpio_table(struct nvbios *bios)
 {
        struct drm_device *dev = bios->dev;
-       uint16_t gpio_table_ptr = bios->dcb.gpio_table_ptr;
-       uint8_t *gpio_table = &bios->data[gpio_table_ptr];
-       int header_len = gpio_table[1],
-           entries = gpio_table[2],
-           entry_len = gpio_table[3];
-       void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
+       struct dcb_gpio_entry *e;
+       u8 headerlen, entries, recordlen;
+       u8 *dcb, *gpio = NULL, *entry;
        int i;
 
-       if (bios->dcb.version >= 0x40) {
-               if (gpio_table_ptr && entry_len != 4) {
-                       NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
-                       return;
-               }
+       dcb = ROMPTR(bios, bios->data[0x36]);
+       if (dcb[0] >= 0x30) {
+               gpio = ROMPTR(bios, dcb[10]);
+               if (!gpio)
+                       goto no_table;
 
-               parse_entry = parse_dcb40_gpio_entry;
+               headerlen = gpio[1];
+               entries   = gpio[2];
+               recordlen = gpio[3];
+       } else
+       if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) {
+               gpio = ROMPTR(bios, dcb[-15]);
+               if (!gpio)
+                       goto no_table;
+
+               headerlen = 3;
+               entries   = gpio[2];
+               recordlen = gpio[1];
+       } else
+       if (dcb[0] >= 0x22) {
+               /* No GPIO table present, parse the TVDAC GPIO data. */
+               uint8_t *tvdac_gpio = &dcb[-5];
 
-       } else if (bios->dcb.version >= 0x30) {
-               if (gpio_table_ptr && entry_len != 2) {
-                       NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
-                       return;
+               if (tvdac_gpio[0] & 1) {
+                       e = new_gpio_entry(bios);
+                       e->tag = DCB_GPIO_TVDAC0;
+                       e->line = tvdac_gpio[1] >> 4;
+                       e->invert = tvdac_gpio[0] & 2;
                }
 
-               parse_entry = parse_dcb30_gpio_entry;
-
-       } else if (bios->dcb.version >= 0x22) {
-               /*
-                * DCBs older than v3.0 don't really have a GPIO
-                * table, instead they keep some GPIO info at fixed
-                * locations.
-                */
-               uint16_t dcbptr = ROM16(bios->data[0x36]);
-               uint8_t *tvdac_gpio = &bios->data[dcbptr - 5];
+               goto no_table;
+       } else {
+               NV_DEBUG(dev, "no/unknown gpio table on DCB 0x%02x\n", dcb[0]);
+               goto no_table;
+       }
 
-               if (tvdac_gpio[0] & 1) {
-                       struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+       entry = gpio + headerlen;
+       for (i = 0; i < entries; i++, entry += recordlen) {
+               e = new_gpio_entry(bios);
+               if (!e)
+                       break;
 
-                       gpio->tag = DCB_GPIO_TVDAC0;
-                       gpio->line = tvdac_gpio[1] >> 4;
-                       gpio->invert = tvdac_gpio[0] & 2;
-               }
-       } else {
-               /*
-                * No systematic way to store GPIO info on pre-v2.2
-                * DCBs, try to match the PCI device IDs.
-                */
+               if (gpio[0] < 0x40) {
+                       e->entry = ROM16(entry[0]);
+                       e->tag = (e->entry & 0x07e0) >> 5;
+                       if (e->tag == 0x3f) {
+                               bios->dcb.gpio.entries--;
+                               continue;
+                       }
 
-               /* Apple iMac G4 NV18 */
-               if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
-                       struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+                       e->line = (e->entry & 0x001f);
+                       e->invert = ((e->entry & 0xf800) >> 11) != 4;
+               } else {
+                       e->entry = ROM32(entry[0]);
+                       e->tag = (e->entry & 0x0000ff00) >> 8;
+                       if (e->tag == 0xff) {
+                               bios->dcb.gpio.entries--;
+                               continue;
+                       }
 
-                       gpio->tag = DCB_GPIO_TVDAC0;
-                       gpio->line = 4;
+                       e->line = (e->entry & 0x0000001f) >> 0;
+                       e->state_default = (e->entry & 0x01000000) >> 24;
+                       e->state[0] = (e->entry & 0x18000000) >> 27;
+                       e->state[1] = (e->entry & 0x60000000) >> 29;
                }
-
        }
 
-       if (!gpio_table_ptr)
-               return;
-
-       if (entries > DCB_MAX_NUM_GPIO_ENTRIES) {
-               NV_WARN(dev, "Too many entries in the DCB GPIO table.\n");
-               entries = DCB_MAX_NUM_GPIO_ENTRIES;
+no_table:
+       /* Apple iMac G4 NV18 */
+       if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
+               e = new_gpio_entry(bios);
+               if (e) {
+                       e->tag = DCB_GPIO_TVDAC0;
+                       e->line = 4;
+               }
        }
-
-       for (i = 0; i < entries; i++)
-               parse_entry(bios, gpio_table_ptr + header_len + entry_len * i);
 }
 
 struct dcb_connector_table_entry *
@@ -6680,6 +6748,8 @@ static int nouveau_parse_vbios_struct(struct drm_device *dev)
                                        bit_signature, sizeof(bit_signature));
        if (offset) {
                NV_TRACE(dev, "BIT BIOS found\n");
+               bios->type = NVBIOS_BIT;
+               bios->offset = offset;
                return parse_bit_structure(bios, offset + 6);
        }
 
@@ -6687,6 +6757,8 @@ static int nouveau_parse_vbios_struct(struct drm_device *dev)
                                        bmp_signature, sizeof(bmp_signature));
        if (offset) {
                NV_TRACE(dev, "BMP BIOS found\n");
+               bios->type = NVBIOS_BMP;
+               bios->offset = offset;
                return parse_bmp_structure(dev, bios, offset);
        }
 
@@ -6806,6 +6878,8 @@ nouveau_bios_init(struct drm_device *dev)
                        "running VBIOS init tables.\n");
                bios->execute = true;
        }
+       if (nouveau_force_post)
+               bios->execute = true;
 
        ret = nouveau_run_vbios_init(dev);
        if (ret)
index c1de2f3fcb0ea7e78ec193d88c74683d5090eaba..50a648e01c499a09287b8861865cf8f32d5e196f 100644 (file)
 
 #define DCB_LOC_ON_CHIP 0
 
+#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
+#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
+#define ROMPTR(bios, x) (ROM16(x) ? &(bios)->data[ROM16(x)] : NULL)
+
+struct bit_entry {
+       uint8_t  id;
+       uint8_t  version;
+       uint16_t length;
+       uint16_t offset;
+       uint8_t *data;
+};
+
+int bit_table(struct drm_device *, u8 id, struct bit_entry *);
+
 struct dcb_i2c_entry {
        uint32_t entry;
        uint8_t port_type;
@@ -170,16 +184,28 @@ enum LVDS_script {
        LVDS_PANEL_OFF
 };
 
-/* changing these requires matching changes to reg tables in nv_get_clock */
-#define MAX_PLL_TYPES  4
+/* these match types in pll limits table version 0x40,
+ * nouveau uses them on all chipsets internally where a
+ * specific pll needs to be referenced, but the exact
+ * register isn't known.
+ */
 enum pll_types {
-       NVPLL,
-       MPLL,
-       VPLL1,
-       VPLL2
+       PLL_CORE   = 0x01,
+       PLL_SHADER = 0x02,
+       PLL_UNK03  = 0x03,
+       PLL_MEMORY = 0x04,
+       PLL_UNK05  = 0x05,
+       PLL_UNK40  = 0x40,
+       PLL_UNK41  = 0x41,
+       PLL_UNK42  = 0x42,
+       PLL_VPLL0  = 0x80,
+       PLL_VPLL1  = 0x81,
+       PLL_MAX    = 0xff
 };
 
 struct pll_lims {
+       u32 reg;
+
        struct {
                int minfreq;
                int maxfreq;
@@ -212,6 +238,11 @@ struct pll_lims {
 
 struct nvbios {
        struct drm_device *dev;
+       enum {
+               NVBIOS_BMP,
+               NVBIOS_BIT
+       } type;
+       uint16_t offset;
 
        uint8_t chip_version;
 
index f6f44779d82fb801ac738cc9e5f83e4179fd6de3..80353e2b8409fdfe34b620b54ce8fdc119af5acd 100644 (file)
 #include <linux/log2.h>
 #include <linux/slab.h>
 
-int
-nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
-{
-       struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
-       int ret;
-
-       if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
-               return 0;
-
-       spin_lock(&nvbo->bo.lock);
-       ret = ttm_bo_wait(&nvbo->bo, false, false, false);
-       spin_unlock(&nvbo->bo.lock);
-       return ret;
-}
-
 static void
 nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
 {
@@ -58,8 +43,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
        struct drm_device *dev = dev_priv->dev;
        struct nouveau_bo *nvbo = nouveau_bo(bo);
 
-       ttm_bo_kunmap(&nvbo->kmap);
-
        if (unlikely(nvbo->gem))
                DRM_ERROR("bo %p still attached to GEM object\n", bo);
 
@@ -164,8 +147,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
        align >>= PAGE_SHIFT;
 
-       nvbo->placement.fpfn = 0;
-       nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0;
        nouveau_bo_placement_set(nvbo, flags, 0);
 
        nvbo->channel = chan;
@@ -305,7 +286,8 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
 void
 nouveau_bo_unmap(struct nouveau_bo *nvbo)
 {
-       ttm_bo_kunmap(&nvbo->kmap);
+       if (nvbo)
+               ttm_bo_kunmap(&nvbo->kmap);
 }
 
 u16
@@ -399,14 +381,19 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case TTM_PL_VRAM:
+               man->func = &ttm_bo_manager_func;
                man->flags = TTM_MEMTYPE_FLAG_FIXED |
                             TTM_MEMTYPE_FLAG_MAPPABLE;
                man->available_caching = TTM_PL_FLAG_UNCACHED |
                                         TTM_PL_FLAG_WC;
                man->default_caching = TTM_PL_FLAG_WC;
-               man->gpu_offset = dev_priv->vm_vram_base;
+               if (dev_priv->card_type == NV_50)
+                       man->gpu_offset = 0x40000000;
+               else
+                       man->gpu_offset = 0;
                break;
        case TTM_PL_TT:
+               man->func = &ttm_bo_manager_func;
                switch (dev_priv->gart_info.type) {
                case NOUVEAU_GART_AGP:
                        man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -469,19 +456,26 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
        if (ret)
                return ret;
 
-       ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
-                                       evict || (nvbo->channel &&
-                                                 nvbo->channel != chan),
+       if (nvbo->channel) {
+               ret = nouveau_fence_sync(fence, nvbo->channel);
+               if (ret)
+                       goto out;
+       }
+
+       ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict,
                                        no_wait_reserve, no_wait_gpu, new_mem);
+out:
        nouveau_fence_unref((void *)&fence);
        return ret;
 }
 
 static inline uint32_t
-nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
-                     struct ttm_mem_reg *mem)
+nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
+                     struct nouveau_channel *chan, struct ttm_mem_reg *mem)
 {
-       if (chan == nouveau_bdev(nvbo->bo.bdev)->channel) {
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+       if (nvbo->no_vm) {
                if (mem->mem_type == TTM_PL_TT)
                        return NvDmaGART;
                return NvDmaVRAM;
@@ -493,86 +487,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
 }
 
 static int
-nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
-                    bool no_wait_reserve, bool no_wait_gpu,
-                    struct ttm_mem_reg *new_mem)
+nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+                 struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-       struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct nouveau_channel *chan;
-       uint64_t src_offset, dst_offset;
-       uint32_t page_count;
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+       u64 length = (new_mem->num_pages << PAGE_SHIFT);
+       u64 src_offset, dst_offset;
        int ret;
 
-       chan = nvbo->channel;
-       if (!chan || nvbo->tile_flags || nvbo->no_vm)
-               chan = dev_priv->channel;
-
-       src_offset = old_mem->mm_node->start << PAGE_SHIFT;
-       dst_offset = new_mem->mm_node->start << PAGE_SHIFT;
-       if (chan != dev_priv->channel) {
-               if (old_mem->mem_type == TTM_PL_TT)
-                       src_offset += dev_priv->vm_gart_base;
-               else
+       src_offset = old_mem->start << PAGE_SHIFT;
+       dst_offset = new_mem->start << PAGE_SHIFT;
+       if (!nvbo->no_vm) {
+               if (old_mem->mem_type == TTM_PL_VRAM)
                        src_offset += dev_priv->vm_vram_base;
-
-               if (new_mem->mem_type == TTM_PL_TT)
-                       dst_offset += dev_priv->vm_gart_base;
                else
+                       src_offset += dev_priv->vm_gart_base;
+
+               if (new_mem->mem_type == TTM_PL_VRAM)
                        dst_offset += dev_priv->vm_vram_base;
+               else
+                       dst_offset += dev_priv->vm_gart_base;
        }
 
        ret = RING_SPACE(chan, 3);
        if (ret)
                return ret;
-       BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
-       OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, old_mem));
-       OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, new_mem));
 
-       if (dev_priv->card_type >= NV_50) {
-               ret = RING_SPACE(chan, 4);
+       BEGIN_RING(chan, NvSubM2MF, 0x0184, 2);
+       OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+       OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
+       while (length) {
+               u32 amount, stride, height;
+
+               amount  = min(length, (u64)(4 * 1024 * 1024));
+               stride  = 16 * 4;
+               height  = amount / stride;
+
+               if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+                       ret = RING_SPACE(chan, 8);
+                       if (ret)
+                               return ret;
+
+                       BEGIN_RING(chan, NvSubM2MF, 0x0200, 7);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, stride);
+                       OUT_RING  (chan, height);
+                       OUT_RING  (chan, 1);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, 0);
+               } else {
+                       ret = RING_SPACE(chan, 2);
+                       if (ret)
+                               return ret;
+
+                       BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
+                       OUT_RING  (chan, 1);
+               }
+               if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+                       ret = RING_SPACE(chan, 8);
+                       if (ret)
+                               return ret;
+
+                       BEGIN_RING(chan, NvSubM2MF, 0x021c, 7);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, stride);
+                       OUT_RING  (chan, height);
+                       OUT_RING  (chan, 1);
+                       OUT_RING  (chan, 0);
+                       OUT_RING  (chan, 0);
+               } else {
+                       ret = RING_SPACE(chan, 2);
+                       if (ret)
+                               return ret;
+
+                       BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
+                       OUT_RING  (chan, 1);
+               }
+
+               ret = RING_SPACE(chan, 14);
                if (ret)
                        return ret;
-               BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
-               OUT_RING(chan, 1);
-               BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
-               OUT_RING(chan, 1);
+
+               BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
+               OUT_RING  (chan, upper_32_bits(src_offset));
+               OUT_RING  (chan, upper_32_bits(dst_offset));
+               BEGIN_RING(chan, NvSubM2MF, 0x030c, 8);
+               OUT_RING  (chan, lower_32_bits(src_offset));
+               OUT_RING  (chan, lower_32_bits(dst_offset));
+               OUT_RING  (chan, stride);
+               OUT_RING  (chan, stride);
+               OUT_RING  (chan, stride);
+               OUT_RING  (chan, height);
+               OUT_RING  (chan, 0x00000101);
+               OUT_RING  (chan, 0x00000000);
+               BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
+               OUT_RING  (chan, 0);
+
+               length -= amount;
+               src_offset += amount;
+               dst_offset += amount;
        }
 
+       return 0;
+}
+
+static int
+nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+                 struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+       u32 src_offset = old_mem->start << PAGE_SHIFT;
+       u32 dst_offset = new_mem->start << PAGE_SHIFT;
+       u32 page_count = new_mem->num_pages;
+       int ret;
+
+       ret = RING_SPACE(chan, 3);
+       if (ret)
+               return ret;
+
+       BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
+       OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+       OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
        page_count = new_mem->num_pages;
        while (page_count) {
                int line_count = (page_count > 2047) ? 2047 : page_count;
 
-               if (dev_priv->card_type >= NV_50) {
-                       ret = RING_SPACE(chan, 3);
-                       if (ret)
-                               return ret;
-                       BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
-                       OUT_RING(chan, upper_32_bits(src_offset));
-                       OUT_RING(chan, upper_32_bits(dst_offset));
-               }
                ret = RING_SPACE(chan, 11);
                if (ret)
                        return ret;
+
                BEGIN_RING(chan, NvSubM2MF,
                                 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-               OUT_RING(chan, lower_32_bits(src_offset));
-               OUT_RING(chan, lower_32_bits(dst_offset));
-               OUT_RING(chan, PAGE_SIZE); /* src_pitch */
-               OUT_RING(chan, PAGE_SIZE); /* dst_pitch */
-               OUT_RING(chan, PAGE_SIZE); /* line_length */
-               OUT_RING(chan, line_count);
-               OUT_RING(chan, (1<<8)|(1<<0));
-               OUT_RING(chan, 0);
+               OUT_RING  (chan, src_offset);
+               OUT_RING  (chan, dst_offset);
+               OUT_RING  (chan, PAGE_SIZE); /* src_pitch */
+               OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */
+               OUT_RING  (chan, PAGE_SIZE); /* line_length */
+               OUT_RING  (chan, line_count);
+               OUT_RING  (chan, 0x00000101);
+               OUT_RING  (chan, 0x00000000);
                BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
-               OUT_RING(chan, 0);
+               OUT_RING  (chan, 0);
 
                page_count -= line_count;
                src_offset += (PAGE_SIZE * line_count);
                dst_offset += (PAGE_SIZE * line_count);
        }
 
+       return 0;
+}
+
+static int
+nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
+                    bool no_wait_reserve, bool no_wait_gpu,
+                    struct ttm_mem_reg *new_mem)
+{
+       struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+       struct nouveau_channel *chan;
+       int ret;
+
+       chan = nvbo->channel;
+       if (!chan || nvbo->no_vm)
+               chan = dev_priv->channel;
+
+       if (dev_priv->card_type < NV_50)
+               ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+       else
+               ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+       if (ret)
+               return ret;
+
        return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 }
 
@@ -606,12 +695,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
 
        ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 out:
-       if (tmp_mem.mm_node) {
-               spin_lock(&bo->bdev->glob->lru_lock);
-               drm_mm_put_block(tmp_mem.mm_node);
-               spin_unlock(&bo->bdev->glob->lru_lock);
-       }
-
+       ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
 }
 
@@ -644,12 +728,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
                goto out;
 
 out:
-       if (tmp_mem.mm_node) {
-               spin_lock(&bo->bdev->glob->lru_lock);
-               drm_mm_put_block(tmp_mem.mm_node);
-               spin_unlock(&bo->bdev->glob->lru_lock);
-       }
-
+       ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
 }
 
@@ -669,7 +748,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
                return 0;
        }
 
-       offset = new_mem->mm_node->start << PAGE_SHIFT;
+       offset = new_mem->start << PAGE_SHIFT;
 
        if (dev_priv->card_type == NV_50) {
                ret = nv50_mem_vm_bind_linear(dev,
@@ -719,12 +798,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       /* Software copy if the card isn't up and running yet. */
-       if (!dev_priv->channel) {
-               ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
-               goto out;
-       }
-
        /* Fake bo copy. */
        if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
                BUG_ON(bo->mem.mm_node != NULL);
@@ -733,6 +806,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
                goto out;
        }
 
+       /* Software copy if the card isn't up and running yet. */
+       if (!dev_priv->channel) {
+               ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+               goto out;
+       }
+
        /* Hardware assisted copy. */
        if (new_mem->mem_type == TTM_PL_SYSTEM)
                ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem);
@@ -783,14 +862,14 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
        case TTM_PL_TT:
 #if __OS_HAS_AGP
                if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
-                       mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+                       mem->bus.offset = mem->start << PAGE_SHIFT;
                        mem->bus.base = dev_priv->gart_info.aper_base;
                        mem->bus.is_iomem = true;
                }
 #endif
                break;
        case TTM_PL_VRAM:
-               mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+               mem->bus.offset = mem->start << PAGE_SHIFT;
                mem->bus.base = pci_resource_start(dev->pdev, 1);
                mem->bus.is_iomem = true;
                break;
@@ -808,7 +887,26 @@ nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 static int
 nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
 {
-       return 0;
+       struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+       /* as long as the bo isn't in vram, and isn't tiled, we've got
+        * nothing to do here.
+        */
+       if (bo->mem.mem_type != TTM_PL_VRAM) {
+               if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
+                       return 0;
+       }
+
+       /* make sure bo is in mappable vram */
+       if (bo->mem.start + bo->mem.num_pages < dev_priv->fb_mappable_pages)
+               return 0;
+
+
+       nvbo->placement.fpfn = 0;
+       nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
+       nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0);
+       return ttm_bo_validate(bo, &nvbo->placement, false, true, false);
 }
 
 struct ttm_bo_driver nouveau_bo_driver = {
index ca85da78484653180ef6c03b64655df3e8117202..dad96cce5e390a77ff3de98d63658632c9603cc0 100644 (file)
@@ -198,8 +198,8 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv_fifo_info fifo_data;
        struct nv_sim_state sim_data;
-       int MClk = nouveau_hw_get_clock(dev, MPLL);
-       int NVClk = nouveau_hw_get_clock(dev, NVPLL);
+       int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY);
+       int NVClk = nouveau_hw_get_clock(dev, PLL_CORE);
        uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
 
        sim_data.pclk_khz = VClk;
@@ -234,7 +234,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
 }
 
 static void
-nv30_update_arb(int *burst, int *lwm)
+nv20_update_arb(int *burst, int *lwm)
 {
        unsigned int fifo_size, burst_size, graphics_lwm;
 
@@ -251,14 +251,14 @@ nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->card_type < NV_30)
+       if (dev_priv->card_type < NV_20)
                nv04_update_arb(dev, vclk, bpp, burst, lwm);
        else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
                 (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
                *burst = 128;
                *lwm = 0x0480;
        } else
-               nv30_update_arb(burst, lwm);
+               nv20_update_arb(burst, lwm);
 }
 
 static int
index 0480f064f2c14fd8c4bf41672fa039f9f2bc9029..373950e3481474e72cdc19c7fb858adf3cd8190c 100644 (file)
@@ -48,14 +48,14 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
                                                  dev_priv->gart_info.aper_size,
                                                  NV_DMA_ACCESS_RO, &pushbuf,
                                                  NULL);
-               chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+               chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
        } else
        if (dev_priv->card_type != NV_04) {
                ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
                                             dev_priv->fb_available_size,
                                             NV_DMA_ACCESS_RO,
                                             NV_DMA_TARGET_VIDMEM, &pushbuf);
-               chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+               chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
        } else {
                /* NV04 cmdbuf hack, from original ddx.. not sure of it's
                 * exact reason for existing :)  PCI access to cmdbuf in
@@ -67,17 +67,11 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
                                             dev_priv->fb_available_size,
                                             NV_DMA_ACCESS_RO,
                                             NV_DMA_TARGET_PCI, &pushbuf);
-               chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
-       }
-
-       ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
-       if (ret) {
-               NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret);
-               if (pushbuf != dev_priv->gart_info.sg_ctxdma)
-                       nouveau_gpuobj_del(dev, &pushbuf);
-               return ret;
+               chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
        }
 
+       nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
+       nouveau_gpuobj_ref(NULL, &pushbuf);
        return 0;
 }
 
@@ -229,7 +223,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
 
        ret = nouveau_dma_init(chan);
        if (!ret)
-               ret = nouveau_fence_init(chan);
+               ret = nouveau_fence_channel_init(chan);
        if (ret) {
                nouveau_channel_free(chan);
                return ret;
@@ -276,7 +270,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
         * above attempts at idling were OK, but if we failed this'll tell TTM
         * we're done with the buffers.
         */
-       nouveau_fence_fini(chan);
+       nouveau_fence_channel_fini(chan);
 
        /* This will prevent pfifo from switching channels. */
        pfifo->reassign(dev, false);
@@ -308,8 +302,9 @@ nouveau_channel_free(struct nouveau_channel *chan)
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Release the channel's resources */
-       nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
+       nouveau_gpuobj_ref(NULL, &chan->pushbuf);
        if (chan->pushbuf_bo) {
+               nouveau_bo_unmap(chan->pushbuf_bo);
                nouveau_bo_unpin(chan->pushbuf_bo);
                nouveau_bo_ref(NULL, &chan->pushbuf_bo);
        }
index fc737037f751c3690dfb09239e3439df1fa4191c..0871495096fa86f1278f825c8420f8e14f1e6b38 100644 (file)
@@ -76,6 +76,22 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder)
        return NULL;
 }
 
+/*TODO: This could use improvement, and learn to handle the fixed
+ *      BIOS tables etc.  It's fine currently, for its only user.
+ */
+int
+nouveau_connector_bpp(struct drm_connector *connector)
+{
+       struct nouveau_connector *nv_connector = nouveau_connector(connector);
+
+       if (nv_connector->edid && nv_connector->edid->revision >= 4) {
+               u8 bpc = ((nv_connector->edid->input & 0x70) >> 3) + 4;
+               if (bpc > 4)
+                       return bpc;
+       }
+
+       return 18;
+}
 
 static void
 nouveau_connector_destroy(struct drm_connector *drm_connector)
@@ -130,6 +146,36 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
        return NULL;
 }
 
+static struct nouveau_encoder *
+nouveau_connector_of_detect(struct drm_connector *connector)
+{
+#ifdef __powerpc__
+       struct drm_device *dev = connector->dev;
+       struct nouveau_connector *nv_connector = nouveau_connector(connector);
+       struct nouveau_encoder *nv_encoder;
+       struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
+
+       if (!dn ||
+           !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) ||
+             (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG))))
+               return NULL;
+
+       for_each_child_of_node(dn, cn) {
+               const char *name = of_get_property(cn, "name", NULL);
+               const void *edid = of_get_property(cn, "EDID", NULL);
+               int idx = name ? name[strlen(name) - 1] - 'A' : 0;
+
+               if (nv_encoder->dcb->i2c_index == idx && edid) {
+                       nv_connector->edid =
+                               kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
+                       of_node_put(cn);
+                       return nv_encoder;
+               }
+       }
+#endif
+       return NULL;
+}
+
 static void
 nouveau_connector_set_encoder(struct drm_connector *connector,
                              struct nouveau_encoder *nv_encoder)
@@ -225,6 +271,12 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
                return connector_status_connected;
        }
 
+       nv_encoder = nouveau_connector_of_detect(connector);
+       if (nv_encoder) {
+               nouveau_connector_set_encoder(connector, nv_encoder);
+               return connector_status_connected;
+       }
+
 detect_analog:
        nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
        if (!nv_encoder && !nouveau_tv_disable)
@@ -630,7 +682,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
                else
                        max_clock = nv_encoder->dp.link_nr * 162000;
 
-               clock *= 3;
+               clock = clock * nouveau_connector_bpp(connector) / 8;
                break;
        default:
                BUG_ON(1);
index 0d2e668ccfe5c52525117ca83a9e3791e0fef936..c21ed6b16f88d41aebdee888997c12a7249fdd03 100644 (file)
@@ -55,4 +55,7 @@ nouveau_connector_create(struct drm_device *, int index);
 void
 nouveau_connector_set_polling(struct drm_connector *);
 
+int
+nouveau_connector_bpp(struct drm_connector *);
+
 #endif /* __NOUVEAU_CONNECTOR_H__ */
index 7933de4aff2ed23745332ca1aeaab7ece4a22fde..8e1592368cce1985d3270f934473a58fb73f6a33 100644 (file)
@@ -157,7 +157,23 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
        return 0;
 }
 
+static int
+nouveau_debugfs_evict_vram(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
+       int ret;
+
+       ret = ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
+       if (ret)
+               seq_printf(m, "failed: %d", ret);
+       else
+               seq_printf(m, "succeeded\n");
+       return 0;
+}
+
 static struct drm_info_list nouveau_debugfs_list[] = {
+       { "evict_vram", nouveau_debugfs_evict_vram, 0, NULL },
        { "chipset", nouveau_debugfs_chipset_info, 0, NULL },
        { "memory", nouveau_debugfs_memory_info, 0, NULL },
        { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
index 2e3c6caa97eeefb70eda2b06f633aae520c19ceb..82581e600dcdea09c9b4d7ccf7ee7c0273506cb7 100644 (file)
@@ -28,6 +28,7 @@
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 
 void
 nouveau_dma_pre_init(struct nouveau_channel *chan)
@@ -58,26 +59,17 @@ nouveau_dma_init(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *m2mf = NULL;
-       struct nouveau_gpuobj *nvsw = NULL;
+       struct nouveau_gpuobj *obj = NULL;
        int ret, i;
 
        /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
        ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
-                                   0x0039 : 0x5039, &m2mf);
+                                   0x0039 : 0x5039, &obj);
        if (ret)
                return ret;
 
-       ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
-       if (ret)
-               return ret;
-
-       /* Create an NV_SW object for various sync purposes */
-       ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
-       if (ret)
-               return ret;
-
-       ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
+       ret = nouveau_ramht_insert(chan, NvM2MF, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
        if (ret)
                return ret;
 
@@ -91,11 +83,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
        if (ret)
                return ret;
 
-       /* Map M2MF notifier object - fbcon. */
-       ret = nouveau_bo_map(chan->notifier_bo);
-       if (ret)
-               return ret;
-
        /* Insert NOPS for NOUVEAU_DMA_SKIPS */
        ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
        if (ret)
@@ -113,13 +100,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
        BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
        OUT_RING(chan, NvNotify0);
 
-       /* Initialise NV_SW */
-       ret = RING_SPACE(chan, 2);
-       if (ret)
-               return ret;
-       BEGIN_RING(chan, NvSubSw, 0, 1);
-       OUT_RING(chan, NvSw);
-
        /* Sit back and pray the channel works.. */
        FIRE_RING(chan);
 
@@ -217,7 +197,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count)
 
                chan->dma.ib_free = get - chan->dma.ib_put;
                if (chan->dma.ib_free <= 0)
-                       chan->dma.ib_free += chan->dma.ib_max + 1;
+                       chan->dma.ib_free += chan->dma.ib_max;
        }
 
        return 0;
index 8b05c15866d5b9ad83bc52f78378944f90412fe9..d578c21d3c8d7f9e42d7dd079eba74b26e355cd1 100644 (file)
@@ -72,6 +72,7 @@ enum {
        NvGdiRect       = 0x8000000c,
        NvImageBlit     = 0x8000000d,
        NvSw            = 0x8000000e,
+       NvSema          = 0x8000000f,
 
        /* G80+ display objects */
        NvEvoVRAM       = 0x01000000,
index 8a1b188b4cd13bcdff20d41484cd120618216293..4562f309ae3db87852021061a583b27886592c52 100644 (file)
@@ -317,7 +317,8 @@ train:
                return false;
 
        config[0] = nv_encoder->dp.link_nr;
-       if (nv_encoder->dp.dpcd_version >= 0x11)
+       if (nv_encoder->dp.dpcd_version >= 0x11 &&
+           nv_encoder->dp.enhanced_frame)
                config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 
        ret = nouveau_dp_lane_count_set(encoder, config[0]);
@@ -468,10 +469,12 @@ nouveau_dp_detect(struct drm_encoder *encoder)
            !nv_encoder->dcb->dpconf.link_bw)
                nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
 
-       nv_encoder->dp.link_nr = dpcd[2] & 0xf;
+       nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
        if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr)
                nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
 
+       nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP);
+
        return true;
 }
 
@@ -524,7 +527,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000);
-               if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
+               if (!nv_wait(dev, NV50_AUXCH_CTRL(index),
+                            0x00010000, 0x00000000)) {
                        NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
                                 nv_rd32(dev, NV50_AUXCH_CTRL(index)));
                        ret = -EBUSY;
index eb15345162a03af66a556ccd6f083907261abd90..90875494a65ab160933f4aebc8a4c00209792585 100644 (file)
 #include "nouveau_hw.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_pm.h"
 #include "nv50_display.h"
 
 #include "drm_pciids.h"
 
-MODULE_PARM_DESC(noagp, "Disable AGP");
-int nouveau_noagp;
-module_param_named(noagp, nouveau_noagp, int, 0400);
+MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
+int nouveau_agpmode = -1;
+module_param_named(agpmode, nouveau_agpmode, int, 0400);
 
 MODULE_PARM_DESC(modeset, "Enable kernel modesetting");
 static int nouveau_modeset = -1; /* kms */
@@ -79,6 +80,10 @@ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
 int nouveau_nofbaccel = 0;
 module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 
+MODULE_PARM_DESC(force_post, "Force POST");
+int nouveau_force_post = 0;
+module_param_named(force_post, nouveau_force_post, int, 0400);
+
 MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
 int nouveau_override_conntype = 0;
 module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
@@ -102,6 +107,14 @@ MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
 int nouveau_reg_debug;
 module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
 
+MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
+char *nouveau_perflvl;
+module_param_named(perflvl, nouveau_perflvl, charp, 0400);
+
+MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
+int nouveau_perflvl_wr;
+module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
+
 int nouveau_fbpercrtc;
 #if 0
 module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
@@ -271,6 +284,8 @@ nouveau_pci_resume(struct pci_dev *pdev)
        if (ret)
                return ret;
 
+       nouveau_pm_resume(dev);
+
        if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
                ret = nouveau_mem_init_agp(dev);
                if (ret) {
@@ -379,8 +394,6 @@ static struct drm_driver driver = {
        .irq_uninstall = nouveau_irq_uninstall,
        .irq_handler = nouveau_irq_handler,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = nouveau_ioctls,
        .fops = {
                .owner = THIS_MODULE,
index b1be617373b63891dc05b09f2dc75807cd8b8472..3a07e580d27af548fe2fd247b4e7df4c67994956 100644 (file)
@@ -133,22 +133,24 @@ enum nouveau_flags {
 #define NVOBJ_ENGINE_DISPLAY   2
 #define NVOBJ_ENGINE_INT       0xdeadbeef
 
-#define NVOBJ_FLAG_ALLOW_NO_REFS       (1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC          (1 << 1)
 #define NVOBJ_FLAG_ZERO_FREE           (1 << 2)
-#define NVOBJ_FLAG_FAKE                        (1 << 3)
 struct nouveau_gpuobj {
+       struct drm_device *dev;
+       struct kref refcount;
        struct list_head list;
 
-       struct nouveau_channel *im_channel;
        struct drm_mm_node *im_pramin;
        struct nouveau_bo *im_backing;
-       uint32_t im_backing_start;
        uint32_t *im_backing_suspend;
        int im_bound;
 
        uint32_t flags;
-       int refcount;
+
+       u32 size;
+       u32 pinst;
+       u32 cinst;
+       u64 vinst;
 
        uint32_t engine;
        uint32_t class;
@@ -157,16 +159,6 @@ struct nouveau_gpuobj {
        void *priv;
 };
 
-struct nouveau_gpuobj_ref {
-       struct list_head list;
-
-       struct nouveau_gpuobj *gpuobj;
-       uint32_t instance;
-
-       struct nouveau_channel *channel;
-       int handle;
-};
-
 struct nouveau_channel {
        struct drm_device *dev;
        int id;
@@ -192,33 +184,32 @@ struct nouveau_channel {
        } fence;
 
        /* DMA push buffer */
-       struct nouveau_gpuobj_ref *pushbuf;
-       struct nouveau_bo         *pushbuf_bo;
-       uint32_t                   pushbuf_base;
+       struct nouveau_gpuobj *pushbuf;
+       struct nouveau_bo     *pushbuf_bo;
+       uint32_t               pushbuf_base;
 
        /* Notifier memory */
        struct nouveau_bo *notifier_bo;
        struct drm_mm notifier_heap;
 
        /* PFIFO context */
-       struct nouveau_gpuobj_ref *ramfc;
-       struct nouveau_gpuobj_ref *cache;
+       struct nouveau_gpuobj *ramfc;
+       struct nouveau_gpuobj *cache;
 
        /* PGRAPH context */
        /* XXX may be merge 2 pointers as private data ??? */
-       struct nouveau_gpuobj_ref *ramin_grctx;
+       struct nouveau_gpuobj *ramin_grctx;
        void *pgraph_ctx;
 
        /* NV50 VM */
-       struct nouveau_gpuobj     *vm_pd;
-       struct nouveau_gpuobj_ref *vm_gart_pt;
-       struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR];
+       struct nouveau_gpuobj *vm_pd;
+       struct nouveau_gpuobj *vm_gart_pt;
+       struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
 
        /* Objects */
-       struct nouveau_gpuobj_ref *ramin; /* Private instmem */
-       struct drm_mm              ramin_heap; /* Private PRAMIN heap */
-       struct nouveau_gpuobj_ref *ramht; /* Hash table */
-       struct list_head           ramht_refs; /* Objects referenced by RAMHT */
+       struct nouveau_gpuobj *ramin; /* Private instmem */
+       struct drm_mm          ramin_heap; /* Private PRAMIN heap */
+       struct nouveau_ramht  *ramht; /* Hash table */
 
        /* GPU object info for stuff used in-kernel (mm_enabled) */
        uint32_t m2mf_ntfy;
@@ -296,7 +287,7 @@ struct nouveau_fb_engine {
 struct nouveau_fifo_engine {
        int  channels;
 
-       struct nouveau_gpuobj_ref *playlist[2];
+       struct nouveau_gpuobj *playlist[2];
        int cur_playlist;
 
        int  (*init)(struct drm_device *);
@@ -305,7 +296,6 @@ struct nouveau_fifo_engine {
        void (*disable)(struct drm_device *);
        void (*enable)(struct drm_device *);
        bool (*reassign)(struct drm_device *, bool enable);
-       bool (*cache_flush)(struct drm_device *dev);
        bool (*cache_pull)(struct drm_device *dev, bool enable);
 
        int  (*channel_id)(struct drm_device *);
@@ -334,7 +324,7 @@ struct nouveau_pgraph_engine {
        int grctx_size;
 
        /* NV2x/NV3x context table (0x400780) */
-       struct nouveau_gpuobj_ref *ctx_table;
+       struct nouveau_gpuobj *ctx_table;
 
        int  (*init)(struct drm_device *);
        void (*takedown)(struct drm_device *);
@@ -369,6 +359,91 @@ struct nouveau_gpio_engine {
        void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
 };
 
+struct nouveau_pm_voltage_level {
+       u8 voltage;
+       u8 vid;
+};
+
+struct nouveau_pm_voltage {
+       bool supported;
+       u8 vid_mask;
+
+       struct nouveau_pm_voltage_level *level;
+       int nr_level;
+};
+
+#define NOUVEAU_PM_MAX_LEVEL 8
+struct nouveau_pm_level {
+       struct device_attribute dev_attr;
+       char name[32];
+       int id;
+
+       u32 core;
+       u32 memory;
+       u32 shader;
+       u32 unk05;
+
+       u8 voltage;
+       u8 fanspeed;
+
+       u16 memscript;
+};
+
+struct nouveau_pm_temp_sensor_constants {
+       u16 offset_constant;
+       s16 offset_mult;
+       u16 offset_div;
+       u16 slope_mult;
+       u16 slope_div;
+};
+
+struct nouveau_pm_threshold_temp {
+       s16 critical;
+       s16 down_clock;
+       s16 fan_boost;
+};
+
+struct nouveau_pm_memtiming {
+       u32 reg_100220;
+       u32 reg_100224;
+       u32 reg_100228;
+       u32 reg_10022c;
+       u32 reg_100230;
+       u32 reg_100234;
+       u32 reg_100238;
+       u32 reg_10023c;
+};
+
+struct nouveau_pm_memtimings {
+       bool supported;
+       struct nouveau_pm_memtiming *timing;
+       int nr_timing;
+};
+
+struct nouveau_pm_engine {
+       struct nouveau_pm_voltage voltage;
+       struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
+       int nr_perflvl;
+       struct nouveau_pm_memtimings memtimings;
+       struct nouveau_pm_temp_sensor_constants sensor_constants;
+       struct nouveau_pm_threshold_temp threshold_temp;
+
+       struct nouveau_pm_level boot;
+       struct nouveau_pm_level *cur;
+
+       struct device *hwmon;
+
+       int (*clock_get)(struct drm_device *, u32 id);
+       void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *,
+                          u32 id, int khz);
+       void (*clock_set)(struct drm_device *, void *);
+       int (*voltage_get)(struct drm_device *);
+       int (*voltage_set)(struct drm_device *, int voltage);
+       int (*fanspeed_get)(struct drm_device *);
+       int (*fanspeed_set)(struct drm_device *, int fanspeed);
+       int (*temp_get)(struct drm_device *);
+};
+
 struct nouveau_engine {
        struct nouveau_instmem_engine instmem;
        struct nouveau_mc_engine      mc;
@@ -378,6 +453,7 @@ struct nouveau_engine {
        struct nouveau_fifo_engine    fifo;
        struct nouveau_display_engine display;
        struct nouveau_gpio_engine    gpio;
+       struct nouveau_pm_engine      pm;
 };
 
 struct nouveau_pll_vals {
@@ -522,8 +598,14 @@ struct drm_nouveau_private {
        int flags;
 
        void __iomem *mmio;
+
+       spinlock_t ramin_lock;
        void __iomem *ramin;
-       uint32_t ramin_size;
+       u32 ramin_size;
+       u32 ramin_base;
+       bool ramin_available;
+       struct drm_mm ramin_heap;
+       struct list_head gpuobj_list;
 
        struct nouveau_bo *vga_ram;
 
@@ -540,6 +622,12 @@ struct drm_nouveau_private {
                atomic_t validate_sequence;
        } ttm;
 
+       struct {
+               spinlock_t lock;
+               struct drm_mm heap;
+               struct nouveau_bo *bo;
+       } fence;
+
        int fifo_alloc_count;
        struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
 
@@ -550,15 +638,11 @@ struct drm_nouveau_private {
        spinlock_t context_switch_lock;
 
        /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
-       struct nouveau_gpuobj *ramht;
+       struct nouveau_ramht  *ramht;
+       struct nouveau_gpuobj *ramfc;
+       struct nouveau_gpuobj *ramro;
+
        uint32_t ramin_rsvd_vram;
-       uint32_t ramht_offset;
-       uint32_t ramht_size;
-       uint32_t ramht_bits;
-       uint32_t ramfc_offset;
-       uint32_t ramfc_size;
-       uint32_t ramro_offset;
-       uint32_t ramro_size;
 
        struct {
                enum {
@@ -576,14 +660,12 @@ struct drm_nouveau_private {
        } gart_info;
 
        /* nv10-nv40 tiling regions */
-       struct {
-               struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
-               spinlock_t lock;
-       } tile;
+       struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR];
 
        /* VRAM/fb configuration */
        uint64_t vram_size;
        uint64_t vram_sys_base;
+       u32 vram_rblock_size;
 
        uint64_t fb_phys;
        uint64_t fb_available_size;
@@ -600,10 +682,6 @@ struct drm_nouveau_private {
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
 
-       struct drm_mm ramin_heap;
-
-       struct list_head gpuobj_list;
-
        struct nvbios vbios;
 
        struct nv04_mode_state mode_reg;
@@ -633,6 +711,12 @@ struct drm_nouveau_private {
        struct apertures_struct *apertures;
 };
 
+static inline struct drm_nouveau_private *
+nouveau_private(struct drm_device *dev)
+{
+       return dev->dev_private;
+}
+
 static inline struct drm_nouveau_private *
 nouveau_bdev(struct ttm_bo_device *bd)
 {
@@ -669,7 +753,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
 } while (0)
 
 /* nouveau_drv.c */
-extern int nouveau_noagp;
+extern int nouveau_agpmode;
 extern int nouveau_duallink;
 extern int nouveau_uscript_lvds;
 extern int nouveau_uscript_tmds;
@@ -683,7 +767,10 @@ extern char *nouveau_vbios;
 extern int nouveau_ignorelid;
 extern int nouveau_nofbaccel;
 extern int nouveau_noaccel;
+extern int nouveau_force_post;
 extern int nouveau_override_conntype;
+extern char *nouveau_perflvl;
+extern int nouveau_perflvl_wr;
 
 extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
 extern int nouveau_pci_resume(struct pci_dev *pdev);
@@ -704,8 +791,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
 extern int  nouveau_card_init(struct drm_device *);
 
 /* nouveau_mem.c */
-extern int  nouveau_mem_detect(struct drm_device *dev);
-extern int  nouveau_mem_init(struct drm_device *);
+extern int  nouveau_mem_vram_init(struct drm_device *);
+extern void nouveau_mem_vram_fini(struct drm_device *);
+extern int  nouveau_mem_gart_init(struct drm_device *);
+extern void nouveau_mem_gart_fini(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
 extern int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
@@ -749,7 +838,6 @@ extern void nouveau_channel_free(struct nouveau_channel *);
 extern int  nouveau_gpuobj_early_init(struct drm_device *);
 extern int  nouveau_gpuobj_init(struct drm_device *);
 extern void nouveau_gpuobj_takedown(struct drm_device *);
-extern void nouveau_gpuobj_late_takedown(struct drm_device *);
 extern int  nouveau_gpuobj_suspend(struct drm_device *dev);
 extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev);
 extern void nouveau_gpuobj_resume(struct drm_device *dev);
@@ -759,24 +847,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
 extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *,
                              uint32_t size, int align, uint32_t flags,
                              struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
-                                 uint32_t handle, struct nouveau_gpuobj *,
-                                 struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_del(struct drm_device *,
-                                 struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
-                                  struct nouveau_gpuobj_ref **ref_ret);
-extern int nouveau_gpuobj_new_ref(struct drm_device *,
-                                 struct nouveau_channel *alloc_chan,
-                                 struct nouveau_channel *ref_chan,
-                                 uint32_t handle, uint32_t size, int align,
-                                 uint32_t flags, struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_new_fake(struct drm_device *,
-                                  uint32_t p_offset, uint32_t b_offset,
-                                  uint32_t size, uint32_t flags,
-                                  struct nouveau_gpuobj **,
-                                  struct nouveau_gpuobj_ref**);
+extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *,
+                              struct nouveau_gpuobj **);
+extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
+                                  u32 size, u32 flags,
+                                  struct nouveau_gpuobj **);
 extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
                                  uint64_t offset, uint64_t size, int access,
                                  int target, struct nouveau_gpuobj **);
@@ -879,6 +954,7 @@ extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *,
                                                      enum dcb_gpio_tag);
 extern struct dcb_connector_table_entry *
 nouveau_bios_connector_entry(struct drm_device *, int index);
+extern u32 get_pll_register(struct drm_device *, enum pll_types);
 extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
                          struct pll_lims *);
 extern int nouveau_bios_run_display_table(struct drm_device *,
@@ -925,10 +1001,10 @@ extern int  nv40_fb_init(struct drm_device *);
 extern void nv40_fb_takedown(struct drm_device *);
 extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
                                      uint32_t, uint32_t);
-
 /* nv50_fb.c */
 extern int  nv50_fb_init(struct drm_device *);
 extern void nv50_fb_takedown(struct drm_device *);
+extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *);
 
 /* nvc0_fb.c */
 extern int  nvc0_fb_init(struct drm_device *);
@@ -939,7 +1015,6 @@ extern int  nv04_fifo_init(struct drm_device *);
 extern void nv04_fifo_disable(struct drm_device *);
 extern void nv04_fifo_enable(struct drm_device *);
 extern bool nv04_fifo_reassign(struct drm_device *, bool);
-extern bool nv04_fifo_cache_flush(struct drm_device *);
 extern bool nv04_fifo_cache_pull(struct drm_device *, bool);
 extern int  nv04_fifo_channel_id(struct drm_device *);
 extern int  nv04_fifo_create_context(struct nouveau_channel *);
@@ -977,7 +1052,6 @@ extern void nvc0_fifo_takedown(struct drm_device *);
 extern void nvc0_fifo_disable(struct drm_device *);
 extern void nvc0_fifo_enable(struct drm_device *);
 extern bool nvc0_fifo_reassign(struct drm_device *, bool);
-extern bool nvc0_fifo_cache_flush(struct drm_device *);
 extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
 extern int  nvc0_fifo_channel_id(struct drm_device *);
 extern int  nvc0_fifo_create_context(struct nouveau_channel *);
@@ -1169,15 +1243,21 @@ extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
 
 /* nouveau_fence.c */
 struct nouveau_fence;
-extern int nouveau_fence_init(struct nouveau_channel *);
-extern void nouveau_fence_fini(struct nouveau_channel *);
+extern int nouveau_fence_init(struct drm_device *);
+extern void nouveau_fence_fini(struct drm_device *);
+extern int nouveau_fence_channel_init(struct nouveau_channel *);
+extern void nouveau_fence_channel_fini(struct nouveau_channel *);
 extern void nouveau_fence_update(struct nouveau_channel *);
 extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **,
                             bool emit);
 extern int nouveau_fence_emit(struct nouveau_fence *);
+extern void nouveau_fence_work(struct nouveau_fence *fence,
+                              void (*work)(void *priv, bool signalled),
+                              void *priv);
 struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
 extern bool nouveau_fence_signalled(void *obj, void *arg);
 extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
 extern int nouveau_fence_flush(void *obj, void *arg);
 extern void nouveau_fence_unref(void **obj);
 extern void *nouveau_fence_ref(void *obj);
@@ -1255,12 +1335,11 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
        iowrite32_native(val, dev_priv->mmio + reg);
 }
 
-static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
+static inline u32 nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
 {
        u32 tmp = nv_rd32(dev, reg);
-       tmp &= ~mask;
-       tmp |= val;
-       nv_wr32(dev, reg, tmp);
+       nv_wr32(dev, reg, (tmp & ~mask) | val);
+       return tmp;
 }
 
 static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
@@ -1275,7 +1354,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val)
        iowrite8(val, dev_priv->mmio + reg);
 }
 
-#define nv_wait(reg, mask, val) \
+#define nv_wait(dev, reg, mask, val) \
        nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val))
 
 /* PRAMIN access */
@@ -1292,17 +1371,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val)
 }
 
 /* object access */
-static inline u32 nv_ro32(struct drm_device *dev, struct nouveau_gpuobj *obj,
-                               unsigned index)
-{
-       return nv_ri32(dev, obj->im_pramin->start + index * 4);
-}
-
-static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj,
-                               unsigned index, u32 val)
-{
-       nv_wi32(dev, obj->im_pramin->start + index * 4, val);
-}
+extern u32 nv_ro32(struct nouveau_gpuobj *, u32 offset);
+extern void nv_wo32(struct nouveau_gpuobj *, u32 offset, u32 val);
 
 /*
  * Logging
@@ -1403,6 +1473,7 @@ nv_match_device(struct drm_device *dev, unsigned device,
 #define NV_SW_SEMAPHORE_OFFSET                                       0x00000064
 #define NV_SW_SEMAPHORE_ACQUIRE                                      0x00000068
 #define NV_SW_SEMAPHORE_RELEASE                                      0x0000006c
+#define NV_SW_YIELD                                                  0x00000080
 #define NV_SW_DMA_VBLSEM                                             0x0000018c
 #define NV_SW_VBLSEM_OFFSET                                          0x00000400
 #define NV_SW_VBLSEM_RELEASE_VALUE                                   0x00000404
index 7c82d68bc155d7d8a738d206a1c795b79849cc05..ae69b61d93dbbd2b3e0caf052b4faae4070c5505 100644 (file)
@@ -55,6 +55,7 @@ struct nouveau_encoder {
                        int dpcd_version;
                        int link_nr;
                        int link_bw;
+                       bool enhanced_frame;
                } dp;
        };
 };
index dbd30b2e43fd13b39aaa59eb0abc4fb0332bd1ee..02a4d1fd484560efe66f6262f140b3983f3e6241 100644 (file)
@@ -104,6 +104,8 @@ static struct fb_ops nouveau_fbcon_ops = {
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static struct fb_ops nv04_fbcon_ops = {
@@ -117,6 +119,8 @@ static struct fb_ops nv04_fbcon_ops = {
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static struct fb_ops nv50_fbcon_ops = {
@@ -130,6 +134,8 @@ static struct fb_ops nv50_fbcon_ops = {
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
index 87ac21ec23d290db82e90c6fe6257e4cffdb5955..441b12420bb1b713fb56b98edad389d31fe367ea 100644 (file)
 #include "drm.h"
 
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 #include "nouveau_dma.h"
 
-#define USE_REFCNT (dev_priv->card_type >= NV_10)
+#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
 
 struct nouveau_fence {
        struct nouveau_channel *channel;
@@ -39,6 +41,15 @@ struct nouveau_fence {
 
        uint32_t sequence;
        bool signalled;
+
+       void (*work)(void *priv, bool signalled);
+       void *priv;
+};
+
+struct nouveau_semaphore {
+       struct kref ref;
+       struct drm_device *dev;
+       struct drm_mm_node *mem;
 };
 
 static inline struct nouveau_fence *
@@ -59,14 +70,13 @@ nouveau_fence_del(struct kref *ref)
 void
 nouveau_fence_update(struct nouveau_channel *chan)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct list_head *entry, *tmp;
-       struct nouveau_fence *fence;
+       struct drm_device *dev = chan->dev;
+       struct nouveau_fence *tmp, *fence;
        uint32_t sequence;
 
        spin_lock(&chan->fence.lock);
 
-       if (USE_REFCNT)
+       if (USE_REFCNT(dev))
                sequence = nvchan_rd32(chan, 0x48);
        else
                sequence = atomic_read(&chan->fence.last_sequence_irq);
@@ -75,12 +85,14 @@ nouveau_fence_update(struct nouveau_channel *chan)
                goto out;
        chan->fence.sequence_ack = sequence;
 
-       list_for_each_safe(entry, tmp, &chan->fence.pending) {
-               fence = list_entry(entry, struct nouveau_fence, entry);
-
+       list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
                sequence = fence->sequence;
                fence->signalled = true;
                list_del(&fence->entry);
+
+               if (unlikely(fence->work))
+                       fence->work(fence->priv, true);
+
                kref_put(&fence->refcount, nouveau_fence_del);
 
                if (sequence == chan->fence.sequence_ack)
@@ -121,8 +133,8 @@ nouveau_fence_channel(struct nouveau_fence *fence)
 int
 nouveau_fence_emit(struct nouveau_fence *fence)
 {
-       struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
        struct nouveau_channel *chan = fence->channel;
+       struct drm_device *dev = chan->dev;
        int ret;
 
        ret = RING_SPACE(chan, 2);
@@ -143,13 +155,32 @@ nouveau_fence_emit(struct nouveau_fence *fence)
        list_add_tail(&fence->entry, &chan->fence.pending);
        spin_unlock(&chan->fence.lock);
 
-       BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
+       BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1);
        OUT_RING(chan, fence->sequence);
        FIRE_RING(chan);
 
        return 0;
 }
 
+void
+nouveau_fence_work(struct nouveau_fence *fence,
+                  void (*work)(void *priv, bool signalled),
+                  void *priv)
+{
+       BUG_ON(fence->work);
+
+       spin_lock(&fence->channel->fence.lock);
+
+       if (fence->signalled) {
+               work(priv, true);
+       } else {
+               fence->work = work;
+               fence->priv = priv;
+       }
+
+       spin_unlock(&fence->channel->fence.lock);
+}
+
 void
 nouveau_fence_unref(void **sync_obj)
 {
@@ -213,6 +244,162 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
        return ret;
 }
 
+static struct nouveau_semaphore *
+alloc_semaphore(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_semaphore *sema;
+
+       if (!USE_SEMA(dev))
+               return NULL;
+
+       sema = kmalloc(sizeof(*sema), GFP_KERNEL);
+       if (!sema)
+               goto fail;
+
+       spin_lock(&dev_priv->fence.lock);
+       sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
+       if (sema->mem)
+               sema->mem = drm_mm_get_block(sema->mem, 4, 0);
+       spin_unlock(&dev_priv->fence.lock);
+
+       if (!sema->mem)
+               goto fail;
+
+       kref_init(&sema->ref);
+       sema->dev = dev;
+       nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0);
+
+       return sema;
+fail:
+       kfree(sema);
+       return NULL;
+}
+
+static void
+free_semaphore(struct kref *ref)
+{
+       struct nouveau_semaphore *sema =
+               container_of(ref, struct nouveau_semaphore, ref);
+       struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+       spin_lock(&dev_priv->fence.lock);
+       drm_mm_put_block(sema->mem);
+       spin_unlock(&dev_priv->fence.lock);
+
+       kfree(sema);
+}
+
+static void
+semaphore_work(void *priv, bool signalled)
+{
+       struct nouveau_semaphore *sema = priv;
+       struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+       if (unlikely(!signalled))
+               nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);
+
+       kref_put(&sema->ref, free_semaphore);
+}
+
+static int
+emit_semaphore(struct nouveau_channel *chan, int method,
+              struct nouveau_semaphore *sema)
+{
+       struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+       struct nouveau_fence *fence;
+       bool smart = (dev_priv->card_type >= NV_50);
+       int ret;
+
+       ret = RING_SPACE(chan, smart ? 8 : 4);
+       if (ret)
+               return ret;
+
+       if (smart) {
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+               OUT_RING(chan, NvSema);
+       }
+       BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1);
+       OUT_RING(chan, sema->mem->start);
+
+       if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) {
+               /*
+                * NV50 tries to be too smart and context-switch
+                * between semaphores instead of doing a "first come,
+                * first served" strategy like previous cards
+                * do.
+                *
+                * That's bad because the ACQUIRE latency can get as
+                * large as the PFIFO context time slice in the
+                * typical DRI2 case where you have several
+                * outstanding semaphores at the same moment.
+                *
+                * If we're going to ACQUIRE, force the card to
+                * context switch before, just in case the matching
+                * RELEASE is already scheduled to be executed in
+                * another channel.
+                */
+               BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+               OUT_RING(chan, 0);
+       }
+
+       BEGIN_RING(chan, NvSubSw, method, 1);
+       OUT_RING(chan, 1);
+
+       if (smart && method == NV_SW_SEMAPHORE_RELEASE) {
+               /*
+                * Force the card to context switch, there may be
+                * another channel waiting for the semaphore we just
+                * released.
+                */
+               BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+               OUT_RING(chan, 0);
+       }
+
+       /* Delay semaphore destruction until its work is done */
+       ret = nouveau_fence_new(chan, &fence, true);
+       if (ret)
+               return ret;
+
+       kref_get(&sema->ref);
+       nouveau_fence_work(fence, semaphore_work, sema);
+       nouveau_fence_unref((void *)&fence);
+
+       return 0;
+}
+
+int
+nouveau_fence_sync(struct nouveau_fence *fence,
+                  struct nouveau_channel *wchan)
+{
+       struct nouveau_channel *chan = nouveau_fence_channel(fence);
+       struct drm_device *dev = wchan->dev;
+       struct nouveau_semaphore *sema;
+       int ret;
+
+       if (likely(!fence || chan == wchan ||
+                  nouveau_fence_signalled(fence, NULL)))
+               return 0;
+
+       sema = alloc_semaphore(dev);
+       if (!sema) {
+               /* Early card or broken userspace, fall back to
+                * software sync. */
+               return nouveau_fence_wait(fence, NULL, false, false);
+       }
+
+       /* Make wchan wait until it gets signalled */
+       ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema);
+       if (ret)
+               goto out;
+
+       /* Signal the semaphore from chan */
+       ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema);
+out:
+       kref_put(&sema->ref, free_semaphore);
+       return ret;
+}
+
 int
 nouveau_fence_flush(void *sync_obj, void *sync_arg)
 {
@@ -220,26 +407,123 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
 }
 
 int
-nouveau_fence_init(struct nouveau_channel *chan)
+nouveau_fence_channel_init(struct nouveau_channel *chan)
 {
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       /* Create an NV_SW object for various sync purposes */
+       ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
+       if (ret)
+               return ret;
+
+       ret = nouveau_ramht_insert(chan, NvSw, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       if (ret)
+               return ret;
+
+       ret = RING_SPACE(chan, 2);
+       if (ret)
+               return ret;
+       BEGIN_RING(chan, NvSubSw, 0, 1);
+       OUT_RING(chan, NvSw);
+
+       /* Create a DMA object for the shared cross-channel sync area. */
+       if (USE_SEMA(dev)) {
+               struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node;
+
+               ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+                                            mem->start << PAGE_SHIFT,
+                                            mem->size << PAGE_SHIFT,
+                                            NV_DMA_ACCESS_RW,
+                                            NV_DMA_TARGET_VIDMEM, &obj);
+               if (ret)
+                       return ret;
+
+               ret = nouveau_ramht_insert(chan, NvSema, obj);
+               nouveau_gpuobj_ref(NULL, &obj);
+               if (ret)
+                       return ret;
+
+               ret = RING_SPACE(chan, 2);
+               if (ret)
+                       return ret;
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+               OUT_RING(chan, NvSema);
+       }
+
+       FIRE_RING(chan);
+
        INIT_LIST_HEAD(&chan->fence.pending);
        spin_lock_init(&chan->fence.lock);
        atomic_set(&chan->fence.last_sequence_irq, 0);
+
        return 0;
 }
 
 void
-nouveau_fence_fini(struct nouveau_channel *chan)
+nouveau_fence_channel_fini(struct nouveau_channel *chan)
 {
-       struct list_head *entry, *tmp;
-       struct nouveau_fence *fence;
-
-       list_for_each_safe(entry, tmp, &chan->fence.pending) {
-               fence = list_entry(entry, struct nouveau_fence, entry);
+       struct nouveau_fence *tmp, *fence;
 
+       list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
                fence->signalled = true;
                list_del(&fence->entry);
+
+               if (unlikely(fence->work))
+                       fence->work(fence->priv, false);
+
                kref_put(&fence->refcount, nouveau_fence_del);
        }
 }
 
+int
+nouveau_fence_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int ret;
+
+       /* Create a shared VRAM heap for cross-channel sync. */
+       if (USE_SEMA(dev)) {
+               ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM,
+                                    0, 0, false, true, &dev_priv->fence.bo);
+               if (ret)
+                       return ret;
+
+               ret = nouveau_bo_pin(dev_priv->fence.bo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       goto fail;
+
+               ret = nouveau_bo_map(dev_priv->fence.bo);
+               if (ret)
+                       goto fail;
+
+               ret = drm_mm_init(&dev_priv->fence.heap, 0,
+                                 dev_priv->fence.bo->bo.mem.size);
+               if (ret)
+                       goto fail;
+
+               spin_lock_init(&dev_priv->fence.lock);
+       }
+
+       return 0;
+fail:
+       nouveau_bo_unmap(dev_priv->fence.bo);
+       nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+       return ret;
+}
+
+void
+nouveau_fence_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (USE_SEMA(dev)) {
+               drm_mm_takedown(&dev_priv->fence.heap);
+               nouveau_bo_unmap(dev_priv->fence.bo);
+               nouveau_bo_unpin(dev_priv->fence.bo);
+               nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+       }
+}
index 19620a6709f55c00e97efd5d2f816705788420f8..5c4c929d7f744d6911c1a16b67924ab770b6de5c 100644 (file)
@@ -362,7 +362,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
        list_for_each_entry(nvbo, list, entry) {
                struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
-               ret = nouveau_bo_sync_gpu(nvbo, chan);
+               ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
                if (unlikely(ret)) {
                        NV_ERROR(dev, "fail pre-validate sync\n");
                        return ret;
@@ -385,7 +385,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
                        return ret;
                }
 
-               ret = nouveau_bo_sync_gpu(nvbo, chan);
+               ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
                if (unlikely(ret)) {
                        NV_ERROR(dev, "fail post-validate sync\n");
                        return ret;
index 5d39c4ce8006a03817c017b0a02a30c9f4dfe879..4a8ad1307fa49403f53e5768488afd7e4b49f8c9 100644 (file)
@@ -126,7 +126,7 @@ gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
        reg = (reg - 0x00400000) / 4;
        reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
 
-       nv_wo32(ctx->dev, ctx->data, reg, val);
+       nv_wo32(ctx->data, reg * 4, val);
 }
 #endif
 
index 7b613682e400b88cc387c83261987b6259026b98..bed669a54a2da0692af9a9a1cd4a89064f4d0fd0 100644 (file)
@@ -305,7 +305,7 @@ setPLL_double_lowregs(struct drm_device *dev, uint32_t NMNMreg,
        bool mpll = Preg == 0x4020;
        uint32_t oldPval = nvReadMC(dev, Preg);
        uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
-       uint32_t Pval = (oldPval & (mpll ? ~(0x11 << 16) : ~(1 << 16))) |
+       uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
                        0xc << 28 | pv->log2P << 16;
        uint32_t saved4600 = 0;
        /* some cards have different maskc040s */
@@ -427,22 +427,12 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum pll_types plltype,
                       struct nouveau_pll_vals *pllvals)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       const uint32_t nv04_regs[MAX_PLL_TYPES] = { NV_PRAMDAC_NVPLL_COEFF,
-                                                   NV_PRAMDAC_MPLL_COEFF,
-                                                   NV_PRAMDAC_VPLL_COEFF,
-                                                   NV_RAMDAC_VPLL2 };
-       const uint32_t nv40_regs[MAX_PLL_TYPES] = { 0x4000,
-                                                   0x4020,
-                                                   NV_PRAMDAC_VPLL_COEFF,
-                                                   NV_RAMDAC_VPLL2 };
-       uint32_t reg1, pll1, pll2 = 0;
+       uint32_t reg1 = get_pll_register(dev, plltype), pll1, pll2 = 0;
        struct pll_lims pll_lim;
        int ret;
 
-       if (dev_priv->card_type < NV_40)
-               reg1 = nv04_regs[plltype];
-       else
-               reg1 = nv40_regs[plltype];
+       if (reg1 == 0)
+               return -ENOENT;
 
        pll1 = nvReadMC(dev, reg1);
 
@@ -491,8 +481,10 @@ int
 nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
 {
        struct nouveau_pll_vals pllvals;
+       int ret;
 
-       if (plltype == MPLL && (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
+       if (plltype == PLL_MEMORY &&
+           (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
                uint32_t mpllP;
 
                pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
@@ -501,14 +493,17 @@ nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
 
                return 400000 / mpllP;
        } else
-       if (plltype == MPLL && (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
+       if (plltype == PLL_MEMORY &&
+           (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
                uint32_t clock;
 
                pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
                return clock;
        }
 
-       nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+       ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+       if (ret)
+               return ret;
 
        return nouveau_hw_pllvals_to_clk(&pllvals);
 }
@@ -526,9 +521,9 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
        struct nouveau_pll_vals pv;
        uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
 
-       if (get_pll_limits(dev, head ? VPLL2 : VPLL1, &pll_lim))
+       if (get_pll_limits(dev, pllreg, &pll_lim))
                return;
-       nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &pv);
+       nouveau_hw_get_pllvals(dev, pllreg, &pv);
 
        if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
            pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -661,7 +656,7 @@ nv_save_state_ramdac(struct drm_device *dev, int head,
        if (dev_priv->card_type >= NV_10)
                regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC);
 
-       nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &regp->pllvals);
+       nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, &regp->pllvals);
        state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT);
        if (nv_two_heads(dev))
                state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
@@ -866,10 +861,11 @@ nv_save_state_ext(struct drm_device *dev, int head,
        rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
 
-       if (dev_priv->card_type >= NV_30) {
+       if (dev_priv->card_type >= NV_20)
                rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+       if (dev_priv->card_type >= NV_30)
                rd_cio_state(dev, head, regp, 0x9f);
-       }
 
        rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
        rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
@@ -976,10 +972,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
 
-       if (dev_priv->card_type >= NV_30) {
+       if (dev_priv->card_type >= NV_20)
                wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+       if (dev_priv->card_type >= NV_30)
                wr_cio_state(dev, head, regp, 0x9f);
-       }
 
        wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
        wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
index 84614858728ba0f7ab959b54989cf9a512d89d6a..fdd7e3de79c895138c93706bc023048772f93026 100644 (file)
@@ -299,7 +299,10 @@ nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
 
 int
 nouveau_i2c_identify(struct drm_device *dev, const char *what,
-                    struct i2c_board_info *info, int index)
+                    struct i2c_board_info *info,
+                    bool (*match)(struct nouveau_i2c_chan *,
+                                  struct i2c_board_info *),
+                    int index)
 {
        struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
        int i;
@@ -307,7 +310,8 @@ nouveau_i2c_identify(struct drm_device *dev, const char *what,
        NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
 
        for (i = 0; info[i].addr; i++) {
-               if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
+               if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&
+                   (!match || match(i2c, &info[i]))) {
                        NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
                        return i;
                }
index cfe7c8426d1d028dc7f3fc6b229463f41c08f306..422b62fd8272487dd78bb3d276dbfe70dd8e80fe 100644 (file)
@@ -43,7 +43,10 @@ void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
 struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
 bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
 int nouveau_i2c_identify(struct drm_device *dev, const char *what,
-                        struct i2c_board_info *info, int index);
+                        struct i2c_board_info *info,
+                        bool (*match)(struct nouveau_i2c_chan *,
+                                      struct i2c_board_info *),
+                        int index);
 
 extern const struct i2c_algorithm nouveau_dp_i2c_algo;
 
index 794b0ee30cf608cd7087a2f4e4055b8702e75e2d..6fd51a51c60861e697f43755593f4ad2a1830c9c 100644 (file)
@@ -35,6 +35,7 @@
 #include "nouveau_drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_reg.h"
+#include "nouveau_ramht.h"
 #include <linux/ratelimit.h>
 
 /* needed for hotplug irq */
@@ -106,15 +107,16 @@ nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
        const int mthd = addr & 0x1ffc;
 
        if (mthd == 0x0000) {
-               struct nouveau_gpuobj_ref *ref = NULL;
+               struct nouveau_gpuobj *gpuobj;
 
-               if (nouveau_gpuobj_ref_find(chan, data, &ref))
+               gpuobj = nouveau_ramht_find(chan, data);
+               if (!gpuobj)
                        return false;
 
-               if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
+               if (gpuobj->engine != NVOBJ_ENGINE_SW)
                        return false;
 
-               chan->sw_subchannel[subc] = ref->gpuobj->class;
+               chan->sw_subchannel[subc] = gpuobj->class;
                nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
                        NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
                return true;
@@ -200,16 +202,45 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                }
 
                if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid);
+                       u32 get = nv_rd32(dev, 0x003244);
+                       u32 put = nv_rd32(dev, 0x003240);
+                       u32 push = nv_rd32(dev, 0x003220);
+                       u32 state = nv_rd32(dev, 0x003228);
+
+                       if (dev_priv->card_type == NV_50) {
+                               u32 ho_get = nv_rd32(dev, 0x003328);
+                               u32 ho_put = nv_rd32(dev, 0x003320);
+                               u32 ib_get = nv_rd32(dev, 0x003334);
+                               u32 ib_put = nv_rd32(dev, 0x003330);
+
+                               NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+                                            "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
+                                            "State 0x%08x Push 0x%08x\n",
+                                       chid, ho_get, get, ho_put, put, ib_get, ib_put,
+                                       state, push);
+
+                               /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+                               nv_wr32(dev, 0x003364, 0x00000000);
+                               if (get != put || ho_get != ho_put) {
+                                       nv_wr32(dev, 0x003244, put);
+                                       nv_wr32(dev, 0x003328, ho_put);
+                               } else
+                               if (ib_get != ib_put) {
+                                       nv_wr32(dev, 0x003334, ib_put);
+                               }
+                       } else {
+                               NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
+                                            "Put 0x%08x State 0x%08x Push 0x%08x\n",
+                                       chid, get, put, state, push);
 
-                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-                       nv_wr32(dev, NV03_PFIFO_INTR_0,
-                                               NV_PFIFO_INTR_DMA_PUSHER);
+                               if (get != put)
+                                       nv_wr32(dev, 0x003244, put);
+                       }
 
-                       nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
-                       if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get)
-                               nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET,
-                                                               get + 4);
+                       nv_wr32(dev, 0x003228, 0x00000000);
+                       nv_wr32(dev, 0x003220, 0x00000001);
+                       nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
                }
 
                if (status & NV_PFIFO_INTR_SEMAPHORE) {
@@ -226,6 +257,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                        nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
                }
 
+               if (dev_priv->card_type == NV_50) {
+                       if (status & 0x00000010) {
+                               nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
+                               status &= ~0x00000010;
+                               nv_wr32(dev, 0x002100, 0x00000010);
+                       }
+               }
+
                if (status) {
                        NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
                                status, chid);
@@ -357,7 +396,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
                        if (!chan || !chan->ramin_grctx)
                                continue;
 
-                       if (inst == chan->ramin_grctx->instance)
+                       if (inst == chan->ramin_grctx->pinst)
                                break;
                }
        } else {
@@ -369,7 +408,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
                        if (!chan || !chan->ramin)
                                continue;
 
-                       if (inst == chan->ramin->instance)
+                       if (inst == chan->ramin->vinst)
                                break;
                }
        }
@@ -605,40 +644,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
        nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
 }
 
-static void
-nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t trap[6];
-       int i, ch;
-       uint32_t idx = nv_rd32(dev, 0x100c90);
-       if (idx & 0x80000000) {
-               idx &= 0xffffff;
-               if (display) {
-                       for (i = 0; i < 6; i++) {
-                               nv_wr32(dev, 0x100c90, idx | i << 24);
-                               trap[i] = nv_rd32(dev, 0x100c94);
-                       }
-                       for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
-                               struct nouveau_channel *chan = dev_priv->fifos[ch];
-
-                               if (!chan || !chan->ramin)
-                                       continue;
-
-                               if (trap[1] == chan->ramin->instance >> 12)
-                                       break;
-                       }
-                       NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
-                                       name, (trap[5]&0x100?"read":"write"),
-                                       trap[5]&0xff, trap[4]&0xffff,
-                                       trap[3]&0xffff, trap[0], trap[2], ch);
-               }
-               nv_wr32(dev, 0x100c90, idx | 0x80000000);
-       } else if (display) {
-               NV_INFO(dev, "%s - no VM fault?\n", name);
-       }
-}
-
 static struct nouveau_enum_names nv50_mp_exec_error_names[] =
 {
        { 3, "STACK_UNDERFLOW" },
@@ -711,7 +716,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
                tps++;
                switch (type) {
                case 6: /* texture error... unknown for now */
-                       nv50_pfb_vm_trap(dev, display, name);
+                       nv50_fb_vm_trap(dev, display, name);
                        if (display) {
                                NV_ERROR(dev, "magic set %d:\n", i);
                                for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
@@ -734,7 +739,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
                        uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
                        uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
                        uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
-                       nv50_pfb_vm_trap(dev, display, name);
+                       nv50_fb_vm_trap(dev, display, name);
                        /* 2d engine destination */
                        if (ustatus & 0x00000010) {
                                if (display) {
@@ -817,7 +822,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
 
                /* Known to be triggered by screwed up NOTIFY and COND... */
                if (ustatus & 0x00000001) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
                        nv_wr32(dev, 0x400500, 0);
                        if (nv_rd32(dev, 0x400808) & 0x80000000) {
                                if (display) {
@@ -842,7 +847,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
                        ustatus &= ~0x00000001;
                }
                if (ustatus & 0x00000002) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
                        nv_wr32(dev, 0x400500, 0);
                        if (nv_rd32(dev, 0x40084c) & 0x80000000) {
                                if (display) {
@@ -884,15 +889,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
                        NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
                }
                if (ustatus & 0x00000001) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
                        ustatus &= ~0x00000001;
                }
                if (ustatus & 0x00000002) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
                        ustatus &= ~0x00000002;
                }
                if (ustatus & 0x00000004) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
                        ustatus &= ~0x00000004;
                }
                NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
@@ -917,7 +922,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
                        NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
                }
                if (ustatus & 0x00000001) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
                        NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
                                        nv_rd32(dev, 0x400c00),
                                        nv_rd32(dev, 0x400c08),
@@ -939,7 +944,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
                        NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
                }
                if (ustatus & 0x00000001) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
                        NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
                                        nv_rd32(dev, 0x401804),
                                        nv_rd32(dev, 0x401808),
@@ -964,7 +969,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
                        NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
                }
                if (ustatus & 0x00000001) {
-                       nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
+                       nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
                        NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
                                        nv_rd32(dev, 0x405800),
                                        nv_rd32(dev, 0x405804),
@@ -986,7 +991,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
         * remaining, so try to handle it anyway. Perhaps related to that
         * unknown DMA slot on tesla? */
        if (status & 0x20) {
-               nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
+               nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
                ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
                if (display)
                        NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
index 9689d41476867c82a7be56d92d4a0cfe2aa6e822..a163c7c612e78eb6b6718620ee75773cd49a26f7 100644 (file)
@@ -35,6 +35,8 @@
 #include "drm_sarea.h"
 #include "nouveau_drv.h"
 
+#define MIN(a,b) a < b ? a : b
+
 /*
  * NV10-NV40 tiling helpers
  */
@@ -47,18 +49,14 @@ nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+       struct nouveau_tile_reg *tile = &dev_priv->tile[i];
 
        tile->addr = addr;
        tile->size = size;
        tile->used = !!pitch;
        nouveau_fence_unref((void **)&tile->fence);
 
-       if (!pfifo->cache_flush(dev))
-               return;
-
        pfifo->reassign(dev, false);
-       pfifo->cache_flush(dev);
        pfifo->cache_pull(dev, false);
 
        nouveau_wait_for_idle(dev);
@@ -76,34 +74,36 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-       struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL;
-       int i;
+       struct nouveau_tile_reg *found = NULL;
+       unsigned long i, flags;
 
-       spin_lock(&dev_priv->tile.lock);
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
 
        for (i = 0; i < pfb->num_tiles; i++) {
-               if (tile[i].used)
+               struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+
+               if (tile->used)
                        /* Tile region in use. */
                        continue;
 
-               if (tile[i].fence &&
-                   !nouveau_fence_signalled(tile[i].fence, NULL))
+               if (tile->fence &&
+                   !nouveau_fence_signalled(tile->fence, NULL))
                        /* Pending tile region. */
                        continue;
 
-               if (max(tile[i].addr, addr) <
-                   min(tile[i].addr + tile[i].size, addr + size))
+               if (max(tile->addr, addr) <
+                   min(tile->addr + tile->size, addr + size))
                        /* Kill an intersecting tile region. */
                        nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
 
                if (pitch && !found) {
                        /* Free tile region. */
                        nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
-                       found = &tile[i];
+                       found = tile;
                }
        }
 
-       spin_unlock(&dev_priv->tile.lock);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        return found;
 }
@@ -169,8 +169,9 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
                        virt  += (end - pte);
 
                        while (pte < end) {
-                               nv_wo32(dev, pgt, pte++, offset_l);
-                               nv_wo32(dev, pgt, pte++, offset_h);
+                               nv_wo32(pgt, (pte * 4) + 0, offset_l);
+                               nv_wo32(pgt, (pte * 4) + 4, offset_h);
+                               pte += 2;
                        }
                }
        }
@@ -203,8 +204,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
                pages -= (end - pte);
                virt  += (end - pte) << 15;
 
-               while (pte < end)
-                       nv_wo32(dev, pgt, pte++, 0);
+               while (pte < end) {
+                       nv_wo32(pgt, (pte * 4), 0);
+                       pte++;
+               }
        }
        dev_priv->engine.instmem.flush(dev);
 
@@ -218,7 +221,7 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
  * Cleanup everything
  */
 void
-nouveau_mem_close(struct drm_device *dev)
+nouveau_mem_vram_fini(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
@@ -229,6 +232,19 @@ nouveau_mem_close(struct drm_device *dev)
 
        nouveau_ttm_global_release(dev_priv);
 
+       if (dev_priv->fb_mtrr >= 0) {
+               drm_mtrr_del(dev_priv->fb_mtrr,
+                            pci_resource_start(dev->pdev, 1),
+                            pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
+               dev_priv->fb_mtrr = -1;
+       }
+}
+
+void
+nouveau_mem_gart_fini(struct drm_device *dev)
+{
+       nouveau_sgdma_takedown(dev);
+
        if (drm_core_has_AGP(dev) && dev->agp) {
                struct drm_agp_mem *entry, *tempe;
 
@@ -248,13 +264,6 @@ nouveau_mem_close(struct drm_device *dev)
                dev->agp->acquired = 0;
                dev->agp->enabled = 0;
        }
-
-       if (dev_priv->fb_mtrr) {
-               drm_mtrr_del(dev_priv->fb_mtrr,
-                            pci_resource_start(dev->pdev, 1),
-                            pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
-               dev_priv->fb_mtrr = -1;
-       }
 }
 
 static uint32_t
@@ -305,8 +314,62 @@ nouveau_mem_detect_nforce(struct drm_device *dev)
        return 0;
 }
 
-/* returns the amount of FB ram in bytes */
-int
+static void
+nv50_vram_preinit(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int i, parts, colbits, rowbitsa, rowbitsb, banks;
+       u64 rowsize, predicted;
+       u32 r0, r4, rt, ru;
+
+       r0 = nv_rd32(dev, 0x100200);
+       r4 = nv_rd32(dev, 0x100204);
+       rt = nv_rd32(dev, 0x100250);
+       ru = nv_rd32(dev, 0x001540);
+       NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+       for (i = 0, parts = 0; i < 8; i++) {
+               if (ru & (0x00010000 << i))
+                       parts++;
+       }
+
+       colbits  =  (r4 & 0x0000f000) >> 12;
+       rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+       rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+       banks    = ((r4 & 0x01000000) ? 8 : 4);
+
+       rowsize = parts * banks * (1 << colbits) * 8;
+       predicted = rowsize << rowbitsa;
+       if (r0 & 0x00000004)
+               predicted += rowsize << rowbitsb;
+
+       if (predicted != dev_priv->vram_size) {
+               NV_WARN(dev, "memory controller reports %dMiB VRAM\n",
+                       (u32)(dev_priv->vram_size >> 20));
+               NV_WARN(dev, "we calculated %dMiB VRAM\n",
+                       (u32)(predicted >> 20));
+       }
+
+       dev_priv->vram_rblock_size = rowsize >> 12;
+       if (rt & 1)
+               dev_priv->vram_rblock_size *= 3;
+
+       NV_DEBUG(dev, "rblock %lld bytes\n",
+                (u64)dev_priv->vram_rblock_size << 12);
+}
+
+static void
+nvaa_vram_preinit(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       /* To our knowledge, there's no large scale reordering of pages
+        * that occurs on IGP chipsets.
+        */
+       dev_priv->vram_rblock_size = 1;
+}
+
+static int
 nouveau_mem_detect(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -325,9 +388,18 @@ nouveau_mem_detect(struct drm_device *dev)
                dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
                dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
                dev_priv->vram_size &= 0xffffffff00ll;
-               if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
+
+               switch (dev_priv->chipset) {
+               case 0xaa:
+               case 0xac:
+               case 0xaf:
                        dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
                        dev_priv->vram_sys_base <<= 12;
+                       nvaa_vram_preinit(dev);
+                       break;
+               default:
+                       nv50_vram_preinit(dev);
+                       break;
                }
        } else {
                dev_priv->vram_size  = nv_rd32(dev, 0x10f20c) << 20;
@@ -345,6 +417,33 @@ nouveau_mem_detect(struct drm_device *dev)
        return -ENOMEM;
 }
 
+#if __OS_HAS_AGP
+static unsigned long
+get_agp_mode(struct drm_device *dev, unsigned long mode)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       /*
+        * FW seems to be broken on nv18, it makes the card lock up
+        * randomly.
+        */
+       if (dev_priv->chipset == 0x18)
+               mode &= ~PCI_AGP_COMMAND_FW;
+
+       /*
+        * AGP mode set in the command line.
+        */
+       if (nouveau_agpmode > 0) {
+               bool agpv3 = mode & 0x8;
+               int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
+
+               mode = (mode & ~0x7) | (rate & 0x7);
+       }
+
+       return mode;
+}
+#endif
+
 int
 nouveau_mem_reset_agp(struct drm_device *dev)
 {
@@ -355,7 +454,8 @@ nouveau_mem_reset_agp(struct drm_device *dev)
        /* First of all, disable fast writes, otherwise if it's
         * already enabled in the AGP bridge and we disable the card's
         * AGP controller we might be locking ourselves out of it. */
-       if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
+       if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) |
+            dev->agp->mode) & PCI_AGP_COMMAND_FW) {
                struct drm_agp_info info;
                struct drm_agp_mode mode;
 
@@ -363,7 +463,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
                if (ret)
                        return ret;
 
-               mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
+               mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW;
                ret = drm_agp_enable(dev, mode);
                if (ret)
                        return ret;
@@ -418,7 +518,7 @@ nouveau_mem_init_agp(struct drm_device *dev)
        }
 
        /* see agp.h for the AGPSTAT_* modes available */
-       mode.mode = info.mode;
+       mode.mode = get_agp_mode(dev, info.mode);
        ret = drm_agp_enable(dev, mode);
        if (ret) {
                NV_ERROR(dev, "Unable to enable AGP: %d\n", ret);
@@ -433,24 +533,27 @@ nouveau_mem_init_agp(struct drm_device *dev)
 }
 
 int
-nouveau_mem_init(struct drm_device *dev)
+nouveau_mem_vram_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
-       int ret, dma_bits = 32;
-
-       dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
-       dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+       int ret, dma_bits;
 
        if (dev_priv->card_type >= NV_50 &&
            pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
                dma_bits = 40;
+       else
+               dma_bits = 32;
 
        ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
-       if (ret) {
-               NV_ERROR(dev, "Error setting DMA mask: %d\n", ret);
+       if (ret)
                return ret;
-       }
+
+       ret = nouveau_mem_detect(dev);
+       if (ret)
+               return ret;
+
+       dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
 
        ret = nouveau_ttm_global_init(dev_priv);
        if (ret)
@@ -465,8 +568,6 @@ nouveau_mem_init(struct drm_device *dev)
                return ret;
        }
 
-       spin_lock_init(&dev_priv->tile.lock);
-
        dev_priv->fb_available_size = dev_priv->vram_size;
        dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
        if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
@@ -474,7 +575,16 @@ nouveau_mem_init(struct drm_device *dev)
                        pci_resource_len(dev->pdev, 1);
        dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
 
-       /* remove reserved space at end of vram from available amount */
+       /* reserve space at end of VRAM for PRAMIN */
+       if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 ||
+           dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b)
+               dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
+       else
+       if (dev_priv->card_type >= NV_40)
+               dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
+       else
+               dev_priv->ramin_rsvd_vram = (512 * 1024);
+
        dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
        dev_priv->fb_aper_free = dev_priv->fb_available_size;
 
@@ -495,9 +605,23 @@ nouveau_mem_init(struct drm_device *dev)
                nouveau_bo_ref(NULL, &dev_priv->vga_ram);
        }
 
-       /* GART */
+       dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+                                        pci_resource_len(dev->pdev, 1),
+                                        DRM_MTRR_WC);
+       return 0;
+}
+
+int
+nouveau_mem_gart_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+       int ret;
+
+       dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+
 #if !defined(__powerpc__) && !defined(__ia64__)
-       if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+       if (drm_device_is_agp(dev) && dev->agp && nouveau_agpmode) {
                ret = nouveau_mem_init_agp(dev);
                if (ret)
                        NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
@@ -523,11 +647,150 @@ nouveau_mem_init(struct drm_device *dev)
                return ret;
        }
 
-       dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
-                                        pci_resource_len(dev->pdev, 1),
-                                        DRM_MTRR_WC);
-
        return 0;
 }
 
+void
+nouveau_mem_timing_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct bit_entry P;
+       u8 tUNK_0, tUNK_1, tUNK_2;
+       u8 tRP;         /* Byte 3 */
+       u8 tRAS;        /* Byte 5 */
+       u8 tRFC;        /* Byte 7 */
+       u8 tRC;         /* Byte 9 */
+       u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
+       u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+       u8 *mem = NULL, *entry;
+       int i, recordlen, entries;
+
+       if (bios->type == NVBIOS_BIT) {
+               if (bit_table(dev, 'P', &P))
+                       return;
+
+               if (P.version == 1)
+                       mem = ROMPTR(bios, P.data[4]);
+               else
+               if (P.version == 2)
+                       mem = ROMPTR(bios, P.data[8]);
+               else {
+                       NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
+               }
+       } else {
+               NV_DEBUG(dev, "BMP version too old for memory\n");
+               return;
+       }
+
+       if (!mem) {
+               NV_DEBUG(dev, "memory timing table pointer invalid\n");
+               return;
+       }
 
+       if (mem[0] != 0x10) {
+               NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]);
+               return;
+       }
+
+       /* validate record length */
+       entries   = mem[2];
+       recordlen = mem[3];
+       if (recordlen < 15) {
+               NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]);
+               return;
+       }
+
+       /* parse vbios entries into common format */
+       memtimings->timing =
+               kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
+       if (!memtimings->timing)
+               return;
+
+       entry = mem + mem[1];
+       for (i = 0; i < entries; i++, entry += recordlen) {
+               struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
+               if (entry[0] == 0)
+                       continue;
+
+               tUNK_18 = 1;
+               tUNK_19 = 1;
+               tUNK_20 = 0;
+               tUNK_21 = 0;
+               switch (MIN(recordlen,21)) {
+               case 21:
+                       tUNK_21 = entry[21];
+               case 20:
+                       tUNK_20 = entry[20];
+               case 19:
+                       tUNK_19 = entry[19];
+               case 18:
+                       tUNK_18 = entry[18];
+               default:
+                       tUNK_0  = entry[0];
+                       tUNK_1  = entry[1];
+                       tUNK_2  = entry[2];
+                       tRP     = entry[3];
+                       tRAS    = entry[5];
+                       tRFC    = entry[7];
+                       tRC     = entry[9];
+                       tUNK_10 = entry[10];
+                       tUNK_11 = entry[11];
+                       tUNK_12 = entry[12];
+                       tUNK_13 = entry[13];
+                       tUNK_14 = entry[14];
+                       break;
+               }
+
+               timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP);
+
+               /* XXX: I don't trust the -1's and +1's... they must come
+                *      from somewhere! */
+               timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 |
+                                     tUNK_18 << 16 |
+                                     (tUNK_1 + tUNK_19 + 1) << 8 |
+                                     (tUNK_2 - 1));
+
+               timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
+               if(recordlen > 19) {
+                       timing->reg_100228 += (tUNK_19 - 1) << 24;
+               } else {
+                       timing->reg_100228 += tUNK_12 << 24;
+               }
+
+               /* XXX: reg_10022c */
+
+               timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
+                                     tUNK_13 << 8  | tUNK_13);
+
+               /* XXX: +6? */
+               timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
+               if(tUNK_10 > tUNK_11) {
+                       timing->reg_100234 += tUNK_10 << 16;
+               } else {
+                       timing->reg_100234 += tUNK_11 << 16;
+               }
+
+               /* XXX; reg_100238, reg_10023c */
+               NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
+                        timing->reg_100220, timing->reg_100224,
+                        timing->reg_100228, timing->reg_10022c);
+               NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
+                        timing->reg_100230, timing->reg_100234,
+                        timing->reg_100238, timing->reg_10023c);
+       }
+
+       memtimings->nr_timing  = entries;
+       memtimings->supported = true;
+}
+
+void
+nouveau_mem_timing_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
+
+       kfree(mem->timing);
+}
index 3ec181ff50cea7a45b22a28a6ed43857b2a841cb..2cc59f8c658bd63b840fbf35c7871d090a587d95 100644 (file)
@@ -28,6 +28,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 int
 nouveau_notifier_init_channel(struct nouveau_channel *chan)
@@ -112,7 +113,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
                return -ENOMEM;
        }
 
-       offset = chan->notifier_bo->bo.mem.mm_node->start << PAGE_SHIFT;
+       offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
        if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) {
                target = NV_DMA_TARGET_VIDMEM;
        } else
@@ -146,11 +147,11 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        nobj->dtor = nouveau_notifier_gpuobj_dtor;
        nobj->priv = mem;
 
-       ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
+       ret = nouveau_ramht_insert(chan, handle, nobj);
+       nouveau_gpuobj_ref(NULL, &nobj);
        if (ret) {
-               nouveau_gpuobj_del(dev, &nobj);
                drm_mm_put_block(mem);
-               NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
+               NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
                return ret;
        }
 
index b6bcb254f4ab49ab123834d78f4e62e58ac0398a..896cf8634144a2b5cf7f69fdd006c848b4b2eb79 100644 (file)
@@ -34,6 +34,7 @@
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
+#include "nouveau_ramht.h"
 
 /* NVidia uses context objects to drive drawing operations.
 
    The key into the hash table depends on the object handle and channel id and
    is given as:
 */
-static uint32_t
-nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t hash = 0;
-       int i;
-
-       NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle);
-
-       for (i = 32; i > 0; i -= dev_priv->ramht_bits) {
-               hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
-               handle >>= dev_priv->ramht_bits;
-       }
-
-       if (dev_priv->card_type < NV_50)
-               hash ^= channel << (dev_priv->ramht_bits - 4);
-       hash <<= 3;
-
-       NV_DEBUG(dev, "hash=0x%08x\n", hash);
-       return hash;
-}
-
-static int
-nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
-                         uint32_t offset)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t ctx = nv_ro32(dev, ramht, (offset + 4)/4);
-
-       if (dev_priv->card_type < NV_40)
-               return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
-       return (ctx != 0);
-}
-
-static int
-nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-       struct nouveau_channel *chan = ref->channel;
-       struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-       uint32_t ctx, co, ho;
-
-       if (!ramht) {
-               NV_ERROR(dev, "No hash table!\n");
-               return -EINVAL;
-       }
-
-       if (dev_priv->card_type < NV_40) {
-               ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) |
-                     (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-                     (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
-       } else
-       if (dev_priv->card_type < NV_50) {
-               ctx = (ref->instance >> 4) |
-                     (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-                     (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
-       } else {
-               if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
-                       ctx = (ref->instance << 10) | 2;
-               } else {
-                       ctx = (ref->instance >> 4) |
-                             ((ref->gpuobj->engine <<
-                               NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
-               }
-       }
-
-       co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
-       do {
-               if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
-                       NV_DEBUG(dev,
-                                "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-                                chan->id, co, ref->handle, ctx);
-                       nv_wo32(dev, ramht, (co + 0)/4, ref->handle);
-                       nv_wo32(dev, ramht, (co + 4)/4, ctx);
-
-                       list_add_tail(&ref->list, &chan->ramht_refs);
-                       instmem->flush(dev);
-                       return 0;
-               }
-               NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
-                        chan->id, co, nv_ro32(dev, ramht, co/4));
-
-               co += 8;
-               if (co >= dev_priv->ramht_size)
-                       co = 0;
-       } while (co != ho);
-
-       NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
-       return -ENOMEM;
-}
-
-static void
-nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-       struct nouveau_channel *chan = ref->channel;
-       struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-       uint32_t co, ho;
-
-       if (!ramht) {
-               NV_ERROR(dev, "No hash table!\n");
-               return;
-       }
-
-       co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
-       do {
-               if (nouveau_ramht_entry_valid(dev, ramht, co) &&
-                   (ref->handle == nv_ro32(dev, ramht, (co/4)))) {
-                       NV_DEBUG(dev,
-                                "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-                                chan->id, co, ref->handle,
-                                nv_ro32(dev, ramht, (co + 4)));
-                       nv_wo32(dev, ramht, (co + 0)/4, 0x00000000);
-                       nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
-
-                       list_del(&ref->list);
-                       instmem->flush(dev);
-                       return;
-               }
-
-               co += 8;
-               if (co >= dev_priv->ramht_size)
-                       co = 0;
-       } while (co != ho);
-       list_del(&ref->list);
-
-       NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
-                chan->id, ref->handle);
-}
 
 int
 nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
@@ -205,7 +75,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
        struct nouveau_gpuobj *gpuobj;
-       struct drm_mm *pramin = NULL;
+       struct drm_mm_node *ramin = NULL;
        int ret;
 
        NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -218,69 +88,102 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        if (!gpuobj)
                return -ENOMEM;
        NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
+       gpuobj->dev = dev;
        gpuobj->flags = flags;
-       gpuobj->im_channel = chan;
+       kref_init(&gpuobj->refcount);
+       gpuobj->size = size;
 
+       spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
 
-       /* Choose between global instmem heap, and per-channel private
-        * instmem heap.  On <NV50 allow requests for private instmem
-        * to be satisfied from global heap if no per-channel area
-        * available.
-        */
        if (chan) {
                NV_DEBUG(dev, "channel heap\n");
-               pramin = &chan->ramin_heap;
+
+               ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
+               if (ramin)
+                       ramin = drm_mm_get_block(ramin, size, align);
+
+               if (!ramin) {
+                       nouveau_gpuobj_ref(NULL, &gpuobj);
+                       return -ENOMEM;
+               }
        } else {
                NV_DEBUG(dev, "global heap\n");
-               pramin = &dev_priv->ramin_heap;
 
+               /* allocate backing pages, sets vinst */
                ret = engine->instmem.populate(dev, gpuobj, &size);
                if (ret) {
-                       nouveau_gpuobj_del(dev, &gpuobj);
+                       nouveau_gpuobj_ref(NULL, &gpuobj);
                        return ret;
                }
-       }
 
-       /* Allocate a chunk of the PRAMIN aperture */
-       gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
-       if (gpuobj->im_pramin)
-               gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+               /* try and get aperture space */
+               do {
+                       if (drm_mm_pre_get(&dev_priv->ramin_heap))
+                               return -ENOMEM;
+
+                       spin_lock(&dev_priv->ramin_lock);
+                       ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
+                                                  align, 0);
+                       if (ramin == NULL) {
+                               spin_unlock(&dev_priv->ramin_lock);
+                               nouveau_gpuobj_ref(NULL, &gpuobj);
+                               return ret;
+                       }
 
-       if (!gpuobj->im_pramin) {
-               nouveau_gpuobj_del(dev, &gpuobj);
-               return -ENOMEM;
+                       ramin = drm_mm_get_block_atomic(ramin, size, align);
+                       spin_unlock(&dev_priv->ramin_lock);
+               } while (ramin == NULL);
+
+               /* on nv50 it's ok to fail, we have a fallback path */
+               if (!ramin && dev_priv->card_type < NV_50) {
+                       nouveau_gpuobj_ref(NULL, &gpuobj);
+                       return -ENOMEM;
+               }
        }
 
-       if (!chan) {
+       /* if we got a chunk of the aperture, map pages into it */
+       gpuobj->im_pramin = ramin;
+       if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) {
                ret = engine->instmem.bind(dev, gpuobj);
                if (ret) {
-                       nouveau_gpuobj_del(dev, &gpuobj);
+                       nouveau_gpuobj_ref(NULL, &gpuobj);
                        return ret;
                }
        }
 
+       /* calculate the various different addresses for the object */
+       if (chan) {
+               gpuobj->pinst = chan->ramin->pinst;
+               if (gpuobj->pinst != ~0)
+                       gpuobj->pinst += gpuobj->im_pramin->start;
+
+               if (dev_priv->card_type < NV_50) {
+                       gpuobj->cinst = gpuobj->pinst;
+               } else {
+                       gpuobj->cinst = gpuobj->im_pramin->start;
+                       gpuobj->vinst = gpuobj->im_pramin->start +
+                                       chan->ramin->vinst;
+               }
+       } else {
+               if (gpuobj->im_pramin)
+                       gpuobj->pinst = gpuobj->im_pramin->start;
+               else
+                       gpuobj->pinst = ~0;
+               gpuobj->cinst = 0xdeadbeef;
+       }
+
        if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
                int i;
 
-               for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-                       nv_wo32(dev, gpuobj, i/4, 0);
+               for (i = 0; i < gpuobj->size; i += 4)
+                       nv_wo32(gpuobj, i, 0);
                engine->instmem.flush(dev);
        }
 
-       *gpuobj_ret = gpuobj;
-       return 0;
-}
-
-int
-nouveau_gpuobj_early_init(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       NV_DEBUG(dev, "\n");
-
-       INIT_LIST_HEAD(&dev_priv->gpuobj_list);
 
+       *gpuobj_ret = gpuobj;
        return 0;
 }
 
@@ -288,18 +191,12 @@ int
 nouveau_gpuobj_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int ret;
 
        NV_DEBUG(dev, "\n");
 
-       if (dev_priv->card_type < NV_50) {
-               ret = nouveau_gpuobj_new_fake(dev,
-                       dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
-                       NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
-                                               &dev_priv->ramht, NULL);
-               if (ret)
-                       return ret;
-       }
+       INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+       spin_lock_init(&dev_priv->ramin_lock);
+       dev_priv->ramin_base = ~0;
 
        return 0;
 }
@@ -311,297 +208,89 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
 
        NV_DEBUG(dev, "\n");
 
-       nouveau_gpuobj_del(dev, &dev_priv->ramht);
+       BUG_ON(!list_empty(&dev_priv->gpuobj_list));
 }
 
-void
-nouveau_gpuobj_late_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *gpuobj = NULL;
-       struct list_head *entry, *tmp;
-
-       NV_DEBUG(dev, "\n");
-
-       list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
-               gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
-
-               NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
-                        gpuobj, gpuobj->refcount);
-               gpuobj->refcount = 0;
-               nouveau_gpuobj_del(dev, &gpuobj);
-       }
-}
 
-int
-nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
+static void
+nouveau_gpuobj_del(struct kref *ref)
 {
+       struct nouveau_gpuobj *gpuobj =
+               container_of(ref, struct nouveau_gpuobj, refcount);
+       struct drm_device *dev = gpuobj->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
-       struct nouveau_gpuobj *gpuobj;
        int i;
 
-       NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
-
-       if (!dev_priv || !pgpuobj || !(*pgpuobj))
-               return -EINVAL;
-       gpuobj = *pgpuobj;
-
-       if (gpuobj->refcount != 0) {
-               NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
-               return -EINVAL;
-       }
+       NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
 
        if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
-               for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-                       nv_wo32(dev, gpuobj, i/4, 0);
+               for (i = 0; i < gpuobj->size; i += 4)
+                       nv_wo32(gpuobj, i, 0);
                engine->instmem.flush(dev);
        }
 
        if (gpuobj->dtor)
                gpuobj->dtor(dev, gpuobj);
 
-       if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
+       if (gpuobj->im_backing)
                engine->instmem.clear(dev, gpuobj);
 
-       if (gpuobj->im_pramin) {
-               if (gpuobj->flags & NVOBJ_FLAG_FAKE)
-                       kfree(gpuobj->im_pramin);
-               else
-                       drm_mm_put_block(gpuobj->im_pramin);
-       }
-
+       spin_lock(&dev_priv->ramin_lock);
+       if (gpuobj->im_pramin)
+               drm_mm_put_block(gpuobj->im_pramin);
        list_del(&gpuobj->list);
+       spin_unlock(&dev_priv->ramin_lock);
 
-       *pgpuobj = NULL;
        kfree(gpuobj);
-       return 0;
 }
 
-static int
-nouveau_gpuobj_instance_get(struct drm_device *dev,
-                           struct nouveau_channel *chan,
-                           struct nouveau_gpuobj *gpuobj, uint32_t *inst)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *cpramin;
-
-       /* <NV50 use PRAMIN address everywhere */
-       if (dev_priv->card_type < NV_50) {
-               *inst = gpuobj->im_pramin->start;
-               return 0;
-       }
-
-       if (chan && gpuobj->im_channel != chan) {
-               NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
-                        gpuobj->im_channel->id, chan->id);
-               return -EINVAL;
-       }
-
-       /* NV50 channel-local instance */
-       if (chan) {
-               cpramin = chan->ramin->gpuobj;
-               *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
-               return 0;
-       }
-
-       /* NV50 global (VRAM) instance */
-       if (!gpuobj->im_channel) {
-               /* ...from global heap */
-               if (!gpuobj->im_backing) {
-                       NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
-                       return -EINVAL;
-               }
-               *inst = gpuobj->im_backing_start;
-               return 0;
-       } else {
-               /* ...from local heap */
-               cpramin = gpuobj->im_channel->ramin->gpuobj;
-               *inst = cpramin->im_backing_start +
-                       (gpuobj->im_pramin->start - cpramin->im_pramin->start);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int
-nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
-                      uint32_t handle, struct nouveau_gpuobj *gpuobj,
-                      struct nouveau_gpuobj_ref **ref_ret)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj_ref *ref;
-       uint32_t instance;
-       int ret;
-
-       NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
-                chan ? chan->id : -1, handle, gpuobj);
-
-       if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
-               return -EINVAL;
-
-       if (!chan && !ref_ret)
-               return -EINVAL;
-
-       if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
-               /* sw object */
-               instance = 0x40;
-       } else {
-               ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
-               if (ret)
-                       return ret;
-       }
-
-       ref = kzalloc(sizeof(*ref), GFP_KERNEL);
-       if (!ref)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&ref->list);
-       ref->gpuobj   = gpuobj;
-       ref->channel  = chan;
-       ref->instance = instance;
-
-       if (!ref_ret) {
-               ref->handle = handle;
-
-               ret = nouveau_ramht_insert(dev, ref);
-               if (ret) {
-                       kfree(ref);
-                       return ret;
-               }
-       } else {
-               ref->handle = ~0;
-               *ref_ret = ref;
-       }
-
-       ref->gpuobj->refcount++;
-       return 0;
-}
-
-int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
-{
-       struct nouveau_gpuobj_ref *ref;
-
-       NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
-
-       if (!dev || !pref || *pref == NULL)
-               return -EINVAL;
-       ref = *pref;
-
-       if (ref->handle != ~0)
-               nouveau_ramht_remove(dev, ref);
-
-       if (ref->gpuobj) {
-               ref->gpuobj->refcount--;
-
-               if (ref->gpuobj->refcount == 0) {
-                       if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
-                               nouveau_gpuobj_del(dev, &ref->gpuobj);
-               }
-       }
-
-       *pref = NULL;
-       kfree(ref);
-       return 0;
-}
-
-int
-nouveau_gpuobj_new_ref(struct drm_device *dev,
-                      struct nouveau_channel *oc, struct nouveau_channel *rc,
-                      uint32_t handle, uint32_t size, int align,
-                      uint32_t flags, struct nouveau_gpuobj_ref **ref)
-{
-       struct nouveau_gpuobj *gpuobj = NULL;
-       int ret;
-
-       ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
-       if (ret)
-               return ret;
-
-       ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
-       if (ret) {
-               nouveau_gpuobj_del(dev, &gpuobj);
-               return ret;
-       }
-
-       return 0;
-}
-
-int
-nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
-                       struct nouveau_gpuobj_ref **ref_ret)
+void
+nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
 {
-       struct nouveau_gpuobj_ref *ref;
-       struct list_head *entry, *tmp;
-
-       list_for_each_safe(entry, tmp, &chan->ramht_refs) {
-               ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
+       if (ref)
+               kref_get(&ref->refcount);
 
-               if (ref->handle == handle) {
-                       if (ref_ret)
-                               *ref_ret = ref;
-                       return 0;
-               }
-       }
+       if (*ptr)
+               kref_put(&(*ptr)->refcount, nouveau_gpuobj_del);
 
-       return -EINVAL;
+       *ptr = ref;
 }
 
 int
-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
-                       uint32_t b_offset, uint32_t size,
-                       uint32_t flags, struct nouveau_gpuobj **pgpuobj,
-                       struct nouveau_gpuobj_ref **pref)
+nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
+                       u32 size, u32 flags, struct nouveau_gpuobj **pgpuobj)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *gpuobj = NULL;
        int i;
 
        NV_DEBUG(dev,
-                "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
-                p_offset, b_offset, size, flags);
+                "pinst=0x%08x vinst=0x%010llx size=0x%08x flags=0x%08x\n",
+                pinst, vinst, size, flags);
 
        gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
        if (!gpuobj)
                return -ENOMEM;
        NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
-       gpuobj->im_channel = NULL;
-       gpuobj->flags      = flags | NVOBJ_FLAG_FAKE;
-
-       list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
-
-       if (p_offset != ~0) {
-               gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
-                                           GFP_KERNEL);
-               if (!gpuobj->im_pramin) {
-                       nouveau_gpuobj_del(dev, &gpuobj);
-                       return -ENOMEM;
-               }
-               gpuobj->im_pramin->start = p_offset;
-               gpuobj->im_pramin->size  = size;
-       }
-
-       if (b_offset != ~0) {
-               gpuobj->im_backing = (struct nouveau_bo *)-1;
-               gpuobj->im_backing_start = b_offset;
-       }
+       gpuobj->dev = dev;
+       gpuobj->flags = flags;
+       kref_init(&gpuobj->refcount);
+       gpuobj->size  = size;
+       gpuobj->pinst = pinst;
+       gpuobj->cinst = 0xdeadbeef;
+       gpuobj->vinst = vinst;
 
        if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
-               for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-                       nv_wo32(dev, gpuobj, i/4, 0);
+               for (i = 0; i < gpuobj->size; i += 4)
+                       nv_wo32(gpuobj, i, 0);
                dev_priv->engine.instmem.flush(dev);
        }
 
-       if (pref) {
-               i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
-               if (i) {
-                       nouveau_gpuobj_del(dev, &gpuobj);
-                       return i;
-               }
-       }
-
-       if (pgpuobj)
-               *pgpuobj = gpuobj;
+       spin_lock(&dev_priv->ramin_lock);
+       list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
+       *pgpuobj = gpuobj;
        return 0;
 }
 
@@ -685,14 +374,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
                adjust = offset &  0x00000fff;
                frame  = offset & ~0x00000fff;
 
-               nv_wo32(dev, *gpuobj, 0, ((1<<12) | (1<<13) |
-                               (adjust << 20) |
-                                (access << 14) |
-                                (target << 16) |
-                                 class));
-               nv_wo32(dev, *gpuobj, 1, size - 1);
-               nv_wo32(dev, *gpuobj, 2, frame | pte_flags);
-               nv_wo32(dev, *gpuobj, 3, frame | pte_flags);
+               nv_wo32(*gpuobj,  0, ((1<<12) | (1<<13) | (adjust << 20) |
+                                     (access << 14) | (target << 16) |
+                                     class));
+               nv_wo32(*gpuobj,  4, size - 1);
+               nv_wo32(*gpuobj,  8, frame | pte_flags);
+               nv_wo32(*gpuobj, 12, frame | pte_flags);
        } else {
                uint64_t limit = offset + size - 1;
                uint32_t flags0, flags5;
@@ -705,12 +392,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
                        flags5 = 0x00080000;
                }
 
-               nv_wo32(dev, *gpuobj, 0, flags0 | class);
-               nv_wo32(dev, *gpuobj, 1, lower_32_bits(limit));
-               nv_wo32(dev, *gpuobj, 2, lower_32_bits(offset));
-               nv_wo32(dev, *gpuobj, 3, ((upper_32_bits(limit) & 0xff) << 24) |
-                                       (upper_32_bits(offset) & 0xff));
-               nv_wo32(dev, *gpuobj, 5, flags5);
+               nv_wo32(*gpuobj,  0, flags0 | class);
+               nv_wo32(*gpuobj,  4, lower_32_bits(limit));
+               nv_wo32(*gpuobj,  8, lower_32_bits(offset));
+               nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
+                                     (upper_32_bits(offset) & 0xff));
+               nv_wo32(*gpuobj, 20, flags5);
        }
 
        instmem->flush(dev);
@@ -741,7 +428,7 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
                        *o_ret = 0;
        } else
        if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
-               *gpuobj = dev_priv->gart_info.sg_ctxdma;
+               nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
                if (offset & ~0xffffffffULL) {
                        NV_ERROR(dev, "obj offset exceeds 32-bits\n");
                        return -EINVAL;
@@ -829,25 +516,25 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
        }
 
        if (dev_priv->card_type >= NV_50) {
-               nv_wo32(dev, *gpuobj, 0, class);
-               nv_wo32(dev, *gpuobj, 5, 0x00010000);
+               nv_wo32(*gpuobj,  0, class);
+               nv_wo32(*gpuobj, 20, 0x00010000);
        } else {
                switch (class) {
                case NV_CLASS_NULL:
-                       nv_wo32(dev, *gpuobj, 0, 0x00001030);
-                       nv_wo32(dev, *gpuobj, 1, 0xFFFFFFFF);
+                       nv_wo32(*gpuobj, 0, 0x00001030);
+                       nv_wo32(*gpuobj, 4, 0xFFFFFFFF);
                        break;
                default:
                        if (dev_priv->card_type >= NV_40) {
-                               nv_wo32(dev, *gpuobj, 0, class);
+                               nv_wo32(*gpuobj, 0, class);
 #ifdef __BIG_ENDIAN
-                               nv_wo32(dev, *gpuobj, 2, 0x01000000);
+                               nv_wo32(*gpuobj, 8, 0x01000000);
 #endif
                        } else {
 #ifdef __BIG_ENDIAN
-                               nv_wo32(dev, *gpuobj, 0, class | 0x00080000);
+                               nv_wo32(*gpuobj, 0, class | 0x00080000);
 #else
-                               nv_wo32(dev, *gpuobj, 0, class);
+                               nv_wo32(*gpuobj, 0, class);
 #endif
                        }
                }
@@ -873,10 +560,15 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
        if (!gpuobj)
                return -ENOMEM;
+       gpuobj->dev = chan->dev;
        gpuobj->engine = NVOBJ_ENGINE_SW;
        gpuobj->class = class;
+       kref_init(&gpuobj->refcount);
+       gpuobj->cinst = 0x40;
 
+       spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
        *gpuobj_ret = gpuobj;
        return 0;
 }
@@ -886,7 +578,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *pramin = NULL;
        uint32_t size;
        uint32_t base;
        int ret;
@@ -911,18 +602,16 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
                size += 0x1000;
        }
 
-       ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
-                                    &chan->ramin);
+       ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
        if (ret) {
                NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret);
                return ret;
        }
-       pramin = chan->ramin->gpuobj;
 
-       ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
+       ret = drm_mm_init(&chan->ramin_heap, base, size);
        if (ret) {
                NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
-               nouveau_gpuobj_ref_del(dev, &chan->ramin);
+               nouveau_gpuobj_ref(NULL, &chan->ramin);
                return ret;
        }
 
@@ -939,8 +628,6 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
        struct nouveau_gpuobj *vram = NULL, *tt = NULL;
        int ret, i;
 
-       INIT_LIST_HEAD(&chan->ramht_refs);
-
        NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
 
        /* Allocate a chunk of memory for per-channel object storage */
@@ -956,41 +643,38 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
         *    locations determined during init.
         */
        if (dev_priv->card_type >= NV_50) {
-               uint32_t vm_offset, pde;
+               u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+               u64 vm_vinst = chan->ramin->vinst + pgd_offs;
+               u32 vm_pinst = chan->ramin->pinst;
+               u32 pde;
 
-               vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
-               vm_offset += chan->ramin->gpuobj->im_pramin->start;
+               if (vm_pinst != ~0)
+                       vm_pinst += pgd_offs;
 
-               ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
-                                                       0, &chan->vm_pd, NULL);
+               ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000,
+                                             0, &chan->vm_pd);
                if (ret)
                        return ret;
                for (i = 0; i < 0x4000; i += 8) {
-                       nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
-                       nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
+                       nv_wo32(chan->vm_pd, i + 0, 0x00000000);
+                       nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
                }
 
-               pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2;
-               ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
-                                            dev_priv->gart_info.sg_ctxdma,
-                                            &chan->vm_gart_pt);
-               if (ret)
-                       return ret;
-               nv_wo32(dev, chan->vm_pd, pde++,
-                           chan->vm_gart_pt->instance | 0x03);
-               nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+               nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma,
+                                  &chan->vm_gart_pt);
+               pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
+               nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3);
+               nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
 
-               pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2;
+               pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
                for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-                       ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
-                                                    dev_priv->vm_vram_pt[i],
-                                                    &chan->vm_vram_pt[i]);
-                       if (ret)
-                               return ret;
+                       nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i],
+                                          &chan->vm_vram_pt[i]);
 
-                       nv_wo32(dev, chan->vm_pd, pde++,
-                                   chan->vm_vram_pt[i]->instance | 0x61);
-                       nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+                       nv_wo32(chan->vm_pd, pde + 0,
+                               chan->vm_vram_pt[i]->vinst | 0x61);
+                       nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
+                       pde += 8;
                }
 
                instmem->flush(dev);
@@ -998,15 +682,17 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
 
        /* RAMHT */
        if (dev_priv->card_type < NV_50) {
-               ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
-                                            &chan->ramht);
+               nouveau_ramht_ref(dev_priv->ramht, &chan->ramht, NULL);
+       } else {
+               struct nouveau_gpuobj *ramht = NULL;
+
+               ret = nouveau_gpuobj_new(dev, chan, 0x8000, 16,
+                                        NVOBJ_FLAG_ZERO_ALLOC, &ramht);
                if (ret)
                        return ret;
-       } else {
-               ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
-                                            0x8000, 16,
-                                            NVOBJ_FLAG_ZERO_ALLOC,
-                                            &chan->ramht);
+
+               ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+               nouveau_gpuobj_ref(NULL, &ramht);
                if (ret)
                        return ret;
        }
@@ -1023,24 +709,32 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
                }
        } else {
                ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-                                               0, dev_priv->fb_available_size,
-                                               NV_DMA_ACCESS_RW,
-                                               NV_DMA_TARGET_VIDMEM, &vram);
+                                            0, dev_priv->fb_available_size,
+                                            NV_DMA_ACCESS_RW,
+                                            NV_DMA_TARGET_VIDMEM, &vram);
                if (ret) {
                        NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
                        return ret;
                }
        }
 
-       ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL);
+       ret = nouveau_ramht_insert(chan, vram_h, vram);
+       nouveau_gpuobj_ref(NULL, &vram);
        if (ret) {
-               NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", ret);
+               NV_ERROR(dev, "Error adding VRAM ctxdma to RAMHT: %d\n", ret);
                return ret;
        }
 
        /* TT memory ctxdma */
        if (dev_priv->card_type >= NV_50) {
-               tt = vram;
+               ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+                                            0, dev_priv->vm_end,
+                                            NV_DMA_ACCESS_RW,
+                                            NV_DMA_TARGET_AGP, &tt);
+               if (ret) {
+                       NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
+                       return ret;
+               }
        } else
        if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
                ret = nouveau_gpuobj_gart_dma_new(chan, 0,
@@ -1056,9 +750,10 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
                return ret;
        }
 
-       ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
+       ret = nouveau_ramht_insert(chan, tt_h, tt);
+       nouveau_gpuobj_ref(NULL, &tt);
        if (ret) {
-               NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret);
+               NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret);
                return ret;
        }
 
@@ -1070,33 +765,23 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct drm_device *dev = chan->dev;
-       struct list_head *entry, *tmp;
-       struct nouveau_gpuobj_ref *ref;
        int i;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       if (!chan->ramht_refs.next)
+       if (!chan->ramht)
                return;
 
-       list_for_each_safe(entry, tmp, &chan->ramht_refs) {
-               ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
-
-               nouveau_gpuobj_ref_del(dev, &ref);
-       }
-
-       nouveau_gpuobj_ref_del(dev, &chan->ramht);
+       nouveau_ramht_ref(NULL, &chan->ramht, chan);
 
-       nouveau_gpuobj_del(dev, &chan->vm_pd);
-       nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt);
+       nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+       nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt);
        for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
-               nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+               nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
 
        if (chan->ramin_heap.free_stack.next)
                drm_mm_takedown(&chan->ramin_heap);
-       if (chan->ramin)
-               nouveau_gpuobj_ref_del(dev, &chan->ramin);
-
+       nouveau_gpuobj_ref(NULL, &chan->ramin);
 }
 
 int
@@ -1117,17 +802,17 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
        }
 
        list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
-               if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE))
+               if (!gpuobj->im_backing)
                        continue;
 
-               gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size);
+               gpuobj->im_backing_suspend = vmalloc(gpuobj->size);
                if (!gpuobj->im_backing_suspend) {
                        nouveau_gpuobj_resume(dev);
                        return -ENOMEM;
                }
 
-               for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
-                       gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
+               for (i = 0; i < gpuobj->size; i += 4)
+                       gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
        }
 
        return 0;
@@ -1172,8 +857,8 @@ nouveau_gpuobj_resume(struct drm_device *dev)
                if (!gpuobj->im_backing_suspend)
                        continue;
 
-               for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
-                       nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
+               for (i = 0; i < gpuobj->size; i += 4)
+                       nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
                dev_priv->engine.instmem.flush(dev);
        }
 
@@ -1208,25 +893,24 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
                return -EPERM;
        }
 
-       if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
+       if (nouveau_ramht_find(chan, init->handle))
                return -EEXIST;
 
        if (!grc->software)
                ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
        else
                ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
-
        if (ret) {
                NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
                         ret, init->channel, init->handle);
                return ret;
        }
 
-       ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL);
+       ret = nouveau_ramht_insert(chan, init->handle, gr);
+       nouveau_gpuobj_ref(NULL, &gr);
        if (ret) {
                NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
                         ret, init->channel, init->handle);
-               nouveau_gpuobj_del(dev, &gr);
                return ret;
        }
 
@@ -1237,16 +921,62 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
        struct drm_nouveau_gpuobj_free *objfree = data;
-       struct nouveau_gpuobj_ref *ref;
+       struct nouveau_gpuobj *gpuobj;
        struct nouveau_channel *chan;
-       int ret;
 
        NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
 
-       ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
-       if (ret)
-               return ret;
-       nouveau_gpuobj_ref_del(dev, &ref);
+       gpuobj = nouveau_ramht_find(chan, objfree->handle);
+       if (!gpuobj)
+               return -ENOENT;
 
+       nouveau_ramht_remove(chan, objfree->handle);
        return 0;
 }
+
+u32
+nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+       struct drm_device *dev = gpuobj->dev;
+
+       if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+               u64  ptr = gpuobj->vinst + offset;
+               u32 base = ptr >> 16;
+               u32  val;
+
+               spin_lock(&dev_priv->ramin_lock);
+               if (dev_priv->ramin_base != base) {
+                       dev_priv->ramin_base = base;
+                       nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+               }
+               val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
+               spin_unlock(&dev_priv->ramin_lock);
+               return val;
+       }
+
+       return nv_ri32(dev, gpuobj->pinst + offset);
+}
+
+void
+nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
+{
+       struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+       struct drm_device *dev = gpuobj->dev;
+
+       if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+               u64  ptr = gpuobj->vinst + offset;
+               u32 base = ptr >> 16;
+
+               spin_lock(&dev_priv->ramin_lock);
+               if (dev_priv->ramin_base != base) {
+                       dev_priv->ramin_base = base;
+                       nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+               }
+               nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
+               spin_unlock(&dev_priv->ramin_lock);
+               return;
+       }
+
+       nv_wi32(dev, gpuobj->pinst + offset, val);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
new file mode 100644 (file)
index 0000000..ac62a1b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static void
+legacy_perf_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       char *perf, *entry, *bmp = &bios->data[bios->offset];
+       int headerlen, use_straps;
+
+       if (bmp[5] < 0x5 || bmp[6] < 0x14) {
+               NV_DEBUG(dev, "BMP version too old for perf\n");
+               return;
+       }
+
+       perf = ROMPTR(bios, bmp[0x73]);
+       if (!perf) {
+               NV_DEBUG(dev, "No memclock table pointer found.\n");
+               return;
+       }
+
+       switch (perf[0]) {
+       case 0x12:
+       case 0x14:
+       case 0x18:
+               use_straps = 0;
+               headerlen = 1;
+               break;
+       case 0x01:
+               use_straps = perf[1] & 1;
+               headerlen = (use_straps ? 8 : 2);
+               break;
+       default:
+               NV_WARN(dev, "Unknown memclock table version %x.\n", perf[0]);
+               return;
+       }
+
+       entry = perf + headerlen;
+       if (use_straps)
+               entry += (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
+
+       sprintf(pm->perflvl[0].name, "performance_level_0");
+       pm->perflvl[0].memory = ROM16(entry[0]) * 20;
+       pm->nr_perflvl = 1;
+}
+
+void
+nouveau_perf_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct bit_entry P;
+       u8 version, headerlen, recordlen, entries;
+       u8 *perf, *entry;
+       int vid, i;
+
+       if (bios->type == NVBIOS_BIT) {
+               if (bit_table(dev, 'P', &P))
+                       return;
+
+               if (P.version != 1 && P.version != 2) {
+                       NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
+                       return;
+               }
+
+               perf = ROMPTR(bios, P.data[0]);
+               version   = perf[0];
+               headerlen = perf[1];
+               if (version < 0x40) {
+                       recordlen = perf[3] + (perf[4] * perf[5]);
+                       entries   = perf[2];
+               } else {
+                       recordlen = perf[2] + (perf[3] * perf[4]);
+                       entries   = perf[5];
+               }
+       } else {
+               if (bios->data[bios->offset + 6] < 0x25) {
+                       legacy_perf_init(dev);
+                       return;
+               }
+
+               perf = ROMPTR(bios, bios->data[bios->offset + 0x94]);
+               if (!perf) {
+                       NV_DEBUG(dev, "perf table pointer invalid\n");
+                       return;
+               }
+
+               version   = perf[1];
+               headerlen = perf[0];
+               recordlen = perf[3];
+               entries   = perf[2];
+       }
+
+       entry = perf + headerlen;
+       for (i = 0; i < entries; i++) {
+               struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+
+               if (entry[0] == 0xff) {
+                       entry += recordlen;
+                       continue;
+               }
+
+               switch (version) {
+               case 0x12:
+               case 0x13:
+               case 0x15:
+                       perflvl->fanspeed = entry[55];
+                       perflvl->voltage = entry[56];
+                       perflvl->core = ROM32(entry[1]) * 10;
+                       perflvl->memory = ROM32(entry[5]) * 20;
+                       break;
+               case 0x21:
+               case 0x23:
+               case 0x24:
+                       perflvl->fanspeed = entry[4];
+                       perflvl->voltage = entry[5];
+                       perflvl->core = ROM16(entry[6]) * 1000;
+
+                       if (dev_priv->chipset == 0x49 ||
+                           dev_priv->chipset == 0x4b)
+                               perflvl->memory = ROM16(entry[11]) * 1000;
+                       else
+                               perflvl->memory = ROM16(entry[11]) * 2000;
+
+                       break;
+               case 0x25:
+                       perflvl->fanspeed = entry[4];
+                       perflvl->voltage = entry[5];
+                       perflvl->core = ROM16(entry[6]) * 1000;
+                       perflvl->shader = ROM16(entry[10]) * 1000;
+                       perflvl->memory = ROM16(entry[12]) * 1000;
+                       break;
+               case 0x30:
+                       perflvl->memscript = ROM16(entry[2]);
+               case 0x35:
+                       perflvl->fanspeed = entry[6];
+                       perflvl->voltage = entry[7];
+                       perflvl->core = ROM16(entry[8]) * 1000;
+                       perflvl->shader = ROM16(entry[10]) * 1000;
+                       perflvl->memory = ROM16(entry[12]) * 1000;
+                       /*XXX: confirm on 0x35 */
+                       perflvl->unk05 = ROM16(entry[16]) * 1000;
+                       break;
+               case 0x40:
+#define subent(n) entry[perf[2] + ((n) * perf[3])]
+                       perflvl->fanspeed = 0; /*XXX*/
+                       perflvl->voltage = entry[2];
+                       perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
+                       perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
+                       perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+                       break;
+               }
+
+               /* make sure vid is valid */
+               if (pm->voltage.supported && perflvl->voltage) {
+                       vid = nouveau_volt_vid_lookup(dev, perflvl->voltage);
+                       if (vid < 0) {
+                               NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
+                               entry += recordlen;
+                               continue;
+                       }
+               }
+
+               snprintf(perflvl->name, sizeof(perflvl->name),
+                        "performance_level_%d", i);
+               perflvl->id = i;
+               pm->nr_perflvl++;
+
+               entry += recordlen;
+       }
+}
+
+void
+nouveau_perf_fini(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
new file mode 100644 (file)
index 0000000..1c99c55
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static int
+nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+                    u8 id, u32 khz)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       void *pre_state;
+
+       if (khz == 0)
+               return 0;
+
+       pre_state = pm->clock_pre(dev, perflvl, id, khz);
+       if (IS_ERR(pre_state))
+               return PTR_ERR(pre_state);
+
+       if (pre_state)
+               pm->clock_set(dev, pre_state);
+       return 0;
+}
+
+static int
+nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       int ret;
+
+       if (perflvl == pm->cur)
+               return 0;
+
+       if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
+               ret = pm->voltage_set(dev, perflvl->voltage);
+               if (ret) {
+                       NV_ERROR(dev, "voltage_set %d failed: %d\n",
+                                perflvl->voltage, ret);
+               }
+       }
+
+       nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core);
+       nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader);
+       nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory);
+       nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05);
+
+       pm->cur = perflvl;
+       return 0;
+}
+
+static int
+nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_level *perflvl = NULL;
+
+       /* safety precaution, for now */
+       if (nouveau_perflvl_wr != 7777)
+               return -EPERM;
+
+       if (!pm->clock_set)
+               return -EINVAL;
+
+       if (!strncmp(profile, "boot", 4))
+               perflvl = &pm->boot;
+       else {
+               int pl = simple_strtol(profile, NULL, 10);
+               int i;
+
+               for (i = 0; i < pm->nr_perflvl; i++) {
+                       if (pm->perflvl[i].id == pl) {
+                               perflvl = &pm->perflvl[i];
+                               break;
+                       }
+               }
+
+               if (!perflvl)
+                       return -EINVAL;
+       }
+
+       NV_INFO(dev, "setting performance level: %s\n", profile);
+       return nouveau_pm_perflvl_set(dev, perflvl);
+}
+
+static int
+nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       int ret;
+
+       if (!pm->clock_get)
+               return -EINVAL;
+
+       memset(perflvl, 0, sizeof(*perflvl));
+
+       ret = pm->clock_get(dev, PLL_CORE);
+       if (ret > 0)
+               perflvl->core = ret;
+
+       ret = pm->clock_get(dev, PLL_MEMORY);
+       if (ret > 0)
+               perflvl->memory = ret;
+
+       ret = pm->clock_get(dev, PLL_SHADER);
+       if (ret > 0)
+               perflvl->shader = ret;
+
+       ret = pm->clock_get(dev, PLL_UNK05);
+       if (ret > 0)
+               perflvl->unk05 = ret;
+
+       if (pm->voltage.supported && pm->voltage_get) {
+               ret = pm->voltage_get(dev);
+               if (ret > 0)
+                       perflvl->voltage = ret;
+       }
+
+       return 0;
+}
+
+static void
+nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+{
+       char c[16], s[16], v[16], f[16];
+
+       c[0] = '\0';
+       if (perflvl->core)
+               snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000);
+
+       s[0] = '\0';
+       if (perflvl->shader)
+               snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
+
+       v[0] = '\0';
+       if (perflvl->voltage)
+               snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10);
+
+       f[0] = '\0';
+       if (perflvl->fanspeed)
+               snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
+
+       snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
+                c, s, v, f);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl_info(struct device *d,
+                           struct device_attribute *a, char *buf)
+{
+       struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a;
+       char *ptr = buf;
+       int len = PAGE_SIZE;
+
+       snprintf(ptr, len, "%d: ", perflvl->id);
+       ptr += strlen(buf);
+       len -= strlen(buf);
+
+       nouveau_pm_perflvl_info(perflvl, ptr, len);
+       return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_level cur;
+       int len = PAGE_SIZE, ret;
+       char *ptr = buf;
+
+       if (!pm->cur)
+               snprintf(ptr, len, "setting: boot\n");
+       else if (pm->cur == &pm->boot)
+               snprintf(ptr, len, "setting: boot\nc: ");
+       else
+               snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id);
+       ptr += strlen(buf);
+       len -= strlen(buf);
+
+       ret = nouveau_pm_perflvl_get(dev, &cur);
+       if (ret == 0)
+               nouveau_pm_perflvl_info(&cur, ptr, len);
+       return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
+                      const char *buf, size_t count)
+{
+       struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+       int ret;
+
+       ret = nouveau_pm_profile_set(dev, buf);
+       if (ret)
+               return ret;
+       return strlen(buf);
+}
+
+static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
+                  nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
+
+static int
+nouveau_sysfs_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct device *d = &dev->pdev->dev;
+       int ret, i;
+
+       ret = device_create_file(d, &dev_attr_performance_level);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < pm->nr_perflvl; i++) {
+               struct nouveau_pm_level *perflvl = &pm->perflvl[i];
+
+               perflvl->dev_attr.attr.name = perflvl->name;
+               perflvl->dev_attr.attr.mode = S_IRUGO;
+               perflvl->dev_attr.show = nouveau_pm_get_perflvl_info;
+               perflvl->dev_attr.store = NULL;
+               sysfs_attr_init(&perflvl->dev_attr.attr);
+
+               ret = device_create_file(d, &perflvl->dev_attr);
+               if (ret) {
+                       NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n",
+                                perflvl->id, i);
+                       perflvl->dev_attr.attr.name = NULL;
+                       nouveau_pm_fini(dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void
+nouveau_sysfs_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct device *d = &dev->pdev->dev;
+       int i;
+
+       device_remove_file(d, &dev_attr_performance_level);
+       for (i = 0; i < pm->nr_perflvl; i++) {
+               struct nouveau_pm_level *pl = &pm->perflvl[i];
+
+               if (!pl->dev_attr.attr.name)
+                       break;
+
+               device_remove_file(d, &pl->dev_attr);
+       }
+}
+
+static ssize_t
+nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
+                                                 NULL, 0);
+
+static ssize_t
+nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
+}
+static ssize_t
+nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
+                                               const char *buf, size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       long value;
+
+       if (strict_strtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       temp->down_clock = value/1000;
+
+       nouveau_temp_safety_checks(dev);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
+                                                 nouveau_hwmon_set_max_temp,
+                                                 0);
+
+static ssize_t
+nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
+                                                       char *buf)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
+}
+static ssize_t
+nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
+                                                           const char *buf,
+                                                               size_t count)
+{
+       struct drm_device *dev = dev_get_drvdata(d);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+       long value;
+
+       if (strict_strtol(buf, 10, &value) == -EINVAL)
+               return count;
+
+       temp->critical = value/1000;
+
+       nouveau_temp_safety_checks(dev);
+
+       return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+                                               nouveau_hwmon_critical_temp,
+                                               nouveau_hwmon_set_critical_temp,
+                                               0);
+
+static ssize_t nouveau_hwmon_show_name(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "nouveau\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
+
+static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "1000\n");
+}
+static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
+                                               nouveau_hwmon_show_update_rate,
+                                               NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_name.dev_attr.attr,
+       &sensor_dev_attr_update_rate.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group hwmon_attrgroup = {
+       .attrs = hwmon_attributes,
+};
+
+static int
+nouveau_hwmon_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct device *hwmon_dev;
+       int ret;
+
+       if (!pm->temp_get)
+               return -ENODEV;
+
+       hwmon_dev = hwmon_device_register(&dev->pdev->dev);
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
+               NV_ERROR(dev,
+                       "Unable to register hwmon device: %d\n", ret);
+               return ret;
+       }
+       dev_set_drvdata(hwmon_dev, dev);
+       ret = sysfs_create_group(&hwmon_dev->kobj,
+                                       &hwmon_attrgroup);
+       if (ret) {
+               NV_ERROR(dev,
+                       "Unable to create hwmon sysfs file: %d\n", ret);
+               hwmon_device_unregister(hwmon_dev);
+               return ret;
+       }
+
+       pm->hwmon = hwmon_dev;
+
+       return 0;
+}
+
+static void
+nouveau_hwmon_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+       if (pm->hwmon) {
+               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
+               hwmon_device_unregister(pm->hwmon);
+       }
+}
+
+int
+nouveau_pm_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       char info[256];
+       int ret, i;
+
+       nouveau_volt_init(dev);
+       nouveau_perf_init(dev);
+       nouveau_temp_init(dev);
+       nouveau_mem_timing_init(dev);
+
+       NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
+       for (i = 0; i < pm->nr_perflvl; i++) {
+               nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
+               NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info);
+       }
+
+       /* determine current ("boot") performance level */
+       ret = nouveau_pm_perflvl_get(dev, &pm->boot);
+       if (ret == 0) {
+               pm->cur = &pm->boot;
+
+               nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+               NV_INFO(dev, "c: %s", info);
+       }
+
+       /* switch performance levels now if requested */
+       if (nouveau_perflvl != NULL) {
+               ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
+               if (ret) {
+                       NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
+                                nouveau_perflvl, ret);
+               }
+       }
+
+       nouveau_sysfs_init(dev);
+       nouveau_hwmon_init(dev);
+
+       return 0;
+}
+
+void
+nouveau_pm_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+       if (pm->cur != &pm->boot)
+               nouveau_pm_perflvl_set(dev, &pm->boot);
+
+       nouveau_mem_timing_fini(dev);
+       nouveau_temp_fini(dev);
+       nouveau_perf_fini(dev);
+       nouveau_volt_fini(dev);
+
+       nouveau_hwmon_fini(dev);
+       nouveau_sysfs_fini(dev);
+}
+
+void
+nouveau_pm_resume(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_level *perflvl;
+
+       if (pm->cur == &pm->boot)
+               return;
+
+       perflvl = pm->cur;
+       pm->cur = &pm->boot;
+       nouveau_pm_perflvl_set(dev, perflvl);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
new file mode 100644 (file)
index 0000000..4a9838d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_PM_H__
+#define __NOUVEAU_PM_H__
+
+/* nouveau_pm.c */
+int  nouveau_pm_init(struct drm_device *dev);
+void nouveau_pm_fini(struct drm_device *dev);
+void nouveau_pm_resume(struct drm_device *dev);
+
+/* nouveau_volt.c */
+void nouveau_volt_init(struct drm_device *);
+void nouveau_volt_fini(struct drm_device *);
+int  nouveau_volt_vid_lookup(struct drm_device *, int voltage);
+int  nouveau_volt_lvl_lookup(struct drm_device *, int vid);
+int  nouveau_voltage_gpio_get(struct drm_device *);
+int  nouveau_voltage_gpio_set(struct drm_device *, int voltage);
+
+/* nouveau_perf.c */
+void nouveau_perf_init(struct drm_device *);
+void nouveau_perf_fini(struct drm_device *);
+
+/* nouveau_mem.c */
+void nouveau_mem_timing_init(struct drm_device *);
+void nouveau_mem_timing_fini(struct drm_device *);
+
+/* nv04_pm.c */
+int nv04_pm_clock_get(struct drm_device *, u32 id);
+void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+                       u32 id, int khz);
+void nv04_pm_clock_set(struct drm_device *, void *);
+
+/* nv50_pm.c */
+int nv50_pm_clock_get(struct drm_device *, u32 id);
+void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+                       u32 id, int khz);
+void nv50_pm_clock_set(struct drm_device *, void *);
+
+/* nva3_pm.c */
+int nva3_pm_clock_get(struct drm_device *, u32 id);
+void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+                       u32 id, int khz);
+void nva3_pm_clock_set(struct drm_device *, void *);
+
+/* nouveau_temp.c */
+void nouveau_temp_init(struct drm_device *dev);
+void nouveau_temp_fini(struct drm_device *dev);
+void nouveau_temp_safety_checks(struct drm_device *dev);
+int nv40_temp_get(struct drm_device *dev);
+int nv84_temp_get(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
new file mode 100644 (file)
index 0000000..7f16697
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+static u32
+nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_ramht *ramht = chan->ramht;
+       u32 hash = 0;
+       int i;
+
+       NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
+
+       for (i = 32; i > 0; i -= ramht->bits) {
+               hash ^= (handle & ((1 << ramht->bits) - 1));
+               handle >>= ramht->bits;
+       }
+
+       if (dev_priv->card_type < NV_50)
+               hash ^= chan->id << (ramht->bits - 4);
+       hash <<= 3;
+
+       NV_DEBUG(dev, "hash=0x%08x\n", hash);
+       return hash;
+}
+
+static int
+nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
+                         u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u32 ctx = nv_ro32(ramht, offset + 4);
+
+       if (dev_priv->card_type < NV_40)
+               return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
+       return (ctx != 0);
+}
+
+static int
+nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
+                                struct nouveau_gpuobj *ramht, u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       u32 ctx = nv_ro32(ramht, offset + 4);
+
+       if (dev_priv->card_type >= NV_50)
+               return true;
+       else if (dev_priv->card_type >= NV_40)
+               return chan->id ==
+                       ((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+       else
+               return chan->id ==
+                       ((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+}
+
+int
+nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
+                    struct nouveau_gpuobj *gpuobj)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+       struct nouveau_ramht_entry *entry;
+       struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+       unsigned long flags;
+       u32 ctx, co, ho;
+
+       if (nouveau_ramht_find(chan, handle))
+               return -EEXIST;
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+       entry->channel = chan;
+       entry->gpuobj = NULL;
+       entry->handle = handle;
+       nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
+
+       if (dev_priv->card_type < NV_40) {
+               ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
+                     (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+                     (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
+       } else
+       if (dev_priv->card_type < NV_50) {
+               ctx = (gpuobj->cinst >> 4) |
+                     (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+                     (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
+       } else {
+               if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
+                       ctx = (gpuobj->cinst << 10) | 2;
+               } else {
+                       ctx = (gpuobj->cinst >> 4) |
+                             ((gpuobj->engine <<
+                               NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
+               }
+       }
+
+       spin_lock_irqsave(&chan->ramht->lock, flags);
+       list_add(&entry->head, &chan->ramht->entries);
+
+       co = ho = nouveau_ramht_hash_handle(chan, handle);
+       do {
+               if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
+                       NV_DEBUG(dev,
+                                "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+                                chan->id, co, handle, ctx);
+                       nv_wo32(ramht, co + 0, handle);
+                       nv_wo32(ramht, co + 4, ctx);
+
+                       spin_unlock_irqrestore(&chan->ramht->lock, flags);
+                       instmem->flush(dev);
+                       return 0;
+               }
+               NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
+                        chan->id, co, nv_ro32(ramht, co));
+
+               co += 8;
+               if (co >= ramht->size)
+                       co = 0;
+       } while (co != ho);
+
+       NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
+       list_del(&entry->head);
+       spin_unlock_irqrestore(&chan->ramht->lock, flags);
+       kfree(entry);
+       return -ENOMEM;
+}
+
+static void
+nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+       struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+       struct nouveau_ramht_entry *entry, *tmp;
+       u32 co, ho;
+
+       list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
+               if (entry->channel != chan || entry->handle != handle)
+                       continue;
+
+               nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+               list_del(&entry->head);
+               kfree(entry);
+               break;
+       }
+
+       co = ho = nouveau_ramht_hash_handle(chan, handle);
+       do {
+               if (nouveau_ramht_entry_valid(dev, ramht, co) &&
+                   nouveau_ramht_entry_same_channel(chan, ramht, co) &&
+                   (handle == nv_ro32(ramht, co))) {
+                       NV_DEBUG(dev,
+                                "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+                                chan->id, co, handle, nv_ro32(ramht, co + 4));
+                       nv_wo32(ramht, co + 0, 0x00000000);
+                       nv_wo32(ramht, co + 4, 0x00000000);
+                       instmem->flush(dev);
+                       return;
+               }
+
+               co += 8;
+               if (co >= ramht->size)
+                       co = 0;
+       } while (co != ho);
+
+       NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
+                chan->id, handle);
+}
+
+void
+nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
+{
+       struct nouveau_ramht *ramht = chan->ramht;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ramht->lock, flags);
+       nouveau_ramht_remove_locked(chan, handle);
+       spin_unlock_irqrestore(&ramht->lock, flags);
+}
+
+struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
+{
+       struct nouveau_ramht *ramht = chan->ramht;
+       struct nouveau_ramht_entry *entry;
+       struct nouveau_gpuobj *gpuobj = NULL;
+       unsigned long flags;
+
+       if (unlikely(!chan->ramht))
+               return NULL;
+
+       spin_lock_irqsave(&ramht->lock, flags);
+       list_for_each_entry(entry, &chan->ramht->entries, head) {
+               if (entry->channel == chan && entry->handle == handle) {
+                       gpuobj = entry->gpuobj;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&ramht->lock, flags);
+
+       return gpuobj;
+}
+
+int
+nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+                 struct nouveau_ramht **pramht)
+{
+       struct nouveau_ramht *ramht;
+
+       ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
+       if (!ramht)
+               return -ENOMEM;
+
+       ramht->dev = dev;
+       kref_init(&ramht->refcount);
+       ramht->bits = drm_order(gpuobj->size / 8);
+       INIT_LIST_HEAD(&ramht->entries);
+       spin_lock_init(&ramht->lock);
+       nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
+
+       *pramht = ramht;
+       return 0;
+}
+
+static void
+nouveau_ramht_del(struct kref *ref)
+{
+       struct nouveau_ramht *ramht =
+               container_of(ref, struct nouveau_ramht, refcount);
+
+       nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
+       kfree(ramht);
+}
+
+void
+nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
+                 struct nouveau_channel *chan)
+{
+       struct nouveau_ramht_entry *entry, *tmp;
+       struct nouveau_ramht *ramht;
+       unsigned long flags;
+
+       if (ref)
+               kref_get(&ref->refcount);
+
+       ramht = *ptr;
+       if (ramht) {
+               spin_lock_irqsave(&ramht->lock, flags);
+               list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
+                       if (entry->channel != chan)
+                               continue;
+
+                       nouveau_ramht_remove_locked(chan, entry->handle);
+               }
+               spin_unlock_irqrestore(&ramht->lock, flags);
+
+               kref_put(&ramht->refcount, nouveau_ramht_del);
+       }
+       *ptr = ref;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h
new file mode 100644 (file)
index 0000000..b79cb5e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_RAMHT_H__
+#define __NOUVEAU_RAMHT_H__
+
+struct nouveau_ramht_entry {
+       struct list_head head;
+       struct nouveau_channel *channel;
+       struct nouveau_gpuobj *gpuobj;
+       u32 handle;
+};
+
+struct nouveau_ramht {
+       struct drm_device *dev;
+       struct kref refcount;
+       spinlock_t lock;
+       struct nouveau_gpuobj *gpuobj;
+       struct list_head entries;
+       int bits;
+};
+
+extern int  nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *,
+                             struct nouveau_ramht **);
+extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
+                             struct nouveau_channel *unref_channel);
+
+extern int  nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
+                                struct nouveau_gpuobj *);
+extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
+extern struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
+
+#endif
index 21a6e453b975afb741a1fdb1f288533b20f3d071..1b42541ca9e5144f3dbf4355a91b1ef12fbf8e14 100644 (file)
 #define NV10_PFIFO_CACHE1_DMA_SUBROUTINE                   0x0000324C
 #define NV03_PFIFO_CACHE1_PULL0                            0x00003240
 #define NV04_PFIFO_CACHE1_PULL0                            0x00003250
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED            0x00000010
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY              0x00001000
 #define NV03_PFIFO_CACHE1_PULL1                            0x00003250
 #define NV04_PFIFO_CACHE1_PULL1                            0x00003254
 #define NV04_PFIFO_CACHE1_HASH                             0x00003258
 #define NV50_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
 #define NV50_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610b70 + (i) * 0x8)
 #define NV50_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610b74 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_P(i)                (0x00610b80 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_C(i)                (0x00610b84 + (i) * 0x8)
 #define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610bdc + (i) * 0x8)
 #define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610be0 + (i) * 0x8)
-
 #define NV90_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610794 + (i) * 0x8)
 #define NV90_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610798 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i)                (0x00610b58 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610b80 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610b84 + (i) * 0x8)
 
 #define NV50_PDISPLAY_CRTC_CLK                                       0x00614000
 #define NV50_PDISPLAY_CRTC_CLK_CTRL1(i)                 ((i) * 0x800 + 0x614100)
index 6b9187d7f67de4383502973ef5cdfc9259ec6f1a..288bacac7e5aefc2f3c6c9b4f461a7e48d6e9ce7 100644 (file)
@@ -95,9 +95,9 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
        struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
        unsigned i, j, pte;
 
-       NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
+       NV_DEBUG(dev, "pg=0x%lx\n", mem->start);
 
-       pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
+       pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT);
        nvbe->pte_start = pte;
        for (i = 0; i < nvbe->nr_pages; i++) {
                dma_addr_t dma_offset = nvbe->pages[i];
@@ -105,11 +105,13 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
                uint32_t offset_h = upper_32_bits(dma_offset);
 
                for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
-                       if (dev_priv->card_type < NV_50)
-                               nv_wo32(dev, gpuobj, pte++, offset_l | 3);
-                       else {
-                               nv_wo32(dev, gpuobj, pte++, offset_l | 0x21);
-                               nv_wo32(dev, gpuobj, pte++, offset_h & 0xff);
+                       if (dev_priv->card_type < NV_50) {
+                               nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
+                               pte += 1;
+                       } else {
+                               nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21);
+                               nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff);
+                               pte += 2;
                        }
 
                        dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -145,11 +147,13 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
                dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
 
                for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
-                       if (dev_priv->card_type < NV_50)
-                               nv_wo32(dev, gpuobj, pte++, dma_offset | 3);
-                       else {
-                               nv_wo32(dev, gpuobj, pte++, dma_offset | 0x21);
-                               nv_wo32(dev, gpuobj, pte++, 0x00000000);
+                       if (dev_priv->card_type < NV_50) {
+                               nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3);
+                               pte += 1;
+                       } else {
+                               nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
+                               nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000);
+                               pte += 2;
                        }
 
                        dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -230,7 +234,6 @@ nouveau_sgdma_init(struct drm_device *dev)
        }
 
        ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
-                                     NVOBJ_FLAG_ALLOW_NO_REFS |
                                      NVOBJ_FLAG_ZERO_ALLOC |
                                      NVOBJ_FLAG_ZERO_FREE, &gpuobj);
        if (ret) {
@@ -239,9 +242,9 @@ nouveau_sgdma_init(struct drm_device *dev)
        }
 
        dev_priv->gart_info.sg_dummy_page =
-               alloc_page(GFP_KERNEL|__GFP_DMA32);
+               alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO);
        if (!dev_priv->gart_info.sg_dummy_page) {
-               nouveau_gpuobj_del(dev, &gpuobj);
+               nouveau_gpuobj_ref(NULL, &gpuobj);
                return -ENOMEM;
        }
 
@@ -250,29 +253,34 @@ nouveau_sgdma_init(struct drm_device *dev)
                pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
                             PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
        if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
-               nouveau_gpuobj_del(dev, &gpuobj);
+               nouveau_gpuobj_ref(NULL, &gpuobj);
                return -EFAULT;
        }
 
        if (dev_priv->card_type < NV_50) {
+               /* special case, allocated from global instmem heap so
+                * cinst is invalid, we use it on all channels though so
+                * cinst needs to be valid, set it the same as pinst
+                */
+               gpuobj->cinst = gpuobj->pinst;
+
                /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
                 * confirmed to work on c51.  Perhaps means NV_DMA_TARGET_PCIE
                 * on those cards? */
-               nv_wo32(dev, gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
-                                      (1 << 12) /* PT present */ |
-                                      (0 << 13) /* PT *not* linear */ |
-                                      (NV_DMA_ACCESS_RW  << 14) |
-                                      (NV_DMA_TARGET_PCI << 16));
-               nv_wo32(dev, gpuobj, 1, aper_size - 1);
+               nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
+                                  (1 << 12) /* PT present */ |
+                                  (0 << 13) /* PT *not* linear */ |
+                                  (NV_DMA_ACCESS_RW  << 14) |
+                                  (NV_DMA_TARGET_PCI << 16));
+               nv_wo32(gpuobj, 4, aper_size - 1);
                for (i = 2; i < 2 + (aper_size >> 12); i++) {
-                       nv_wo32(dev, gpuobj, i,
-                                   dev_priv->gart_info.sg_dummy_bus | 3);
+                       nv_wo32(gpuobj, i * 4,
+                               dev_priv->gart_info.sg_dummy_bus | 3);
                }
        } else {
                for (i = 0; i < obj_size; i += 8) {
-                       nv_wo32(dev, gpuobj, (i+0)/4,
-                                   dev_priv->gart_info.sg_dummy_bus | 0x21);
-                       nv_wo32(dev, gpuobj, (i+4)/4, 0);
+                       nv_wo32(gpuobj, i + 0, 0x00000000);
+                       nv_wo32(gpuobj, i + 4, 0x00000000);
                }
        }
        dev_priv->engine.instmem.flush(dev);
@@ -298,7 +306,7 @@ nouveau_sgdma_takedown(struct drm_device *dev)
                dev_priv->gart_info.sg_dummy_bus = 0;
        }
 
-       nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma);
+       nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
 }
 
 int
@@ -308,9 +316,9 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
        struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
        int pte;
 
-       pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
+       pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2;
        if (dev_priv->card_type < NV_50) {
-               *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
+               *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK;
                return 0;
        }
 
index 989322be37287af5f4ba555fd7041889222365fd..ed7757f14083a17e3122250ca83aa8ee2959ddec 100644 (file)
@@ -35,6 +35,8 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
+#include "nouveau_pm.h"
 #include "nv50_display.h"
 
 static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -78,7 +80,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.disable            = nv04_fifo_disable;
                engine->fifo.enable             = nv04_fifo_enable;
                engine->fifo.reassign           = nv04_fifo_reassign;
-               engine->fifo.cache_flush        = nv04_fifo_cache_flush;
                engine->fifo.cache_pull         = nv04_fifo_cache_pull;
                engine->fifo.channel_id         = nv04_fifo_channel_id;
                engine->fifo.create_context     = nv04_fifo_create_context;
@@ -95,6 +96,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = NULL;
                engine->gpio.set                = NULL;
                engine->gpio.irq_enable         = NULL;
+               engine->pm.clock_get            = nv04_pm_clock_get;
+               engine->pm.clock_pre            = nv04_pm_clock_pre;
+               engine->pm.clock_set            = nv04_pm_clock_set;
                break;
        case 0x10:
                engine->instmem.init            = nv04_instmem_init;
@@ -130,7 +134,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.disable            = nv04_fifo_disable;
                engine->fifo.enable             = nv04_fifo_enable;
                engine->fifo.reassign           = nv04_fifo_reassign;
-               engine->fifo.cache_flush        = nv04_fifo_cache_flush;
                engine->fifo.cache_pull         = nv04_fifo_cache_pull;
                engine->fifo.channel_id         = nv10_fifo_channel_id;
                engine->fifo.create_context     = nv10_fifo_create_context;
@@ -147,6 +150,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv10_gpio_get;
                engine->gpio.set                = nv10_gpio_set;
                engine->gpio.irq_enable         = NULL;
+               engine->pm.clock_get            = nv04_pm_clock_get;
+               engine->pm.clock_pre            = nv04_pm_clock_pre;
+               engine->pm.clock_set            = nv04_pm_clock_set;
                break;
        case 0x20:
                engine->instmem.init            = nv04_instmem_init;
@@ -182,7 +188,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.disable            = nv04_fifo_disable;
                engine->fifo.enable             = nv04_fifo_enable;
                engine->fifo.reassign           = nv04_fifo_reassign;
-               engine->fifo.cache_flush        = nv04_fifo_cache_flush;
                engine->fifo.cache_pull         = nv04_fifo_cache_pull;
                engine->fifo.channel_id         = nv10_fifo_channel_id;
                engine->fifo.create_context     = nv10_fifo_create_context;
@@ -199,6 +204,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv10_gpio_get;
                engine->gpio.set                = nv10_gpio_set;
                engine->gpio.irq_enable         = NULL;
+               engine->pm.clock_get            = nv04_pm_clock_get;
+               engine->pm.clock_pre            = nv04_pm_clock_pre;
+               engine->pm.clock_set            = nv04_pm_clock_set;
                break;
        case 0x30:
                engine->instmem.init            = nv04_instmem_init;
@@ -234,7 +242,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.disable            = nv04_fifo_disable;
                engine->fifo.enable             = nv04_fifo_enable;
                engine->fifo.reassign           = nv04_fifo_reassign;
-               engine->fifo.cache_flush        = nv04_fifo_cache_flush;
                engine->fifo.cache_pull         = nv04_fifo_cache_pull;
                engine->fifo.channel_id         = nv10_fifo_channel_id;
                engine->fifo.create_context     = nv10_fifo_create_context;
@@ -251,6 +258,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv10_gpio_get;
                engine->gpio.set                = nv10_gpio_set;
                engine->gpio.irq_enable         = NULL;
+               engine->pm.clock_get            = nv04_pm_clock_get;
+               engine->pm.clock_pre            = nv04_pm_clock_pre;
+               engine->pm.clock_set            = nv04_pm_clock_set;
+               engine->pm.voltage_get          = nouveau_voltage_gpio_get;
+               engine->pm.voltage_set          = nouveau_voltage_gpio_set;
                break;
        case 0x40:
        case 0x60:
@@ -287,7 +299,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.disable            = nv04_fifo_disable;
                engine->fifo.enable             = nv04_fifo_enable;
                engine->fifo.reassign           = nv04_fifo_reassign;
-               engine->fifo.cache_flush        = nv04_fifo_cache_flush;
                engine->fifo.cache_pull         = nv04_fifo_cache_pull;
                engine->fifo.channel_id         = nv10_fifo_channel_id;
                engine->fifo.create_context     = nv40_fifo_create_context;
@@ -304,6 +315,12 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv10_gpio_get;
                engine->gpio.set                = nv10_gpio_set;
                engine->gpio.irq_enable         = NULL;
+               engine->pm.clock_get            = nv04_pm_clock_get;
+               engine->pm.clock_pre            = nv04_pm_clock_pre;
+               engine->pm.clock_set            = nv04_pm_clock_set;
+               engine->pm.voltage_get          = nouveau_voltage_gpio_get;
+               engine->pm.voltage_set          = nouveau_voltage_gpio_set;
+               engine->pm.temp_get             = nv40_temp_get;
                break;
        case 0x50:
        case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -358,6 +375,27 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv50_gpio_get;
                engine->gpio.set                = nv50_gpio_set;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
+               switch (dev_priv->chipset) {
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+               case 0xaf:
+                       engine->pm.clock_get    = nva3_pm_clock_get;
+                       engine->pm.clock_pre    = nva3_pm_clock_pre;
+                       engine->pm.clock_set    = nva3_pm_clock_set;
+                       break;
+               default:
+                       engine->pm.clock_get    = nv50_pm_clock_get;
+                       engine->pm.clock_pre    = nv50_pm_clock_pre;
+                       engine->pm.clock_set    = nv50_pm_clock_set;
+                       break;
+               }
+               engine->pm.voltage_get          = nouveau_voltage_gpio_get;
+               engine->pm.voltage_set          = nouveau_voltage_gpio_set;
+               if (dev_priv->chipset >= 0x84)
+                       engine->pm.temp_get     = nv84_temp_get;
+               else
+                       engine->pm.temp_get     = nv40_temp_get;
                break;
        case 0xC0:
                engine->instmem.init            = nvc0_instmem_init;
@@ -437,16 +475,14 @@ static int
 nouveau_card_init_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *gpuobj;
+       struct nouveau_gpuobj *gpuobj = NULL;
        int ret;
 
        ret = nouveau_channel_alloc(dev, &dev_priv->channel,
-                                   (struct drm_file *)-2,
-                                   NvDmaFB, NvDmaTT);
+                                   (struct drm_file *)-2, NvDmaFB, NvDmaTT);
        if (ret)
                return ret;
 
-       gpuobj = NULL;
        ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
                                     0, dev_priv->vram_size,
                                     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
@@ -454,26 +490,25 @@ nouveau_card_init_channel(struct drm_device *dev)
        if (ret)
                goto out_err;
 
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
-                                    gpuobj, NULL);
+       ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj);
+       nouveau_gpuobj_ref(NULL, &gpuobj);
        if (ret)
                goto out_err;
 
-       gpuobj = NULL;
        ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
                                          dev_priv->gart_info.aper_size,
                                          NV_DMA_ACCESS_RW, &gpuobj, NULL);
        if (ret)
                goto out_err;
 
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
-                                    gpuobj, NULL);
+       ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj);
+       nouveau_gpuobj_ref(NULL, &gpuobj);
        if (ret)
                goto out_err;
 
        return 0;
+
 out_err:
-       nouveau_gpuobj_del(dev, &gpuobj);
        nouveau_channel_free(dev_priv->channel);
        dev_priv->channel = NULL;
        return ret;
@@ -534,35 +569,28 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_display_early;
 
-       ret = nouveau_mem_detect(dev);
+       nouveau_pm_init(dev);
+
+       ret = nouveau_mem_vram_init(dev);
        if (ret)
                goto out_bios;
 
-       ret = nouveau_gpuobj_early_init(dev);
+       ret = nouveau_gpuobj_init(dev);
        if (ret)
-               goto out_bios;
+               goto out_vram;
 
-       /* Initialise instance memory, must happen before mem_init so we
-        * know exactly how much VRAM we're able to use for "normal"
-        * purposes.
-        */
        ret = engine->instmem.init(dev);
        if (ret)
-               goto out_gpuobj_early;
+               goto out_gpuobj;
 
-       /* Setup the memory manager */
-       ret = nouveau_mem_init(dev);
+       ret = nouveau_mem_gart_init(dev);
        if (ret)
                goto out_instmem;
 
-       ret = nouveau_gpuobj_init(dev);
-       if (ret)
-               goto out_mem;
-
        /* PMC */
        ret = engine->mc.init(dev);
        if (ret)
-               goto out_gpuobj;
+               goto out_gart;
 
        /* PGPIO */
        ret = engine->gpio.init(dev);
@@ -611,9 +639,13 @@ nouveau_card_init(struct drm_device *dev)
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
        if (!engine->graph.accel_blocked) {
-               ret = nouveau_card_init_channel(dev);
+               ret = nouveau_fence_init(dev);
                if (ret)
                        goto out_irq;
+
+               ret = nouveau_card_init_channel(dev);
+               if (ret)
+                       goto out_fence;
        }
 
        ret = nouveau_backlight_init(dev);
@@ -624,6 +656,8 @@ nouveau_card_init(struct drm_device *dev)
        drm_kms_helper_poll_init(dev);
        return 0;
 
+out_fence:
+       nouveau_fence_fini(dev);
 out_irq:
        drm_irq_uninstall(dev);
 out_display:
@@ -642,16 +676,16 @@ out_gpio:
        engine->gpio.takedown(dev);
 out_mc:
        engine->mc.takedown(dev);
-out_gpuobj:
-       nouveau_gpuobj_takedown(dev);
-out_mem:
-       nouveau_sgdma_takedown(dev);
-       nouveau_mem_close(dev);
+out_gart:
+       nouveau_mem_gart_fini(dev);
 out_instmem:
        engine->instmem.takedown(dev);
-out_gpuobj_early:
-       nouveau_gpuobj_late_takedown(dev);
+out_gpuobj:
+       nouveau_gpuobj_takedown(dev);
+out_vram:
+       nouveau_mem_vram_fini(dev);
 out_bios:
+       nouveau_pm_fini(dev);
        nouveau_bios_takedown(dev);
 out_display_early:
        engine->display.late_takedown(dev);
@@ -667,7 +701,8 @@ static void nouveau_card_takedown(struct drm_device *dev)
 
        nouveau_backlight_exit(dev);
 
-       if (dev_priv->channel) {
+       if (!engine->graph.accel_blocked) {
+               nouveau_fence_fini(dev);
                nouveau_channel_free(dev_priv->channel);
                dev_priv->channel = NULL;
        }
@@ -686,15 +721,15 @@ static void nouveau_card_takedown(struct drm_device *dev)
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
        mutex_unlock(&dev->struct_mutex);
-       nouveau_sgdma_takedown(dev);
+       nouveau_mem_gart_fini(dev);
 
-       nouveau_gpuobj_takedown(dev);
-       nouveau_mem_close(dev);
        engine->instmem.takedown(dev);
+       nouveau_gpuobj_takedown(dev);
+       nouveau_mem_vram_fini(dev);
 
        drm_irq_uninstall(dev);
 
-       nouveau_gpuobj_late_takedown(dev);
+       nouveau_pm_fini(dev);
        nouveau_bios_takedown(dev);
 
        vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -1057,7 +1092,7 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout,
 /* Waits for PGRAPH to go completely idle */
 bool nouveau_wait_for_idle(struct drm_device *dev)
 {
-       if (!nv_wait(NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
+       if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
                NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
                         nv_rd32(dev, NV04_PGRAPH_STATUS));
                return false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
new file mode 100644 (file)
index 0000000..16bbbf1
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2010 PathScale inc.
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static void
+nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+       struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+       int i, headerlen, recordlen, entries;
+
+       if (!temp) {
+               NV_DEBUG(dev, "temperature table pointer invalid\n");
+               return;
+       }
+
+       /* Set the default sensor's contants */
+       sensor->offset_constant = 0;
+       sensor->offset_mult = 1;
+       sensor->offset_div = 1;
+       sensor->slope_mult = 1;
+       sensor->slope_div = 1;
+
+       /* Set the default temperature thresholds */
+       temps->critical = 110;
+       temps->down_clock = 100;
+       temps->fan_boost = 90;
+
+       /* Set the known default values to setup the temperature sensor */
+       if (dev_priv->card_type >= NV_40) {
+               switch (dev_priv->chipset) {
+               case 0x43:
+                       sensor->offset_mult = 32060;
+                       sensor->offset_div = 1000;
+                       sensor->slope_mult = 792;
+                       sensor->slope_div = 1000;
+                       break;
+
+               case 0x44:
+               case 0x47:
+               case 0x4a:
+                       sensor->offset_mult = 27839;
+                       sensor->offset_div = 1000;
+                       sensor->slope_mult = 780;
+                       sensor->slope_div = 1000;
+                       break;
+
+               case 0x46:
+                       sensor->offset_mult = -24775;
+                       sensor->offset_div = 100;
+                       sensor->slope_mult = 467;
+                       sensor->slope_div = 10000;
+                       break;
+
+               case 0x49:
+                       sensor->offset_mult = -25051;
+                       sensor->offset_div = 100;
+                       sensor->slope_mult = 458;
+                       sensor->slope_div = 10000;
+                       break;
+
+               case 0x4b:
+                       sensor->offset_mult = -24088;
+                       sensor->offset_div = 100;
+                       sensor->slope_mult = 442;
+                       sensor->slope_div = 10000;
+                       break;
+
+               case 0x50:
+                       sensor->offset_mult = -22749;
+                       sensor->offset_div = 100;
+                       sensor->slope_mult = 431;
+                       sensor->slope_div = 10000;
+                       break;
+               }
+       }
+
+       headerlen = temp[1];
+       recordlen = temp[2];
+       entries = temp[3];
+       temp = temp + headerlen;
+
+       /* Read the entries from the table */
+       for (i = 0; i < entries; i++) {
+               u16 value = ROM16(temp[1]);
+
+               switch (temp[0]) {
+               case 0x01:
+                       if ((value & 0x8f) == 0)
+                               sensor->offset_constant = (value >> 9) & 0x7f;
+                       break;
+
+               case 0x04:
+                       if ((value & 0xf00f) == 0xa000) /* core */
+                               temps->critical = (value&0x0ff0) >> 4;
+                       break;
+
+               case 0x07:
+                       if ((value & 0xf00f) == 0xa000) /* core */
+                               temps->down_clock = (value&0x0ff0) >> 4;
+                       break;
+
+               case 0x08:
+                       if ((value & 0xf00f) == 0xa000) /* core */
+                               temps->fan_boost = (value&0x0ff0) >> 4;
+                       break;
+
+               case 0x10:
+                       sensor->offset_mult = value;
+                       break;
+
+               case 0x11:
+                       sensor->offset_div = value;
+                       break;
+
+               case 0x12:
+                       sensor->slope_mult = value;
+                       break;
+
+               case 0x13:
+                       sensor->slope_div = value;
+                       break;
+               }
+               temp += recordlen;
+       }
+
+       nouveau_temp_safety_checks(dev);
+}
+
+static int
+nv40_sensor_setup(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+       u32 offset = sensor->offset_mult / sensor->offset_div;
+       u32 sensor_calibration;
+
+       /* set up the sensors */
+       sensor_calibration = 120 - offset - sensor->offset_constant;
+       sensor_calibration = sensor_calibration * sensor->slope_div /
+                               sensor->slope_mult;
+
+       if (dev_priv->chipset >= 0x46)
+               sensor_calibration |= 0x80000000;
+       else
+               sensor_calibration |= 0x10000000;
+
+       nv_wr32(dev, 0x0015b0, sensor_calibration);
+
+       /* Wait for the sensor to update */
+       msleep(5);
+
+       /* read */
+       return nv_rd32(dev, 0x0015b4) & 0x1fff;
+}
+
+int
+nv40_temp_get(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+       int offset = sensor->offset_mult / sensor->offset_div;
+       int core_temp;
+
+       if (dev_priv->chipset >= 0x50) {
+               core_temp = nv_rd32(dev, 0x20008);
+       } else {
+               core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
+               /* Setup the sensor if the temperature is 0 */
+               if (core_temp == 0)
+                       core_temp = nv40_sensor_setup(dev);
+       }
+
+       core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+       core_temp = core_temp + offset + sensor->offset_constant;
+
+       return core_temp;
+}
+
+int
+nv84_temp_get(struct drm_device *dev)
+{
+       return nv_rd32(dev, 0x20400);
+}
+
+void
+nouveau_temp_safety_checks(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+
+       if (temps->critical > 120)
+               temps->critical = 120;
+       else if (temps->critical < 80)
+               temps->critical = 80;
+
+       if (temps->down_clock > 110)
+               temps->down_clock = 110;
+       else if (temps->down_clock < 60)
+               temps->down_clock = 60;
+
+       if (temps->fan_boost > 100)
+               temps->fan_boost = 100;
+       else if (temps->fan_boost < 40)
+               temps->fan_boost = 40;
+}
+
+static bool
+probe_monitoring_device(struct nouveau_i2c_chan *i2c,
+                       struct i2c_board_info *info)
+{
+       char modalias[16] = "i2c:";
+       struct i2c_client *client;
+
+       strlcat(modalias, info->type, sizeof(modalias));
+       request_module(modalias);
+
+       client = i2c_new_device(&i2c->adapter, info);
+       if (!client)
+               return false;
+
+       if (!client->driver || client->driver->detect(client, info)) {
+               i2c_unregister_device(client);
+               return false;
+       }
+
+       return true;
+}
+
+static void
+nouveau_temp_probe_i2c(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+       struct i2c_board_info info[] = {
+               { I2C_BOARD_INFO("w83l785ts", 0x2d) },
+               { I2C_BOARD_INFO("w83781d", 0x2d) },
+               { I2C_BOARD_INFO("f75375", 0x2e) },
+               { I2C_BOARD_INFO("adt7473", 0x2e) },
+               { I2C_BOARD_INFO("lm99", 0x4c) },
+               { }
+       };
+       int idx = (dcb->version >= 0x40 ?
+                  dcb->i2c_default_indices & 0xf : 2);
+
+       nouveau_i2c_identify(dev, "monitoring device", info,
+                            probe_monitoring_device, idx);
+}
+
+void
+nouveau_temp_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct bit_entry P;
+       u8 *temp = NULL;
+
+       if (bios->type == NVBIOS_BIT) {
+               if (bit_table(dev, 'P', &P))
+                       return;
+
+               if (P.version == 1)
+                       temp = ROMPTR(bios, P.data[12]);
+               else if (P.version == 2)
+                       temp = ROMPTR(bios, P.data[16]);
+               else
+                       NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
+
+               nouveau_temp_vbios_parse(dev, temp);
+       }
+
+       nouveau_temp_probe_i2c(dev);
+}
+
+void
+nouveau_temp_fini(struct drm_device *dev)
+{
+
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
new file mode 100644 (file)
index 0000000..04fdc00
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a };
+static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
+
+int
+nouveau_voltage_gpio_get(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       u8 vid = 0;
+       int i;
+
+       for (i = 0; i < nr_vidtag; i++) {
+               if (!(volt->vid_mask & (1 << i)))
+                       continue;
+
+               vid |= gpio->get(dev, vidtag[i]) << i;
+       }
+
+       return nouveau_volt_lvl_lookup(dev, vid);
+}
+
+int
+nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       int vid, i;
+
+       vid = nouveau_volt_vid_lookup(dev, voltage);
+       if (vid < 0)
+               return vid;
+
+       for (i = 0; i < nr_vidtag; i++) {
+               if (!(volt->vid_mask & (1 << i)))
+                       continue;
+
+               gpio->set(dev, vidtag[i], !!(vid & (1 << i)));
+       }
+
+       return 0;
+}
+
+int
+nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       int i;
+
+       for (i = 0; i < volt->nr_level; i++) {
+               if (volt->level[i].voltage == voltage)
+                       return volt->level[i].vid;
+       }
+
+       return -ENOENT;
+}
+
+int
+nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+       int i;
+
+       for (i = 0; i < volt->nr_level; i++) {
+               if (volt->level[i].vid == vid)
+                       return volt->level[i].voltage;
+       }
+
+       return -ENOENT;
+}
+
+void
+nouveau_volt_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_voltage *voltage = &pm->voltage;
+       struct nvbios *bios = &dev_priv->vbios;
+       struct bit_entry P;
+       u8 *volt = NULL, *entry;
+       int i, headerlen, recordlen, entries, vidmask, vidshift;
+
+       if (bios->type == NVBIOS_BIT) {
+               if (bit_table(dev, 'P', &P))
+                       return;
+
+               if (P.version == 1)
+                       volt = ROMPTR(bios, P.data[16]);
+               else
+               if (P.version == 2)
+                       volt = ROMPTR(bios, P.data[12]);
+               else {
+                       NV_WARN(dev, "unknown volt for BIT P %d\n", P.version);
+               }
+       } else {
+               if (bios->data[bios->offset + 6] < 0x27) {
+                       NV_DEBUG(dev, "BMP version too old for voltage\n");
+                       return;
+               }
+
+               volt = ROMPTR(bios, bios->data[bios->offset + 0x98]);
+       }
+
+       if (!volt) {
+               NV_DEBUG(dev, "voltage table pointer invalid\n");
+               return;
+       }
+
+       switch (volt[0]) {
+       case 0x10:
+       case 0x11:
+       case 0x12:
+               headerlen = 5;
+               recordlen = volt[1];
+               entries   = volt[2];
+               vidshift  = 0;
+               vidmask   = volt[4];
+               break;
+       case 0x20:
+               headerlen = volt[1];
+               recordlen = volt[3];
+               entries   = volt[2];
+               vidshift  = 0; /* could be vidshift like 0x30? */
+               vidmask   = volt[5];
+               break;
+       case 0x30:
+               headerlen = volt[1];
+               recordlen = volt[2];
+               entries   = volt[3];
+               vidshift  = hweight8(volt[5]);
+               vidmask   = volt[4];
+               break;
+       default:
+               NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
+               return;
+       }
+
+       /* validate vid mask */
+       voltage->vid_mask = vidmask;
+       if (!voltage->vid_mask)
+               return;
+
+       i = 0;
+       while (vidmask) {
+               if (i > nr_vidtag) {
+                       NV_DEBUG(dev, "vid bit %d unknown\n", i);
+                       return;
+               }
+
+               if (!nouveau_bios_gpio_entry(dev, vidtag[i])) {
+                       NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i);
+                       return;
+               }
+
+               vidmask >>= 1;
+               i++;
+       }
+
+       /* parse vbios entries into common format */
+       voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
+       if (!voltage->level)
+               return;
+
+       entry = volt + headerlen;
+       for (i = 0; i < entries; i++, entry += recordlen) {
+               voltage->level[i].voltage = entry[0];
+               voltage->level[i].vid     = entry[1] >> vidshift;
+       }
+       voltage->nr_level  = entries;
+       voltage->supported = true;
+}
+
+void
+nouveau_volt_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+
+       kfree(volt->level);
+}
index 497df8765f28489c0dbaf34f0cdde137de46c80c..c71abc2a34d5d9cf22a01d3c3bf455a29c5d1dbf 100644 (file)
@@ -33,6 +33,7 @@
 #include "nouveau_fb.h"
 #include "nouveau_hw.h"
 #include "nvreg.h"
+#include "nouveau_fbcon.h"
 
 static int
 nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@ -109,7 +110,7 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
        struct nouveau_pll_vals *pv = &regp->pllvals;
        struct pll_lims pll_lim;
 
-       if (get_pll_limits(dev, nv_crtc->index ? VPLL2 : VPLL1, &pll_lim))
+       if (get_pll_limits(dev, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, &pll_lim))
                return;
 
        /* NM2 == 0 is used to determine single stage mode on two stage plls */
@@ -718,6 +719,7 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
 
        drm_crtc_cleanup(crtc);
 
+       nouveau_bo_unmap(nv_crtc->cursor.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
        kfree(nv_crtc);
 }
@@ -768,8 +770,9 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
 }
 
 static int
-nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                       struct drm_framebuffer *old_fb)
+nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
+                          struct drm_framebuffer *passed_fb,
+                          int x, int y, bool atomic)
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -780,13 +783,26 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        int arb_burst, arb_lwm;
        int ret;
 
-       ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
-       if (ret)
-               return ret;
+       /* If atomic, we want to switch to the fb we were passed, so
+        * now we update pointers to do that.  (We don't pin; just
+        * assume we're already pinned and update the base address.)
+        */
+       if (atomic) {
+               drm_fb = passed_fb;
+               fb = nouveau_framebuffer(passed_fb);
+       }
+       else {
+               /* If not atomic, we can go ahead and pin, and unpin the
+                * old fb we were passed.
+                */
+               ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       return ret;
 
-       if (old_fb) {
-               struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
-               nouveau_bo_unpin(ofb->nvbo);
+               if (passed_fb) {
+                       struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+                       nouveau_bo_unpin(ofb->nvbo);
+               }
        }
 
        nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -826,7 +842,7 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX);
 
-       if (dev_priv->card_type >= NV_30) {
+       if (dev_priv->card_type >= NV_20) {
                regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8;
                crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47);
        }
@@ -834,6 +850,29 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
+static int
+nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                       struct drm_framebuffer *old_fb)
+{
+       return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
+}
+
+static int
+nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+                              struct drm_framebuffer *fb,
+                              int x, int y, enum mode_set_atomic state)
+{
+       struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+       struct drm_device *dev = dev_priv->dev;
+
+       if (state == ENTER_ATOMIC_MODE_SET)
+               nouveau_fbcon_save_disable_accel(dev);
+       else
+               nouveau_fbcon_restore_accel(dev);
+
+       return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
+}
+
 static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src,
                               struct nouveau_bo *dst)
 {
@@ -962,6 +1001,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
        .mode_fixup = nv_crtc_mode_fixup,
        .mode_set = nv_crtc_mode_set,
        .mode_set_base = nv04_crtc_mode_set_base,
+       .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
        .load_lut = nv_crtc_gamma_load,
 };
 
index ea3627041ecf8e7eb4a59199d8c1c7e1e64fd437..ba6423f2ffccb2e5e7f2a8c9ea431c4aa087cec2 100644 (file)
@@ -291,6 +291,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
        msleep(5);
 
        sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
+       /* do it again just in case it's a residual current */
+       sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
 
        temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL,
@@ -343,22 +345,13 @@ static void nv04_dac_prepare(struct drm_encoder *encoder)
 {
        struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct drm_device *dev = encoder->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        int head = nouveau_crtc(encoder->crtc)->index;
-       struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg;
 
        helper->dpms(encoder, DRM_MODE_DPMS_OFF);
 
        nv04_dfp_disable(dev, head);
-
-       /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-        * at LCD__INDEX which we don't alter
-        */
-       if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44))
-               crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
 }
 
-
 static void nv04_dac_mode_set(struct drm_encoder *encoder,
                              struct drm_display_mode *mode,
                              struct drm_display_mode *adjusted_mode)
index 0d3206a7046cb008814237250d5fa9fe2502ac2c..c936403b26e22f7b4bcc1b4fee4fa6809498689b 100644 (file)
@@ -104,6 +104,8 @@ void nv04_dfp_disable(struct drm_device *dev, int head)
        }
        /* don't inadvertently turn it on when state written later */
        crtcstate[head].fp_control = FP_TG_CONTROL_OFF;
+       crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] &=
+               ~NV_CIO_CRE_LCD_ROUTE_MASK;
 }
 
 void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
@@ -253,26 +255,21 @@ static void nv04_dfp_prepare(struct drm_encoder *encoder)
 
        nv04_dfp_prepare_sel_clk(dev, nv_encoder, head);
 
-       /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-        * at LCD__INDEX which we don't alter
-        */
-       if (!(*cr_lcd & 0x44)) {
-               *cr_lcd = 0x3;
-
-               if (nv_two_heads(dev)) {
-                       if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
-                               *cr_lcd |= head ? 0x0 : 0x8;
-                       else {
-                               *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
-                               if (nv_encoder->dcb->type == OUTPUT_LVDS)
-                                       *cr_lcd |= 0x30;
-                               if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
-                                       /* avoid being connected to both crtcs */
-                                       *cr_lcd_oth &= ~0x30;
-                                       NVWriteVgaCrtc(dev, head ^ 1,
-                                                      NV_CIO_CRE_LCD__INDEX,
-                                                      *cr_lcd_oth);
-                               }
+       *cr_lcd = (*cr_lcd & ~NV_CIO_CRE_LCD_ROUTE_MASK) | 0x3;
+
+       if (nv_two_heads(dev)) {
+               if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
+                       *cr_lcd |= head ? 0x0 : 0x8;
+               else {
+                       *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
+                       if (nv_encoder->dcb->type == OUTPUT_LVDS)
+                               *cr_lcd |= 0x30;
+                       if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
+                               /* avoid being connected to both crtcs */
+                               *cr_lcd_oth &= ~0x30;
+                               NVWriteVgaCrtc(dev, head ^ 1,
+                                              NV_CIO_CRE_LCD__INDEX,
+                                              *cr_lcd_oth);
                        }
                }
        }
@@ -640,7 +637,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
            get_tmds_slave(encoder))
                return;
 
-       type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+       type = nouveau_i2c_identify(dev, "TMDS transmitter", info, NULL, 2);
        if (type < 0)
                return;
 
index 1eeac4fae73dc244b252d43976b2d8d5ccf8ce2e..33e4c9388bc1b8f787f5bc89e7350670098a7722 100644 (file)
@@ -25,6 +25,7 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 #include "nouveau_fbcon.h"
 
 void
@@ -169,11 +170,9 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
        if (ret)
                return ret;
 
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, handle, obj, NULL);
-       if (ret)
-               return ret;
-
-       return 0;
+       ret = nouveau_ramht_insert(dev_priv->channel, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
 int
index 06cedd99c26a3a72e4fc18d1f743a19a374a8706..708293b7ddcd5ad36fc184271b274753e29d71b8 100644 (file)
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
-#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
+#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
 #define NV04_RAMFC__SIZE 32
 #define NV04_RAMFC_DMA_PUT                                       0x00
 #define NV04_RAMFC_DMA_GET                                       0x04
 #define NV04_RAMFC_ENGINE                                        0x14
 #define NV04_RAMFC_PULL1_ENGINE                                  0x18
 
-#define RAMFC_WR(offset, val) nv_wo32(dev, chan->ramfc->gpuobj, \
-                                        NV04_RAMFC_##offset/4, (val))
-#define RAMFC_RD(offset)      nv_ro32(dev, chan->ramfc->gpuobj, \
-                                        NV04_RAMFC_##offset/4)
+#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val))
+#define RAMFC_RD(offset)      nv_ro32(chan->ramfc, NV04_RAMFC_##offset)
 
 void
 nv04_fifo_disable(struct drm_device *dev)
@@ -71,38 +70,33 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable)
        return (reassign == 1);
 }
 
-bool
-nv04_fifo_cache_flush(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
-       uint64_t start = ptimer->read(dev);
-
-       do {
-               if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) ==
-                   nv_rd32(dev, NV03_PFIFO_CACHE1_PUT))
-                       return true;
-
-       } while (ptimer->read(dev) - start < 100000000);
-
-       NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n");
-
-       return false;
-}
-
 bool
 nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
 {
-       uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0);
+       int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
+
+       if (!enable) {
+               /* In some cases the PFIFO puller may be left in an
+                * inconsistent state if you try to stop it when it's
+                * busy translating handles. Sometimes you get a
+                * PFIFO_CACHE_ERROR, sometimes it just fails silently
+                * sending incorrect instance offsets to PGRAPH after
+                * it's started up again. To avoid the latter we
+                * invalidate the most recently calculated instance.
+                */
+               if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
+                            NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
+                       NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
+
+               if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
+                   NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+                       nv_wr32(dev, NV03_PFIFO_INTR_0,
+                               NV_PFIFO_INTR_CACHE_ERROR);
 
-       if (enable) {
-               nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1);
-       } else {
-               nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1);
                nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
        }
 
-       return !!(pull & 1);
+       return pull & 1;
 }
 
 int
@@ -130,7 +124,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
                                                NV04_RAMFC__SIZE,
                                                NVOBJ_FLAG_ZERO_ALLOC |
                                                NVOBJ_FLAG_ZERO_FREE,
-                                               NULL, &chan->ramfc);
+                                               &chan->ramfc);
        if (ret)
                return ret;
 
@@ -139,7 +133,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
        /* Setup initial state */
        RAMFC_WR(DMA_PUT, chan->pushbuf_base);
        RAMFC_WR(DMA_GET, chan->pushbuf_base);
-       RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
+       RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4);
        RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
                             NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
                             NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -161,7 +155,7 @@ nv04_fifo_destroy_context(struct nouveau_channel *chan)
        nv_wr32(dev, NV04_PFIFO_MODE,
                nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-       nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -264,10 +258,10 @@ nv04_fifo_init_ramxx(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
        nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-                                      ((dev_priv->ramht_bits - 9) << 16) |
-                                      (dev_priv->ramht_offset >> 8));
-       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
-       nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+                                      ((dev_priv->ramht->bits - 9) << 16) |
+                                      (dev_priv->ramht->gpuobj->pinst >> 8));
+       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+       nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
 }
 
 static void
index 4408232d33f179805205763974beede957ddd6f1..0b5ae297abdecb0d4403bedf8b4d84ad75940ef9 100644 (file)
@@ -1,6 +1,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 /* returns the size of fifo context */
 static int
@@ -17,102 +18,51 @@ nouveau_fifo_ctx_size(struct drm_device *dev)
        return 32;
 }
 
-static void
-nv04_instmem_determine_amount(struct drm_device *dev)
+int nv04_instmem_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int i;
+       struct nouveau_gpuobj *ramht = NULL;
+       u32 offset, length;
+       int ret;
 
-       /* Figure out how much instance memory we need */
-       if (dev_priv->card_type >= NV_40) {
-               /* We'll want more instance memory than this on some NV4x cards.
-                * There's a 16MB aperture to play with that maps onto the end
-                * of vram.  For now, only reserve a small piece until we know
-                * more about what each chipset requires.
-                */
-               switch (dev_priv->chipset) {
-               case 0x40:
-               case 0x47:
-               case 0x49:
-               case 0x4b:
-                       dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
-                       break;
-               default:
-                       dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
-                       break;
-               }
-       } else {
-               /*XXX: what *are* the limits on <NV40 cards?
-                */
-               dev_priv->ramin_rsvd_vram = (512 * 1024);
-       }
-       NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
+       /* RAMIN always available */
+       dev_priv->ramin_available = true;
 
-       /* Clear all of it, except the BIOS image that's in the first 64KiB */
-       for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
-               nv_wi32(dev, i, 0x00000000);
-}
+       /* Setup shared RAMHT */
+       ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096,
+                                     NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+       if (ret)
+               return ret;
 
-static void
-nv04_instmem_configure_fixed_tables(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_engine *engine = &dev_priv->engine;
+       ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht);
+       nouveau_gpuobj_ref(NULL, &ramht);
+       if (ret)
+               return ret;
 
-       /* FIFO hash table (RAMHT)
-        *   use 4k hash table at RAMIN+0x10000
-        *   TODO: extend the hash table
-        */
-       dev_priv->ramht_offset = 0x10000;
-       dev_priv->ramht_bits   = 9;
-       dev_priv->ramht_size   = (1 << dev_priv->ramht_bits); /* nr entries */
-       dev_priv->ramht_size  *= 8; /* 2 32-bit values per entry in RAMHT */
-       NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
-                                                     dev_priv->ramht_size);
-
-       /* FIFO runout table (RAMRO) - 512k at 0x11200 */
-       dev_priv->ramro_offset = 0x11200;
-       dev_priv->ramro_size   = 512;
-       NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
-                                                     dev_priv->ramro_size);
-
-       /* FIFO context table (RAMFC)
-        *   NV40  : Not sure exactly how to position RAMFC on some cards,
-        *           0x30002 seems to position it at RAMIN+0x20000 on these
-        *           cards.  RAMFC is 4kb (32 fifos, 128byte entries).
-        *   Others: Position RAMFC at RAMIN+0x11400
-        */
-       dev_priv->ramfc_size = engine->fifo.channels *
-                                               nouveau_fifo_ctx_size(dev);
+       /* And RAMRO */
+       ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512,
+                                     NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro);
+       if (ret)
+               return ret;
+
+       /* And RAMFC */
+       length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev);
        switch (dev_priv->card_type) {
        case NV_40:
-               dev_priv->ramfc_offset = 0x20000;
+               offset = 0x20000;
                break;
-       case NV_30:
-       case NV_20:
-       case NV_10:
-       case NV_04:
        default:
-               dev_priv->ramfc_offset = 0x11400;
+               offset = 0x11400;
                break;
        }
-       NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
-                                                     dev_priv->ramfc_size);
-}
 
-int nv04_instmem_init(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t offset;
-       int ret;
-
-       nv04_instmem_determine_amount(dev);
-       nv04_instmem_configure_fixed_tables(dev);
+       ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length,
+                                     NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc);
+       if (ret)
+               return ret;
 
-       /* Create a heap to manage RAMIN allocations, we don't allocate
-        * the space that was reserved for RAMHT/FC/RO.
-        */
-       offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
+       /* Only allow space after RAMFC to be used for object allocation */
+       offset += length;
 
        /* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
         * on certain NV4x chipsets as well as RAMFC.  When 0x2230 == 0
@@ -140,46 +90,34 @@ int nv04_instmem_init(struct drm_device *dev)
 void
 nv04_instmem_takedown(struct drm_device *dev)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
+       nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
+       nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
 }
 
 int
-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
+nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+                     uint32_t *sz)
 {
-       if (gpuobj->im_backing)
-               return -EINVAL;
-
        return 0;
 }
 
 void
 nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (gpuobj && gpuobj->im_backing) {
-               if (gpuobj->im_bound)
-                       dev_priv->engine.instmem.unbind(dev, gpuobj);
-               gpuobj->im_backing = NULL;
-       }
 }
 
 int
 nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-       if (!gpuobj->im_pramin || gpuobj->im_bound)
-               return -EINVAL;
-
-       gpuobj->im_bound = 1;
        return 0;
 }
 
 int
 nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-       if (gpuobj->im_bound == 0)
-               return -EINVAL;
-
-       gpuobj->im_bound = 0;
        return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
new file mode 100644 (file)
index 0000000..6a6eb69
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_hw.h"
+#include "nouveau_pm.h"
+
+struct nv04_pm_state {
+       struct pll_lims pll;
+       struct nouveau_pll_vals calc;
+};
+
+int
+nv04_pm_clock_get(struct drm_device *dev, u32 id)
+{
+       return nouveau_hw_get_clock(dev, id);
+}
+
+void *
+nv04_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+                 u32 id, int khz)
+{
+       struct nv04_pm_state *state;
+       int ret;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       ret = get_pll_limits(dev, id, &state->pll);
+       if (ret) {
+               kfree(state);
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       }
+
+       ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
+       if (!ret) {
+               kfree(state);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return state;
+}
+
+void
+nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv04_pm_state *state = pre_state;
+       u32 reg = state->pll.reg;
+
+       /* thank the insane nouveau_hw_setpll() interface for this */
+       if (dev_priv->card_type >= NV_40)
+               reg += 4;
+
+       nouveau_hw_setpll(dev, reg, &state->calc);
+       kfree(state);
+}
+
index 0b5d012d7c28d4aebacf8aa15576cebe71b36c84..3eb605ddfd031bd4ceb74c532597a00177e5a380 100644 (file)
@@ -49,8 +49,8 @@ static struct i2c_board_info nv04_tv_encoder_info[] = {
 
 int nv04_tv_identify(struct drm_device *dev, int i2c_index)
 {
-       return nouveau_i2c_identify(dev, "TV encoder",
-                                   nv04_tv_encoder_info, i2c_index);
+       return nouveau_i2c_identify(dev, "TV encoder", nv04_tv_encoder_info,
+                                   NULL, i2c_index);
 }
 
 
@@ -99,12 +99,10 @@ static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
 
        state->tv_setup = 0;
 
-       if (bind) {
-               state->CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
+       if (bind)
                state->CRTC[NV_CIO_CRE_49] |= 0x10;
-       } else {
+       else
                state->CRTC[NV_CIO_CRE_49] &= ~0x10;
-       }
 
        NVWriteVgaCrtc(dev, head, NV_CIO_CRE_LCD__INDEX,
                       state->CRTC[NV_CIO_CRE_LCD__INDEX]);
index 7a4069cf5d0b835caccd983722bb640df7f6e351..f1b03ad58fd5459f928ad6b54d97a45dce417648 100644 (file)
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
-#define NV10_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE))
+#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE))
 #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
 
 int
@@ -48,7 +49,7 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
 
        ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0,
                                      NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
-                                     NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+                                     NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
        if (ret)
                return ret;
 
@@ -57,7 +58,7 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
         */
        nv_wi32(dev, fc +  0, chan->pushbuf_base);
        nv_wi32(dev, fc +  4, chan->pushbuf_base);
-       nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+       nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
        nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
                              NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
                              NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -80,7 +81,7 @@ nv10_fifo_destroy_context(struct nouveau_channel *chan)
        nv_wr32(dev, NV04_PFIFO_MODE,
                        nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-       nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -202,14 +203,14 @@ nv10_fifo_init_ramxx(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
        nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-                                      ((dev_priv->ramht_bits - 9) << 16) |
-                                      (dev_priv->ramht_offset >> 8));
-       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+                                      ((dev_priv->ramht->bits - 9) << 16) |
+                                      (dev_priv->ramht->gpuobj->pinst >> 8));
+       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
 
        if (dev_priv->chipset < 0x17) {
-               nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+               nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
        } else {
-               nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc_offset >> 8) |
+               nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) |
                                               (1 << 16) /* 64 Bytes entry*/);
                /* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */
        }
index b2f6a57c0cc5f1d5c0f879268d6468a8f77014ba..8e68c97311597ebe2c8b8a9b58536e0df3f81eb3 100644 (file)
@@ -803,7 +803,7 @@ nv10_graph_context_switch(struct drm_device *dev)
        /* Load context for next channel */
        chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
        chan = dev_priv->fifos[chid];
-       if (chan)
+       if (chan && chan->pgraph_ctx)
                nv10_graph_load_context(chan);
 
        pgraph->fifo_access(dev, true);
index 13cdc05b7c2d0f4e7785cbe428ce4ab86205bd67..28119fd19d03c7974451c131898b38261eabcfbe 100644 (file)
@@ -193,55 +193,56 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
        }
 }
 
-static const struct {
-       int hdisplay;
-       int vdisplay;
-} modes[] = {
-       { 640, 400 },
-       { 640, 480 },
-       { 720, 480 },
-       { 720, 576 },
-       { 800, 600 },
-       { 1024, 768 },
-       { 1280, 720 },
-       { 1280, 1024 },
-       { 1920, 1080 }
-};
-
-static int nv17_tv_get_modes(struct drm_encoder *encoder,
-                            struct drm_connector *connector)
+static int nv17_tv_get_ld_modes(struct drm_encoder *encoder,
+                               struct drm_connector *connector)
 {
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
-       struct drm_display_mode *mode;
-       struct drm_display_mode *output_mode;
+       struct drm_display_mode *mode, *tv_mode;
        int n = 0;
-       int i;
-
-       if (tv_norm->kind != CTV_ENC_MODE) {
-               struct drm_display_mode *tv_mode;
 
-               for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
-                       mode = drm_mode_duplicate(encoder->dev, tv_mode);
+       for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
+               mode = drm_mode_duplicate(encoder->dev, tv_mode);
 
-                       mode->clock = tv_norm->tv_enc_mode.vrefresh *
-                                               mode->htotal / 1000 *
-                                               mode->vtotal / 1000;
+               mode->clock = tv_norm->tv_enc_mode.vrefresh *
+                       mode->htotal / 1000 *
+                       mode->vtotal / 1000;
 
-                       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-                               mode->clock *= 2;
+               if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                       mode->clock *= 2;
 
-                       if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
-                           mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
-                               mode->type |= DRM_MODE_TYPE_PREFERRED;
+               if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
+                   mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
+                       mode->type |= DRM_MODE_TYPE_PREFERRED;
 
-                       drm_mode_probed_add(connector, mode);
-                       n++;
-               }
-               return n;
+               drm_mode_probed_add(connector, mode);
+               n++;
        }
 
-       /* tv_norm->kind == CTV_ENC_MODE */
-       output_mode = &tv_norm->ctv_enc_mode.mode;
+       return n;
+}
+
+static int nv17_tv_get_hd_modes(struct drm_encoder *encoder,
+                               struct drm_connector *connector)
+{
+       struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+       struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;
+       struct drm_display_mode *mode;
+       const struct {
+               int hdisplay;
+               int vdisplay;
+       } modes[] = {
+               { 640, 400 },
+               { 640, 480 },
+               { 720, 480 },
+               { 720, 576 },
+               { 800, 600 },
+               { 1024, 768 },
+               { 1280, 720 },
+               { 1280, 1024 },
+               { 1920, 1080 }
+       };
+       int i, n = 0;
+
        for (i = 0; i < ARRAY_SIZE(modes); i++) {
                if (modes[i].hdisplay > output_mode->hdisplay ||
                    modes[i].vdisplay > output_mode->vdisplay)
@@ -251,11 +252,12 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
                    modes[i].vdisplay == output_mode->vdisplay) {
                        mode = drm_mode_duplicate(encoder->dev, output_mode);
                        mode->type |= DRM_MODE_TYPE_PREFERRED;
+
                } else {
                        mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,
-                               modes[i].vdisplay, 60, false,
-                               output_mode->flags & DRM_MODE_FLAG_INTERLACE,
-                               false);
+                                           modes[i].vdisplay, 60, false,
+                                           (output_mode->flags &
+                                            DRM_MODE_FLAG_INTERLACE), false);
                }
 
                /* CVT modes are sometimes unsuitable... */
@@ -266,6 +268,7 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
                                             - mode->hdisplay) * 9 / 10) & ~7;
                        mode->hsync_end = mode->hsync_start + 8;
                }
+
                if (output_mode->vdisplay >= 1024) {
                        mode->vtotal = output_mode->vtotal;
                        mode->vsync_start = output_mode->vsync_start;
@@ -276,9 +279,21 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
                drm_mode_probed_add(connector, mode);
                n++;
        }
+
        return n;
 }
 
+static int nv17_tv_get_modes(struct drm_encoder *encoder,
+                            struct drm_connector *connector)
+{
+       struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+
+       if (tv_norm->kind == CTV_ENC_MODE)
+               return nv17_tv_get_hd_modes(encoder, connector);
+       else
+               return nv17_tv_get_ld_modes(encoder, connector);
+}
+
 static int nv17_tv_mode_valid(struct drm_encoder *encoder,
                              struct drm_display_mode *mode)
 {
@@ -408,15 +423,8 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
 
        }
 
-       /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-        * at LCD__INDEX which we don't alter
-        */
-       if (!(*cr_lcd & 0x44)) {
-               if (tv_norm->kind == CTV_ENC_MODE)
-                       *cr_lcd = 0x1 | (head ? 0x0 : 0x8);
-               else
-                       *cr_lcd = 0;
-       }
+       if (tv_norm->kind == CTV_ENC_MODE)
+               *cr_lcd |= 0x1 | (head ? 0x0 : 0x8);
 
        /* Set the DACCLK register */
        dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
index c00977cedabd6654e446965fbff7b94d782a9670..6bf03840f9ebddf9b8ff661e229c52e3432330a8 100644 (file)
@@ -127,7 +127,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder);
 
 /* TV hardware access functions */
 
-static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val)
+static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg,
+                               uint32_t val)
 {
        nv_wr32(dev, reg, val);
 }
@@ -137,7 +138,8 @@ static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg)
        return nv_rd32(dev, reg);
 }
 
-static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, uint8_t val)
+static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg,
+                                  uint8_t val)
 {
        nv_write_ptv(dev, NV_PTV_TV_INDEX, reg);
        nv_write_ptv(dev, NV_PTV_TV_DATA, val);
@@ -149,8 +151,11 @@ static inline uint8_t nv_read_tv_enc(struct drm_device *dev, uint8_t reg)
        return nv_read_ptv(dev, NV_PTV_TV_DATA);
 }
 
-#define nv_load_ptv(dev, state, reg) nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
-#define nv_save_ptv(dev, state, reg) state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
-#define nv_load_tv_enc(dev, state, reg) nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
+#define nv_load_ptv(dev, state, reg) \
+       nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
+#define nv_save_ptv(dev, state, reg) \
+       state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
+#define nv_load_tv_enc(dev, state, reg) \
+       nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
 
 #endif
index d64683d97e0d044a192a8a42146a13aa4a08a4b4..9d3893c50a419b15bbedcc9e3c8dbd1800ded066 100644 (file)
@@ -336,12 +336,17 @@ static void tv_setup_filter(struct drm_encoder *encoder)
                        struct filter_params *p = &fparams[k][j];
 
                        for (i = 0; i < 7; i++) {
-                               int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + p->ki3*i*i*i)
-                                       + (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k]
-                                       + (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker
-                                       + (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k];
-
-                               (*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9);
+                               int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
+                                            p->ki3*i*i*i)
+                                       + (p->kr + p->kir*i + p->ki2r*i*i +
+                                          p->ki3r*i*i*i) * rs[k]
+                                       + (p->kf + p->kif*i + p->ki2f*i*i +
+                                          p->ki3f*i*i*i) * flicker
+                                       + (p->krf + p->kirf*i + p->ki2rf*i*i +
+                                          p->ki3rf*i*i*i) * flicker * rs[k];
+
+                               (*filters[k])[j][i] = (c + id5/2) >> 39
+                                       & (0x1 << 31 | 0x7f << 9);
                        }
                }
        }
@@ -349,7 +354,8 @@ static void tv_setup_filter(struct drm_encoder *encoder)
 
 /* Hardware state saving/restoring */
 
-static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_save_filter(struct drm_device *dev, uint32_t base,
+                          uint32_t regs[4][7])
 {
        int i, j;
        uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -360,7 +366,8 @@ static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[
        }
 }
 
-static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_load_filter(struct drm_device *dev, uint32_t base,
+                          uint32_t regs[4][7])
 {
        int i, j;
        uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -504,10 +511,10 @@ void nv17_tv_update_properties(struct drm_encoder *encoder)
                break;
        }
 
-       regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255,
-                                        tv_enc->saturation);
-       regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255,
-                                        tv_enc->saturation);
+       regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
+                                        255, tv_enc->saturation);
+       regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
+                                        255, tv_enc->saturation);
        regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
 
        nv_load_ptv(dev, regs, 204);
@@ -541,7 +548,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
        int head = nouveau_crtc(encoder->crtc)->index;
        struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
        struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
-       struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode;
+       struct drm_display_mode *output_mode =
+               &get_tv_norm(encoder)->ctv_enc_mode.mode;
        int overscan, hmargin, vmargin, hratio, vratio;
 
        /* The rescaler doesn't do the right thing for interlaced modes. */
@@ -553,13 +561,15 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
        hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
        vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
 
-       hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin,
-                             overscan);
-       vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin,
-                             overscan);
+       hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
+                             hmargin, overscan);
+       vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
+                             vmargin, overscan);
 
-       hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin);
-       vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3;
+       hratio = crtc_mode->hdisplay * 0x800 /
+               (output_mode->hdisplay - 2*hmargin);
+       vratio = crtc_mode->vdisplay * 0x800 /
+               (output_mode->vdisplay - 2*vmargin) & ~3;
 
        regs->fp_horiz_regs[FP_VALID_START] = hmargin;
        regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
index 17f309b36c910060a355af6d1ada2e6ca6fc7cfd..12ab9cd56ecad286440d9d60d9fe97dd3be0fb7c 100644 (file)
@@ -37,49 +37,49 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
-       nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+       nv_wo32(ctx, 0x033c, 0xffff0000);
+       nv_wo32(ctx, 0x03a0, 0x0fff0000);
+       nv_wo32(ctx, 0x03a4, 0x0fff0000);
+       nv_wo32(ctx, 0x047c, 0x00000101);
+       nv_wo32(ctx, 0x0490, 0x00000111);
+       nv_wo32(ctx, 0x04a8, 0x44400000);
        for (i = 0x04d4; i <= 0x04e0; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x04f4; i <= 0x0500; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080000);
+               nv_wo32(ctx, i, 0x00080000);
        for (i = 0x050c; i <= 0x0518; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x051c; i <= 0x0528; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x000105b8);
+               nv_wo32(ctx, i, 0x000105b8);
        for (i = 0x052c; i <= 0x0538; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
+               nv_wo32(ctx, i, 0x00080008);
        for (i = 0x055c; i <= 0x0598; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
-       nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+       nv_wo32(ctx, 0x05fc, 0x00000001);
+       nv_wo32(ctx, 0x0604, 0x00004000);
+       nv_wo32(ctx, 0x0610, 0x00000001);
+       nv_wo32(ctx, 0x0618, 0x00040000);
+       nv_wo32(ctx, 0x061c, 0x00010000);
        for (i = 0x1c1c; i <= 0x248c; i += 16) {
-               nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-               nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-               nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+               nv_wo32(ctx, (i + 0), 0x10700ff9);
+               nv_wo32(ctx, (i + 4), 0x0436086c);
+               nv_wo32(ctx, (i + 8), 0x000c001b);
        }
-       nv_wo32(dev, ctx, 0x281c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2830/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x285c/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2860/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2864/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x286c/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2870/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2878/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x2880/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x34a4/4, 0x000fe000);
-       nv_wo32(dev, ctx, 0x3530/4, 0x000003f8);
-       nv_wo32(dev, ctx, 0x3540/4, 0x002fe000);
+       nv_wo32(ctx, 0x281c, 0x3f800000);
+       nv_wo32(ctx, 0x2830, 0x3f800000);
+       nv_wo32(ctx, 0x285c, 0x40000000);
+       nv_wo32(ctx, 0x2860, 0x3f800000);
+       nv_wo32(ctx, 0x2864, 0x3f000000);
+       nv_wo32(ctx, 0x286c, 0x40000000);
+       nv_wo32(ctx, 0x2870, 0x3f800000);
+       nv_wo32(ctx, 0x2878, 0xbf800000);
+       nv_wo32(ctx, 0x2880, 0xbf800000);
+       nv_wo32(ctx, 0x34a4, 0x000fe000);
+       nv_wo32(ctx, 0x3530, 0x000003f8);
+       nv_wo32(ctx, 0x3540, 0x002fe000);
        for (i = 0x355c; i <= 0x3578; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x001c527c);
+               nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -87,58 +87,58 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x035c/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x03c0/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x03c4/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x049c/4, 0x00000101);
-       nv_wo32(dev, ctx, 0x04b0/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x04c8/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x04cc/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x04d0/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x04e4/4, 0x44400000);
-       nv_wo32(dev, ctx, 0x04fc/4, 0x4b800000);
+       nv_wo32(ctx, 0x035c, 0xffff0000);
+       nv_wo32(ctx, 0x03c0, 0x0fff0000);
+       nv_wo32(ctx, 0x03c4, 0x0fff0000);
+       nv_wo32(ctx, 0x049c, 0x00000101);
+       nv_wo32(ctx, 0x04b0, 0x00000111);
+       nv_wo32(ctx, 0x04c8, 0x00000080);
+       nv_wo32(ctx, 0x04cc, 0xffff0000);
+       nv_wo32(ctx, 0x04d0, 0x00000001);
+       nv_wo32(ctx, 0x04e4, 0x44400000);
+       nv_wo32(ctx, 0x04fc, 0x4b800000);
        for (i = 0x0510; i <= 0x051c; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x0530; i <= 0x053c; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080000);
+               nv_wo32(ctx, i, 0x00080000);
        for (i = 0x0548; i <= 0x0554; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x0558; i <= 0x0564; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x000105b8);
+               nv_wo32(ctx, i, 0x000105b8);
        for (i = 0x0568; i <= 0x0574; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
+               nv_wo32(ctx, i, 0x00080008);
        for (i = 0x0598; i <= 0x05d4; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x05e0/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x0620/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0624/4, 0x30201000);
-       nv_wo32(dev, ctx, 0x0628/4, 0x70605040);
-       nv_wo32(dev, ctx, 0x062c/4, 0xb0a09080);
-       nv_wo32(dev, ctx, 0x0630/4, 0xf0e0d0c0);
-       nv_wo32(dev, ctx, 0x0664/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x066c/4, 0x00004000);
-       nv_wo32(dev, ctx, 0x0678/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0680/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x0684/4, 0x00010000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x05e0, 0x4b7fffff);
+       nv_wo32(ctx, 0x0620, 0x00000080);
+       nv_wo32(ctx, 0x0624, 0x30201000);
+       nv_wo32(ctx, 0x0628, 0x70605040);
+       nv_wo32(ctx, 0x062c, 0xb0a09080);
+       nv_wo32(ctx, 0x0630, 0xf0e0d0c0);
+       nv_wo32(ctx, 0x0664, 0x00000001);
+       nv_wo32(ctx, 0x066c, 0x00004000);
+       nv_wo32(ctx, 0x0678, 0x00000001);
+       nv_wo32(ctx, 0x0680, 0x00040000);
+       nv_wo32(ctx, 0x0684, 0x00010000);
        for (i = 0x1b04; i <= 0x2374; i += 16) {
-               nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-               nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-               nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+               nv_wo32(ctx, (i + 0), 0x10700ff9);
+               nv_wo32(ctx, (i + 4), 0x0436086c);
+               nv_wo32(ctx, (i + 8), 0x000c001b);
        }
-       nv_wo32(dev, ctx, 0x2704/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2718/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2744/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2748/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x274c/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x2754/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2758/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2760/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x2768/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x308c/4, 0x000fe000);
-       nv_wo32(dev, ctx, 0x3108/4, 0x000003f8);
-       nv_wo32(dev, ctx, 0x3468/4, 0x002fe000);
+       nv_wo32(ctx, 0x2704, 0x3f800000);
+       nv_wo32(ctx, 0x2718, 0x3f800000);
+       nv_wo32(ctx, 0x2744, 0x40000000);
+       nv_wo32(ctx, 0x2748, 0x3f800000);
+       nv_wo32(ctx, 0x274c, 0x3f000000);
+       nv_wo32(ctx, 0x2754, 0x40000000);
+       nv_wo32(ctx, 0x2758, 0x3f800000);
+       nv_wo32(ctx, 0x2760, 0xbf800000);
+       nv_wo32(ctx, 0x2768, 0xbf800000);
+       nv_wo32(ctx, 0x308c, 0x000fe000);
+       nv_wo32(ctx, 0x3108, 0x000003f8);
+       nv_wo32(ctx, 0x3468, 0x002fe000);
        for (i = 0x3484; i <= 0x34a0; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x001c527c);
+               nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -146,49 +146,49 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
-       nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+       nv_wo32(ctx, 0x033c, 0xffff0000);
+       nv_wo32(ctx, 0x03a0, 0x0fff0000);
+       nv_wo32(ctx, 0x03a4, 0x0fff0000);
+       nv_wo32(ctx, 0x047c, 0x00000101);
+       nv_wo32(ctx, 0x0490, 0x00000111);
+       nv_wo32(ctx, 0x04a8, 0x44400000);
        for (i = 0x04d4; i <= 0x04e0; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x04f4; i <= 0x0500; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080000);
+               nv_wo32(ctx, i, 0x00080000);
        for (i = 0x050c; i <= 0x0518; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x051c; i <= 0x0528; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x000105b8);
+               nv_wo32(ctx, i, 0x000105b8);
        for (i = 0x052c; i <= 0x0538; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
+               nv_wo32(ctx, i, 0x00080008);
        for (i = 0x055c; i <= 0x0598; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
-       nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+       nv_wo32(ctx, 0x05fc, 0x00000001);
+       nv_wo32(ctx, 0x0604, 0x00004000);
+       nv_wo32(ctx, 0x0610, 0x00000001);
+       nv_wo32(ctx, 0x0618, 0x00040000);
+       nv_wo32(ctx, 0x061c, 0x00010000);
        for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
-               nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-               nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-               nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+               nv_wo32(ctx, (i + 0), 0x10700ff9);
+               nv_wo32(ctx, (i + 4), 0x0436086c);
+               nv_wo32(ctx, (i + 8), 0x000c001b);
        }
-       nv_wo32(dev, ctx, 0x269c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x26b0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x26dc/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x26e0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x26e4/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x26ec/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x26f0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x26f8/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x2700/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x3024/4, 0x000fe000);
-       nv_wo32(dev, ctx, 0x30a0/4, 0x000003f8);
-       nv_wo32(dev, ctx, 0x33fc/4, 0x002fe000);
+       nv_wo32(ctx, 0x269c, 0x3f800000);
+       nv_wo32(ctx, 0x26b0, 0x3f800000);
+       nv_wo32(ctx, 0x26dc, 0x40000000);
+       nv_wo32(ctx, 0x26e0, 0x3f800000);
+       nv_wo32(ctx, 0x26e4, 0x3f000000);
+       nv_wo32(ctx, 0x26ec, 0x40000000);
+       nv_wo32(ctx, 0x26f0, 0x3f800000);
+       nv_wo32(ctx, 0x26f8, 0xbf800000);
+       nv_wo32(ctx, 0x2700, 0xbf800000);
+       nv_wo32(ctx, 0x3024, 0x000fe000);
+       nv_wo32(ctx, 0x30a0, 0x000003f8);
+       nv_wo32(ctx, 0x33fc, 0x002fe000);
        for (i = 0x341c; i <= 0x3438; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x001c527c);
+               nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -196,57 +196,57 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x0410/4, 0x00000101);
-       nv_wo32(dev, ctx, 0x0424/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x0428/4, 0x00000060);
-       nv_wo32(dev, ctx, 0x0444/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0448/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x044c/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x0460/4, 0x44400000);
-       nv_wo32(dev, ctx, 0x048c/4, 0xffff0000);
+       nv_wo32(ctx, 0x0410, 0x00000101);
+       nv_wo32(ctx, 0x0424, 0x00000111);
+       nv_wo32(ctx, 0x0428, 0x00000060);
+       nv_wo32(ctx, 0x0444, 0x00000080);
+       nv_wo32(ctx, 0x0448, 0xffff0000);
+       nv_wo32(ctx, 0x044c, 0x00000001);
+       nv_wo32(ctx, 0x0460, 0x44400000);
+       nv_wo32(ctx, 0x048c, 0xffff0000);
        for (i = 0x04e0; i < 0x04e8; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x04ec/4, 0x00011100);
+               nv_wo32(ctx, i, 0x0fff0000);
+       nv_wo32(ctx, 0x04ec, 0x00011100);
        for (i = 0x0508; i < 0x0548; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x0550/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x058c/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0590/4, 0x30201000);
-       nv_wo32(dev, ctx, 0x0594/4, 0x70605040);
-       nv_wo32(dev, ctx, 0x0598/4, 0xb8a89888);
-       nv_wo32(dev, ctx, 0x059c/4, 0xf8e8d8c8);
-       nv_wo32(dev, ctx, 0x05b0/4, 0xb0000000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x0550, 0x4b7fffff);
+       nv_wo32(ctx, 0x058c, 0x00000080);
+       nv_wo32(ctx, 0x0590, 0x30201000);
+       nv_wo32(ctx, 0x0594, 0x70605040);
+       nv_wo32(ctx, 0x0598, 0xb8a89888);
+       nv_wo32(ctx, 0x059c, 0xf8e8d8c8);
+       nv_wo32(ctx, 0x05b0, 0xb0000000);
        for (i = 0x0600; i < 0x0640; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00010588);
+               nv_wo32(ctx, i, 0x00010588);
        for (i = 0x0640; i < 0x0680; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x06c0; i < 0x0700; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0008aae4);
+               nv_wo32(ctx, i, 0x0008aae4);
        for (i = 0x0700; i < 0x0740; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x0740; i < 0x0780; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
-       nv_wo32(dev, ctx, 0x085c/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x0860/4, 0x00010000);
+               nv_wo32(ctx, i, 0x00080008);
+       nv_wo32(ctx, 0x085c, 0x00040000);
+       nv_wo32(ctx, 0x0860, 0x00010000);
        for (i = 0x0864; i < 0x0874; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00040004);
+               nv_wo32(ctx, i, 0x00040004);
        for (i = 0x1f18; i <= 0x3088 ; i += 16) {
-               nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-               nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-               nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+               nv_wo32(ctx, i + 0, 0x10700ff9);
+               nv_wo32(ctx, i + 1, 0x0436086c);
+               nv_wo32(ctx, i + 2, 0x000c001b);
        }
        for (i = 0x30b8; i < 0x30c8; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0000ffff);
-       nv_wo32(dev, ctx, 0x344c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3808/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x381c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3848/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x384c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3850/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x3858/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x385c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3864/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x386c/4, 0xbf800000);
+               nv_wo32(ctx, i, 0x0000ffff);
+       nv_wo32(ctx, 0x344c, 0x3f800000);
+       nv_wo32(ctx, 0x3808, 0x3f800000);
+       nv_wo32(ctx, 0x381c, 0x3f800000);
+       nv_wo32(ctx, 0x3848, 0x40000000);
+       nv_wo32(ctx, 0x384c, 0x3f800000);
+       nv_wo32(ctx, 0x3850, 0x3f000000);
+       nv_wo32(ctx, 0x3858, 0x40000000);
+       nv_wo32(ctx, 0x385c, 0x3f800000);
+       nv_wo32(ctx, 0x3864, 0xbf800000);
+       nv_wo32(ctx, 0x386c, 0xbf800000);
 }
 
 static void
@@ -254,57 +254,57 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x040c/4, 0x01000101);
-       nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
-       nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
-       nv_wo32(dev, ctx, 0x0480/4, 0xffff0000);
+       nv_wo32(ctx, 0x040c, 0x01000101);
+       nv_wo32(ctx, 0x0420, 0x00000111);
+       nv_wo32(ctx, 0x0424, 0x00000060);
+       nv_wo32(ctx, 0x0440, 0x00000080);
+       nv_wo32(ctx, 0x0444, 0xffff0000);
+       nv_wo32(ctx, 0x0448, 0x00000001);
+       nv_wo32(ctx, 0x045c, 0x44400000);
+       nv_wo32(ctx, 0x0480, 0xffff0000);
        for (i = 0x04d4; i < 0x04dc; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x04e0/4, 0x00011100);
+               nv_wo32(ctx, i, 0x0fff0000);
+       nv_wo32(ctx, 0x04e0, 0x00011100);
        for (i = 0x04fc; i < 0x053c; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x0544/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x057c/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0580/4, 0x30201000);
-       nv_wo32(dev, ctx, 0x0584/4, 0x70605040);
-       nv_wo32(dev, ctx, 0x0588/4, 0xb8a89888);
-       nv_wo32(dev, ctx, 0x058c/4, 0xf8e8d8c8);
-       nv_wo32(dev, ctx, 0x05a0/4, 0xb0000000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x0544, 0x4b7fffff);
+       nv_wo32(ctx, 0x057c, 0x00000080);
+       nv_wo32(ctx, 0x0580, 0x30201000);
+       nv_wo32(ctx, 0x0584, 0x70605040);
+       nv_wo32(ctx, 0x0588, 0xb8a89888);
+       nv_wo32(ctx, 0x058c, 0xf8e8d8c8);
+       nv_wo32(ctx, 0x05a0, 0xb0000000);
        for (i = 0x05f0; i < 0x0630; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00010588);
+               nv_wo32(ctx, i, 0x00010588);
        for (i = 0x0630; i < 0x0670; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x06b0; i < 0x06f0; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0008aae4);
+               nv_wo32(ctx, i, 0x0008aae4);
        for (i = 0x06f0; i < 0x0730; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x0730; i < 0x0770; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
-       nv_wo32(dev, ctx, 0x0850/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x0854/4, 0x00010000);
+               nv_wo32(ctx, i, 0x00080008);
+       nv_wo32(ctx, 0x0850, 0x00040000);
+       nv_wo32(ctx, 0x0854, 0x00010000);
        for (i = 0x0858; i < 0x0868; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00040004);
+               nv_wo32(ctx, i, 0x00040004);
        for (i = 0x15ac; i <= 0x271c ; i += 16) {
-               nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-               nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-               nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+               nv_wo32(ctx, i + 0, 0x10700ff9);
+               nv_wo32(ctx, i + 1, 0x0436086c);
+               nv_wo32(ctx, i + 2, 0x000c001b);
        }
        for (i = 0x274c; i < 0x275c; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0000ffff);
-       nv_wo32(dev, ctx, 0x2ae0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2e9c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2eb0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2edc/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2ee0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2ee4/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x2eec/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x2ef0/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x2ef8/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x2f00/4, 0xbf800000);
+               nv_wo32(ctx, i, 0x0000ffff);
+       nv_wo32(ctx, 0x2ae0, 0x3f800000);
+       nv_wo32(ctx, 0x2e9c, 0x3f800000);
+       nv_wo32(ctx, 0x2eb0, 0x3f800000);
+       nv_wo32(ctx, 0x2edc, 0x40000000);
+       nv_wo32(ctx, 0x2ee0, 0x3f800000);
+       nv_wo32(ctx, 0x2ee4, 0x3f000000);
+       nv_wo32(ctx, 0x2eec, 0x40000000);
+       nv_wo32(ctx, 0x2ef0, 0x3f800000);
+       nv_wo32(ctx, 0x2ef8, 0xbf800000);
+       nv_wo32(ctx, 0x2f00, 0xbf800000);
 }
 
 static void
@@ -312,57 +312,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 {
        int i;
 
-       nv_wo32(dev, ctx, 0x040c/4, 0x00000101);
-       nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
-       nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
-       nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
-       nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
-       nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
-       nv_wo32(dev, ctx, 0x0488/4, 0xffff0000);
+       nv_wo32(ctx, 0x040c, 0x00000101);
+       nv_wo32(ctx, 0x0420, 0x00000111);
+       nv_wo32(ctx, 0x0424, 0x00000060);
+       nv_wo32(ctx, 0x0440, 0x00000080);
+       nv_wo32(ctx, 0x0444, 0xffff0000);
+       nv_wo32(ctx, 0x0448, 0x00000001);
+       nv_wo32(ctx, 0x045c, 0x44400000);
+       nv_wo32(ctx, 0x0488, 0xffff0000);
        for (i = 0x04dc; i < 0x04e4; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0fff0000);
-       nv_wo32(dev, ctx, 0x04e8/4, 0x00011100);
+               nv_wo32(ctx, i, 0x0fff0000);
+       nv_wo32(ctx, 0x04e8, 0x00011100);
        for (i = 0x0504; i < 0x0544; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x07ff0000);
-       nv_wo32(dev, ctx, 0x054c/4, 0x4b7fffff);
-       nv_wo32(dev, ctx, 0x0588/4, 0x00000080);
-       nv_wo32(dev, ctx, 0x058c/4, 0x30201000);
-       nv_wo32(dev, ctx, 0x0590/4, 0x70605040);
-       nv_wo32(dev, ctx, 0x0594/4, 0xb8a89888);
-       nv_wo32(dev, ctx, 0x0598/4, 0xf8e8d8c8);
-       nv_wo32(dev, ctx, 0x05ac/4, 0xb0000000);
+               nv_wo32(ctx, i, 0x07ff0000);
+       nv_wo32(ctx, 0x054c, 0x4b7fffff);
+       nv_wo32(ctx, 0x0588, 0x00000080);
+       nv_wo32(ctx, 0x058c, 0x30201000);
+       nv_wo32(ctx, 0x0590, 0x70605040);
+       nv_wo32(ctx, 0x0594, 0xb8a89888);
+       nv_wo32(ctx, 0x0598, 0xf8e8d8c8);
+       nv_wo32(ctx, 0x05ac, 0xb0000000);
        for (i = 0x0604; i < 0x0644; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00010588);
+               nv_wo32(ctx, i, 0x00010588);
        for (i = 0x0644; i < 0x0684; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00030303);
+               nv_wo32(ctx, i, 0x00030303);
        for (i = 0x06c4; i < 0x0704; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0008aae4);
+               nv_wo32(ctx, i, 0x0008aae4);
        for (i = 0x0704; i < 0x0744; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x01012000);
+               nv_wo32(ctx, i, 0x01012000);
        for (i = 0x0744; i < 0x0784; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00080008);
-       nv_wo32(dev, ctx, 0x0860/4, 0x00040000);
-       nv_wo32(dev, ctx, 0x0864/4, 0x00010000);
+               nv_wo32(ctx, i, 0x00080008);
+       nv_wo32(ctx, 0x0860, 0x00040000);
+       nv_wo32(ctx, 0x0864, 0x00010000);
        for (i = 0x0868; i < 0x0878; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x00040004);
+               nv_wo32(ctx, i, 0x00040004);
        for (i = 0x1f1c; i <= 0x308c ; i += 16) {
-               nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-               nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-               nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+               nv_wo32(ctx, i + 0, 0x10700ff9);
+               nv_wo32(ctx, i + 4, 0x0436086c);
+               nv_wo32(ctx, i + 8, 0x000c001b);
        }
        for (i = 0x30bc; i < 0x30cc; i += 4)
-               nv_wo32(dev, ctx, i/4, 0x0000ffff);
-       nv_wo32(dev, ctx, 0x3450/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x380c/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3820/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x384c/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x3850/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3854/4, 0x3f000000);
-       nv_wo32(dev, ctx, 0x385c/4, 0x40000000);
-       nv_wo32(dev, ctx, 0x3860/4, 0x3f800000);
-       nv_wo32(dev, ctx, 0x3868/4, 0xbf800000);
-       nv_wo32(dev, ctx, 0x3870/4, 0xbf800000);
+               nv_wo32(ctx, i, 0x0000ffff);
+       nv_wo32(ctx, 0x3450, 0x3f800000);
+       nv_wo32(ctx, 0x380c, 0x3f800000);
+       nv_wo32(ctx, 0x3820, 0x3f800000);
+       nv_wo32(ctx, 0x384c, 0x40000000);
+       nv_wo32(ctx, 0x3850, 0x3f800000);
+       nv_wo32(ctx, 0x3854, 0x3f000000);
+       nv_wo32(ctx, 0x385c, 0x40000000);
+       nv_wo32(ctx, 0x3860, 0x3f800000);
+       nv_wo32(ctx, 0x3868, 0xbf800000);
+       nv_wo32(ctx, 0x3870, 0xbf800000);
 }
 
 int
@@ -372,7 +372,7 @@ nv20_graph_create_context(struct nouveau_channel *chan)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
-       unsigned int idoffs = 0x28/4;
+       unsigned int idoffs = 0x28;
        int ret;
 
        switch (dev_priv->chipset) {
@@ -403,21 +403,19 @@ nv20_graph_create_context(struct nouveau_channel *chan)
                BUG_ON(1);
        }
 
-       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-                                    16, NVOBJ_FLAG_ZERO_ALLOC,
-                                    &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
        if (ret)
                return ret;
 
        /* Initialise default context values */
-       ctx_init(dev, chan->ramin_grctx->gpuobj);
+       ctx_init(dev, chan->ramin_grctx);
 
        /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-       nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
-                                       (chan->id << 24) | 0x1); /* CTX_USER */
+       nv_wo32(chan->ramin_grctx, idoffs,
+               (chan->id << 24) | 0x1); /* CTX_USER */
 
-       nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
-                    chan->ramin_grctx->instance >> 4);
+       nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
        return 0;
 }
 
@@ -428,10 +426,8 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 
-       if (chan->ramin_grctx)
-               nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
-
-       nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
+       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+       nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
 }
 
 int
@@ -442,7 +438,7 @@ nv20_graph_load_context(struct nouveau_channel *chan)
 
        if (!chan->ramin_grctx)
                return -EINVAL;
-       inst = chan->ramin_grctx->instance >> 4;
+       inst = chan->ramin_grctx->pinst >> 4;
 
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -465,7 +461,7 @@ nv20_graph_unload_context(struct drm_device *dev)
        chan = pgraph->channel(dev);
        if (!chan)
                return 0;
-       inst = chan->ramin_grctx->instance >> 4;
+       inst = chan->ramin_grctx->pinst >> 4;
 
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -552,15 +548,15 @@ nv20_graph_init(struct drm_device *dev)
 
        if (!pgraph->ctx_table) {
                /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
-                                                 NVOBJ_FLAG_ZERO_ALLOC,
-                                                 &pgraph->ctx_table);
+               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+                                        NVOBJ_FLAG_ZERO_ALLOC,
+                                        &pgraph->ctx_table);
                if (ret)
                        return ret;
        }
 
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->instance >> 4);
+                    pgraph->ctx_table->pinst >> 4);
 
        nv20_graph_rdi(dev);
 
@@ -646,7 +642,7 @@ nv20_graph_takedown(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 
-       nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
+       nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
 }
 
 int
@@ -681,15 +677,15 @@ nv30_graph_init(struct drm_device *dev)
 
        if (!pgraph->ctx_table) {
                /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
-                                                 NVOBJ_FLAG_ZERO_ALLOC,
-                                                 &pgraph->ctx_table);
+               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+                                        NVOBJ_FLAG_ZERO_ALLOC,
+                                        &pgraph->ctx_table);
                if (ret)
                        return ret;
        }
 
        nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->instance >> 4);
+                    pgraph->ctx_table->pinst >> 4);
 
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
index 2b67f1835c3942c4fddbe63b2b84a9050df81134..d337b8b28cdd6f669c315fc677f32a8078428d57 100644 (file)
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
+#include "nouveau_ramht.h"
 
-#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE))
+#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE))
 #define NV40_RAMFC__SIZE 128
 
 int
@@ -42,7 +43,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
 
        ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
                                      NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
-                                     NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+                                     NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
        if (ret)
                return ret;
 
@@ -50,7 +51,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
 
        nv_wi32(dev, fc +  0, chan->pushbuf_base);
        nv_wi32(dev, fc +  4, chan->pushbuf_base);
-       nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+       nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
        nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
                              NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
                              NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -58,7 +59,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
                              NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
                              0x30000000 /* no idea.. */);
-       nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
+       nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4);
        nv_wi32(dev, fc + 60, 0x0001FFFF);
 
        /* enable the fifo dma operation */
@@ -77,8 +78,7 @@ nv40_fifo_destroy_context(struct nouveau_channel *chan)
        nv_wr32(dev, NV04_PFIFO_MODE,
                nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-       if (chan->ramfc)
-               nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -241,9 +241,9 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
        nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-                                      ((dev_priv->ramht_bits - 9) << 16) |
-                                      (dev_priv->ramht_offset >> 8));
-       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+                                      ((dev_priv->ramht->bits - 9) << 16) |
+                                      (dev_priv->ramht->gpuobj->pinst >> 8));
+       nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
 
        switch (dev_priv->chipset) {
        case 0x47:
@@ -271,7 +271,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
                nv_wr32(dev, 0x2230, 0);
                nv_wr32(dev, NV40_PFIFO_RAMFC,
                        ((dev_priv->vram_size - 512 * 1024 +
-                         dev_priv->ramfc_offset) >> 16) | (3 << 16));
+                         dev_priv->ramfc->pinst) >> 16) | (3 << 16));
                break;
        }
 }
index fd7d2b5013167f58e92b0c5859fd965564f2e53d..7ee1b91569b8ad29b22437d21ee915e56c123c6d 100644 (file)
@@ -45,7 +45,7 @@ nv40_graph_channel(struct drm_device *dev)
                struct nouveau_channel *chan = dev_priv->fifos[i];
 
                if (chan && chan->ramin_grctx &&
-                   chan->ramin_grctx->instance == inst)
+                   chan->ramin_grctx->pinst == inst)
                        return chan;
        }
 
@@ -61,27 +61,25 @@ nv40_graph_create_context(struct nouveau_channel *chan)
        struct nouveau_grctx ctx = {};
        int ret;
 
-       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-                                    16, NVOBJ_FLAG_ZERO_ALLOC,
-                                    &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
        if (ret)
                return ret;
 
        /* Initialise default context values */
        ctx.dev = chan->dev;
        ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx->gpuobj;
+       ctx.data = chan->ramin_grctx;
        nv40_grctx_init(&ctx);
 
-       nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
-                    chan->ramin_grctx->gpuobj->im_pramin->start);
+       nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
        return 0;
 }
 
 void
 nv40_graph_destroy_context(struct nouveau_channel *chan)
 {
-       nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx);
+       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
 }
 
 static int
@@ -135,7 +133,7 @@ nv40_graph_load_context(struct nouveau_channel *chan)
 
        if (!chan->ramin_grctx)
                return -EINVAL;
-       inst = chan->ramin_grctx->instance >> 4;
+       inst = chan->ramin_grctx->pinst >> 4;
 
        ret = nv40_graph_transfer_context(dev, inst, 0);
        if (ret)
index 9b5c9746958868b98152446a03cacb78b3d3d010..ce585093264e69af22d0689efb2c3c4a8298c201 100644 (file)
@@ -596,13 +596,13 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx)
 
        offset += 0x0280/4;
        for (i = 0; i < 16; i++, offset += 2)
-               nv_wo32(dev, obj, offset, 0x3f800000);
+               nv_wo32(obj, offset * 4, 0x3f800000);
 
        for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
                for (i = 0; i < vs_nr_b0 * 6; i += 6)
-                       nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001);
+                       nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
                for (i = 0; i < vs_nr_b1 * 4; i += 4)
-                       nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000);
+                       nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
        }
 }
 
index bfd4ca2fe7ef3de146accfe37895bb1e5a760784..16380d52cd885599f349219c903f12cf7b9c6159 100644 (file)
@@ -104,8 +104,7 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
                OUT_RING(evo, nv_crtc->lut.depth == 8 ?
                                NV50_EVO_CRTC_CLUT_MODE_OFF :
                                NV50_EVO_CRTC_CLUT_MODE_ON);
-               OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.mm_node->start <<
-                                PAGE_SHIFT) >> 8);
+               OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.start << PAGE_SHIFT) >> 8);
                if (dev_priv->chipset != 0x50) {
                        BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
                        OUT_RING(evo, NvEvoVRAM);
@@ -266,15 +265,10 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct pll_lims pll;
-       uint32_t reg, reg1, reg2;
+       uint32_t reg1, reg2;
        int ret, N1, M1, N2, M2, P;
 
-       if (dev_priv->chipset < NV_C0)
-               reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
-       else
-               reg = 0x614140 + (head * 0x800);
-
-       ret = get_pll_limits(dev, reg, &pll);
+       ret = get_pll_limits(dev, PLL_VPLL0 + head, &pll);
        if (ret)
                return ret;
 
@@ -286,11 +280,11 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
                         pclk, ret, N1, M1, N2, M2, P);
 
-               reg1 = nv_rd32(dev, reg + 4) & 0xff00ff00;
-               reg2 = nv_rd32(dev, reg + 8) & 0x8000ff00;
-               nv_wr32(dev, reg, 0x10000611);
-               nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
-               nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
+               reg1 = nv_rd32(dev, pll.reg + 4) & 0xff00ff00;
+               reg2 = nv_rd32(dev, pll.reg + 8) & 0x8000ff00;
+               nv_wr32(dev, pll.reg + 0, 0x10000611);
+               nv_wr32(dev, pll.reg + 4, reg1 | (M1 << 16) | N1);
+               nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
        } else
        if (dev_priv->chipset < NV_C0) {
                ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
@@ -300,10 +294,10 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
                         pclk, ret, N1, N2, M1, P);
 
-               reg1 = nv_rd32(dev, reg + 4) & 0xffc00000;
-               nv_wr32(dev, reg, 0x50000610);
-               nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
-               nv_wr32(dev, reg + 8, N2);
+               reg1 = nv_rd32(dev, pll.reg + 4) & 0xffc00000;
+               nv_wr32(dev, pll.reg + 0, 0x50000610);
+               nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
+               nv_wr32(dev, pll.reg + 8, N2);
        } else {
                ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
@@ -312,9 +306,9 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
                         pclk, ret, N1, N2, M1, P);
 
-               nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
-               nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
-               nv_wr32(dev, reg + 0x10, N2 << 16);
+               nv_mask(dev, pll.reg + 0x0c, 0x00000000, 0x00000100);
+               nv_wr32(dev, pll.reg + 0x04, (P << 16) | (N1 << 8) | M1);
+               nv_wr32(dev, pll.reg + 0x10, N2 << 16);
        }
 
        return 0;
@@ -338,7 +332,9 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
 
        nv50_cursor_fini(nv_crtc);
 
+       nouveau_bo_unmap(nv_crtc->lut.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+       nouveau_bo_unmap(nv_crtc->cursor.nvbo);
        nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
        kfree(nv_crtc->mode);
        kfree(nv_crtc);
@@ -491,8 +487,9 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
 }
 
 static int
-nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                          struct drm_framebuffer *old_fb, bool update)
+nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
+                          struct drm_framebuffer *passed_fb,
+                          int x, int y, bool update, bool atomic)
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = nv_crtc->base.dev;
@@ -504,6 +501,28 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
 
        NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
+       /* If atomic, we want to switch to the fb we were passed, so
+        * now we update pointers to do that.  (We don't pin; just
+        * assume we're already pinned and update the base address.)
+        */
+       if (atomic) {
+               drm_fb = passed_fb;
+               fb = nouveau_framebuffer(passed_fb);
+       }
+       else {
+               /* If not atomic, we can go ahead and pin, and unpin the
+                * old fb we were passed.
+                */
+               ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       return ret;
+
+               if (passed_fb) {
+                       struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+                       nouveau_bo_unpin(ofb->nvbo);
+               }
+       }
+
        switch (drm_fb->depth) {
        case  8:
                format = NV50_EVO_CRTC_FB_DEPTH_8;
@@ -526,15 +545,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
                 return -EINVAL;
        }
 
-       ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
-       if (ret)
-               return ret;
-
-       if (old_fb) {
-               struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
-               nouveau_bo_unpin(ofb->nvbo);
-       }
-
        nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
        nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
        nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
@@ -685,14 +695,22 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
        nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
        nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
 
-       return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, false);
+       return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false);
 }
 
 static int
 nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                        struct drm_framebuffer *old_fb)
 {
-       return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, true);
+       return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false);
+}
+
+static int
+nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+                              struct drm_framebuffer *fb,
+                              int x, int y, enum mode_set_atomic state)
+{
+       return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true);
 }
 
 static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
@@ -702,6 +720,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
        .mode_fixup = nv50_crtc_mode_fixup,
        .mode_set = nv50_crtc_mode_set,
        .mode_set_base = nv50_crtc_mode_set_base,
+       .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
        .load_lut = nv50_crtc_lut_load,
 };
 
index 03ad7ab14f0960e1729674cd637a15ff325ae169..1b9ce3021aa3ae4ea3329a882be9dffebb1acaee 100644 (file)
@@ -147,7 +147,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
        NV_DEBUG_KMS(dev, "\n");
 
        nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
-       if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
+       if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
                     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
                NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
                NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
index 1bc085962945056aba2e5ea5acfc8c72a5ca5da2..875414b09adea8bfd3ae46842b1447314ca2cd3f 100644 (file)
@@ -79,7 +79,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 
        nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
-       if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+       if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
                NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
                NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -130,7 +130,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
        NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
 
        /* wait for it to be done */
-       if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+       if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
                NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
                NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
index 612fa6d6a0cba9d415b9277308969043fe65a2d8..55c9663ef2bf8ddd4df2cf15b452daed66abc583 100644 (file)
 #include "nouveau_connector.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
 #include "drm_crtc_helper.h"
 
+static inline int
+nv50_sor_nr(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->chipset  < 0x90 ||
+           dev_priv->chipset == 0x92 ||
+           dev_priv->chipset == 0xa0)
+               return 2;
+
+       return 4;
+}
+
 static void
 nv50_evo_channel_del(struct nouveau_channel **pchan)
 {
@@ -42,6 +56,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan)
        *pchan = NULL;
 
        nouveau_gpuobj_channel_takedown(chan);
+       nouveau_bo_unmap(chan->pushbuf_bo);
        nouveau_bo_ref(NULL, &chan->pushbuf_bo);
 
        if (chan->user)
@@ -65,23 +80,23 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
                return ret;
        obj->engine = NVOBJ_ENGINE_DISPLAY;
 
-       ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL);
-       if (ret) {
-               nouveau_gpuobj_del(dev, &obj);
-               return ret;
-       }
-
-       nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
-       nv_wo32(dev, obj, 1, limit);
-       nv_wo32(dev, obj, 2, offset);
-       nv_wo32(dev, obj, 3, 0x00000000);
-       nv_wo32(dev, obj, 4, 0x00000000);
+       nv_wo32(obj,  0, (tile_flags << 22) | (magic_flags << 16) | class);
+       nv_wo32(obj,  4, limit);
+       nv_wo32(obj,  8, offset);
+       nv_wo32(obj, 12, 0x00000000);
+       nv_wo32(obj, 16, 0x00000000);
        if (dev_priv->card_type < NV_C0)
-               nv_wo32(dev, obj, 5, 0x00010000);
+               nv_wo32(obj, 20, 0x00010000);
        else
-               nv_wo32(dev, obj, 5, 0x00020000);
+               nv_wo32(obj, 20, 0x00020000);
        dev_priv->engine.instmem.flush(dev);
 
+       ret = nouveau_ramht_insert(evo, name, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       if (ret) {
+               return ret;
+       }
+
        return 0;
 }
 
@@ -89,6 +104,7 @@ static int
 nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramht = NULL;
        struct nouveau_channel *chan;
        int ret;
 
@@ -102,32 +118,35 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
        chan->user_get = 4;
        chan->user_put = 0;
 
-       INIT_LIST_HEAD(&chan->ramht_refs);
-
-       ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000,
-                                    NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
+       ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
        if (ret) {
                NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
                nv50_evo_channel_del(pchan);
                return ret;
        }
 
-       ret = drm_mm_init(&chan->ramin_heap,
-                         chan->ramin->gpuobj->im_pramin->start, 32768);
+       ret = drm_mm_init(&chan->ramin_heap, 0, 32768);
        if (ret) {
                NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
                nv50_evo_channel_del(pchan);
                return ret;
        }
 
-       ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16,
-                                    0, &chan->ramht);
+       ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht);
        if (ret) {
                NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
                nv50_evo_channel_del(pchan);
                return ret;
        }
 
+       ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+       nouveau_gpuobj_ref(NULL, &ramht);
+       if (ret) {
+               nv50_evo_channel_del(pchan);
+               return ret;
+       }
+
        if (dev_priv->chipset != 0x50) {
                ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19,
                                          0, 0xffffffff);
@@ -227,11 +246,11 @@ nv50_display_init(struct drm_device *dev)
                nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
        }
        /* SOR */
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < nv50_sor_nr(dev); i++) {
                val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
                nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
        }
-       /* Something not yet in use, tv-out maybe. */
+       /* EXT */
        for (i = 0; i < 3; i++) {
                val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
                nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
@@ -260,7 +279,7 @@ nv50_display_init(struct drm_device *dev)
        if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
                nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
                nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
-               if (!nv_wait(0x006194e8, 2, 0)) {
+               if (!nv_wait(dev, 0x006194e8, 2, 0)) {
                        NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
                        NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
                                                nv_rd32(dev, 0x6194e8));
@@ -291,7 +310,8 @@ nv50_display_init(struct drm_device *dev)
 
        nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE);
        nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03);
-       if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) {
+       if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
+                    0x40000000, 0x40000000)) {
                NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n");
                NV_ERROR(dev, "0x610200 = 0x%08x\n",
                          nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
@@ -300,7 +320,7 @@ nv50_display_init(struct drm_device *dev)
 
        for (i = 0; i < 2; i++) {
                nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
-               if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
                        NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
                        NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
@@ -310,7 +330,7 @@ nv50_display_init(struct drm_device *dev)
 
                nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                        NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
-               if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+               if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
                             NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
                        NV_ERROR(dev, "timeout: "
@@ -321,16 +341,16 @@ nv50_display_init(struct drm_device *dev)
                }
        }
 
-       nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9);
+       nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
 
        /* initialise fifo */
        nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0),
-               ((evo->pushbuf_bo->bo.mem.mm_node->start << PAGE_SHIFT) >> 8) |
+               ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) |
                NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM |
                NV50_PDISPLAY_CHANNEL_DMA_CB_VALID);
        nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000);
        nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002);
-       if (!nv_wait(0x610200, 0x80000000, 0x00000000)) {
+       if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) {
                NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n");
                NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200));
                return -EBUSY;
@@ -370,7 +390,7 @@ nv50_display_init(struct drm_device *dev)
        BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
        OUT_RING(evo, 0);
        FIRE_RING(evo);
-       if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2))
+       if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
                NV_ERROR(dev, "evo pushbuf stalled\n");
 
        /* enable clock change interrupts. */
@@ -424,7 +444,7 @@ static int nv50_display_disable(struct drm_device *dev)
                        continue;
 
                nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
-               if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) {
+               if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
                        NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
                                      "0x%08x\n", mask, mask);
                        NV_ERROR(dev, "0x610024 = 0x%08x\n",
@@ -434,14 +454,14 @@ static int nv50_display_disable(struct drm_device *dev)
 
        nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0);
        nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0);
-       if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
+       if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
                NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n");
                NV_ERROR(dev, "0x610200 = 0x%08x\n",
                          nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
        }
 
        for (i = 0; i < 3; i++) {
-               if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i),
+               if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
                             NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
                        NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
                        NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
@@ -710,7 +730,7 @@ nv50_display_unk10_handler(struct drm_device *dev)
                or = i;
        }
 
-       for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+       for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
                if (dev_priv->chipset  < 0x90 ||
                    dev_priv->chipset == 0x92 ||
                    dev_priv->chipset == 0xa0)
@@ -841,7 +861,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
                or = i;
        }
 
-       for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+       for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
                if (dev_priv->chipset  < 0x90 ||
                    dev_priv->chipset == 0x92 ||
                    dev_priv->chipset == 0xa0)
index 32611bd30e6db6524a44588f06602c33266fb4bc..cd1988b15d2c9f3c2318bd6eba07bf935e3086eb 100644 (file)
@@ -20,6 +20,7 @@ nv50_fb_init(struct drm_device *dev)
        case 0x50:
                nv_wr32(dev, 0x100c90, 0x0707ff);
                break;
+       case 0xa3:
        case 0xa5:
        case 0xa8:
                nv_wr32(dev, 0x100c90, 0x0d0fff);
@@ -36,3 +37,42 @@ void
 nv50_fb_takedown(struct drm_device *dev)
 {
 }
+
+void
+nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u32 trap[6], idx, chinst;
+       int i, ch;
+
+       idx = nv_rd32(dev, 0x100c90);
+       if (!(idx & 0x80000000))
+               return;
+       idx &= 0x00ffffff;
+
+       for (i = 0; i < 6; i++) {
+               nv_wr32(dev, 0x100c90, idx | i << 24);
+               trap[i] = nv_rd32(dev, 0x100c94);
+       }
+       nv_wr32(dev, 0x100c90, idx | 0x80000000);
+
+       if (!display)
+               return;
+
+       chinst = (trap[2] << 16) | trap[1];
+       for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
+               struct nouveau_channel *chan = dev_priv->fifos[ch];
+
+               if (!chan || !chan->ramin)
+                       continue;
+
+               if (chinst == chan->ramin->vinst >> 12)
+                       break;
+       }
+
+       NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x "
+                    "channel %d (0x%08x)\n",
+               name, (trap[5] & 0x100 ? "read" : "write"),
+               trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
+               trap[0], ch, chinst);
+}
index 6bf025c6fc6fc14b5fff7a94938a20cc2426a102..6dcf048eddbc7130b753b0e64f6de65d7f10887d 100644 (file)
@@ -1,6 +1,7 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 #include "nouveau_fbcon.h"
 
 void
@@ -193,7 +194,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
        if (ret)
                return ret;
 
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
+       ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
+       nouveau_gpuobj_ref(NULL, &eng2d);
        if (ret)
                return ret;
 
index fb0281ae8f90569508711a5edd275cea064da6df..a46a961102f39052832856cac762e3cfe8ae1f88 100644 (file)
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 static void
 nv50_fifo_playlist_update(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_gpuobj_ref *cur;
+       struct nouveau_gpuobj *cur;
        int i, nr;
 
        NV_DEBUG(dev, "\n");
@@ -43,12 +44,14 @@ nv50_fifo_playlist_update(struct drm_device *dev)
 
        /* We never schedule channel 0 or 127 */
        for (i = 1, nr = 0; i < 127; i++) {
-               if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
-                       nv_wo32(dev, cur->gpuobj, nr++, i);
+               if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) {
+                       nv_wo32(cur, (nr * 4), i);
+                       nr++;
+               }
        }
        dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, 0x32f4, cur->instance >> 12);
+       nv_wr32(dev, 0x32f4, cur->vinst >> 12);
        nv_wr32(dev, 0x32ec, nr);
        nv_wr32(dev, 0x2500, 0x101);
 }
@@ -63,9 +66,9 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel)
        NV_DEBUG(dev, "ch%d\n", channel);
 
        if (dev_priv->chipset == 0x50)
-               inst = chan->ramfc->instance >> 12;
+               inst = chan->ramfc->vinst >> 12;
        else
-               inst = chan->ramfc->instance >> 8;
+               inst = chan->ramfc->vinst >> 8;
 
        nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
                     NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
@@ -163,19 +166,19 @@ nv50_fifo_init(struct drm_device *dev)
                goto just_reset;
        }
 
-       ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
-                                    NVOBJ_FLAG_ZERO_ALLOC,
-                                    &pfifo->playlist[0]);
+       ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC,
+                                &pfifo->playlist[0]);
        if (ret) {
                NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
                return ret;
        }
 
-       ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
-                                    NVOBJ_FLAG_ZERO_ALLOC,
-                                    &pfifo->playlist[1]);
+       ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC,
+                                &pfifo->playlist[1]);
        if (ret) {
-               nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+               nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
                NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
                return ret;
        }
@@ -203,8 +206,8 @@ nv50_fifo_takedown(struct drm_device *dev)
        if (!pfifo->playlist[0])
                return;
 
-       nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
-       nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
+       nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
+       nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
 }
 
 int
@@ -226,59 +229,54 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
        if (dev_priv->chipset == 0x50) {
-               uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
-               uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
-
-               ret = nouveau_gpuobj_new_fake(dev, ramin_poffset, ramin_voffset,
-                                             0x100, NVOBJ_FLAG_ZERO_ALLOC |
-                                             NVOBJ_FLAG_ZERO_FREE, &ramfc,
+               ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
+                                             chan->ramin->vinst, 0x100,
+                                             NVOBJ_FLAG_ZERO_ALLOC |
+                                             NVOBJ_FLAG_ZERO_FREE,
                                              &chan->ramfc);
                if (ret)
                        return ret;
 
-               ret = nouveau_gpuobj_new_fake(dev, ramin_poffset + 0x0400,
-                                             ramin_voffset + 0x0400, 4096,
-                                             0, NULL, &chan->cache);
+               ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400,
+                                             chan->ramin->vinst + 0x0400,
+                                             4096, 0, &chan->cache);
                if (ret)
                        return ret;
        } else {
-               ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256,
-                                            NVOBJ_FLAG_ZERO_ALLOC |
-                                            NVOBJ_FLAG_ZERO_FREE,
-                                            &chan->ramfc);
+               ret = nouveau_gpuobj_new(dev, chan, 0x100, 256,
+                                        NVOBJ_FLAG_ZERO_ALLOC |
+                                        NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
                if (ret)
                        return ret;
-               ramfc = chan->ramfc->gpuobj;
 
-               ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
-                                            0, &chan->cache);
+               ret = nouveau_gpuobj_new(dev, chan, 4096, 1024,
+                                        0, &chan->cache);
                if (ret)
                        return ret;
        }
+       ramfc = chan->ramfc;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
 
-       nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
-       nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
-                                   (4 << 24) /* SEARCH_FULL */ |
-                                   (chan->ramht->instance >> 4));
-       nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
-       nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
-       nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
-       nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
-       nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
-       nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
-       nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
-                                   chan->dma.ib_base * 4);
-       nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
+       nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
+       nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+                            (4 << 24) /* SEARCH_FULL */ |
+                            (chan->ramht->gpuobj->cinst >> 4));
+       nv_wo32(ramfc, 0x44, 0x2101ffff);
+       nv_wo32(ramfc, 0x60, 0x7fffffff);
+       nv_wo32(ramfc, 0x40, 0x00000000);
+       nv_wo32(ramfc, 0x7c, 0x30000001);
+       nv_wo32(ramfc, 0x78, 0x00000000);
+       nv_wo32(ramfc, 0x3c, 0x403f6078);
+       nv_wo32(ramfc, 0x50, chan->pushbuf_base + chan->dma.ib_base * 4);
+       nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16);
 
        if (dev_priv->chipset != 0x50) {
-               nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
-               nv_wo32(dev, chan->ramin->gpuobj, 1,
-                                               chan->ramfc->instance >> 8);
+               nv_wo32(chan->ramin, 0, chan->id);
+               nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8);
 
-               nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10);
-               nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
+               nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10);
+               nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12);
        }
 
        dev_priv->engine.instmem.flush(dev);
@@ -293,12 +291,13 @@ void
 nv50_fifo_destroy_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
-       struct nouveau_gpuobj_ref *ramfc = chan->ramfc;
+       struct nouveau_gpuobj *ramfc = NULL;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
        /* This will ensure the channel is seen as disabled. */
-       chan->ramfc = NULL;
+       nouveau_gpuobj_ref(chan->ramfc, &ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->ramfc);
        nv50_fifo_channel_disable(dev, chan->id);
 
        /* Dummy channel, also used on ch 127 */
@@ -306,8 +305,8 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
                nv50_fifo_channel_disable(dev, 127);
        nv50_fifo_playlist_update(dev);
 
-       nouveau_gpuobj_ref_del(dev, &ramfc);
-       nouveau_gpuobj_ref_del(dev, &chan->cache);
+       nouveau_gpuobj_ref(NULL, &ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->cache);
 }
 
 int
@@ -315,63 +314,63 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj;
-       struct nouveau_gpuobj *cache = chan->cache->gpuobj;
+       struct nouveau_gpuobj *ramfc = chan->ramfc;
+       struct nouveau_gpuobj *cache = chan->cache;
        int ptr, cnt;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
-       nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
-       nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
-       nv_wr32(dev, 0x3320, nv_ro32(dev, ramfc, 0x0c/4));
-       nv_wr32(dev, 0x3244, nv_ro32(dev, ramfc, 0x10/4));
-       nv_wr32(dev, 0x3328, nv_ro32(dev, ramfc, 0x14/4));
-       nv_wr32(dev, 0x3368, nv_ro32(dev, ramfc, 0x18/4));
-       nv_wr32(dev, 0x336c, nv_ro32(dev, ramfc, 0x1c/4));
-       nv_wr32(dev, 0x3370, nv_ro32(dev, ramfc, 0x20/4));
-       nv_wr32(dev, 0x3374, nv_ro32(dev, ramfc, 0x24/4));
-       nv_wr32(dev, 0x3378, nv_ro32(dev, ramfc, 0x28/4));
-       nv_wr32(dev, 0x337c, nv_ro32(dev, ramfc, 0x2c/4));
-       nv_wr32(dev, 0x3228, nv_ro32(dev, ramfc, 0x30/4));
-       nv_wr32(dev, 0x3364, nv_ro32(dev, ramfc, 0x34/4));
-       nv_wr32(dev, 0x32a0, nv_ro32(dev, ramfc, 0x38/4));
-       nv_wr32(dev, 0x3224, nv_ro32(dev, ramfc, 0x3c/4));
-       nv_wr32(dev, 0x324c, nv_ro32(dev, ramfc, 0x40/4));
-       nv_wr32(dev, 0x2044, nv_ro32(dev, ramfc, 0x44/4));
-       nv_wr32(dev, 0x322c, nv_ro32(dev, ramfc, 0x48/4));
-       nv_wr32(dev, 0x3234, nv_ro32(dev, ramfc, 0x4c/4));
-       nv_wr32(dev, 0x3340, nv_ro32(dev, ramfc, 0x50/4));
-       nv_wr32(dev, 0x3344, nv_ro32(dev, ramfc, 0x54/4));
-       nv_wr32(dev, 0x3280, nv_ro32(dev, ramfc, 0x58/4));
-       nv_wr32(dev, 0x3254, nv_ro32(dev, ramfc, 0x5c/4));
-       nv_wr32(dev, 0x3260, nv_ro32(dev, ramfc, 0x60/4));
-       nv_wr32(dev, 0x3264, nv_ro32(dev, ramfc, 0x64/4));
-       nv_wr32(dev, 0x3268, nv_ro32(dev, ramfc, 0x68/4));
-       nv_wr32(dev, 0x326c, nv_ro32(dev, ramfc, 0x6c/4));
-       nv_wr32(dev, 0x32e4, nv_ro32(dev, ramfc, 0x70/4));
-       nv_wr32(dev, 0x3248, nv_ro32(dev, ramfc, 0x74/4));
-       nv_wr32(dev, 0x2088, nv_ro32(dev, ramfc, 0x78/4));
-       nv_wr32(dev, 0x2058, nv_ro32(dev, ramfc, 0x7c/4));
-       nv_wr32(dev, 0x2210, nv_ro32(dev, ramfc, 0x80/4));
-
-       cnt = nv_ro32(dev, ramfc, 0x84/4);
+       nv_wr32(dev, 0x3330, nv_ro32(ramfc, 0x00));
+       nv_wr32(dev, 0x3334, nv_ro32(ramfc, 0x04));
+       nv_wr32(dev, 0x3240, nv_ro32(ramfc, 0x08));
+       nv_wr32(dev, 0x3320, nv_ro32(ramfc, 0x0c));
+       nv_wr32(dev, 0x3244, nv_ro32(ramfc, 0x10));
+       nv_wr32(dev, 0x3328, nv_ro32(ramfc, 0x14));
+       nv_wr32(dev, 0x3368, nv_ro32(ramfc, 0x18));
+       nv_wr32(dev, 0x336c, nv_ro32(ramfc, 0x1c));
+       nv_wr32(dev, 0x3370, nv_ro32(ramfc, 0x20));
+       nv_wr32(dev, 0x3374, nv_ro32(ramfc, 0x24));
+       nv_wr32(dev, 0x3378, nv_ro32(ramfc, 0x28));
+       nv_wr32(dev, 0x337c, nv_ro32(ramfc, 0x2c));
+       nv_wr32(dev, 0x3228, nv_ro32(ramfc, 0x30));
+       nv_wr32(dev, 0x3364, nv_ro32(ramfc, 0x34));
+       nv_wr32(dev, 0x32a0, nv_ro32(ramfc, 0x38));
+       nv_wr32(dev, 0x3224, nv_ro32(ramfc, 0x3c));
+       nv_wr32(dev, 0x324c, nv_ro32(ramfc, 0x40));
+       nv_wr32(dev, 0x2044, nv_ro32(ramfc, 0x44));
+       nv_wr32(dev, 0x322c, nv_ro32(ramfc, 0x48));
+       nv_wr32(dev, 0x3234, nv_ro32(ramfc, 0x4c));
+       nv_wr32(dev, 0x3340, nv_ro32(ramfc, 0x50));
+       nv_wr32(dev, 0x3344, nv_ro32(ramfc, 0x54));
+       nv_wr32(dev, 0x3280, nv_ro32(ramfc, 0x58));
+       nv_wr32(dev, 0x3254, nv_ro32(ramfc, 0x5c));
+       nv_wr32(dev, 0x3260, nv_ro32(ramfc, 0x60));
+       nv_wr32(dev, 0x3264, nv_ro32(ramfc, 0x64));
+       nv_wr32(dev, 0x3268, nv_ro32(ramfc, 0x68));
+       nv_wr32(dev, 0x326c, nv_ro32(ramfc, 0x6c));
+       nv_wr32(dev, 0x32e4, nv_ro32(ramfc, 0x70));
+       nv_wr32(dev, 0x3248, nv_ro32(ramfc, 0x74));
+       nv_wr32(dev, 0x2088, nv_ro32(ramfc, 0x78));
+       nv_wr32(dev, 0x2058, nv_ro32(ramfc, 0x7c));
+       nv_wr32(dev, 0x2210, nv_ro32(ramfc, 0x80));
+
+       cnt = nv_ro32(ramfc, 0x84);
        for (ptr = 0; ptr < cnt; ptr++) {
                nv_wr32(dev, NV40_PFIFO_CACHE1_METHOD(ptr),
-                       nv_ro32(dev, cache, (ptr * 2) + 0));
+                       nv_ro32(cache, (ptr * 8) + 0));
                nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr),
-                       nv_ro32(dev, cache, (ptr * 2) + 1));
+                       nv_ro32(cache, (ptr * 8) + 4));
        }
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2);
        nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
 
        /* guessing that all the 0x34xx regs aren't on NV50 */
        if (dev_priv->chipset != 0x50) {
-               nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
-               nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
-               nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
-               nv_wr32(dev, 0x3408, nv_ro32(dev, ramfc, 0x94/4));
-               nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
+               nv_wr32(dev, 0x340c, nv_ro32(ramfc, 0x88));
+               nv_wr32(dev, 0x3400, nv_ro32(ramfc, 0x8c));
+               nv_wr32(dev, 0x3404, nv_ro32(ramfc, 0x90));
+               nv_wr32(dev, 0x3408, nv_ro32(ramfc, 0x94));
+               nv_wr32(dev, 0x3410, nv_ro32(ramfc, 0x98));
        }
 
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
@@ -399,62 +398,63 @@ nv50_fifo_unload_context(struct drm_device *dev)
                return -EINVAL;
        }
        NV_DEBUG(dev, "ch%d\n", chan->id);
-       ramfc = chan->ramfc->gpuobj;
-       cache = chan->cache->gpuobj;
-
-       nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
-       nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
-       nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
-       nv_wo32(dev, ramfc, 0x0c/4, nv_rd32(dev, 0x3320));
-       nv_wo32(dev, ramfc, 0x10/4, nv_rd32(dev, 0x3244));
-       nv_wo32(dev, ramfc, 0x14/4, nv_rd32(dev, 0x3328));
-       nv_wo32(dev, ramfc, 0x18/4, nv_rd32(dev, 0x3368));
-       nv_wo32(dev, ramfc, 0x1c/4, nv_rd32(dev, 0x336c));
-       nv_wo32(dev, ramfc, 0x20/4, nv_rd32(dev, 0x3370));
-       nv_wo32(dev, ramfc, 0x24/4, nv_rd32(dev, 0x3374));
-       nv_wo32(dev, ramfc, 0x28/4, nv_rd32(dev, 0x3378));
-       nv_wo32(dev, ramfc, 0x2c/4, nv_rd32(dev, 0x337c));
-       nv_wo32(dev, ramfc, 0x30/4, nv_rd32(dev, 0x3228));
-       nv_wo32(dev, ramfc, 0x34/4, nv_rd32(dev, 0x3364));
-       nv_wo32(dev, ramfc, 0x38/4, nv_rd32(dev, 0x32a0));
-       nv_wo32(dev, ramfc, 0x3c/4, nv_rd32(dev, 0x3224));
-       nv_wo32(dev, ramfc, 0x40/4, nv_rd32(dev, 0x324c));
-       nv_wo32(dev, ramfc, 0x44/4, nv_rd32(dev, 0x2044));
-       nv_wo32(dev, ramfc, 0x48/4, nv_rd32(dev, 0x322c));
-       nv_wo32(dev, ramfc, 0x4c/4, nv_rd32(dev, 0x3234));
-       nv_wo32(dev, ramfc, 0x50/4, nv_rd32(dev, 0x3340));
-       nv_wo32(dev, ramfc, 0x54/4, nv_rd32(dev, 0x3344));
-       nv_wo32(dev, ramfc, 0x58/4, nv_rd32(dev, 0x3280));
-       nv_wo32(dev, ramfc, 0x5c/4, nv_rd32(dev, 0x3254));
-       nv_wo32(dev, ramfc, 0x60/4, nv_rd32(dev, 0x3260));
-       nv_wo32(dev, ramfc, 0x64/4, nv_rd32(dev, 0x3264));
-       nv_wo32(dev, ramfc, 0x68/4, nv_rd32(dev, 0x3268));
-       nv_wo32(dev, ramfc, 0x6c/4, nv_rd32(dev, 0x326c));
-       nv_wo32(dev, ramfc, 0x70/4, nv_rd32(dev, 0x32e4));
-       nv_wo32(dev, ramfc, 0x74/4, nv_rd32(dev, 0x3248));
-       nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088));
-       nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058));
-       nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210));
+       ramfc = chan->ramfc;
+       cache = chan->cache;
+
+       nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330));
+       nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334));
+       nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240));
+       nv_wo32(ramfc, 0x0c, nv_rd32(dev, 0x3320));
+       nv_wo32(ramfc, 0x10, nv_rd32(dev, 0x3244));
+       nv_wo32(ramfc, 0x14, nv_rd32(dev, 0x3328));
+       nv_wo32(ramfc, 0x18, nv_rd32(dev, 0x3368));
+       nv_wo32(ramfc, 0x1c, nv_rd32(dev, 0x336c));
+       nv_wo32(ramfc, 0x20, nv_rd32(dev, 0x3370));
+       nv_wo32(ramfc, 0x24, nv_rd32(dev, 0x3374));
+       nv_wo32(ramfc, 0x28, nv_rd32(dev, 0x3378));
+       nv_wo32(ramfc, 0x2c, nv_rd32(dev, 0x337c));
+       nv_wo32(ramfc, 0x30, nv_rd32(dev, 0x3228));
+       nv_wo32(ramfc, 0x34, nv_rd32(dev, 0x3364));
+       nv_wo32(ramfc, 0x38, nv_rd32(dev, 0x32a0));
+       nv_wo32(ramfc, 0x3c, nv_rd32(dev, 0x3224));
+       nv_wo32(ramfc, 0x40, nv_rd32(dev, 0x324c));
+       nv_wo32(ramfc, 0x44, nv_rd32(dev, 0x2044));
+       nv_wo32(ramfc, 0x48, nv_rd32(dev, 0x322c));
+       nv_wo32(ramfc, 0x4c, nv_rd32(dev, 0x3234));
+       nv_wo32(ramfc, 0x50, nv_rd32(dev, 0x3340));
+       nv_wo32(ramfc, 0x54, nv_rd32(dev, 0x3344));
+       nv_wo32(ramfc, 0x58, nv_rd32(dev, 0x3280));
+       nv_wo32(ramfc, 0x5c, nv_rd32(dev, 0x3254));
+       nv_wo32(ramfc, 0x60, nv_rd32(dev, 0x3260));
+       nv_wo32(ramfc, 0x64, nv_rd32(dev, 0x3264));
+       nv_wo32(ramfc, 0x68, nv_rd32(dev, 0x3268));
+       nv_wo32(ramfc, 0x6c, nv_rd32(dev, 0x326c));
+       nv_wo32(ramfc, 0x70, nv_rd32(dev, 0x32e4));
+       nv_wo32(ramfc, 0x74, nv_rd32(dev, 0x3248));
+       nv_wo32(ramfc, 0x78, nv_rd32(dev, 0x2088));
+       nv_wo32(ramfc, 0x7c, nv_rd32(dev, 0x2058));
+       nv_wo32(ramfc, 0x80, nv_rd32(dev, 0x2210));
 
        put = (nv_rd32(dev, NV03_PFIFO_CACHE1_PUT) & 0x7ff) >> 2;
        get = (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) & 0x7ff) >> 2;
        ptr = 0;
        while (put != get) {
-               nv_wo32(dev, cache, ptr++,
-                           nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
-               nv_wo32(dev, cache, ptr++,
-                           nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
+               nv_wo32(cache, ptr + 0,
+                       nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
+               nv_wo32(cache, ptr + 4,
+                       nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
                get = (get + 1) & 0x1ff;
+               ptr += 8;
        }
 
        /* guessing that all the 0x34xx regs aren't on NV50 */
        if (dev_priv->chipset != 0x50) {
-               nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
-               nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
-               nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
-               nv_wo32(dev, ramfc, 0x90/4, nv_rd32(dev, 0x3404));
-               nv_wo32(dev, ramfc, 0x94/4, nv_rd32(dev, 0x3408));
-               nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
+               nv_wo32(ramfc, 0x84, ptr >> 3);
+               nv_wo32(ramfc, 0x88, nv_rd32(dev, 0x340c));
+               nv_wo32(ramfc, 0x8c, nv_rd32(dev, 0x3400));
+               nv_wo32(ramfc, 0x90, nv_rd32(dev, 0x3404));
+               nv_wo32(ramfc, 0x94, nv_rd32(dev, 0x3408));
+               nv_wo32(ramfc, 0x98, nv_rd32(dev, 0x3410));
        }
 
        dev_priv->engine.instmem.flush(dev);
index 1413028e15808b8f9ea476bd7e0d81f948801b40..cbf5ae2f67d4a110de1bb9d9c129224fbcdd6c3c 100644 (file)
@@ -27,7 +27,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
-
+#include "nouveau_ramht.h"
 #include "nouveau_grctx.h"
 
 static void
@@ -181,7 +181,7 @@ nv50_graph_channel(struct drm_device *dev)
        /* Be sure we're not in the middle of a context switch or bad things
         * will happen, such as unloading the wrong pgraph context.
         */
-       if (!nv_wait(0x400300, 0x00000001, 0x00000000))
+       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
                NV_ERROR(dev, "Ctxprog is still running\n");
 
        inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
@@ -192,7 +192,7 @@ nv50_graph_channel(struct drm_device *dev)
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
                struct nouveau_channel *chan = dev_priv->fifos[i];
 
-               if (chan && chan->ramin && chan->ramin->instance == inst)
+               if (chan && chan->ramin && chan->ramin->vinst == inst)
                        return chan;
        }
 
@@ -204,36 +204,34 @@ nv50_graph_create_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
-       struct nouveau_gpuobj *obj;
+       struct nouveau_gpuobj *ramin = chan->ramin;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_grctx ctx = {};
        int hdr, ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-                                    0x1000, NVOBJ_FLAG_ZERO_ALLOC |
-                                    NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
        if (ret)
                return ret;
-       obj = chan->ramin_grctx->gpuobj;
 
        hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-       nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
-       nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
-                                          pgraph->grctx_size - 1);
-       nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
-       nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
-       nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
-       nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
+       nv_wo32(ramin, hdr + 0x00, 0x00190002);
+       nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
+                                  pgraph->grctx_size - 1);
+       nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+       nv_wo32(ramin, hdr + 0x0c, 0);
+       nv_wo32(ramin, hdr + 0x10, 0);
+       nv_wo32(ramin, hdr + 0x14, 0x00010000);
 
        ctx.dev = chan->dev;
        ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = obj;
+       ctx.data = chan->ramin_grctx;
        nv50_grctx_init(&ctx);
 
-       nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
+       nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
 
        dev_priv->engine.instmem.flush(dev);
        return 0;
@@ -248,14 +246,14 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       if (!chan->ramin || !chan->ramin->gpuobj)
+       if (!chan->ramin)
                return;
 
        for (i = hdr; i < hdr + 24; i += 4)
-               nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
+               nv_wo32(chan->ramin, i, 0);
        dev_priv->engine.instmem.flush(dev);
 
-       nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
 }
 
 static int
@@ -282,7 +280,7 @@ nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
 int
 nv50_graph_load_context(struct nouveau_channel *chan)
 {
-       uint32_t inst = chan->ramin->instance >> 12;
+       uint32_t inst = chan->ramin->vinst >> 12;
 
        NV_DEBUG(chan->dev, "ch%d\n", chan->id);
        return nv50_graph_do_load_context(chan->dev, inst);
@@ -327,15 +325,16 @@ static int
 nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
                           int mthd, uint32_t data)
 {
-       struct nouveau_gpuobj_ref *ref = NULL;
+       struct nouveau_gpuobj *gpuobj;
 
-       if (nouveau_gpuobj_ref_find(chan, data, &ref))
+       gpuobj = nouveau_ramht_find(chan, data);
+       if (!gpuobj)
                return -ENOENT;
 
-       if (nouveau_notifier_offset(ref->gpuobj, NULL))
+       if (nouveau_notifier_offset(gpuobj, NULL))
                return -EINVAL;
 
-       chan->nvsw.vblsem = ref->gpuobj;
+       chan->nvsw.vblsem = gpuobj;
        chan->nvsw.vblsem_offset = ~0;
        return 0;
 }
index 42a8fb20c1e6359d698107654b46ee015c7fb36a..336aab2a24a66ff030b7af629db43f53aaa9ef8e 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_grctx.h"
 
+#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
+#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
+
 /*
  * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
  * the GPU itself that does context-switching, but it needs a special
@@ -182,6 +185,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
        case 0xa8:
        case 0xaa:
        case 0xac:
+       case 0xaf:
                break;
        default:
                NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
@@ -267,6 +271,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
  * registers to save/restore and the default values for them.
  */
 
+static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx);
+
 static void
 nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 {
@@ -286,7 +293,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                gr_def(ctx, 0x400840, 0xffe806a8);
        }
        gr_def(ctx, 0x400844, 0x00000002);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+       if (IS_NVA3F(dev_priv->chipset))
                gr_def(ctx, 0x400894, 0x00001000);
        gr_def(ctx, 0x4008e8, 0x00000003);
        gr_def(ctx, 0x4008ec, 0x00001000);
@@ -299,13 +306,15 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 
        if (dev_priv->chipset >= 0xa0)
                cp_ctx(ctx, 0x400b00, 0x1);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+       if (IS_NVA3F(dev_priv->chipset)) {
                cp_ctx(ctx, 0x400b10, 0x1);
                gr_def(ctx, 0x400b10, 0x0001629d);
                cp_ctx(ctx, 0x400b20, 0x1);
                gr_def(ctx, 0x400b20, 0x0001629d);
        }
 
+       nv50_graph_construct_mmio_ddata(ctx);
+
        /* 0C00: VFETCH */
        cp_ctx(ctx, 0x400c08, 0x2);
        gr_def(ctx, 0x400c08, 0x0000fe0c);
@@ -314,7 +323,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        if (dev_priv->chipset < 0xa0) {
                cp_ctx(ctx, 0x401008, 0x4);
                gr_def(ctx, 0x401014, 0x00001000);
-       } else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) {
+       } else if (!IS_NVA3F(dev_priv->chipset)) {
                cp_ctx(ctx, 0x401008, 0x5);
                gr_def(ctx, 0x401018, 0x00001000);
        } else {
@@ -368,10 +377,13 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        case 0xa3:
        case 0xa5:
        case 0xa8:
+       case 0xaf:
                gr_def(ctx, 0x401c00, 0x142500df);
                break;
        }
 
+       /* 2000 */
+
        /* 2400 */
        cp_ctx(ctx, 0x402400, 0x1);
        if (dev_priv->chipset == 0x50)
@@ -380,12 +392,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                cp_ctx(ctx, 0x402408, 0x2);
        gr_def(ctx, 0x402408, 0x00000600);
 
-       /* 2800 */
+       /* 2800: CSCHED */
        cp_ctx(ctx, 0x402800, 0x1);
        if (dev_priv->chipset == 0x50)
                gr_def(ctx, 0x402800, 0x00000006);
 
-       /* 2C00 */
+       /* 2C00: ZCULL */
        cp_ctx(ctx, 0x402c08, 0x6);
        if (dev_priv->chipset != 0x50)
                gr_def(ctx, 0x402c14, 0x01000000);
@@ -396,23 +408,23 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                cp_ctx(ctx, 0x402ca0, 0x2);
        if (dev_priv->chipset < 0xa0)
                gr_def(ctx, 0x402ca0, 0x00000400);
-       else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+       else if (!IS_NVA3F(dev_priv->chipset))
                gr_def(ctx, 0x402ca0, 0x00000800);
        else
                gr_def(ctx, 0x402ca0, 0x00000400);
        cp_ctx(ctx, 0x402cac, 0x4);
 
-       /* 3000 */
+       /* 3000: ENG2D */
        cp_ctx(ctx, 0x403004, 0x1);
        gr_def(ctx, 0x403004, 0x00000001);
 
-       /* 3404 */
+       /* 3400 */
        if (dev_priv->chipset >= 0xa0) {
                cp_ctx(ctx, 0x403404, 0x1);
                gr_def(ctx, 0x403404, 0x00000001);
        }
 
-       /* 5000 */
+       /* 5000: CCACHE */
        cp_ctx(ctx, 0x405000, 0x1);
        switch (dev_priv->chipset) {
        case 0x50:
@@ -425,6 +437,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        case 0xa8:
        case 0xaa:
        case 0xac:
+       case 0xaf:
                gr_def(ctx, 0x405000, 0x000e0080);
                break;
        case 0x86:
@@ -441,210 +454,6 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        cp_ctx(ctx, 0x405024, 0x1);
        cp_ctx(ctx, 0x40502c, 0x1);
 
-       /* 5400 or maybe 4800 */
-       if (dev_priv->chipset == 0x50) {
-               offset = 0x405400;
-               cp_ctx(ctx, 0x405400, 0xea);
-       } else if (dev_priv->chipset < 0x94) {
-               offset = 0x405400;
-               cp_ctx(ctx, 0x405400, 0xcb);
-       } else if (dev_priv->chipset < 0xa0) {
-               offset = 0x405400;
-               cp_ctx(ctx, 0x405400, 0xcc);
-       } else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               offset = 0x404800;
-               cp_ctx(ctx, 0x404800, 0xda);
-       } else {
-               offset = 0x405400;
-               cp_ctx(ctx, 0x405400, 0xd4);
-       }
-       gr_def(ctx, offset + 0x0c, 0x00000002);
-       gr_def(ctx, offset + 0x10, 0x00000001);
-       if (dev_priv->chipset >= 0x94)
-               offset += 4;
-       gr_def(ctx, offset + 0x1c, 0x00000001);
-       gr_def(ctx, offset + 0x20, 0x00000100);
-       gr_def(ctx, offset + 0x38, 0x00000002);
-       gr_def(ctx, offset + 0x3c, 0x00000001);
-       gr_def(ctx, offset + 0x40, 0x00000001);
-       gr_def(ctx, offset + 0x50, 0x00000001);
-       gr_def(ctx, offset + 0x54, 0x003fffff);
-       gr_def(ctx, offset + 0x58, 0x00001fff);
-       gr_def(ctx, offset + 0x60, 0x00000001);
-       gr_def(ctx, offset + 0x64, 0x00000001);
-       gr_def(ctx, offset + 0x6c, 0x00000001);
-       gr_def(ctx, offset + 0x70, 0x00000001);
-       gr_def(ctx, offset + 0x74, 0x00000001);
-       gr_def(ctx, offset + 0x78, 0x00000004);
-       gr_def(ctx, offset + 0x7c, 0x00000001);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               offset += 4;
-       gr_def(ctx, offset + 0x80, 0x00000001);
-       gr_def(ctx, offset + 0x84, 0x00000001);
-       gr_def(ctx, offset + 0x88, 0x00000007);
-       gr_def(ctx, offset + 0x8c, 0x00000001);
-       gr_def(ctx, offset + 0x90, 0x00000007);
-       gr_def(ctx, offset + 0x94, 0x00000001);
-       gr_def(ctx, offset + 0x98, 0x00000001);
-       gr_def(ctx, offset + 0x9c, 0x00000001);
-       if (dev_priv->chipset == 0x50) {
-                gr_def(ctx, offset + 0xb0, 0x00000001);
-                gr_def(ctx, offset + 0xb4, 0x00000001);
-                gr_def(ctx, offset + 0xbc, 0x00000001);
-                gr_def(ctx, offset + 0xc0, 0x0000000a);
-                gr_def(ctx, offset + 0xd0, 0x00000040);
-                gr_def(ctx, offset + 0xd8, 0x00000002);
-                gr_def(ctx, offset + 0xdc, 0x00000100);
-                gr_def(ctx, offset + 0xe0, 0x00000001);
-                gr_def(ctx, offset + 0xe4, 0x00000100);
-                gr_def(ctx, offset + 0x100, 0x00000001);
-                gr_def(ctx, offset + 0x124, 0x00000004);
-                gr_def(ctx, offset + 0x13c, 0x00000001);
-                gr_def(ctx, offset + 0x140, 0x00000100);
-                gr_def(ctx, offset + 0x148, 0x00000001);
-                gr_def(ctx, offset + 0x154, 0x00000100);
-                gr_def(ctx, offset + 0x158, 0x00000001);
-                gr_def(ctx, offset + 0x15c, 0x00000100);
-                gr_def(ctx, offset + 0x164, 0x00000001);
-                gr_def(ctx, offset + 0x170, 0x00000100);
-                gr_def(ctx, offset + 0x174, 0x00000001);
-                gr_def(ctx, offset + 0x17c, 0x00000001);
-                gr_def(ctx, offset + 0x188, 0x00000002);
-                gr_def(ctx, offset + 0x190, 0x00000001);
-                gr_def(ctx, offset + 0x198, 0x00000001);
-                gr_def(ctx, offset + 0x1ac, 0x00000003);
-                offset += 0xd0;
-       } else {
-               gr_def(ctx, offset + 0xb0, 0x00000001);
-               gr_def(ctx, offset + 0xb4, 0x00000100);
-               gr_def(ctx, offset + 0xbc, 0x00000001);
-               gr_def(ctx, offset + 0xc8, 0x00000100);
-               gr_def(ctx, offset + 0xcc, 0x00000001);
-               gr_def(ctx, offset + 0xd0, 0x00000100);
-               gr_def(ctx, offset + 0xd8, 0x00000001);
-               gr_def(ctx, offset + 0xe4, 0x00000100);
-       }
-       gr_def(ctx, offset + 0xf8, 0x00000004);
-       gr_def(ctx, offset + 0xfc, 0x00000070);
-       gr_def(ctx, offset + 0x100, 0x00000080);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               offset += 4;
-       gr_def(ctx, offset + 0x114, 0x0000000c);
-       if (dev_priv->chipset == 0x50)
-               offset -= 4;
-       gr_def(ctx, offset + 0x11c, 0x00000008);
-       gr_def(ctx, offset + 0x120, 0x00000014);
-       if (dev_priv->chipset == 0x50) {
-               gr_def(ctx, offset + 0x124, 0x00000026);
-               offset -= 0x18;
-       } else {
-               gr_def(ctx, offset + 0x128, 0x00000029);
-               gr_def(ctx, offset + 0x12c, 0x00000027);
-               gr_def(ctx, offset + 0x130, 0x00000026);
-               gr_def(ctx, offset + 0x134, 0x00000008);
-               gr_def(ctx, offset + 0x138, 0x00000004);
-               gr_def(ctx, offset + 0x13c, 0x00000027);
-       }
-       gr_def(ctx, offset + 0x148, 0x00000001);
-       gr_def(ctx, offset + 0x14c, 0x00000002);
-       gr_def(ctx, offset + 0x150, 0x00000003);
-       gr_def(ctx, offset + 0x154, 0x00000004);
-       gr_def(ctx, offset + 0x158, 0x00000005);
-       gr_def(ctx, offset + 0x15c, 0x00000006);
-       gr_def(ctx, offset + 0x160, 0x00000007);
-       gr_def(ctx, offset + 0x164, 0x00000001);
-       gr_def(ctx, offset + 0x1a8, 0x000000cf);
-       if (dev_priv->chipset == 0x50)
-               offset -= 4;
-       gr_def(ctx, offset + 0x1d8, 0x00000080);
-       gr_def(ctx, offset + 0x1dc, 0x00000004);
-       gr_def(ctx, offset + 0x1e0, 0x00000004);
-       if (dev_priv->chipset == 0x50)
-               offset -= 4;
-       else
-               gr_def(ctx, offset + 0x1e4, 0x00000003);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               gr_def(ctx, offset + 0x1ec, 0x00000003);
-               offset += 8;
-       }
-       gr_def(ctx, offset + 0x1e8, 0x00000001);
-       if (dev_priv->chipset == 0x50)
-               offset -= 4;
-       gr_def(ctx, offset + 0x1f4, 0x00000012);
-       gr_def(ctx, offset + 0x1f8, 0x00000010);
-       gr_def(ctx, offset + 0x1fc, 0x0000000c);
-       gr_def(ctx, offset + 0x200, 0x00000001);
-       gr_def(ctx, offset + 0x210, 0x00000004);
-       gr_def(ctx, offset + 0x214, 0x00000002);
-       gr_def(ctx, offset + 0x218, 0x00000004);
-       if (dev_priv->chipset >= 0xa0)
-               offset += 4;
-       gr_def(ctx, offset + 0x224, 0x003fffff);
-       gr_def(ctx, offset + 0x228, 0x00001fff);
-       if (dev_priv->chipset == 0x50)
-               offset -= 0x20;
-       else if (dev_priv->chipset >= 0xa0) {
-               gr_def(ctx, offset + 0x250, 0x00000001);
-               gr_def(ctx, offset + 0x254, 0x00000001);
-               gr_def(ctx, offset + 0x258, 0x00000002);
-               offset += 0x10;
-       }
-       gr_def(ctx, offset + 0x250, 0x00000004);
-       gr_def(ctx, offset + 0x254, 0x00000014);
-       gr_def(ctx, offset + 0x258, 0x00000001);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               offset += 4;
-       gr_def(ctx, offset + 0x264, 0x00000002);
-       if (dev_priv->chipset >= 0xa0)
-               offset += 8;
-       gr_def(ctx, offset + 0x270, 0x00000001);
-       gr_def(ctx, offset + 0x278, 0x00000002);
-       gr_def(ctx, offset + 0x27c, 0x00001000);
-       if (dev_priv->chipset == 0x50)
-               offset -= 0xc;
-       else {
-               gr_def(ctx, offset + 0x280, 0x00000e00);
-               gr_def(ctx, offset + 0x284, 0x00001000);
-               gr_def(ctx, offset + 0x288, 0x00001e00);
-       }
-       gr_def(ctx, offset + 0x290, 0x00000001);
-       gr_def(ctx, offset + 0x294, 0x00000001);
-       gr_def(ctx, offset + 0x298, 0x00000001);
-       gr_def(ctx, offset + 0x29c, 0x00000001);
-       gr_def(ctx, offset + 0x2a0, 0x00000001);
-       gr_def(ctx, offset + 0x2b0, 0x00000200);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               gr_def(ctx, offset + 0x2b4, 0x00000200);
-               offset += 4;
-       }
-       if (dev_priv->chipset < 0xa0) {
-               gr_def(ctx, offset + 0x2b8, 0x00000001);
-               gr_def(ctx, offset + 0x2bc, 0x00000070);
-               gr_def(ctx, offset + 0x2c0, 0x00000080);
-               gr_def(ctx, offset + 0x2cc, 0x00000001);
-               gr_def(ctx, offset + 0x2d0, 0x00000070);
-               gr_def(ctx, offset + 0x2d4, 0x00000080);
-       } else {
-               gr_def(ctx, offset + 0x2b8, 0x00000001);
-               gr_def(ctx, offset + 0x2bc, 0x000000f0);
-               gr_def(ctx, offset + 0x2c0, 0x000000ff);
-               gr_def(ctx, offset + 0x2cc, 0x00000001);
-               gr_def(ctx, offset + 0x2d0, 0x000000f0);
-               gr_def(ctx, offset + 0x2d4, 0x000000ff);
-               gr_def(ctx, offset + 0x2dc, 0x00000009);
-               offset += 4;
-       }
-       gr_def(ctx, offset + 0x2e4, 0x00000001);
-       gr_def(ctx, offset + 0x2e8, 0x000000cf);
-       gr_def(ctx, offset + 0x2f0, 0x00000001);
-       gr_def(ctx, offset + 0x300, 0x000000cf);
-       gr_def(ctx, offset + 0x308, 0x00000002);
-       gr_def(ctx, offset + 0x310, 0x00000001);
-       gr_def(ctx, offset + 0x318, 0x00000001);
-       gr_def(ctx, offset + 0x320, 0x000000cf);
-       gr_def(ctx, offset + 0x324, 0x000000cf);
-       gr_def(ctx, offset + 0x328, 0x00000001);
-
        /* 6000? */
        if (dev_priv->chipset == 0x50)
                cp_ctx(ctx, 0x4063e0, 0x1);
@@ -661,7 +470,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                        gr_def(ctx, 0x406818, 0x00000f80);
                else
                        gr_def(ctx, 0x406818, 0x00001f80);
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+               if (IS_NVA3F(dev_priv->chipset))
                        gr_def(ctx, 0x40681c, 0x00000030);
                cp_ctx(ctx, 0x406830, 0x3);
        }
@@ -706,7 +515,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 
                        if (dev_priv->chipset < 0xa0)
                                cp_ctx(ctx, 0x407094 + (i<<8), 1);
-                       else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+                       else if (!IS_NVA3F(dev_priv->chipset))
                                cp_ctx(ctx, 0x407094 + (i<<8), 3);
                        else {
                                cp_ctx(ctx, 0x407094 + (i<<8), 4);
@@ -799,6 +608,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                case 0xa8:
                                case 0xaa:
                                case 0xac:
+                               case 0xaf:
                                        gr_def(ctx, offset + 0x1c, 0x300c0000);
                                        break;
                                }
@@ -825,7 +635,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                gr_def(ctx, base + 0x304, 0x00007070);
                        else if (dev_priv->chipset < 0xa0)
                                gr_def(ctx, base + 0x304, 0x00027070);
-                       else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+                       else if (!IS_NVA3F(dev_priv->chipset))
                                gr_def(ctx, base + 0x304, 0x01127070);
                        else
                                gr_def(ctx, base + 0x304, 0x05127070);
@@ -849,7 +659,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                        if (dev_priv->chipset < 0xa0) {
                                cp_ctx(ctx, base + 0x340, 9);
                                offset = base + 0x340;
-                       } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+                       } else if (!IS_NVA3F(dev_priv->chipset)) {
                                cp_ctx(ctx, base + 0x33c, 0xb);
                                offset = base + 0x344;
                        } else {
@@ -880,7 +690,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                        gr_def(ctx, offset + 0x0, 0x000001f0);
                        gr_def(ctx, offset + 0x4, 0x00000001);
                        gr_def(ctx, offset + 0x8, 0x00000003);
-                       if (dev_priv->chipset == 0x50 || dev_priv->chipset >= 0xaa)
+                       if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset))
                                gr_def(ctx, offset + 0xc, 0x00008000);
                        gr_def(ctx, offset + 0x14, 0x00039e00);
                        cp_ctx(ctx, offset + 0x1c, 2);
@@ -892,7 +702,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 
                        if (dev_priv->chipset >= 0xa0) {
                                cp_ctx(ctx, base + 0x54c, 2);
-                               if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+                               if (!IS_NVA3F(dev_priv->chipset))
                                        gr_def(ctx, base + 0x54c, 0x003fe006);
                                else
                                        gr_def(ctx, base + 0x54c, 0x003fe007);
@@ -948,6 +758,336 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        }
 }
 
+static void
+dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+       int i;
+       if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
+               for (i = 0; i < num; i++)
+                       nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
+       ctx->ctxvals_pos += num;
+}
+
+static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int base, num;
+       base = ctx->ctxvals_pos;
+
+       /* tesla state */
+       dd_emit(ctx, 1, 0);     /* 00000001 UNK0F90 */
+       dd_emit(ctx, 1, 0);     /* 00000001 UNK135C */
+
+       /* SRC_TIC state */
+       dd_emit(ctx, 1, 0);     /* 00000007 SRC_TILE_MODE_Z */
+       dd_emit(ctx, 1, 2);     /* 00000007 SRC_TILE_MODE_Y */
+       dd_emit(ctx, 1, 1);     /* 00000001 SRC_LINEAR #1 */
+       dd_emit(ctx, 1, 0);     /* 000000ff SRC_ADDRESS_HIGH */
+       dd_emit(ctx, 1, 0);     /* 00000001 SRC_SRGB */
+       if (dev_priv->chipset >= 0x94)
+               dd_emit(ctx, 1, 0);     /* 00000003 eng2d UNK0258 */
+       dd_emit(ctx, 1, 1);     /* 00000fff SRC_DEPTH */
+       dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */
+
+       /* turing state */
+       dd_emit(ctx, 1, 0);             /* 0000000f TEXTURES_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 0000000f SAMPLERS_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 000000ff CB_DEF_ADDRESS_HIGH */
+       dd_emit(ctx, 1, 0);             /* ffffffff CB_DEF_ADDRESS_LOW */
+       dd_emit(ctx, 1, 0);             /* ffffffff SHARED_SIZE */
+       dd_emit(ctx, 1, 2);             /* ffffffff REG_MODE */
+       dd_emit(ctx, 1, 1);             /* 0000ffff BLOCK_ALLOC_THREADS */
+       dd_emit(ctx, 1, 1);             /* 00000001 LANES32 */
+       dd_emit(ctx, 1, 0);             /* 000000ff UNK370 */
+       dd_emit(ctx, 1, 0);             /* 000000ff USER_PARAM_UNK */
+       dd_emit(ctx, 1, 0);             /* 000000ff USER_PARAM_COUNT */
+       dd_emit(ctx, 1, 1);             /* 000000ff UNK384 bits 8-15 */
+       dd_emit(ctx, 1, 0x3fffff);      /* 003fffff TIC_LIMIT */
+       dd_emit(ctx, 1, 0x1fff);        /* 000fffff TSC_LIMIT */
+       dd_emit(ctx, 1, 0);             /* 0000ffff CB_ADDR_INDEX */
+       dd_emit(ctx, 1, 1);             /* 000007ff BLOCKDIM_X */
+       dd_emit(ctx, 1, 1);             /* 000007ff BLOCKDIM_XMY */
+       dd_emit(ctx, 1, 0);             /* 00000001 BLOCKDIM_XMY_OVERFLOW */
+       dd_emit(ctx, 1, 1);             /* 0003ffff BLOCKDIM_XMYMZ */
+       dd_emit(ctx, 1, 1);             /* 000007ff BLOCKDIM_Y */
+       dd_emit(ctx, 1, 1);             /* 0000007f BLOCKDIM_Z */
+       dd_emit(ctx, 1, 4);             /* 000000ff CP_REG_ALLOC_TEMP */
+       dd_emit(ctx, 1, 1);             /* 00000001 BLOCKDIM_DIRTY */
+       if (IS_NVA3F(dev_priv->chipset))
+               dd_emit(ctx, 1, 0);     /* 00000003 UNK03E8 */
+       dd_emit(ctx, 1, 1);             /* 0000007f BLOCK_ALLOC_HALFWARPS */
+       dd_emit(ctx, 1, 1);             /* 00000007 LOCAL_WARPS_NO_CLAMP */
+       dd_emit(ctx, 1, 7);             /* 00000007 LOCAL_WARPS_LOG_ALLOC */
+       dd_emit(ctx, 1, 1);             /* 00000007 STACK_WARPS_NO_CLAMP */
+       dd_emit(ctx, 1, 7);             /* 00000007 STACK_WARPS_LOG_ALLOC */
+       dd_emit(ctx, 1, 1);             /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
+       dd_emit(ctx, 1, 1);             /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
+       dd_emit(ctx, 1, 1);             /* 000007ff BLOCK_ALLOC_THREADS */
+
+       /* compat 2d state */
+       if (dev_priv->chipset == 0x50) {
+               dd_emit(ctx, 4, 0);             /* 0000ffff clip X, Y, W, H */
+
+               dd_emit(ctx, 1, 1);             /* ffffffff chroma COLOR_FORMAT */
+
+               dd_emit(ctx, 1, 1);             /* ffffffff pattern COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff pattern SHAPE */
+               dd_emit(ctx, 1, 1);             /* ffffffff pattern PATTERN_SELECT */
+
+               dd_emit(ctx, 1, 0xa);           /* ffffffff surf2d SRC_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff surf2d DMA_SRC */
+               dd_emit(ctx, 1, 0);             /* 000000ff surf2d SRC_ADDRESS_HIGH */
+               dd_emit(ctx, 1, 0);             /* ffffffff surf2d SRC_ADDRESS_LOW */
+               dd_emit(ctx, 1, 0x40);          /* 0000ffff surf2d SRC_PITCH */
+               dd_emit(ctx, 1, 0);             /* 0000000f surf2d SRC_TILE_MODE_Z */
+               dd_emit(ctx, 1, 2);             /* 0000000f surf2d SRC_TILE_MODE_Y */
+               dd_emit(ctx, 1, 0x100);         /* ffffffff surf2d SRC_HEIGHT */
+               dd_emit(ctx, 1, 1);             /* 00000001 surf2d SRC_LINEAR */
+               dd_emit(ctx, 1, 0x100);         /* ffffffff surf2d SRC_WIDTH */
+
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_B_X */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_B_Y */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_C_X */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_C_Y */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_D_X */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect CLIP_D_Y */
+               dd_emit(ctx, 1, 1);             /* ffffffff gdirect COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff gdirect OPERATION */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect POINT_X */
+               dd_emit(ctx, 1, 0);             /* 0000ffff gdirect POINT_Y */
+
+               dd_emit(ctx, 1, 0);             /* 0000ffff blit SRC_Y */
+               dd_emit(ctx, 1, 0);             /* ffffffff blit OPERATION */
+
+               dd_emit(ctx, 1, 0);             /* ffffffff ifc OPERATION */
+
+               dd_emit(ctx, 1, 0);             /* ffffffff iifc INDEX_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff iifc LUT_OFFSET */
+               dd_emit(ctx, 1, 4);             /* ffffffff iifc COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff iifc OPERATION */
+       }
+
+       /* m2mf state */
+       dd_emit(ctx, 1, 0);             /* ffffffff m2mf LINE_COUNT */
+       dd_emit(ctx, 1, 0);             /* ffffffff m2mf LINE_LENGTH_IN */
+       dd_emit(ctx, 2, 0);             /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
+       dd_emit(ctx, 1, 1);             /* ffffffff m2mf TILING_DEPTH_OUT */
+       dd_emit(ctx, 1, 0x100);         /* ffffffff m2mf TILING_HEIGHT_OUT */
+       dd_emit(ctx, 1, 0);             /* ffffffff m2mf TILING_POSITION_OUT_Z */
+       dd_emit(ctx, 1, 1);             /* 00000001 m2mf LINEAR_OUT */
+       dd_emit(ctx, 2, 0);             /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
+       dd_emit(ctx, 1, 0x100);         /* ffffffff m2mf TILING_PITCH_OUT */
+       dd_emit(ctx, 1, 1);             /* ffffffff m2mf TILING_DEPTH_IN */
+       dd_emit(ctx, 1, 0x100);         /* ffffffff m2mf TILING_HEIGHT_IN */
+       dd_emit(ctx, 1, 0);             /* ffffffff m2mf TILING_POSITION_IN_Z */
+       dd_emit(ctx, 1, 1);             /* 00000001 m2mf LINEAR_IN */
+       dd_emit(ctx, 2, 0);             /* 0000ffff m2mf TILING_POSITION_IN_X, Y */
+       dd_emit(ctx, 1, 0x100);         /* ffffffff m2mf TILING_PITCH_IN */
+
+       /* more compat 2d state */
+       if (dev_priv->chipset == 0x50) {
+               dd_emit(ctx, 1, 1);             /* ffffffff line COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff line OPERATION */
+
+               dd_emit(ctx, 1, 1);             /* ffffffff triangle COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff triangle OPERATION */
+
+               dd_emit(ctx, 1, 0);             /* 0000000f sifm TILE_MODE_Z */
+               dd_emit(ctx, 1, 2);             /* 0000000f sifm TILE_MODE_Y */
+               dd_emit(ctx, 1, 0);             /* 000000ff sifm FORMAT_FILTER */
+               dd_emit(ctx, 1, 1);             /* 000000ff sifm FORMAT_ORIGIN */
+               dd_emit(ctx, 1, 0);             /* 0000ffff sifm SRC_PITCH */
+               dd_emit(ctx, 1, 1);             /* 00000001 sifm SRC_LINEAR */
+               dd_emit(ctx, 1, 0);             /* 000000ff sifm SRC_OFFSET_HIGH */
+               dd_emit(ctx, 1, 0);             /* ffffffff sifm SRC_OFFSET */
+               dd_emit(ctx, 1, 0);             /* 0000ffff sifm SRC_HEIGHT */
+               dd_emit(ctx, 1, 0);             /* 0000ffff sifm SRC_WIDTH */
+               dd_emit(ctx, 1, 3);             /* ffffffff sifm COLOR_FORMAT */
+               dd_emit(ctx, 1, 0);             /* ffffffff sifm OPERATION */
+
+               dd_emit(ctx, 1, 0);             /* ffffffff sifc OPERATION */
+       }
+
+       /* tesla state */
+       dd_emit(ctx, 1, 0);             /* 0000000f GP_TEXTURES_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 0000000f GP_SAMPLERS_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 000000ff */
+       dd_emit(ctx, 1, 0);             /* ffffffff */
+       dd_emit(ctx, 1, 4);             /* 000000ff UNK12B0_0 */
+       dd_emit(ctx, 1, 0x70);          /* 000000ff UNK12B0_1 */
+       dd_emit(ctx, 1, 0x80);          /* 000000ff UNK12B0_3 */
+       dd_emit(ctx, 1, 0);             /* 000000ff UNK12B0_2 */
+       dd_emit(ctx, 1, 0);             /* 0000000f FP_TEXTURES_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 0000000f FP_SAMPLERS_LOG2 */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               dd_emit(ctx, 1, 0);     /* ffffffff */
+               dd_emit(ctx, 1, 0);     /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
+       } else {
+               dd_emit(ctx, 1, 0);     /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
+       } 
+       dd_emit(ctx, 1, 0xc);           /* 000000ff SEMANTIC_COLOR.BFC0_ID */
+       if (dev_priv->chipset != 0x50)
+               dd_emit(ctx, 1, 0);     /* 00000001 SEMANTIC_COLOR.CLMP_EN */
+       dd_emit(ctx, 1, 8);             /* 000000ff SEMANTIC_COLOR.COLR_NR */
+       dd_emit(ctx, 1, 0x14);          /* 000000ff SEMANTIC_COLOR.FFC0_ID */
+       if (dev_priv->chipset == 0x50) {
+               dd_emit(ctx, 1, 0);     /* 000000ff SEMANTIC_LAYER */
+               dd_emit(ctx, 1, 0);     /* 00000001 */
+       } else {
+               dd_emit(ctx, 1, 0);     /* 00000001 SEMANTIC_PTSZ.ENABLE */
+               dd_emit(ctx, 1, 0x29);  /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
+               dd_emit(ctx, 1, 0x27);  /* 000000ff SEMANTIC_PRIM */
+               dd_emit(ctx, 1, 0x26);  /* 000000ff SEMANTIC_LAYER */
+               dd_emit(ctx, 1, 8);     /* 0000000f SMENATIC_CLIP.CLIP_HIGH */
+               dd_emit(ctx, 1, 4);     /* 000000ff SEMANTIC_CLIP.CLIP_LO */
+               dd_emit(ctx, 1, 0x27);  /* 000000ff UNK0FD4 */
+               dd_emit(ctx, 1, 0);     /* 00000001 UNK1900 */
+       }
+       dd_emit(ctx, 1, 0);             /* 00000007 RT_CONTROL_MAP0 */
+       dd_emit(ctx, 1, 1);             /* 00000007 RT_CONTROL_MAP1 */
+       dd_emit(ctx, 1, 2);             /* 00000007 RT_CONTROL_MAP2 */
+       dd_emit(ctx, 1, 3);             /* 00000007 RT_CONTROL_MAP3 */
+       dd_emit(ctx, 1, 4);             /* 00000007 RT_CONTROL_MAP4 */
+       dd_emit(ctx, 1, 5);             /* 00000007 RT_CONTROL_MAP5 */
+       dd_emit(ctx, 1, 6);             /* 00000007 RT_CONTROL_MAP6 */
+       dd_emit(ctx, 1, 7);             /* 00000007 RT_CONTROL_MAP7 */
+       dd_emit(ctx, 1, 1);             /* 0000000f RT_CONTROL_COUNT */
+       dd_emit(ctx, 8, 0);             /* 00000001 RT_HORIZ_UNK */
+       dd_emit(ctx, 8, 0);             /* ffffffff RT_ADDRESS_LOW */
+       dd_emit(ctx, 1, 0xcf);          /* 000000ff RT_FORMAT */
+       dd_emit(ctx, 7, 0);             /* 000000ff RT_FORMAT */
+       if (dev_priv->chipset != 0x50)
+               dd_emit(ctx, 3, 0);     /* 1, 1, 1 */
+       else
+               dd_emit(ctx, 2, 0);     /* 1, 1 */
+       dd_emit(ctx, 1, 0);             /* ffffffff GP_ENABLE */
+       dd_emit(ctx, 1, 0x80);          /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
+       dd_emit(ctx, 1, 4);             /* 000000ff GP_REG_ALLOC_RESULT */
+       dd_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               dd_emit(ctx, 1, 3);     /* 00000003 */
+               dd_emit(ctx, 1, 0);     /* 00000001 UNK1418. Alone. */
+       }
+       if (dev_priv->chipset != 0x50)
+               dd_emit(ctx, 1, 3);     /* 00000003 UNK15AC */
+       dd_emit(ctx, 1, 1);             /* ffffffff RASTERIZE_ENABLE */
+       dd_emit(ctx, 1, 0);             /* 00000001 FP_CONTROL.EXPORTS_Z */
+       if (dev_priv->chipset != 0x50)
+               dd_emit(ctx, 1, 0);     /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
+       dd_emit(ctx, 1, 0x12);          /* 000000ff FP_INTERPOLANT_CTRL.COUNT */
+       dd_emit(ctx, 1, 0x10);          /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
+       dd_emit(ctx, 1, 0xc);           /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
+       dd_emit(ctx, 1, 1);             /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
+       dd_emit(ctx, 1, 0);             /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
+       dd_emit(ctx, 1, 0);             /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
+       dd_emit(ctx, 1, 0);             /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
+       dd_emit(ctx, 1, 4);             /* 000000ff FP_RESULT_COUNT */
+       dd_emit(ctx, 1, 2);             /* ffffffff REG_MODE */
+       dd_emit(ctx, 1, 4);             /* 000000ff FP_REG_ALLOC_TEMP */
+       if (dev_priv->chipset >= 0xa0)
+               dd_emit(ctx, 1, 0);     /* ffffffff */
+       dd_emit(ctx, 1, 0);             /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
+       dd_emit(ctx, 1, 0);             /* ffffffff STRMOUT_ENABLE */
+       dd_emit(ctx, 1, 0x3fffff);      /* 003fffff TIC_LIMIT */
+       dd_emit(ctx, 1, 0x1fff);        /* 000fffff TSC_LIMIT */
+       dd_emit(ctx, 1, 0);             /* 00000001 VERTEX_TWO_SIDE_ENABLE*/
+       if (dev_priv->chipset != 0x50)
+               dd_emit(ctx, 8, 0);     /* 00000001 */
+       if (dev_priv->chipset >= 0xa0) {
+               dd_emit(ctx, 1, 1);     /* 00000007 VTX_ATTR_DEFINE.COMP */
+               dd_emit(ctx, 1, 1);     /* 00000007 VTX_ATTR_DEFINE.SIZE */
+               dd_emit(ctx, 1, 2);     /* 00000007 VTX_ATTR_DEFINE.TYPE */
+               dd_emit(ctx, 1, 0);     /* 000000ff VTX_ATTR_DEFINE.ATTR */
+       }
+       dd_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       dd_emit(ctx, 1, 0x14);          /* 0000001f ZETA_FORMAT */
+       dd_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       dd_emit(ctx, 1, 0);             /* 0000000f VP_TEXTURES_LOG2 */
+       dd_emit(ctx, 1, 0);             /* 0000000f VP_SAMPLERS_LOG2 */
+       if (IS_NVA3F(dev_priv->chipset))
+               dd_emit(ctx, 1, 0);     /* 00000001 */
+       dd_emit(ctx, 1, 2);             /* 00000003 POLYGON_MODE_BACK */
+       if (dev_priv->chipset >= 0xa0)
+               dd_emit(ctx, 1, 0);     /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
+       dd_emit(ctx, 1, 0);             /* 0000ffff CB_ADDR_INDEX */
+       if (dev_priv->chipset >= 0xa0)
+               dd_emit(ctx, 1, 0);     /* 00000003 */
+       dd_emit(ctx, 1, 0);             /* 00000001 CULL_FACE_ENABLE */
+       dd_emit(ctx, 1, 1);             /* 00000003 CULL_FACE */
+       dd_emit(ctx, 1, 0);             /* 00000001 FRONT_FACE */
+       dd_emit(ctx, 1, 2);             /* 00000003 POLYGON_MODE_FRONT */
+       dd_emit(ctx, 1, 0x1000);        /* 00007fff UNK141C */
+       if (dev_priv->chipset != 0x50) {
+               dd_emit(ctx, 1, 0xe00);         /* 7fff */
+               dd_emit(ctx, 1, 0x1000);        /* 7fff */
+               dd_emit(ctx, 1, 0x1e00);        /* 7fff */
+       }
+       dd_emit(ctx, 1, 0);             /* 00000001 BEGIN_END_ACTIVE */
+       dd_emit(ctx, 1, 1);             /* 00000001 POLYGON_MODE_??? */
+       dd_emit(ctx, 1, 1);             /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
+       dd_emit(ctx, 1, 1);             /* 000000ff FP_REG_ALLOC_TEMP... without /4? */
+       dd_emit(ctx, 1, 1);             /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
+       dd_emit(ctx, 1, 1);             /* 00000001 */
+       dd_emit(ctx, 1, 0);             /* 00000001 */
+       dd_emit(ctx, 1, 0);             /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
+       dd_emit(ctx, 1, 0);             /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
+       dd_emit(ctx, 1, 0x200);         /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
+       if (IS_NVA3F(dev_priv->chipset))
+               dd_emit(ctx, 1, 0x200);
+       dd_emit(ctx, 1, 0);             /* 00000001 */
+       if (dev_priv->chipset < 0xa0) {
+               dd_emit(ctx, 1, 1);     /* 00000001 */
+               dd_emit(ctx, 1, 0x70);  /* 000000ff */
+               dd_emit(ctx, 1, 0x80);  /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 00000001 */
+               dd_emit(ctx, 1, 1);     /* 00000001 */
+               dd_emit(ctx, 1, 0x70);  /* 000000ff */
+               dd_emit(ctx, 1, 0x80);  /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 000000ff */
+       } else {
+               dd_emit(ctx, 1, 1);     /* 00000001 */
+               dd_emit(ctx, 1, 0xf0);  /* 000000ff */
+               dd_emit(ctx, 1, 0xff);  /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 00000001 */
+               dd_emit(ctx, 1, 1);     /* 00000001 */
+               dd_emit(ctx, 1, 0xf0);  /* 000000ff */
+               dd_emit(ctx, 1, 0xff);  /* 000000ff */
+               dd_emit(ctx, 1, 0);     /* 000000ff */
+               dd_emit(ctx, 1, 9);     /* 0000003f UNK114C.COMP,SIZE */
+       }
+
+       /* eng2d state */
+       dd_emit(ctx, 1, 0);             /* 00000001 eng2d COLOR_KEY_ENABLE */
+       dd_emit(ctx, 1, 0);             /* 00000007 eng2d COLOR_KEY_FORMAT */
+       dd_emit(ctx, 1, 1);             /* ffffffff eng2d DST_DEPTH */
+       dd_emit(ctx, 1, 0xcf);          /* 000000ff eng2d DST_FORMAT */
+       dd_emit(ctx, 1, 0);             /* ffffffff eng2d DST_LAYER */
+       dd_emit(ctx, 1, 1);             /* 00000001 eng2d DST_LINEAR */
+       dd_emit(ctx, 1, 0);             /* 00000007 eng2d PATTERN_COLOR_FORMAT */
+       dd_emit(ctx, 1, 0);             /* 00000007 eng2d OPERATION */
+       dd_emit(ctx, 1, 0);             /* 00000003 eng2d PATTERN_SELECT */
+       dd_emit(ctx, 1, 0xcf);          /* 000000ff eng2d SIFC_FORMAT */
+       dd_emit(ctx, 1, 0);             /* 00000001 eng2d SIFC_BITMAP_ENABLE */
+       dd_emit(ctx, 1, 2);             /* 00000003 eng2d SIFC_BITMAP_UNK808 */
+       dd_emit(ctx, 1, 0);             /* ffffffff eng2d BLIT_DU_DX_FRACT */
+       dd_emit(ctx, 1, 1);             /* ffffffff eng2d BLIT_DU_DX_INT */
+       dd_emit(ctx, 1, 0);             /* ffffffff eng2d BLIT_DV_DY_FRACT */
+       dd_emit(ctx, 1, 1);             /* ffffffff eng2d BLIT_DV_DY_INT */
+       dd_emit(ctx, 1, 0);             /* 00000001 eng2d BLIT_CONTROL_FILTER */
+       dd_emit(ctx, 1, 0xcf);          /* 000000ff eng2d DRAW_COLOR_FORMAT */
+       dd_emit(ctx, 1, 0xcf);          /* 000000ff eng2d SRC_FORMAT */
+       dd_emit(ctx, 1, 1);             /* 00000001 eng2d SRC_LINEAR #2 */
+
+       num = ctx->ctxvals_pos - base;
+       ctx->ctxvals_pos = base;
+       if (IS_NVA3F(dev_priv->chipset))
+               cp_ctx(ctx, 0x404800, num);
+       else
+               cp_ctx(ctx, 0x405400, num);
+}
+
 /*
  * xfer areas. These are a pain.
  *
@@ -990,28 +1130,33 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
  * without the help of ctxprog.
  */
 
-static inline void
+static void
 xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
        int i;
        if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
                for (i = 0; i < num; i++)
-                       nv_wo32(ctx->dev, ctx->data, ctx->ctxvals_pos + (i << 3), val);
+                       nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
        ctx->ctxvals_pos += num << 3;
 }
 
 /* Gene declarations... */
 
+static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
 
@@ -1030,102 +1175,32 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
        if (dev_priv->chipset < 0xa0) {
                /* Strand 0 */
                ctx->ctxvals_pos = offset;
-               switch (dev_priv->chipset) {
-               case 0x50:
-                       xf_emit(ctx, 0x99, 0);
-                       break;
-               case 0x84:
-               case 0x86:
-                       xf_emit(ctx, 0x384, 0);
-                       break;
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0x98:
-                       xf_emit(ctx, 0x380, 0);
-                       break;
-               }
-               nv50_graph_construct_gene_m2mf (ctx);
-               switch (dev_priv->chipset) {
-               case 0x50:
-               case 0x84:
-               case 0x86:
-               case 0x98:
-                       xf_emit(ctx, 0x4c4, 0);
-                       break;
-               case 0x92:
-               case 0x94:
-               case 0x96:
-                       xf_emit(ctx, 0x984, 0);
-                       break;
-               }
-               nv50_graph_construct_gene_unk5(ctx);
-               if (dev_priv->chipset == 0x50)
-                       xf_emit(ctx, 0xa, 0);
-               else
-                       xf_emit(ctx, 0xb, 0);
-               nv50_graph_construct_gene_unk4(ctx);
-               nv50_graph_construct_gene_unk3(ctx);
+               nv50_graph_construct_gene_dispatch(ctx);
+               nv50_graph_construct_gene_m2mf(ctx);
+               nv50_graph_construct_gene_unk24xx(ctx);
+               nv50_graph_construct_gene_clipid(ctx);
+               nv50_graph_construct_gene_zcull(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 1 */
                ctx->ctxvals_pos = offset + 0x1;
-               nv50_graph_construct_gene_unk6(ctx);
-               nv50_graph_construct_gene_unk7(ctx);
-               nv50_graph_construct_gene_unk8(ctx);
-               switch (dev_priv->chipset) {
-               case 0x50:
-               case 0x92:
-                       xf_emit(ctx, 0xfb, 0);
-                       break;
-               case 0x84:
-                       xf_emit(ctx, 0xd3, 0);
-                       break;
-               case 0x94:
-               case 0x96:
-                       xf_emit(ctx, 0xab, 0);
-                       break;
-               case 0x86:
-               case 0x98:
-                       xf_emit(ctx, 0x6b, 0);
-                       break;
-               }
-               xf_emit(ctx, 2, 0x4e3bfdf);
-               xf_emit(ctx, 4, 0);
-               xf_emit(ctx, 1, 0x0fac6881);
-               xf_emit(ctx, 0xb, 0);
-               xf_emit(ctx, 2, 0x4e3bfdf);
+               nv50_graph_construct_gene_vfetch(ctx);
+               nv50_graph_construct_gene_eng2d(ctx);
+               nv50_graph_construct_gene_csched(ctx);
+               nv50_graph_construct_gene_ropm1(ctx);
+               nv50_graph_construct_gene_ropm2(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 2 */
                ctx->ctxvals_pos = offset + 0x2;
-               switch (dev_priv->chipset) {
-               case 0x50:
-               case 0x92:
-                       xf_emit(ctx, 0xa80, 0);
-                       break;
-               case 0x84:
-                       xf_emit(ctx, 0xa7e, 0);
-                       break;
-               case 0x94:
-               case 0x96:
-                       xf_emit(ctx, 0xa7c, 0);
-                       break;
-               case 0x86:
-               case 0x98:
-                       xf_emit(ctx, 0xa7a, 0);
-                       break;
-               }
-               xf_emit(ctx, 1, 0x3fffff);
-               xf_emit(ctx, 2, 0);
-               xf_emit(ctx, 1, 0x1fff);
-               xf_emit(ctx, 0xe, 0);
-               nv50_graph_construct_gene_unk9(ctx);
-               nv50_graph_construct_gene_unk2(ctx);
-               nv50_graph_construct_gene_unk1(ctx);
-               nv50_graph_construct_gene_unk10(ctx);
+               nv50_graph_construct_gene_ccache(ctx);
+               nv50_graph_construct_gene_unk1cxx(ctx);
+               nv50_graph_construct_gene_strmout(ctx);
+               nv50_graph_construct_gene_unk14xx(ctx);
+               nv50_graph_construct_gene_unk10xx(ctx);
+               nv50_graph_construct_gene_unk34xx(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
@@ -1150,86 +1225,46 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
        } else {
                /* Strand 0 */
                ctx->ctxvals_pos = offset;
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-                       xf_emit(ctx, 0x385, 0);
-               else
-                       xf_emit(ctx, 0x384, 0);
+               nv50_graph_construct_gene_dispatch(ctx);
                nv50_graph_construct_gene_m2mf(ctx);
-               xf_emit(ctx, 0x950, 0);
-               nv50_graph_construct_gene_unk10(ctx);
-               xf_emit(ctx, 1, 0x0fac6881);
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-                       xf_emit(ctx, 1, 1);
-                       xf_emit(ctx, 3, 0);
-               }
-               nv50_graph_construct_gene_unk8(ctx);
-               if (dev_priv->chipset == 0xa0)
-                       xf_emit(ctx, 0x189, 0);
-               else if (dev_priv->chipset == 0xa3)
-                       xf_emit(ctx, 0xd5, 0);
-               else if (dev_priv->chipset == 0xa5)
-                       xf_emit(ctx, 0x99, 0);
-               else if (dev_priv->chipset == 0xaa)
-                       xf_emit(ctx, 0x65, 0);
-               else
-                       xf_emit(ctx, 0x6d, 0);
-               nv50_graph_construct_gene_unk9(ctx);
+               nv50_graph_construct_gene_unk34xx(ctx);
+               nv50_graph_construct_gene_csched(ctx);
+               nv50_graph_construct_gene_unk1cxx(ctx);
+               nv50_graph_construct_gene_strmout(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 1 */
                ctx->ctxvals_pos = offset + 1;
-               nv50_graph_construct_gene_unk1(ctx);
+               nv50_graph_construct_gene_unk10xx(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 2 */
                ctx->ctxvals_pos = offset + 2;
-               if (dev_priv->chipset == 0xa0) {
-                       nv50_graph_construct_gene_unk2(ctx);
-               }
-               xf_emit(ctx, 0x36, 0);
-               nv50_graph_construct_gene_unk5(ctx);
+               if (dev_priv->chipset == 0xa0)
+                       nv50_graph_construct_gene_unk14xx(ctx);
+               nv50_graph_construct_gene_unk24xx(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 3 */
                ctx->ctxvals_pos = offset + 3;
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 1, 1);
-               nv50_graph_construct_gene_unk6(ctx);
+               nv50_graph_construct_gene_vfetch(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 4 */
                ctx->ctxvals_pos = offset + 4;
-               if (dev_priv->chipset == 0xa0)
-                       xf_emit(ctx, 0xa80, 0);
-               else if (dev_priv->chipset == 0xa3)
-                       xf_emit(ctx, 0xa7c, 0);
-               else
-                       xf_emit(ctx, 0xa7a, 0);
-               xf_emit(ctx, 1, 0x3fffff);
-               xf_emit(ctx, 2, 0);
-               xf_emit(ctx, 1, 0x1fff);
+               nv50_graph_construct_gene_ccache(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
                /* Strand 5 */
                ctx->ctxvals_pos = offset + 5;
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 1, 0x0fac6881);
-               xf_emit(ctx, 0xb, 0);
-               xf_emit(ctx, 2, 0x4e3bfdf);
-               xf_emit(ctx, 3, 0);
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-                       xf_emit(ctx, 1, 0x11);
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 2, 0x4e3bfdf);
-               xf_emit(ctx, 2, 0);
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-                       xf_emit(ctx, 1, 0x11);
-               xf_emit(ctx, 1, 0);
+               nv50_graph_construct_gene_ropm2(ctx);
+               nv50_graph_construct_gene_ropm1(ctx);
+               /* per-ROP context */
                for (i = 0; i < 8; i++)
                        if (units & (1<<(i+16)))
                                nv50_graph_construct_gene_ropc(ctx);
@@ -1238,10 +1273,9 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
 
                /* Strand 6 */
                ctx->ctxvals_pos = offset + 6;
-               nv50_graph_construct_gene_unk3(ctx);
-               xf_emit(ctx, 0xb, 0);
-               nv50_graph_construct_gene_unk4(ctx);
-               nv50_graph_construct_gene_unk7(ctx);
+               nv50_graph_construct_gene_zcull(ctx);
+               nv50_graph_construct_gene_clipid(ctx);
+               nv50_graph_construct_gene_eng2d(ctx);
                if (units & (1 << 0))
                        nv50_graph_construct_xfer_tp(ctx);
                if (units & (1 << 1))
@@ -1269,7 +1303,7 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
                        if (units & (1 << 9))
                                nv50_graph_construct_xfer_tp(ctx);
                } else {
-                       nv50_graph_construct_gene_unk2(ctx);
+                       nv50_graph_construct_gene_unk14xx(ctx);
                }
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
@@ -1289,10 +1323,71 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
  * non-trivial demagiced parts of ctx init go here
  */
 
+static void
+nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
+{
+       /* start of strand 0 */
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       /* SEEK */
+       if (dev_priv->chipset == 0x50)
+               xf_emit(ctx, 5, 0);
+       else if (!IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 6, 0);
+       else
+               xf_emit(ctx, 4, 0);
+       /* SEEK */
+       /* the PGRAPH's internal FIFO */
+       if (dev_priv->chipset == 0x50)
+               xf_emit(ctx, 8*3, 0);
+       else
+               xf_emit(ctx, 0x100*3, 0);
+       /* and another bonus slot?!? */
+       xf_emit(ctx, 3, 0);
+       /* and YET ANOTHER bonus slot? */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 3, 0);
+       /* SEEK */
+       /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
+       xf_emit(ctx, 9, 0);
+       /* SEEK */
+       xf_emit(ctx, 9, 0);
+       /* SEEK */
+       xf_emit(ctx, 9, 0);
+       /* SEEK */
+       xf_emit(ctx, 9, 0);
+       /* SEEK */
+       if (dev_priv->chipset < 0x90)
+               xf_emit(ctx, 4, 0);
+       /* SEEK */
+       xf_emit(ctx, 2, 0);
+       /* SEEK */
+       xf_emit(ctx, 6*2, 0);
+       xf_emit(ctx, 2, 0);
+       /* SEEK */
+       xf_emit(ctx, 2, 0);
+       /* SEEK */
+       xf_emit(ctx, 6*2, 0);
+       xf_emit(ctx, 2, 0);
+       /* SEEK */
+       if (dev_priv->chipset == 0x50)
+               xf_emit(ctx, 0x1c, 0);
+       else if (dev_priv->chipset < 0xa0)
+               xf_emit(ctx, 0x1e, 0);
+       else
+               xf_emit(ctx, 0x22, 0);
+       /* SEEK */
+       xf_emit(ctx, 0x15, 0);
+}
+
 static void
 nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
 {
-       /* m2mf state */
+       /* Strand 0, right after dispatch */
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int smallm2mf = 0;
+       if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98)
+               smallm2mf = 1;
+       /* SEEK */
        xf_emit (ctx, 1, 0);            /* DMA_NOTIFY instance >> 4 */
        xf_emit (ctx, 1, 0);            /* DMA_BUFFER_IN instance >> 4 */
        xf_emit (ctx, 1, 0);            /* DMA_BUFFER_OUT instance >> 4 */
@@ -1319,427 +1414,975 @@ nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
        xf_emit (ctx, 1, 0);            /* TILING_POSITION_OUT */
        xf_emit (ctx, 1, 0);            /* OFFSET_IN_HIGH */
        xf_emit (ctx, 1, 0);            /* OFFSET_OUT_HIGH */
+       /* SEEK */
+       if (smallm2mf)
+               xf_emit(ctx, 0x40, 0);  /* 20 * ffffffff, 3ffff */
+       else
+               xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */
+       xf_emit(ctx, 4, 0);             /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
+       /* SEEK */
+       if (smallm2mf)
+               xf_emit(ctx, 0x400, 0); /* ffffffff */
+       else
+               xf_emit(ctx, 0x800, 0); /* ffffffff */
+       xf_emit(ctx, 4, 0);             /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
+       /* SEEK */
+       xf_emit(ctx, 0x40, 0);          /* 20 * bits ffffffff, 3ffff */
+       xf_emit(ctx, 0x6, 0);           /* 1f, 0, 1f, 0, 1f, 0 */
 }
 
 static void
-nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* end of area 2 on pre-NVA0, area 1 on NVAx */
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x80);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0x80c14);
-       xf_emit(ctx, 1, 0);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0x3ff);
-       else
-               xf_emit(ctx, 1, 0x7ff);
+       xf_emit(ctx, 2, 0);             /* RO */
+       xf_emit(ctx, 0x800, 0);         /* ffffffff */
        switch (dev_priv->chipset) {
        case 0x50:
-       case 0x86:
-       case 0x98:
-       case 0xaa:
-       case 0xac:
-               xf_emit(ctx, 0x542, 0);
+       case 0x92:
+       case 0xa0:
+               xf_emit(ctx, 0x2b, 0);
                break;
        case 0x84:
-       case 0x92:
+               xf_emit(ctx, 0x29, 0);
+               break;
        case 0x94:
        case 0x96:
-               xf_emit(ctx, 0x942, 0);
-               break;
-       case 0xa0:
        case 0xa3:
-               xf_emit(ctx, 0x2042, 0);
+               xf_emit(ctx, 0x27, 0);
                break;
+       case 0x86:
+       case 0x98:
        case 0xa5:
        case 0xa8:
-               xf_emit(ctx, 0x842, 0);
+       case 0xaa:
+       case 0xac:
+       case 0xaf:
+               xf_emit(ctx, 0x25, 0);
                break;
        }
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x80);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x27);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x26);
-       xf_emit(ctx, 3, 0);
+       /* CB bindings, 0x80 of them. first word is address >> 8, second is
+        * size >> 4 | valid << 24 */
+       xf_emit(ctx, 0x100, 0);         /* ffffffff CB_DEF */
+       xf_emit(ctx, 1, 0);             /* 0000007f CB_ADDR_BUFFER */
+       xf_emit(ctx, 1, 0);             /* 0 */
+       xf_emit(ctx, 0x30, 0);          /* ff SET_PROGRAM_CB */
+       xf_emit(ctx, 1, 0);             /* 3f last SET_PROGRAM_CB */
+       xf_emit(ctx, 4, 0);             /* RO */
+       xf_emit(ctx, 0x100, 0);         /* ffffffff */
+       xf_emit(ctx, 8, 0);             /* 1f, 0, 0, ... */
+       xf_emit(ctx, 8, 0);             /* ffffffff */
+       xf_emit(ctx, 4, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 3 */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_CODE_CB */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_TIC */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_TSC */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINKED_TSC */
+       xf_emit(ctx, 1, 0);             /* 000000ff TIC_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff TIC_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0x3fffff);      /* 003fffff TIC_LIMIT */
+       xf_emit(ctx, 1, 0);             /* 000000ff TSC_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff TSC_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0x1fff);        /* 000fffff TSC_LIMIT */
+       xf_emit(ctx, 1, 0);             /* 000000ff VP_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff VP_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 00ffffff VP_START_ID */
+       xf_emit(ctx, 1, 0);             /* 000000ff CB_DEF_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff CB_DEF_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 000000ff GP_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff GP_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 00ffffff GP_START_ID */
+       xf_emit(ctx, 1, 0);             /* 000000ff FP_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff FP_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 00ffffff FP_START_ID */
 }
 
 static void
-nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
 {
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int i;
        /* end of area 2 on pre-NVA0, area 1 on NVAx */
-       xf_emit(ctx, 0x10, 0x04000000);
-       xf_emit(ctx, 0x24, 0);
-       xf_emit(ctx, 2, 0x04e3bfdf);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x1fe21);
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x80);          /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 0x80c14);       /* 01ffffff SEMANTIC_COLOR */
+       xf_emit(ctx, 1, 0);             /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+       if (dev_priv->chipset == 0x50)
+               xf_emit(ctx, 1, 0x3ff);
+       else
+               xf_emit(ctx, 1, 0x7ff); /* 000007ff */
+       xf_emit(ctx, 1, 0);             /* 111/113 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       for (i = 0; i < 8; i++) {
+               switch (dev_priv->chipset) {
+               case 0x50:
+               case 0x86:
+               case 0x98:
+               case 0xaa:
+               case 0xac:
+                       xf_emit(ctx, 0xa0, 0);  /* ffffffff */
+                       break;
+               case 0x84:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+                       xf_emit(ctx, 0x120, 0);
+                       break;
+               case 0xa5:
+               case 0xa8:
+                       xf_emit(ctx, 0x100, 0); /* ffffffff */
+                       break;
+               case 0xa0:
+               case 0xa3:
+               case 0xaf:
+                       xf_emit(ctx, 0x400, 0); /* ffffffff */
+                       break;
+               }
+               xf_emit(ctx, 4, 0);     /* 3f, 0, 0, 0 */
+               xf_emit(ctx, 4, 0);     /* ffffffff */
+       }
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x80);          /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_REG_ALLOC_TEMP */
+       xf_emit(ctx, 1, 1);             /* 00000001 RASTERIZE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0x27);          /* 000000ff UNK0FD4 */
+       xf_emit(ctx, 1, 0);             /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0x26);          /* 000000ff SEMANTIC_LAYER */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       /* end of area 2 on pre-NVA0, area 1 on NVAx */
+       xf_emit(ctx, 1, 0);             /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000003 VIEWPORT_CLIP_MODE */
+       xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
+       xf_emit(ctx, 1, 0);             /* 00000001 POLYGON_STIPPLE_ENABLE */
+       xf_emit(ctx, 0x20, 0);          /* ffffffff POLYGON_STIPPLE */
+       xf_emit(ctx, 2, 0);             /* 00007fff WINDOW_OFFSET_XY */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0x04e3bfdf);    /* ffffffff UNK0D64 */
+       xf_emit(ctx, 1, 0x04e3bfdf);    /* ffffffff UNK0DF4 */
+       xf_emit(ctx, 1, 0);             /* 00000003 WINDOW_ORIGIN */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0x1fe21);       /* 0001ffff tesla UNK0FAC */
+       if (dev_priv->chipset >= 0xa0)
+               xf_emit(ctx, 1, 0x0fac6881);
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 1);
+               xf_emit(ctx, 3, 0);
+       }
 }
 
 static void
-nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
        /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
        if (dev_priv->chipset != 0x50) {
-               xf_emit(ctx, 5, 0);
-               xf_emit(ctx, 1, 0x80c14);
-               xf_emit(ctx, 2, 0);
-               xf_emit(ctx, 1, 0x804);
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 2, 4);
-               xf_emit(ctx, 1, 0x8100c12);
+               xf_emit(ctx, 5, 0);             /* ffffffff */
+               xf_emit(ctx, 1, 0x80c14);       /* 01ffffff SEMANTIC_COLOR */
+               xf_emit(ctx, 1, 0);             /* 00000001 */
+               xf_emit(ctx, 1, 0);             /* 000003ff */
+               xf_emit(ctx, 1, 0x804);         /* 00000fff SEMANTIC_CLIP */
+               xf_emit(ctx, 1, 0);             /* 00000001 */
+               xf_emit(ctx, 2, 4);             /* 7f, ff */
+               xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
        }
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x10);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 3, 0);
-       else
-               xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x804);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x1a);
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 4);                     /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);                     /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x10);                  /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);                     /* 000000ff VP_CLIP_DISTANCE_ENABLE */
        if (dev_priv->chipset != 0x50)
-               xf_emit(ctx, 1, 0x7f);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x80c14);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 6, 0);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0x3ff);
-       else
-               xf_emit(ctx, 1, 0x7ff);
-       xf_emit(ctx, 1, 0x80c14);
-       xf_emit(ctx, 0x38, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 0x38, 0);
-       xf_emit(ctx, 2, 0x88);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 0x16, 0);
-       xf_emit(ctx, 1, 0x26);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x3f800000);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 4, 0);
-       else
-               xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x1a);
-       xf_emit(ctx, 1, 0x10);
+               xf_emit(ctx, 1, 0);             /* 3ff */
+       xf_emit(ctx, 1, 0);                     /* 000000ff tesla UNK1940 */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK0D7C */
+       xf_emit(ctx, 1, 0x804);                 /* 00000fff SEMANTIC_CLIP */
+       xf_emit(ctx, 1, 1);                     /* 00000001 VIEWPORT_TRANSFORM_EN */
+       xf_emit(ctx, 1, 0x1a);                  /* 0000001f POLYGON_MODE */
        if (dev_priv->chipset != 0x50)
-               xf_emit(ctx, 0x28, 0);
+               xf_emit(ctx, 1, 0x7f);          /* 000000ff tesla UNK0FFC */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 1);                     /* 00000001 SHADE_MODEL */
+       xf_emit(ctx, 1, 0x80c14);               /* 01ffffff SEMANTIC_COLOR */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0x8100c12);             /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 4);                     /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);                     /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x10);                  /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK0D7C */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK0F8C */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 1);                     /* 00000001 VIEWPORT_TRANSFORM_EN */
+       xf_emit(ctx, 1, 0x8100c12);             /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 4, 0);                     /* ffffffff NOPERSPECTIVE_BITMAP */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0);                     /* 0000000f */
+       if (dev_priv->chipset == 0x50)
+               xf_emit(ctx, 1, 0x3ff);         /* 000003ff tesla UNK0D68 */
        else
-               xf_emit(ctx, 0x25, 0);
-       xf_emit(ctx, 1, 0x52);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x26);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x1a);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x00ffff00);
-       xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 1, 0x7ff);         /* 000007ff tesla UNK0D68 */
+       xf_emit(ctx, 1, 0x80c14);               /* 01ffffff SEMANTIC_COLOR */
+       xf_emit(ctx, 1, 0);                     /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+       xf_emit(ctx, 0x30, 0);                  /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
+       xf_emit(ctx, 3, 0);                     /* f, 0, 0 */
+       xf_emit(ctx, 3, 0);                     /* ffffffff last VIEWPORT_SCALE? */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 1);                     /* 00000001 VIEWPORT_TRANSFORM_EN */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1924 */
+       xf_emit(ctx, 1, 0x10);                  /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);                     /* 00000001 */
+       xf_emit(ctx, 0x30, 0);                  /* ffffffff VIEWPORT_TRANSLATE */
+       xf_emit(ctx, 3, 0);                     /* f, 0, 0 */
+       xf_emit(ctx, 3, 0);                     /* ffffffff */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 2, 0x88);                  /* 000001ff tesla UNK19D8 */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1924 */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 4);                     /* 0000000f CULL_MODE */
+       xf_emit(ctx, 2, 0);                     /* 07ffffff SCREEN_SCISSOR */
+       xf_emit(ctx, 2, 0);                     /* 00007fff WINDOW_OFFSET_XY */
+       xf_emit(ctx, 1, 0);                     /* 00000003 WINDOW_ORIGIN */
+       xf_emit(ctx, 0x10, 0);                  /* 00000001 SCISSOR_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0x26);                  /* 000000ff SEMANTIC_LAYER */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0);                     /* 0000000f */
+       xf_emit(ctx, 1, 0x3f800000);            /* ffffffff LINE_WIDTH */
+       xf_emit(ctx, 1, 0);                     /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 LINE_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 0);             /* 00000001 */
+       xf_emit(ctx, 1, 0x1a);                  /* 0000001f POLYGON_MODE */
+       xf_emit(ctx, 1, 0x10);                  /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+       if (dev_priv->chipset != 0x50) {
+               xf_emit(ctx, 1, 0);             /* ffffffff */
+               xf_emit(ctx, 1, 0);             /* 00000001 */
+               xf_emit(ctx, 1, 0);             /* 000003ff */
+       }
+       xf_emit(ctx, 0x20, 0);                  /* 10xbits ffffffff, 3fffff. SCISSOR_* */
+       xf_emit(ctx, 1, 0);                     /* f */
+       xf_emit(ctx, 1, 0);                     /* 0? */
+       xf_emit(ctx, 1, 0);                     /* ffffffff */
+       xf_emit(ctx, 1, 0);                     /* 003fffff */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0x52);                  /* 000001ff SEMANTIC_PTSZ */
+       xf_emit(ctx, 1, 0);                     /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0x26);                  /* 000000ff SEMANTIC_LAYER */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 4);                     /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);                     /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x1a);                  /* 0000001f POLYGON_MODE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 LINE_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0x00ffff00);            /* 00ffffff LINE_STIPPLE_PATTERN */
+       xf_emit(ctx, 1, 0);                     /* 0000000f */
 }
 
 static void
-nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* end of area 0 on pre-NVA0, beginning of area 6 on NVAx */
-       xf_emit(ctx, 1, 0x3f);
-       xf_emit(ctx, 0xa, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 0x04000000);
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 4);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 0x10, 0);
-       else
-               xf_emit(ctx, 0x11, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x1001);
-       xf_emit(ctx, 4, 0xffff);
-       xf_emit(ctx, 0x20, 0);
-       xf_emit(ctx, 0x10, 0x3f800000);
-       xf_emit(ctx, 1, 0x10);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0);
-       else
-               xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 2, 0);
+       /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
+       /* SEEK */
+       xf_emit(ctx, 1, 0x3f);          /* 0000003f UNK1590 */
+       xf_emit(ctx, 1, 0);             /* 00000001 ALPHA_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_BACK_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_REF */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 2);             /* 00000003 tesla UNK143C */
+       xf_emit(ctx, 2, 0x04000000);    /* 07ffffff tesla UNK0D6C */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0);             /* 00000001 CLIPID_ENABLE */
+       xf_emit(ctx, 2, 0);             /* ffffffff DEPTH_BOUNDS */
+       xf_emit(ctx, 1, 0);             /* 00000001 */
+       xf_emit(ctx, 1, 0);             /* 00000007 DEPTH_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 0000000f CULL_MODE */
+       xf_emit(ctx, 1, 0);             /* 0000ffff */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK0FB0 */
+       xf_emit(ctx, 1, 0);             /* 00000001 POLYGON_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0);             /* 000000ff CLEAR_STENCIL */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_REF */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff CLEAR_DEPTH */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       if (dev_priv->chipset != 0x50)
+               xf_emit(ctx, 1, 0);     /* 00000003 tesla UNK1108 */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0x1001);        /* 00001fff ZETA_ARRAY_MODE */
+       /* SEEK */
+       xf_emit(ctx, 4, 0xffff);        /* 0000ffff MSAA_MASK */
+       xf_emit(ctx, 0x10, 0);          /* 00000001 SCISSOR_ENABLE */
+       xf_emit(ctx, 0x10, 0);          /* ffffffff DEPTH_RANGE_NEAR */
+       xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+       xf_emit(ctx, 1, 0x10);          /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);             /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+       xf_emit(ctx, 1, 3);             /* 00000003 FP_CTRL_UNK196C */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK1968 */
+       if (dev_priv->chipset != 0x50)
+               xf_emit(ctx, 1, 0);     /* 0fffffff tesla UNK1104 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK151C */
 }
 
 static void
-nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx)
 {
-       /* middle of area 0 on pre-NVA0, middle of area 6 on NVAx */
-       xf_emit(ctx, 2, 0x04000000);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x80);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x80);
-       xf_emit(ctx, 1, 0);
+       /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000007 UNK0FB4 */
+       /* SEEK */
+       xf_emit(ctx, 4, 0);             /* 07ffffff CLIPID_REGION_HORIZ */
+       xf_emit(ctx, 4, 0);             /* 07ffffff CLIPID_REGION_VERT */
+       xf_emit(ctx, 2, 0);             /* 07ffffff SCREEN_SCISSOR */
+       xf_emit(ctx, 2, 0x04000000);    /* 07ffffff UNK1508 */
+       xf_emit(ctx, 1, 0);             /* 00000001 CLIPID_ENABLE */
+       xf_emit(ctx, 1, 0x80);          /* 00003fff CLIPID_WIDTH */
+       xf_emit(ctx, 1, 0);             /* 000000ff CLIPID_ID */
+       xf_emit(ctx, 1, 0);             /* 000000ff CLIPID_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff CLIPID_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0x80);          /* 00003fff CLIPID_HEIGHT */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_CLIPID */
 }
 
 static void
-nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* middle of area 0 on pre-NVA0 [after m2mf], end of area 2 on NVAx */
-       xf_emit(ctx, 2, 4);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0x1c4d, 0);
+       int i;
+       /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
+       /* SEEK */
+       xf_emit(ctx, 0x33, 0);
+       /* SEEK */
+       xf_emit(ctx, 2, 0);
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 4, 0);     /* RO */
+               xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+               xf_emit(ctx, 1, 0);     /* 1ff */
+               xf_emit(ctx, 8, 0);     /* 0? */
+               xf_emit(ctx, 9, 0);     /* ffffffff, 7ff */
+
+               xf_emit(ctx, 4, 0);     /* RO */
+               xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+               xf_emit(ctx, 1, 0);     /* 1ff */
+               xf_emit(ctx, 8, 0);     /* 0? */
+               xf_emit(ctx, 9, 0);     /* ffffffff, 7ff */
+       }
        else
-               xf_emit(ctx, 0x1c4b, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0x8100c12);
+       {
+               xf_emit(ctx, 0xc, 0);   /* RO */
+               /* SEEK */
+               xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+               xf_emit(ctx, 1, 0);     /* 1ff */
+               xf_emit(ctx, 8, 0);     /* 0? */
+
+               /* SEEK */
+               xf_emit(ctx, 0xc, 0);   /* RO */
+               /* SEEK */
+               xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+               xf_emit(ctx, 1, 0);     /* 1ff */
+               xf_emit(ctx, 8, 0);     /* 0? */
+       }
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
        if (dev_priv->chipset != 0x50)
-               xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x80c14);
-       xf_emit(ctx, 1, 1);
+               xf_emit(ctx, 1, 3);     /* 00000003 tesla UNK1100 */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 0);             /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+       xf_emit(ctx, 1, 0x80c14);       /* 01ffffff SEMANTIC_COLOR */
+       xf_emit(ctx, 1, 1);             /* 00000001 */
+       /* SEEK */
        if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0x80c14);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 1, 0x27);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x3c1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x16, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 2, 4);     /* 000000ff */
+       xf_emit(ctx, 1, 0x80c14);       /* 01ffffff SEMANTIC_COLOR */
+       xf_emit(ctx, 1, 0);             /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 POINT_SPRITE_ENABLE */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 0x27);          /* 000000ff SEMANTIC_PRIM_ID */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f */
+       xf_emit(ctx, 1, 1);             /* 00000001 */
+       for (i = 0; i < 10; i++) {
+               /* SEEK */
+               xf_emit(ctx, 0x40, 0);          /* ffffffff */
+               xf_emit(ctx, 0x10, 0);          /* 3, 0, 0.... */
+               xf_emit(ctx, 0x10, 0);          /* ffffffff */
+       }
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000001 POINT_SPRITE_CTRL */
+       xf_emit(ctx, 1, 1);             /* 00000001 */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 4, 0);             /* ffffffff NOPERSPECTIVE_BITMAP */
+       xf_emit(ctx, 0x10, 0);          /* 00ffffff POINT_COORD_REPLACE_MAP */
+       xf_emit(ctx, 1, 0);             /* 00000003 WINDOW_ORIGIN */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
+       if (dev_priv->chipset != 0x50)
+               xf_emit(ctx, 1, 0);     /* 000003ff */
 }
 
 static void
-nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* beginning of area 1 on pre-NVA0 [after m2mf], area 3 on NVAx */
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0xf);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 8, 0);
-       else
-               xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x20);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0x11, 0);
+       int acnt = 0x10, rep, i;
+       /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
+       if (IS_NVA3F(dev_priv->chipset))
+               acnt = 0x20;
+       /* SEEK */
+       if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 1, 0);     /* ffffffff tesla UNK13A4 */
+               xf_emit(ctx, 1, 1);     /* 00000fff tesla UNK1318 */
+       }
+       xf_emit(ctx, 1, 0);             /* ffffffff VERTEX_BUFFER_FIRST */
+       xf_emit(ctx, 1, 0);             /* 00000001 PRIMITIVE_RESTART_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK0DE8 */
+       xf_emit(ctx, 1, 0);             /* ffffffff PRIMITIVE_RESTART_INDEX */
+       xf_emit(ctx, 1, 0xf);           /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, (acnt/8)-1, 0);    /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, acnt/8, 0);        /* ffffffff VTX_ATR_MASK_UNK0DD0 */
+       xf_emit(ctx, 1, 0);             /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+       xf_emit(ctx, 1, 0x20);          /* 0000ffff tesla UNK129C */
+       xf_emit(ctx, 1, 0);             /* 000000ff turing UNK370??? */
+       xf_emit(ctx, 1, 0);             /* 0000ffff turing USER_PARAM_COUNT */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0xb, 0);   /* RO */
        else if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 0xf, 0);
+               xf_emit(ctx, 0x9, 0);   /* RO */
        else
-               xf_emit(ctx, 0xe, 0);
-       xf_emit(ctx, 1, 0x1a);
-       xf_emit(ctx, 0xd, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 8);
-       xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 0x8, 0);   /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 00000001 EDGE_FLAG */
+       xf_emit(ctx, 1, 0);             /* 00000001 PROVOKING_VERTEX_LAST */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0x1a);          /* 0000001f POLYGON_MODE */
+       /* SEEK */
+       xf_emit(ctx, 0xc, 0);           /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 7f/ff */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+       xf_emit(ctx, 1, 4);             /* 000001ff UNK1A28 */
+       xf_emit(ctx, 1, 8);             /* 000001ff UNK0DF0 */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
        if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0x3ff);
+               xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */
        else
-               xf_emit(ctx, 1, 0x7ff);
+               xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */
        if (dev_priv->chipset == 0xa8)
-               xf_emit(ctx, 1, 0x1e00);
-       xf_emit(ctx, 0xc, 0);
-       xf_emit(ctx, 1, 0xf);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 0x125, 0);
-       else if (dev_priv->chipset < 0xa0)
-               xf_emit(ctx, 0x126, 0);
-       else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
-               xf_emit(ctx, 0x124, 0);
+               xf_emit(ctx, 1, 0x1e00);        /* 7fff */
+       /* SEEK */
+       xf_emit(ctx, 0xc, 0);           /* RO or close */
+       /* SEEK */
+       xf_emit(ctx, 1, 0xf);           /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, (acnt/8)-1, 0);    /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, 1, 0);             /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+       if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0)
+               xf_emit(ctx, 2, 0);     /* ffffffff */
        else
-               xf_emit(ctx, 0x1f7, 0);
-       xf_emit(ctx, 1, 0xf);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 3, 0);
+               xf_emit(ctx, 1, 0);     /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK0FD8 */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 0x10, 0);  /* 0? */
+               xf_emit(ctx, 2, 0);     /* weird... */
+               xf_emit(ctx, 2, 0);     /* RO */
+       } else {
+               xf_emit(ctx, 8, 0);     /* 0? */
+               xf_emit(ctx, 1, 0);     /* weird... */
+               xf_emit(ctx, 2, 0);     /* RO */
+       }
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* ffffffff VB_ELEMENT_BASE */
+       xf_emit(ctx, 1, 0);             /* ffffffff UNK1438 */
+       xf_emit(ctx, acnt, 0);          /* 1 tesla UNK1000 */
+       if (dev_priv->chipset >= 0xa0)
+               xf_emit(ctx, 1, 0);     /* ffffffff tesla UNK1118? */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* ffffffff VERTEX_ARRAY_UNK90C */
+       xf_emit(ctx, 1, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* ffffffff VERTEX_ARRAY_UNK90C */
+       xf_emit(ctx, 1, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* RO */
+       xf_emit(ctx, 2, 0);             /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK111C? */
+       xf_emit(ctx, 1, 0);             /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 000000ff UNK15F4_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff UNK15F4_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 000000ff UNK0F84_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff UNK0F84_ADDRESS_LOW */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* 00000fff VERTEX_ARRAY_STRIDE */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* ffffffff VERTEX_ARRAY_LOW */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* 000000ff VERTEX_ARRAY_HIGH */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* ffffffff VERTEX_LIMIT_LOW */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       xf_emit(ctx, acnt, 0);          /* 000000ff VERTEX_LIMIT_HIGH */
+       xf_emit(ctx, 3, 0);             /* f/1f */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, acnt, 0);          /* f */
+               xf_emit(ctx, 3, 0);             /* f/1f */
+       }
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 2, 0);     /* RO */
+       else
+               xf_emit(ctx, 5, 0);     /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* ffff DMA_VTXBUF */
+       /* SEEK */
+       if (dev_priv->chipset < 0xa0) {
+               xf_emit(ctx, 0x41, 0);  /* RO */
+               /* SEEK */
+               xf_emit(ctx, 0x11, 0);  /* RO */
+       } else if (!IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0x50, 0);  /* RO */
        else
-               xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0xa1, 0);
+               xf_emit(ctx, 0x58, 0);  /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0xf);           /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, (acnt/8)-1, 0);    /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, 1, 1);             /* 1 UNK0DEC */
+       /* SEEK */
+       xf_emit(ctx, acnt*4, 0);        /* ffffffff VTX_ATTR */
+       xf_emit(ctx, 4, 0);             /* f/1f, 0, 0, 0 */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0x1d, 0);  /* RO */
        else
-               xf_emit(ctx, 0x5a, 0);
-       xf_emit(ctx, 1, 0xf);
+               xf_emit(ctx, 0x16, 0);  /* RO */
+       /* SEEK */
+       xf_emit(ctx, 1, 0xf);           /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, (acnt/8)-1, 0);    /* ffffffff VP_ATTR_EN */
+       /* SEEK */
        if (dev_priv->chipset < 0xa0)
-               xf_emit(ctx, 0x834, 0);
-       else if (dev_priv->chipset == 0xa0)
-               xf_emit(ctx, 0x1873, 0);
-       else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0x8ba, 0);
+               xf_emit(ctx, 8, 0);     /* RO */
+       else if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0xc, 0);   /* RO */
+       else
+               xf_emit(ctx, 7, 0);     /* RO */
+       /* SEEK */
+       xf_emit(ctx, 0xa, 0);           /* RO */
+       if (dev_priv->chipset == 0xa0)
+               rep = 0xc;
+       else
+               rep = 4;
+       for (i = 0; i < rep; i++) {
+               /* SEEK */
+               if (IS_NVA3F(dev_priv->chipset))
+                       xf_emit(ctx, 0x20, 0);  /* ffffffff */
+               xf_emit(ctx, 0x200, 0); /* ffffffff */
+               xf_emit(ctx, 4, 0);     /* 7f/ff, 0, 0, 0 */
+               xf_emit(ctx, 4, 0);     /* ffffffff */
+       }
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 113/111 */
+       xf_emit(ctx, 1, 0xf);           /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, (acnt/8)-1, 0);    /* ffffffff VP_ATTR_EN */
+       xf_emit(ctx, acnt/8, 0);        /* ffffffff VTX_ATTR_MASK_UNK0DD0 */
+       xf_emit(ctx, 1, 0);             /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       /* SEEK */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 7, 0);     /* weird... */
        else
-               xf_emit(ctx, 0x833, 0);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 0xf, 0);
+               xf_emit(ctx, 5, 0);     /* weird... */
 }
 
 static void
-nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 6 on NVAx */
-       xf_emit(ctx, 2, 0);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 2, 1);
-       else
-               xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0x100);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 8);
-       xf_emit(ctx, 5, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 3, 1);
-       xf_emit(ctx, 1, 0xcf);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 6, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 3, 1);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x15);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x4444480);
-       xf_emit(ctx, 0x37, 0);
+       /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
+       /* SEEK */
+       xf_emit(ctx, 2, 0);             /* 0001ffff CLIP_X, CLIP_Y */
+       xf_emit(ctx, 2, 0);             /* 0000ffff CLIP_W, CLIP_H */
+       xf_emit(ctx, 1, 0);             /* 00000001 CLIP_ENABLE */
+       if (dev_priv->chipset < 0xa0) {
+               /* this is useless on everything but the original NV50,
+                * guess they forgot to nuke it. Or just didn't bother. */
+               xf_emit(ctx, 2, 0);     /* 0000ffff IFC_CLIP_X, Y */
+               xf_emit(ctx, 2, 1);     /* 0000ffff IFC_CLIP_W, H */
+               xf_emit(ctx, 1, 0);     /* 00000001 IFC_CLIP_ENABLE */
+       }
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       xf_emit(ctx, 1, 0x100);         /* 0001ffff DST_WIDTH */
+       xf_emit(ctx, 1, 0x100);         /* 0001ffff DST_HEIGHT */
+       xf_emit(ctx, 1, 0x11);          /* 3f[NV50]/7f[NV84+] DST_FORMAT */
+       xf_emit(ctx, 1, 0);             /* 0001ffff DRAW_POINT_X */
+       xf_emit(ctx, 1, 8);             /* 0000000f DRAW_UNK58C */
+       xf_emit(ctx, 1, 0);             /* 000fffff SIFC_DST_X_FRACT */
+       xf_emit(ctx, 1, 0);             /* 0001ffff SIFC_DST_X_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff SIFC_DST_Y_FRACT */
+       xf_emit(ctx, 1, 0);             /* 0001ffff SIFC_DST_Y_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff SIFC_DX_DU_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff SIFC_DX_DU_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff SIFC_DY_DV_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff SIFC_DY_DV_INT */
+       xf_emit(ctx, 1, 1);             /* 0000ffff SIFC_WIDTH */
+       xf_emit(ctx, 1, 1);             /* 0000ffff SIFC_HEIGHT */
+       xf_emit(ctx, 1, 0xcf);          /* 000000ff SIFC_FORMAT */
+       xf_emit(ctx, 1, 2);             /* 00000003 SIFC_BITMAP_UNK808 */
+       xf_emit(ctx, 1, 0);             /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
+       xf_emit(ctx, 1, 0);             /* 00000001 SIFC_BITMAP_LSB_FIRST */
+       xf_emit(ctx, 1, 0);             /* 00000001 SIFC_BITMAP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000ffff BLIT_DST_X */
+       xf_emit(ctx, 1, 0);             /* 0000ffff BLIT_DST_Y */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_DU_DX_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff BLIT_DU_DX_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_DV_DY_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff BLIT_DV_DY_INT */
+       xf_emit(ctx, 1, 1);             /* 0000ffff BLIT_DST_W */
+       xf_emit(ctx, 1, 1);             /* 0000ffff BLIT_DST_H */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_SRC_X_FRACT */
+       xf_emit(ctx, 1, 0);             /* 0001ffff BLIT_SRC_X_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_SRC_Y_FRACT */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK888 */
+       xf_emit(ctx, 1, 4);             /* 0000003f UNK884 */
+       xf_emit(ctx, 1, 0);             /* 00000007 UNK880 */
+       xf_emit(ctx, 1, 1);             /* 0000001f tesla UNK0FB8 */
+       xf_emit(ctx, 1, 0x15);          /* 000000ff tesla UNK128C */
+       xf_emit(ctx, 2, 0);             /* 00000007, ffff0ff3 */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK260 */
+       xf_emit(ctx, 1, 0x4444480);     /* 1fffffff UNK870 */
+       /* SEEK */
+       xf_emit(ctx, 0x10, 0);
+       /* SEEK */
+       xf_emit(ctx, 0x27, 0);
 }
 
 static void
-nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
 {
-       /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 0 on NVAx */
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x100);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x10001);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x10001);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x10001);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 2);
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
+       /* SEEK */
+       xf_emit(ctx, 2, 0);             /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1924 */
+       xf_emit(ctx, 1, 0);             /* 00000003 WINDOW_ORIGIN */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 0);             /* 000003ff */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* ffffffff turing UNK364 */
+       xf_emit(ctx, 1, 0);             /* 0000000f turing UNK36C */
+       xf_emit(ctx, 1, 0);             /* 0000ffff USER_PARAM_COUNT */
+       xf_emit(ctx, 1, 0x100);         /* 00ffffff turing UNK384 */
+       xf_emit(ctx, 1, 0);             /* 0000000f turing UNK2A0 */
+       xf_emit(ctx, 1, 0);             /* 0000ffff GRIDID */
+       xf_emit(ctx, 1, 0x10001);       /* ffffffff GRIDDIM_XY */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0x10001);       /* ffffffff BLOCKDIM_XY */
+       xf_emit(ctx, 1, 1);             /* 0000ffff BLOCKDIM_Z */
+       xf_emit(ctx, 1, 0x10001);       /* 00ffffff BLOCK_ALLOC */
+       xf_emit(ctx, 1, 1);             /* 00000001 LANES32 */
+       xf_emit(ctx, 1, 4);             /* 000000ff FP_REG_ALLOC_TEMP */
+       xf_emit(ctx, 1, 2);             /* 00000003 REG_MODE */
+       /* SEEK */
+       xf_emit(ctx, 0x40, 0);          /* ffffffff USER_PARAM */
+       switch (dev_priv->chipset) {
+       case 0x50:
+       case 0x92:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0x80, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 0x10*2, 0);        /* ffffffff, 1f */
+               break;
+       case 0x84:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0x60, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+               break;
+       case 0x94:
+       case 0x96:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0x40, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 8*2, 0);   /* ffffffff, 1f */
+               break;
+       case 0x86:
+       case 0x98:
+               xf_emit(ctx, 4, 0);     /* f, 0, 0, 0 */
+               xf_emit(ctx, 0x10, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 2*2, 0);   /* ffffffff, 1f */
+               break;
+       case 0xa0:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0xf0, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 0x1e*2, 0);        /* ffffffff, 1f */
+               break;
+       case 0xa3:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0x60, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+               break;
+       case 0xa5:
+       case 0xaf:
+               xf_emit(ctx, 8, 0);     /* 7, 0, 0, 0, ... */
+               xf_emit(ctx, 0x30, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 6*2, 0);   /* ffffffff, 1f */
+               break;
+       case 0xaa:
+               xf_emit(ctx, 0x12, 0);
+               break;
+       case 0xa8:
+       case 0xac:
+               xf_emit(ctx, 4, 0);     /* f, 0, 0, 0 */
+               xf_emit(ctx, 0x10, 0);  /* fff */
+               xf_emit(ctx, 2, 0);     /* ff, fff */
+               xf_emit(ctx, 2*2, 0);   /* ffffffff, 1f */
+               break;
+       }
+       xf_emit(ctx, 1, 0);             /* 0000000f */
+       xf_emit(ctx, 1, 0);             /* 00000000 */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 0000001f */
+       xf_emit(ctx, 4, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 00000003 turing UNK35C */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 4, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 00000003 turing UNK35C */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 000000ff */
 }
 
 static void
-nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       /* middle of area 2 on pre-NVA0 [after m2mf], end of area 0 on NVAx */
-       xf_emit(ctx, 1, 0x3f800000);
-       xf_emit(ctx, 6, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0x1a);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x12, 0);
-       xf_emit(ctx, 1, 0x00ffff00);
-       xf_emit(ctx, 6, 0);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 0xf, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 2, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 3);
+       xf_emit(ctx, 2, 0);             /* 00007fff WINDOW_OFFSET_XY */
+       xf_emit(ctx, 1, 0x3f800000);    /* ffffffff LINE_WIDTH */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1658 */
+       xf_emit(ctx, 1, 0);             /* 00000001 POLYGON_SMOOTH_ENABLE */
+       xf_emit(ctx, 3, 0);             /* 00000001 POLYGON_OFFSET_*_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 0000000f CULL_MODE */
+       xf_emit(ctx, 1, 0x1a);          /* 0000001f POLYGON_MODE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 0);             /* 00000001 POINT_SPRITE_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK165C */
+       xf_emit(ctx, 0x10, 0);          /* 00000001 SCISSOR_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0x00ffff00);    /* 00ffffff LINE_STIPPLE_PATTERN */
+       xf_emit(ctx, 1, 0);             /* ffffffff POLYGON_OFFSET_UNITS */
+       xf_emit(ctx, 1, 0);             /* ffffffff POLYGON_OFFSET_FACTOR */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK1668 */
+       xf_emit(ctx, 2, 0);             /* 07ffffff SCREEN_SCISSOR */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0x11);          /* 0000007f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 0000007f RT_FORMAT */
+       xf_emit(ctx, 8, 0);             /* 00000001 RT_HORIZ_LINEAR */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000001 ALPHA_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 ALPHA_TEST_FUNC */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 3);     /* 00000003 UNK16B4 */
        else if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 0x04000000);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 5);
-       xf_emit(ctx, 1, 0x52);
-       if (dev_priv->chipset == 0x50) {
-               xf_emit(ctx, 0x13, 0);
-       } else {
-               xf_emit(ctx, 4, 0);
-               xf_emit(ctx, 1, 1);
-               if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-                       xf_emit(ctx, 0x11, 0);
-               else
-                       xf_emit(ctx, 0x10, 0);
+               xf_emit(ctx, 1, 1);     /* 00000001 UNK16B4 */
+       xf_emit(ctx, 1, 0);             /* 00000003 MULTISAMPLE_CTRL */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK0F90 */
+       xf_emit(ctx, 1, 2);             /* 00000003 tesla UNK143C */
+       xf_emit(ctx, 2, 0x04000000);    /* 07ffffff tesla UNK0D6C */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 5);             /* 0000000f UNK1408 */
+       xf_emit(ctx, 1, 0x52);          /* 000001ff SEMANTIC_PTSZ */
+       xf_emit(ctx, 1, 0);             /* ffffffff POINT_SIZE */
+       xf_emit(ctx, 1, 0);             /* 00000001 */
+       xf_emit(ctx, 1, 0);             /* 00000007 tesla UNK0FB4 */
+       if (dev_priv->chipset != 0x50) {
+               xf_emit(ctx, 1, 0);     /* 3ff */
+               xf_emit(ctx, 1, 1);     /* 00000001 tesla UNK1110 */
        }
-       xf_emit(ctx, 0x10, 0x3f800000);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 0x26, 0);
-       xf_emit(ctx, 1, 0x8100c12);
-       xf_emit(ctx, 1, 5);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 4, 0xffff);
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 0);     /* 00000003 tesla UNK1928 */
+       xf_emit(ctx, 0x10, 0);          /* ffffffff DEPTH_RANGE_NEAR */
+       xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+       xf_emit(ctx, 1, 0x10);          /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 0x20, 0);          /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK187C */
+       xf_emit(ctx, 1, 0);             /* 00000003 WINDOW_ORIGIN */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_MASK */
+       xf_emit(ctx, 1, 0x8100c12);     /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 5);             /* 0000000f tesla UNK1220 */
+       xf_emit(ctx, 1, 0);             /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 000000ff tesla UNK1A20 */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+       xf_emit(ctx, 4, 0xffff);        /* 0000ffff MSAA_MASK */
        if (dev_priv->chipset != 0x50)
-               xf_emit(ctx, 1, 3);
+               xf_emit(ctx, 1, 3);     /* 00000003 tesla UNK1100 */
        if (dev_priv->chipset < 0xa0)
-               xf_emit(ctx, 0x1f, 0);
-       else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0xc, 0);
-       else
-               xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x00ffff00);
-       xf_emit(ctx, 1, 0x1a);
+               xf_emit(ctx, 0x1c, 0);  /* RO */
+       else if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0x9, 0);
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0x00ffff00);    /* 00ffffff LINE_STIPPLE_PATTERN */
+       xf_emit(ctx, 1, 0x1a);          /* 0000001f POLYGON_MODE */
+       xf_emit(ctx, 1, 0);             /* 00000003 WINDOW_ORIGIN */
        if (dev_priv->chipset != 0x50) {
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 1, 3);
+               xf_emit(ctx, 1, 3);     /* 00000003 tesla UNK1100 */
+               xf_emit(ctx, 1, 0);     /* 3ff */
        }
+       /* XXX: the following block could belong either to unk1cxx, or
+        * to STRMOUT. Rather hard to tell. */
        if (dev_priv->chipset < 0xa0)
-               xf_emit(ctx, 0x26, 0);
+               xf_emit(ctx, 0x25, 0);
        else
-               xf_emit(ctx, 0x3c, 0);
-       xf_emit(ctx, 1, 0x102);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 4, 4);
-       if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 0x3b, 0);
+}
+
+static void
+nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       xf_emit(ctx, 1, 0x102);         /* 0000ffff STRMOUT_BUFFER_CTRL */
+       xf_emit(ctx, 1, 0);             /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+       xf_emit(ctx, 4, 4);             /* 000000ff STRMOUT_NUM_ATTRIBS */
+       if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 4, 0);     /* ffffffff UNK1A8C */
+               xf_emit(ctx, 4, 0);     /* ffffffff UNK1780 */
+       }
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 4);             /* 0000007f VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
        if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0x3ff);
+               xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
        else
-               xf_emit(ctx, 1, 0x7ff);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x102);
-       xf_emit(ctx, 9, 0);
-       xf_emit(ctx, 4, 4);
-       xf_emit(ctx, 0x2c, 0);
+               xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       /* SEEK */
+       xf_emit(ctx, 1, 0x102);         /* 0000ffff STRMOUT_BUFFER_CTRL */
+       xf_emit(ctx, 1, 0);             /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+       xf_emit(ctx, 4, 0);             /* 000000ff STRMOUT_ADDRESS_HIGH */
+       xf_emit(ctx, 4, 0);             /* ffffffff STRMOUT_ADDRESS_LOW */
+       xf_emit(ctx, 4, 4);             /* 000000ff STRMOUT_NUM_ATTRIBS */
+       if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 4, 0);     /* ffffffff UNK1A8C */
+               xf_emit(ctx, 4, 0);     /* ffffffff UNK1780 */
+       }
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_STRMOUT */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_QUERY */
+       xf_emit(ctx, 1, 0);             /* 000000ff QUERY_ADDRESS_HIGH */
+       xf_emit(ctx, 2, 0);             /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
+       xf_emit(ctx, 2, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       /* SEEK */
+       xf_emit(ctx, 0x20, 0);          /* ffffffff STRMOUT_MAP */
+       xf_emit(ctx, 1, 0);             /* 0000000f */
+       xf_emit(ctx, 1, 0);             /* 00000000? */
+       xf_emit(ctx, 2, 0);             /* ffffffff */
+}
+
+static void
+nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       xf_emit(ctx, 1, 0x4e3bfdf);     /* ffffffff UNK0D64 */
+       xf_emit(ctx, 1, 0x4e3bfdf);     /* ffffffff UNK0DF4 */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0);             /* 000003ff */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 0x11);  /* 000000ff tesla UNK1968 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_QUERY */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 2, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 000000ff QUERY_ADDRESS_HIGH */
+       xf_emit(ctx, 2, 0);             /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 7 */
+       /* SEEK */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_QUERY */
+       xf_emit(ctx, 1, 0);             /* 000000ff QUERY_ADDRESS_HIGH */
+       xf_emit(ctx, 2, 0);             /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+       xf_emit(ctx, 1, 0x4e3bfdf);     /* ffffffff UNK0D64 */
+       xf_emit(ctx, 1, 0x4e3bfdf);     /* ffffffff UNK0DF4 */
+       xf_emit(ctx, 1, 0);             /* 00000001 eng2d UNK260 */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 0x11);  /* 000000ff tesla UNK1968 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
 }
 
 static void
@@ -1749,443 +2392,709 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
        int magic2;
        if (dev_priv->chipset == 0x50) {
                magic2 = 0x00003e60;
-       } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+       } else if (!IS_NVA3F(dev_priv->chipset)) {
                magic2 = 0x001ffe67;
        } else {
                magic2 = 0x00087e67;
        }
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, magic2);
-       xf_emit(ctx, 4, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 7, 0);
-       if (dev_priv->chipset >= 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 0x15);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 4, 0);
+       xf_emit(ctx, 1, 0);             /* f/7 MUTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_BACK_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 2);             /* 00000003 tesla UNK143C */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, magic2);        /* 001fffff tesla UNK0F78 */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000007 DEPTH_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset))
+               xf_emit(ctx, 1, 0x15);  /* 000000ff */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 0x10);          /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);             /* ffffffff CLEAR_DEPTH */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
        if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
-               xf_emit(ctx, 1, 4);
-               xf_emit(ctx, 1, 0x400);
-               xf_emit(ctx, 1, 0x300);
-               xf_emit(ctx, 1, 0x1001);
+               xf_emit(ctx, 3, 0);     /* ff, ffffffff, ffffffff */
+               xf_emit(ctx, 1, 4);     /* 7 */
+               xf_emit(ctx, 1, 0x400); /* fffffff */
+               xf_emit(ctx, 1, 0x300); /* ffff */
+               xf_emit(ctx, 1, 0x1001);        /* 1fff */
                if (dev_priv->chipset != 0xa0) {
-                       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-                               xf_emit(ctx, 1, 0);
+                       if (IS_NVA3F(dev_priv->chipset))
+                               xf_emit(ctx, 1, 0);     /* 0000000f UNK15C8 */
                        else
-                               xf_emit(ctx, 1, 0x15);
+                               xf_emit(ctx, 1, 0x15);  /* ff */
                }
-               xf_emit(ctx, 3, 0);
        }
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x13, 0);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 0x10, 0);
-       xf_emit(ctx, 0x10, 0x3f800000);
-       xf_emit(ctx, 0x19, 0);
-       xf_emit(ctx, 1, 0x10);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x3f);
-       xf_emit(ctx, 6, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
+       xf_emit(ctx, 1, 0);             /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_BACK_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 2);             /* 00000003 tesla UNK143C */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000007 DEPTH_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 0x10);          /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1900 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_BACK_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_REF */
+       xf_emit(ctx, 2, 0);             /* ffffffff DEPTH_BOUNDS */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000007 DEPTH_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK0FB0 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_REF */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 0x10);          /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 0x10, 0);          /* ffffffff DEPTH_RANGE_NEAR */
+       xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 0);             /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_BACK_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_FUNC_REF */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 2, 0);             /* ffffffff DEPTH_BOUNDS */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000007 DEPTH_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 000000ff CLEAR_STENCIL */
+       xf_emit(ctx, 1, 0);             /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_FUNC_REF */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 1, 0x10);          /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 0x3f);          /* 0000003f UNK1590 */
+       xf_emit(ctx, 1, 0);             /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 2, 0);             /* ffff0ff3, ffff */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK0FB0 */
+       xf_emit(ctx, 1, 0);             /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff CLEAR_DEPTH */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK19CC */
        if (dev_priv->chipset >= 0xa0) {
                xf_emit(ctx, 2, 0);
                xf_emit(ctx, 1, 0x1001);
                xf_emit(ctx, 0xb, 0);
        } else {
-               xf_emit(ctx, 0xc, 0);
+               xf_emit(ctx, 1, 0);     /* 00000007 */
+               xf_emit(ctx, 1, 0);     /* 00000001 tesla UNK1534 */
+               xf_emit(ctx, 1, 0);     /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+               xf_emit(ctx, 8, 0);     /* 00000001 BLEND_ENABLE */
+               xf_emit(ctx, 1, 0);     /* ffff0ff3 */
        }
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x11);
-       if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 4, 0);
-       else
-               xf_emit(ctx, 6, 0);
-       xf_emit(ctx, 3, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, magic2);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 0x18, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 8, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 8, 1);
-               xf_emit(ctx, 3, 0);
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 5, 0);
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 0x16, 0);
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f */
+       xf_emit(ctx, 1, 0);             /* 00000001 LOGIC_OP_ENABLE */
+       if (dev_priv->chipset != 0x50) {
+               xf_emit(ctx, 1, 0);     /* 0000000f LOGIC_OP */
+               xf_emit(ctx, 1, 0);     /* 000000ff */
+       }
+       xf_emit(ctx, 1, 0);             /* 00000007 OPERATION */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 0);             /* 00000003 UNK0F90 */
+       xf_emit(ctx, 2, 1);             /* 00000007 BLEND_EQUATION_RGB, ALPHA */
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK133C */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_RGB */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_RGB */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_ALPHA */
+       xf_emit(ctx, 1, 0);             /* 00000001 */
+       xf_emit(ctx, 1, magic2);        /* 001fffff tesla UNK0F78 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 0);     /* 00000001 tesla UNK12E4 */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_RGB */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_ALPHA */
+               xf_emit(ctx, 8, 1);     /* 00000001 IBLEND_UNK00 */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_FUNC_SRC_RGB */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_FUNC_DST_RGB */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_FUNC_DST_ALPHA */
+               xf_emit(ctx, 1, 0);     /* 00000001 tesla UNK1140 */
+               xf_emit(ctx, 2, 0);     /* 00000001 */
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+               xf_emit(ctx, 1, 0);     /* 0000000f */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* ffffffff */
+               xf_emit(ctx, 2, 0);     /* 00000001 */
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+               xf_emit(ctx, 1, 0);     /* 00000001 */
+               xf_emit(ctx, 1, 0);     /* 000003ff */
+       } else if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 2, 0);     /* 00000001 */
+               xf_emit(ctx, 1, 0);     /* 00000007 */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* ffffffff */
+               xf_emit(ctx, 2, 0);     /* 00000001 */
        } else {
-               if (dev_priv->chipset >= 0xa0)
-                       xf_emit(ctx, 0x1b, 0);
-               else
-                       xf_emit(ctx, 0x15, 0);
+               xf_emit(ctx, 1, 0);     /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+               xf_emit(ctx, 1, 0);     /* 00000003 tesla UNK1430 */
+               xf_emit(ctx, 1, 0);     /* ffffffff tesla UNK1A3C */
        }
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 1);
+       xf_emit(ctx, 4, 0);             /* ffffffff CLEAR_COLOR */
+       xf_emit(ctx, 4, 0);             /* ffffffff BLEND_COLOR A R G B */
+       xf_emit(ctx, 1, 0);             /* 00000fff eng2d UNK2B0 */
        if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 4, 0);
-       else
-               xf_emit(ctx, 3, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 0x10, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 0x10, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 8, 1);
-               xf_emit(ctx, 3, 0);
+               xf_emit(ctx, 2, 0);     /* 00000001 */
+       xf_emit(ctx, 1, 0);             /* 000003ff */
+       xf_emit(ctx, 8, 0);             /* 00000001 BLEND_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK133C */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_RGB */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_RGB */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_RGB */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_ALPHA */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK19C0 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LOGIC_OP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f LOGIC_OP */
+       if (dev_priv->chipset >= 0xa0)
+               xf_emit(ctx, 1, 0);     /* 00000001 UNK12E4? NVA3+ only? */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 8, 1);     /* 00000001 IBLEND_UNK00 */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_RGB */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_FUNC_SRC_RGB */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_FUNC_DST_RGB */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_ALPHA */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_FUNC_DST_ALPHA */
+               xf_emit(ctx, 1, 0);     /* 00000001 tesla UNK15C4 */
+               xf_emit(ctx, 1, 0);     /* 00000001 */
+               xf_emit(ctx, 1, 0);     /* 00000001 tesla UNK1140 */
        }
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x5b, 0);
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       xf_emit(ctx, 1, 0);             /* 00000007 PATTERN_COLOR_FORMAT */
+       xf_emit(ctx, 2, 0);             /* ffffffff PATTERN_MONO_COLOR */
+       xf_emit(ctx, 1, 0);             /* 00000001 PATTERN_MONO_FORMAT */
+       xf_emit(ctx, 2, 0);             /* ffffffff PATTERN_MONO_BITMAP */
+       xf_emit(ctx, 1, 0);             /* 00000003 PATTERN_SELECT */
+       xf_emit(ctx, 1, 0);             /* 000000ff ROP */
+       xf_emit(ctx, 1, 0);             /* ffffffff BETA1 */
+       xf_emit(ctx, 1, 0);             /* ffffffff BETA4 */
+       xf_emit(ctx, 1, 0);             /* 00000007 OPERATION */
+       xf_emit(ctx, 0x50, 0);          /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x1(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
        int magic3;
-       if (dev_priv->chipset == 0x50)
+       switch (dev_priv->chipset) {
+       case 0x50:
                magic3 = 0x1000;
-       else if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8)
+               break;
+       case 0x86:
+       case 0x98:
+       case 0xa8:
+       case 0xaa:
+       case 0xac:
+       case 0xaf:
                magic3 = 0x1e00;
-       else
+               break;
+       default:
                magic3 = 0;
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 4);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0x24, 0);
+       }
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 111/113[NVA0+] */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0x1f, 0);  /* ffffffff */
        else if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 0x14, 0);
+               xf_emit(ctx, 0x0f, 0);  /* ffffffff */
        else
-               xf_emit(ctx, 0x15, 0);
-       xf_emit(ctx, 2, 4);
+               xf_emit(ctx, 0x10, 0);  /* fffffff VP_RESULT_MAP_1 up */
+       xf_emit(ctx, 2, 0);             /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_RESULT_MAP_SIZE */
        if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 1, 0x03020100);
+               xf_emit(ctx, 1, 0x03020100);    /* ffffffff */
        else
-               xf_emit(ctx, 1, 0x00608080);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 2, 4);
-       xf_emit(ctx, 1, 0x80);
+               xf_emit(ctx, 1, 0x00608080);    /* fffffff VP_RESULT_MAP_0 */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 2, 0);             /* 111/113, 7f/ff */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0x80);          /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
        if (magic3)
-               xf_emit(ctx, 1, magic3);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 0x24, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0x80);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0x03020100);
-       xf_emit(ctx, 1, 3);
+               xf_emit(ctx, 1, magic3);        /* 00007fff tesla UNK141C */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 111/113 */
+       xf_emit(ctx, 0x1f, 0);          /* ffffffff GP_RESULT_MAP_1 up */
+       xf_emit(ctx, 1, 0);             /* 0000001f */
+       xf_emit(ctx, 1, 0);             /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 0x80);          /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0x03020100);    /* ffffffff GP_RESULT_MAP_0 */
+       xf_emit(ctx, 1, 3);             /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
        if (magic3)
-               xf_emit(ctx, 1, magic3);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 4);
+               xf_emit(ctx, 1, magic3);        /* 7fff tesla UNK141C */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 0);             /* 00000001 PROVOKING_VERTEX_LAST */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 111/113 */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 3);             /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+       xf_emit(ctx, 1, 0);             /* 00000001 PROVOKING_VERTEX_LAST */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK13A0 */
+       xf_emit(ctx, 1, 4);             /* 7f/ff VP_REG_ALLOC_RESULT */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+       xf_emit(ctx, 1, 0);             /* 111/113 */
        if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
-               xf_emit(ctx, 0x1024, 0);
+               xf_emit(ctx, 0x1020, 0);        /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
        else if (dev_priv->chipset < 0xa0)
-               xf_emit(ctx, 0xa24, 0);
-       else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
-               xf_emit(ctx, 0x214, 0);
+               xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+       else if (!IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 0x210, 0); /* ffffffff */
        else
-               xf_emit(ctx, 0x414, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 2, 0);
+               xf_emit(ctx, 0x410, 0); /* ffffffff */
+       xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+       xf_emit(ctx, 1, 4);             /* 000000ff GP_RESULT_MAP_SIZE */
+       xf_emit(ctx, 1, 3);             /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+       xf_emit(ctx, 1, 0);             /* 00000001 PROVOKING_VERTEX_LAST */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
        int magic1, magic2;
        if (dev_priv->chipset == 0x50) {
                magic1 = 0x3ff;
                magic2 = 0x00003e60;
-       } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+       } else if (!IS_NVA3F(dev_priv->chipset)) {
                magic1 = 0x7ff;
                magic2 = 0x001ffe67;
        } else {
                magic1 = 0x7ff;
                magic2 = 0x00087e67;
        }
-       xf_emit(ctx, 3, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0xc, 0);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 0xb, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 4, 0xffff);
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 5, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 1, 3);
-               xf_emit(ctx, 1, 0);
-       } else if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0xa, 0);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 0x18, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 8, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 8, 1);
-               xf_emit(ctx, 1, 0);
+       xf_emit(ctx, 1, 0);             /* 00000007 ALPHA_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* ffffffff ALPHA_TEST_REF */
+       xf_emit(ctx, 1, 0);             /* 00000001 ALPHA_TEST_ENABLE */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000000f UNK16A0 */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_BACK_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 4, 0);             /* ffffffff BLEND_COLOR */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK19C0 */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK0FDC */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 LOGIC_OP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ff[NV50]/3ff[NV84+] */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 4, 0xffff);        /* 0000ffff MSAA_MASK */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 3, 0);             /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_BACK_ENABLE */
+       xf_emit(ctx, 2, 0);             /* 00007fff WINDOW_OFFSET_XY */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK19CC */
+       xf_emit(ctx, 1, 0);             /* 7 */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff COLOR_KEY */
+       xf_emit(ctx, 1, 0);             /* 00000001 COLOR_KEY_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 COLOR_KEY_FORMAT */
+       xf_emit(ctx, 2, 0);             /* ffffffff SIFC_BITMAP_COLOR */
+       xf_emit(ctx, 1, 1);             /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 ALPHA_TEST_FUNC */
+       xf_emit(ctx, 1, 0);             /* 00000001 ALPHA_TEST_ENABLE */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 3);     /* 00000003 tesla UNK16B4 */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* 00000003 tesla UNK1298 */
+       } else if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 1, 1);     /* 00000001 tesla UNK16B4 */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+       } else {
+               xf_emit(ctx, 1, 0);     /* 00000003 MULTISAMPLE_CTRL */
        }
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 3, 0xcf);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0xa, 0);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 8, 1);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, magic2);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x11);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 2, 1);
-       else
-               xf_emit(ctx, 1, 1);
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 8, 0);             /* 00000001 BLEND_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_ALPHA */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_RGB */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_RGB */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_RGB */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 0);     /* 00000001 UNK12E4 */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_RGB */
+               xf_emit(ctx, 8, 1);     /* 00000007 IBLEND_EQUATION_ALPHA */
+               xf_emit(ctx, 8, 1);     /* 00000001 IBLEND_UNK00 */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_SRC_RGB */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_DST_RGB */
+               xf_emit(ctx, 8, 2);     /* 0000001f IBLEND_SRC_ALPHA */
+               xf_emit(ctx, 8, 1);     /* 0000001f IBLEND_DST_ALPHA */
+               xf_emit(ctx, 1, 0);     /* 00000001 UNK1140 */
+       }
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK133C */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000001 LOGIC_OP_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000003 UNK0F90 */
+       xf_emit(ctx, 1, 0);             /* 00000001 FRAMEBUFFER_SRGB */
+       xf_emit(ctx, 1, 0);             /* 7 */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       xf_emit(ctx, 1, 0);             /* 00000007 OPERATION */
+       xf_emit(ctx, 1, 0xcf);          /* 000000ff SIFC_FORMAT */
+       xf_emit(ctx, 1, 0xcf);          /* 000000ff DRAW_COLOR_FORMAT */
+       xf_emit(ctx, 1, 0xcf);          /* 000000ff SRC_FORMAT */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       xf_emit(ctx, 1, 0);             /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 8, 0);             /* 00000001 BLEND_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_ALPHA */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_ALPHA */
+       xf_emit(ctx, 1, 1);             /* 0000001f BLEND_FUNC_DST_RGB */
+       xf_emit(ctx, 1, 1);             /* 00000007 BLEND_EQUATION_RGB */
+       xf_emit(ctx, 1, 2);             /* 0000001f BLEND_FUNC_SRC_RGB */
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK133C */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 8, 1);             /* 00000001 UNK19E0 */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, magic2);        /* 001fffff tesla UNK0F78 */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
        if(dev_priv->chipset == 0x50)
-               xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 1, 0);     /* ff */
        else
-               xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 5, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, magic1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 0x28, 0);
-       xf_emit(ctx, 8, 8);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 8, 0x400);
-       xf_emit(ctx, 8, 0x300);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x20);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 0x100);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x40);
-       xf_emit(ctx, 1, 0x100);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 4, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, magic2);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 9, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x400);
-       xf_emit(ctx, 1, 0x300);
-       xf_emit(ctx, 1, 0x1001);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 4, 0);
-       else
-               xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 1, 0xf);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 0x15, 0);
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 3, 0);
-       } else
-               xf_emit(ctx, 0x17, 0);
+               xf_emit(ctx, 3, 0);     /* 1, 7, 3ff */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000003 UNK0F90 */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_DU_DX_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff BLIT_DU_DX_INT */
+       xf_emit(ctx, 1, 0);             /* 000fffff BLIT_DV_DY_FRACT */
+       xf_emit(ctx, 1, 1);             /* 0001ffff BLIT_DV_DY_INT */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, magic1);        /* 3ff/7ff tesla UNK0D68 */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 8, 0);             /* 0000ffff DMA_COLOR */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_GLOBAL */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_LOCAL */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_STACK */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_DST */
+       xf_emit(ctx, 1, 0);             /* 7 */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 8, 0);             /* 000000ff RT_ADDRESS_HIGH */
+       xf_emit(ctx, 8, 0);             /* ffffffff RT_LAYER_STRIDE */
+       xf_emit(ctx, 8, 0);             /* ffffffff RT_ADDRESS_LOW */
+       xf_emit(ctx, 8, 8);             /* 0000007f RT_TILE_MODE */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 8, 0x400);         /* 0fffffff RT_HORIZ */
+       xf_emit(ctx, 8, 0x300);         /* 0000ffff RT_VERT */
+       xf_emit(ctx, 1, 1);             /* 00001fff RT_ARRAY_MODE */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, 0x20);          /* 00000fff DST_TILE_MODE */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 0x100);         /* 0001ffff DST_HEIGHT */
+       xf_emit(ctx, 1, 0);             /* 000007ff DST_LAYER */
+       xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
+       xf_emit(ctx, 1, 0);             /* ffffffff DST_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0);             /* 000000ff DST_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0x40);          /* 0007ffff DST_PITCH */
+       xf_emit(ctx, 1, 0x100);         /* 0001ffff DST_WIDTH */
+       xf_emit(ctx, 1, 0);             /* 0000ffff */
+       xf_emit(ctx, 1, 3);             /* 00000003 tesla UNK15AC */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 0);             /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0);             /* 00000003 UNK0F90 */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 1, magic2);        /* 001fffff tesla UNK0F78 */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 2);             /* 00000003 tesla UNK143C */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_ZETA */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 2, 0);             /* ffff, ff/3ff */
+       xf_emit(ctx, 1, 0);             /* 0001ffff GP_BUILTIN_RESULT_EN */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 000000ff STENCIL_FRONT_MASK */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0);             /* ffffffff ZETA_LAYER_STRIDE */
+       xf_emit(ctx, 1, 0);             /* 000000ff ZETA_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);             /* ffffffff ZETA_ADDRESS_LOW */
+       xf_emit(ctx, 1, 4);             /* 00000007 ZETA_TILE_MODE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       xf_emit(ctx, 1, 0x400);         /* 0fffffff ZETA_HORIZ */
+       xf_emit(ctx, 1, 0x300);         /* 0000ffff ZETA_VERT */
+       xf_emit(ctx, 1, 0x1001);        /* 00001fff ZETA_ARRAY_MODE */
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 0);     /* 00000001 */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 7, 0);             /* 3f/7f RT_FORMAT */
+       xf_emit(ctx, 1, 0x0fac6881);    /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0xf);           /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 7, 0);             /* 0000000f COLOR_MASK */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 8, 0);             /* 00000001 BLEND_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000003 UNK0F90 */
+       xf_emit(ctx, 1, 0);             /* 00000001 FRAMEBUFFER_SRGB */
+       xf_emit(ctx, 1, 0);             /* 7 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LOGIC_OP_ENABLE */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 0);     /* 00000001 UNK1140 */
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       }
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK1534 */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
        if (dev_priv->chipset >= 0xa0)
-               xf_emit(ctx, 1, 0x0fac6881);
-       xf_emit(ctx, 1, magic2);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 3, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 2, 1);
-       else
-               xf_emit(ctx, 1, 1);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 2, 0);
-       else if (dev_priv->chipset != 0x50)
-               xf_emit(ctx, 1, 0);
+               xf_emit(ctx, 1, 0x0fac6881);    /* fffffff */
+       xf_emit(ctx, 1, magic2);        /* 001fffff tesla UNK0F78 */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_BOUNDS_EN */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE_ENABLE */
+       xf_emit(ctx, 1, 0x11);          /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK0FB0 */
+       xf_emit(ctx, 1, 0);             /* ff/3ff */
+       xf_emit(ctx, 1, 4);             /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);             /* 00000001 STENCIL_FRONT_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK15B4 */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK19CC */
+       xf_emit(ctx, 1, 0);             /* 00000007 */
+       xf_emit(ctx, 1, 0);             /* 00000001 SAMPLECNT_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 0000000f ZETA_FORMAT */
+       xf_emit(ctx, 1, 1);             /* 00000001 ZETA_ENABLE */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+               xf_emit(ctx, 1, 0);     /* 0000000f tesla UNK15C8 */
+       }
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A3C */
+       if (dev_priv->chipset >= 0xa0) {
+               xf_emit(ctx, 3, 0);             /* 7/f, 1, ffff0ff3 */
+               xf_emit(ctx, 1, 0xfac6881);     /* fffffff */
+               xf_emit(ctx, 4, 0);             /* 1, 1, 1, 3ff */
+               xf_emit(ctx, 1, 4);             /* 7 */
+               xf_emit(ctx, 1, 0);             /* 1 */
+               xf_emit(ctx, 2, 1);             /* 1 */
+               xf_emit(ctx, 2, 0);             /* 7, f */
+               xf_emit(ctx, 1, 1);             /* 1 */
+               xf_emit(ctx, 1, 0);             /* 7/f */
+               if (IS_NVA3F(dev_priv->chipset))
+                       xf_emit(ctx, 0x9, 0);   /* 1 */
+               else
+                       xf_emit(ctx, 0x8, 0);   /* 1 */
+               xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+               xf_emit(ctx, 8, 1);             /* 1 */
+               xf_emit(ctx, 1, 0x11);          /* 7f */
+               xf_emit(ctx, 7, 0);             /* 7f */
+               xf_emit(ctx, 1, 0xfac6881);     /* fffffff */
+               xf_emit(ctx, 1, 0xf);           /* f */
+               xf_emit(ctx, 7, 0);             /* f */
+               xf_emit(ctx, 1, 0x11);          /* 7f */
+               xf_emit(ctx, 1, 1);             /* 1 */
+               xf_emit(ctx, 5, 0);             /* 1, 7, 3ff, 3, 7 */
+               if (IS_NVA3F(dev_priv->chipset)) {
+                       xf_emit(ctx, 1, 0);     /* 00000001 UNK1140 */
+                       xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+               }
+       }
 }
 
 static void
-nv50_graph_construct_xfer_tp_x3(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
+       xf_emit(ctx, 2, 0);             /* 1 LINKED_TSC. yes, 2. */
+       if (dev_priv->chipset != 0x50)
+               xf_emit(ctx, 1, 0);     /* 3 */
+       xf_emit(ctx, 1, 1);             /* 1ffff BLIT_DU_DX_INT */
+       xf_emit(ctx, 1, 0);             /* fffff BLIT_DU_DX_FRACT */
+       xf_emit(ctx, 1, 1);             /* 1ffff BLIT_DV_DY_INT */
+       xf_emit(ctx, 1, 0);             /* fffff BLIT_DV_DY_FRACT */
        if (dev_priv->chipset == 0x50)
-               xf_emit(ctx, 2, 0);
+               xf_emit(ctx, 1, 0);     /* 3 BLIT_CONTROL */
        else
-               xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0x2a712488);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x4085c000);
-       xf_emit(ctx, 1, 0x40);
-       xf_emit(ctx, 1, 0x100);
-       xf_emit(ctx, 1, 0x10100);
-       xf_emit(ctx, 1, 0x02800000);
+               xf_emit(ctx, 2, 0);     /* 3ff, 1 */
+       xf_emit(ctx, 1, 0x2a712488);    /* ffffffff SRC_TIC_0 */
+       xf_emit(ctx, 1, 0);             /* ffffffff SRC_TIC_1 */
+       xf_emit(ctx, 1, 0x4085c000);    /* ffffffff SRC_TIC_2 */
+       xf_emit(ctx, 1, 0x40);          /* ffffffff SRC_TIC_3 */
+       xf_emit(ctx, 1, 0x100);         /* ffffffff SRC_TIC_4 */
+       xf_emit(ctx, 1, 0x10100);       /* ffffffff SRC_TIC_5 */
+       xf_emit(ctx, 1, 0x02800000);    /* ffffffff SRC_TIC_6 */
+       xf_emit(ctx, 1, 0);             /* ffffffff SRC_TIC_7 */
+       if (dev_priv->chipset == 0x50) {
+               xf_emit(ctx, 1, 0);     /* 00000001 turing UNK358 */
+               xf_emit(ctx, 1, 0);     /* ffffffff tesla UNK1A34? */
+               xf_emit(ctx, 1, 0);     /* 00000003 turing UNK37C tesla UNK1690 */
+               xf_emit(ctx, 1, 0);     /* 00000003 BLIT_CONTROL */
+               xf_emit(ctx, 1, 0);     /* 00000001 turing UNK32C tesla UNK0F94 */
+       } else if (!IS_NVAAF(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 0);     /* ffffffff tesla UNK1A34? */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* 000003ff */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* 000003ff */
+               xf_emit(ctx, 1, 0);     /* 00000003 tesla UNK1664 / turing UNK03E8 */
+               xf_emit(ctx, 1, 0);     /* 00000003 */
+               xf_emit(ctx, 1, 0);     /* 000003ff */
+       } else {
+               xf_emit(ctx, 0x6, 0);
+       }
+       xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A34 */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_TEXTURE */
+       xf_emit(ctx, 1, 0);             /* 0000ffff DMA_SRC */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x4(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       xf_emit(ctx, 2, 0x04e3bfdf);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x00ffff00);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 2, 1);
-       else
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 0x00ffff00);
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0x30201000);
-       xf_emit(ctx, 1, 0x70605040);
-       xf_emit(ctx, 1, 0xb8a89888);
-       xf_emit(ctx, 1, 0xf8e8d8c8);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x1a);
-}
-
-static void
-nv50_graph_construct_xfer_tp_x5(struct nouveau_grctx *ctx)
-{
-       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 0xfac6881);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 2, 0);
-       xf_emit(ctx, 1, 1);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 0xb, 0);
-       else
-               xf_emit(ctx, 0xa, 0);
-       xf_emit(ctx, 8, 1);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0xfac6881);
-       xf_emit(ctx, 1, 0xf);
-       xf_emit(ctx, 7, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 1);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 6, 0);
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 6, 0);
-       } else {
-               xf_emit(ctx, 0xb, 0);
-       }
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 2, 0);             /* 7, ffff0ff3 */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE */
+       xf_emit(ctx, 1, 0x04e3bfdf);    /* ffffffff UNK0D64 */
+       xf_emit(ctx, 1, 0x04e3bfdf);    /* ffffffff UNK0DF4 */
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK15B4 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0x00ffff00);    /* 00ffffff LINE_STIPPLE_PATTERN */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK0F98 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK1668 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_STIPPLE_ENABLE */
+       xf_emit(ctx, 1, 0x00ffff00);    /* 00ffffff LINE_STIPPLE_PATTERN */
+       xf_emit(ctx, 1, 0);             /* 00000001 POLYGON_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 UNK1534 */
+       xf_emit(ctx, 1, 0);             /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 1, 0);             /* 00000001 tesla UNK1658 */
+       xf_emit(ctx, 1, 0);             /* 00000001 LINE_SMOOTH_ENABLE */
+       xf_emit(ctx, 1, 0);             /* ffff0ff3 */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);             /* 00000001 DEPTH_WRITE */
+       xf_emit(ctx, 1, 1);             /* 00000001 UNK15B4 */
+       xf_emit(ctx, 1, 0);             /* 00000001 POINT_SPRITE_ENABLE */
+       xf_emit(ctx, 1, 1);             /* 00000001 tesla UNK165C */
+       xf_emit(ctx, 1, 0x30201000);    /* ffffffff tesla UNK1670 */
+       xf_emit(ctx, 1, 0x70605040);    /* ffffffff tesla UNK1670 */
+       xf_emit(ctx, 1, 0xb8a89888);    /* ffffffff tesla UNK1670 */
+       xf_emit(ctx, 1, 0xf8e8d8c8);    /* ffffffff tesla UNK1670 */
+       xf_emit(ctx, 1, 0);             /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+       xf_emit(ctx, 1, 0x1a);          /* 0000001f POLYGON_MODE */
 }
 
 static void
@@ -2193,108 +3102,136 @@ nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
        if (dev_priv->chipset < 0xa0) {
-               nv50_graph_construct_xfer_tp_x1(ctx);
-               nv50_graph_construct_xfer_tp_x2(ctx);
-               nv50_graph_construct_xfer_tp_x3(ctx);
-               if (dev_priv->chipset == 0x50)
-                       xf_emit(ctx, 0xf, 0);
-               else
-                       xf_emit(ctx, 0x12, 0);
-               nv50_graph_construct_xfer_tp_x4(ctx);
+               nv50_graph_construct_xfer_unk84xx(ctx);
+               nv50_graph_construct_xfer_tprop(ctx);
+               nv50_graph_construct_xfer_tex(ctx);
+               nv50_graph_construct_xfer_unk8cxx(ctx);
        } else {
-               nv50_graph_construct_xfer_tp_x3(ctx);
-               if (dev_priv->chipset < 0xaa)
-                       xf_emit(ctx, 0xc, 0);
-               else
-                       xf_emit(ctx, 0xa, 0);
-               nv50_graph_construct_xfer_tp_x2(ctx);
-               nv50_graph_construct_xfer_tp_x5(ctx);
-               nv50_graph_construct_xfer_tp_x4(ctx);
-               nv50_graph_construct_xfer_tp_x1(ctx);
+               nv50_graph_construct_xfer_tex(ctx);
+               nv50_graph_construct_xfer_tprop(ctx);
+               nv50_graph_construct_xfer_unk8cxx(ctx);
+               nv50_graph_construct_xfer_unk84xx(ctx);
        }
 }
 
 static void
-nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
 {
        struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-       int i, mpcnt;
-       if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
-               mpcnt = 1;
-       else if (dev_priv->chipset < 0xa0 || dev_priv->chipset >= 0xa8)
-               mpcnt = 2;
-       else
-               mpcnt = 3;
+       int i, mpcnt = 2;
+       switch (dev_priv->chipset) {
+               case 0x98:
+               case 0xaa:
+                       mpcnt = 1;
+                       break;
+               case 0x50:
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0xa8:
+               case 0xac:
+                       mpcnt = 2;
+                       break;
+               case 0xa0:
+               case 0xa3:
+               case 0xa5:
+               case 0xaf:
+                       mpcnt = 3;
+                       break;
+       }
        for (i = 0; i < mpcnt; i++) {
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 1, 0x80);
-               xf_emit(ctx, 1, 0x80007004);
-               xf_emit(ctx, 1, 0x04000400);
+               xf_emit(ctx, 1, 0);             /* ff */
+               xf_emit(ctx, 1, 0x80);          /* ffffffff tesla UNK1404 */
+               xf_emit(ctx, 1, 0x80007004);    /* ffffffff tesla UNK12B0 */
+               xf_emit(ctx, 1, 0x04000400);    /* ffffffff */
                if (dev_priv->chipset >= 0xa0)
-                       xf_emit(ctx, 1, 0xc0);
-               xf_emit(ctx, 1, 0x1000);
-               xf_emit(ctx, 2, 0);
-               if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) {
-                       xf_emit(ctx, 1, 0xe00);
-                       xf_emit(ctx, 1, 0x1e00);
+                       xf_emit(ctx, 1, 0xc0);  /* 00007fff tesla UNK152C */
+               xf_emit(ctx, 1, 0x1000);        /* 0000ffff tesla UNK0D60 */
+               xf_emit(ctx, 1, 0);             /* ff/3ff */
+               xf_emit(ctx, 1, 0);             /* ffffffff tesla UNK1A30 */
+               if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) {
+                       xf_emit(ctx, 1, 0xe00);         /* 7fff */
+                       xf_emit(ctx, 1, 0x1e00);        /* 7fff */
                }
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 2, 0);
+               xf_emit(ctx, 1, 1);             /* 000000ff VP_REG_ALLOC_TEMP */
+               xf_emit(ctx, 1, 0);             /* 00000001 LINKED_TSC */
+               xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
                if (dev_priv->chipset == 0x50)
-                       xf_emit(ctx, 2, 0x1000);
-               xf_emit(ctx, 1, 1);
-               xf_emit(ctx, 1, 0);
-               xf_emit(ctx, 1, 4);
-               xf_emit(ctx, 1, 2);
-               if (dev_priv->chipset >= 0xaa)
-                       xf_emit(ctx, 0xb, 0);
+                       xf_emit(ctx, 2, 0x1000);        /* 7fff tesla UNK141C */
+               xf_emit(ctx, 1, 1);             /* 000000ff GP_REG_ALLOC_TEMP */
+               xf_emit(ctx, 1, 0);             /* 00000001 GP_ENABLE */
+               xf_emit(ctx, 1, 4);             /* 000000ff FP_REG_ALLOC_TEMP */
+               xf_emit(ctx, 1, 2);             /* 00000003 REG_MODE */
+               if (IS_NVAAF(dev_priv->chipset))
+                       xf_emit(ctx, 0xb, 0);   /* RO */
                else if (dev_priv->chipset >= 0xa0)
-                       xf_emit(ctx, 0xc, 0);
+                       xf_emit(ctx, 0xc, 0);   /* RO */
                else
-                       xf_emit(ctx, 0xa, 0);
+                       xf_emit(ctx, 0xa, 0);   /* RO */
        }
-       xf_emit(ctx, 1, 0x08100c12);
-       xf_emit(ctx, 1, 0);
+       xf_emit(ctx, 1, 0x08100c12);            /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 0);                     /* ff/3ff */
        if (dev_priv->chipset >= 0xa0) {
-               xf_emit(ctx, 1, 0x1fe21);
+               xf_emit(ctx, 1, 0x1fe21);       /* 0003ffff tesla UNK0FAC */
        }
-       xf_emit(ctx, 5, 0);
-       xf_emit(ctx, 4, 0xffff);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 2, 0x10001);
-       xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 0x1fe21);
-       xf_emit(ctx, 1, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 1);
-       xf_emit(ctx, 4, 0);
-       xf_emit(ctx, 1, 0x08100c12);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 8, 0);
-       xf_emit(ctx, 1, 0xfac6881);
-       xf_emit(ctx, 1, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-               xf_emit(ctx, 1, 3);
-       xf_emit(ctx, 3, 0);
-       xf_emit(ctx, 1, 4);
-       xf_emit(ctx, 9, 0);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 2, 1);
-       xf_emit(ctx, 1, 2);
-       xf_emit(ctx, 3, 1);
-       xf_emit(ctx, 1, 0);
-       if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 0x10, 1);
-               xf_emit(ctx, 8, 2);
-               xf_emit(ctx, 0x18, 1);
-               xf_emit(ctx, 3, 0);
+       xf_emit(ctx, 3, 0);                     /* 7fff, 0, 0 */
+       xf_emit(ctx, 1, 0);                     /* 00000001 tesla UNK1534 */
+       xf_emit(ctx, 1, 0);                     /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+       xf_emit(ctx, 4, 0xffff);                /* 0000ffff MSAA_MASK */
+       xf_emit(ctx, 1, 1);                     /* 00000001 LANES32 */
+       xf_emit(ctx, 1, 0x10001);               /* 00ffffff BLOCK_ALLOC */
+       xf_emit(ctx, 1, 0x10001);               /* ffffffff BLOCKDIM_XY */
+       xf_emit(ctx, 1, 1);                     /* 0000ffff BLOCKDIM_Z */
+       xf_emit(ctx, 1, 0);                     /* ffffffff SHARED_SIZE */
+       xf_emit(ctx, 1, 0x1fe21);               /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
+       xf_emit(ctx, 1, 0);                     /* ffffffff tesla UNK1A34 */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 1);             /* 0000001f tesla UNK169C */
+       xf_emit(ctx, 1, 0);                     /* ff/3ff */
+       xf_emit(ctx, 1, 0);                     /* 1 LINKED_TSC */
+       xf_emit(ctx, 1, 0);                     /* ff FP_ADDRESS_HIGH */
+       xf_emit(ctx, 1, 0);                     /* ffffffff FP_ADDRESS_LOW */
+       xf_emit(ctx, 1, 0x08100c12);            /* 1fffffff FP_INTERPOLANT_CTRL */
+       xf_emit(ctx, 1, 4);                     /* 00000007 FP_CONTROL */
+       xf_emit(ctx, 1, 0);                     /* 000000ff FRAG_COLOR_CLAMP_EN */
+       xf_emit(ctx, 1, 2);                     /* 00000003 REG_MODE */
+       xf_emit(ctx, 1, 0x11);                  /* 0000007f RT_FORMAT */
+       xf_emit(ctx, 7, 0);                     /* 0000007f RT_FORMAT */
+       xf_emit(ctx, 1, 0);                     /* 00000007 */
+       xf_emit(ctx, 1, 0xfac6881);             /* 0fffffff RT_CONTROL */
+       xf_emit(ctx, 1, 0);                     /* 00000003 MULTISAMPLE_CTRL */
+       if (IS_NVA3F(dev_priv->chipset))
+               xf_emit(ctx, 1, 3);             /* 00000003 tesla UNK16B4 */
+       xf_emit(ctx, 1, 0);                     /* 00000001 ALPHA_TEST_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 00000007 ALPHA_TEST_FUNC */
+       xf_emit(ctx, 1, 0);                     /* 00000001 FRAMEBUFFER_SRGB */
+       xf_emit(ctx, 1, 4);                     /* ffffffff tesla UNK1400 */
+       xf_emit(ctx, 8, 0);                     /* 00000001 BLEND_ENABLE */
+       xf_emit(ctx, 1, 0);                     /* 00000001 LOGIC_OP_ENABLE */
+       xf_emit(ctx, 1, 2);                     /* 0000001f BLEND_FUNC_SRC_RGB */
+       xf_emit(ctx, 1, 1);                     /* 0000001f BLEND_FUNC_DST_RGB */
+       xf_emit(ctx, 1, 1);                     /* 00000007 BLEND_EQUATION_RGB */
+       xf_emit(ctx, 1, 2);                     /* 0000001f BLEND_FUNC_SRC_ALPHA */
+       xf_emit(ctx, 1, 1);                     /* 0000001f BLEND_FUNC_DST_ALPHA */
+       xf_emit(ctx, 1, 1);                     /* 00000007 BLEND_EQUATION_ALPHA */
+       xf_emit(ctx, 1, 1);                     /* 00000001 UNK133C */
+       if (IS_NVA3F(dev_priv->chipset)) {
+               xf_emit(ctx, 1, 0);             /* 00000001 UNK12E4 */
+               xf_emit(ctx, 8, 2);             /* 0000001f IBLEND_FUNC_SRC_RGB */
+               xf_emit(ctx, 8, 1);             /* 0000001f IBLEND_FUNC_DST_RGB */
+               xf_emit(ctx, 8, 1);             /* 00000007 IBLEND_EQUATION_RGB */
+               xf_emit(ctx, 8, 2);             /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+               xf_emit(ctx, 8, 1);             /* 0000001f IBLEND_FUNC_DST_ALPHA */
+               xf_emit(ctx, 8, 1);             /* 00000007 IBLEND_EQUATION_ALPHA */
+               xf_emit(ctx, 8, 1);             /* 00000001 IBLEND_UNK00 */
+               xf_emit(ctx, 1, 0);             /* 00000003 tesla UNK1928 */
+               xf_emit(ctx, 1, 0);             /* 00000001 UNK1140 */
        }
-       xf_emit(ctx, 1, 4);
+       xf_emit(ctx, 1, 0);                     /* 00000003 tesla UNK0F90 */
+       xf_emit(ctx, 1, 4);                     /* 000000ff FP_RESULT_COUNT */
+       /* XXX: demagic this part some day */
        if (dev_priv->chipset == 0x50)
                xf_emit(ctx, 0x3a0, 0);
        else if (dev_priv->chipset < 0x94)
@@ -2303,9 +3240,9 @@ nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
                xf_emit(ctx, 0x39f, 0);
        else
                xf_emit(ctx, 0x3a3, 0);
-       xf_emit(ctx, 1, 0x11);
-       xf_emit(ctx, 1, 0);
-       xf_emit(ctx, 1, 1);
+       xf_emit(ctx, 1, 0x11);                  /* 3f/7f DST_FORMAT */
+       xf_emit(ctx, 1, 0);                     /* 7 OPERATION */
+       xf_emit(ctx, 1, 1);                     /* 1 DST_LINEAR */
        xf_emit(ctx, 0x2d, 0);
 }
 
@@ -2323,52 +3260,56 @@ nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
        if (dev_priv->chipset < 0xa0) {
                for (i = 0; i < 8; i++) {
                        ctx->ctxvals_pos = offset + i;
+                       /* that little bugger belongs to csched. No idea
+                        * what it's doing here. */
                        if (i == 0)
-                               xf_emit(ctx, 1, 0x08100c12);
+                               xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
                        if (units & (1 << i))
-                               nv50_graph_construct_xfer_tp2(ctx);
+                               nv50_graph_construct_xfer_mpc(ctx);
                        if ((ctx->ctxvals_pos-offset)/8 > size)
                                size = (ctx->ctxvals_pos-offset)/8;
                }
        } else {
                /* Strand 0: TPs 0, 1 */
                ctx->ctxvals_pos = offset;
-               xf_emit(ctx, 1, 0x08100c12);
+               /* that little bugger belongs to csched. No idea
+                * what it's doing here. */
+               xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
                if (units & (1 << 0))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 1))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
-               /* Strand 0: TPs 2, 3 */
+               /* Strand 1: TPs 2, 3 */
                ctx->ctxvals_pos = offset + 1;
                if (units & (1 << 2))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 3))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
-               /* Strand 0: TPs 4, 5, 6 */
+               /* Strand 2: TPs 4, 5, 6 */
                ctx->ctxvals_pos = offset + 2;
                if (units & (1 << 4))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 5))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 6))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
 
-               /* Strand 0: TPs 7, 8, 9 */
+               /* Strand 3: TPs 7, 8, 9 */
                ctx->ctxvals_pos = offset + 3;
                if (units & (1 << 7))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 8))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if (units & (1 << 9))
-                       nv50_graph_construct_xfer_tp2(ctx);
+                       nv50_graph_construct_xfer_mpc(ctx);
                if ((ctx->ctxvals_pos-offset)/8 > size)
                        size = (ctx->ctxvals_pos-offset)/8;
        }
index 91ef93cf1f352f89553b7dab4ab9fb4f219326ad..a53fc974332b38ec659513e91a8421017e43c411 100644 (file)
 struct nv50_instmem_priv {
        uint32_t save1700[5]; /* 0x1700->0x1710 */
 
-       struct nouveau_gpuobj_ref *pramin_pt;
-       struct nouveau_gpuobj_ref *pramin_bar;
-       struct nouveau_gpuobj_ref *fb_bar;
+       struct nouveau_gpuobj *pramin_pt;
+       struct nouveau_gpuobj *pramin_bar;
+       struct nouveau_gpuobj *fb_bar;
 };
 
-#define NV50_INSTMEM_PAGE_SHIFT 12
-#define NV50_INSTMEM_PAGE_SIZE  (1 << NV50_INSTMEM_PAGE_SHIFT)
-#define NV50_INSTMEM_PT_SIZE(a)        (((a) >> 12) << 3)
+static void
+nv50_channel_del(struct nouveau_channel **pchan)
+{
+       struct nouveau_channel *chan;
 
-/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN
- */
-#define BAR0_WI32(g, o, v) do {                                   \
-       uint32_t offset;                                          \
-       if ((g)->im_backing) {                                    \
-               offset = (g)->im_backing_start;                   \
-       } else {                                                  \
-               offset  = chan->ramin->gpuobj->im_backing_start;  \
-               offset += (g)->im_pramin->start;                  \
-       }                                                         \
-       offset += (o);                                            \
-       nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v));              \
-} while (0)
+       chan = *pchan;
+       *pchan = NULL;
+       if (!chan)
+               return;
+
+       nouveau_gpuobj_ref(NULL, &chan->ramfc);
+       nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+       if (chan->ramin_heap.free_stack.next)
+               drm_mm_takedown(&chan->ramin_heap);
+       nouveau_gpuobj_ref(NULL, &chan->ramin);
+       kfree(chan);
+}
+
+static int
+nv50_channel_new(struct drm_device *dev, u32 size,
+                struct nouveau_channel **pchan)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+       u32  fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200;
+       struct nouveau_channel *chan;
+       int ret;
+
+       chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+       chan->dev = dev;
+
+       ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
+       if (ret) {
+               nv50_channel_del(&chan);
+               return ret;
+       }
+
+       ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size);
+       if (ret) {
+               nv50_channel_del(&chan);
+               return ret;
+       }
+
+       ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+                                     chan->ramin->pinst + pgd,
+                                     chan->ramin->vinst + pgd,
+                                     0x4000, NVOBJ_FLAG_ZERO_ALLOC,
+                                     &chan->vm_pd);
+       if (ret) {
+               nv50_channel_del(&chan);
+               return ret;
+       }
+
+       ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+                                     chan->ramin->pinst + fc,
+                                     chan->ramin->vinst + fc, 0x100,
+                                     NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc);
+       if (ret) {
+               nv50_channel_del(&chan);
+               return ret;
+       }
+
+       *pchan = chan;
+       return 0;
+}
 
 int
 nv50_instmem_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
-       uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size;
-       uint32_t save_nv001700;
-       uint64_t v;
        struct nv50_instmem_priv *priv;
+       struct nouveau_channel *chan;
        int ret, i;
+       u32 tmp;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -75,212 +123,115 @@ nv50_instmem_init(struct drm_device *dev)
        for (i = 0x1700; i <= 0x1710; i += 4)
                priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
 
-       /* Reserve the last MiB of VRAM, we should probably try to avoid
-        * setting up the below tables over the top of the VBIOS image at
-        * some point.
-        */
-       dev_priv->ramin_rsvd_vram = 1 << 20;
-       c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
-       c_size   = 128 << 10;
-       c_vmpd   = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
-       c_ramfc  = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
-       c_base   = c_vmpd + 0x4000;
-       pt_size  = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size);
-
-       NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset);
-       NV_DEBUG(dev, "    VBIOS image: 0x%08x\n",
-                               (nv_rd32(dev, 0x619f04) & ~0xff) << 8);
-       NV_DEBUG(dev, "  Aperture size: %d MiB\n", dev_priv->ramin_size >> 20);
-       NV_DEBUG(dev, "        PT size: %d KiB\n", pt_size >> 10);
-
-       /* Determine VM layout, we need to do this first to make sure
-        * we allocate enough memory for all the page tables.
-        */
-       dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
-       dev_priv->vm_gart_size = NV50_VM_BLOCK;
-
-       dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
-       dev_priv->vm_vram_size = dev_priv->vram_size;
-       if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
-               dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
-       dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
-       dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
-
-       dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
-
-       NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
-                dev_priv->vm_gart_base,
-                dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
-       NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
-                dev_priv->vm_vram_base,
-                dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
-
-       c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8);
-
-       /* Map BAR0 PRAMIN aperture over the memory we want to use */
-       save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN);
-       nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16));
-
-       /* Create a fake channel, and use it as our "dummy" channels 0/127.
-        * The main reason for creating a channel is so we can use the gpuobj
-        * code.  However, it's probably worth noting that NVIDIA also setup
-        * their channels 0/127 with the same values they configure here.
-        * So, there may be some other reason for doing this.
-        *
-        * Have to create the entire channel manually, as the real channel
-        * creation code assumes we have PRAMIN access, and we don't until
-        * we're done here.
-        */
-       chan = kzalloc(sizeof(*chan), GFP_KERNEL);
-       if (!chan)
+       /* Global PRAMIN heap */
+       ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size);
+       if (ret) {
+               NV_ERROR(dev, "Failed to init RAMIN heap\n");
                return -ENOMEM;
-       chan->id = 0;
-       chan->dev = dev;
-       chan->file_priv = (struct drm_file *)-2;
-       dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
-
-       INIT_LIST_HEAD(&chan->ramht_refs);
+       }
 
-       /* Channel's PRAMIN object + heap */
-       ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
-                                                       NULL, &chan->ramin);
+       /* we need a channel to plug into the hw to control the BARs */
+       ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]);
        if (ret)
                return ret;
+       chan = dev_priv->fifos[127] = dev_priv->fifos[0];
 
-       if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
-               return -ENOMEM;
-
-       /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
-       ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc,
-                                               0x4000, 0, NULL, &chan->ramfc);
+       /* allocate page table for PRAMIN BAR */
+       ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8,
+                                0x1000, NVOBJ_FLAG_ZERO_ALLOC,
+                                &priv->pramin_pt);
        if (ret)
                return ret;
 
-       for (i = 0; i < c_vmpd; i += 4)
-               BAR0_WI32(chan->ramin->gpuobj, i, 0);
+       nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63);
+       nv_wo32(chan->vm_pd, 0x0004, 0);
 
-       /* VM page directory */
-       ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd,
-                                          0x4000, 0, &chan->vm_pd, NULL);
+       /* DMA object for PRAMIN BAR */
+       ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar);
        if (ret)
                return ret;
-       for (i = 0; i < 0x4000; i += 8) {
-               BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000);
-               BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000);
-       }
-
-       /* PRAMIN page table, cheat and map into VM at 0x0000000000.
-        * We map the entire fake channel into the start of the PRAMIN BAR
-        */
-       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
-                                    0, &priv->pramin_pt);
+       nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000);
+       nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1);
+       nv_wo32(priv->pramin_bar, 0x08, 0x00000000);
+       nv_wo32(priv->pramin_bar, 0x0c, 0x00000000);
+       nv_wo32(priv->pramin_bar, 0x10, 0x00000000);
+       nv_wo32(priv->pramin_bar, 0x14, 0x00000000);
+
+       /* map channel into PRAMIN, gpuobj didn't do it for us */
+       ret = nv50_instmem_bind(dev, chan->ramin);
        if (ret)
                return ret;
 
-       v = c_offset | 1;
-       if (dev_priv->vram_sys_base) {
-               v += dev_priv->vram_sys_base;
-               v |= 0x30;
-       }
+       /* poke regs... */
+       nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12));
+       nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
+       nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4));
 
-       i = 0;
-       while (v < dev_priv->vram_sys_base + c_offset + c_size) {
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v));
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v));
-               v += 0x1000;
-               i += 8;
+       tmp = nv_ri32(dev, 0);
+       nv_wi32(dev, 0, ~tmp);
+       if (nv_ri32(dev, 0) != ~tmp) {
+               NV_ERROR(dev, "PRAMIN readback failed\n");
+               return -EIO;
        }
+       nv_wi32(dev, 0, tmp);
 
-       while (i < pt_size) {
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
-               i += 8;
-       }
+       dev_priv->ramin_available = true;
 
-       BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
-       BAR0_WI32(chan->vm_pd, 0x04, 0x00000000);
+       /* Determine VM layout */
+       dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
+       dev_priv->vm_gart_size = NV50_VM_BLOCK;
+
+       dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
+       dev_priv->vm_vram_size = dev_priv->vram_size;
+       if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
+               dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
+       dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
+       dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
+
+       dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
+
+       NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
+                dev_priv->vm_gart_base,
+                dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
+       NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
+                dev_priv->vm_vram_base,
+                dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
 
        /* VRAM page table(s), mapped into VM at +1GiB  */
        for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-               ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0,
-                                            NV50_VM_BLOCK/65536*8, 0, 0,
-                                            &chan->vm_vram_pt[i]);
+               ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8,
+                                        0, NVOBJ_FLAG_ZERO_ALLOC,
+                                        &chan->vm_vram_pt[i]);
                if (ret) {
-                       NV_ERROR(dev, "Error creating VRAM page tables: %d\n",
-                                                                       ret);
+                       NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret);
                        dev_priv->vm_vram_pt_nr = i;
                        return ret;
                }
-               dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj;
+               dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i];
 
-               for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size;
-                                                               v += 4)
-                       BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0);
-
-               BAR0_WI32(chan->vm_pd, 0x10 + (i*8),
-                         chan->vm_vram_pt[i]->instance | 0x61);
-               BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0);
+               nv_wo32(chan->vm_pd, 0x10 + (i*8),
+                       chan->vm_vram_pt[i]->vinst | 0x61);
+               nv_wo32(chan->vm_pd, 0x14 + (i*8), 0);
        }
 
-       /* DMA object for PRAMIN BAR */
-       ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
-                                                       &priv->pramin_bar);
-       if (ret)
-               return ret;
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000);
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1);
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000);
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000);
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000);
-       BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000);
-
        /* DMA object for FB BAR */
-       ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
-                                                       &priv->fb_bar);
+       ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar);
        if (ret)
                return ret;
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
-                                             pci_resource_len(dev->pdev, 1) - 1);
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
-       BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000);
+       nv_wo32(priv->fb_bar, 0x00, 0x7fc00000);
+       nv_wo32(priv->fb_bar, 0x04, 0x40000000 +
+                                   pci_resource_len(dev->pdev, 1) - 1);
+       nv_wo32(priv->fb_bar, 0x08, 0x40000000);
+       nv_wo32(priv->fb_bar, 0x0c, 0x00000000);
+       nv_wo32(priv->fb_bar, 0x10, 0x00000000);
+       nv_wo32(priv->fb_bar, 0x14, 0x00000000);
 
-       /* Poke the relevant regs, and pray it works :) */
-       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
-       nv_wr32(dev, NV50_PUNK_UNK1710, 0);
-       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
-                                        NV50_PUNK_BAR_CFG_BASE_VALID);
-       nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
-                                       NV50_PUNK_BAR1_CTXDMA_VALID);
-       nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
-                                       NV50_PUNK_BAR3_CTXDMA_VALID);
+       dev_priv->engine.instmem.flush(dev);
 
+       nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4));
        for (i = 0; i < 8; i++)
                nv_wr32(dev, 0x1900 + (i*4), 0);
 
-       /* Assume that praying isn't enough, check that we can re-read the
-        * entire fake channel back from the PRAMIN BAR */
-       for (i = 0; i < c_size; i += 4) {
-               if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
-                       NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
-                                                                       i);
-                       return -EINVAL;
-               }
-       }
-
-       nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
-
-       /* Global PRAMIN heap */
-       if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
-               NV_ERROR(dev, "Failed to init RAMIN heap\n");
-       }
-
-       /*XXX: incorrect, but needed to make hash func "work" */
-       dev_priv->ramht_offset = 0x10000;
-       dev_priv->ramht_bits   = 9;
-       dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
        return 0;
 }
 
@@ -297,29 +248,24 @@ nv50_instmem_takedown(struct drm_device *dev)
        if (!priv)
                return;
 
+       dev_priv->ramin_available = false;
+
        /* Restore state from before init */
        for (i = 0x1700; i <= 0x1710; i += 4)
                nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]);
 
-       nouveau_gpuobj_ref_del(dev, &priv->fb_bar);
-       nouveau_gpuobj_ref_del(dev, &priv->pramin_bar);
-       nouveau_gpuobj_ref_del(dev, &priv->pramin_pt);
+       nouveau_gpuobj_ref(NULL, &priv->fb_bar);
+       nouveau_gpuobj_ref(NULL, &priv->pramin_bar);
+       nouveau_gpuobj_ref(NULL, &priv->pramin_pt);
 
        /* Destroy dummy channel */
        if (chan) {
-               for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-                       nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
-                       dev_priv->vm_vram_pt[i] = NULL;
-               }
+               for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
+                       nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
                dev_priv->vm_vram_pt_nr = 0;
 
-               nouveau_gpuobj_del(dev, &chan->vm_pd);
-               nouveau_gpuobj_ref_del(dev, &chan->ramfc);
-               nouveau_gpuobj_ref_del(dev, &chan->ramin);
-               drm_mm_takedown(&chan->ramin_heap);
-
-               dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
-               kfree(chan);
+               nv50_channel_del(&dev_priv->fifos[0]);
+               dev_priv->fifos[127] = NULL;
        }
 
        dev_priv->engine.instmem.priv = NULL;
@@ -331,14 +277,14 @@ nv50_instmem_suspend(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_channel *chan = dev_priv->fifos[0];
-       struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+       struct nouveau_gpuobj *ramin = chan->ramin;
        int i;
 
-       ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size);
+       ramin->im_backing_suspend = vmalloc(ramin->size);
        if (!ramin->im_backing_suspend)
                return -ENOMEM;
 
-       for (i = 0; i < ramin->im_pramin->size; i += 4)
+       for (i = 0; i < ramin->size; i += 4)
                ramin->im_backing_suspend[i/4] = nv_ri32(dev, i);
        return 0;
 }
@@ -349,23 +295,25 @@ nv50_instmem_resume(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
        struct nouveau_channel *chan = dev_priv->fifos[0];
-       struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+       struct nouveau_gpuobj *ramin = chan->ramin;
        int i;
 
-       nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16));
-       for (i = 0; i < ramin->im_pramin->size; i += 4)
-               BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]);
+       dev_priv->ramin_available = false;
+       dev_priv->ramin_base = ~0;
+       for (i = 0; i < ramin->size; i += 4)
+               nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]);
+       dev_priv->ramin_available = true;
        vfree(ramin->im_backing_suspend);
        ramin->im_backing_suspend = NULL;
 
        /* Poke the relevant regs, and pray it works :) */
-       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
+       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12));
        nv_wr32(dev, NV50_PUNK_UNK1710, 0);
-       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
+       nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) |
                                         NV50_PUNK_BAR_CFG_BASE_VALID);
-       nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
+       nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) |
                                        NV50_PUNK_BAR1_CTXDMA_VALID);
-       nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
+       nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) |
                                        NV50_PUNK_BAR3_CTXDMA_VALID);
 
        for (i = 0; i < 8; i++)
@@ -381,7 +329,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
        if (gpuobj->im_backing)
                return -EINVAL;
 
-       *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
+       *sz = ALIGN(*sz, 4096);
        if (*sz == 0)
                return -EINVAL;
 
@@ -399,9 +347,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
                return ret;
        }
 
-       gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
-       gpuobj->im_backing_start <<= PAGE_SHIFT;
-
+       gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
        return 0;
 }
 
@@ -424,7 +370,7 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
-       struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
+       struct nouveau_gpuobj *pramin_pt = priv->pramin_pt;
        uint32_t pte, pte_end;
        uint64_t vram;
 
@@ -436,11 +382,11 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 
        pte     = (gpuobj->im_pramin->start >> 12) << 1;
        pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
-       vram    = gpuobj->im_backing_start;
+       vram    = gpuobj->vinst;
 
        NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
                 gpuobj->im_pramin->start, pte, pte_end);
-       NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+       NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
 
        vram |= 1;
        if (dev_priv->vram_sys_base) {
@@ -449,9 +395,10 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        }
 
        while (pte < pte_end) {
-               nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
-               nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
-               vram += NV50_INSTMEM_PAGE_SIZE;
+               nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
+               nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
+               vram += 0x1000;
+               pte += 2;
        }
        dev_priv->engine.instmem.flush(dev);
 
@@ -472,12 +419,17 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        if (gpuobj->im_bound == 0)
                return -EINVAL;
 
+       /* can happen during late takedown */
+       if (unlikely(!dev_priv->ramin_available))
+               return 0;
+
        pte     = (gpuobj->im_pramin->start >> 12) << 1;
        pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
 
        while (pte < pte_end) {
-               nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
-               nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
+               nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000);
+               nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000);
+               pte += 2;
        }
        dev_priv->engine.instmem.flush(dev);
 
@@ -489,7 +441,7 @@ void
 nv50_instmem_flush(struct drm_device *dev)
 {
        nv_wr32(dev, 0x00330c, 0x00000001);
-       if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
+       if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -497,7 +449,7 @@ void
 nv84_instmem_flush(struct drm_device *dev)
 {
        nv_wr32(dev, 0x070000, 0x00000001);
-       if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+       if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -505,7 +457,7 @@ void
 nv50_vm_flush(struct drm_device *dev, int engine)
 {
        nv_wr32(dev, 0x100c80, (engine << 16) | 1);
-       if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
+       if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
                NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
new file mode 100644 (file)
index 0000000..7dbb305
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_bios.h"
+#include "nouveau_pm.h"
+
+struct nv50_pm_state {
+       struct nouveau_pm_level *perflvl;
+       struct pll_lims pll;
+       enum pll_types type;
+       int N, M, P;
+};
+
+int
+nv50_pm_clock_get(struct drm_device *dev, u32 id)
+{
+       struct pll_lims pll;
+       int P, N, M, ret;
+       u32 reg0, reg1;
+
+       ret = get_pll_limits(dev, id, &pll);
+       if (ret)
+               return ret;
+
+       reg0 = nv_rd32(dev, pll.reg + 0);
+       reg1 = nv_rd32(dev, pll.reg + 4);
+       P = (reg0 & 0x00070000) >> 16;
+       N = (reg1 & 0x0000ff00) >> 8;
+       M = (reg1 & 0x000000ff);
+
+       return ((pll.refclk * N / M) >> P);
+}
+
+void *
+nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+                 u32 id, int khz)
+{
+       struct nv50_pm_state *state;
+       int dummy, ret;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+       state->type = id;
+       state->perflvl = perflvl;
+
+       ret = get_pll_limits(dev, id, &state->pll);
+       if (ret < 0) {
+               kfree(state);
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       }
+
+       ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M,
+                           &dummy, &dummy, &state->P);
+       if (ret < 0) {
+               kfree(state);
+               return ERR_PTR(ret);
+       }
+
+       return state;
+}
+
+void
+nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+       struct nv50_pm_state *state = pre_state;
+       struct nouveau_pm_level *perflvl = state->perflvl;
+       u32 reg = state->pll.reg, tmp;
+       struct bit_entry BIT_M;
+       u16 script;
+       int N = state->N;
+       int M = state->M;
+       int P = state->P;
+
+       if (state->type == PLL_MEMORY && perflvl->memscript &&
+           bit_table(dev, 'M', &BIT_M) == 0 &&
+           BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+               script = ROM16(BIT_M.data[0x05]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+               script = ROM16(BIT_M.data[0x07]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+               script = ROM16(BIT_M.data[0x09]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+
+               nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
+       }
+
+       if (state->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x100210, 0);
+               nv_wr32(dev, 0x1002dc, 1);
+       }
+
+       tmp  = nv_rd32(dev, reg + 0) & 0xfff8ffff;
+       tmp |= 0x80000000 | (P << 16);
+       nv_wr32(dev, reg + 0, tmp);
+       nv_wr32(dev, reg + 4, (N << 8) | M);
+
+       if (state->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x1002dc, 0);
+               nv_wr32(dev, 0x100210, 0x80000000);
+       }
+
+       kfree(state);
+}
+
index bcd4cf84a7e641cb0d79d5b1d67a8604110a9af3..b4a5ecb199f925646ca10c4364ebe05696786a7d 100644 (file)
@@ -92,7 +92,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
        }
 
        /* wait for it to be done */
-       if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+       if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
                     NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
                NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
                NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -108,7 +108,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
 
        nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
                NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
-       if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(or),
+       if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or),
                     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
                NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
                NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
new file mode 100644 (file)
index 0000000..dbbafed
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_bios.h"
+#include "nouveau_pm.h"
+
+/*XXX: boards using limits 0x40 need fixing, the register layout
+ *     is correct here, but, there's some other funny magic
+ *     that modifies things, so it's not likely we'll set/read
+ *     the correct timings yet..  working on it...
+ */
+
+struct nva3_pm_state {
+       struct pll_lims pll;
+       int N, M, P;
+};
+
+int
+nva3_pm_clock_get(struct drm_device *dev, u32 id)
+{
+       struct pll_lims pll;
+       int P, N, M, ret;
+       u32 reg;
+
+       ret = get_pll_limits(dev, id, &pll);
+       if (ret)
+               return ret;
+
+       reg = nv_rd32(dev, pll.reg + 4);
+       P = (reg & 0x003f0000) >> 16;
+       N = (reg & 0x0000ff00) >> 8;
+       M = (reg & 0x000000ff);
+       return pll.refclk * N / M / P;
+}
+
+void *
+nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+                 u32 id, int khz)
+{
+       struct nva3_pm_state *state;
+       int dummy, ret;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       ret = get_pll_limits(dev, id, &state->pll);
+       if (ret < 0) {
+               kfree(state);
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       }
+
+       ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
+                            &state->M, &state->P);
+       if (ret < 0) {
+               kfree(state);
+               return ERR_PTR(ret);
+       }
+
+       return state;
+}
+
+void
+nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+       struct nva3_pm_state *state = pre_state;
+       u32 reg = state->pll.reg;
+
+       nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
+       kfree(state);
+}
+
index d64375871979d5bf06147ca65b3afe4644dfb095..890c2b95fbc12751c4954d384dc56d0ccb19dc06 100644 (file)
@@ -42,12 +42,6 @@ nvc0_fifo_reassign(struct drm_device *dev, bool enable)
        return false;
 }
 
-bool
-nvc0_fifo_cache_flush(struct drm_device *dev)
-{
-       return true;
-}
-
 bool
 nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
 {
index 6b451f864783e5c1ed3610c13c86adb5588a5783..13a0f78a9088c3b57c25ab148819ef6e47b914cb 100644 (file)
@@ -50,8 +50,7 @@ nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
                return ret;
        }
 
-       gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
-       gpuobj->im_backing_start <<= PAGE_SHIFT;
+       gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
        return 0;
 }
 
@@ -84,11 +83,11 @@ nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 
        pte     = gpuobj->im_pramin->start >> 12;
        pte_end = (gpuobj->im_pramin->size >> 12) + pte;
-       vram    = gpuobj->im_backing_start;
+       vram    = gpuobj->vinst;
 
        NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
                 gpuobj->im_pramin->start, pte, pte_end);
-       NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+       NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
 
        while (pte < pte_end) {
                nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
@@ -134,7 +133,7 @@ void
 nvc0_instmem_flush(struct drm_device *dev)
 {
        nv_wr32(dev, 0x070000, 1);
-       if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+       if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -221,10 +220,6 @@ nvc0_instmem_init(struct drm_device *dev)
                return -ENOMEM;
        }
 
-       /*XXX: incorrect, but needed to make hash func "work" */
-       dev_priv->ramht_offset = 0x10000;
-       dev_priv->ramht_bits   = 9;
-       dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
        return 0;
 }
 
index ad64673ace1fc955d650a2c6f8645ec0aba2a402..881f8a585613a82f190349d60f4a2dd2b6815adb 100644 (file)
 #              define NV_CIO_CRE_HCUR_ADDR1_ADR        7:2
 #      define NV_CIO_CRE_LCD__INDEX            0x33
 #              define NV_CIO_CRE_LCD_LCD_SELECT        0:0
+#              define NV_CIO_CRE_LCD_ROUTE_MASK        0x3b
 #      define NV_CIO_CRE_DDC0_STATUS__INDEX    0x36
 #      define NV_CIO_CRE_DDC0_WR__INDEX        0x37
 #      define NV_CIO_CRE_ILACE__INDEX          0x39    /* interlace */
index d42c76c237142225adf95332a3e4ca2c2dee62ea..18c3c71e41b1cc37c94477d052b7959085fe0ebd 100644 (file)
@@ -56,8 +56,6 @@ static struct drm_driver driver = {
        .irq_uninstall = r128_driver_irq_uninstall,
        .irq_handler = r128_driver_irq_handler,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = r128_ioctls,
        .dma_ioctl = r128_cce_buffers,
        .fops = {
index aebe00875041448351bb129b7a131baab66f4e9e..6cae4f2028d27544467f2c2c3d605788b9f60df8 100644 (file)
@@ -65,7 +65,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
        r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
        r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
-       evergreen.o evergreen_cs.o
+       evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
index cd0290f946cff51e8aa8c702dda5e650ec5f9af0..df2b6f2b35f893d00b475147f8d995a7b3c15bc2 100644 (file)
@@ -398,65 +398,76 @@ static void atombios_disable_ss(struct drm_crtc *crtc)
 
 
 union atom_enable_ss {
-       ENABLE_LVDS_SS_PARAMETERS legacy;
+       ENABLE_LVDS_SS_PARAMETERS lvds_ss;
+       ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
        ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
+       ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
 };
 
-static void atombios_enable_ss(struct drm_crtc *crtc)
+static void atombios_crtc_program_ss(struct drm_crtc *crtc,
+                                    int enable,
+                                    int pll_id,
+                                    struct radeon_atom_ss *ss)
 {
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
-       struct drm_encoder *encoder = NULL;
-       struct radeon_encoder *radeon_encoder = NULL;
-       struct radeon_encoder_atom_dig *dig = NULL;
        int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
        union atom_enable_ss args;
-       uint16_t percentage = 0;
-       uint8_t type = 0, step = 0, delay = 0, range = 0;
 
-       /* XXX add ss support for DCE4 */
-       if (ASIC_IS_DCE4(rdev))
-               return;
+       memset(&args, 0, sizeof(args));
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               if (encoder->crtc == crtc) {
-                       radeon_encoder = to_radeon_encoder(encoder);
-                       /* only enable spread spectrum on LVDS */
-                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               dig = radeon_encoder->enc_priv;
-                               if (dig && dig->ss) {
-                                       percentage = dig->ss->percentage;
-                                       type = dig->ss->type;
-                                       step = dig->ss->step;
-                                       delay = dig->ss->delay;
-                                       range = dig->ss->range;
-                               } else
-                                       return;
-                       } else
-                               return;
+       if (ASIC_IS_DCE4(rdev)) {
+               args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+               args.v2.ucSpreadSpectrumType = ss->type;
+               switch (pll_id) {
+               case ATOM_PPLL1:
+                       args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
+                       args.v2.usSpreadSpectrumAmount = ss->amount;
+                       args.v2.usSpreadSpectrumStep = ss->step;
+                       break;
+               case ATOM_PPLL2:
+                       args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
+                       args.v2.usSpreadSpectrumAmount = ss->amount;
+                       args.v2.usSpreadSpectrumStep = ss->step;
                        break;
+               case ATOM_DCPLL:
+                       args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
+                       args.v2.usSpreadSpectrumAmount = 0;
+                       args.v2.usSpreadSpectrumStep = 0;
+                       break;
+               case ATOM_PPLL_INVALID:
+                       return;
                }
-       }
-
-       if (!radeon_encoder)
-               return;
-
-       memset(&args, 0, sizeof(args));
-       if (ASIC_IS_AVIVO(rdev)) {
-               args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
-               args.v1.ucSpreadSpectrumType = type;
-               args.v1.ucSpreadSpectrumStep = step;
-               args.v1.ucSpreadSpectrumDelay = delay;
-               args.v1.ucSpreadSpectrumRange = range;
-               args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
-               args.v1.ucEnable = ATOM_ENABLE;
+               args.v2.ucEnable = enable;
+       } else if (ASIC_IS_DCE3(rdev)) {
+               args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+               args.v1.ucSpreadSpectrumType = ss->type;
+               args.v1.ucSpreadSpectrumStep = ss->step;
+               args.v1.ucSpreadSpectrumDelay = ss->delay;
+               args.v1.ucSpreadSpectrumRange = ss->range;
+               args.v1.ucPpll = pll_id;
+               args.v1.ucEnable = enable;
+       } else if (ASIC_IS_AVIVO(rdev)) {
+               if (enable == ATOM_DISABLE) {
+                       atombios_disable_ss(crtc);
+                       return;
+               }
+               args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+               args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
+               args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
+               args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
+               args.lvds_ss_2.ucEnable = enable;
        } else {
-               args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
-               args.legacy.ucSpreadSpectrumType = type;
-               args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
-               args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
-               args.legacy.ucEnable = ATOM_ENABLE;
+               if (enable == ATOM_DISABLE) {
+                       atombios_disable_ss(crtc);
+                       return;
+               }
+               args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+               args.lvds_ss.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
+               args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
+               args.lvds_ss.ucEnable = enable;
        }
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -468,7 +479,9 @@ union adjust_pixel_clock {
 
 static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
-                              struct radeon_pll *pll)
+                              struct radeon_pll *pll,
+                              bool ss_enabled,
+                              struct radeon_atom_ss *ss)
 {
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -482,19 +495,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        /* reset the pll flags */
        pll->flags = 0;
 
-       /* select the PLL algo */
-       if (ASIC_IS_AVIVO(rdev)) {
-               if (radeon_new_pll == 0)
-                       pll->algo = PLL_ALGO_LEGACY;
-               else
-                       pll->algo = PLL_ALGO_NEW;
-       } else {
-               if (radeon_new_pll == 1)
-                       pll->algo = PLL_ALGO_NEW;
-               else
-                       pll->algo = PLL_ALGO_LEGACY;
-       }
-
        if (ASIC_IS_AVIVO(rdev)) {
                if ((rdev->family == CHIP_RS600) ||
                    (rdev->family == CHIP_RS690) ||
@@ -531,29 +531,22 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                }
                        }
 
+                       /* use recommended ref_div for ss */
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               if (ss_enabled) {
+                                       if (ss->refdiv) {
+                                               pll->flags |= RADEON_PLL_USE_REF_DIV;
+                                               pll->reference_div = ss->refdiv;
+                                       }
+                               }
+                       }
+
                        if (ASIC_IS_AVIVO(rdev)) {
                                /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
                                if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
                                        adjusted_clock = mode->clock * 2;
-                               if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
-                                       pll->algo = PLL_ALGO_LEGACY;
+                               if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
                                        pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
-                               }
-                               /* There is some evidence (often anecdotal) that RV515/RV620 LVDS
-                                * (on some boards at least) prefers the legacy algo.  I'm not
-                                * sure whether this should handled generically or on a
-                                * case-by-case quirk basis.  Both algos should work fine in the
-                                * majority of cases.
-                                */
-                               if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
-                                   ((rdev->family == CHIP_RV515) ||
-                                    (rdev->family == CHIP_RV620))) {
-                                       /* allow the user to overrride just in case */
-                                       if (radeon_new_pll == 1)
-                                               pll->algo = PLL_ALGO_NEW;
-                                       else
-                                               pll->algo = PLL_ALGO_LEGACY;
-                               }
                        } else {
                                if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
                                        pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@@ -589,9 +582,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v1.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v1.ucEncodeMode = encoder_mode;
                                if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                       /* may want to enable SS on DP eventually */
-                                       /* args.v1.ucConfig |=
-                                          ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/
+                                       if (ss_enabled)
+                                               args.v1.ucConfig |=
+                                                       ADJUST_DISPLAY_CONFIG_SS_ENABLE;
                                } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
                                        args.v1.ucConfig |=
                                                ADJUST_DISPLAY_CONFIG_SS_ENABLE;
@@ -608,11 +601,10 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v3.sInput.ucDispPllConfig = 0;
                                if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                                        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                               /* may want to enable SS on DP/eDP eventually */
-                                               /*args.v3.sInput.ucDispPllConfig |=
-                                                 DISPPLL_CONFIG_SS_ENABLE;*/
+                                               if (ss_enabled)
+                                                       args.v3.sInput.ucDispPllConfig |=
+                                                               DISPPLL_CONFIG_SS_ENABLE;
                                                args.v3.sInput.ucDispPllConfig |=
                                                        DISPPLL_CONFIG_COHERENT_MODE;
                                                /* 16200 or 27000 */
@@ -632,17 +624,17 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                        }
                                } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                               /* may want to enable SS on DP/eDP eventually */
-                                               /*args.v3.sInput.ucDispPllConfig |=
-                                                 DISPPLL_CONFIG_SS_ENABLE;*/
+                                               if (ss_enabled)
+                                                       args.v3.sInput.ucDispPllConfig |=
+                                                               DISPPLL_CONFIG_SS_ENABLE;
                                                args.v3.sInput.ucDispPllConfig |=
                                                        DISPPLL_CONFIG_COHERENT_MODE;
                                                /* 16200 or 27000 */
                                                args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
                                        } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
-                                               /* want to enable SS on LVDS eventually */
-                                               /*args.v3.sInput.ucDispPllConfig |=
-                                                 DISPPLL_CONFIG_SS_ENABLE;*/
+                                               if (ss_enabled)
+                                                       args.v3.sInput.ucDispPllConfig |=
+                                                               DISPPLL_CONFIG_SS_ENABLE;
                                        } else {
                                                if (mode->clock > 165000)
                                                        args.v3.sInput.ucDispPllConfig |=
@@ -816,6 +808,8 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        struct radeon_pll *pll;
        u32 adjusted_clock;
        int encoder_mode = 0;
+       struct radeon_atom_ss ss;
+       bool ss_enabled = false;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc == crtc) {
@@ -842,25 +836,123 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                break;
        }
 
+       if (radeon_encoder->active_device &
+           (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
+               struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+               struct drm_connector *connector =
+                       radeon_get_connector_for_encoder(encoder);
+               struct radeon_connector *radeon_connector =
+                       to_radeon_connector(connector);
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+               int dp_clock;
+
+               switch (encoder_mode) {
+               case ATOM_ENCODER_MODE_DP:
+                       /* DP/eDP */
+                       dp_clock = dig_connector->dp_clock / 10;
+                       if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               if (ASIC_IS_DCE4(rdev))
+                                       ss_enabled =
+                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                                dig->lcd_ss_id,
+                                                                                dp_clock);
+                               else
+                                       ss_enabled =
+                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                dig->lcd_ss_id);
+                       } else {
+                               if (ASIC_IS_DCE4(rdev))
+                                       ss_enabled =
+                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                                ASIC_INTERNAL_SS_ON_DP,
+                                                                                dp_clock);
+                               else {
+                                       if (dp_clock == 16200) {
+                                               ss_enabled =
+                                                       radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                        ATOM_DP_SS_ID2);
+                                               if (!ss_enabled)
+                                                       ss_enabled =
+                                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                                ATOM_DP_SS_ID1);
+                                       } else
+                                               ss_enabled =
+                                                       radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                        ATOM_DP_SS_ID1);
+                               }
+                       }
+                       break;
+               case ATOM_ENCODER_MODE_LVDS:
+                       if (ASIC_IS_DCE4(rdev))
+                               ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                             dig->lcd_ss_id,
+                                                                             mode->clock / 10);
+                       else
+                               ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                             dig->lcd_ss_id);
+                       break;
+               case ATOM_ENCODER_MODE_DVI:
+                       if (ASIC_IS_DCE4(rdev))
+                               ss_enabled =
+                                       radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                        ASIC_INTERNAL_SS_ON_TMDS,
+                                                                        mode->clock / 10);
+                       break;
+               case ATOM_ENCODER_MODE_HDMI:
+                       if (ASIC_IS_DCE4(rdev))
+                               ss_enabled =
+                                       radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                        ASIC_INTERNAL_SS_ON_HDMI,
+                                                                        mode->clock / 10);
+                       break;
+               default:
+                       break;
+               }
+       }
+
        /* adjust pixel clock as needed */
-       adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+       adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
 
        radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
                           &ref_div, &post_div);
 
+       atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
+
        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
                                  encoder_mode, radeon_encoder->encoder_id, mode->clock,
                                  ref_div, fb_div, frac_fb_div, post_div);
 
+       if (ss_enabled) {
+               /* calculate ss amount and step size */
+               if (ASIC_IS_DCE4(rdev)) {
+                       u32 step_size;
+                       u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
+                       ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
+                       ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+                               ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
+                       if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
+                               step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
+                                       (125 * 25 * pll->reference_freq / 100);
+                       else
+                               step_size = (2 * amount * ref_div * (ss.rate * 2048)) /
+                                       (125 * 25 * pll->reference_freq / 100);
+                       ss.step = step_size;
+               }
+
+               atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss);
+       }
 }
 
-static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
-                                  struct drm_framebuffer *old_fb)
+static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
+                                     struct drm_framebuffer *fb,
+                                     int x, int y, int atomic)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_framebuffer *radeon_fb;
+       struct drm_framebuffer *target_fb;
        struct drm_gem_object *obj;
        struct radeon_bo *rbo;
        uint64_t fb_location;
@@ -868,28 +960,43 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        int r;
 
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!atomic && !crtc->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
 
-       radeon_fb = to_radeon_framebuffer(crtc->fb);
+       if (atomic) {
+               radeon_fb = to_radeon_framebuffer(fb);
+               target_fb = fb;
+       }
+       else {
+               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               target_fb = crtc->fb;
+       }
 
-       /* Pin framebuffer & get tilling informations */
+       /* If atomic, assume fb object is pinned & idle & fenced and
+        * just update base pointers
+        */
        obj = radeon_fb->obj;
        rbo = obj->driver_private;
        r = radeon_bo_reserve(rbo, false);
        if (unlikely(r != 0))
                return r;
-       r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
-       if (unlikely(r != 0)) {
-               radeon_bo_unreserve(rbo);
-               return -EINVAL;
+
+       if (atomic)
+               fb_location = radeon_bo_gpu_offset(rbo);
+       else {
+               r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+               if (unlikely(r != 0)) {
+                       radeon_bo_unreserve(rbo);
+                       return -EINVAL;
+               }
        }
+
        radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
        radeon_bo_unreserve(rbo);
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (target_fb->bits_per_pixel) {
        case 8:
                fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
                             EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
@@ -909,7 +1016,7 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
-                         crtc->fb->bits_per_pixel);
+                         target_fb->bits_per_pixel);
                return -EINVAL;
        }
 
@@ -955,10 +1062,10 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
        WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
        WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
-       WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
-       WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+       WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+       WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
 
-       fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+       fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
        WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
        WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
@@ -977,8 +1084,8 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        else
                WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
 
-       if (old_fb && old_fb != crtc->fb) {
-               radeon_fb = to_radeon_framebuffer(old_fb);
+       if (!atomic && fb && fb != crtc->fb) {
+               radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
                r = radeon_bo_reserve(rbo, false);
                if (unlikely(r != 0))
@@ -993,8 +1100,9 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
-static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
-                              struct drm_framebuffer *old_fb)
+static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
+                                 struct drm_framebuffer *fb,
+                                 int x, int y, int atomic)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -1002,33 +1110,48 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        struct radeon_framebuffer *radeon_fb;
        struct drm_gem_object *obj;
        struct radeon_bo *rbo;
+       struct drm_framebuffer *target_fb;
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
        int r;
 
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!atomic && !crtc->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
 
-       radeon_fb = to_radeon_framebuffer(crtc->fb);
+       if (atomic) {
+               radeon_fb = to_radeon_framebuffer(fb);
+               target_fb = fb;
+       }
+       else {
+               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               target_fb = crtc->fb;
+       }
 
-       /* Pin framebuffer & get tilling informations */
        obj = radeon_fb->obj;
        rbo = obj->driver_private;
        r = radeon_bo_reserve(rbo, false);
        if (unlikely(r != 0))
                return r;
-       r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
-       if (unlikely(r != 0)) {
-               radeon_bo_unreserve(rbo);
-               return -EINVAL;
+
+       /* If atomic, assume fb object is pinned & idle & fenced and
+        * just update base pointers
+        */
+       if (atomic)
+               fb_location = radeon_bo_gpu_offset(rbo);
+       else {
+               r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+               if (unlikely(r != 0)) {
+                       radeon_bo_unreserve(rbo);
+                       return -EINVAL;
+               }
        }
        radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
        radeon_bo_unreserve(rbo);
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (target_fb->bits_per_pixel) {
        case 8:
                fb_format =
                    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
@@ -1052,7 +1175,7 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
-                         crtc->fb->bits_per_pixel);
+                         target_fb->bits_per_pixel);
                return -EINVAL;
        }
 
@@ -1093,10 +1216,10 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
        WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
        WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
-       WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
-       WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+       WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+       WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
 
-       fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+       fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
        WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
        WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
@@ -1115,8 +1238,8 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        else
                WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
 
-       if (old_fb && old_fb != crtc->fb) {
-               radeon_fb = to_radeon_framebuffer(old_fb);
+       if (!atomic && fb && fb != crtc->fb) {
+               radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
                r = radeon_bo_reserve(rbo, false);
                if (unlikely(r != 0))
@@ -1138,11 +1261,26 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev))
-               return evergreen_crtc_set_base(crtc, x, y, old_fb);
+               return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else if (ASIC_IS_AVIVO(rdev))
-               return avivo_crtc_set_base(crtc, x, y, old_fb);
+               return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else
-               return radeon_crtc_set_base(crtc, x, y, old_fb);
+               return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                  struct drm_framebuffer *fb,
+                                 int x, int y, enum mode_set_atomic state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (ASIC_IS_DCE4(rdev))
+               return evergreen_crtc_do_set_base(crtc, fb, x, y, 1);
+       else if (ASIC_IS_AVIVO(rdev))
+               return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
+       else
+               return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
 }
 
 /* properly set additional regs when using atombios */
@@ -1230,12 +1368,19 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       atombios_disable_ss(crtc);
        /* always set DCPLL */
-       if (ASIC_IS_DCE4(rdev))
+       if (ASIC_IS_DCE4(rdev)) {
+               struct radeon_atom_ss ss;
+               bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                  ASIC_INTERNAL_SS_ON_DCPLL,
+                                                                  rdev->clock.default_dispclk);
+               if (ss_enabled)
+                       atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss);
                atombios_crtc_set_dcpll(crtc);
+               if (ss_enabled)
+                       atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss);
+       }
        atombios_crtc_set_pll(crtc, adjusted_mode);
-       atombios_enable_ss(crtc);
 
        if (ASIC_IS_DCE4(rdev))
                atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
@@ -1311,6 +1456,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
        .mode_fixup = atombios_crtc_mode_fixup,
        .mode_set = atombios_crtc_mode_set,
        .mode_set_base = atombios_crtc_set_base,
+       .mode_set_base_atomic = atombios_crtc_set_base_atomic,
        .prepare = atombios_crtc_prepare,
        .commit = atombios_crtc_commit,
        .load_lut = radeon_crtc_load_lut,
index 2f93d46ae69ad58dfb90ea5db02021a402506ae5..f12a5b3ec050320505c6dc0b1cb44dcdde3fbeed 100644 (file)
@@ -32,6 +32,7 @@
 #include "atom.h"
 #include "avivod.h"
 #include "evergreen_reg.h"
+#include "evergreen_blit_shaders.h"
 
 #define EVERGREEN_PFP_UCODE_SIZE 1120
 #define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -284,9 +285,444 @@ void evergreen_hpd_fini(struct radeon_device *rdev)
        }
 }
 
+/* watermark setup */
+
+static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
+                                       struct radeon_crtc *radeon_crtc,
+                                       struct drm_display_mode *mode,
+                                       struct drm_display_mode *other_mode)
+{
+       u32 tmp = 0;
+       /*
+        * Line Buffer Setup
+        * There are 3 line buffers, each one shared by 2 display controllers.
+        * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+        * the display controllers.  The paritioning is done via one of four
+        * preset allocations specified in bits 2:0:
+        * first display controller
+        *  0 - first half of lb (3840 * 2)
+        *  1 - first 3/4 of lb (5760 * 2)
+        *  2 - whole lb (7680 * 2)
+        *  3 - first 1/4 of lb (1920 * 2)
+        * second display controller
+        *  4 - second half of lb (3840 * 2)
+        *  5 - second 3/4 of lb (5760 * 2)
+        *  6 - whole lb (7680 * 2)
+        *  7 - last 1/4 of lb (1920 * 2)
+        */
+       if (mode && other_mode) {
+               if (mode->hdisplay > other_mode->hdisplay) {
+                       if (mode->hdisplay > 2560)
+                               tmp = 1; /* 3/4 */
+                       else
+                               tmp = 0; /* 1/2 */
+               } else if (other_mode->hdisplay > mode->hdisplay) {
+                       if (other_mode->hdisplay > 2560)
+                               tmp = 3; /* 1/4 */
+                       else
+                               tmp = 0; /* 1/2 */
+               } else
+                       tmp = 0; /* 1/2 */
+       } else if (mode)
+               tmp = 2; /* whole */
+       else if (other_mode)
+               tmp = 3; /* 1/4 */
+
+       /* second controller of the pair uses second half of the lb */
+       if (radeon_crtc->crtc_id % 2)
+               tmp += 4;
+       WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp);
+
+       switch (tmp) {
+       case 0:
+       case 4:
+       default:
+               return 3840 * 2;
+       case 1:
+       case 5:
+               return 5760 * 2;
+       case 2:
+       case 6:
+               return 7680 * 2;
+       case 3:
+       case 7:
+               return 1920 * 2;
+       }
+}
+
+static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+       u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+       switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+       case 0:
+       default:
+               return 1;
+       case 1:
+               return 2;
+       case 2:
+               return 4;
+       case 3:
+               return 8;
+       }
+}
+
+struct evergreen_wm_params {
+       u32 dram_channels; /* number of dram channels */
+       u32 yclk;          /* bandwidth per dram data pin in kHz */
+       u32 sclk;          /* engine clock in kHz */
+       u32 disp_clk;      /* display clock in kHz */
+       u32 src_width;     /* viewport width */
+       u32 active_time;   /* active display time in ns */
+       u32 blank_time;    /* blank time in ns */
+       bool interlaced;    /* mode is interlaced */
+       fixed20_12 vsc;    /* vertical scale ratio */
+       u32 num_heads;     /* number of active crtcs */
+       u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+       u32 lb_size;       /* line buffer allocated to pipe */
+       u32 vtaps;         /* vertical scaler taps */
+};
+
+static u32 evergreen_dram_bandwidth(struct evergreen_wm_params *wm)
+{
+       /* Calculate DRAM Bandwidth and the part allocated to display. */
+       fixed20_12 dram_efficiency; /* 0.7 */
+       fixed20_12 yclk, dram_channels, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       yclk.full = dfixed_const(wm->yclk);
+       yclk.full = dfixed_div(yclk, a);
+       dram_channels.full = dfixed_const(wm->dram_channels * 4);
+       a.full = dfixed_const(10);
+       dram_efficiency.full = dfixed_const(7);
+       dram_efficiency.full = dfixed_div(dram_efficiency, a);
+       bandwidth.full = dfixed_mul(dram_channels, yclk);
+       bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+       /* Calculate DRAM Bandwidth and the part allocated to display. */
+       fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+       fixed20_12 yclk, dram_channels, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       yclk.full = dfixed_const(wm->yclk);
+       yclk.full = dfixed_div(yclk, a);
+       dram_channels.full = dfixed_const(wm->dram_channels * 4);
+       a.full = dfixed_const(10);
+       disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+       disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+       bandwidth.full = dfixed_mul(dram_channels, yclk);
+       bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+       return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_data_return_bandwidth(struct evergreen_wm_params *wm)
+{
+       /* Calculate the display Data return Bandwidth */
+       fixed20_12 return_efficiency; /* 0.8 */
+       fixed20_12 sclk, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       sclk.full = dfixed_const(wm->sclk);
+       sclk.full = dfixed_div(sclk, a);
+       a.full = dfixed_const(10);
+       return_efficiency.full = dfixed_const(8);
+       return_efficiency.full = dfixed_div(return_efficiency, a);
+       a.full = dfixed_const(32);
+       bandwidth.full = dfixed_mul(a, sclk);
+       bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dmif_request_bandwidth(struct evergreen_wm_params *wm)
+{
+       /* Calculate the DMIF Request Bandwidth */
+       fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+       fixed20_12 disp_clk, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       disp_clk.full = dfixed_const(wm->disp_clk);
+       disp_clk.full = dfixed_div(disp_clk, a);
+       a.full = dfixed_const(10);
+       disp_clk_request_efficiency.full = dfixed_const(8);
+       disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+       a.full = dfixed_const(32);
+       bandwidth.full = dfixed_mul(a, disp_clk);
+       bandwidth.full = dfixed_mul(bandwidth, disp_clk_request_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_available_bandwidth(struct evergreen_wm_params *wm)
+{
+       /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+       u32 dram_bandwidth = evergreen_dram_bandwidth(wm);
+       u32 data_return_bandwidth = evergreen_data_return_bandwidth(wm);
+       u32 dmif_req_bandwidth = evergreen_dmif_request_bandwidth(wm);
+
+       return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+static u32 evergreen_average_bandwidth(struct evergreen_wm_params *wm)
+{
+       /* Calculate the display mode Average Bandwidth
+        * DisplayMode should contain the source and destination dimensions,
+        * timing, etc.
+        */
+       fixed20_12 bpp;
+       fixed20_12 line_time;
+       fixed20_12 src_width;
+       fixed20_12 bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+       line_time.full = dfixed_div(line_time, a);
+       bpp.full = dfixed_const(wm->bytes_per_pixel);
+       src_width.full = dfixed_const(wm->src_width);
+       bandwidth.full = dfixed_mul(src_width, bpp);
+       bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+       bandwidth.full = dfixed_div(bandwidth, line_time);
+
+       return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_latency_watermark(struct evergreen_wm_params *wm)
+{
+       /* First calcualte the latency in ns */
+       u32 mc_latency = 2000; /* 2000 ns. */
+       u32 available_bandwidth = evergreen_available_bandwidth(wm);
+       u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+       u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+       u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+       u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+               (wm->num_heads * cursor_line_pair_return_time);
+       u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+       u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+       fixed20_12 a, b, c;
+
+       if (wm->num_heads == 0)
+               return 0;
+
+       a.full = dfixed_const(2);
+       b.full = dfixed_const(1);
+       if ((wm->vsc.full > a.full) ||
+           ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+           (wm->vtaps >= 5) ||
+           ((wm->vsc.full >= a.full) && wm->interlaced))
+               max_src_lines_per_dst_line = 4;
+       else
+               max_src_lines_per_dst_line = 2;
+
+       a.full = dfixed_const(available_bandwidth);
+       b.full = dfixed_const(wm->num_heads);
+       a.full = dfixed_div(a, b);
+
+       b.full = dfixed_const(1000);
+       c.full = dfixed_const(wm->disp_clk);
+       b.full = dfixed_div(c, b);
+       c.full = dfixed_const(wm->bytes_per_pixel);
+       b.full = dfixed_mul(b, c);
+
+       lb_fill_bw = min(dfixed_trunc(a), dfixed_trunc(b));
+
+       a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+       b.full = dfixed_const(1000);
+       c.full = dfixed_const(lb_fill_bw);
+       b.full = dfixed_div(c, b);
+       a.full = dfixed_div(a, b);
+       line_fill_time = dfixed_trunc(a);
+
+       if (line_fill_time < wm->active_time)
+               return latency;
+       else
+               return latency + (line_fill_time - wm->active_time);
+
+}
+
+static bool evergreen_average_bandwidth_vs_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+       if (evergreen_average_bandwidth(wm) <=
+           (evergreen_dram_bandwidth_for_display(wm) / wm->num_heads))
+               return true;
+       else
+               return false;
+};
+
+static bool evergreen_average_bandwidth_vs_available_bandwidth(struct evergreen_wm_params *wm)
+{
+       if (evergreen_average_bandwidth(wm) <=
+           (evergreen_available_bandwidth(wm) / wm->num_heads))
+               return true;
+       else
+               return false;
+};
+
+static bool evergreen_check_latency_hiding(struct evergreen_wm_params *wm)
+{
+       u32 lb_partitions = wm->lb_size / wm->src_width;
+       u32 line_time = wm->active_time + wm->blank_time;
+       u32 latency_tolerant_lines;
+       u32 latency_hiding;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1);
+       if (wm->vsc.full > a.full)
+               latency_tolerant_lines = 1;
+       else {
+               if (lb_partitions <= (wm->vtaps + 1))
+                       latency_tolerant_lines = 1;
+               else
+                       latency_tolerant_lines = 2;
+       }
+
+       latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+       if (evergreen_latency_watermark(wm) <= latency_hiding)
+               return true;
+       else
+               return false;
+}
+
+static void evergreen_program_watermarks(struct radeon_device *rdev,
+                                        struct radeon_crtc *radeon_crtc,
+                                        u32 lb_size, u32 num_heads)
+{
+       struct drm_display_mode *mode = &radeon_crtc->base.mode;
+       struct evergreen_wm_params wm;
+       u32 pixel_period;
+       u32 line_time = 0;
+       u32 latency_watermark_a = 0, latency_watermark_b = 0;
+       u32 priority_a_mark = 0, priority_b_mark = 0;
+       u32 priority_a_cnt = PRIORITY_OFF;
+       u32 priority_b_cnt = PRIORITY_OFF;
+       u32 pipe_offset = radeon_crtc->crtc_id * 16;
+       u32 tmp, arb_control3;
+       fixed20_12 a, b, c;
+
+       if (radeon_crtc->base.enabled && num_heads && mode) {
+               pixel_period = 1000000 / (u32)mode->clock;
+               line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+               priority_a_cnt = 0;
+               priority_b_cnt = 0;
+
+               wm.yclk = rdev->pm.current_mclk * 10;
+               wm.sclk = rdev->pm.current_sclk * 10;
+               wm.disp_clk = mode->clock;
+               wm.src_width = mode->crtc_hdisplay;
+               wm.active_time = mode->crtc_hdisplay * pixel_period;
+               wm.blank_time = line_time - wm.active_time;
+               wm.interlaced = false;
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       wm.interlaced = true;
+               wm.vsc = radeon_crtc->vsc;
+               wm.vtaps = 1;
+               if (radeon_crtc->rmx_type != RMX_OFF)
+                       wm.vtaps = 2;
+               wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+               wm.lb_size = lb_size;
+               wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+               wm.num_heads = num_heads;
+
+               /* set for high clocks */
+               latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535);
+               /* set for low clocks */
+               /* wm.yclk = low clk; wm.sclk = low clk */
+               latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535);
+
+               /* possibly force display priority to high */
+               /* should really do this at mode validation time... */
+               if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+                   !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
+                   !evergreen_check_latency_hiding(&wm) ||
+                   (rdev->disp_priority == 2)) {
+                       DRM_INFO("force priority to high\n");
+                       priority_a_cnt |= PRIORITY_ALWAYS_ON;
+                       priority_b_cnt |= PRIORITY_ALWAYS_ON;
+               }
+
+               a.full = dfixed_const(1000);
+               b.full = dfixed_const(mode->clock);
+               b.full = dfixed_div(b, a);
+               c.full = dfixed_const(latency_watermark_a);
+               c.full = dfixed_mul(c, b);
+               c.full = dfixed_mul(c, radeon_crtc->hsc);
+               c.full = dfixed_div(c, a);
+               a.full = dfixed_const(16);
+               c.full = dfixed_div(c, a);
+               priority_a_mark = dfixed_trunc(c);
+               priority_a_cnt |= priority_a_mark & PRIORITY_MARK_MASK;
+
+               a.full = dfixed_const(1000);
+               b.full = dfixed_const(mode->clock);
+               b.full = dfixed_div(b, a);
+               c.full = dfixed_const(latency_watermark_b);
+               c.full = dfixed_mul(c, b);
+               c.full = dfixed_mul(c, radeon_crtc->hsc);
+               c.full = dfixed_div(c, a);
+               a.full = dfixed_const(16);
+               c.full = dfixed_div(c, a);
+               priority_b_mark = dfixed_trunc(c);
+               priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+       }
+
+       /* select wm A */
+       arb_control3 = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+       tmp = arb_control3;
+       tmp &= ~LATENCY_WATERMARK_MASK(3);
+       tmp |= LATENCY_WATERMARK_MASK(1);
+       WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+       WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+              (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+               LATENCY_HIGH_WATERMARK(line_time)));
+       /* select wm B */
+       tmp = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+       tmp &= ~LATENCY_WATERMARK_MASK(3);
+       tmp |= LATENCY_WATERMARK_MASK(2);
+       WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+       WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+              (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+               LATENCY_HIGH_WATERMARK(line_time)));
+       /* restore original selection */
+       WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, arb_control3);
+
+       /* write the priority marks */
+       WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
+       WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+
+}
+
 void evergreen_bandwidth_update(struct radeon_device *rdev)
 {
-       /* XXX */
+       struct drm_display_mode *mode0 = NULL;
+       struct drm_display_mode *mode1 = NULL;
+       u32 num_heads = 0, lb_size;
+       int i;
+
+       radeon_update_display_priority(rdev);
+
+       for (i = 0; i < rdev->num_crtc; i++) {
+               if (rdev->mode_info.crtcs[i]->base.enabled)
+                       num_heads++;
+       }
+       for (i = 0; i < rdev->num_crtc; i += 2) {
+               mode0 = &rdev->mode_info.crtcs[i]->base.mode;
+               mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+               lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
+               evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+               lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
+               evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i+1], lb_size, num_heads);
+       }
 }
 
 static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
@@ -677,7 +1113,7 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev)
 
 static int evergreen_cp_start(struct radeon_device *rdev)
 {
-       int r;
+       int r, i;
        uint32_t cp_me;
 
        r = radeon_ring_lock(rdev, 7);
@@ -697,16 +1133,39 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        cp_me = 0xff;
        WREG32(CP_ME_CNTL, cp_me);
 
-       r = radeon_ring_lock(rdev, 4);
+       r = radeon_ring_lock(rdev, evergreen_default_size + 15);
        if (r) {
                DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
                return r;
        }
-       /* init some VGT regs */
-       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
-       radeon_ring_write(rdev, (VGT_VERTEX_REUSE_BLOCK_CNTL - PACKET3_SET_CONTEXT_REG_START) >> 2);
-       radeon_ring_write(rdev, 0xe);
-       radeon_ring_write(rdev, 0x10);
+
+       /* setup clear context state */
+       radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       radeon_ring_write(rdev, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+       for (i = 0; i < evergreen_default_size; i++)
+               radeon_ring_write(rdev, evergreen_default_state[i]);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       radeon_ring_write(rdev, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+       /* set clear context state */
+       radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+       radeon_ring_write(rdev, 0);
+
+       /* SQ_VTX_BASE_VTX_LOC */
+       radeon_ring_write(rdev, 0xc0026f00);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000000);
+
+       /* Clear consts */
+       radeon_ring_write(rdev, 0xc0036f00);
+       radeon_ring_write(rdev, 0x00000bc4);
+       radeon_ring_write(rdev, 0xffffffff);
+       radeon_ring_write(rdev, 0xffffffff);
+       radeon_ring_write(rdev, 0xffffffff);
+
        radeon_ring_unlock_commit(rdev);
 
        return 0;
@@ -731,7 +1190,7 @@ int evergreen_cp_resume(struct radeon_device *rdev)
 
        /* Set ring buffer size */
        rb_bufsz = drm_order(rdev->cp.ring_size / 8);
-       tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -745,8 +1204,19 @@ int evergreen_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
        WREG32(CP_RB_RPTR_WR, 0);
        WREG32(CP_RB_WPTR, 0);
-       WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
-       WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+       /* set the wb address wether it's enabled or not */
+       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+       WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+       if (rdev->wb.enabled)
+               WREG32(SCRATCH_UMSK, 0xff);
+       else {
+               tmp |= RB_NO_UPDATE;
+               WREG32(SCRATCH_UMSK, 0);
+       }
+
        mdelay(1);
        WREG32(CP_RB_CNTL, tmp);
 
@@ -1584,6 +2054,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
        if (rdev->irq.sw_int) {
                DRM_DEBUG("evergreen_irq_set: sw int\n");
                cp_int_cntl |= RB_INT_ENABLE;
+               cp_int_cntl |= TIME_STAMP_INT_ENABLE;
        }
        if (rdev->irq.crtc_vblank_int[0]) {
                DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@@ -1760,8 +2231,10 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
 {
        u32 wptr, tmp;
 
-       /* XXX use writeback */
-       wptr = RREG32(IH_RB_WPTR);
+       if (rdev->wb.enabled)
+               wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+       else
+               wptr = RREG32(IH_RB_WPTR);
 
        if (wptr & RB_OVERFLOW) {
                /* When a ring buffer overflow happen start parsing interrupt
@@ -2000,6 +2473,7 @@ restart_ih:
                        break;
                case 181: /* CP EOP event */
                        DRM_DEBUG("IH: CP EOP\n");
+                       radeon_fence_process(rdev);
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: CP EOP\n");
@@ -2048,26 +2522,18 @@ static int evergreen_startup(struct radeon_device *rdev)
                        return r;
        }
        evergreen_gpu_init(rdev);
-#if 0
-       if (!rdev->r600_blit.shader_obj) {
-               r = r600_blit_init(rdev);
-               if (r) {
-                       DRM_ERROR("radeon: failed blitter (%d).\n", r);
-                       return r;
-               }
-       }
 
-       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-       if (unlikely(r != 0))
-               return r;
-       r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-                       &rdev->r600_blit.shader_gpu_addr);
-       radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+       r = evergreen_blit_init(rdev);
        if (r) {
-               DRM_ERROR("failed to pin blit object %d\n", r);
-               return r;
+               evergreen_blit_fini(rdev);
+               rdev->asic->copy = NULL;
+               dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
        }
-#endif
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
 
        /* Enable IRQ */
        r = r600_irq_init(rdev);
@@ -2087,8 +2553,6 @@ static int evergreen_startup(struct radeon_device *rdev)
        r = evergreen_cp_resume(rdev);
        if (r)
                return r;
-       /* write back buffer are not vital so don't worry about failure */
-       r600_wb_enable(rdev);
 
        return 0;
 }
@@ -2122,23 +2586,43 @@ int evergreen_resume(struct radeon_device *rdev)
 
 int evergreen_suspend(struct radeon_device *rdev)
 {
-#if 0
        int r;
-#endif
+
        /* FIXME: we should wait for ring to be empty */
        r700_cp_stop(rdev);
        rdev->cp.ready = false;
        evergreen_irq_suspend(rdev);
-       r600_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        evergreen_pcie_gart_disable(rdev);
-#if 0
+
        /* unpin shaders bo */
        r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
        if (likely(r == 0)) {
                radeon_bo_unpin(rdev->r600_blit.shader_obj);
                radeon_bo_unreserve(rdev->r600_blit.shader_obj);
        }
-#endif
+
+       return 0;
+}
+
+int evergreen_copy_blit(struct radeon_device *rdev,
+                       uint64_t src_offset, uint64_t dst_offset,
+                       unsigned num_pages, struct radeon_fence *fence)
+{
+       int r;
+
+       mutex_lock(&rdev->r600_blit.mutex);
+       rdev->r600_blit.vb_ib = NULL;
+       r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+       if (r) {
+               if (rdev->r600_blit.vb_ib)
+                       radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+               mutex_unlock(&rdev->r600_blit.mutex);
+               return r;
+       }
+       evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+       evergreen_blit_done_copy(rdev, fence);
+       mutex_unlock(&rdev->r600_blit.mutex);
        return 0;
 }
 
@@ -2246,8 +2730,8 @@ int evergreen_init(struct radeon_device *rdev)
        if (r) {
                dev_err(rdev->dev, "disabling GPU acceleration\n");
                r700_cp_fini(rdev);
-               r600_wb_fini(rdev);
                r600_irq_fini(rdev);
+               radeon_wb_fini(rdev);
                radeon_irq_kms_fini(rdev);
                evergreen_pcie_gart_fini(rdev);
                rdev->accel_working = false;
@@ -2269,10 +2753,10 @@ int evergreen_init(struct radeon_device *rdev)
 
 void evergreen_fini(struct radeon_device *rdev)
 {
-       /*r600_blit_fini(rdev);*/
+       evergreen_blit_fini(rdev);
        r700_cp_fini(rdev);
-       r600_wb_fini(rdev);
        r600_irq_fini(rdev);
+       radeon_wb_fini(rdev);
        radeon_irq_kms_fini(rdev);
        evergreen_pcie_gart_fini(rdev);
        radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
new file mode 100644 (file)
index 0000000..086b9b0
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS 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:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#include "evergreend.h"
+#include "evergreen_blit_shaders.h"
+
+#define DI_PT_RECTLIST        0x11
+#define DI_INDEX_SIZE_16_BIT  0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8                 0x1
+#define FMT_5_6_5             0x8
+#define FMT_8_8_8_8           0x1a
+#define COLOR_8               0x1
+#define COLOR_5_6_5           0x8
+#define COLOR_8_8_8_8         0x1a
+
+/* emits 17 */
+static void
+set_render_target(struct radeon_device *rdev, int format,
+                 int w, int h, u64 gpu_addr)
+{
+       u32 cb_color_info;
+       int pitch, slice;
+
+       h = ALIGN(h, 8);
+       if (h < 8)
+               h = 8;
+
+       cb_color_info = ((format << 2) | (1 << 24));
+       pitch = (w / 8) - 1;
+       slice = ((w * h) / 64) - 1;
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 15));
+       radeon_ring_write(rdev, (CB_COLOR0_BASE - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, gpu_addr >> 8);
+       radeon_ring_write(rdev, pitch);
+       radeon_ring_write(rdev, slice);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, cb_color_info);
+       radeon_ring_write(rdev, (1 << 4));
+       radeon_ring_write(rdev, (w - 1) | ((h - 1) << 16));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+}
+
+/* emits 5dw */
+static void
+cp_set_surface_sync(struct radeon_device *rdev,
+                   u32 sync_type, u32 size,
+                   u64 mc_addr)
+{
+       u32 cp_coher_size;
+
+       if (size == 0xffffffff)
+               cp_coher_size = 0xffffffff;
+       else
+               cp_coher_size = ((size + 255) >> 8);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3));
+       radeon_ring_write(rdev, sync_type);
+       radeon_ring_write(rdev, cp_coher_size);
+       radeon_ring_write(rdev, mc_addr >> 8);
+       radeon_ring_write(rdev, 10); /* poll interval */
+}
+
+/* emits 11dw + 1 surface sync = 16dw */
+static void
+set_shaders(struct radeon_device *rdev)
+{
+       u64 gpu_addr;
+
+       /* VS */
+       gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 3));
+       radeon_ring_write(rdev, (SQ_PGM_START_VS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, gpu_addr >> 8);
+       radeon_ring_write(rdev, 2);
+       radeon_ring_write(rdev, 0);
+
+       /* PS */
+       gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.ps_offset;
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 4));
+       radeon_ring_write(rdev, (SQ_PGM_START_PS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, gpu_addr >> 8);
+       radeon_ring_write(rdev, 1);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 2);
+
+       gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+       cp_set_surface_sync(rdev, PACKET3_SH_ACTION_ENA, 512, gpu_addr);
+}
+
+/* emits 10 + 1 sync (5) = 15 */
+static void
+set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
+{
+       u32 sq_vtx_constant_word2, sq_vtx_constant_word3;
+
+       /* high addr, stride */
+       sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+       /* xyzw swizzles */
+       sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+       radeon_ring_write(rdev, 0x580);
+       radeon_ring_write(rdev, gpu_addr & 0xffffffff);
+       radeon_ring_write(rdev, 48 - 1); /* size */
+       radeon_ring_write(rdev, sq_vtx_constant_word2);
+       radeon_ring_write(rdev, sq_vtx_constant_word3);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30);
+
+       if (rdev->family == CHIP_CEDAR)
+               cp_set_surface_sync(rdev,
+                                   PACKET3_TC_ACTION_ENA, 48, gpu_addr);
+       else
+               cp_set_surface_sync(rdev,
+                                   PACKET3_VC_ACTION_ENA, 48, gpu_addr);
+
+}
+
+/* emits 10 */
+static void
+set_tex_resource(struct radeon_device *rdev,
+                int format, int w, int h, int pitch,
+                u64 gpu_addr)
+{
+       u32 sq_tex_resource_word0, sq_tex_resource_word1;
+       u32 sq_tex_resource_word4, sq_tex_resource_word7;
+
+       if (h < 1)
+               h = 1;
+
+       sq_tex_resource_word0 = (1 << 0); /* 2D */
+       sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) |
+                                 ((w - 1) << 18));
+       sq_tex_resource_word1 = ((h - 1) << 0);
+       /* xyzw swizzles */
+       sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25);
+
+       sq_tex_resource_word7 = format | (SQ_TEX_VTX_VALID_TEXTURE << 30);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, sq_tex_resource_word0);
+       radeon_ring_write(rdev, sq_tex_resource_word1);
+       radeon_ring_write(rdev, gpu_addr >> 8);
+       radeon_ring_write(rdev, gpu_addr >> 8);
+       radeon_ring_write(rdev, sq_tex_resource_word4);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, sq_tex_resource_word7);
+}
+
+/* emits 12 */
+static void
+set_scissors(struct radeon_device *rdev, int x1, int y1,
+            int x2, int y2)
+{
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+       radeon_ring_write(rdev, (PA_SC_SCREEN_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, (x1 << 0) | (y1 << 16));
+       radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+       radeon_ring_write(rdev, (PA_SC_GENERIC_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+       radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+       radeon_ring_write(rdev, (PA_SC_WINDOW_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+       radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+       radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+}
+
+/* emits 10 */
+static void
+draw_auto(struct radeon_device *rdev)
+{
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       radeon_ring_write(rdev, (VGT_PRIMITIVE_TYPE - PACKET3_SET_CONFIG_REG_START) >> 2);
+       radeon_ring_write(rdev, DI_PT_RECTLIST);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
+       radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
+       radeon_ring_write(rdev, 1);
+
+       radeon_ring_write(rdev, PACKET3(PACKET3_DRAW_INDEX_AUTO, 1));
+       radeon_ring_write(rdev, 3);
+       radeon_ring_write(rdev, DI_SRC_SEL_AUTO_INDEX);
+
+}
+
+/* emits 30 */
+static void
+set_default_state(struct radeon_device *rdev)
+{
+       u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2, sq_gpr_resource_mgmt_3;
+       u32 sq_thread_resource_mgmt, sq_thread_resource_mgmt_2;
+       u32 sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2, sq_stack_resource_mgmt_3;
+       int num_ps_gprs, num_vs_gprs, num_temp_gprs;
+       int num_gs_gprs, num_es_gprs, num_hs_gprs, num_ls_gprs;
+       int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads;
+       int num_hs_threads, num_ls_threads;
+       int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
+       int num_hs_stack_entries, num_ls_stack_entries;
+
+       switch (rdev->family) {
+       case CHIP_CEDAR:
+       default:
+               num_ps_gprs = 93;
+               num_vs_gprs = 46;
+               num_temp_gprs = 4;
+               num_gs_gprs = 31;
+               num_es_gprs = 31;
+               num_hs_gprs = 23;
+               num_ls_gprs = 23;
+               num_ps_threads = 96;
+               num_vs_threads = 16;
+               num_gs_threads = 16;
+               num_es_threads = 16;
+               num_hs_threads = 16;
+               num_ls_threads = 16;
+               num_ps_stack_entries = 42;
+               num_vs_stack_entries = 42;
+               num_gs_stack_entries = 42;
+               num_es_stack_entries = 42;
+               num_hs_stack_entries = 42;
+               num_ls_stack_entries = 42;
+               break;
+       case CHIP_REDWOOD:
+               num_ps_gprs = 93;
+               num_vs_gprs = 46;
+               num_temp_gprs = 4;
+               num_gs_gprs = 31;
+               num_es_gprs = 31;
+               num_hs_gprs = 23;
+               num_ls_gprs = 23;
+               num_ps_threads = 128;
+               num_vs_threads = 20;
+               num_gs_threads = 20;
+               num_es_threads = 20;
+               num_hs_threads = 20;
+               num_ls_threads = 20;
+               num_ps_stack_entries = 42;
+               num_vs_stack_entries = 42;
+               num_gs_stack_entries = 42;
+               num_es_stack_entries = 42;
+               num_hs_stack_entries = 42;
+               num_ls_stack_entries = 42;
+               break;
+       case CHIP_JUNIPER:
+               num_ps_gprs = 93;
+               num_vs_gprs = 46;
+               num_temp_gprs = 4;
+               num_gs_gprs = 31;
+               num_es_gprs = 31;
+               num_hs_gprs = 23;
+               num_ls_gprs = 23;
+               num_ps_threads = 128;
+               num_vs_threads = 20;
+               num_gs_threads = 20;
+               num_es_threads = 20;
+               num_hs_threads = 20;
+               num_ls_threads = 20;
+               num_ps_stack_entries = 85;
+               num_vs_stack_entries = 85;
+               num_gs_stack_entries = 85;
+               num_es_stack_entries = 85;
+               num_hs_stack_entries = 85;
+               num_ls_stack_entries = 85;
+               break;
+       case CHIP_CYPRESS:
+       case CHIP_HEMLOCK:
+               num_ps_gprs = 93;
+               num_vs_gprs = 46;
+               num_temp_gprs = 4;
+               num_gs_gprs = 31;
+               num_es_gprs = 31;
+               num_hs_gprs = 23;
+               num_ls_gprs = 23;
+               num_ps_threads = 128;
+               num_vs_threads = 20;
+               num_gs_threads = 20;
+               num_es_threads = 20;
+               num_hs_threads = 20;
+               num_ls_threads = 20;
+               num_ps_stack_entries = 85;
+               num_vs_stack_entries = 85;
+               num_gs_stack_entries = 85;
+               num_es_stack_entries = 85;
+               num_hs_stack_entries = 85;
+               num_ls_stack_entries = 85;
+               break;
+       }
+
+       if (rdev->family == CHIP_CEDAR)
+               sq_config = 0;
+       else
+               sq_config = VC_ENABLE;
+
+       sq_config |= (EXPORT_SRC_C |
+                     CS_PRIO(0) |
+                     LS_PRIO(0) |
+                     HS_PRIO(0) |
+                     PS_PRIO(0) |
+                     VS_PRIO(1) |
+                     GS_PRIO(2) |
+                     ES_PRIO(3));
+
+       sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) |
+                                 NUM_VS_GPRS(num_vs_gprs) |
+                                 NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
+       sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) |
+                                 NUM_ES_GPRS(num_es_gprs));
+       sq_gpr_resource_mgmt_3 = (NUM_HS_GPRS(num_hs_gprs) |
+                                 NUM_LS_GPRS(num_ls_gprs));
+       sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) |
+                                  NUM_VS_THREADS(num_vs_threads) |
+                                  NUM_GS_THREADS(num_gs_threads) |
+                                  NUM_ES_THREADS(num_es_threads));
+       sq_thread_resource_mgmt_2 = (NUM_HS_THREADS(num_hs_threads) |
+                                    NUM_LS_THREADS(num_ls_threads));
+       sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
+                                   NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
+       sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
+                                   NUM_ES_STACK_ENTRIES(num_es_stack_entries));
+       sq_stack_resource_mgmt_3 = (NUM_HS_STACK_ENTRIES(num_hs_stack_entries) |
+                                   NUM_LS_STACK_ENTRIES(num_ls_stack_entries));
+
+       /* set clear context state */
+       radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+       radeon_ring_write(rdev, 0);
+
+       /* disable dyn gprs */
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
+       radeon_ring_write(rdev, 0);
+
+       /* SQ config */
+       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
+       radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
+       radeon_ring_write(rdev, sq_config);
+       radeon_ring_write(rdev, sq_gpr_resource_mgmt_1);
+       radeon_ring_write(rdev, sq_gpr_resource_mgmt_2);
+       radeon_ring_write(rdev, sq_gpr_resource_mgmt_3);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, sq_thread_resource_mgmt);
+       radeon_ring_write(rdev, sq_thread_resource_mgmt_2);
+       radeon_ring_write(rdev, sq_stack_resource_mgmt_1);
+       radeon_ring_write(rdev, sq_stack_resource_mgmt_2);
+       radeon_ring_write(rdev, sq_stack_resource_mgmt_3);
+
+       /* CONTEXT_CONTROL */
+       radeon_ring_write(rdev, 0xc0012800);
+       radeon_ring_write(rdev, 0x80000000);
+       radeon_ring_write(rdev, 0x80000000);
+
+       /* SQ_VTX_BASE_VTX_LOC */
+       radeon_ring_write(rdev, 0xc0026f00);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000000);
+
+       /* SET_SAMPLER */
+       radeon_ring_write(rdev, 0xc0036e00);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000012);
+       radeon_ring_write(rdev, 0x00000000);
+       radeon_ring_write(rdev, 0x00000000);
+
+}
+
+static inline uint32_t i2f(uint32_t input)
+{
+       u32 result, i, exponent, fraction;
+
+       if ((input & 0x3fff) == 0)
+               result = 0; /* 0 is a special case */
+       else {
+               exponent = 140; /* exponent biased by 127; */
+               fraction = (input & 0x3fff) << 10; /* cheat and only
+                                                     handle numbers below 2^^15 */
+               for (i = 0; i < 14; i++) {
+                       if (fraction & 0x800000)
+                               break;
+                       else {
+                               fraction = fraction << 1; /* keep
+                                                            shifting left until top bit = 1 */
+                               exponent = exponent - 1;
+                       }
+               }
+               result = exponent << 23 | (fraction & 0x7fffff); /* mask
+                                                                   off top bit; assumed 1 */
+       }
+       return result;
+}
+
+int evergreen_blit_init(struct radeon_device *rdev)
+{
+       u32 obj_size;
+       int r;
+       void *ptr;
+
+       /* pin copy shader into vram if already initialized */
+       if (rdev->r600_blit.shader_obj)
+               goto done;
+
+       mutex_init(&rdev->r600_blit.mutex);
+       rdev->r600_blit.state_offset = 0;
+       rdev->r600_blit.state_len = 0;
+       obj_size = 0;
+
+       rdev->r600_blit.vs_offset = obj_size;
+       obj_size += evergreen_vs_size * 4;
+       obj_size = ALIGN(obj_size, 256);
+
+       rdev->r600_blit.ps_offset = obj_size;
+       obj_size += evergreen_ps_size * 4;
+       obj_size = ALIGN(obj_size, 256);
+
+       r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+                               &rdev->r600_blit.shader_obj);
+       if (r) {
+               DRM_ERROR("evergreen failed to allocate shader\n");
+               return r;
+       }
+
+       DRM_DEBUG("evergreen blit allocated bo %08x vs %08x ps %08x\n",
+                 obj_size,
+                 rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset);
+
+       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+       if (unlikely(r != 0))
+               return r;
+       r = radeon_bo_kmap(rdev->r600_blit.shader_obj, &ptr);
+       if (r) {
+               DRM_ERROR("failed to map blit object %d\n", r);
+               return r;
+       }
+
+       memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4);
+       memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4);
+       radeon_bo_kunmap(rdev->r600_blit.shader_obj);
+       radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+       if (unlikely(r != 0))
+               return r;
+       r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+                         &rdev->r600_blit.shader_gpu_addr);
+       radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+       if (r) {
+               dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+               return r;
+       }
+       return 0;
+}
+
+void evergreen_blit_fini(struct radeon_device *rdev)
+{
+       int r;
+
+       if (rdev->r600_blit.shader_obj == NULL)
+               return;
+       /* If we can't reserve the bo, unref should be enough to destroy
+        * it when it becomes idle.
+        */
+       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+       if (!r) {
+               radeon_bo_unpin(rdev->r600_blit.shader_obj);
+               radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+       }
+       radeon_bo_unref(&rdev->r600_blit.shader_obj);
+}
+
+static int evergreen_vb_ib_get(struct radeon_device *rdev)
+{
+       int r;
+       r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
+       if (r) {
+               DRM_ERROR("failed to get IB for vertex buffer\n");
+               return r;
+       }
+
+       rdev->r600_blit.vb_total = 64*1024;
+       rdev->r600_blit.vb_used = 0;
+       return 0;
+}
+
+static void evergreen_vb_ib_put(struct radeon_device *rdev)
+{
+       radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
+       radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+}
+
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
+{
+       int r;
+       int ring_size, line_size;
+       int max_size;
+       /* loops of emits + fence emit possible */
+       int dwords_per_loop = 74, num_loops;
+
+       r = evergreen_vb_ib_get(rdev);
+       if (r)
+               return r;
+
+       /* 8 bpp vs 32 bpp for xfer unit */
+       if (size_bytes & 3)
+               line_size = 8192;
+       else
+               line_size = 8192 * 4;
+
+       max_size = 8192 * line_size;
+
+       /* major loops cover the max size transfer */
+       num_loops = ((size_bytes + max_size) / max_size);
+       /* minor loops cover the extra non aligned bits */
+       num_loops += ((size_bytes % line_size) ? 1 : 0);
+       /* calculate number of loops correctly */
+       ring_size = num_loops * dwords_per_loop;
+       /* set default  + shaders */
+       ring_size += 46; /* shaders + def state */
+       ring_size += 10; /* fence emit for VB IB */
+       ring_size += 5; /* done copy */
+       ring_size += 10; /* fence emit for done copy */
+       r = radeon_ring_lock(rdev, ring_size);
+       if (r)
+               return r;
+
+       set_default_state(rdev); /* 30 */
+       set_shaders(rdev); /* 16 */
+       return 0;
+}
+
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
+{
+       int r;
+
+       if (rdev->r600_blit.vb_ib)
+               evergreen_vb_ib_put(rdev);
+
+       if (fence)
+               r = radeon_fence_emit(rdev, fence);
+
+       radeon_ring_unlock_commit(rdev);
+}
+
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+                            u64 src_gpu_addr, u64 dst_gpu_addr,
+                            int size_bytes)
+{
+       int max_bytes;
+       u64 vb_gpu_addr;
+       u32 *vb;
+
+       DRM_DEBUG("emitting copy %16llx %16llx %d %d\n", src_gpu_addr, dst_gpu_addr,
+                 size_bytes, rdev->r600_blit.vb_used);
+       vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
+       if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
+               max_bytes = 8192;
+
+               while (size_bytes) {
+                       int cur_size = size_bytes;
+                       int src_x = src_gpu_addr & 255;
+                       int dst_x = dst_gpu_addr & 255;
+                       int h = 1;
+                       src_gpu_addr = src_gpu_addr & ~255ULL;
+                       dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+                       if (!src_x && !dst_x) {
+                               h = (cur_size / max_bytes);
+                               if (h > 8192)
+                                       h = 8192;
+                               if (h == 0)
+                                       h = 1;
+                               else
+                                       cur_size = max_bytes;
+                       } else {
+                               if (cur_size > max_bytes)
+                                       cur_size = max_bytes;
+                               if (cur_size > (max_bytes - dst_x))
+                                       cur_size = (max_bytes - dst_x);
+                               if (cur_size > (max_bytes - src_x))
+                                       cur_size = (max_bytes - src_x);
+                       }
+
+                       if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+                               WARN_ON(1);
+                       }
+
+                       vb[0] = i2f(dst_x);
+                       vb[1] = 0;
+                       vb[2] = i2f(src_x);
+                       vb[3] = 0;
+
+                       vb[4] = i2f(dst_x);
+                       vb[5] = i2f(h);
+                       vb[6] = i2f(src_x);
+                       vb[7] = i2f(h);
+
+                       vb[8] = i2f(dst_x + cur_size);
+                       vb[9] = i2f(h);
+                       vb[10] = i2f(src_x + cur_size);
+                       vb[11] = i2f(h);
+
+                       /* src 10 */
+                       set_tex_resource(rdev, FMT_8,
+                                        src_x + cur_size, h, src_x + cur_size,
+                                        src_gpu_addr);
+
+                       /* 5 */
+                       cp_set_surface_sync(rdev,
+                                           PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+
+                       /* dst 17 */
+                       set_render_target(rdev, COLOR_8,
+                                         dst_x + cur_size, h,
+                                         dst_gpu_addr);
+
+                       /* scissors 12 */
+                       set_scissors(rdev, dst_x, 0, dst_x + cur_size, h);
+
+                       /* 15 */
+                       vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+                       set_vtx_resource(rdev, vb_gpu_addr);
+
+                       /* draw 10 */
+                       draw_auto(rdev);
+
+                       /* 5 */
+                       cp_set_surface_sync(rdev,
+                                           PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+                                           cur_size * h, dst_gpu_addr);
+
+                       vb += 12;
+                       rdev->r600_blit.vb_used += 12 * 4;
+
+                       src_gpu_addr += cur_size * h;
+                       dst_gpu_addr += cur_size * h;
+                       size_bytes -= cur_size * h;
+               }
+       } else {
+               max_bytes = 8192 * 4;
+
+               while (size_bytes) {
+                       int cur_size = size_bytes;
+                       int src_x = (src_gpu_addr & 255);
+                       int dst_x = (dst_gpu_addr & 255);
+                       int h = 1;
+                       src_gpu_addr = src_gpu_addr & ~255ULL;
+                       dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+                       if (!src_x && !dst_x) {
+                               h = (cur_size / max_bytes);
+                               if (h > 8192)
+                                       h = 8192;
+                               if (h == 0)
+                                       h = 1;
+                               else
+                                       cur_size = max_bytes;
+                       } else {
+                               if (cur_size > max_bytes)
+                                       cur_size = max_bytes;
+                               if (cur_size > (max_bytes - dst_x))
+                                       cur_size = (max_bytes - dst_x);
+                               if (cur_size > (max_bytes - src_x))
+                                       cur_size = (max_bytes - src_x);
+                       }
+
+                       if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+                               WARN_ON(1);
+                       }
+
+                       vb[0] = i2f(dst_x / 4);
+                       vb[1] = 0;
+                       vb[2] = i2f(src_x / 4);
+                       vb[3] = 0;
+
+                       vb[4] = i2f(dst_x / 4);
+                       vb[5] = i2f(h);
+                       vb[6] = i2f(src_x / 4);
+                       vb[7] = i2f(h);
+
+                       vb[8] = i2f((dst_x + cur_size) / 4);
+                       vb[9] = i2f(h);
+                       vb[10] = i2f((src_x + cur_size) / 4);
+                       vb[11] = i2f(h);
+
+                       /* src 10 */
+                       set_tex_resource(rdev, FMT_8_8_8_8,
+                                        (src_x + cur_size) / 4,
+                                        h, (src_x + cur_size) / 4,
+                                        src_gpu_addr);
+                       /* 5 */
+                       cp_set_surface_sync(rdev,
+                                           PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+                       /* dst 17 */
+                       set_render_target(rdev, COLOR_8_8_8_8,
+                                         (dst_x + cur_size) / 4, h,
+                                         dst_gpu_addr);
+
+                       /* scissors 12  */
+                       set_scissors(rdev, (dst_x / 4), 0, (dst_x + cur_size / 4), h);
+
+                       /* Vertex buffer setup 15 */
+                       vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+                       set_vtx_resource(rdev, vb_gpu_addr);
+
+                       /* draw 10 */
+                       draw_auto(rdev);
+
+                       /* 5 */
+                       cp_set_surface_sync(rdev,
+                                           PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+                                           cur_size * h, dst_gpu_addr);
+
+                       /* 74 ring dwords per loop */
+                       vb += 12;
+                       rdev->r600_blit.vb_used += 12 * 4;
+
+                       src_gpu_addr += cur_size * h;
+                       dst_gpu_addr += cur_size * h;
+                       size_bytes -= cur_size * h;
+               }
+       }
+}
+
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
new file mode 100644 (file)
index 0000000..ef1d28c
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS 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:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+/*
+ * evergreen cards need to use the 3D engine to blit data which requires
+ * quite a bit of hw state setup.  Rather than pull the whole 3D driver
+ * (which normally generates the 3D state) into the DRM, we opt to use
+ * statically generated state tables.  The regsiter state and shaders
+ * were hand generated to support blitting functionality.  See the 3D
+ * driver or documentation for descriptions of the registers and
+ * shader instructions.
+ */
+
+const u32 evergreen_default_state[] =
+{
+       0xc0016900,
+       0x0000023b,
+       0x00000000, /* SQ_LDS_ALLOC_PS */
+
+       0xc0066900,
+       0x00000240,
+       0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       0xc0046900,
+       0x00000247,
+       0x00000000, /* SQ_GS_VERT_ITEMSIZE */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       0xc0026900,
+       0x00000010,
+       0x00000000, /* DB_Z_INFO */
+       0x00000000, /* DB_STENCIL_INFO */
+
+       0xc0016900,
+       0x00000200,
+       0x00000000, /* DB_DEPTH_CONTROL */
+
+       0xc0066900,
+       0x00000000,
+       0x00000060, /* DB_RENDER_CONTROL */
+       0x00000000, /* DB_COUNT_CONTROL */
+       0x00000000, /* DB_DEPTH_VIEW */
+       0x0000002a, /* DB_RENDER_OVERRIDE */
+       0x00000000, /* DB_RENDER_OVERRIDE2 */
+       0x00000000, /* DB_HTILE_DATA_BASE */
+
+       0xc0026900,
+       0x0000000a,
+       0x00000000, /* DB_STENCIL_CLEAR */
+       0x00000000, /* DB_DEPTH_CLEAR */
+
+       0xc0016900,
+       0x000002dc,
+       0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+       0xc0016900,
+       0x00000080,
+       0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+       0xc00d6900,
+       0x00000083,
+       0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+       0x00000000, /* PA_SC_CLIPRECT_0_TL */
+       0x20002000, /* PA_SC_CLIPRECT_0_BR */
+       0x00000000,
+       0x20002000,
+       0x00000000,
+       0x20002000,
+       0x00000000,
+       0x20002000,
+       0xaaaaaaaa, /* PA_SC_EDGERULE */
+       0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+       0x0000000f, /* CB_TARGET_MASK */
+       0x0000000f, /* CB_SHADER_MASK */
+
+       0xc0226900,
+       0x00000094,
+       0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+       0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+       0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+       0xc0016900,
+       0x000000d4,
+       0x00000000, /* SX_MISC */
+
+       0xc0026900,
+       0x00000292,
+       0x00000000, /* PA_SC_MODE_CNTL_0 */
+       0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+       0xc0106900,
+       0x00000300,
+       0x00000000, /* PA_SC_LINE_CNTL */
+       0x00000000, /* PA_SC_AA_CONFIG */
+       0x00000005, /* PA_SU_VTX_CNTL */
+       0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+       0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+       0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+       0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+       0x00000000, /* PA_SC_AA_SAMPLE_LOCS_0 */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /* PA_SC_AA_SAMPLE_LOCS_7 */
+       0xffffffff, /* PA_SC_AA_MASK */
+
+       0xc00d6900,
+       0x00000202,
+       0x00cc0010, /* CB_COLOR_CONTROL */
+       0x00000210, /* DB_SHADER_CONTROL */
+       0x00010000, /* PA_CL_CLIP_CNTL */
+       0x00000004, /* PA_SU_SC_MODE_CNTL */
+       0x00000100, /* PA_CL_VTE_CNTL */
+       0x00000000, /* PA_CL_VS_OUT_CNTL */
+       0x00000000, /* PA_CL_NANINF_CNTL */
+       0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+       0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+       0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /* SQ_DYN_GPR_RESOURCE_LIMIT_1 */
+
+       0xc0066900,
+       0x000002de,
+       0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+
+       0xc0016900,
+       0x00000229,
+       0x00000000, /* SQ_PGM_START_FS */
+
+       0xc0016900,
+       0x0000022a,
+       0x00000000, /* SQ_PGM_RESOURCES_FS */
+
+       0xc0096900,
+       0x00000100,
+       0x00ffffff, /* VGT_MAX_VTX_INDX */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /* SX_ALPHA_TEST_CONTROL */
+       0x00000000, /* CB_BLEND_RED */
+       0x00000000, /* CB_BLEND_GREEN */
+       0x00000000, /* CB_BLEND_BLUE */
+       0x00000000, /* CB_BLEND_ALPHA */
+
+       0xc0026900,
+       0x000002a8,
+       0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+       0x00000000, /*  */
+
+       0xc0026900,
+       0x000002ad,
+       0x00000000, /* VGT_REUSE_OFF */
+       0x00000000, /*  */
+
+       0xc0116900,
+       0x00000280,
+       0x00000000, /* PA_SU_POINT_SIZE */
+       0x00000000, /* PA_SU_POINT_MINMAX */
+       0x00000008, /* PA_SU_LINE_CNTL */
+       0x00000000, /* PA_SC_LINE_STIPPLE */
+       0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+       0x00000000, /* VGT_HOS_CNTL */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /* VGT_GS_MODE */
+
+       0xc0016900,
+       0x000002a1,
+       0x00000000, /* VGT_PRIMITIVEID_EN */
+
+       0xc0016900,
+       0x000002a5,
+       0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+       0xc0016900,
+       0x000002d5,
+       0x00000000, /* VGT_SHADER_STAGES_EN */
+
+       0xc0026900,
+       0x000002e5,
+       0x00000000, /* VGT_STRMOUT_CONFIG */
+       0x00000000, /*  */
+
+       0xc0016900,
+       0x000001e0,
+       0x00000000, /* CB_BLEND0_CONTROL */
+
+       0xc0016900,
+       0x000001b1,
+       0x00000000, /* SPI_VS_OUT_CONFIG */
+
+       0xc0016900,
+       0x00000187,
+       0x00000000, /* SPI_VS_OUT_ID_0 */
+
+       0xc0016900,
+       0x00000191,
+       0x00000100, /* SPI_PS_INPUT_CNTL_0 */
+
+       0xc00b6900,
+       0x000001b3,
+       0x20000001, /* SPI_PS_IN_CONTROL_0 */
+       0x00000000, /* SPI_PS_IN_CONTROL_1 */
+       0x00000000, /* SPI_INTERP_CONTROL_0 */
+       0x00000000, /* SPI_INPUT_Z */
+       0x00000000, /* SPI_FOG_CNTL */
+       0x00100000, /* SPI_BARYC_CNTL */
+       0x00000000, /* SPI_PS_IN_CONTROL_2 */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+       0x00000000, /*  */
+
+       0xc0026900,
+       0x00000316,
+       0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+       0x00000010, /*  */
+};
+
+const u32 evergreen_vs[] =
+{
+       0x00000004,
+       0x80800400,
+       0x0000a03c,
+       0x95000688,
+       0x00004000,
+       0x15200688,
+       0x00000000,
+       0x00000000,
+       0x3c000000,
+       0x67961001,
+       0x00080000,
+       0x00000000,
+       0x1c000000,
+       0x67961000,
+       0x00000008,
+       0x00000000,
+};
+
+const u32 evergreen_ps[] =
+{
+       0x00000003,
+       0xa00c0000,
+       0x00000008,
+       0x80400000,
+       0x00000000,
+       0x95200688,
+       0x00380400,
+       0x00146b10,
+       0x00380000,
+       0x20146b10,
+       0x00380400,
+       0x40146b00,
+       0x80380000,
+       0x60146b00,
+       0x00000000,
+       0x00000000,
+       0x00000010,
+       0x000d1000,
+       0xb0800000,
+       0x00000000,
+};
+
+const u32 evergreen_ps_size = ARRAY_SIZE(evergreen_ps);
+const u32 evergreen_vs_size = ARRAY_SIZE(evergreen_vs);
+const u32 evergreen_default_size = ARRAY_SIZE(evergreen_default_state);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.h b/drivers/gpu/drm/radeon/evergreen_blit_shaders.h
new file mode 100644 (file)
index 0000000..bb8d6c7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS 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 EVERGREEN_BLIT_SHADERS_H
+#define EVERGREEN_BLIT_SHADERS_H
+
+extern const u32 evergreen_ps[];
+extern const u32 evergreen_vs[];
+extern const u32 evergreen_default_state[];
+
+extern const u32 evergreen_ps_size, evergreen_vs_size;
+extern const u32 evergreen_default_size;
+
+#endif
index 9b7532dd30f754d4ad2e3e02915006ae823538f2..113c70cc8b3930eba7170a94f2c75b9f62e07c1d 100644 (file)
 #define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
+/* display watermarks */
+#define        DC_LB_MEMORY_SPLIT                                0x6b0c
+#define        PRIORITY_A_CNT                                    0x6b18
+#define                PRIORITY_MARK_MASK                        0x7fff
+#define                PRIORITY_OFF                              (1 << 16)
+#define                PRIORITY_ALWAYS_ON                        (1 << 20)
+#define        PRIORITY_B_CNT                                    0x6b1c
+#define        PIPE0_ARBITRATION_CONTROL3                        0x0bf0
+#       define LATENCY_WATERMARK_MASK(x)                  ((x) << 16)
+#define        PIPE0_LATENCY_CONTROL                             0x0bf4
+#       define LATENCY_LOW_WATERMARK(x)                   ((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)                  ((x) << 16)
+
 #define IH_RB_CNTL                                        0x3e00
 #       define IH_RB_ENABLE                               (1 << 0)
 #       define IH_IB_SIZE(x)                              ((x) << 1) /* log2 */
 #define        PACKET3_EVENT_WRITE_EOP                         0x47
 #define        PACKET3_EVENT_WRITE_EOS                         0x48
 #define        PACKET3_PREAMBLE_CNTL                           0x4A
+#              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)
+#              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)
 #define        PACKET3_RB_OFFSET                               0x4B
 #define        PACKET3_ALU_PS_CONST_BUFFER_COPY                0x4C
 #define        PACKET3_ALU_VS_CONST_BUFFER_COPY                0x4D
 #define SQ_ALU_CONST_CACHE_LS_14                       0x28f78
 #define SQ_ALU_CONST_CACHE_LS_15                       0x28f7c
 
+#define PA_SC_SCREEN_SCISSOR_TL                         0x28030
+#define PA_SC_GENERIC_SCISSOR_TL                        0x28240
+#define PA_SC_WINDOW_SCISSOR_TL                         0x28204
+#define VGT_PRIMITIVE_TYPE                              0x8958
+
 #define DB_DEPTH_CONTROL                               0x28800
 #define DB_DEPTH_VIEW                                  0x28008
 #define DB_HTILE_DATA_BASE                             0x28014
index e59422320bb6df9873fbf88f9e29d34fdc412110..6d1540c0bfed1c192e258bb2a4c65b74e559b2a0 100644 (file)
@@ -675,67 +675,6 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
 }
 
-int r100_wb_init(struct radeon_device *rdev)
-{
-       int r;
-
-       if (rdev->wb.wb_obj == NULL) {
-               r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
-                                       RADEON_GEM_DOMAIN_GTT,
-                                       &rdev->wb.wb_obj);
-               if (r) {
-                       dev_err(rdev->dev, "(%d) create WB buffer failed\n", r);
-                       return r;
-               }
-               r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-               if (unlikely(r != 0))
-                       return r;
-               r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
-                                       &rdev->wb.gpu_addr);
-               if (r) {
-                       dev_err(rdev->dev, "(%d) pin WB buffer failed\n", r);
-                       radeon_bo_unreserve(rdev->wb.wb_obj);
-                       return r;
-               }
-               r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
-               radeon_bo_unreserve(rdev->wb.wb_obj);
-               if (r) {
-                       dev_err(rdev->dev, "(%d) map WB buffer failed\n", r);
-                       return r;
-               }
-       }
-       WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr);
-       WREG32(R_00070C_CP_RB_RPTR_ADDR,
-               S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + 1024) >> 2));
-       WREG32(R_000770_SCRATCH_UMSK, 0xff);
-       return 0;
-}
-
-void r100_wb_disable(struct radeon_device *rdev)
-{
-       WREG32(R_000770_SCRATCH_UMSK, 0);
-}
-
-void r100_wb_fini(struct radeon_device *rdev)
-{
-       int r;
-
-       r100_wb_disable(rdev);
-       if (rdev->wb.wb_obj) {
-               r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-               if (unlikely(r != 0)) {
-                       dev_err(rdev->dev, "(%d) can't finish WB\n", r);
-                       return;
-               }
-               radeon_bo_kunmap(rdev->wb.wb_obj);
-               radeon_bo_unpin(rdev->wb.wb_obj);
-               radeon_bo_unreserve(rdev->wb.wb_obj);
-               radeon_bo_unref(&rdev->wb.wb_obj);
-               rdev->wb.wb = NULL;
-               rdev->wb.wb_obj = NULL;
-       }
-}
-
 int r100_copy_blit(struct radeon_device *rdev,
                   uint64_t src_offset,
                   uint64_t dst_offset,
@@ -996,20 +935,32 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
        WREG32(0x718, pre_write_timer | (pre_write_limit << 28));
        tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) |
               REG_SET(RADEON_RB_BLKSZ, rb_blksz) |
-              REG_SET(RADEON_MAX_FETCH, max_fetch) |
-              RADEON_RB_NO_UPDATE);
+              REG_SET(RADEON_MAX_FETCH, max_fetch));
 #ifdef __BIG_ENDIAN
        tmp |= RADEON_BUF_SWAP_32BIT;
 #endif
-       WREG32(RADEON_CP_RB_CNTL, tmp);
+       WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE);
 
        /* Set ring address */
        DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr);
        WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr);
        /* Force read & write ptr to 0 */
-       WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+       WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE);
        WREG32(RADEON_CP_RB_RPTR_WR, 0);
        WREG32(RADEON_CP_RB_WPTR, 0);
+
+       /* set the wb address whether it's enabled or not */
+       WREG32(R_00070C_CP_RB_RPTR_ADDR,
+               S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) >> 2));
+       WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET);
+
+       if (rdev->wb.enabled)
+               WREG32(R_000770_SCRATCH_UMSK, 0xff);
+       else {
+               tmp |= RADEON_RB_NO_UPDATE;
+               WREG32(R_000770_SCRATCH_UMSK, 0);
+       }
+
        WREG32(RADEON_CP_RB_CNTL, tmp);
        udelay(10);
        rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
@@ -1052,6 +1003,7 @@ void r100_cp_disable(struct radeon_device *rdev)
        rdev->cp.ready = false;
        WREG32(RADEON_CP_CSQ_MODE, 0);
        WREG32(RADEON_CP_CSQ_CNTL, 0);
+       WREG32(R_000770_SCRATCH_UMSK, 0);
        if (r100_gui_wait_for_idle(rdev)) {
                printk(KERN_WARNING "Failed to wait GUI idle while "
                       "programming pipes. Bad things might happen.\n");
@@ -2318,6 +2270,9 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
                /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - 
                 * Novell bug 204882 + along with lots of ubuntu ones
                 */
+               if (rdev->mc.aper_size > config_aper_size)
+                       config_aper_size = rdev->mc.aper_size;
+
                if (config_aper_size > rdev->mc.real_vram_size)
                        rdev->mc.mc_vram_size = config_aper_size;
                else
@@ -3737,6 +3692,12 @@ static int r100_startup(struct radeon_device *rdev)
                if (r)
                        return r;
        }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r100_irq_set(rdev);
        rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -3746,9 +3707,6 @@ static int r100_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -3782,7 +3740,7 @@ int r100_resume(struct radeon_device *rdev)
 int r100_suspend(struct radeon_device *rdev)
 {
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
        if (rdev->flags & RADEON_IS_PCI)
                r100_pci_gart_disable(rdev);
@@ -3792,7 +3750,7 @@ int r100_suspend(struct radeon_device *rdev)
 void r100_fini(struct radeon_device *rdev)
 {
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        if (rdev->flags & RADEON_IS_PCI)
@@ -3905,7 +3863,7 @@ int r100_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                radeon_irq_kms_fini(rdev);
                if (rdev->flags & RADEON_IS_PCI)
index c827738ad7ddbe620323937f97c5cc8953365338..34527e600fe94f91ab33da78285b695afbb6cd6e 100644 (file)
@@ -1332,6 +1332,12 @@ static int r300_startup(struct radeon_device *rdev)
                if (r)
                        return r;
        }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r100_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -1341,9 +1347,6 @@ static int r300_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -1379,7 +1382,7 @@ int r300_resume(struct radeon_device *rdev)
 int r300_suspend(struct radeon_device *rdev)
 {
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
        if (rdev->flags & RADEON_IS_PCIE)
                rv370_pcie_gart_disable(rdev);
@@ -1391,7 +1394,7 @@ int r300_suspend(struct radeon_device *rdev)
 void r300_fini(struct radeon_device *rdev)
 {
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        if (rdev->flags & RADEON_IS_PCIE)
@@ -1484,7 +1487,7 @@ int r300_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                radeon_irq_kms_fini(rdev);
                if (rdev->flags & RADEON_IS_PCIE)
index 59f7bccc5be0a291dcf0fcfb9487080ea93d5693..c387346f93a9d5a924bc6aab769e92aebba8fe91 100644 (file)
@@ -248,6 +248,12 @@ static int r420_startup(struct radeon_device *rdev)
                        return r;
        }
        r420_pipes_init(rdev);
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r100_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -258,10 +264,6 @@ static int r420_startup(struct radeon_device *rdev)
                return r;
        }
        r420_cp_errata_init(rdev);
-       r = r100_wb_init(rdev);
-       if (r) {
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
-       }
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -302,7 +304,7 @@ int r420_suspend(struct radeon_device *rdev)
 {
        r420_cp_errata_fini(rdev);
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
        if (rdev->flags & RADEON_IS_PCIE)
                rv370_pcie_gart_disable(rdev);
@@ -314,7 +316,7 @@ int r420_suspend(struct radeon_device *rdev)
 void r420_fini(struct radeon_device *rdev)
 {
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        if (rdev->flags & RADEON_IS_PCIE)
@@ -418,7 +420,7 @@ int r420_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                radeon_irq_kms_fini(rdev);
                if (rdev->flags & RADEON_IS_PCIE)
index 1458dee902dd6124db7c11d3c74911220c7648de..3c8677f9e38550f05e9940fd12a728d8178a58c8 100644 (file)
@@ -181,6 +181,12 @@ static int r520_startup(struct radeon_device *rdev)
                if (r)
                        return r;
        }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        rs600_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -190,9 +196,6 @@ static int r520_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -295,7 +298,7 @@ int r520_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                radeon_irq_kms_fini(rdev);
                rv370_pcie_gart_fini(rdev);
index 7b65e4efe8af61e2df5404ea52c468fe8ee564db..33952a12f0a31a49986a248a39c38cb48cdf618c 100644 (file)
@@ -1608,8 +1608,11 @@ void r600_gpu_init(struct radeon_device *rdev)
        rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes;
        rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
        tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
-       tiling_config |= GROUP_SIZE(0);
-       rdev->config.r600.tiling_group_size = 256;
+       tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+       if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+               rdev->config.r600.tiling_group_size = 512;
+       else
+               rdev->config.r600.tiling_group_size = 256;
        tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
        if (tmp > 3) {
                tiling_config |= ROW_TILING(3);
@@ -1920,6 +1923,7 @@ void r600_cp_stop(struct radeon_device *rdev)
 {
        rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
+       WREG32(SCRATCH_UMSK, 0);
 }
 
 int r600_init_microcode(struct radeon_device *rdev)
@@ -2152,7 +2156,7 @@ int r600_cp_resume(struct radeon_device *rdev)
 
        /* Set ring buffer size */
        rb_bufsz = drm_order(rdev->cp.ring_size / 8);
-       tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -2166,8 +2170,19 @@ int r600_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
        WREG32(CP_RB_RPTR_WR, 0);
        WREG32(CP_RB_WPTR, 0);
-       WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
-       WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+       /* set the wb address whether it's enabled or not */
+       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+       WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+       if (rdev->wb.enabled)
+               WREG32(SCRATCH_UMSK, 0xff);
+       else {
+               tmp |= RB_NO_UPDATE;
+               WREG32(SCRATCH_UMSK, 0);
+       }
+
        mdelay(1);
        WREG32(CP_RB_CNTL, tmp);
 
@@ -2219,9 +2234,10 @@ void r600_scratch_init(struct radeon_device *rdev)
        int i;
 
        rdev->scratch.num_reg = 7;
+       rdev->scratch.reg_base = SCRATCH_REG0;
        for (i = 0; i < rdev->scratch.num_reg; i++) {
                rdev->scratch.free[i] = true;
-               rdev->scratch.reg[i] = SCRATCH_REG0 + (i * 4);
+               rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
        }
 }
 
@@ -2265,88 +2281,34 @@ int r600_ring_test(struct radeon_device *rdev)
        return r;
 }
 
-void r600_wb_disable(struct radeon_device *rdev)
-{
-       int r;
-
-       WREG32(SCRATCH_UMSK, 0);
-       if (rdev->wb.wb_obj) {
-               r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-               if (unlikely(r != 0))
-                       return;
-               radeon_bo_kunmap(rdev->wb.wb_obj);
-               radeon_bo_unpin(rdev->wb.wb_obj);
-               radeon_bo_unreserve(rdev->wb.wb_obj);
-       }
-}
-
-void r600_wb_fini(struct radeon_device *rdev)
-{
-       r600_wb_disable(rdev);
-       if (rdev->wb.wb_obj) {
-               radeon_bo_unref(&rdev->wb.wb_obj);
-               rdev->wb.wb = NULL;
-               rdev->wb.wb_obj = NULL;
-       }
-}
-
-int r600_wb_enable(struct radeon_device *rdev)
-{
-       int r;
-
-       if (rdev->wb.wb_obj == NULL) {
-               r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
-                               RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
-               if (r) {
-                       dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
-                       return r;
-               }
-               r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-               if (unlikely(r != 0)) {
-                       r600_wb_fini(rdev);
-                       return r;
-               }
-               r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
-                               &rdev->wb.gpu_addr);
-               if (r) {
-                       radeon_bo_unreserve(rdev->wb.wb_obj);
-                       dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
-                       r600_wb_fini(rdev);
-                       return r;
-               }
-               r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
-               radeon_bo_unreserve(rdev->wb.wb_obj);
-               if (r) {
-                       dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
-                       r600_wb_fini(rdev);
-                       return r;
-               }
-       }
-       WREG32(SCRATCH_ADDR, (rdev->wb.gpu_addr >> 8) & 0xFFFFFFFF);
-       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + 1024) & 0xFFFFFFFC);
-       WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + 1024) & 0xFF);
-       WREG32(SCRATCH_UMSK, 0xff);
-       return 0;
-}
-
 void r600_fence_ring_emit(struct radeon_device *rdev,
                          struct radeon_fence *fence)
 {
-       /* Also consider EVENT_WRITE_EOP.  it handles the interrupts + timestamps + events */
-
-       radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
-       radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
-       /* wait for 3D idle clean */
-       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-       radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
-       radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
-       /* Emit fence sequence & fire IRQ */
-       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-       radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
-       radeon_ring_write(rdev, fence->seq);
-       /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
-       radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
-       radeon_ring_write(rdev, RB_INT_STAT);
+       if (rdev->wb.use_event) {
+               u64 addr = rdev->wb.gpu_addr + R600_WB_EVENT_OFFSET +
+                       (u64)(rdev->fence_drv.scratch_reg - rdev->scratch.reg_base);
+               /* EVENT_WRITE_EOP - flush caches, send int */
+               radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+               radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5));
+               radeon_ring_write(rdev, addr & 0xffffffff);
+               radeon_ring_write(rdev, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));
+               radeon_ring_write(rdev, fence->seq);
+               radeon_ring_write(rdev, 0);
+       } else {
+               radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
+               radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT) | EVENT_INDEX(0));
+               /* wait for 3D idle clean */
+               radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+               radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+               radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
+               /* Emit fence sequence & fire IRQ */
+               radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+               radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
+               radeon_ring_write(rdev, fence->seq);
+               /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
+               radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
+               radeon_ring_write(rdev, RB_INT_STAT);
+       }
 }
 
 int r600_copy_blit(struct radeon_device *rdev,
@@ -2428,19 +2390,12 @@ int r600_startup(struct radeon_device *rdev)
                rdev->asic->copy = NULL;
                dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
        }
-       /* pin copy shader into vram */
-       if (rdev->r600_blit.shader_obj) {
-               r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-               if (unlikely(r != 0))
-                       return r;
-               r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-                               &rdev->r600_blit.shader_gpu_addr);
-               radeon_bo_unreserve(rdev->r600_blit.shader_obj);
-               if (r) {
-                       dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
-                       return r;
-               }
-       }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r = r600_irq_init(rdev);
        if (r) {
@@ -2459,8 +2414,7 @@ int r600_startup(struct radeon_device *rdev)
        r = r600_cp_resume(rdev);
        if (r)
                return r;
-       /* write back buffer are not vital so don't worry about failure */
-       r600_wb_enable(rdev);
+
        return 0;
 }
 
@@ -2519,7 +2473,7 @@ int r600_suspend(struct radeon_device *rdev)
        r600_cp_stop(rdev);
        rdev->cp.ready = false;
        r600_irq_suspend(rdev);
-       r600_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        r600_pcie_gart_disable(rdev);
        /* unpin shaders bo */
        if (rdev->r600_blit.shader_obj) {
@@ -2616,8 +2570,8 @@ int r600_init(struct radeon_device *rdev)
        if (r) {
                dev_err(rdev->dev, "disabling GPU acceleration\n");
                r600_cp_fini(rdev);
-               r600_wb_fini(rdev);
                r600_irq_fini(rdev);
+               radeon_wb_fini(rdev);
                radeon_irq_kms_fini(rdev);
                r600_pcie_gart_fini(rdev);
                rdev->accel_working = false;
@@ -2647,8 +2601,8 @@ void r600_fini(struct radeon_device *rdev)
        r600_audio_fini(rdev);
        r600_blit_fini(rdev);
        r600_cp_fini(rdev);
-       r600_wb_fini(rdev);
        r600_irq_fini(rdev);
+       radeon_wb_fini(rdev);
        radeon_irq_kms_fini(rdev);
        r600_pcie_gart_fini(rdev);
        radeon_agp_fini(rdev);
@@ -2983,10 +2937,13 @@ int r600_irq_init(struct radeon_device *rdev)
        ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
                      IH_WPTR_OVERFLOW_CLEAR |
                      (rb_bufsz << 1));
-       /* WPTR writeback, not yet */
-       /*ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;*/
-       WREG32(IH_RB_WPTR_ADDR_LO, 0);
-       WREG32(IH_RB_WPTR_ADDR_HI, 0);
+
+       if (rdev->wb.enabled)
+               ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+       /* set the writeback address whether it's enabled or not */
+       WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
 
        WREG32(IH_RB_CNTL, ih_rb_cntl);
 
@@ -3070,6 +3027,7 @@ int r600_irq_set(struct radeon_device *rdev)
        if (rdev->irq.sw_int) {
                DRM_DEBUG("r600_irq_set: sw int\n");
                cp_int_cntl |= RB_INT_ENABLE;
+               cp_int_cntl |= TIME_STAMP_INT_ENABLE;
        }
        if (rdev->irq.crtc_vblank_int[0]) {
                DRM_DEBUG("r600_irq_set: vblank 0\n");
@@ -3244,8 +3202,10 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
 {
        u32 wptr, tmp;
 
-       /* XXX use writeback */
-       wptr = RREG32(IH_RB_WPTR);
+       if (rdev->wb.enabled)
+               wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+       else
+               wptr = RREG32(IH_RB_WPTR);
 
        if (wptr & RB_OVERFLOW) {
                /* When a ring buffer overflow happen start parsing interrupt
@@ -3433,6 +3393,7 @@ restart_ih:
                        break;
                case 181: /* CP EOP event */
                        DRM_DEBUG("IH: CP EOP\n");
+                       radeon_fence_process(rdev);
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: CP EOP\n");
index 3473c00781ffaaac06cab0c520231a5a66a21111..8362974ef41ac9eac713f1e66377661aa7106c0b 100644 (file)
@@ -472,9 +472,10 @@ int r600_blit_init(struct radeon_device *rdev)
        u32 packet2s[16];
        int num_packet2s = 0;
 
-       /* don't reinitialize blit */
+       /* pin copy shader into vram if already initialized */
        if (rdev->r600_blit.shader_obj)
-               return 0;
+               goto done;
+
        mutex_init(&rdev->r600_blit.mutex);
        rdev->r600_blit.state_offset = 0;
 
@@ -532,6 +533,18 @@ int r600_blit_init(struct radeon_device *rdev)
        memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+       if (unlikely(r != 0))
+               return r;
+       r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+                         &rdev->r600_blit.shader_gpu_addr);
+       radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+       if (r) {
+               dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+               return r;
+       }
        rdev->mc.active_vram_size = rdev->mc.real_vram_size;
        return 0;
 }
@@ -554,7 +567,7 @@ void r600_blit_fini(struct radeon_device *rdev)
        radeon_bo_unref(&rdev->r600_blit.shader_obj);
 }
 
-int r600_vb_ib_get(struct radeon_device *rdev)
+static int r600_vb_ib_get(struct radeon_device *rdev)
 {
        int r;
        r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
@@ -568,7 +581,7 @@ int r600_vb_ib_get(struct radeon_device *rdev)
        return 0;
 }
 
-void r600_vb_ib_put(struct radeon_device *rdev)
+static void r600_vb_ib_put(struct radeon_device *rdev)
 {
        radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
        radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
@@ -650,8 +663,8 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        int src_x = src_gpu_addr & 255;
                        int dst_x = dst_gpu_addr & 255;
                        int h = 1;
-                       src_gpu_addr = src_gpu_addr & ~255;
-                       dst_gpu_addr = dst_gpu_addr & ~255;
+                       src_gpu_addr = src_gpu_addr & ~255ULL;
+                       dst_gpu_addr = dst_gpu_addr & ~255ULL;
 
                        if (!src_x && !dst_x) {
                                h = (cur_size / max_bytes);
@@ -672,17 +685,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
 
                        if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
                                WARN_ON(1);
-
-#if 0
-                               r600_vb_ib_put(rdev);
-
-                               r600_nomm_put_vb(dev);
-                               r600_nomm_get_vb(dev);
-                               if (!dev_priv->blit_vb)
-                                       return;
-                               set_shaders(dev);
-                               vb = r600_nomm_get_vb_ptr(dev);
-#endif
                        }
 
                        vb[0] = i2f(dst_x);
@@ -744,8 +746,8 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        int src_x = (src_gpu_addr & 255);
                        int dst_x = (dst_gpu_addr & 255);
                        int h = 1;
-                       src_gpu_addr = src_gpu_addr & ~255;
-                       dst_gpu_addr = dst_gpu_addr & ~255;
+                       src_gpu_addr = src_gpu_addr & ~255ULL;
+                       dst_gpu_addr = dst_gpu_addr & ~255ULL;
 
                        if (!src_x && !dst_x) {
                                h = (cur_size / max_bytes);
@@ -767,17 +769,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
                                WARN_ON(1);
                        }
-#if 0
-                       if ((rdev->blit_vb->used + 48) > rdev->blit_vb->total) {
-                               r600_nomm_put_vb(dev);
-                               r600_nomm_get_vb(dev);
-                               if (!rdev->blit_vb)
-                                       return;
-
-                               set_shaders(dev);
-                               vb = r600_nomm_get_vb_ptr(dev);
-                       }
-#endif
 
                        vb[0] = i2f(dst_x / 4);
                        vb[1] = 0;
index 250a3a918193e9821aa6f5836d463553cf6f903d..7b294c127c5ff7c5000174390bb600767870eff5 100644 (file)
@@ -170,6 +170,7 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        struct r600_cs_track *track = p->track;
        u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
        volatile u32 *ib = p->ib->ptr;
+       unsigned array_mode;
 
        if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
                dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
@@ -185,12 +186,12 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        /* pitch is the number of 8x8 tiles per row */
        pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
        slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
-       height = size / (pitch * 8 * bpe);
+       slice_tile_max *= 64;
+       height = slice_tile_max / (pitch * 8);
        if (height > 8192)
                height = 8192;
-       if (height > 7)
-               height &= ~0x7;
-       switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
+       array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+       switch (array_mode) {
        case V_0280A0_ARRAY_LINEAR_GENERAL:
                /* technically height & 0x7 */
                break;
@@ -214,6 +215,9 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                                 __func__, __LINE__, pitch);
                        return -EINVAL;
                }
+               /* avoid breaking userspace */
+               if (height > 7)
+                       height &= ~0x7;
                if (!IS_ALIGNED(height, 8)) {
                        dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
                                 __func__, __LINE__, height);
@@ -222,13 +226,13 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                break;
        case V_0280A0_ARRAY_2D_TILED_THIN1:
                pitch_align = max((u32)track->nbanks,
-                                 (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks));
+                                 (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
                if (!IS_ALIGNED(pitch, pitch_align)) {
                        dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
                                __func__, __LINE__, pitch);
                        return -EINVAL;
                }
-               if (!IS_ALIGNED((height / 8), track->nbanks)) {
+               if (!IS_ALIGNED((height / 8), track->npipes)) {
                        dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
                                 __func__, __LINE__, height);
                        return -EINVAL;
@@ -243,8 +247,18 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        /* check offset */
        tmp = height * pitch * 8 * bpe;
        if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
-               dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]);
-               return -EINVAL;
+               if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
+                       /* the initial DDX does bad things with the CB size occasionally */
+                       /* it rounds up height too far for slice tile max but the BO is smaller */
+                       tmp = (height - 7) * 8 * bpe;
+                       if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
+                               dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+                               return -EINVAL;
+                       }
+               } else {
+                       dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+                       return -EINVAL;
+               }
        }
        if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
                dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
@@ -361,13 +375,13 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                                break;
                        case V_028010_ARRAY_2D_TILED_THIN1:
                                pitch_align = max((u32)track->nbanks,
-                                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+                                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
                                if (!IS_ALIGNED(pitch, pitch_align)) {
                                        dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
                                                 __func__, __LINE__, pitch);
                                        return -EINVAL;
                                }
-                               if ((height / 8) & (track->nbanks - 1)) {
+                               if (!IS_ALIGNED((height / 8), track->npipes)) {
                                        dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
                                                 __func__, __LINE__, height);
                                        return -EINVAL;
@@ -1138,7 +1152,7 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
                break;
        case V_038000_ARRAY_2D_TILED_THIN1:
                pitch_align = max((u32)track->nbanks,
-                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
                if (!IS_ALIGNED(pitch, pitch_align)) {
                        dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
                                __func__, __LINE__, pitch);
index 858a1920c0d76bb2c916c847c8b2751058d7e9d5..966a793e225b79a5bfdf3f8bf4c1f413ee2b3dc5 100644 (file)
 #define        VGT_VERTEX_REUSE_BLOCK_CNTL                     0x28C58
 #define                VTX_REUSE_DEPTH_MASK                            0x000000FF
 #define VGT_EVENT_INITIATOR                             0x28a90
+#       define CACHE_FLUSH_AND_INV_EVENT_TS                     (0x14 << 0)
 #       define CACHE_FLUSH_AND_INV_EVENT                        (0x16 << 0)
 
 #define VM_CONTEXT0_CNTL                               0x1410
 #define                PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
 #define        PACKET3_COND_WRITE                              0x45
 #define        PACKET3_EVENT_WRITE                             0x46
+#define                EVENT_TYPE(x)                           ((x) << 0)
+#define                EVENT_INDEX(x)                          ((x) << 8)
+                /* 0 - any non-TS event
+                * 1 - ZPASS_DONE
+                * 2 - SAMPLE_PIPELINESTAT
+                * 3 - SAMPLE_STREAMOUTSTAT*
+                * 4 - *S_PARTIAL_FLUSH
+                * 5 - TS events
+                */
 #define        PACKET3_EVENT_WRITE_EOP                         0x47
+#define                DATA_SEL(x)                             ((x) << 29)
+                /* 0 - discard
+                * 1 - send low 32bit data
+                * 2 - send 64bit data
+                * 3 - send 64bit counter value
+                */
+#define                INT_SEL(x)                              ((x) << 24)
+                /* 0 - none
+                * 1 - interrupt only (DATA_SEL = 0)
+                * 2 - interrupt when data write is confirmed
+                */
 #define        PACKET3_ONE_REG_WRITE                           0x57
 #define        PACKET3_SET_CONFIG_REG                          0x68
 #define                PACKET3_SET_CONFIG_REG_OFFSET                   0x00008000
index 9ff38c99a6ea0e568f2567c0a7ad34b06e60e512..73f600d39ad4bb79c4dfdeddee97972a8caeaec0 100644 (file)
@@ -88,7 +88,6 @@ extern int radeon_benchmarking;
 extern int radeon_testing;
 extern int radeon_connector_table;
 extern int radeon_tv;
-extern int radeon_new_pll;
 extern int radeon_audio;
 extern int radeon_disp_priority;
 extern int radeon_hw_i2c;
@@ -366,6 +365,7 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev);
  */
 struct radeon_scratch {
        unsigned                num_reg;
+       uint32_t                reg_base;
        bool                    free[32];
        uint32_t                reg[32];
 };
@@ -594,8 +594,15 @@ struct radeon_wb {
        struct radeon_bo        *wb_obj;
        volatile uint32_t       *wb;
        uint64_t                gpu_addr;
+       bool                    enabled;
+       bool                    use_event;
 };
 
+#define RADEON_WB_SCRATCH_OFFSET 0
+#define RADEON_WB_CP_RPTR_OFFSET 1024
+#define R600_WB_IH_WPTR_OFFSET   2048
+#define R600_WB_EVENT_OFFSET     3072
+
 /**
  * struct radeon_pm - power management datas
  * @max_bandwidth:      maximum bandwidth the gpu has (MByte/s)
@@ -1124,6 +1131,12 @@ void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
 void r600_kms_blit_copy(struct radeon_device *rdev,
                        u64 src_gpu_addr, u64 dst_gpu_addr,
                        int size_bytes);
+/* evergreen blit */
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes);
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence);
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+                            u64 src_gpu_addr, u64 dst_gpu_addr,
+                            int size_bytes);
 
 static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
 {
@@ -1341,6 +1354,9 @@ extern void radeon_update_bandwidth_info(struct radeon_device *rdev);
 extern void radeon_update_display_priority(struct radeon_device *rdev);
 extern bool radeon_boot_test_post_card(struct radeon_device *rdev);
 extern void radeon_scratch_init(struct radeon_device *rdev);
+extern void radeon_wb_fini(struct radeon_device *rdev);
+extern int radeon_wb_init(struct radeon_device *rdev);
+extern void radeon_wb_disable(struct radeon_device *rdev);
 extern void radeon_surface_init(struct radeon_device *rdev);
 extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
 extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
@@ -1425,9 +1441,6 @@ extern int r600_pcie_gart_init(struct radeon_device *rdev);
 extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
 extern int r600_ib_test(struct radeon_device *rdev);
 extern int r600_ring_test(struct radeon_device *rdev);
-extern void r600_wb_fini(struct radeon_device *rdev);
-extern int r600_wb_enable(struct radeon_device *rdev);
-extern void r600_wb_disable(struct radeon_device *rdev);
 extern void r600_scratch_init(struct radeon_device *rdev);
 extern int r600_blit_init(struct radeon_device *rdev);
 extern void r600_blit_fini(struct radeon_device *rdev);
@@ -1465,6 +1478,8 @@ extern void r700_cp_stop(struct radeon_device *rdev);
 extern void r700_cp_fini(struct radeon_device *rdev);
 extern void evergreen_disable_interrupt_state(struct radeon_device *rdev);
 extern int evergreen_irq_set(struct radeon_device *rdev);
+extern int evergreen_blit_init(struct radeon_device *rdev);
+extern void evergreen_blit_fini(struct radeon_device *rdev);
 
 /* radeon_acpi.c */ 
 #if defined(CONFIG_ACPI) 
index 25e1dd1977917ad4151cdaf599add440ef14d625..64fb89ecbf74728893bccb0dfcf442688c904688 100644 (file)
@@ -726,9 +726,9 @@ static struct radeon_asic evergreen_asic = {
        .get_vblank_counter = &evergreen_get_vblank_counter,
        .fence_ring_emit = &r600_fence_ring_emit,
        .cs_parse = &evergreen_cs_parse,
-       .copy_blit = NULL,
-       .copy_dma = NULL,
-       .copy = NULL,
+       .copy_blit = &evergreen_copy_blit,
+       .copy_dma = &evergreen_copy_blit,
+       .copy = &evergreen_copy_blit,
        .get_engine_clock = &radeon_atom_get_engine_clock,
        .set_engine_clock = &radeon_atom_set_engine_clock,
        .get_memory_clock = &radeon_atom_get_memory_clock,
index a5aff755f0d2e185dbdd4a1efd541dea5dae78fa..740988244143ce2105ba6fb04964a87c9eff644e 100644 (file)
@@ -108,9 +108,6 @@ void r100_irq_disable(struct radeon_device *rdev);
 void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save);
 void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save);
 void r100_vram_init_sizes(struct radeon_device *rdev);
-void r100_wb_disable(struct radeon_device *rdev);
-void r100_wb_fini(struct radeon_device *rdev);
-int r100_wb_init(struct radeon_device *rdev);
 int r100_cp_reset(struct radeon_device *rdev);
 void r100_vga_render_disable(struct radeon_device *rdev);
 void r100_restore_sanity(struct radeon_device *rdev);
@@ -257,11 +254,6 @@ void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 int r600_cs_parse(struct radeon_cs_parser *p);
 void r600_fence_ring_emit(struct radeon_device *rdev,
                          struct radeon_fence *fence);
-int r600_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset,
-                 uint64_t dst_offset,
-                 unsigned num_pages,
-                 struct radeon_fence *fence);
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_set(struct radeon_device *rdev);
 bool r600_gpu_is_lockup(struct radeon_device *rdev);
@@ -307,6 +299,9 @@ int evergreen_resume(struct radeon_device *rdev);
 bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
 int evergreen_asic_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
+int evergreen_copy_blit(struct radeon_device *rdev,
+                       uint64_t src_offset, uint64_t dst_offset,
+                       unsigned num_pages, struct radeon_fence *fence);
 void evergreen_hpd_init(struct radeon_device *rdev);
 void evergreen_hpd_fini(struct radeon_device *rdev);
 bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
index 8e43ddae70cc27d3c37d472561527432cc51dd53..04cac7ec90397fa7f4f46f9d966fb41b2d3c5368 100644 (file)
@@ -1112,8 +1112,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                         * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
                         * family.
                         */
-                       if (!radeon_new_pll)
-                               p1pll->pll_out_min = 64800;
+                       p1pll->pll_out_min = 64800;
                }
 
                p1pll->pll_in_min =
@@ -1277,36 +1276,27 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
        return false;
 }
 
-static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
-                                                         radeon_encoder
-                                                         *encoder,
-                                                         int id)
+bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+                                     struct radeon_atom_ss *ss,
+                                     int id)
 {
-       struct drm_device *dev = encoder->base.dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct radeon_mode_info *mode_info = &rdev->mode_info;
        int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
-       uint16_t data_offset;
+       uint16_t data_offset, size;
        struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
        uint8_t frev, crev;
-       struct radeon_atom_ss *ss = NULL;
-       int i;
-
-       if (id > ATOM_MAX_SS_ENTRY)
-               return NULL;
+       int i, num_indices;
 
-       if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+       memset(ss, 0, sizeof(struct radeon_atom_ss));
+       if (atom_parse_data_header(mode_info->atom_context, index, &size,
                                   &frev, &crev, &data_offset)) {
                ss_info =
                        (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
 
-               ss =
-                   kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL);
-
-               if (!ss)
-                       return NULL;
+               num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                       sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
 
-               for (i = 0; i < ATOM_MAX_SS_ENTRY; i++) {
+               for (i = 0; i < num_indices; i++) {
                        if (ss_info->asSS_Info[i].ucSS_Id == id) {
                                ss->percentage =
                                        le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
@@ -1315,11 +1305,88 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
                                ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
                                ss->range = ss_info->asSS_Info[i].ucSS_Range;
                                ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
-                               break;
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+union asic_ss_info {
+       struct _ATOM_ASIC_INTERNAL_SS_INFO info;
+       struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
+       struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
+};
+
+bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+                                     struct radeon_atom_ss *ss,
+                                     int id, u32 clock)
+{
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+       uint16_t data_offset, size;
+       union asic_ss_info *ss_info;
+       uint8_t frev, crev;
+       int i, num_indices;
+
+       memset(ss, 0, sizeof(struct radeon_atom_ss));
+       if (atom_parse_data_header(mode_info->atom_context, index, &size,
+                                  &frev, &crev, &data_offset)) {
+
+               ss_info =
+                       (union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
+
+               switch (frev) {
+               case 1:
+                       num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                               sizeof(ATOM_ASIC_SS_ASSIGNMENT);
+
+                       for (i = 0; i < num_indices; i++) {
+                               if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
+                                   (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                       ss->percentage =
+                                               le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+                                       ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
+                                       return true;
+                               }
+                       }
+                       break;
+               case 2:
+                       num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                               sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+                       for (i = 0; i < num_indices; i++) {
+                               if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
+                                   (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                       ss->percentage =
+                                               le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+                                       ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+                                       return true;
+                               }
                        }
+                       break;
+               case 3:
+                       num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                               sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+                       for (i = 0; i < num_indices; i++) {
+                               if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
+                                   (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                       ss->percentage =
+                                               le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+                                       ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+                                       return true;
+                               }
+                       }
+                       break;
+               default:
+                       DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
+                       break;
                }
+
        }
-       return ss;
+       return false;
 }
 
 union lvds_info {
@@ -1371,7 +1438,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                        le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
                lvds->panel_pwr_delay =
                    le16_to_cpu(lvds_info->info.usOffDelayInMs);
-               lvds->lvds_misc = lvds_info->info.ucLVDS_Misc;
+               lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
 
                misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
                if (misc & ATOM_VSYNC_POLARITY)
@@ -1388,19 +1455,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                /* set crtc values */
                drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
 
-               lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
-
-               if (ASIC_IS_AVIVO(rdev)) {
-                       if (radeon_new_pll == 0)
-                               lvds->pll_algo = PLL_ALGO_LEGACY;
-                       else
-                               lvds->pll_algo = PLL_ALGO_NEW;
-               } else {
-                       if (radeon_new_pll == 1)
-                               lvds->pll_algo = PLL_ALGO_NEW;
-                       else
-                               lvds->pll_algo = PLL_ALGO_LEGACY;
-               }
+               lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
 
                encoder->native_mode = lvds->native_mode;
 
index ecc1a8fafbfd3eb3c12c0c4d45b4b091a1bee03b..4dac4b0a02eea1928837c7009f88e84f227a81f5 100644 (file)
@@ -326,6 +326,34 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
                }
        }
 
+       if (property == rdev->mode_info.underscan_hborder_property) {
+               /* need to find digital encoder on connector */
+               encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+               if (!encoder)
+                       return 0;
+
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               if (radeon_encoder->underscan_hborder != val) {
+                       radeon_encoder->underscan_hborder = val;
+                       radeon_property_change_mode(&radeon_encoder->base);
+               }
+       }
+
+       if (property == rdev->mode_info.underscan_vborder_property) {
+               /* need to find digital encoder on connector */
+               encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+               if (!encoder)
+                       return 0;
+
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               if (radeon_encoder->underscan_vborder != val) {
+                       radeon_encoder->underscan_vborder = val;
+                       radeon_property_change_mode(&radeon_encoder->base);
+               }
+       }
+
        if (property == rdev->mode_info.tv_std_property) {
                encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
                if (!encoder) {
@@ -635,6 +663,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
                                ret = connector_status_connected;
                }
        } else {
+
+               /* if we aren't forcing don't do destructive polling */
+               if (!force)
+                       return connector->status;
+
                if (radeon_connector->dac_load_detect && encoder) {
                        encoder_funcs = encoder->helper_private;
                        ret = encoder_funcs->detect(encoder, connector);
@@ -822,6 +855,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
                goto out;
 
+       if (!force) {
+               ret = connector->status;
+               goto out;
+       }
+
        /* find analog encoder */
        if (radeon_connector->dac_load_detect) {
                for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
@@ -1153,10 +1191,17 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_attach_property(&radeon_connector->base,
                                              rdev->mode_info.coherent_mode_property,
                                              1);
-               if (ASIC_IS_AVIVO(rdev))
+               if (ASIC_IS_AVIVO(rdev)) {
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_AUTO);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_hborder_property,
+                                                     0);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_vborder_property,
+                                                     0);
+               }
                if (connector_type == DRM_MODE_CONNECTOR_DVII) {
                        radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
@@ -1181,10 +1226,17 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_attach_property(&radeon_connector->base,
                                              rdev->mode_info.coherent_mode_property,
                                              1);
-               if (ASIC_IS_AVIVO(rdev))
+               if (ASIC_IS_AVIVO(rdev)) {
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_AUTO);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_hborder_property,
+                                                     0);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_vborder_property,
+                                                     0);
+               }
                subpixel_order = SubPixelHorizontalRGB;
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
@@ -1212,10 +1264,17 @@ radeon_add_atom_connector(struct drm_device *dev,
                drm_connector_attach_property(&radeon_connector->base,
                                              rdev->mode_info.coherent_mode_property,
                                              1);
-               if (ASIC_IS_AVIVO(rdev))
+               if (ASIC_IS_AVIVO(rdev)) {
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_AUTO);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_hborder_property,
+                                                     0);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.underscan_vborder_property,
+                                                     0);
+               }
                break;
        case DRM_MODE_CONNECTOR_SVIDEO:
        case DRM_MODE_CONNECTOR_Composite:
index 3eef567b0421ae71826abd77ac3bc035a5ec1c33..017ac54920fb4f3fb58f7c0f9a57e1efb46450f0 100644 (file)
@@ -118,22 +118,25 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
 }
 
 static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
-                             uint32_t gpu_addr)
+                             uint64_t gpu_addr)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct radeon_device *rdev = crtc->dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev)) {
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0);
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+                      upper_32_bits(gpu_addr));
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      gpu_addr & 0xffffffff);
        } else if (ASIC_IS_AVIVO(rdev)) {
                if (rdev->family >= CHIP_RV770) {
                        if (radeon_crtc->crtc_id)
-                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0);
+                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
                        else
-                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, 0);
+                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
                }
-               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      gpu_addr & 0xffffffff);
        } else {
                radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
                /* offset is from DISP(2)_BASE_ADDRESS */
index 256d204a6d24226a93f68b5d4d097fc4b52739c7..8adfedfe547f6b6455676deaa26dada2592ff6a5 100644 (file)
@@ -117,9 +117,10 @@ void radeon_scratch_init(struct radeon_device *rdev)
        } else {
                rdev->scratch.num_reg = 7;
        }
+       rdev->scratch.reg_base = RADEON_SCRATCH_REG0;
        for (i = 0; i < rdev->scratch.num_reg; i++) {
                rdev->scratch.free[i] = true;
-               rdev->scratch.reg[i] = RADEON_SCRATCH_REG0 + (i * 4);
+               rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
        }
 }
 
@@ -149,6 +150,86 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
        }
 }
 
+void radeon_wb_disable(struct radeon_device *rdev)
+{
+       int r;
+
+       if (rdev->wb.wb_obj) {
+               r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+               if (unlikely(r != 0))
+                       return;
+               radeon_bo_kunmap(rdev->wb.wb_obj);
+               radeon_bo_unpin(rdev->wb.wb_obj);
+               radeon_bo_unreserve(rdev->wb.wb_obj);
+       }
+       rdev->wb.enabled = false;
+}
+
+void radeon_wb_fini(struct radeon_device *rdev)
+{
+       radeon_wb_disable(rdev);
+       if (rdev->wb.wb_obj) {
+               radeon_bo_unref(&rdev->wb.wb_obj);
+               rdev->wb.wb = NULL;
+               rdev->wb.wb_obj = NULL;
+       }
+}
+
+int radeon_wb_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (rdev->wb.wb_obj == NULL) {
+               r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
+                               RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
+               if (r) {
+                       dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
+                       return r;
+               }
+       }
+       r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+       if (unlikely(r != 0)) {
+               radeon_wb_fini(rdev);
+               return r;
+       }
+       r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
+                         &rdev->wb.gpu_addr);
+       if (r) {
+               radeon_bo_unreserve(rdev->wb.wb_obj);
+               dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
+               radeon_wb_fini(rdev);
+               return r;
+       }
+       r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
+       radeon_bo_unreserve(rdev->wb.wb_obj);
+       if (r) {
+               dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
+               radeon_wb_fini(rdev);
+               return r;
+       }
+
+       /* disable event_write fences */
+       rdev->wb.use_event = false;
+       /* disabled via module param */
+       if (radeon_no_wb == 1)
+               rdev->wb.enabled = false;
+       else {
+               /* often unreliable on AGP */
+               if (rdev->flags & RADEON_IS_AGP) {
+                       rdev->wb.enabled = false;
+               } else {
+                       rdev->wb.enabled = true;
+                       /* event_write fences are only available on r600+ */
+                       if (rdev->family >= CHIP_R600)
+                               rdev->wb.use_event = true;
+               }
+       }
+
+       dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
+
+       return 0;
+}
+
 /**
  * radeon_vram_location - try to find VRAM location
  * @rdev: radeon device structure holding all necessary informations
index b92d2f2fcbed6a8bd472ce9f4b936aa82f309278..0383631da69c42db417f27f6b87ddf58f19eb24e 100644 (file)
@@ -454,13 +454,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
        return n;
 }
 
-static void radeon_compute_pll_legacy(struct radeon_pll *pll,
-                                     uint64_t freq,
-                                     uint32_t *dot_clock_p,
-                                     uint32_t *fb_div_p,
-                                     uint32_t *frac_fb_div_p,
-                                     uint32_t *ref_div_p,
-                                     uint32_t *post_div_p)
+void radeon_compute_pll(struct radeon_pll *pll,
+                       uint64_t freq,
+                       uint32_t *dot_clock_p,
+                       uint32_t *fb_div_p,
+                       uint32_t *frac_fb_div_p,
+                       uint32_t *ref_div_p,
+                       uint32_t *post_div_p)
 {
        uint32_t min_ref_div = pll->min_ref_div;
        uint32_t max_ref_div = pll->max_ref_div;
@@ -513,7 +513,7 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
                max_fractional_feed_div = pll->max_frac_feedback_div;
        }
 
-       for (post_div = min_post_div; post_div <= max_post_div; ++post_div) {
+       for (post_div = max_post_div; post_div >= min_post_div; --post_div) {
                uint32_t ref_div;
 
                if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
@@ -631,214 +631,6 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
        *post_div_p = best_post_div;
 }
 
-static bool
-calc_fb_div(struct radeon_pll *pll,
-           uint32_t freq,
-            uint32_t post_div,
-            uint32_t ref_div,
-            uint32_t *fb_div,
-            uint32_t *fb_div_frac)
-{
-       fixed20_12 feedback_divider, a, b;
-       u32 vco_freq;
-
-       vco_freq = freq * post_div;
-       /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
-       a.full = dfixed_const(pll->reference_freq);
-       feedback_divider.full = dfixed_const(vco_freq);
-       feedback_divider.full = dfixed_div(feedback_divider, a);
-       a.full = dfixed_const(ref_div);
-       feedback_divider.full = dfixed_mul(feedback_divider, a);
-
-       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
-               /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
-               a.full = dfixed_const(10);
-               feedback_divider.full = dfixed_mul(feedback_divider, a);
-               feedback_divider.full += dfixed_const_half(0);
-               feedback_divider.full = dfixed_floor(feedback_divider);
-               feedback_divider.full = dfixed_div(feedback_divider, a);
-
-               /* *fb_div = floor(feedback_divider); */
-               a.full = dfixed_floor(feedback_divider);
-               *fb_div = dfixed_trunc(a);
-               /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
-               a.full = dfixed_const(10);
-               b.full = dfixed_mul(feedback_divider, a);
-
-               feedback_divider.full = dfixed_floor(feedback_divider);
-               feedback_divider.full = dfixed_mul(feedback_divider, a);
-               feedback_divider.full = b.full - feedback_divider.full;
-               *fb_div_frac = dfixed_trunc(feedback_divider);
-       } else {
-               /* *fb_div = floor(feedback_divider + 0.5); */
-               feedback_divider.full += dfixed_const_half(0);
-               feedback_divider.full = dfixed_floor(feedback_divider);
-
-               *fb_div = dfixed_trunc(feedback_divider);
-               *fb_div_frac = 0;
-       }
-
-       if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
-               return false;
-       else
-               return true;
-}
-
-static bool
-calc_fb_ref_div(struct radeon_pll *pll,
-               uint32_t freq,
-               uint32_t post_div,
-               uint32_t *fb_div,
-                uint32_t *fb_div_frac,
-                uint32_t *ref_div)
-{
-       fixed20_12 ffreq, max_error, error, pll_out, a;
-       u32 vco;
-       u32 pll_out_min, pll_out_max;
-
-       if (pll->flags & RADEON_PLL_IS_LCD) {
-               pll_out_min = pll->lcd_pll_out_min;
-               pll_out_max = pll->lcd_pll_out_max;
-       } else {
-               pll_out_min = pll->pll_out_min;
-               pll_out_max = pll->pll_out_max;
-       }
-
-       ffreq.full = dfixed_const(freq);
-       /* max_error = ffreq * 0.0025; */
-       a.full = dfixed_const(400);
-       max_error.full = dfixed_div(ffreq, a);
-
-       for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
-               if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
-                       vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
-                       vco = vco / ((*ref_div) * 10);
-
-                       if ((vco < pll_out_min) || (vco > pll_out_max))
-                               continue;
-
-                       /* pll_out = vco / post_div; */
-                       a.full = dfixed_const(post_div);
-                       pll_out.full = dfixed_const(vco);
-                       pll_out.full = dfixed_div(pll_out, a);
-
-                       if (pll_out.full >= ffreq.full) {
-                               error.full = pll_out.full - ffreq.full;
-                               if (error.full <= max_error.full)
-                                       return true;
-                       }
-               }
-       }
-       return false;
-}
-
-static void radeon_compute_pll_new(struct radeon_pll *pll,
-                                  uint64_t freq,
-                                  uint32_t *dot_clock_p,
-                                  uint32_t *fb_div_p,
-                                  uint32_t *frac_fb_div_p,
-                                  uint32_t *ref_div_p,
-                                  uint32_t *post_div_p)
-{
-       u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
-       u32 best_freq = 0, vco_frequency;
-       u32 pll_out_min, pll_out_max;
-
-       if (pll->flags & RADEON_PLL_IS_LCD) {
-               pll_out_min = pll->lcd_pll_out_min;
-               pll_out_max = pll->lcd_pll_out_max;
-       } else {
-               pll_out_min = pll->pll_out_min;
-               pll_out_max = pll->pll_out_max;
-       }
-
-       /* freq = freq / 10; */
-       do_div(freq, 10);
-
-       if (pll->flags & RADEON_PLL_USE_POST_DIV) {
-               post_div = pll->post_div;
-               if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
-                       goto done;
-
-               vco_frequency = freq * post_div;
-               if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
-                       goto done;
-
-               if (pll->flags & RADEON_PLL_USE_REF_DIV) {
-                       ref_div = pll->reference_div;
-                       if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
-                               goto done;
-                       if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
-                               goto done;
-               }
-       } else {
-               for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
-                       if (pll->flags & RADEON_PLL_LEGACY) {
-                               if ((post_div == 5) ||
-                                   (post_div == 7) ||
-                                   (post_div == 9) ||
-                                   (post_div == 10) ||
-                                   (post_div == 11))
-                                       continue;
-                       }
-
-                       if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
-                               continue;
-
-                       vco_frequency = freq * post_div;
-                       if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
-                               continue;
-                       if (pll->flags & RADEON_PLL_USE_REF_DIV) {
-                               ref_div = pll->reference_div;
-                               if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
-                                       goto done;
-                               if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
-                                       break;
-                       } else {
-                               if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
-                                       break;
-                       }
-               }
-       }
-
-       best_freq = pll->reference_freq * 10 * fb_div;
-       best_freq += pll->reference_freq * fb_div_frac;
-       best_freq = best_freq / (ref_div * post_div);
-
-done:
-       if (best_freq == 0)
-               DRM_ERROR("Couldn't find valid PLL dividers\n");
-
-       *dot_clock_p = best_freq / 10;
-       *fb_div_p = fb_div;
-       *frac_fb_div_p = fb_div_frac;
-       *ref_div_p = ref_div;
-       *post_div_p = post_div;
-
-       DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
-}
-
-void radeon_compute_pll(struct radeon_pll *pll,
-                       uint64_t freq,
-                       uint32_t *dot_clock_p,
-                       uint32_t *fb_div_p,
-                       uint32_t *frac_fb_div_p,
-                       uint32_t *ref_div_p,
-                       uint32_t *post_div_p)
-{
-       switch (pll->algo) {
-       case PLL_ALGO_NEW:
-               radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
-                                      frac_fb_div_p, ref_div_p, post_div_p);
-               break;
-       case PLL_ALGO_LEGACY:
-       default:
-               radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
-                                         frac_fb_div_p, ref_div_p, post_div_p);
-               break;
-       }
-}
-
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
@@ -1002,6 +794,24 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
                                      radeon_underscan_enum_list[i].name);
        }
 
+       rdev->mode_info.underscan_hborder_property =
+               drm_property_create(rdev->ddev,
+                                       DRM_MODE_PROP_RANGE,
+                                       "underscan hborder", 2);
+       if (!rdev->mode_info.underscan_hborder_property)
+               return -ENOMEM;
+       rdev->mode_info.underscan_hborder_property->values[0] = 0;
+       rdev->mode_info.underscan_hborder_property->values[1] = 128;
+
+       rdev->mode_info.underscan_vborder_property =
+               drm_property_create(rdev->ddev,
+                                       DRM_MODE_PROP_RANGE,
+                                       "underscan vborder", 2);
+       if (!rdev->mode_info.underscan_vborder_property)
+               return -ENOMEM;
+       rdev->mode_info.underscan_vborder_property->values[0] = 0;
+       rdev->mode_info.underscan_vborder_property->values[1] = 128;
+
        return 0;
 }
 
@@ -1159,8 +969,14 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
                             ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
                              drm_detect_hdmi_monitor(radeon_connector->edid) &&
                              is_hdtv_mode(mode)))) {
-                               radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
-                               radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
+                               if (radeon_encoder->underscan_hborder != 0)
+                                       radeon_crtc->h_border = radeon_encoder->underscan_hborder;
+                               else
+                                       radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
+                               if (radeon_encoder->underscan_vborder != 0)
+                                       radeon_crtc->v_border = radeon_encoder->underscan_vborder;
+                               else
+                                       radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
                                radeon_crtc->rmx_type = RMX_FULL;
                                src_v = crtc->mode.vdisplay;
                                dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
@@ -1195,3 +1011,156 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
        }
        return true;
 }
+
+/*
+ * Retrieve current video scanout position of crtc on a given gpu.
+ *
+ * \param rdev Device to query.
+ * \param crtc Crtc to query.
+ * \param *vpos Location where vertical scanout position should be stored.
+ * \param *hpos Location where horizontal scanout position should go.
+ *
+ * Returns vpos as a positive number while in active scanout area.
+ * Returns vpos as a negative number inside vblank, counting the number
+ * of scanlines to go until end of vblank, e.g., -1 means "one scanline
+ * until start of active scanout / end of vblank."
+ *
+ * \return Flags, or'ed together as follows:
+ *
+ * RADEON_SCANOUTPOS_VALID = Query successfull.
+ * RADEON_SCANOUTPOS_INVBL = Inside vblank.
+ * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
+ * this flag means that returned position may be offset by a constant but
+ * unknown small number of scanlines wrt. real scanout position.
+ *
+ */
+int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
+{
+       u32 stat_crtc = 0, vbl = 0, position = 0;
+       int vbl_start, vbl_end, vtotal, ret = 0;
+       bool in_vbl = true;
+
+       if (ASIC_IS_DCE4(rdev)) {
+               if (crtc == 0) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC0_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC0_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 1) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC1_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC1_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 2) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC2_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC2_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 3) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC3_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC3_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 4) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC4_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC4_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 5) {
+                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+                                    EVERGREEN_CRTC5_REGISTER_OFFSET);
+                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+                                         EVERGREEN_CRTC5_REGISTER_OFFSET);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+       } else if (ASIC_IS_AVIVO(rdev)) {
+               if (crtc == 0) {
+                       vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
+                       position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 1) {
+                       vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
+                       position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+       } else {
+               /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
+               if (crtc == 0) {
+                       /* Assume vbl_end == 0, get vbl_start from
+                        * upper 16 bits.
+                        */
+                       vbl = (RREG32(RADEON_CRTC_V_TOTAL_DISP) &
+                               RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+                       /* Only retrieve vpos from upper 16 bits, set hpos == 0. */
+                       position = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+                       stat_crtc = RREG32(RADEON_CRTC_STATUS);
+                       if (!(stat_crtc & 1))
+                               in_vbl = false;
+
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+               if (crtc == 1) {
+                       vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
+                               RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+                       position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+                       stat_crtc = RREG32(RADEON_CRTC2_STATUS);
+                       if (!(stat_crtc & 1))
+                               in_vbl = false;
+
+                       ret |= RADEON_SCANOUTPOS_VALID;
+               }
+       }
+
+       /* Decode into vertical and horizontal scanout position. */
+       *vpos = position & 0x1fff;
+       *hpos = (position >> 16) & 0x1fff;
+
+       /* Valid vblank area boundaries from gpu retrieved? */
+       if (vbl > 0) {
+               /* Yes: Decode. */
+               ret |= RADEON_SCANOUTPOS_ACCURATE;
+               vbl_start = vbl & 0x1fff;
+               vbl_end = (vbl >> 16) & 0x1fff;
+       }
+       else {
+               /* No: Fake something reasonable which gives at least ok results. */
+               vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
+               vbl_end = 0;
+       }
+
+       /* Test scanout position against vblank region. */
+       if ((*vpos < vbl_start) && (*vpos >= vbl_end))
+               in_vbl = false;
+
+       /* Check if inside vblank area and apply corrective offsets:
+        * vpos will then be >=0 in video scanout area, but negative
+        * within vblank area, counting down the number of lines until
+        * start of scanout.
+        */
+
+       /* Inside "upper part" of vblank area? Apply corrective offset if so: */
+       if (in_vbl && (*vpos >= vbl_start)) {
+               vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
+               *vpos = *vpos - vtotal;
+       }
+
+       /* Correct for shifted end of vbl at vbl_end. */
+       *vpos = *vpos - vbl_end;
+
+       /* In vblank? */
+       if (in_vbl)
+               ret |= RADEON_SCANOUTPOS_INVBL;
+
+       return ret;
+}
index 29c1237c2e7b8357d7b72d07cf76a99ed9375869..88e4ea925900ef3aecf71aa17744d3f9d0d8c445 100644 (file)
  * - 2.4.0 - add crtc id query
  * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
  * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
+ *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       6
+#define KMS_DRIVER_MINOR       7
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -93,7 +94,6 @@ int radeon_benchmarking = 0;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
-int radeon_new_pll = -1;
 int radeon_audio = 1;
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
@@ -131,9 +131,6 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
-MODULE_PARM_DESC(new_pll, "Select new PLL code");
-module_param_named(new_pll, radeon_new_pll, int, 0444);
-
 MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
 module_param_named(audio, radeon_audio, int, 0444);
 
@@ -203,8 +200,6 @@ static struct drm_driver driver_old = {
        .irq_uninstall = radeon_driver_irq_uninstall,
        .irq_handler = radeon_driver_irq_handler,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = radeon_ioctls,
        .dma_ioctl = radeon_cp_buffers,
        .fops = {
@@ -291,8 +286,6 @@ static struct drm_driver kms_driver = {
        .irq_uninstall = radeon_driver_irq_uninstall_kms,
        .irq_handler = radeon_driver_irq_handler_kms,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = radeon_ioctls_kms,
        .gem_init_object = radeon_gem_object_init,
        .gem_free_object = radeon_gem_object_free,
index 2c293e8304d657d047144708bff75c6474d560f0..ae58b6849a2eaa4fd259b88f3d43d2497733161b 100644 (file)
@@ -529,9 +529,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
                                args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
                        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+                               if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
                                        args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-                               if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+                               if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
                                        args.v1.ucMisc |= (1 << 1);
                        } else {
                                if (dig->linkb)
@@ -558,18 +558,18 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
                        args.v2.ucTemporal = 0;
                        args.v2.ucFRC = 0;
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+                               if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
                                        args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-                               if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) {
+                               if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) {
                                        args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
-                                       if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+                                       if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
                                                args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
                                }
-                               if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) {
+                               if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) {
                                        args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
-                                       if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+                                       if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
                                                args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
-                                       if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
+                                       if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
                                                args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
                                }
                        } else {
index 40b0c087b5921384d46bf7f745cf93f2b391015b..efa211898fe60204a424b98cdb9295ea2ee99356 100644 (file)
@@ -59,6 +59,8 @@ static struct fb_ops radeonfb_ops = {
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 
index b1f9a81b5d1dabcf37da7de738817a6d8db5f84a..216392d0353bcace87cd2a80d06dda358e285ee4 100644 (file)
@@ -72,7 +72,15 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
        bool wake = false;
        unsigned long cjiffies;
 
-       seq = RREG32(rdev->fence_drv.scratch_reg);
+       if (rdev->wb.enabled) {
+               u32 scratch_index;
+               if (rdev->wb.use_event)
+                       scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               else
+                       scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               seq = rdev->wb.wb[scratch_index/4];
+       } else
+               seq = RREG32(rdev->fence_drv.scratch_reg);
        if (seq != rdev->fence_drv.last_seq) {
                rdev->fence_drv.last_seq = seq;
                rdev->fence_drv.last_jiffies = jiffies;
index 305049afde15235e558dc22f3992543508f362e6..ace2e6384d4093a688b856c7a5369a9b4124fe94 100644 (file)
@@ -347,11 +347,26 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
 
 int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                         struct drm_framebuffer *old_fb)
+{
+       return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               int x, int y, enum mode_set_atomic state)
+{
+       return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
+}
+
+int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+                        struct drm_framebuffer *fb,
+                        int x, int y, int atomic)
 {
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct radeon_framebuffer *radeon_fb;
+       struct drm_framebuffer *target_fb;
        struct drm_gem_object *obj;
        struct radeon_bo *rbo;
        uint64_t base;
@@ -364,14 +379,21 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 
        DRM_DEBUG_KMS("\n");
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!atomic && !crtc->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
 
-       radeon_fb = to_radeon_framebuffer(crtc->fb);
+       if (atomic) {
+               radeon_fb = to_radeon_framebuffer(fb);
+               target_fb = fb;
+       }
+       else {
+               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               target_fb = crtc->fb;
+       }
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (target_fb->bits_per_pixel) {
        case 8:
                format = 2;
                break;
@@ -415,10 +437,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 
        crtc_offset_cntl = 0;
 
-       pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
-       crtc_pitch  = (((pitch_pixels * crtc->fb->bits_per_pixel) +
-                       ((crtc->fb->bits_per_pixel * 8) - 1)) /
-                      (crtc->fb->bits_per_pixel * 8));
+       pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
+       crtc_pitch  = (((pitch_pixels * target_fb->bits_per_pixel) +
+                       ((target_fb->bits_per_pixel * 8) - 1)) /
+                      (target_fb->bits_per_pixel * 8));
        crtc_pitch |= crtc_pitch << 16;
 
 
@@ -443,14 +465,14 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                        crtc_tile_x0_y0 = x | (y << 16);
                        base &= ~0x7ff;
                } else {
-                       int byteshift = crtc->fb->bits_per_pixel >> 4;
+                       int byteshift = target_fb->bits_per_pixel >> 4;
                        int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;
                        base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
                        crtc_offset_cntl |= (y % 16);
                }
        } else {
                int offset = y * pitch_pixels + x;
-               switch (crtc->fb->bits_per_pixel) {
+               switch (target_fb->bits_per_pixel) {
                case 8:
                        offset *= 1;
                        break;
@@ -496,8 +518,8 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
        WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
 
-       if (old_fb && old_fb != crtc->fb) {
-               radeon_fb = to_radeon_framebuffer(old_fb);
+       if (!atomic && fb && fb != crtc->fb) {
+               radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
                r = radeon_bo_reserve(rbo, false);
                if (unlikely(r != 0))
@@ -717,10 +739,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
                pll = &rdev->clock.p1pll;
 
        pll->flags = RADEON_PLL_LEGACY;
-       if (radeon_new_pll == 1)
-               pll->algo = PLL_ALGO_NEW;
-       else
-               pll->algo = PLL_ALGO_LEGACY;
 
        if (mode->clock > 200000) /* range limits??? */
                pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
@@ -1040,6 +1058,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
        .mode_fixup = radeon_crtc_mode_fixup,
        .mode_set = radeon_crtc_mode_set,
        .mode_set_base = radeon_crtc_set_base,
+       .mode_set_base_atomic = radeon_crtc_set_base_atomic,
        .prepare = radeon_crtc_prepare,
        .commit = radeon_crtc_commit,
        .load_lut = radeon_crtc_load_lut,
index 454c1dc7ea45ea5975647680b15191d15f2bb470..92457163d07094dba9bd5975dc63dfb4968e92a6 100644 (file)
@@ -35,6 +35,7 @@
 #include <drm_edid.h>
 #include <drm_dp_helper.h>
 #include <drm_fixed.h>
+#include <drm_crtc_helper.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
@@ -149,12 +150,6 @@ struct radeon_tmds_pll {
 #define RADEON_PLL_USE_POST_DIV         (1 << 12)
 #define RADEON_PLL_IS_LCD               (1 << 13)
 
-/* pll algo */
-enum radeon_pll_algo {
-       PLL_ALGO_LEGACY,
-       PLL_ALGO_NEW
-};
-
 struct radeon_pll {
        /* reference frequency */
        uint32_t reference_freq;
@@ -187,8 +182,6 @@ struct radeon_pll {
 
        /* pll id */
        uint32_t id;
-       /* pll algo */
-       enum radeon_pll_algo algo;
 };
 
 struct radeon_i2c_chan {
@@ -240,6 +233,8 @@ struct radeon_mode_info {
        struct drm_property *tmds_pll_property;
        /* underscan */
        struct drm_property *underscan_property;
+       struct drm_property *underscan_hborder_property;
+       struct drm_property *underscan_vborder_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
 
@@ -335,22 +330,24 @@ struct radeon_encoder_ext_tmds {
 struct radeon_atom_ss {
        uint16_t percentage;
        uint8_t type;
-       uint8_t step;
+       uint16_t step;
        uint8_t delay;
        uint8_t range;
        uint8_t refdiv;
+       /* asic_ss */
+       uint16_t rate;
+       uint16_t amount;
 };
 
 struct radeon_encoder_atom_dig {
        bool linkb;
        /* atom dig */
        bool coherent_mode;
-       int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */
-       /* atom lvds */
-       uint32_t lvds_misc;
+       int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */
+       /* atom lvds/edp */
+       uint32_t lcd_misc;
        uint16_t panel_pwr_delay;
-       enum radeon_pll_algo pll_algo;
-       struct radeon_atom_ss *ss;
+       uint32_t lcd_ss_id;
        /* panel mode */
        struct drm_display_mode native_mode;
 };
@@ -369,6 +366,8 @@ struct radeon_encoder {
        uint32_t pixel_clock;
        enum radeon_rmx_type rmx_type;
        enum radeon_underscan_type underscan_type;
+       uint32_t underscan_hborder;
+       uint32_t underscan_vborder;
        struct drm_display_mode native_mode;
        void *enc_priv;
        int audio_polling_active;
@@ -435,6 +434,11 @@ struct radeon_framebuffer {
        struct drm_gem_object *obj;
 };
 
+/* radeon_get_crtc_scanoutpos() return flags */
+#define RADEON_SCANOUTPOS_VALID        (1 << 0)
+#define RADEON_SCANOUTPOS_INVBL        (1 << 1)
+#define RADEON_SCANOUTPOS_ACCURATE     (1 << 2)
+
 extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std
@@ -490,6 +494,13 @@ extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
 extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
 
+extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+                                            struct radeon_atom_ss *ss,
+                                            int id);
+extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+                                            struct radeon_atom_ss *ss,
+                                            int id, u32 clock);
+
 extern void radeon_compute_pll(struct radeon_pll *pll,
                               uint64_t freq,
                               uint32_t *dot_clock_p,
@@ -513,6 +524,10 @@ extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
 extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                                   struct drm_framebuffer *old_fb);
+extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
+                                        int x, int y,
+                                        enum mode_set_atomic state);
 extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
                                   struct drm_display_mode *mode,
                                   struct drm_display_mode *adjusted_mode,
@@ -522,7 +537,13 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
 
 extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                                 struct drm_framebuffer *old_fb);
-
+extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                      struct drm_framebuffer *fb,
+                                      int x, int y,
+                                      enum mode_set_atomic state);
+extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+                                  struct drm_framebuffer *fb,
+                                  int x, int y, int atomic);
 extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
                                  struct drm_file *file_priv,
                                  uint32_t handle,
@@ -531,6 +552,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
 extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                                   int x, int y);
 
+extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos);
+
 extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
 extern struct edid *
 radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
index b3b5306bb578bf88547e4078fe48f59d9e0ea720..d7ab914164103bdda7bf9ea72e8e35a2c78a5f37 100644 (file)
@@ -435,7 +435,7 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
 
 out:
        radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
-                              bo->tbo.mem.mm_node->start << PAGE_SHIFT,
+                              bo->tbo.mem.start << PAGE_SHIFT,
                               bo->tbo.num_pages << PAGE_SHIFT);
        return 0;
 }
@@ -532,7 +532,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
        rdev = rbo->rdev;
        if (bo->mem.mem_type == TTM_PL_VRAM) {
                size = bo->mem.num_pages << PAGE_SHIFT;
-               offset = bo->mem.mm_node->start << PAGE_SHIFT;
+               offset = bo->mem.start << PAGE_SHIFT;
                if ((offset + size) > rdev->mc.visible_vram_size) {
                        /* hurrah the memory is not visible ! */
                        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
@@ -540,7 +540,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
                        r = ttm_bo_validate(bo, &rbo->placement, false, true, false);
                        if (unlikely(r != 0))
                                return r;
-                       offset = bo->mem.mm_node->start << PAGE_SHIFT;
+                       offset = bo->mem.start << PAGE_SHIFT;
                        /* this should not happen */
                        if ((offset + size) > rdev->mc.visible_vram_size)
                                return -EINVAL;
index f87efec76236966ac790ff0709f5cf2ae3c57563..8c9b2ef32c681229aa9b21d5d2bce87b7bfae6fa 100644 (file)
@@ -712,73 +712,21 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
 
 static bool radeon_pm_in_vbl(struct radeon_device *rdev)
 {
-       u32 stat_crtc = 0, vbl = 0, position = 0;
+       int  crtc, vpos, hpos, vbl_status;
        bool in_vbl = true;
 
-       if (ASIC_IS_DCE4(rdev)) {
-               if (rdev->pm.active_crtcs & (1 << 0)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 1)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 2)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 3)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 4)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 5)) {
-                       vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-                                    EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
-                       position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-                                         EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
-               }
-       } else if (ASIC_IS_AVIVO(rdev)) {
-               if (rdev->pm.active_crtcs & (1 << 0)) {
-                       vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END) & 0xfff;
-                       position = RREG32(AVIVO_D1CRTC_STATUS_POSITION) & 0xfff;
-               }
-               if (rdev->pm.active_crtcs & (1 << 1)) {
-                       vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END) & 0xfff;
-                       position = RREG32(AVIVO_D2CRTC_STATUS_POSITION) & 0xfff;
-               }
-               if (position < vbl && position > 1)
-                       in_vbl = false;
-       } else {
-               if (rdev->pm.active_crtcs & (1 << 0)) {
-                       stat_crtc = RREG32(RADEON_CRTC_STATUS);
-                       if (!(stat_crtc & 1))
-                               in_vbl = false;
-               }
-               if (rdev->pm.active_crtcs & (1 << 1)) {
-                       stat_crtc = RREG32(RADEON_CRTC2_STATUS);
-                       if (!(stat_crtc & 1))
+       /* Iterate over all active crtc's. All crtc's must be in vblank,
+        * otherwise return in_vbl == false.
+        */
+       for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
+               if (rdev->pm.active_crtcs & (1 << crtc)) {
+                       vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos);
+                       if ((vbl_status & RADEON_SCANOUTPOS_VALID) &&
+                           !(vbl_status & RADEON_SCANOUTPOS_INVBL))
                                in_vbl = false;
                }
        }
 
-       if (position < vbl && position > 1)
-               in_vbl = false;
-
        return in_vbl;
 }
 
index 261e98a276dbb813631e56bf48358e003491c32f..6ea798ce821896dd4b2704461b260578a63a2516 100644 (file)
@@ -247,10 +247,14 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
  */
 void radeon_ring_free_size(struct radeon_device *rdev)
 {
-       if (rdev->family >= CHIP_R600)
-               rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
-       else
-               rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       if (rdev->wb.enabled)
+               rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4];
+       else {
+               if (rdev->family >= CHIP_R600)
+                       rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+               else
+                       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       }
        /* This works because ring_size is a power of 2 */
        rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4));
        rdev->cp.ring_free_dw -= rdev->cp.wptr;
index a823d8fe54c2ccaac8e63256a75e249bce542994..fe95bb35317ea26c2cabe33fc0bae285bfc32cef 100644 (file)
@@ -152,6 +152,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case TTM_PL_TT:
+               man->func = &ttm_bo_manager_func;
                man->gpu_offset = rdev->mc.gtt_start;
                man->available_caching = TTM_PL_MASK_CACHING;
                man->default_caching = TTM_PL_FLAG_CACHED;
@@ -173,6 +174,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                break;
        case TTM_PL_VRAM:
                /* "On-card" video ram */
+               man->func = &ttm_bo_manager_func;
                man->gpu_offset = rdev->mc.vram_start;
                man->flags = TTM_MEMTYPE_FLAG_FIXED |
                             TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -246,8 +248,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                return r;
        }
-       old_start = old_mem->mm_node->start << PAGE_SHIFT;
-       new_start = new_mem->mm_node->start << PAGE_SHIFT;
+       old_start = old_mem->start << PAGE_SHIFT;
+       new_start = new_mem->start << PAGE_SHIFT;
 
        switch (old_mem->mem_type) {
        case TTM_PL_VRAM:
@@ -326,14 +328,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        }
        r = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem);
 out_cleanup:
-       if (tmp_mem.mm_node) {
-               struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
-               spin_lock(&glob->lru_lock);
-               drm_mm_put_block(tmp_mem.mm_node);
-               spin_unlock(&glob->lru_lock);
-               return r;
-       }
+       ttm_bo_mem_put(bo, &tmp_mem);
        return r;
 }
 
@@ -372,14 +367,7 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
                goto out_cleanup;
        }
 out_cleanup:
-       if (tmp_mem.mm_node) {
-               struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
-               spin_lock(&glob->lru_lock);
-               drm_mm_put_block(tmp_mem.mm_node);
-               spin_unlock(&glob->lru_lock);
-               return r;
-       }
+       ttm_bo_mem_put(bo, &tmp_mem);
        return r;
 }
 
@@ -449,14 +437,14 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
 #if __OS_HAS_AGP
                if (rdev->flags & RADEON_IS_AGP) {
                        /* RADEON_IS_AGP is set only if AGP is active */
-                       mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+                       mem->bus.offset = mem->start << PAGE_SHIFT;
                        mem->bus.base = rdev->mc.agp_base;
                        mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
                }
 #endif
                break;
        case TTM_PL_VRAM:
-               mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+               mem->bus.offset = mem->start << PAGE_SHIFT;
                /* check if it's visible */
                if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size)
                        return -EINVAL;
@@ -699,7 +687,7 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
        int r;
 
        gtt = container_of(backend, struct radeon_ttm_backend, backend);
-       gtt->offset = bo_mem->mm_node->start << PAGE_SHIFT;
+       gtt->offset = bo_mem->start << PAGE_SHIFT;
        if (!gtt->num_pages) {
                WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
        }
@@ -798,9 +786,9 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
                radeon_mem_types_list[i].show = &radeon_mm_dump_table;
                radeon_mem_types_list[i].driver_features = 0;
                if (i == 0)
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].manager;
+                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv;
                else
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].manager;
+                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv;
 
        }
        /* Add ttm page pool to debugfs */
index f78fd592544d67a58e15016487d4d8b47ee38bf7..ac40fd39d7873f23fd48235d676c5e59ddd9a4a2 100644 (file)
@@ -22,6 +22,10 @@ evergreen 0x9400
 0x00008B10 PA_SC_LINE_STIPPLE_STATE
 0x00008BF0 PA_SC_ENHANCE
 0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008D90 SQ_DYN_GPR_OPTIMIZATION
+0x00008D94 SQ_DYN_GPR_SIMD_LOCK_EN
+0x00008D98 SQ_DYN_GPR_THREAD_LIMIT
+0x00008D9C SQ_DYN_GPR_LDS_LIMIT
 0x00008C00 SQ_CONFIG
 0x00008C04 SQ_GPR_RESOURCE_MGMT_1
 0x00008C08 SQ_GPR_RESOURCE_MGMT_2
@@ -34,6 +38,10 @@ evergreen 0x9400
 0x00008C24 SQ_STACK_RESOURCE_MGMT_2
 0x00008C28 SQ_STACK_RESOURCE_MGMT_3
 0x00008DF8 SQ_CONST_MEM_BASE
+0x00008E20 SQ_STATIC_THREAD_MGMT_1
+0x00008E24 SQ_STATIC_THREAD_MGMT_2
+0x00008E28 SQ_STATIC_THREAD_MGMT_3
+0x00008E2C SQ_LDS_RESOURCE_MGMT
 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
 0x00009100 SPI_CONFIG_CNTL
 0x0000913C SPI_CONFIG_CNTL_1
index ae2b76b9a388ae78da7e9d923a14de2d19c956e8..f683e51a2a0674518b476d6a2157b39a303170a6 100644 (file)
@@ -397,6 +397,12 @@ static int rs400_startup(struct radeon_device *rdev)
        r = rs400_gart_enable(rdev);
        if (r)
                return r;
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r100_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -406,9 +412,6 @@ static int rs400_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -443,7 +446,7 @@ int rs400_resume(struct radeon_device *rdev)
 int rs400_suspend(struct radeon_device *rdev)
 {
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
        rs400_gart_disable(rdev);
        return 0;
@@ -452,7 +455,7 @@ int rs400_suspend(struct radeon_device *rdev)
 void rs400_fini(struct radeon_device *rdev)
 {
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        rs400_gart_fini(rdev);
@@ -526,7 +529,7 @@ int rs400_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                rs400_gart_fini(rdev);
                radeon_irq_kms_fini(rdev);
index 51d5f7b5ab21b40a6e34d2fd286f28da91e4f0b0..b091a1f6fa4ed2b86dc1975717abbf017667c251 100644 (file)
@@ -796,6 +796,12 @@ static int rs600_startup(struct radeon_device *rdev)
        r = rs600_gart_enable(rdev);
        if (r)
                return r;
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        rs600_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -805,9 +811,6 @@ static int rs600_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -848,7 +851,7 @@ int rs600_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        rs600_irq_disable(rdev);
        rs600_gart_disable(rdev);
        return 0;
@@ -858,7 +861,7 @@ void rs600_fini(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        rs600_gart_fini(rdev);
@@ -932,7 +935,7 @@ int rs600_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                rs600_gart_fini(rdev);
                radeon_irq_kms_fini(rdev);
index 4dc2a87ea68018f0292cc0724d6ef4868c00e8ac..0137d3e3728d950734fdbe9e3489a9f2f44847f1 100644 (file)
@@ -616,6 +616,12 @@ static int rs690_startup(struct radeon_device *rdev)
        r = rs400_gart_enable(rdev);
        if (r)
                return r;
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        rs600_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -625,9 +631,6 @@ static int rs690_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -668,7 +671,7 @@ int rs690_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        rs600_irq_disable(rdev);
        rs400_gart_disable(rdev);
        return 0;
@@ -678,7 +681,7 @@ void rs690_fini(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        rs400_gart_fini(rdev);
@@ -753,7 +756,7 @@ int rs690_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                rs400_gart_fini(rdev);
                radeon_irq_kms_fini(rdev);
index 4d6e86041a9fde07f8caa56c4f90ba75c05a9f9e..5d569f41f4aeadbe04ee1d1c21cb165d4bf8c338 100644 (file)
@@ -386,6 +386,12 @@ static int rv515_startup(struct radeon_device *rdev)
                if (r)
                        return r;
        }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        rs600_irq_set(rdev);
        rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -395,9 +401,6 @@ static int rv515_startup(struct radeon_device *rdev)
                dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
                return r;
        }
-       r = r100_wb_init(rdev);
-       if (r)
-               dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
        r = r100_ib_init(rdev);
        if (r) {
                dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -431,7 +434,7 @@ int rv515_resume(struct radeon_device *rdev)
 int rv515_suspend(struct radeon_device *rdev)
 {
        r100_cp_disable(rdev);
-       r100_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        rs600_irq_disable(rdev);
        if (rdev->flags & RADEON_IS_PCIE)
                rv370_pcie_gart_disable(rdev);
@@ -447,7 +450,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev)
 void rv515_fini(struct radeon_device *rdev)
 {
        r100_cp_fini(rdev);
-       r100_wb_fini(rdev);
+       radeon_wb_fini(rdev);
        r100_ib_fini(rdev);
        radeon_gem_fini(rdev);
        rv370_pcie_gart_fini(rdev);
@@ -527,7 +530,7 @@ int rv515_init(struct radeon_device *rdev)
                /* Somethings want wront with the accel init stop accel */
                dev_err(rdev->dev, "Disabling GPU acceleration\n");
                r100_cp_fini(rdev);
-               r100_wb_fini(rdev);
+               radeon_wb_fini(rdev);
                r100_ib_fini(rdev);
                radeon_irq_kms_fini(rdev);
                rv370_pcie_gart_fini(rdev);
index 9490da700749487c00fe9c57671ec89727653136..245374e2b778b7706e9bf828c8a65876c1e11a00 100644 (file)
@@ -269,6 +269,7 @@ void r700_cp_stop(struct radeon_device *rdev)
 {
        rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
+       WREG32(SCRATCH_UMSK, 0);
 }
 
 static int rv770_cp_load_microcode(struct radeon_device *rdev)
@@ -643,10 +644,11 @@ static void rv770_gpu_init(struct radeon_device *rdev)
        else
                gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
        rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3);
-
-       gb_tiling_config |= GROUP_SIZE(0);
-       rdev->config.rv770.tiling_group_size = 256;
-
+       gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+       if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+               rdev->config.rv770.tiling_group_size = 512;
+       else
+               rdev->config.rv770.tiling_group_size = 256;
        if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) {
                gb_tiling_config |= ROW_TILING(3);
                gb_tiling_config |= SAMPLE_SPLIT(3);
@@ -1030,19 +1032,12 @@ static int rv770_startup(struct radeon_device *rdev)
                rdev->asic->copy = NULL;
                dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
        }
-       /* pin copy shader into vram */
-       if (rdev->r600_blit.shader_obj) {
-               r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-               if (unlikely(r != 0))
-                       return r;
-               r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-                               &rdev->r600_blit.shader_gpu_addr);
-               radeon_bo_unreserve(rdev->r600_blit.shader_obj);
-               if (r) {
-                       DRM_ERROR("failed to pin blit object %d\n", r);
-                       return r;
-               }
-       }
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
        /* Enable IRQ */
        r = r600_irq_init(rdev);
        if (r) {
@@ -1061,8 +1056,7 @@ static int rv770_startup(struct radeon_device *rdev)
        r = r600_cp_resume(rdev);
        if (r)
                return r;
-       /* write back buffer are not vital so don't worry about failure */
-       r600_wb_enable(rdev);
+
        return 0;
 }
 
@@ -1108,7 +1102,7 @@ int rv770_suspend(struct radeon_device *rdev)
        r700_cp_stop(rdev);
        rdev->cp.ready = false;
        r600_irq_suspend(rdev);
-       r600_wb_disable(rdev);
+       radeon_wb_disable(rdev);
        rv770_pcie_gart_disable(rdev);
        /* unpin shaders bo */
        if (rdev->r600_blit.shader_obj) {
@@ -1203,8 +1197,8 @@ int rv770_init(struct radeon_device *rdev)
        if (r) {
                dev_err(rdev->dev, "disabling GPU acceleration\n");
                r700_cp_fini(rdev);
-               r600_wb_fini(rdev);
                r600_irq_fini(rdev);
+               radeon_wb_fini(rdev);
                radeon_irq_kms_fini(rdev);
                rv770_pcie_gart_fini(rdev);
                rdev->accel_working = false;
@@ -1236,8 +1230,8 @@ void rv770_fini(struct radeon_device *rdev)
 {
        r600_blit_fini(rdev);
        r700_cp_fini(rdev);
-       r600_wb_fini(rdev);
        r600_irq_fini(rdev);
+       radeon_wb_fini(rdev);
        radeon_irq_kms_fini(rdev);
        rv770_pcie_gart_fini(rdev);
        rv770_vram_scratch_fini(rdev);
index 2a2830f5a8409b802a000b663faa1580d9a20815..fa64d25d4248d6e361ace5c8ea920b322a65f0c5 100644 (file)
@@ -42,8 +42,6 @@ static struct drm_driver driver = {
        .lastclose = savage_driver_lastclose,
        .unload = savage_driver_unload,
        .reclaim_buffers = savage_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = savage_ioctls,
        .dma_ioctl = savage_bci_buffers,
        .fops = {
index 4bb10ef6676a711b795346006f2e97ebdce51e42..4caf5d01cfd3feb5ae76e3fefc7cbe0bea8c20f8 100644 (file)
@@ -67,13 +67,10 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
        .load = sis_driver_load,
        .unload = sis_driver_unload,
-       .context_dtor = NULL,
        .dma_quiescent = sis_idle,
        .reclaim_buffers = NULL,
        .reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
        .lastclose = sis_lastclose,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = sis_ioctls,
        .fops = {
                 .owner = THIS_MODULE,
index 640567ef713dbe97e9f22c710a7d951cc73c46b5..b70fa91d761a950ef163877327c31254cfa1ce32 100644 (file)
@@ -42,8 +42,6 @@ static struct pci_device_id pciidlist[] = {
 static struct drm_driver driver = {
        .driver_features = DRIVER_USE_MTRR,
        .reclaim_buffers = drm_core_reclaim_buffers,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .fops = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
index b256d4adfafe76710cf1dd6e3b03371e03f7fd46..f3cf6f02c9970da645280df0f12622a12a3e0d7e 100644 (file)
@@ -4,6 +4,7 @@
 ccflags-y := -Iinclude/drm
 ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
        ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
-       ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o
+       ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o \
+       ttm_bo_manager.o
 
 obj-$(CONFIG_DRM_TTM) += ttm.o
index 4bf69c4044913d7e890f06a93aa2e5d25ca40fb9..f999e36f30b4c184fd5d04aa2f34bf085eba89ab 100644 (file)
@@ -74,6 +74,7 @@ static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
 {
        struct ttm_agp_backend *agp_be =
            container_of(backend, struct ttm_agp_backend, backend);
+       struct drm_mm_node *node = bo_mem->mm_node;
        struct agp_memory *mem = agp_be->mem;
        int cached = (bo_mem->placement & TTM_PL_FLAG_CACHED);
        int ret;
@@ -81,7 +82,7 @@ static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
        mem->is_flushed = 1;
        mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY;
 
-       ret = agp_bind_memory(mem, bo_mem->mm_node->start);
+       ret = agp_bind_memory(mem, node->start);
        if (ret)
                printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n");
 
index db809e034cc48b6d8c246cba1ede0660113e30de..a1cb783c7131c56de8aa19cf5afb6a668e5e4345 100644 (file)
@@ -84,11 +84,8 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
                man->available_caching);
        printk(KERN_ERR TTM_PFX "    default_caching: 0x%08X\n",
                man->default_caching);
-       if (mem_type != TTM_PL_SYSTEM) {
-               spin_lock(&bdev->glob->lru_lock);
-               drm_mm_debug_table(&man->manager, TTM_PFX);
-               spin_unlock(&bdev->glob->lru_lock);
-       }
+       if (mem_type != TTM_PL_SYSTEM)
+               (*man->func->debug)(man, TTM_PFX);
 }
 
 static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
@@ -169,18 +166,13 @@ static void ttm_bo_release_list(struct kref *list_kref)
 
 int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
 {
-
        if (interruptible) {
-               int ret = 0;
-
-               ret = wait_event_interruptible(bo->event_queue,
+               return wait_event_interruptible(bo->event_queue,
                                               atomic_read(&bo->reserved) == 0);
-               if (unlikely(ret != 0))
-                       return ret;
        } else {
                wait_event(bo->event_queue, atomic_read(&bo->reserved) == 0);
+               return 0;
        }
-       return 0;
 }
 EXPORT_SYMBOL(ttm_bo_wait_unreserved);
 
@@ -421,7 +413,7 @@ moved:
 
        if (bo->mem.mm_node) {
                spin_lock(&bo->lock);
-               bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) +
+               bo->offset = (bo->mem.start << PAGE_SHIFT) +
                    bdev->man[bo->mem.mem_type].gpu_offset;
                bo->cur_placement = bo->mem.placement;
                spin_unlock(&bo->lock);
@@ -442,135 +434,144 @@ out_err:
 }
 
 /**
- * Call bo::reserved and with the lru lock held.
+ * Call bo::reserved.
  * Will release GPU memory type usage on destruction.
- * This is the place to put in driver specific hooks.
- * Will release the bo::reserved lock and the
- * lru lock on exit.
+ * This is the place to put in driver specific hooks to release
+ * driver private resources.
+ * Will release the bo::reserved lock.
  */
 
 static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
 {
-       struct ttm_bo_global *glob = bo->glob;
-
        if (bo->ttm) {
-
-               /**
-                * Release the lru_lock, since we don't want to have
-                * an atomic requirement on ttm_tt[unbind|destroy].
-                */
-
-               spin_unlock(&glob->lru_lock);
                ttm_tt_unbind(bo->ttm);
                ttm_tt_destroy(bo->ttm);
                bo->ttm = NULL;
-               spin_lock(&glob->lru_lock);
        }
 
-       if (bo->mem.mm_node) {
-               drm_mm_put_block(bo->mem.mm_node);
-               bo->mem.mm_node = NULL;
-       }
+       ttm_bo_mem_put(bo, &bo->mem);
 
        atomic_set(&bo->reserved, 0);
        wake_up_all(&bo->event_queue);
-       spin_unlock(&glob->lru_lock);
 }
 
-
-/**
- * If bo idle, remove from delayed- and lru lists, and unref.
- * If not idle, and already on delayed list, do nothing.
- * If not idle, and not on delayed list, put on delayed list,
- *   up the list_kref and schedule a delayed list check.
- */
-
-static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
+static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_bo_global *glob = bo->glob;
-       struct ttm_bo_driver *driver = bdev->driver;
+       struct ttm_bo_driver *driver;
+       void *sync_obj;
+       void *sync_obj_arg;
+       int put_count;
        int ret;
 
        spin_lock(&bo->lock);
-retry:
-       (void) ttm_bo_wait(bo, false, false, !remove_all);
-
+       (void) ttm_bo_wait(bo, false, false, true);
        if (!bo->sync_obj) {
-               int put_count;
-
-               spin_unlock(&bo->lock);
 
                spin_lock(&glob->lru_lock);
-               ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
 
                /**
-                * Someone else has the object reserved. Bail and retry.
+                * Lock inversion between bo::reserve and bo::lock here,
+                * but that's OK, since we're only trylocking.
                 */
 
-               if (unlikely(ret == -EBUSY)) {
-                       spin_unlock(&glob->lru_lock);
-                       spin_lock(&bo->lock);
-                       goto requeue;
-               }
-
-               /**
-                * We can re-check for sync object without taking
-                * the bo::lock since setting the sync object requires
-                * also bo::reserved. A busy object at this point may
-                * be caused by another thread starting an accelerated
-                * eviction.
-                */
+               ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
 
-               if (unlikely(bo->sync_obj)) {
-                       atomic_set(&bo->reserved, 0);
-                       wake_up_all(&bo->event_queue);
-                       spin_unlock(&glob->lru_lock);
-                       spin_lock(&bo->lock);
-                       if (remove_all)
-                               goto retry;
-                       else
-                               goto requeue;
-               }
+               if (unlikely(ret == -EBUSY))
+                       goto queue;
 
+               spin_unlock(&bo->lock);
                put_count = ttm_bo_del_from_lru(bo);
 
-               if (!list_empty(&bo->ddestroy)) {
-                       list_del_init(&bo->ddestroy);
-                       ++put_count;
-               }
-
+               spin_unlock(&glob->lru_lock);
                ttm_bo_cleanup_memtype_use(bo);
 
                while (put_count--)
                        kref_put(&bo->list_kref, ttm_bo_ref_bug);
 
-               return 0;
+               return;
+       } else {
+               spin_lock(&glob->lru_lock);
        }
-requeue:
+queue:
+       sync_obj = bo->sync_obj;
+       sync_obj_arg = bo->sync_obj_arg;
+       driver = bdev->driver;
+
+       kref_get(&bo->list_kref);
+       list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+       spin_unlock(&glob->lru_lock);
+       spin_unlock(&bo->lock);
+
+       if (sync_obj)
+               driver->sync_obj_flush(sync_obj, sync_obj_arg);
+       schedule_delayed_work(&bdev->wq,
+                             ((HZ / 100) < 1) ? 1 : HZ / 100);
+}
+
+/**
+ * function ttm_bo_cleanup_refs
+ * If bo idle, remove from delayed- and lru lists, and unref.
+ * If not idle, do nothing.
+ *
+ * @interruptible         Any sleeps should occur interruptibly.
+ * @no_wait_reserve       Never wait for reserve. Return -EBUSY instead.
+ * @no_wait_gpu           Never wait for gpu. Return -EBUSY instead.
+ */
+
+static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
+                              bool interruptible,
+                              bool no_wait_reserve,
+                              bool no_wait_gpu)
+{
+       struct ttm_bo_global *glob = bo->glob;
+       int put_count;
+       int ret = 0;
+
+retry:
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
+       spin_unlock(&bo->lock);
+
+       if (unlikely(ret != 0))
+               return ret;
+
        spin_lock(&glob->lru_lock);
-       if (list_empty(&bo->ddestroy)) {
-               void *sync_obj = bo->sync_obj;
-               void *sync_obj_arg = bo->sync_obj_arg;
+       ret = ttm_bo_reserve_locked(bo, interruptible,
+                                   no_wait_reserve, false, 0);
 
-               kref_get(&bo->list_kref);
-               list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+       if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) {
                spin_unlock(&glob->lru_lock);
-               spin_unlock(&bo->lock);
+               return ret;
+       }
 
-               if (sync_obj)
-                       driver->sync_obj_flush(sync_obj, sync_obj_arg);
-               schedule_delayed_work(&bdev->wq,
-                                     ((HZ / 100) < 1) ? 1 : HZ / 100);
-               ret = 0;
+       /**
+        * We can re-check for sync object without taking
+        * the bo::lock since setting the sync object requires
+        * also bo::reserved. A busy object at this point may
+        * be caused by another thread recently starting an accelerated
+        * eviction.
+        */
 
-       } else {
+       if (unlikely(bo->sync_obj)) {
+               atomic_set(&bo->reserved, 0);
+               wake_up_all(&bo->event_queue);
                spin_unlock(&glob->lru_lock);
-               spin_unlock(&bo->lock);
-               ret = -EBUSY;
+               goto retry;
        }
 
-       return ret;
+       put_count = ttm_bo_del_from_lru(bo);
+       list_del_init(&bo->ddestroy);
+       ++put_count;
+
+       spin_unlock(&glob->lru_lock);
+       ttm_bo_cleanup_memtype_use(bo);
+
+       while (put_count--)
+               kref_put(&bo->list_kref, ttm_bo_ref_bug);
+
+       return 0;
 }
 
 /**
@@ -602,7 +603,8 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
                }
 
                spin_unlock(&glob->lru_lock);
-               ret = ttm_bo_cleanup_refs(entry, remove_all);
+               ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
+                                         !remove_all);
                kref_put(&entry->list_kref, ttm_bo_release_list);
                entry = nentry;
 
@@ -645,7 +647,7 @@ static void ttm_bo_release(struct kref *kref)
                bo->vm_node = NULL;
        }
        write_unlock(&bdev->vm_lock);
-       ttm_bo_cleanup_refs(bo, false);
+       ttm_bo_cleanup_refs_or_queue(bo);
        kref_put(&bo->list_kref, ttm_bo_release_list);
        write_lock(&bdev->vm_lock);
 }
@@ -680,7 +682,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
                        bool no_wait_reserve, bool no_wait_gpu)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_global *glob = bo->glob;
        struct ttm_mem_reg evict_mem;
        struct ttm_placement placement;
        int ret = 0;
@@ -726,12 +727,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
        if (ret) {
                if (ret != -ERESTARTSYS)
                        printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
-               spin_lock(&glob->lru_lock);
-               if (evict_mem.mm_node) {
-                       drm_mm_put_block(evict_mem.mm_node);
-                       evict_mem.mm_node = NULL;
-               }
-               spin_unlock(&glob->lru_lock);
+               ttm_bo_mem_put(bo, &evict_mem);
                goto out;
        }
        bo->evicted = true;
@@ -759,6 +755,18 @@ retry:
        bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
        kref_get(&bo->list_kref);
 
+       if (!list_empty(&bo->ddestroy)) {
+               spin_unlock(&glob->lru_lock);
+               ret = ttm_bo_cleanup_refs(bo, interruptible,
+                                         no_wait_reserve, no_wait_gpu);
+               kref_put(&bo->list_kref, ttm_bo_release_list);
+
+               if (likely(ret == 0 || ret == -ERESTARTSYS))
+                       return ret;
+
+               goto retry;
+       }
+
        ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0);
 
        if (unlikely(ret == -EBUSY)) {
@@ -792,41 +800,14 @@ retry:
        return ret;
 }
 
-static int ttm_bo_man_get_node(struct ttm_buffer_object *bo,
-                               struct ttm_mem_type_manager *man,
-                               struct ttm_placement *placement,
-                               struct ttm_mem_reg *mem,
-                               struct drm_mm_node **node)
+void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
 {
-       struct ttm_bo_global *glob = bo->glob;
-       unsigned long lpfn;
-       int ret;
+       struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
 
-       lpfn = placement->lpfn;
-       if (!lpfn)
-               lpfn = man->size;
-       *node = NULL;
-       do {
-               ret = drm_mm_pre_get(&man->manager);
-               if (unlikely(ret))
-                       return ret;
-
-               spin_lock(&glob->lru_lock);
-               *node = drm_mm_search_free_in_range(&man->manager,
-                                       mem->num_pages, mem->page_alignment,
-                                       placement->fpfn, lpfn, 1);
-               if (unlikely(*node == NULL)) {
-                       spin_unlock(&glob->lru_lock);
-                       return 0;
-               }
-               *node = drm_mm_get_block_atomic_range(*node, mem->num_pages,
-                                                       mem->page_alignment,
-                                                       placement->fpfn,
-                                                       lpfn);
-               spin_unlock(&glob->lru_lock);
-       } while (*node == NULL);
-       return 0;
+       if (mem->mm_node)
+               (*man->func->put_node)(man, mem);
 }
+EXPORT_SYMBOL(ttm_bo_mem_put);
 
 /**
  * Repeatedly evict memory from the LRU for @mem_type until we create enough
@@ -843,14 +824,13 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_bo_global *glob = bdev->glob;
        struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-       struct drm_mm_node *node;
        int ret;
 
        do {
-               ret = ttm_bo_man_get_node(bo, man, placement, mem, &node);
+               ret = (*man->func->get_node)(man, bo, placement, mem);
                if (unlikely(ret != 0))
                        return ret;
-               if (node)
+               if (mem->mm_node)
                        break;
                spin_lock(&glob->lru_lock);
                if (list_empty(&man->lru)) {
@@ -863,9 +843,8 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
                if (unlikely(ret != 0))
                        return ret;
        } while (1);
-       if (node == NULL)
+       if (mem->mm_node == NULL)
                return -ENOMEM;
-       mem->mm_node = node;
        mem->mem_type = mem_type;
        return 0;
 }
@@ -939,7 +918,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
        bool type_found = false;
        bool type_ok = false;
        bool has_erestartsys = false;
-       struct drm_mm_node *node = NULL;
        int i, ret;
 
        mem->mm_node = NULL;
@@ -973,17 +951,15 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 
                if (man->has_type && man->use_type) {
                        type_found = true;
-                       ret = ttm_bo_man_get_node(bo, man, placement, mem,
-                                                       &node);
+                       ret = (*man->func->get_node)(man, bo, placement, mem);
                        if (unlikely(ret))
                                return ret;
                }
-               if (node)
+               if (mem->mm_node)
                        break;
        }
 
-       if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || node) {
-               mem->mm_node = node;
+       if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || mem->mm_node) {
                mem->mem_type = mem_type;
                mem->placement = cur_flags;
                return 0;
@@ -1053,7 +1029,6 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
                        bool interruptible, bool no_wait_reserve,
                        bool no_wait_gpu)
 {
-       struct ttm_bo_global *glob = bo->glob;
        int ret = 0;
        struct ttm_mem_reg mem;
 
@@ -1081,11 +1056,8 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
                goto out_unlock;
        ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait_reserve, no_wait_gpu);
 out_unlock:
-       if (ret && mem.mm_node) {
-               spin_lock(&glob->lru_lock);
-               drm_mm_put_block(mem.mm_node);
-               spin_unlock(&glob->lru_lock);
-       }
+       if (ret && mem.mm_node)
+               ttm_bo_mem_put(bo, &mem);
        return ret;
 }
 
@@ -1093,11 +1065,10 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement,
                             struct ttm_mem_reg *mem)
 {
        int i;
-       struct drm_mm_node *node = mem->mm_node;
 
-       if (node && placement->lpfn != 0 &&
-           (node->start < placement->fpfn ||
-            node->start + node->size > placement->lpfn))
+       if (mem->mm_node && placement->lpfn != 0 &&
+           (mem->start < placement->fpfn ||
+            mem->start + mem->num_pages > placement->lpfn))
                return -1;
 
        for (i = 0; i < placement->num_placement; i++) {
@@ -1341,7 +1312,6 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
 
 int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
 {
-       struct ttm_bo_global *glob = bdev->glob;
        struct ttm_mem_type_manager *man;
        int ret = -EINVAL;
 
@@ -1364,13 +1334,7 @@ int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
        if (mem_type > 0) {
                ttm_bo_force_list_clean(bdev, mem_type, false);
 
-               spin_lock(&glob->lru_lock);
-               if (drm_mm_clean(&man->manager))
-                       drm_mm_takedown(&man->manager);
-               else
-                       ret = -EBUSY;
-
-               spin_unlock(&glob->lru_lock);
+               ret = (*man->func->takedown)(man);
        }
 
        return ret;
@@ -1421,6 +1385,7 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
        ret = bdev->driver->init_mem_type(bdev, type, man);
        if (ret)
                return ret;
+       man->bdev = bdev;
 
        ret = 0;
        if (type != TTM_PL_SYSTEM) {
@@ -1430,7 +1395,8 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
                               type);
                        return ret;
                }
-               ret = drm_mm_init(&man->manager, 0, p_size);
+
+               ret = (*man->func->init)(man, p_size);
                if (ret)
                        return ret;
        }
@@ -1824,6 +1790,13 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
                                      struct ttm_buffer_object, swap);
                kref_get(&bo->list_kref);
 
+               if (!list_empty(&bo->ddestroy)) {
+                       spin_unlock(&glob->lru_lock);
+                       (void) ttm_bo_cleanup_refs(bo, false, false, false);
+                       kref_put(&bo->list_kref, ttm_bo_release_list);
+                       continue;
+               }
+
                /**
                 * Reserve buffer. Since we unlock while sleeping, we need
                 * to re-check that nobody removed us from the swap-list while
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
new file mode 100644 (file)
index 0000000..7410c19
--- /dev/null
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
+ * 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 COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/module.h>
+
+static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
+                              struct ttm_buffer_object *bo,
+                              struct ttm_placement *placement,
+                              struct ttm_mem_reg *mem)
+{
+       struct ttm_bo_global *glob = man->bdev->glob;
+       struct drm_mm *mm = man->priv;
+       struct drm_mm_node *node = NULL;
+       unsigned long lpfn;
+       int ret;
+
+       lpfn = placement->lpfn;
+       if (!lpfn)
+               lpfn = man->size;
+       do {
+               ret = drm_mm_pre_get(mm);
+               if (unlikely(ret))
+                       return ret;
+
+               spin_lock(&glob->lru_lock);
+               node = drm_mm_search_free_in_range(mm,
+                                       mem->num_pages, mem->page_alignment,
+                                       placement->fpfn, lpfn, 1);
+               if (unlikely(node == NULL)) {
+                       spin_unlock(&glob->lru_lock);
+                       return 0;
+               }
+               node = drm_mm_get_block_atomic_range(node, mem->num_pages,
+                                                       mem->page_alignment,
+                                                       placement->fpfn,
+                                                       lpfn);
+               spin_unlock(&glob->lru_lock);
+       } while (node == NULL);
+
+       mem->mm_node = node;
+       mem->start = node->start;
+       return 0;
+}
+
+static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
+                               struct ttm_mem_reg *mem)
+{
+       struct ttm_bo_global *glob = man->bdev->glob;
+
+       if (mem->mm_node) {
+               spin_lock(&glob->lru_lock);
+               drm_mm_put_block(mem->mm_node);
+               spin_unlock(&glob->lru_lock);
+               mem->mm_node = NULL;
+       }
+}
+
+static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
+                          unsigned long p_size)
+{
+       struct drm_mm *mm;
+       int ret;
+
+       mm = kzalloc(sizeof(*mm), GFP_KERNEL);
+       if (!mm)
+               return -ENOMEM;
+
+       ret = drm_mm_init(mm, 0, p_size);
+       if (ret) {
+               kfree(mm);
+               return ret;
+       }
+
+       man->priv = mm;
+       return 0;
+}
+
+static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
+{
+       struct ttm_bo_global *glob = man->bdev->glob;
+       struct drm_mm *mm = man->priv;
+       int ret = 0;
+
+       spin_lock(&glob->lru_lock);
+       if (drm_mm_clean(mm)) {
+               drm_mm_takedown(mm);
+               kfree(mm);
+               man->priv = NULL;
+       } else
+               ret = -EBUSY;
+       spin_unlock(&glob->lru_lock);
+       return ret;
+}
+
+static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
+                            const char *prefix)
+{
+       struct ttm_bo_global *glob = man->bdev->glob;
+       struct drm_mm *mm = man->priv;
+
+       spin_lock(&glob->lru_lock);
+       drm_mm_debug_table(mm, prefix);
+       spin_unlock(&glob->lru_lock);
+}
+
+const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
+       ttm_bo_man_init,
+       ttm_bo_man_takedown,
+       ttm_bo_man_get_node,
+       ttm_bo_man_put_node,
+       ttm_bo_man_debug
+};
+EXPORT_SYMBOL(ttm_bo_manager_func);
index 3451a82adba76c31672ee96f086146f5da1ab12b..3106d5bcce32d908f0991ad07eca6936c5c01cde 100644 (file)
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
-
-       if (old_mem->mm_node) {
-               spin_lock(&bo->glob->lru_lock);
-               drm_mm_put_block(old_mem->mm_node);
-               spin_unlock(&bo->glob->lru_lock);
-       }
-       old_mem->mm_node = NULL;
+       ttm_bo_mem_put(bo, &bo->mem);
 }
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
@@ -170,7 +163,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
        src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
 
 #ifdef CONFIG_X86
-       dst = kmap_atomic_prot(d, KM_USER0, prot);
+       dst = kmap_atomic_prot(d, prot);
 #else
        if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
                dst = vmap(&d, 1, 0, prot);
@@ -183,7 +176,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
        memcpy_fromio(dst, src, PAGE_SIZE);
 
 #ifdef CONFIG_X86
-       kunmap_atomic(dst, KM_USER0);
+       kunmap_atomic(dst);
 #else
        if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
                vunmap(dst);
@@ -206,7 +199,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
 
        dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
 #ifdef CONFIG_X86
-       src = kmap_atomic_prot(s, KM_USER0, prot);
+       src = kmap_atomic_prot(s, prot);
 #else
        if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
                src = vmap(&s, 1, 0, prot);
@@ -219,7 +212,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
        memcpy_toio(dst, src, PAGE_SIZE);
 
 #ifdef CONFIG_X86
-       kunmap_atomic(src, KM_USER0);
+       kunmap_atomic(src);
 #else
        if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
                vunmap(src);
@@ -263,8 +256,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
        dir = 1;
 
        if ((old_mem->mem_type == new_mem->mem_type) &&
-           (new_mem->mm_node->start <
-            old_mem->mm_node->start + old_mem->mm_node->size)) {
+           (new_mem->start < old_mem->start + old_mem->size)) {
                dir = -1;
                add = new_mem->num_pages - 1;
        }
index b8984a5ae5218b375764fe2845d6c8cb5febc548..e1ff4e7a6eb02ee72d09762c0ea70f7afa3bac28 100644 (file)
@@ -51,8 +51,6 @@ static struct drm_driver driver = {
        .reclaim_buffers_locked = NULL,
        .reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
        .lastclose = via_lastclose,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = via_ioctls,
        .fops = {
                .owner = THIS_MODULE,
index 4505e17df3f557e21beb14581e72f3356985e345..c9281a1b1d3b27c82c0c2c769745cff5edc1604f 100644 (file)
@@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm
 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
            vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
            vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
-           vmwgfx_overlay.o vmwgfx_fence.o
+           vmwgfx_overlay.o vmwgfx_fence.o vmwgfx_gmrid_manager.o
 
 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
index c4f5114aee7c8bf956867dd45da9ddb1f4236b00..80bc37b274e71b29c6b8c5622a020b945c915410 100644 (file)
@@ -39,6 +39,9 @@ static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
 static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
        TTM_PL_FLAG_CACHED;
 
+static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
+       TTM_PL_FLAG_CACHED;
+
 struct ttm_placement vmw_vram_placement = {
        .fpfn = 0,
        .lpfn = 0,
@@ -48,6 +51,20 @@ struct ttm_placement vmw_vram_placement = {
        .busy_placement = &vram_placement_flags
 };
 
+static uint32_t vram_gmr_placement_flags[] = {
+       TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
+       VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+};
+
+struct ttm_placement vmw_vram_gmr_placement = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .num_placement = 2,
+       .placement = vram_gmr_placement_flags,
+       .num_busy_placement = 1,
+       .busy_placement = &gmr_placement_flags
+};
+
 struct ttm_placement vmw_vram_sys_placement = {
        .fpfn = 0,
        .lpfn = 0,
@@ -77,27 +94,52 @@ struct ttm_placement vmw_sys_placement = {
 
 struct vmw_ttm_backend {
        struct ttm_backend backend;
+       struct page **pages;
+       unsigned long num_pages;
+       struct vmw_private *dev_priv;
+       int gmr_id;
 };
 
 static int vmw_ttm_populate(struct ttm_backend *backend,
                            unsigned long num_pages, struct page **pages,
                            struct page *dummy_read_page)
 {
+       struct vmw_ttm_backend *vmw_be =
+           container_of(backend, struct vmw_ttm_backend, backend);
+
+       vmw_be->pages = pages;
+       vmw_be->num_pages = num_pages;
+
        return 0;
 }
 
 static int vmw_ttm_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
 {
-       return 0;
+       struct vmw_ttm_backend *vmw_be =
+           container_of(backend, struct vmw_ttm_backend, backend);
+
+       vmw_be->gmr_id = bo_mem->start;
+
+       return vmw_gmr_bind(vmw_be->dev_priv, vmw_be->pages,
+                           vmw_be->num_pages, vmw_be->gmr_id);
 }
 
 static int vmw_ttm_unbind(struct ttm_backend *backend)
 {
+       struct vmw_ttm_backend *vmw_be =
+           container_of(backend, struct vmw_ttm_backend, backend);
+
+       vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
        return 0;
 }
 
 static void vmw_ttm_clear(struct ttm_backend *backend)
 {
+       struct vmw_ttm_backend *vmw_be =
+               container_of(backend, struct vmw_ttm_backend, backend);
+
+       vmw_be->pages = NULL;
+       vmw_be->num_pages = 0;
 }
 
 static void vmw_ttm_destroy(struct ttm_backend *backend)
@@ -125,6 +167,7 @@ struct ttm_backend *vmw_ttm_backend_init(struct ttm_bo_device *bdev)
                return NULL;
 
        vmw_be->backend.func = &vmw_ttm_func;
+       vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
 
        return &vmw_be->backend;
 }
@@ -142,15 +185,28 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                /* System memory */
 
                man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_MASK_CACHING;
+               man->available_caching = TTM_PL_FLAG_CACHED;
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case TTM_PL_VRAM:
                /* "On-card" video ram */
+               man->func = &ttm_bo_manager_func;
                man->gpu_offset = 0;
                man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_WC;
+               man->available_caching = TTM_PL_FLAG_CACHED;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case VMW_PL_GMR:
+               /*
+                * "Guest Memory Regions" is an aperture like feature with
+                *  one slot per bo. There is an upper limit of the number of
+                *  slots as well as the bo size.
+                */
+               man->func = &vmw_gmrid_manager_func;
+               man->gpu_offset = 0;
+               man->flags = TTM_MEMTYPE_FLAG_CMA | TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_FLAG_CACHED;
+               man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        default:
                DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
@@ -174,18 +230,6 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
        return 0;
 }
 
-static void vmw_move_notify(struct ttm_buffer_object *bo,
-                    struct ttm_mem_reg *new_mem)
-{
-       if (new_mem->mem_type != TTM_PL_SYSTEM)
-               vmw_dmabuf_gmr_unbind(bo);
-}
-
-static void vmw_swap_notify(struct ttm_buffer_object *bo)
-{
-       vmw_dmabuf_gmr_unbind(bo);
-}
-
 static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
        struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
@@ -200,10 +244,10 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
                return -EINVAL;
        switch (mem->mem_type) {
        case TTM_PL_SYSTEM:
-               /* System memory */
+       case VMW_PL_GMR:
                return 0;
        case TTM_PL_VRAM:
-               mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+               mem->bus.offset = mem->start << PAGE_SHIFT;
                mem->bus.base = dev_priv->vram_start;
                mem->bus.is_iomem = true;
                break;
@@ -276,8 +320,8 @@ struct ttm_bo_driver vmw_bo_driver = {
        .sync_obj_flush = vmw_sync_obj_flush,
        .sync_obj_unref = vmw_sync_obj_unref,
        .sync_obj_ref = vmw_sync_obj_ref,
-       .move_notify = vmw_move_notify,
-       .swap_notify = vmw_swap_notify,
+       .move_notify = NULL,
+       .swap_notify = NULL,
        .fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
        .io_mem_reserve = &vmw_ttm_io_mem_reserve,
        .io_mem_free = &vmw_ttm_io_mem_free,
index 2ef93df9e8ae39f8c9e267a500ee5157f2fda420..10ca97ee02063c6c83c56b27f2d5ac895382dad1 100644 (file)
@@ -260,13 +260,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        idr_init(&dev_priv->context_idr);
        idr_init(&dev_priv->surface_idr);
        idr_init(&dev_priv->stream_idr);
-       ida_init(&dev_priv->gmr_ida);
        mutex_init(&dev_priv->init_mutex);
        init_waitqueue_head(&dev_priv->fence_queue);
        init_waitqueue_head(&dev_priv->fifo_queue);
        atomic_set(&dev_priv->fence_queue_waiters, 0);
        atomic_set(&dev_priv->fifo_queue_waiters, 0);
-       INIT_LIST_HEAD(&dev_priv->gmr_lru);
 
        dev_priv->io_start = pci_resource_start(dev->pdev, 0);
        dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
@@ -341,6 +339,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_err2;
        }
 
+       dev_priv->has_gmr = true;
+       if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+                          dev_priv->max_gmr_ids) != 0) {
+               DRM_INFO("No GMR memory available. "
+                        "Graphics memory resources are very limited.\n");
+               dev_priv->has_gmr = false;
+       }
+
        dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
                                           dev_priv->mmio_size, DRM_MTRR_WC);
 
@@ -440,13 +446,14 @@ out_err4:
 out_err3:
        drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
                     dev_priv->mmio_size, DRM_MTRR_WC);
+       if (dev_priv->has_gmr)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
        (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
 out_err2:
        (void)ttm_bo_device_release(&dev_priv->bdev);
 out_err1:
        vmw_ttm_global_release(dev_priv);
 out_err0:
-       ida_destroy(&dev_priv->gmr_ida);
        idr_destroy(&dev_priv->surface_idr);
        idr_destroy(&dev_priv->context_idr);
        idr_destroy(&dev_priv->stream_idr);
@@ -478,10 +485,11 @@ static int vmw_driver_unload(struct drm_device *dev)
        iounmap(dev_priv->mmio_virt);
        drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
                     dev_priv->mmio_size, DRM_MTRR_WC);
+       if (dev_priv->has_gmr)
+               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
        (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
        (void)ttm_bo_device_release(&dev_priv->bdev);
        vmw_ttm_global_release(dev_priv);
-       ida_destroy(&dev_priv->gmr_ida);
        idr_destroy(&dev_priv->surface_idr);
        idr_destroy(&dev_priv->context_idr);
        idr_destroy(&dev_priv->stream_idr);
@@ -597,6 +605,8 @@ static void vmw_lastclose(struct drm_device *dev)
 static void vmw_master_init(struct vmw_master *vmaster)
 {
        ttm_lock_init(&vmaster->lock);
+       INIT_LIST_HEAD(&vmaster->fb_surf);
+       mutex_init(&vmaster->fb_surf_mutex);
 }
 
 static int vmw_master_create(struct drm_device *dev,
@@ -608,7 +618,7 @@ static int vmw_master_create(struct drm_device *dev,
        if (unlikely(vmaster == NULL))
                return -ENOMEM;
 
-       ttm_lock_init(&vmaster->lock);
+       vmw_master_init(vmaster);
        ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
        master->driver_priv = vmaster;
 
@@ -699,6 +709,7 @@ static void vmw_master_drop(struct drm_device *dev,
 
        vmw_fp->locked_master = drm_master_get(file_priv->master);
        ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+       vmw_kms_idle_workqueues(vmaster);
 
        if (unlikely((ret != 0))) {
                DRM_ERROR("Unable to lock TTM at VT switch.\n");
@@ -751,15 +762,16 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
                 * Buffer contents is moved to swappable memory.
                 */
                ttm_bo_swapout_all(&dev_priv->bdev);
+
                break;
        case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
+       case PM_POST_RESTORE:
                ttm_suspend_unlock(&vmaster->lock);
+
                break;
        case PM_RESTORE_PREPARE:
                break;
-       case PM_POST_RESTORE:
-               break;
        default:
                break;
        }
@@ -770,21 +782,98 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
  * These might not be needed with the virtual SVGA device.
  */
 
-int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       if (dev_priv->num_3d_resources != 0) {
+               DRM_INFO("Can't suspend or hibernate "
+                        "while 3D resources are active.\n");
+               return -EBUSY;
+       }
+
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
        return 0;
 }
 
-int vmw_pci_resume(struct pci_dev *pdev)
+static int vmw_pci_resume(struct pci_dev *pdev)
 {
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        return pci_enable_device(pdev);
 }
 
+static int vmw_pm_suspend(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct pm_message dummy;
+
+       dummy.event = 0;
+
+       return vmw_pci_suspend(pdev, dummy);
+}
+
+static int vmw_pm_resume(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+
+       return vmw_pci_resume(pdev);
+}
+
+static int vmw_pm_prepare(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Release 3d reference held by fbdev and potentially
+        * stop fifo.
+        */
+       dev_priv->suspended = true;
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_dec(dev_priv);
+
+       if (dev_priv->num_3d_resources != 0) {
+
+               DRM_INFO("Can't suspend or hibernate "
+                        "while 3D resources are active.\n");
+
+               if (dev_priv->enable_fb)
+                       vmw_3d_resource_inc(dev_priv);
+               dev_priv->suspended = false;
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void vmw_pm_complete(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Reclaim 3d reference held by fbdev and potentially
+        * start fifo.
+        */
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_inc(dev_priv);
+
+       dev_priv->suspended = false;
+}
+
+static const struct dev_pm_ops vmw_pm_ops = {
+       .prepare = vmw_pm_prepare,
+       .complete = vmw_pm_complete,
+       .suspend = vmw_pm_suspend,
+       .resume = vmw_pm_resume,
+};
+
 static struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
        DRIVER_MODESET,
@@ -798,8 +887,6 @@ static struct drm_driver driver = {
        .irq_handler = vmw_irq_handler,
        .get_vblank_counter = vmw_get_vblank_counter,
        .reclaim_buffers_locked = NULL,
-       .get_map_ofs = drm_core_get_map_ofs,
-       .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = vmw_ioctls,
        .num_ioctls = DRM_ARRAY_SIZE(vmw_ioctls),
        .dma_quiescent = NULL,  /*vmw_dma_quiescent, */
@@ -821,15 +908,16 @@ static struct drm_driver driver = {
                 .compat_ioctl = drm_compat_ioctl,
 #endif
                 .llseek = noop_llseek,
-                },
+       },
        .pci_driver = {
-                      .name = VMWGFX_DRIVER_NAME,
-                      .id_table = vmw_pci_id_list,
-                      .probe = vmw_probe,
-                      .remove = vmw_remove,
-                      .suspend = vmw_pci_suspend,
-                      .resume = vmw_pci_resume
-                      },
+                .name = VMWGFX_DRIVER_NAME,
+                .id_table = vmw_pci_id_list,
+                .probe = vmw_probe,
+                .remove = vmw_remove,
+                .driver = {
+                        .pm = &vmw_pm_ops
+                }
+        },
        .name = VMWGFX_DRIVER_NAME,
        .desc = VMWGFX_DRIVER_DESC,
        .date = VMWGFX_DRIVER_DATE,
@@ -863,3 +951,7 @@ module_exit(vmwgfx_exit);
 MODULE_AUTHOR("VMware Inc. and others");
 MODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device");
 MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(__stringify(VMWGFX_DRIVER_MAJOR) "."
+              __stringify(VMWGFX_DRIVER_MINOR) "."
+              __stringify(VMWGFX_DRIVER_PATCHLEVEL) "."
+              "0");
index 58de6393f611dd79fbbebeab81102dcf0f4abfcb..e7a58d055041bfacd5e4af4b5f6f055dd6214a5b 100644 (file)
@@ -39,9 +39,9 @@
 #include "ttm/ttm_execbuf_util.h"
 #include "ttm/ttm_module.h"
 
-#define VMWGFX_DRIVER_DATE "20100209"
+#define VMWGFX_DRIVER_DATE "20100927"
 #define VMWGFX_DRIVER_MAJOR 1
-#define VMWGFX_DRIVER_MINOR 2
+#define VMWGFX_DRIVER_MINOR 4
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -49,6 +49,9 @@
 #define VMWGFX_MAX_GMRS 2048
 #define VMWGFX_MAX_DISPLAYS 16
 
+#define VMW_PL_GMR TTM_PL_PRIV0
+#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
+
 struct vmw_fpriv {
        struct drm_master *locked_master;
        struct ttm_object_file *tfile;
@@ -57,8 +60,6 @@ struct vmw_fpriv {
 struct vmw_dma_buffer {
        struct ttm_buffer_object base;
        struct list_head validate_list;
-       struct list_head gmr_lru;
-       uint32_t gmr_id;
        bool gmr_bound;
        uint32_t cur_validate_node;
        bool on_validate_list;
@@ -151,6 +152,8 @@ struct vmw_overlay;
 
 struct vmw_master {
        struct ttm_lock lock;
+       struct mutex fb_surf_mutex;
+       struct list_head fb_surf;
 };
 
 struct vmw_vga_topology_state {
@@ -182,6 +185,7 @@ struct vmw_private {
        uint32_t capabilities;
        uint32_t max_gmr_descriptors;
        uint32_t max_gmr_ids;
+       bool has_gmr;
        struct mutex hw_mutex;
 
        /*
@@ -263,14 +267,6 @@ struct vmw_private {
        uint32_t val_seq;
        struct mutex cmdbuf_mutex;
 
-       /**
-        * GMR management. Protected by the lru spinlock.
-        */
-
-       struct ida gmr_ida;
-       struct list_head gmr_lru;
-
-
        /**
         * Operating mode.
         */
@@ -286,6 +282,7 @@ struct vmw_private {
        struct vmw_master *active_master;
        struct vmw_master fbdev_master;
        struct notifier_block pm_nb;
+       bool suspended;
 
        struct mutex release_mutex;
        uint32_t num_3d_resources;
@@ -331,7 +328,9 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv);
  */
 
 extern int vmw_gmr_bind(struct vmw_private *dev_priv,
-                       struct ttm_buffer_object *bo);
+                       struct page *pages[],
+                       unsigned long num_pages,
+                       int gmr_id);
 extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
 
 /**
@@ -380,14 +379,10 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
 extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
 extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
                                  uint32_t id, struct vmw_dma_buffer **out);
-extern uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo);
-extern void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id);
-extern int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id);
 extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
                                       struct vmw_dma_buffer *bo);
 extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
                                struct vmw_dma_buffer *bo);
-extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo);
 extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv);
 extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -439,6 +434,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
 extern struct ttm_placement vmw_vram_placement;
 extern struct ttm_placement vmw_vram_ne_placement;
 extern struct ttm_placement vmw_vram_sys_placement;
+extern struct ttm_placement vmw_vram_gmr_placement;
 extern struct ttm_placement vmw_sys_placement;
 extern struct ttm_bo_driver vmw_bo_driver;
 extern int vmw_dma_quiescent(struct drm_device *dev);
@@ -518,6 +514,10 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv,
                        unsigned bbp, unsigned depth);
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster);
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+                               uint32_t pitch,
+                               uint32_t height);
 u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
 
 /**
@@ -536,6 +536,12 @@ int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
 int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
 int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
 
+/**
+ * GMR Id manager
+ */
+
+extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;
+
 /**
  * Inline helper functions
  */
index 8e396850513cab2b6abebf3858227a7463001121..51d9f9f1d7f2aa1b2ea04f309569d71bd9244600 100644 (file)
@@ -538,8 +538,11 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
                reloc = &sw_context->relocs[i];
                validate = &sw_context->val_bufs[reloc->index];
                bo = validate->bo;
-               reloc->location->offset += bo->offset;
-               reloc->location->gmrId = vmw_dmabuf_gmr(bo);
+               if (bo->mem.mem_type == TTM_PL_VRAM) {
+                       reloc->location->offset += bo->offset;
+                       reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
+               } else
+                       reloc->location->gmrId = bo->mem.start;
        }
        vmw_free_relocations(sw_context);
 }
@@ -563,25 +566,14 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
 {
        int ret;
 
-       if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
-               return 0;
-
        /**
-        * Put BO in VRAM, only if there is space.
+        * Put BO in VRAM if there is space, otherwise as a GMR.
+        * If there is no space in VRAM and GMR ids are all used up,
+        * start evicting GMRs to make room. If the DMA buffer can't be
+        * used as a GMR, this will return -ENOMEM.
         */
 
-       ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false, false);
-       if (unlikely(ret == -ERESTARTSYS))
-               return ret;
-
-       /**
-        * Otherwise, set it up as GMR.
-        */
-
-       if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
-               return 0;
-
-       ret = vmw_gmr_bind(dev_priv, bo);
+       ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false, false);
        if (likely(ret == 0 || ret == -ERESTARTSYS))
                return ret;
 
@@ -590,6 +582,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
         * previous contents.
         */
 
+       DRM_INFO("Falling through to VRAM.\n");
        ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false, false);
        return ret;
 }
index 409e172f4abfe94502be96502e251b5d6b2e54c9..41d9a5b73c03ebae477655eeff56d24e4766d1a0 100644 (file)
@@ -144,6 +144,13 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
+       if (!vmw_kms_validate_mode_vram(vmw_priv,
+                                       info->fix.line_length,
+                                       var->yoffset + var->yres)) {
+               DRM_ERROR("Requested geom can not fit in framebuffer\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -205,6 +212,9 @@ static void vmw_fb_dirty_flush(struct vmw_fb_par *par)
                SVGAFifoCmdUpdate body;
        } *cmd;
 
+       if (vmw_priv->suspended)
+               return;
+
        spin_lock_irqsave(&par->dirty.lock, flags);
        if (!par->dirty.active) {
                spin_unlock_irqrestore(&par->dirty.lock, flags);
@@ -616,7 +626,8 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
                goto err_unlock;
 
        if (bo->mem.mem_type == TTM_PL_VRAM &&
-           bo->mem.mm_node->start < bo->num_pages)
+           bo->mem.start < bo->num_pages &&
+           bo->mem.start > 0)
                (void) ttm_bo_validate(bo, &vmw_sys_placement, false,
                                       false, false);
 
index 5f8908a5d7fd49edd8d2f375ee67fec4fb01586a..de0c5948521dcab39bef89190ca19750a738b983 100644 (file)
@@ -146,7 +146,7 @@ static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv,
  */
 
 static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
-                                              unsigned long num_pages)
+                                       unsigned long num_pages)
 {
        unsigned long prev_pfn = ~(0UL);
        unsigned long pfn;
@@ -163,45 +163,33 @@ static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
 }
 
 int vmw_gmr_bind(struct vmw_private *dev_priv,
-                struct ttm_buffer_object *bo)
+                struct page *pages[],
+                unsigned long num_pages,
+                int gmr_id)
 {
-       struct ttm_tt *ttm = bo->ttm;
-       unsigned long descriptors;
-       int ret;
-       uint32_t id;
        struct list_head desc_pages;
+       int ret;
 
-       if (!(dev_priv->capabilities & SVGA_CAP_GMR))
+       if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR)))
                return -EINVAL;
 
-       ret = ttm_tt_populate(ttm);
-       if (unlikely(ret != 0))
-               return ret;
-
-       descriptors = vmw_gmr_count_descriptors(ttm->pages, ttm->num_pages);
-       if (unlikely(descriptors > dev_priv->max_gmr_descriptors))
+       if (vmw_gmr_count_descriptors(pages, num_pages) >
+           dev_priv->max_gmr_descriptors)
                return -EINVAL;
 
        INIT_LIST_HEAD(&desc_pages);
-       ret = vmw_gmr_build_descriptors(&desc_pages, ttm->pages,
-                                       ttm->num_pages);
-       if (unlikely(ret != 0))
-               return ret;
 
-       ret = vmw_gmr_id_alloc(dev_priv, &id);
+       ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages);
        if (unlikely(ret != 0))
-               goto out_no_id;
+               return ret;
 
-       vmw_gmr_fire_descriptors(dev_priv, id, &desc_pages);
+       vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages);
        vmw_gmr_free_descriptors(&desc_pages);
-       vmw_dmabuf_set_gmr(bo, id);
-       return 0;
 
-out_no_id:
-       vmw_gmr_free_descriptors(&desc_pages);
-       return ret;
+       return 0;
 }
 
+
 void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
 {
        mutex_lock(&dev_priv->hw_mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
new file mode 100644 (file)
index 0000000..ac6e0d1
--- /dev/null
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
+ * 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 COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "vmwgfx_drv.h"
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/idr.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+
+struct vmwgfx_gmrid_man {
+       spinlock_t lock;
+       struct ida gmr_ida;
+       uint32_t max_gmr_ids;
+};
+
+static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
+                                 struct ttm_buffer_object *bo,
+                                 struct ttm_placement *placement,
+                                 struct ttm_mem_reg *mem)
+{
+       struct vmwgfx_gmrid_man *gman =
+               (struct vmwgfx_gmrid_man *)man->priv;
+       int ret;
+       int id;
+
+       mem->mm_node = NULL;
+
+       do {
+               if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0))
+                       return -ENOMEM;
+
+               spin_lock(&gman->lock);
+               ret = ida_get_new(&gman->gmr_ida, &id);
+
+               if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
+                       ida_remove(&gman->gmr_ida, id);
+                       spin_unlock(&gman->lock);
+                       return 0;
+               }
+
+               spin_unlock(&gman->lock);
+
+       } while (ret == -EAGAIN);
+
+       if (likely(ret == 0)) {
+               mem->mm_node = gman;
+               mem->start = id;
+       }
+
+       return ret;
+}
+
+static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
+                                  struct ttm_mem_reg *mem)
+{
+       struct vmwgfx_gmrid_man *gman =
+               (struct vmwgfx_gmrid_man *)man->priv;
+
+       if (mem->mm_node) {
+               spin_lock(&gman->lock);
+               ida_remove(&gman->gmr_ida, mem->start);
+               spin_unlock(&gman->lock);
+               mem->mm_node = NULL;
+       }
+}
+
+static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
+                             unsigned long p_size)
+{
+       struct vmwgfx_gmrid_man *gman =
+               kzalloc(sizeof(*gman), GFP_KERNEL);
+
+       if (unlikely(gman == NULL))
+               return -ENOMEM;
+
+       spin_lock_init(&gman->lock);
+       ida_init(&gman->gmr_ida);
+       gman->max_gmr_ids = p_size;
+       man->priv = (void *) gman;
+       return 0;
+}
+
+static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
+{
+       struct vmwgfx_gmrid_man *gman =
+               (struct vmwgfx_gmrid_man *)man->priv;
+
+       if (gman) {
+               ida_destroy(&gman->gmr_ida);
+               kfree(gman);
+       }
+       return 0;
+}
+
+static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
+                               const char *prefix)
+{
+       printk(KERN_INFO "%s: No debug info available for the GMR "
+              "id manager.\n", prefix);
+}
+
+const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
+       vmw_gmrid_man_init,
+       vmw_gmrid_man_takedown,
+       vmw_gmrid_man_get_node,
+       vmw_gmrid_man_put_node,
+       vmw_gmrid_man_debug
+};
index 1c7a316454d80ceb9aaeb6c83d6ac6a82f1cae1f..570d57775a58de0eebf9574f5ce3782fafcae508 100644 (file)
@@ -54,6 +54,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
        case DRM_VMW_PARAM_FIFO_CAPS:
                param->value = dev_priv->fifo.capabilities;
                break;
+       case DRM_VMW_PARAM_MAX_FB_SIZE:
+               param->value = dev_priv->vram_size;
+               break;
        default:
                DRM_ERROR("Illegal vmwgfx get param request: %d\n",
                          param->param);
index e882ba099f0c33dab30f12f7b9328b3b628ac712..87c6e6156d7de8bc809a62bab06dbf64a7da512b 100644 (file)
@@ -332,18 +332,55 @@ struct vmw_framebuffer_surface {
        struct delayed_work d_work;
        struct mutex work_lock;
        bool present_fs;
+       struct list_head head;
+       struct drm_master *master;
 };
 
+/**
+ * vmw_kms_idle_workqueues - Flush workqueues on this master
+ *
+ * @vmaster - Pointer identifying the master, for the surfaces of which
+ * we idle the dirty work queues.
+ *
+ * This function should be called with the ttm lock held in exclusive mode
+ * to idle all dirty work queues before the fifo is taken down.
+ *
+ * The work task may actually requeue itself, but after the flush returns we're
+ * sure that there's nothing to present, since the ttm lock is held in
+ * exclusive mode, so the fifo will never get used.
+ */
+
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster)
+{
+       struct vmw_framebuffer_surface *entry;
+
+       mutex_lock(&vmaster->fb_surf_mutex);
+       list_for_each_entry(entry, &vmaster->fb_surf, head) {
+               if (cancel_delayed_work_sync(&entry->d_work))
+                       (void) entry->d_work.work.func(&entry->d_work.work);
+
+               (void) cancel_delayed_work_sync(&entry->d_work);
+       }
+       mutex_unlock(&vmaster->fb_surf_mutex);
+}
+
 void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
 {
-       struct vmw_framebuffer_surface *vfb =
+       struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
+       struct vmw_master *vmaster = vmw_master(vfbs->master);
+
 
-       cancel_delayed_work_sync(&vfb->d_work);
+       mutex_lock(&vmaster->fb_surf_mutex);
+       list_del(&vfbs->head);
+       mutex_unlock(&vmaster->fb_surf_mutex);
+
+       cancel_delayed_work_sync(&vfbs->d_work);
+       drm_master_put(&vfbs->master);
        drm_framebuffer_cleanup(framebuffer);
-       vmw_surface_unreference(&vfb->surface);
+       vmw_surface_unreference(&vfbs->surface);
 
-       kfree(framebuffer);
+       kfree(vfbs);
 }
 
 static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
@@ -362,6 +399,12 @@ static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
                SVGA3dCopyRect cr;
        } *cmd;
 
+       /**
+        * Strictly we should take the ttm_lock in read mode before accessing
+        * the fifo, to make sure the fifo is present and up. However,
+        * instead we flush all workqueues under the ttm lock in exclusive mode
+        * before taking down the fifo.
+        */
        mutex_lock(&vfbs->work_lock);
        if (!vfbs->present_fs)
                goto out_unlock;
@@ -392,17 +435,20 @@ out_unlock:
 
 
 int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+                                 struct drm_file *file_priv,
                                  unsigned flags, unsigned color,
                                  struct drm_clip_rect *clips,
                                  unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
        struct vmw_surface *surf = vfbs->surface;
        struct drm_clip_rect norect;
        SVGA3dCopyRect *cr;
        int i, inc = 1;
+       int ret;
 
        struct {
                SVGA3dCmdHeader header;
@@ -410,6 +456,13 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                SVGA3dCopyRect cr;
        } *cmd;
 
+       if (unlikely(vfbs->master != file_priv->master))
+               return -EINVAL;
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
        if (!num_clips ||
            !(dev_priv->fifo.capabilities &
              SVGA_FIFO_CAP_SCREEN_OBJECT)) {
@@ -425,6 +478,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                         */
                        vmw_framebuffer_present_fs_callback(&vfbs->d_work.work);
                }
+               ttm_read_unlock(&vmaster->lock);
                return 0;
        }
 
@@ -442,6 +496,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Fifo reserve failed.\n");
+               ttm_read_unlock(&vmaster->lock);
                return -ENOMEM;
        }
 
@@ -461,7 +516,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        }
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
-
+       ttm_read_unlock(&vmaster->lock);
        return 0;
 }
 
@@ -471,16 +526,57 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
        .create_handle = vmw_framebuffer_create_handle,
 };
 
-int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
-                                   struct vmw_surface *surface,
-                                   struct vmw_framebuffer **out,
-                                   unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
+                                          struct drm_file *file_priv,
+                                          struct vmw_surface *surface,
+                                          struct vmw_framebuffer **out,
+                                          const struct drm_mode_fb_cmd
+                                          *mode_cmd)
 
 {
        struct drm_device *dev = dev_priv->dev;
        struct vmw_framebuffer_surface *vfbs;
+       enum SVGA3dSurfaceFormat format;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
+       /*
+        * Sanity checks.
+        */
+
+       if (unlikely(surface->mip_levels[0] != 1 ||
+                    surface->num_sizes != 1 ||
+                    surface->sizes[0].width < mode_cmd->width ||
+                    surface->sizes[0].height < mode_cmd->height ||
+                    surface->sizes[0].depth != 1)) {
+               DRM_ERROR("Incompatible surface dimensions "
+                         "for requested mode.\n");
+               return -EINVAL;
+       }
+
+       switch (mode_cmd->depth) {
+       case 32:
+               format = SVGA3D_A8R8G8B8;
+               break;
+       case 24:
+               format = SVGA3D_X8R8G8B8;
+               break;
+       case 16:
+               format = SVGA3D_R5G6B5;
+               break;
+       case 15:
+               format = SVGA3D_A1R5G5B5;
+               break;
+       default:
+               DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
+               return -EINVAL;
+       }
+
+       if (unlikely(format != surface->format)) {
+               DRM_ERROR("Invalid surface format for requested mode.\n");
+               return -EINVAL;
+       }
+
        vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
        if (!vfbs) {
                ret = -ENOMEM;
@@ -498,16 +594,22 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
        }
 
        /* XXX get the first 3 from the surface info */
-       vfbs->base.base.bits_per_pixel = 32;
-       vfbs->base.base.pitch = width * 32 / 4;
-       vfbs->base.base.depth = 24;
-       vfbs->base.base.width = width;
-       vfbs->base.base.height = height;
+       vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
+       vfbs->base.base.pitch = mode_cmd->pitch;
+       vfbs->base.base.depth = mode_cmd->depth;
+       vfbs->base.base.width = mode_cmd->width;
+       vfbs->base.base.height = mode_cmd->height;
        vfbs->base.pin = &vmw_surface_dmabuf_pin;
        vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
        vfbs->surface = surface;
+       vfbs->master = drm_master_get(file_priv->master);
        mutex_init(&vfbs->work_lock);
+
+       mutex_lock(&vmaster->fb_surf_mutex);
        INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
+       list_add_tail(&vfbs->head, &vmaster->fb_surf);
+       mutex_unlock(&vmaster->fb_surf_mutex);
+
        *out = &vfbs->base;
 
        return 0;
@@ -544,18 +646,25 @@ void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
 }
 
 int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+                                struct drm_file *file_priv,
                                 unsigned flags, unsigned color,
                                 struct drm_clip_rect *clips,
                                 unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_clip_rect norect;
+       int ret;
        struct {
                uint32_t header;
                SVGAFifoCmdUpdate body;
        } *cmd;
        int i, increment = 1;
 
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
        if (!num_clips) {
                num_clips = 1;
                clips = &norect;
@@ -570,6 +679,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips);
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Fifo reserve failed.\n");
+               ttm_read_unlock(&vmaster->lock);
                return -ENOMEM;
        }
 
@@ -582,6 +692,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        }
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
+       ttm_read_unlock(&vmaster->lock);
 
        return 0;
 }
@@ -659,16 +770,25 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
        return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
 }
 
-int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
-                                  struct vmw_dma_buffer *dmabuf,
-                                  struct vmw_framebuffer **out,
-                                  unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
+                                         struct vmw_dma_buffer *dmabuf,
+                                         struct vmw_framebuffer **out,
+                                         const struct drm_mode_fb_cmd
+                                         *mode_cmd)
 
 {
        struct drm_device *dev = dev_priv->dev;
        struct vmw_framebuffer_dmabuf *vfbd;
+       unsigned int requested_size;
        int ret;
 
+       requested_size = mode_cmd->height * mode_cmd->pitch;
+       if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) {
+               DRM_ERROR("Screen buffer object size is too small "
+                         "for requested mode.\n");
+               return -EINVAL;
+       }
+
        vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
        if (!vfbd) {
                ret = -ENOMEM;
@@ -685,12 +805,11 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
                goto out_err3;
        }
 
-       /* XXX get the first 3 from the surface info */
-       vfbd->base.base.bits_per_pixel = 32;
-       vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
-       vfbd->base.base.depth = 24;
-       vfbd->base.base.width = width;
-       vfbd->base.base.height = height;
+       vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
+       vfbd->base.base.pitch = mode_cmd->pitch;
+       vfbd->base.base.depth = mode_cmd->depth;
+       vfbd->base.base.width = mode_cmd->width;
+       vfbd->base.base.height = mode_cmd->height;
        vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
        vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
        vfbd->buffer = dmabuf;
@@ -719,8 +838,25 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        struct vmw_framebuffer *vfb = NULL;
        struct vmw_surface *surface = NULL;
        struct vmw_dma_buffer *bo = NULL;
+       u64 required_size;
        int ret;
 
+       /**
+        * This code should be conditioned on Screen Objects not being used.
+        * If screen objects are used, we can allocate a GMR to hold the
+        * requested framebuffer.
+        */
+
+       required_size = mode_cmd->pitch * mode_cmd->height;
+       if (unlikely(required_size > (u64) dev_priv->vram_size)) {
+               DRM_ERROR("VRAM size is too small for requested mode.\n");
+               return NULL;
+       }
+
+       /**
+        * End conditioned code.
+        */
+
        ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
                                             mode_cmd->handle, &surface);
        if (ret)
@@ -729,8 +865,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        if (!surface->scanout)
                goto err_not_scanout;
 
-       ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
-                                             mode_cmd->width, mode_cmd->height);
+       ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface,
+                                             &vfb, mode_cmd);
 
        /* vmw_user_surface_lookup takes one ref so does new_fb */
        vmw_surface_unreference(&surface);
@@ -751,7 +887,7 @@ try_dmabuf:
        }
 
        ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
-                                            mode_cmd->width, mode_cmd->height);
+                                            mode_cmd);
 
        /* vmw_user_dmabuf_lookup takes one ref so does new_fb */
        vmw_dmabuf_unreference(&bo);
@@ -889,6 +1025,9 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
        vmw_priv->num_displays = vmw_read(vmw_priv,
                                          SVGA_REG_NUM_GUEST_DISPLAYS);
 
+       if (vmw_priv->num_displays == 0)
+               vmw_priv->num_displays = 1;
+
        for (i = 0; i < vmw_priv->num_displays; ++i) {
                save = &vmw_priv->vga_save[i];
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
@@ -997,6 +1136,13 @@ out_unlock:
        return ret;
 }
 
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+                               uint32_t pitch,
+                               uint32_t height)
+{
+       return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size;
+}
+
 u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc)
 {
        return 0;
index 11cb39e3accbfa9581801095ab0398952d2313f1..a01c47ddb5bc724617b74c15ad3bffc2ed63067f 100644 (file)
@@ -427,7 +427,9 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
 {
        struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
        struct drm_device *dev = connector->dev;
+       struct vmw_private *dev_priv = vmw_priv(dev);
        struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *bmode;
        struct drm_display_mode prefmode = { DRM_MODE("preferred",
                DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -443,22 +445,30 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
                mode->hdisplay = ldu->pref_width;
                mode->vdisplay = ldu->pref_height;
                mode->vrefresh = drm_mode_vrefresh(mode);
-               drm_mode_probed_add(connector, mode);
+               if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
+                                              mode->vdisplay)) {
+                       drm_mode_probed_add(connector, mode);
 
-               if (ldu->pref_mode) {
-                       list_del_init(&ldu->pref_mode->head);
-                       drm_mode_destroy(dev, ldu->pref_mode);
-               }
+                       if (ldu->pref_mode) {
+                               list_del_init(&ldu->pref_mode->head);
+                               drm_mode_destroy(dev, ldu->pref_mode);
+                       }
 
-               ldu->pref_mode = mode;
+                       ldu->pref_mode = mode;
+               }
        }
 
        for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
-               if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
-                   vmw_ldu_connector_builtin[i].vdisplay > max_height)
+               bmode = &vmw_ldu_connector_builtin[i];
+               if (bmode->hdisplay > max_width ||
+                   bmode->vdisplay > max_height)
+                       continue;
+
+               if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2,
+                                               bmode->vdisplay))
                        continue;
 
-               mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]);
+               mode = drm_mode_duplicate(dev, bmode);
                if (!mode)
                        return 0;
                mode->vrefresh = drm_mode_vrefresh(mode);
index c8c40e9979dbd21442a5d87cf6ac4cdcad08cfad..36e129f0023ffc3d6407b9c0251376aa3fc9f5c0 100644 (file)
@@ -765,28 +765,11 @@ static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob,
        return bo_user_size + page_array_size;
 }
 
-void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo)
-{
-       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
-       struct ttm_bo_global *glob = bo->glob;
-       struct vmw_private *dev_priv =
-               container_of(bo->bdev, struct vmw_private, bdev);
-
-       if (vmw_bo->gmr_bound) {
-               vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
-               spin_lock(&glob->lru_lock);
-               ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
-               spin_unlock(&glob->lru_lock);
-               vmw_bo->gmr_bound = false;
-       }
-}
-
 void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
 {
        struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
        struct ttm_bo_global *glob = bo->glob;
 
-       vmw_dmabuf_gmr_unbind(bo);
        ttm_mem_global_free(glob->mem_glob, bo->acc_size);
        kfree(vmw_bo);
 }
@@ -818,10 +801,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
 
        memset(vmw_bo, 0, sizeof(*vmw_bo));
 
-       INIT_LIST_HEAD(&vmw_bo->gmr_lru);
        INIT_LIST_HEAD(&vmw_bo->validate_list);
-       vmw_bo->gmr_id = 0;
-       vmw_bo->gmr_bound = false;
 
        ret = ttm_bo_init(bdev, &vmw_bo->base, size,
                          ttm_bo_type_device, placement,
@@ -835,7 +815,6 @@ static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
        struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
        struct ttm_bo_global *glob = bo->glob;
 
-       vmw_dmabuf_gmr_unbind(bo);
        ttm_mem_global_free(glob->mem_glob, bo->acc_size);
        kfree(vmw_user_bo);
 }
@@ -938,25 +917,6 @@ void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo)
        vmw_bo->on_validate_list = false;
 }
 
-uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo)
-{
-       struct vmw_dma_buffer *vmw_bo;
-
-       if (bo->mem.mem_type == TTM_PL_VRAM)
-               return SVGA_GMR_FRAMEBUFFER;
-
-       vmw_bo = vmw_dma_buffer(bo);
-
-       return (vmw_bo->gmr_bound) ? vmw_bo->gmr_id : SVGA_GMR_NULL;
-}
-
-void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id)
-{
-       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
-       vmw_bo->gmr_bound = true;
-       vmw_bo->gmr_id = id;
-}
-
 int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
                           uint32_t handle, struct vmw_dma_buffer **out)
 {
@@ -985,41 +945,6 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
        return 0;
 }
 
-/**
- * TODO: Implement a gmr id eviction mechanism. Currently we just fail
- * when we're out of ids, causing GMR space to be allocated
- * out of VRAM.
- */
-
-int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
-{
-       struct ttm_bo_global *glob = dev_priv->bdev.glob;
-       int id;
-       int ret;
-
-       do {
-               if (unlikely(ida_pre_get(&dev_priv->gmr_ida, GFP_KERNEL) == 0))
-                       return -ENOMEM;
-
-               spin_lock(&glob->lru_lock);
-               ret = ida_get_new(&dev_priv->gmr_ida, &id);
-               spin_unlock(&glob->lru_lock);
-       } while (ret == -EAGAIN);
-
-       if (unlikely(ret != 0))
-               return ret;
-
-       if (unlikely(id >= dev_priv->max_gmr_ids)) {
-               spin_lock(&glob->lru_lock);
-               ida_remove(&dev_priv->gmr_ida, id);
-               spin_unlock(&glob->lru_lock);
-               return -EBUSY;
-       }
-
-       *p_id = (uint32_t) id;
-       return 0;
-}
-
 /*
  * Stream management
  */
diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig
new file mode 100644 (file)
index 0000000..742c423
--- /dev/null
@@ -0,0 +1,13 @@
+config STUB_POULSBO
+       tristate "Intel GMA500 Stub Driver"
+       depends on PCI
+       # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
+       # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+       select ACPI_VIDEO if ACPI
+       help
+         Choose this option if you have a system that has Intel GMA500
+         (Poulsbo) integrated graphics. If M is selected, the module will
+         be called Poulsbo. This driver is a stub driver for Poulsbo that
+         will call poulsbo.ko to enable the acpi backlight control sysfs
+         entry file because there have no poulsbo native driver can support
+         intel opregion.
diff --git a/drivers/gpu/stub/Makefile b/drivers/gpu/stub/Makefile
new file mode 100644 (file)
index 0000000..cd940cc
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_STUB_POULSBO) += poulsbo.o
diff --git a/drivers/gpu/stub/poulsbo.c b/drivers/gpu/stub/poulsbo.c
new file mode 100644 (file)
index 0000000..7edfd27
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Intel Poulsbo Stub driver
+ *
+ * Copyright (C) 2010 Novell <jlee@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/video.h>
+
+#define DRIVER_NAME "poulsbo"
+
+enum {
+       CHIP_PSB_8108 = 0,
+       CHIP_PSB_8109 = 1,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+       {0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108}, \
+       {0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109}, \
+       {0, 0, 0}
+};
+
+static int poulsbo_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       return acpi_video_register();
+}
+
+static void poulsbo_remove(struct pci_dev *pdev)
+{
+       acpi_video_unregister();
+}
+
+static struct pci_driver poulsbo_driver = {
+       .name = DRIVER_NAME,
+       .id_table = pciidlist,
+       .probe = poulsbo_probe,
+       .remove = poulsbo_remove,
+};
+
+static int __init poulsbo_init(void)
+{
+       return pci_register_driver(&poulsbo_driver);
+}
+
+static void __exit poulsbo_exit(void)
+{
+       pci_unregister_driver(&poulsbo_driver);
+}
+
+module_init(poulsbo_init);
+module_exit(poulsbo_exit);
+
+MODULE_AUTHOR("Lee, Chun-Yi <jlee@novell.com>");
+MODULE_DESCRIPTION("Poulsbo Stub Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
index 7832b6e2478b09c9f51ae9abc31ce4c98d708c01..515345b11ac95b380942638ce25f8ea8afccd472 100644 (file)
@@ -1780,6 +1780,11 @@ static bool hid_ignore(struct hid_device *hdev)
                    hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
                        return true;
                break;
+       case USB_VENDOR_ID_HANWANG:
+               if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+                   hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+                       return true;
+               break;
        }
 
        if (hdev->type == HID_TYPE_USBMOUSE &&
index 3ee999d33004a64ea5801987bb7d3016960f0990..3341baa86a30f66ab426b78cd68b2f953f311a1b 100644 (file)
 #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
 #define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
 
+#define USB_VENDOR_ID_HANWANG          0x0b57
+#define USB_DEVICE_ID_HANWANG_TABLET_FIRST     0x5000
+#define USB_DEVICE_ID_HANWANG_TABLET_LAST      0x8fff
+
 #define USB_VENDOR_ID_HAPP             0x078b
 #define USB_DEVICE_ID_UGCI_DRIVING     0x0010
 #define USB_DEVICE_ID_UGCI_FLYING      0x0020
index 834ef47b76d6f456184dff1adc9663160bebfa28..bb0b3659437b1a98302f159f2e1773db21a0e2ee 100644 (file)
@@ -68,39 +68,52 @@ static const struct {
 #define map_key_clear(c)       hid_map_usage_clear(hidinput, usage, &bit, \
                &max, EV_KEY, (c))
 
-static inline int match_scancode(unsigned int code, unsigned int scancode)
+static bool match_scancode(struct hid_usage *usage,
+                          unsigned int cur_idx, unsigned int scancode)
 {
-       if (scancode == 0)
-               return 1;
-
-       return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
+       return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
 }
 
-static inline int match_keycode(unsigned int code, unsigned int keycode)
+static bool match_keycode(struct hid_usage *usage,
+                         unsigned int cur_idx, unsigned int keycode)
 {
-       if (keycode == 0)
-               return 1;
+       /*
+        * We should exclude unmapped usages when doing lookup by keycode.
+        */
+       return (usage->type == EV_KEY && usage->code == keycode);
+}
 
-       return code == keycode;
+static bool match_index(struct hid_usage *usage,
+                       unsigned int cur_idx, unsigned int idx)
+{
+       return cur_idx == idx;
 }
 
+typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
+                               unsigned int cur_idx, unsigned int val);
+
 static struct hid_usage *hidinput_find_key(struct hid_device *hid,
-                                          unsigned int scancode,
-                                          unsigned int keycode)
+                                          hid_usage_cmp_t match,
+                                          unsigned int value,
+                                          unsigned int *usage_idx)
 {
-       int i, j, k;
+       unsigned int i, j, k, cur_idx = 0;
        struct hid_report *report;
        struct hid_usage *usage;
 
        for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
                list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
                        for (i = 0; i < report->maxfield; i++) {
-                               for ( j = 0; j < report->field[i]->maxusage; j++) {
+                               for (j = 0; j < report->field[i]->maxusage; j++) {
                                        usage = report->field[i]->usage + j;
-                                       if (usage->type == EV_KEY &&
-                                               match_scancode(usage->hid, scancode) &&
-                                               match_keycode(usage->code, keycode))
-                                               return usage;
+                                       if (usage->type == EV_KEY || usage->type == 0) {
+                                               if (match(usage, cur_idx, value)) {
+                                                       if (usage_idx)
+                                                               *usage_idx = cur_idx;
+                                                       return usage;
+                                               }
+                                               cur_idx++;
+                                       }
                                }
                        }
                }
@@ -108,39 +121,68 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid,
        return NULL;
 }
 
+static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
+                                       const struct input_keymap_entry *ke,
+                                       unsigned int *index)
+{
+       struct hid_usage *usage;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+               usage = hidinput_find_key(hid, match_index, ke->index, index);
+       else if (input_scancode_to_scalar(ke, &scancode) == 0)
+               usage = hidinput_find_key(hid, match_scancode, scancode, index);
+       else
+               usage = NULL;
+
+       return usage;
+}
+
 static int hidinput_getkeycode(struct input_dev *dev,
-                              unsigned int scancode, unsigned int *keycode)
+                              struct input_keymap_entry *ke)
 {
        struct hid_device *hid = input_get_drvdata(dev);
        struct hid_usage *usage;
+       unsigned int scancode, index;
 
-       usage = hidinput_find_key(hid, scancode, 0);
+       usage = hidinput_locate_usage(hid, ke, &index);
        if (usage) {
-               *keycode = usage->code;
+               ke->keycode = usage->type == EV_KEY ?
+                               usage->code : KEY_RESERVED;
+               ke->index = index;
+               scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
+               ke->len = sizeof(scancode);
+               memcpy(ke->scancode, &scancode, sizeof(scancode));
                return 0;
        }
+
        return -EINVAL;
 }
 
 static int hidinput_setkeycode(struct input_dev *dev,
-                              unsigned int scancode, unsigned int keycode)
+                              const struct input_keymap_entry *ke,
+                              unsigned int *old_keycode)
 {
        struct hid_device *hid = input_get_drvdata(dev);
        struct hid_usage *usage;
-       int old_keycode;
 
-       usage = hidinput_find_key(hid, scancode, 0);
+       usage = hidinput_locate_usage(hid, ke, NULL);
        if (usage) {
-               old_keycode = usage->code;
-               usage->code = keycode;
+               *old_keycode = usage->type == EV_KEY ?
+                               usage->code : KEY_RESERVED;
+               usage->code = ke->keycode;
 
-               clear_bit(old_keycode, dev->keybit);
+               clear_bit(*old_keycode, dev->keybit);
                set_bit(usage->code, dev->keybit);
-               dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
-               /* Set the keybit for the old keycode if the old keycode is used
-                * by another key */
-               if (hidinput_find_key (hid, 0, old_keycode))
-                       set_bit(old_keycode, dev->keybit);
+               dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
+                       usage->code, usage->hid);
+
+               /*
+                * Set the keybit for the old keycode if the old keycode is used
+                * by another key
+                */
+               if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
+                       set_bit(*old_keycode, dev->keybit);
 
                return 0;
        }
@@ -835,8 +877,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                        hid->ll_driver->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
-                               input_dev->setkeycode = hidinput_setkeycode;
-                               input_dev->getkeycode = hidinput_getkeycode;
+                               input_dev->setkeycode_new = hidinput_setkeycode;
+                               input_dev->getkeycode_new = hidinput_getkeycode;
 
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
index 97499d00615aacbddcf5963bcfa08b5f4733a1bb..c357c835eb1e232387f755553c285e911c793a2a 100644 (file)
@@ -399,6 +399,15 @@ config SENSORS_GL520SM
          This driver can also be built as a module.  If so, the module
          will be called gl520sm.
 
+config SENSORS_GPIO_FAN
+       tristate "GPIO fan"
+       depends on GENERIC_GPIO
+       help
+         If you say yes here you get support for fans connected to GPIO lines.
+
+         This driver can also be built as a module.  If so, the module
+         will be called gpio-fan.
+
 config SENSORS_CORETEMP
        tristate "Intel Core/Core2/Atom temperature sensor"
        depends on X86 && PCI && EXPERIMENTAL
@@ -654,6 +663,17 @@ config SENSORS_LTC4245
          This driver can also be built as a module. If so, the module will
          be called ltc4245.
 
+config SENSORS_LTC4261
+       tristate "Linear Technology LTC4261"
+       depends on I2C && EXPERIMENTAL
+       default n
+       help
+         If you say yes here you get support for Linear Technology LTC4261
+         Negative Voltage Hot Swap Controller I2C interface.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc4261.
+
 config SENSORS_LM95241
        tristate "National Semiconductor LM95241 sensor chip"
        depends on I2C
@@ -1088,26 +1108,6 @@ config SENSORS_ULTRA45
          This driver provides support for the Ultra45 workstation environmental
          sensors.
 
-config SENSORS_HDAPS
-       tristate "IBM Hard Drive Active Protection System (hdaps)"
-       depends on INPUT && X86
-       select INPUT_POLLDEV
-       default n
-       help
-         This driver provides support for the IBM Hard Drive Active Protection
-         System (hdaps), which provides an accelerometer and other misc. data.
-         ThinkPads starting with the R50, T41, and X40 are supported.  The
-         accelerometer data is readable via sysfs.
-
-         This driver also provides an absolute input class device, allowing
-         the laptop to act as a pinball machine-esque joystick.
-
-         If your ThinkPad is not recognized by the driver, please update to latest
-         BIOS. This is especially the case for some R52 ThinkPads.
-
-         Say Y here if you have an applicable laptop and want to experience
-         the awesome power of hdaps.
-
 config SENSORS_LIS3_SPI
        tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
        depends on !ACPI && SPI_MASTER && INPUT
index e3c2484f6c5f4adb009712f3ae0bd5be032db16f..d30f0f6870e02ff859c6df5d19f3762eb3dc78a1 100644 (file)
@@ -51,8 +51,8 @@ obj-$(CONFIG_SENSORS_FSCHMD)  += fschmd.o
 obj-$(CONFIG_SENSORS_G760A)    += g760a.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
+obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
 obj-$(CONFIG_SENSORS_ULTRA45)  += ultra45_env.o
-obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
@@ -80,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM93)    += lm93.o
 obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
 obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4261)  += ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
index a23b17a78ace8f42cb114b30f593b9019a24a982..42de98d73ff5016d68a2884b91ad5f70b9b99713 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -280,11 +279,9 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
        case 0x1a:
                dev_warn(dev, "TjMax is assumed as 100 C!\n");
                return 100000;
-               break;
        case 0x17:
        case 0x1c:              /* Atom CPUs */
                return adjust_tjmax(c, id, dev);
-               break;
        default:
                dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
                        " using default TjMax of 100C.\n", c->x86_model);
@@ -292,6 +289,15 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
        }
 }
 
+static void __devinit get_ucode_rev_on_cpu(void *edx)
+{
+       u32 eax;
+
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+       sync_core();
+       rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
+}
+
 static int __devinit coretemp_probe(struct platform_device *pdev)
 {
        struct coretemp_data *data;
@@ -327,8 +333,15 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
 
        if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
                /* check for microcode update */
-               rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
-               if (edx < 0x39) {
+               err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
+                                              &edx, 1);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Cannot determine microcode revision of "
+                               "CPU#%u (%d)!\n", data->id, err);
+                       err = -ENODEV;
+                       goto exit_free;
+               } else if (edx < 0x39) {
                        err = -ENODEV;
                        dev_err(&pdev->dev,
                                "Errata AE18 not fixed, update BIOS or "
@@ -490,7 +503,7 @@ exit:
        return err;
 }
 
-static void coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p;
        unsigned int i;
@@ -569,9 +582,8 @@ exit:
 static void __exit coretemp_exit(void)
 {
        struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
        unregister_hotcpu_notifier(&coretemp_cpu_notifier);
-#endif
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
                platform_device_unregister(p->pdev);
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
new file mode 100644 (file)
index 0000000..aa701a1
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * gpio-fan.c - Hwmon driver for fans connected to GPIO lines.
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/gpio.h>
+#include <linux/gpio-fan.h>
+
+struct gpio_fan_data {
+       struct platform_device  *pdev;
+       struct device           *hwmon_dev;
+       struct mutex            lock; /* lock GPIOs operations. */
+       int                     num_ctrl;
+       unsigned                *ctrl;
+       int                     num_speed;
+       struct gpio_fan_speed   *speed;
+       int                     speed_index;
+#ifdef CONFIG_PM
+       int                     resume_speed;
+#endif
+       bool                    pwm_enable;
+       struct gpio_fan_alarm   *alarm;
+       struct work_struct      alarm_work;
+};
+
+/*
+ * Alarm GPIO.
+ */
+
+static void fan_alarm_notify(struct work_struct *ws)
+{
+       struct gpio_fan_data *fan_data =
+               container_of(ws, struct gpio_fan_data, alarm_work);
+
+       sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
+       kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
+{
+       struct gpio_fan_data *fan_data = dev_id;
+
+       schedule_work(&fan_data->alarm_work);
+
+       return IRQ_NONE;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+       struct gpio_fan_alarm *alarm = fan_data->alarm;
+       int value = gpio_get_value(alarm->gpio);
+
+       if (alarm->active_low)
+               value = !value;
+
+       return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
+
+static int fan_alarm_init(struct gpio_fan_data *fan_data,
+                         struct gpio_fan_alarm *alarm)
+{
+       int err;
+       int alarm_irq;
+       struct platform_device *pdev = fan_data->pdev;
+
+       fan_data->alarm = alarm;
+
+       err = gpio_request(alarm->gpio, "GPIO fan alarm");
+       if (err)
+               return err;
+
+       err = gpio_direction_input(alarm->gpio);
+       if (err)
+               goto err_free_gpio;
+
+       err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
+       if (err)
+               goto err_free_gpio;
+
+       /*
+        * If the alarm GPIO don't support interrupts, just leave
+        * without initializing the fail notification support.
+        */
+       alarm_irq = gpio_to_irq(alarm->gpio);
+       if (alarm_irq < 0)
+               return 0;
+
+       INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
+       set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
+       err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED,
+                         "GPIO fan alarm", fan_data);
+       if (err)
+               goto err_free_sysfs;
+
+       return 0;
+
+err_free_sysfs:
+       device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+err_free_gpio:
+       gpio_free(alarm->gpio);
+
+       return err;
+}
+
+static void fan_alarm_free(struct gpio_fan_data *fan_data)
+{
+       struct platform_device *pdev = fan_data->pdev;
+       int alarm_irq = gpio_to_irq(fan_data->alarm->gpio);
+
+       if (alarm_irq >= 0)
+               free_irq(alarm_irq, fan_data);
+       device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+       gpio_free(fan_data->alarm->gpio);
+}
+
+/*
+ * Control GPIOs.
+ */
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
+{
+       int i;
+
+       for (i = 0; i < fan_data->num_ctrl; i++)
+               gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+}
+
+static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
+{
+       int i;
+       int ctrl_val = 0;
+
+       for (i = 0; i < fan_data->num_ctrl; i++) {
+               int value;
+
+               value = gpio_get_value(fan_data->ctrl[i]);
+               ctrl_val |= (value << i);
+       }
+       return ctrl_val;
+}
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
+{
+       if (fan_data->speed_index == speed_index)
+               return;
+
+       __set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
+       fan_data->speed_index = speed_index;
+}
+
+static int get_fan_speed_index(struct gpio_fan_data *fan_data)
+{
+       int ctrl_val = __get_fan_ctrl(fan_data);
+       int i;
+
+       for (i = 0; i < fan_data->num_speed; i++)
+               if (fan_data->speed[i].ctrl_val == ctrl_val)
+                       return i;
+
+       dev_warn(&fan_data->pdev->dev,
+                "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
+
+       return -EINVAL;
+}
+
+static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm)
+{
+       struct gpio_fan_speed *speed = fan_data->speed;
+       int i;
+
+       for (i = 0; i < fan_data->num_speed; i++)
+               if (speed[i].rpm >= rpm)
+                       return i;
+
+       return fan_data->num_speed - 1;
+}
+
+static ssize_t show_pwm(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+       u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
+
+       return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+       unsigned long pwm;
+       int speed_index;
+       int ret = count;
+
+       if (strict_strtoul(buf, 10, &pwm) || pwm > 255)
+               return -EINVAL;
+
+       mutex_lock(&fan_data->lock);
+
+       if (!fan_data->pwm_enable) {
+               ret = -EPERM;
+               goto exit_unlock;
+       }
+
+       speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
+       set_fan_speed(fan_data, speed_index);
+
+exit_unlock:
+       mutex_unlock(&fan_data->lock);
+
+       return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", fan_data->pwm_enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) || val > 1)
+               return -EINVAL;
+
+       if (fan_data->pwm_enable == val)
+               return count;
+
+       mutex_lock(&fan_data->lock);
+
+       fan_data->pwm_enable = val;
+
+       /* Disable manual control mode: set fan at full speed. */
+       if (val == 0)
+               set_fan_speed(fan_data, fan_data->num_speed - 1);
+
+       mutex_unlock(&fan_data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_mode(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0\n");
+}
+
+static ssize_t show_rpm_min(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
+}
+
+static ssize_t show_rpm_max(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n",
+                      fan_data->speed[fan_data->num_speed - 1].rpm);
+}
+
+static ssize_t show_rpm(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
+}
+
+static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+       unsigned long rpm;
+       int ret = count;
+
+       if (strict_strtoul(buf, 10, &rpm))
+               return -EINVAL;
+
+       mutex_lock(&fan_data->lock);
+
+       if (!fan_data->pwm_enable) {
+               ret = -EPERM;
+               goto exit_unlock;
+       }
+
+       set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
+
+exit_unlock:
+       mutex_unlock(&fan_data->lock);
+
+       return ret;
+}
+
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                  show_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL);
+static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL);
+static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
+static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
+
+static struct attribute *gpio_fan_ctrl_attributes[] = {
+       &dev_attr_pwm1.attr,
+       &dev_attr_pwm1_enable.attr,
+       &dev_attr_pwm1_mode.attr,
+       &dev_attr_fan1_input.attr,
+       &dev_attr_fan1_target.attr,
+       &dev_attr_fan1_min.attr,
+       &dev_attr_fan1_max.attr,
+       NULL
+};
+
+static const struct attribute_group gpio_fan_ctrl_group = {
+       .attrs = gpio_fan_ctrl_attributes,
+};
+
+static int fan_ctrl_init(struct gpio_fan_data *fan_data,
+                        struct gpio_fan_platform_data *pdata)
+{
+       struct platform_device *pdev = fan_data->pdev;
+       int num_ctrl = pdata->num_ctrl;
+       unsigned *ctrl = pdata->ctrl;
+       int i, err;
+
+       for (i = 0; i < num_ctrl; i++) {
+               err = gpio_request(ctrl[i], "GPIO fan control");
+               if (err)
+                       goto err_free_gpio;
+
+               err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
+               if (err) {
+                       gpio_free(ctrl[i]);
+                       goto err_free_gpio;
+               }
+       }
+
+       err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+       if (err)
+               goto err_free_gpio;
+
+       fan_data->num_ctrl = num_ctrl;
+       fan_data->ctrl = ctrl;
+       fan_data->num_speed = pdata->num_speed;
+       fan_data->speed = pdata->speed;
+       fan_data->pwm_enable = true; /* Enable manual fan speed control. */
+       fan_data->speed_index = get_fan_speed_index(fan_data);
+       if (fan_data->speed_index < 0) {
+               err = -ENODEV;
+               goto err_free_gpio;
+       }
+
+       return 0;
+
+err_free_gpio:
+       for (i = i - 1; i >= 0; i--)
+               gpio_free(ctrl[i]);
+
+       return err;
+}
+
+static void fan_ctrl_free(struct gpio_fan_data *fan_data)
+{
+       struct platform_device *pdev = fan_data->pdev;
+       int i;
+
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+       for (i = 0; i < fan_data->num_ctrl; i++)
+               gpio_free(fan_data->ctrl[i]);
+}
+
+/*
+ * Platform driver.
+ */
+
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "gpio-fan\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __devinit gpio_fan_probe(struct platform_device *pdev)
+{
+       int err;
+       struct gpio_fan_data *fan_data;
+       struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -EINVAL;
+
+       fan_data = kzalloc(sizeof(struct gpio_fan_data), GFP_KERNEL);
+       if (!fan_data)
+               return -ENOMEM;
+
+       fan_data->pdev = pdev;
+       platform_set_drvdata(pdev, fan_data);
+       mutex_init(&fan_data->lock);
+
+       /* Configure alarm GPIO if available. */
+       if (pdata->alarm) {
+               err = fan_alarm_init(fan_data, pdata->alarm);
+               if (err)
+                       goto err_free_data;
+       }
+
+       /* Configure control GPIOs if available. */
+       if (pdata->ctrl && pdata->num_ctrl > 0) {
+               if (!pdata->speed || pdata->num_speed <= 1) {
+                       err = -EINVAL;
+                       goto err_free_alarm;
+               }
+               err = fan_ctrl_init(fan_data, pdata);
+               if (err)
+                       goto err_free_alarm;
+       }
+
+       err = device_create_file(&pdev->dev, &dev_attr_name);
+       if (err)
+               goto err_free_ctrl;
+
+       /* Make this driver part of hwmon class. */
+       fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(fan_data->hwmon_dev)) {
+               err = PTR_ERR(fan_data->hwmon_dev);
+               goto err_remove_name;
+       }
+
+       dev_info(&pdev->dev, "GPIO fan initialized\n");
+
+       return 0;
+
+err_remove_name:
+       device_remove_file(&pdev->dev, &dev_attr_name);
+err_free_ctrl:
+       if (fan_data->ctrl)
+               fan_ctrl_free(fan_data);
+err_free_alarm:
+       if (fan_data->alarm)
+               fan_alarm_free(fan_data);
+err_free_data:
+       platform_set_drvdata(pdev, NULL);
+       kfree(fan_data);
+
+       return err;
+}
+
+static int __devexit gpio_fan_remove(struct platform_device *pdev)
+{
+       struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+       hwmon_device_unregister(fan_data->hwmon_dev);
+       device_remove_file(&pdev->dev, &dev_attr_name);
+       if (fan_data->alarm)
+               fan_alarm_free(fan_data);
+       if (fan_data->ctrl)
+               fan_ctrl_free(fan_data);
+       kfree(fan_data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_fan_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+       if (fan_data->ctrl) {
+               fan_data->resume_speed = fan_data->speed_index;
+               set_fan_speed(fan_data, 0);
+       }
+
+       return 0;
+}
+
+static int gpio_fan_resume(struct platform_device *pdev)
+{
+       struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+       if (fan_data->ctrl)
+               set_fan_speed(fan_data, fan_data->resume_speed);
+
+       return 0;
+}
+#else
+#define gpio_fan_suspend NULL
+#define gpio_fan_resume NULL
+#endif
+
+static struct platform_driver gpio_fan_driver = {
+       .probe          = gpio_fan_probe,
+       .remove         = __devexit_p(gpio_fan_remove),
+       .suspend        = gpio_fan_suspend,
+       .resume         = gpio_fan_resume,
+       .driver = {
+               .name   = "gpio-fan",
+       },
+};
+
+static int __init gpio_fan_init(void)
+{
+       return platform_driver_register(&gpio_fan_driver);
+}
+
+static void __exit gpio_fan_exit(void)
+{
+       platform_driver_unregister(&gpio_fan_driver);
+}
+
+module_init(gpio_fan_init);
+module_exit(gpio_fan_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("GPIO FAN driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-fan");
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
deleted file mode 100644 (file)
index bfd42f1..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
- *
- * Copyright (C) 2005 Robert Love <rml@novell.com>
- * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
- *
- * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
- * starting with the R40, T41, and X40.  It provides a basic two-axis
- * accelerometer and other data, such as the device's temperature.
- *
- * This driver is based on the document by Mark A. Smith available at
- * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
- * and error.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License v2 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
- */
-
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/input-polldev.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-
-#define HDAPS_LOW_PORT         0x1600  /* first port used by hdaps */
-#define HDAPS_NR_PORTS         0x30    /* number of ports: 0x1600 - 0x162f */
-
-#define HDAPS_PORT_STATE       0x1611  /* device state */
-#define HDAPS_PORT_YPOS                0x1612  /* y-axis position */
-#define        HDAPS_PORT_XPOS         0x1614  /* x-axis position */
-#define HDAPS_PORT_TEMP1       0x1616  /* device temperature, in Celsius */
-#define HDAPS_PORT_YVAR                0x1617  /* y-axis variance (what is this?) */
-#define HDAPS_PORT_XVAR                0x1619  /* x-axis variance (what is this?) */
-#define HDAPS_PORT_TEMP2       0x161b  /* device temperature (again?) */
-#define HDAPS_PORT_UNKNOWN     0x161c  /* what is this? */
-#define HDAPS_PORT_KMACT       0x161d  /* keyboard or mouse activity */
-
-#define STATE_FRESH            0x50    /* accelerometer data is fresh */
-
-#define KEYBD_MASK             0x20    /* set if keyboard activity */
-#define MOUSE_MASK             0x40    /* set if mouse activity */
-#define KEYBD_ISSET(n)         (!! (n & KEYBD_MASK))   /* keyboard used? */
-#define MOUSE_ISSET(n)         (!! (n & MOUSE_MASK))   /* mouse used? */
-
-#define INIT_TIMEOUT_MSECS     4000    /* wait up to 4s for device init ... */
-#define INIT_WAIT_MSECS                200     /* ... in 200ms increments */
-
-#define HDAPS_POLL_INTERVAL    50      /* poll for input every 1/20s (50 ms)*/
-#define HDAPS_INPUT_FUZZ       4       /* input event threshold */
-#define HDAPS_INPUT_FLAT       4
-
-#define HDAPS_X_AXIS           (1 << 0)
-#define HDAPS_Y_AXIS           (1 << 1)
-#define HDAPS_BOTH_AXES                (HDAPS_X_AXIS | HDAPS_Y_AXIS)
-
-static struct platform_device *pdev;
-static struct input_polled_dev *hdaps_idev;
-static unsigned int hdaps_invert;
-static u8 km_activity;
-static int rest_x;
-static int rest_y;
-
-static DEFINE_MUTEX(hdaps_mtx);
-
-/*
- * __get_latch - Get the value from a given port.  Callers must hold hdaps_mtx.
- */
-static inline u8 __get_latch(u16 port)
-{
-       return inb(port) & 0xff;
-}
-
-/*
- * __check_latch - Check a port latch for a given value.  Returns zero if the
- * port contains the given value.  Callers must hold hdaps_mtx.
- */
-static inline int __check_latch(u16 port, u8 val)
-{
-       if (__get_latch(port) == val)
-               return 0;
-       return -EINVAL;
-}
-
-/*
- * __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained.  Callers must hold hdaps_mtx.
- */
-static int __wait_latch(u16 port, u8 val)
-{
-       unsigned int i;
-
-       for (i = 0; i < 20; i++) {
-               if (!__check_latch(port, val))
-                       return 0;
-               udelay(5);
-       }
-
-       return -EIO;
-}
-
-/*
- * __device_refresh - request a refresh from the accelerometer.  Does not wait
- * for refresh to complete.  Callers must hold hdaps_mtx.
- */
-static void __device_refresh(void)
-{
-       udelay(200);
-       if (inb(0x1604) != STATE_FRESH) {
-               outb(0x11, 0x1610);
-               outb(0x01, 0x161f);
-       }
-}
-
-/*
- * __device_refresh_sync - request a synchronous refresh from the
- * accelerometer.  We wait for the refresh to complete.  Returns zero if
- * successful and nonzero on error.  Callers must hold hdaps_mtx.
- */
-static int __device_refresh_sync(void)
-{
-       __device_refresh();
-       return __wait_latch(0x1604, STATE_FRESH);
-}
-
-/*
- * __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh.  Callers must hold hdaps_mtx.
- */
-static inline void __device_complete(void)
-{
-       inb(0x161f);
-       inb(0x1604);
-       __device_refresh();
-}
-
-/*
- * hdaps_readb_one - reads a byte from a single I/O port, placing the value in
- * the given pointer.  Returns zero on success or a negative error on failure.
- * Can sleep.
- */
-static int hdaps_readb_one(unsigned int port, u8 *val)
-{
-       int ret;
-
-       mutex_lock(&hdaps_mtx);
-
-       /* do a sync refresh -- we need to be sure that we read fresh data */
-       ret = __device_refresh_sync();
-       if (ret)
-               goto out;
-
-       *val = inb(port);
-       __device_complete();
-
-out:
-       mutex_unlock(&hdaps_mtx);
-       return ret;
-}
-
-/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */
-static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
-                            int *x, int *y)
-{
-       /* do a sync refresh -- we need to be sure that we read fresh data */
-       if (__device_refresh_sync())
-               return -EIO;
-
-       *y = inw(port2);
-       *x = inw(port1);
-       km_activity = inb(HDAPS_PORT_KMACT);
-       __device_complete();
-
-       /* hdaps_invert is a bitvector to negate the axes */
-       if (hdaps_invert & HDAPS_X_AXIS)
-               *x = -*x;
-       if (hdaps_invert & HDAPS_Y_AXIS)
-               *y = -*y;
-
-       return 0;
-}
-
-/*
- * hdaps_read_pair - reads the values from a pair of ports, placing the values
- * in the given pointers.  Returns zero on success.  Can sleep.
- */
-static int hdaps_read_pair(unsigned int port1, unsigned int port2,
-                          int *val1, int *val2)
-{
-       int ret;
-
-       mutex_lock(&hdaps_mtx);
-       ret = __hdaps_read_pair(port1, port2, val1, val2);
-       mutex_unlock(&hdaps_mtx);
-
-       return ret;
-}
-
-/*
- * hdaps_device_init - initialize the accelerometer.  Returns zero on success
- * and negative error code on failure.  Can sleep.
- */
-static int hdaps_device_init(void)
-{
-       int total, ret = -ENXIO;
-
-       mutex_lock(&hdaps_mtx);
-
-       outb(0x13, 0x1610);
-       outb(0x01, 0x161f);
-       if (__wait_latch(0x161f, 0x00))
-               goto out;
-
-       /*
-        * Most ThinkPads return 0x01.
-        *
-        * Others--namely the R50p, T41p, and T42p--return 0x03.  These laptops
-        * have "inverted" axises.
-        *
-        * The 0x02 value occurs when the chip has been previously initialized.
-        */
-       if (__check_latch(0x1611, 0x03) &&
-                    __check_latch(0x1611, 0x02) &&
-                    __check_latch(0x1611, 0x01))
-               goto out;
-
-       printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
-              __get_latch(0x1611));
-
-       outb(0x17, 0x1610);
-       outb(0x81, 0x1611);
-       outb(0x01, 0x161f);
-       if (__wait_latch(0x161f, 0x00))
-               goto out;
-       if (__wait_latch(0x1611, 0x00))
-               goto out;
-       if (__wait_latch(0x1612, 0x60))
-               goto out;
-       if (__wait_latch(0x1613, 0x00))
-               goto out;
-       outb(0x14, 0x1610);
-       outb(0x01, 0x1611);
-       outb(0x01, 0x161f);
-       if (__wait_latch(0x161f, 0x00))
-               goto out;
-       outb(0x10, 0x1610);
-       outb(0xc8, 0x1611);
-       outb(0x00, 0x1612);
-       outb(0x02, 0x1613);
-       outb(0x01, 0x161f);
-       if (__wait_latch(0x161f, 0x00))
-               goto out;
-       if (__device_refresh_sync())
-               goto out;
-       if (__wait_latch(0x1611, 0x00))
-               goto out;
-
-       /* we have done our dance, now let's wait for the applause */
-       for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
-               int x, y;
-
-               /* a read of the device helps push it into action */
-               __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
-               if (!__wait_latch(0x1611, 0x02)) {
-                       ret = 0;
-                       break;
-               }
-
-               msleep(INIT_WAIT_MSECS);
-       }
-
-out:
-       mutex_unlock(&hdaps_mtx);
-       return ret;
-}
-
-
-/* Device model stuff */
-
-static int hdaps_probe(struct platform_device *dev)
-{
-       int ret;
-
-       ret = hdaps_device_init();
-       if (ret)
-               return ret;
-
-       printk(KERN_INFO "hdaps: device successfully initialized.\n");
-       return 0;
-}
-
-static int hdaps_resume(struct platform_device *dev)
-{
-       return hdaps_device_init();
-}
-
-static struct platform_driver hdaps_driver = {
-       .probe = hdaps_probe,
-       .resume = hdaps_resume,
-       .driver = {
-               .name = "hdaps",
-               .owner = THIS_MODULE,
-       },
-};
-
-/*
- * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_mtx.
- */
-static void hdaps_calibrate(void)
-{
-       __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
-}
-
-static void hdaps_mousedev_poll(struct input_polled_dev *dev)
-{
-       struct input_dev *input_dev = dev->input;
-       int x, y;
-
-       mutex_lock(&hdaps_mtx);
-
-       if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
-               goto out;
-
-       input_report_abs(input_dev, ABS_X, x - rest_x);
-       input_report_abs(input_dev, ABS_Y, y - rest_y);
-       input_sync(input_dev);
-
-out:
-       mutex_unlock(&hdaps_mtx);
-}
-
-
-/* Sysfs Files */
-
-static ssize_t hdaps_position_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       int ret, x, y;
-
-       ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
-       if (ret)
-               return ret;
-
-       return sprintf(buf, "(%d,%d)\n", x, y);
-}
-
-static ssize_t hdaps_variance_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       int ret, x, y;
-
-       ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);
-       if (ret)
-               return ret;
-
-       return sprintf(buf, "(%d,%d)\n", x, y);
-}
-
-static ssize_t hdaps_temp1_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       u8 temp;
-       int ret;
-
-       ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%u\n", temp);
-}
-
-static ssize_t hdaps_temp2_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       u8 temp;
-       int ret;
-
-       ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%u\n", temp);
-}
-
-static ssize_t hdaps_keyboard_activity_show(struct device *dev,
-                                           struct device_attribute *attr,
-                                           char *buf)
-{
-       return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));
-}
-
-static ssize_t hdaps_mouse_activity_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));
-}
-
-static ssize_t hdaps_calibrate_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
-}
-
-static ssize_t hdaps_calibrate_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
-{
-       mutex_lock(&hdaps_mtx);
-       hdaps_calibrate();
-       mutex_unlock(&hdaps_mtx);
-
-       return count;
-}
-
-static ssize_t hdaps_invert_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%u\n", hdaps_invert);
-}
-
-static ssize_t hdaps_invert_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       int invert;
-
-       if (sscanf(buf, "%d", &invert) != 1 ||
-           invert < 0 || invert > HDAPS_BOTH_AXES)
-               return -EINVAL;
-
-       hdaps_invert = invert;
-       hdaps_calibrate();
-
-       return count;
-}
-
-static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
-static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);
-static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
-static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);
-static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
-static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
-static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
-static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
-
-static struct attribute *hdaps_attributes[] = {
-       &dev_attr_position.attr,
-       &dev_attr_variance.attr,
-       &dev_attr_temp1.attr,
-       &dev_attr_temp2.attr,
-       &dev_attr_keyboard_activity.attr,
-       &dev_attr_mouse_activity.attr,
-       &dev_attr_calibrate.attr,
-       &dev_attr_invert.attr,
-       NULL,
-};
-
-static struct attribute_group hdaps_attribute_group = {
-       .attrs = hdaps_attributes,
-};
-
-
-/* Module stuff */
-
-/* hdaps_dmi_match - found a match.  return one, short-circuiting the hunt. */
-static int __init hdaps_dmi_match(const struct dmi_system_id *id)
-{
-       printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
-       return 1;
-}
-
-/* hdaps_dmi_match_invert - found an inverted match. */
-static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
-{
-       hdaps_invert = (unsigned long)id->driver_data;
-       printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
-              hdaps_invert);
-       return hdaps_dmi_match(id);
-}
-
-#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) {  \
-       .ident = vendor " " model,                      \
-       .callback = hdaps_dmi_match_invert,             \
-       .driver_data = (void *)axes,                    \
-       .matches = {                                    \
-               DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
-               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
-       }                                               \
-}
-
-#define HDAPS_DMI_MATCH_NORMAL(vendor, model)          \
-       HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
-
-/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
-   "ThinkPad T42p", so the order of the entries matters.
-   If your ThinkPad is not recognized, please update to latest
-   BIOS. This is especially the case for some R52 ThinkPads. */
-static struct dmi_system_id __initdata hdaps_whitelist[] = {
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
-       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
-       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
-       { .ident = NULL }
-};
-
-static int __init hdaps_init(void)
-{
-       struct input_dev *idev;
-       int ret;
-
-       if (!dmi_check_system(hdaps_whitelist)) {
-               printk(KERN_WARNING "hdaps: supported laptop not found!\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       ret = platform_driver_register(&hdaps_driver);
-       if (ret)
-               goto out_region;
-
-       pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
-       if (IS_ERR(pdev)) {
-               ret = PTR_ERR(pdev);
-               goto out_driver;
-       }
-
-       ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
-       if (ret)
-               goto out_device;
-
-       hdaps_idev = input_allocate_polled_device();
-       if (!hdaps_idev) {
-               ret = -ENOMEM;
-               goto out_group;
-       }
-
-       hdaps_idev->poll = hdaps_mousedev_poll;
-       hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
-
-       /* initial calibrate for the input device */
-       hdaps_calibrate();
-
-       /* initialize the input class */
-       idev = hdaps_idev->input;
-       idev->name = "hdaps";
-       idev->phys = "isa1600/input0";
-       idev->id.bustype = BUS_ISA;
-       idev->dev.parent = &pdev->dev;
-       idev->evbit[0] = BIT_MASK(EV_ABS);
-       input_set_abs_params(idev, ABS_X,
-                       -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
-       input_set_abs_params(idev, ABS_Y,
-                       -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
-
-       ret = input_register_polled_device(hdaps_idev);
-       if (ret)
-               goto out_idev;
-
-       printk(KERN_INFO "hdaps: driver successfully loaded.\n");
-       return 0;
-
-out_idev:
-       input_free_polled_device(hdaps_idev);
-out_group:
-       sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
-out_device:
-       platform_device_unregister(pdev);
-out_driver:
-       platform_driver_unregister(&hdaps_driver);
-out_region:
-       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
-out:
-       printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
-       return ret;
-}
-
-static void __exit hdaps_exit(void)
-{
-       input_unregister_polled_device(hdaps_idev);
-       input_free_polled_device(hdaps_idev);
-       sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
-       platform_device_unregister(pdev);
-       platform_driver_unregister(&hdaps_driver);
-       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
-
-       printk(KERN_INFO "hdaps: driver unloaded.\n");
-}
-
-module_init(hdaps_init);
-module_exit(hdaps_exit);
-
-module_param_named(invert, hdaps_invert, int, 0);
-MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
-                "2 invert y-axis, 3 invert both axes.");
-
-MODULE_AUTHOR("Robert Love");
-MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
-MODULE_LICENSE("GPL v2");
index 36e95753223059ab0e1b5ed8490fe7364b39673e..a56a78412fcba4f9e8d42887cd40382d4418bd2d 100644 (file)
@@ -146,7 +146,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
-       lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
+       lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
        printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
 
        return 1;
@@ -154,16 +154,19 @@ static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 
 /* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
  * If the value is negative, the opposite of the hw value is used. */
-static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
-static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_right = {2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
+#define DEFINE_CONV(name, x, y, z)                           \
+       static union axis_conversion lis3lv02d_axis_##name = \
+               { .as_array = { x, y, z } }
+DEFINE_CONV(normal, 1, 2, 3);
+DEFINE_CONV(y_inverted, 1, -2, 3);
+DEFINE_CONV(x_inverted, -1, 2, 3);
+DEFINE_CONV(z_inverted, 1, 2, -3);
+DEFINE_CONV(xy_swap, 2, 1, 3);
+DEFINE_CONV(xy_rotated_left, -2, 1, 3);
+DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
+DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
+DEFINE_CONV(xy_rotated_right, 2, -1, 3);
+DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
 
 #define AXIS_DMI_MATCH(_ident, _name, _axis) {         \
        .ident = _ident,                                \
@@ -222,7 +225,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
        AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
        AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
-       AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd),
+       AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
@@ -299,7 +302,10 @@ static int lis3lv02d_add(struct acpi_device *device)
        lis3lv02d_enum_resources(device);
 
        /* If possible use a "standard" axes order */
-       if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+       if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
+               printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
+                      lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+       } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
                printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
                                 "using default axes configuration\n");
                lis3_dev.ac = lis3lv02d_axis_normal;
index fc591ae53107da8481a2ab5e02f53117ac6e2471..0cee73a6124e346238bb9bbdded94f0c0d167f59 100644 (file)
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
+#include <linux/slab.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
+#include <linux/pm_runtime.h>
 #include <asm/atomic.h>
 #include "lis3lv02d.h"
 
 #define MDPS_POLL_INTERVAL 50
 #define MDPS_POLL_MIN     0
 #define MDPS_POLL_MAX     2000
+
+#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
+
+#define SELFTEST_OK           0
+#define SELFTEST_FAIL         -1
+#define SELFTEST_IRQ          -2
+
+#define IRQ_LINE0             0
+#define IRQ_LINE1             1
+
 /*
  * The sensor can also generate interrupts (DRDY) but it's pretty pointless
  * because they are generated even if the data do not change. So it's better
 #define LIS3_SENSITIVITY_12B           ((LIS3_ACCURACY * 1000) / 1024)
 #define LIS3_SENSITIVITY_8B            (18 * LIS3_ACCURACY)
 
-#define LIS3_DEFAULT_FUZZ              3
-#define LIS3_DEFAULT_FLAT              3
+#define LIS3_DEFAULT_FUZZ_12B          3
+#define LIS3_DEFAULT_FLAT_12B          3
+#define LIS3_DEFAULT_FUZZ_8B           1
+#define LIS3_DEFAULT_FLAT_8B           1
 
 struct lis3lv02d lis3_dev = {
        .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
@@ -75,6 +89,30 @@ struct lis3lv02d lis3_dev = {
 
 EXPORT_SYMBOL_GPL(lis3_dev);
 
+/* just like param_set_int() but does sanity-check so that it won't point
+ * over the axis array size
+ */
+static int param_set_axis(const char *val, const struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       if (!ret) {
+               int val = *(int *)kp->arg;
+               if (val < 0)
+                       val = -val;
+               if (!val || val > 3)
+                       return -EINVAL;
+       }
+       return ret;
+}
+
+static struct kernel_param_ops param_ops_axis = {
+       .set = param_set_axis,
+       .get = param_get_int,
+};
+
+module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
+MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
+
 static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
 {
        s8 lo;
@@ -123,9 +161,24 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
        int position[3];
        int i;
 
-       position[0] = lis3->read_data(lis3, OUTX);
-       position[1] = lis3->read_data(lis3, OUTY);
-       position[2] = lis3->read_data(lis3, OUTZ);
+       if (lis3->blkread) {
+               if (lis3_dev.whoami == WAI_12B) {
+                       u16 data[3];
+                       lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
+                       for (i = 0; i < 3; i++)
+                               position[i] = (s16)le16_to_cpu(data[i]);
+               } else {
+                       u8 data[5];
+                       /* Data: x, dummy, y, dummy, z */
+                       lis3->blkread(lis3, OUTX, 5, data);
+                       for (i = 0; i < 3; i++)
+                               position[i] = (s8)data[i * 2];
+               }
+       } else {
+               position[0] = lis3->read_data(lis3, OUTX);
+               position[1] = lis3->read_data(lis3, OUTY);
+               position[2] = lis3->read_data(lis3, OUTZ);
+       }
 
        for (i = 0; i < 3; i++)
                position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -138,6 +191,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
 /* conversion btw sampling rate and the register values */
 static int lis3_12_rates[4] = {40, 160, 640, 2560};
 static int lis3_8_rates[2] = {100, 400};
+static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
 
 /* ODR is Output Data Rate */
 static int lis3lv02d_get_odr(void)
@@ -156,6 +210,9 @@ static int lis3lv02d_set_odr(int rate)
        u8 ctrl;
        int i, len, shift;
 
+       if (!rate)
+               return -EINVAL;
+
        lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
        ctrl &= ~lis3_dev.odr_mask;
        len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
@@ -172,19 +229,42 @@ static int lis3lv02d_set_odr(int rate)
 
 static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 {
-       u8 reg;
+       u8 ctlreg, reg;
        s16 x, y, z;
        u8 selftest;
        int ret;
+       u8 ctrl_reg_data;
+       unsigned char irq_cfg;
 
        mutex_lock(&lis3->mutex);
-       if (lis3_dev.whoami == WAI_12B)
-               selftest = CTRL1_ST;
-       else
-               selftest = CTRL1_STP;
 
-       lis3->read(lis3, CTRL_REG1, &reg);
-       lis3->write(lis3, CTRL_REG1, (reg | selftest));
+       irq_cfg = lis3->irq_cfg;
+       if (lis3_dev.whoami == WAI_8B) {
+               lis3->data_ready_count[IRQ_LINE0] = 0;
+               lis3->data_ready_count[IRQ_LINE1] = 0;
+
+               /* Change interrupt cfg to data ready for selftest */
+               atomic_inc(&lis3_dev.wake_thread);
+               lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
+               lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
+               lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
+                               ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
+                               (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
+       }
+
+       if (lis3_dev.whoami == WAI_3DC) {
+               ctlreg = CTRL_REG4;
+               selftest = CTRL4_ST0;
+       } else {
+               ctlreg = CTRL_REG1;
+               if (lis3_dev.whoami == WAI_12B)
+                       selftest = CTRL1_ST;
+               else
+                       selftest = CTRL1_STP;
+       }
+
+       lis3->read(lis3, ctlreg, &reg);
+       lis3->write(lis3, ctlreg, (reg | selftest));
        msleep(lis3->pwron_delay / lis3lv02d_get_odr());
 
        /* Read directly to avoid axis remap */
@@ -193,7 +273,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
        z = lis3->read_data(lis3, OUTZ);
 
        /* back to normal settings */
-       lis3->write(lis3, CTRL_REG1, reg);
+       lis3->write(lis3, ctlreg, reg);
        msleep(lis3->pwron_delay / lis3lv02d_get_odr());
 
        results[0] = x - lis3->read_data(lis3, OUTX);
@@ -201,13 +281,33 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
        results[2] = z - lis3->read_data(lis3, OUTZ);
 
        ret = 0;
+
+       if (lis3_dev.whoami == WAI_8B) {
+               /* Restore original interrupt configuration */
+               atomic_dec(&lis3_dev.wake_thread);
+               lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
+               lis3->irq_cfg = irq_cfg;
+
+               if ((irq_cfg & LIS3_IRQ1_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE0] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+
+               if ((irq_cfg & LIS3_IRQ2_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE1] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+       }
+
        if (lis3->pdata) {
                int i;
                for (i = 0; i < 3; i++) {
                        /* Check against selftest acceptance limits */
                        if ((results[i] < lis3->pdata->st_min_limits[i]) ||
                            (results[i] > lis3->pdata->st_max_limits[i])) {
-                               ret = -EIO;
+                               ret = SELFTEST_FAIL;
                                goto fail;
                        }
                }
@@ -219,10 +319,46 @@ fail:
        return ret;
 }
 
+/*
+ * Order of registers in the list affects to order of the restore process.
+ * Perhaps it is a good idea to set interrupt enable register as a last one
+ * after all other configurations
+ */
+static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
+                              FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
+                              CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
+                              CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
+                              CTRL_REG1, CTRL_REG2, CTRL_REG3};
+
+static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
+                              FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
+                              DD_THSE_L, DD_THSE_H,
+                              CTRL_REG1, CTRL_REG3, CTRL_REG2};
+
+static inline void lis3_context_save(struct lis3lv02d *lis3)
+{
+       int i;
+       for (i = 0; i < lis3->regs_size; i++)
+               lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
+       lis3->regs_stored = true;
+}
+
+static inline void lis3_context_restore(struct lis3lv02d *lis3)
+{
+       int i;
+       if (lis3->regs_stored)
+               for (i = 0; i < lis3->regs_size; i++)
+                       lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
+}
+
 void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 {
+       if (lis3->reg_ctrl)
+               lis3_context_save(lis3);
        /* disable X,Y,Z axis and power down */
        lis3->write(lis3, CTRL_REG1, 0x00);
+       if (lis3->reg_ctrl)
+               lis3->reg_ctrl(lis3, LIS3_REG_OFF);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
@@ -232,19 +368,24 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
 
        lis3->init(lis3);
 
-       /* LIS3 power on delay is quite long */
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
        /*
         * Common configuration
         * BDU: (12 bits sensors only) LSB and MSB values are not updated until
         *      both have been read. So the value read will always be correct.
+        * Set BOOT bit to refresh factory tuning values.
         */
-       if (lis3->whoami ==  WAI_12B) {
-               lis3->read(lis3, CTRL_REG2, &reg);
-               reg |= CTRL2_BDU;
-               lis3->write(lis3, CTRL_REG2, reg);
-       }
+       lis3->read(lis3, CTRL_REG2, &reg);
+       if (lis3->whoami ==  WAI_12B)
+               reg |= CTRL2_BDU | CTRL2_BOOT;
+       else
+               reg |= CTRL2_BOOT_8B;
+       lis3->write(lis3, CTRL_REG2, reg);
+
+       /* LIS3 power on delay is quite long */
+       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+
+       if (lis3->reg_ctrl)
+               lis3_context_restore(lis3);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
@@ -262,6 +403,27 @@ static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
        mutex_unlock(&lis3_dev.mutex);
 }
 
+static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
+{
+       if (lis3_dev.pm_dev)
+               pm_runtime_get_sync(lis3_dev.pm_dev);
+
+       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
+               atomic_set(&lis3_dev.wake_thread, 1);
+       /*
+        * Update coordinates for the case where poll interval is 0 and
+        * the chip in running purely under interrupt control
+        */
+       lis3lv02d_joystick_poll(pidev);
+}
+
+static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
+{
+       atomic_set(&lis3_dev.wake_thread, 0);
+       if (lis3_dev.pm_dev)
+               pm_runtime_put(lis3_dev.pm_dev);
+}
+
 static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 {
        if (!test_bit(0, &lis3_dev.misc_opened))
@@ -277,8 +439,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
        wake_up_interruptible(&lis3_dev.misc_wait);
        kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
 out:
-       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
-           lis3_dev.idev->input->users)
+       if (atomic_read(&lis3_dev.wake_thread))
                return IRQ_WAKE_THREAD;
        return IRQ_HANDLED;
 }
@@ -309,44 +470,41 @@ static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
        mutex_unlock(&lis3->mutex);
 }
 
-static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
 {
-       u8 wu1_src;
-       u8 wu2_src;
-
-       lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
-       lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
+       int dummy;
 
-       wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
-       wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
-
-       /* joystick poll is internally protected by the lis3->mutex. */
-       if (wu1_src || wu2_src)
-               lis3lv02d_joystick_poll(lis3_dev.idev);
+       /* Dummy read to ack interrupt */
+       lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
+       lis3->data_ready_count[index]++;
 }
 
 static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
 {
-
        struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
 
-       if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+       if (irq_cfg == LIS3_IRQ1_CLICK)
                lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE0);
        else
-               lis302dl_interrupt_handle_ff_wu(lis3);
+               lis3lv02d_joystick_poll(lis3->idev);
 
        return IRQ_HANDLED;
 }
 
 static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
 {
-
        struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
 
-       if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+       if (irq_cfg == LIS3_IRQ2_CLICK)
                lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE1);
        else
-               lis302dl_interrupt_handle_ff_wu(lis3);
+               lis3lv02d_joystick_poll(lis3->idev);
 
        return IRQ_HANDLED;
 }
@@ -356,6 +514,9 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
        if (test_and_set_bit(0, &lis3_dev.misc_opened))
                return -EBUSY; /* already open */
 
+       if (lis3_dev.pm_dev)
+               pm_runtime_get_sync(lis3_dev.pm_dev);
+
        atomic_set(&lis3_dev.count, 0);
        return 0;
 }
@@ -364,6 +525,8 @@ static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
        fasync_helper(-1, file, 0, &lis3_dev.async_queue);
        clear_bit(0, &lis3_dev.misc_opened); /* release the device */
+       if (lis3_dev.pm_dev)
+               pm_runtime_put(lis3_dev.pm_dev);
        return 0;
 }
 
@@ -460,6 +623,8 @@ int lis3lv02d_joystick_enable(void)
                return -ENOMEM;
 
        lis3_dev.idev->poll = lis3lv02d_joystick_poll;
+       lis3_dev.idev->open = lis3lv02d_joystick_open;
+       lis3_dev.idev->close = lis3lv02d_joystick_close;
        lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
        lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
        lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
@@ -473,8 +638,16 @@ int lis3lv02d_joystick_enable(void)
 
        set_bit(EV_ABS, input_dev->evbit);
        max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
-       fuzz = (LIS3_DEFAULT_FUZZ * lis3_dev.scale) / LIS3_ACCURACY;
-       flat = (LIS3_DEFAULT_FLAT * lis3_dev.scale) / LIS3_ACCURACY;
+       if (lis3_dev.whoami == WAI_12B) {
+               fuzz = LIS3_DEFAULT_FUZZ_12B;
+               flat = LIS3_DEFAULT_FLAT_12B;
+       } else {
+               fuzz = LIS3_DEFAULT_FUZZ_8B;
+               flat = LIS3_DEFAULT_FLAT_8B;
+       }
+       fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
+       flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+
        input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
@@ -512,14 +685,47 @@ void lis3lv02d_joystick_disable(void)
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
 /* Sysfs stuff */
+static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
+{
+       /*
+        * SYSFS functions are fast visitors so put-call
+        * immediately after the get-call. However, keep
+        * chip running for a while and schedule delayed
+        * suspend. This way periodic sysfs calls doesn't
+        * suffer from relatively long power up time.
+        */
+
+       if (lis3->pm_dev) {
+               pm_runtime_get_sync(lis3->pm_dev);
+               pm_runtime_put_noidle(lis3->pm_dev);
+               pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
+       }
+}
+
 static ssize_t lis3lv02d_selftest_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       int result;
        s16 values[3];
 
-       result = lis3lv02d_selftest(&lis3_dev, values);
-       return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
+       static const char ok[] = "OK";
+       static const char fail[] = "FAIL";
+       static const char irq[] = "FAIL_IRQ";
+       const char *res;
+
+       lis3lv02d_sysfs_poweron(&lis3_dev);
+       switch (lis3lv02d_selftest(&lis3_dev, values)) {
+       case SELFTEST_FAIL:
+               res = fail;
+               break;
+       case SELFTEST_IRQ:
+               res = irq;
+               break;
+       case SELFTEST_OK:
+       default:
+               res = ok;
+               break;
+       }
+       return sprintf(buf, "%s %d %d %d\n", res,
                values[0], values[1], values[2]);
 }
 
@@ -528,6 +734,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
 {
        int x, y, z;
 
+       lis3lv02d_sysfs_poweron(&lis3_dev);
        mutex_lock(&lis3_dev.mutex);
        lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
        mutex_unlock(&lis3_dev.mutex);
@@ -537,6 +744,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
 static ssize_t lis3lv02d_rate_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
+       lis3lv02d_sysfs_poweron(&lis3_dev);
        return sprintf(buf, "%d\n", lis3lv02d_get_odr());
 }
 
@@ -549,6 +757,7 @@ static ssize_t lis3lv02d_rate_set(struct device *dev,
        if (strict_strtoul(buf, 0, &rate))
                return -EINVAL;
 
+       lis3lv02d_sysfs_poweron(&lis3_dev);
        if (lis3lv02d_set_odr(rate))
                return -EINVAL;
 
@@ -585,6 +794,18 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 {
        sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
        platform_device_unregister(lis3->pdev);
+       if (lis3->pm_dev) {
+               /* Barrier after the sysfs remove */
+               pm_runtime_barrier(lis3->pm_dev);
+
+               /* SYSFS may have left chip running. Turn off if necessary */
+               if (!pm_runtime_suspended(lis3->pm_dev))
+                       lis3lv02d_poweroff(&lis3_dev);
+
+               pm_runtime_disable(lis3->pm_dev);
+               pm_runtime_set_suspended(lis3->pm_dev);
+       }
+       kfree(lis3->reg_cache);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
@@ -616,16 +837,16 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
        if (p->wakeup_flags) {
                dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
                dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
-               /* default to 2.5ms for now */
-               dev->write(dev, FF_WU_DURATION_1, 1);
+               /* pdata value + 1 to keep this backward compatible*/
+               dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
                ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
        }
 
        if (p->wakeup_flags2) {
                dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
                dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
-               /* default to 2.5ms for now */
-               dev->write(dev, FF_WU_DURATION_2, 1);
+               /* pdata value + 1 to keep this backward compatible*/
+               dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
                ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
        }
        /* Configure hipass filters */
@@ -635,8 +856,8 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
                err = request_threaded_irq(p->irq2,
                                        NULL,
                                        lis302dl_interrupt_thread2_8b,
-                                       IRQF_TRIGGER_RISING |
-                                       IRQF_ONESHOT,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+                                       (p->irq_flags2 & IRQF_TRIGGER_MASK),
                                        DRIVER_NAME, &lis3_dev);
                if (err < 0)
                        printk(KERN_ERR DRIVER_NAME
@@ -652,6 +873,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 {
        int err;
        irq_handler_t thread_fn;
+       int irq_flags = 0;
 
        dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
 
@@ -664,6 +886,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                dev->odrs = lis3_12_rates;
                dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
                dev->scale = LIS3_SENSITIVITY_12B;
+               dev->regs = lis3_wai12_regs;
+               dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
                break;
        case WAI_8B:
                printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
@@ -673,6 +897,17 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                dev->odrs = lis3_8_rates;
                dev->odr_mask = CTRL1_DR;
                dev->scale = LIS3_SENSITIVITY_8B;
+               dev->regs = lis3_wai8_regs;
+               dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+               break;
+       case WAI_3DC:
+               printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n");
+               dev->read_data = lis3lv02d_read_8;
+               dev->mdps_max_val = 128;
+               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+               dev->odrs = lis3_3dc_rates;
+               dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+               dev->scale = LIS3_SENSITIVITY_8B;
                break;
        default:
                printk(KERN_ERR DRIVER_NAME
@@ -680,11 +915,25 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                return -EINVAL;
        }
 
+       dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+                                    sizeof(lis3_wai12_regs)), GFP_KERNEL);
+
+       if (dev->reg_cache == NULL) {
+               printk(KERN_ERR DRIVER_NAME "out of memory\n");
+               return -ENOMEM;
+       }
+
        mutex_init(&dev->mutex);
+       atomic_set(&dev->wake_thread, 0);
 
        lis3lv02d_add_fs(dev);
        lis3lv02d_poweron(dev);
 
+       if (dev->pm_dev) {
+               pm_runtime_set_active(dev->pm_dev);
+               pm_runtime_enable(dev->pm_dev);
+       }
+
        if (lis3lv02d_joystick_enable())
                printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
 
@@ -696,8 +945,14 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                if (dev->whoami == WAI_8B)
                        lis3lv02d_8b_configure(dev, p);
 
+               irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
+
+               dev->irq_cfg = p->irq_cfg;
                if (p->irq_cfg)
                        dev->write(dev, CTRL_REG3, p->irq_cfg);
+
+               if (p->default_rate)
+                       lis3lv02d_set_odr(p->default_rate);
        }
 
        /* bail if we did not get an IRQ from the bus layer */
@@ -725,7 +980,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
        err = request_threaded_irq(dev->irq, lis302dl_interrupt,
                                thread_fn,
-                               IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                               IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+                               irq_flags,
                                DRIVER_NAME, &lis3_dev);
 
        if (err < 0) {
index 854091380e33887c365898a867af46e70964dee5..a1939589eb2c47e9067ecc85911a19cede974503 100644 (file)
@@ -20,6 +20,7 @@
  */
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
+#include <linux/regulator/consumer.h>
 
 /*
  * This driver tries to support the "digital" accelerometer chips from
@@ -45,6 +46,7 @@ enum lis3_reg {
        CTRL_REG1       = 0x20,
        CTRL_REG2       = 0x21,
        CTRL_REG3       = 0x22,
+       CTRL_REG4       = 0x23,
        HP_FILTER_RESET = 0x23,
        STATUS_REG      = 0x27,
        OUTX_L          = 0x28,
@@ -93,6 +95,7 @@ enum lis3lv02d_reg {
 };
 
 enum lis3_who_am_i {
+       WAI_3DC         = 0x33, /* 8 bits: LIS3DC, HP3DC */
        WAI_12B         = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
        WAI_8B          = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
        WAI_6B          = 0x52, /* 6 bits: LIS331DLF - not supported */
@@ -118,6 +121,13 @@ enum lis3lv02d_ctrl1_8b {
        CTRL1_DR        = 0x80,
 };
 
+enum lis3lv02d_ctrl1_3dc {
+       CTRL1_ODR0      = 0x10,
+       CTRL1_ODR1      = 0x20,
+       CTRL1_ODR2      = 0x40,
+       CTRL1_ODR3      = 0x80,
+};
+
 enum lis3lv02d_ctrl2 {
        CTRL2_DAS       = 0x01,
        CTRL2_SIM       = 0x02,
@@ -129,9 +139,18 @@ enum lis3lv02d_ctrl2 {
        CTRL2_FS        = 0x80, /* Full Scale selection */
 };
 
+enum lis3lv02d_ctrl4_3dc {
+       CTRL4_SIM       = 0x01,
+       CTRL4_ST0       = 0x02,
+       CTRL4_ST1       = 0x04,
+       CTRL4_FS0       = 0x10,
+       CTRL4_FS1       = 0x20,
+};
+
 enum lis302d_ctrl2 {
        HP_FF_WU2       = 0x08,
        HP_FF_WU1       = 0x04,
+       CTRL2_BOOT_8B   = 0x40,
 };
 
 enum lis3lv02d_ctrl3 {
@@ -206,19 +225,33 @@ enum lis3lv02d_click_src_8b {
        CLICK_IA        = 0x40,
 };
 
-struct axis_conversion {
-       s8      x;
-       s8      y;
-       s8      z;
+enum lis3lv02d_reg_state {
+       LIS3_REG_OFF    = 0x00,
+       LIS3_REG_ON     = 0x01,
+};
+
+union axis_conversion {
+       struct {
+               int x, y, z;
+       };
+       int as_array[3];
+
 };
 
 struct lis3lv02d {
        void                    *bus_priv; /* used by the bus layer only */
+       struct device           *pm_dev; /* for pm_runtime purposes */
        int (*init) (struct lis3lv02d *lis3);
        int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
        int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
+       int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
+       int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
 
        int                     *odrs;     /* Supported output data rates */
+       u8                      *regs;     /* Regs to store / restore */
+       int                     regs_size;
+       u8                      *reg_cache;
+       bool                    regs_stored;
        u8                      odr_mask;  /* ODR bit mask */
        u8                      whoami;    /* indicates measurement precision */
        s16 (*read_data) (struct lis3lv02d *lis3, int reg);
@@ -231,14 +264,18 @@ struct lis3lv02d {
 
        struct input_polled_dev *idev;     /* input device */
        struct platform_device  *pdev;     /* platform device */
+       struct regulator_bulk_data regulators[2];
        atomic_t                count;     /* interrupt count after last read */
-       struct axis_conversion  ac;        /* hw -> logical axis */
+       union axis_conversion   ac;        /* hw -> logical axis */
        int                     mapped_btns[3];
 
        u32                     irq;       /* IRQ number */
        struct fasync_struct    *async_queue; /* queue for the misc device */
        wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
        unsigned long           misc_opened; /* bit0: whether the device is open */
+       int                     data_ready_count[2];
+       atomic_t                wake_thread;
+       unsigned char           irq_cfg;
 
        struct lis3lv02d_platform_data *pdata;  /* for passing board config */
        struct mutex            mutex;     /* Serialize poll and selftest */
index 8e5933b72d1956c2a931ea7176b1c589e3066968..9f4bae07f7194ebff499b2902895dc44c507d974 100644 (file)
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
 #include "lis3lv02d.h"
 
 #define DRV_NAME       "lis3lv02d_i2c"
 
+static const char reg_vdd[]    = "Vdd";
+static const char reg_vdd_io[] = "Vdd_IO";
+
+static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
+{
+       int ret;
+       if (state == LIS3_REG_OFF) {
+               ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
+                                       lis3->regulators);
+       } else {
+               ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
+                                       lis3->regulators);
+               /* Chip needs time to wakeup. Not mentioned in datasheet */
+               usleep_range(10000, 20000);
+       }
+       return ret;
+}
+
 static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
 {
        struct i2c_client *c = lis3->bus_priv;
@@ -46,24 +66,38 @@ static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
        return 0;
 }
 
+static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
+                               u8 *v)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       reg |= (1 << 7); /* 7th bit enables address auto incrementation */
+       return i2c_smbus_read_i2c_block_data(c, reg, len, v);
+}
+
 static int lis3_i2c_init(struct lis3lv02d *lis3)
 {
        u8 reg;
        int ret;
 
+       if (lis3->reg_ctrl)
+               lis3_reg_ctrl(lis3, LIS3_REG_ON);
+
+       lis3->read(lis3, WHO_AM_I, &reg);
+       if (reg != lis3->whoami)
+               printk(KERN_ERR "lis3: power on failure\n");
+
        /* power up the device */
        ret = lis3->read(lis3, CTRL_REG1, &reg);
        if (ret < 0)
                return ret;
 
-       reg |= CTRL1_PD0;
+       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
        return lis3->write(lis3, CTRL_REG1, reg);
 }
 
 /* Default axis mapping but it can be overwritten by platform data */
-static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
-                                                    LIS3_DEV_Y,
-                                                    LIS3_DEV_Z };
+static union axis_conversion lis3lv02d_axis_map =
+       { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
 
 static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
@@ -72,6 +106,15 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
        struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
 
        if (pdata) {
+               /* Regulator control is optional */
+               if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
+                       lis3_dev.reg_ctrl = lis3_reg_ctrl;
+
+               if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
+                       (i2c_check_functionality(client->adapter,
+                                               I2C_FUNC_SMBUS_I2C_BLOCK)))
+                       lis3_dev.blkread  = lis3_i2c_blockread;
+
                if (pdata->axis_x)
                        lis3lv02d_axis_map.x = pdata->axis_x;
 
@@ -88,6 +131,16 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
                        goto fail;
        }
 
+       if (lis3_dev.reg_ctrl) {
+               lis3_dev.regulators[0].supply = reg_vdd;
+               lis3_dev.regulators[1].supply = reg_vdd_io;
+               ret = regulator_bulk_get(&client->dev,
+                                       ARRAY_SIZE(lis3_dev.regulators),
+                                       lis3_dev.regulators);
+               if (ret < 0)
+                       goto fail;
+       }
+
        lis3_dev.pdata    = pdata;
        lis3_dev.bus_priv = client;
        lis3_dev.init     = lis3_i2c_init;
@@ -95,10 +148,24 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
        lis3_dev.write    = lis3_i2c_write;
        lis3_dev.irq      = client->irq;
        lis3_dev.ac       = lis3lv02d_axis_map;
+       lis3_dev.pm_dev   = &client->dev;
 
        i2c_set_clientdata(client, &lis3_dev);
+
+       /* Provide power over the init call */
+       if (lis3_dev.reg_ctrl)
+               lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
+
        ret = lis3lv02d_init_device(&lis3_dev);
+
+       if (lis3_dev.reg_ctrl)
+               lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
+
+       if (ret == 0)
+               return 0;
 fail:
+       if (pdata && pdata->release_resources)
+               pdata->release_resources();
        return ret;
 }
 
@@ -111,14 +178,18 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
                pdata->release_resources();
 
        lis3lv02d_joystick_disable();
-       lis3lv02d_poweroff(lis3);
+       lis3lv02d_remove_fs(&lis3_dev);
 
-       return lis3lv02d_remove_fs(&lis3_dev);
+       if (lis3_dev.reg_ctrl)
+               regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
+                               lis3_dev.regulators);
+       return 0;
 }
 
 #ifdef CONFIG_PM
-static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int lis3lv02d_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
        struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
        if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -126,18 +197,21 @@ static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int lis3lv02d_i2c_resume(struct i2c_client *client)
+static int lis3lv02d_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
        struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+       /*
+        * pm_runtime documentation says that devices should always
+        * be powered on at resume. Pm_runtime turns them off after system
+        * wide resume is complete.
+        */
+       if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
+               pm_runtime_suspended(dev))
                lis3lv02d_poweron(lis3);
-       return 0;
-}
 
-static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
-{
-       lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
+       return 0;
 }
 #else
 #define lis3lv02d_i2c_suspend  NULL
@@ -145,6 +219,24 @@ static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
 #define lis3lv02d_i2c_shutdown NULL
 #endif
 
+static int lis3_i2c_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static int lis3_i2c_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       lis3lv02d_poweron(lis3);
+       return 0;
+}
+
 static const struct i2c_device_id lis3lv02d_id[] = {
        {"lis3lv02d", 0 },
        {}
@@ -152,14 +244,20 @@ static const struct i2c_device_id lis3lv02d_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
 
+static const struct dev_pm_ops lis3_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
+                               lis3lv02d_i2c_resume)
+       SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
+                          lis3_i2c_runtime_resume,
+                          NULL)
+};
+
 static struct i2c_driver lis3lv02d_i2c_driver = {
        .driver  = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .pm     = &lis3_pm_ops,
        },
-       .suspend = lis3lv02d_i2c_suspend,
-       .shutdown = lis3lv02d_i2c_shutdown,
-       .resume = lis3lv02d_i2c_resume,
        .probe  = lis3lv02d_i2c_probe,
        .remove = __devexit_p(lis3lv02d_i2c_remove),
        .id_table = lis3lv02d_id,
index b9be5e3a22b3825bc640d9c038c8c724e888c5b4..2549de1de4e2baccadca7ed80d8fc642d65ca781 100644 (file)
@@ -50,11 +50,12 @@ static int lis3_spi_init(struct lis3lv02d *lis3)
        if (ret < 0)
                return ret;
 
-       reg |= CTRL1_PD0;
+       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
        return lis3->write(lis3, CTRL_REG1, reg);
 }
 
-static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
+static union axis_conversion lis3lv02d_axis_normal =
+       { .as_array = { 1, 2, 3 } };
 
 static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 {
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
new file mode 100644 (file)
index 0000000..2676261
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot Swap Controller
+ *
+ * Copyright (C) 2010 Ericsson AB.
+ *
+ * Derived from:
+ *
+ *  Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ *  Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Datasheet: http://cds.linear.com/docs/Datasheet/42612fb.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/* chip registers */
+#define LTC4261_STATUS 0x00    /* readonly */
+#define LTC4261_FAULT  0x01
+#define LTC4261_ALERT  0x02
+#define LTC4261_CONTROL        0x03
+#define LTC4261_SENSE_H        0x04
+#define LTC4261_SENSE_L        0x05
+#define LTC4261_ADIN2_H        0x06
+#define LTC4261_ADIN2_L        0x07
+#define LTC4261_ADIN_H 0x08
+#define LTC4261_ADIN_L 0x09
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV       (1<<0)
+#define FAULT_UV       (1<<1)
+#define FAULT_OC       (1<<2)
+
+struct ltc4261_data {
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated;     /* in jiffies */
+
+       /* Registers */
+       u8 regs[10];
+};
+
+static struct ltc4261_data *ltc4261_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ltc4261_data *data = i2c_get_clientdata(client);
+       struct ltc4261_data *ret = data;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ / 4) || !data->valid) {
+               int i;
+
+               /* Read registers -- 0x00 to 0x09 */
+               for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+                       int val;
+
+                       val = i2c_smbus_read_byte_data(client, i);
+                       if (unlikely(val < 0)) {
+                               dev_dbg(dev,
+                                       "Failed to read ADC value: error %d",
+                                       val);
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->regs[i] = val;
+               }
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4261_get_value(struct ltc4261_data *data, u8 reg)
+{
+       u32 val;
+
+       val = (data->regs[reg] << 2) + (data->regs[reg + 1] >> 6);
+
+       switch (reg) {
+       case LTC4261_ADIN_H:
+       case LTC4261_ADIN2_H:
+               /* 2.5mV resolution. Convert to mV. */
+               val = val * 25 / 10;
+               break;
+       case LTC4261_SENSE_H:
+               /*
+                * 62.5uV resolution. Convert to current as measured with
+                * an 1 mOhm sense resistor, in mA. If a different sense
+                * resistor is installed, calculate the actual current by
+                * dividing the reported current by the sense resistor value
+                * in mOhm.
+                */
+               val = val * 625 / 10;
+               break;
+       default:
+               /* If we get here, the developer messed up */
+               WARN_ON_ONCE(1);
+               val = 0;
+               break;
+       }
+
+       return val;
+}
+
+static ssize_t ltc4261_show_value(struct device *dev,
+                                 struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ltc4261_data *data = ltc4261_update_device(dev);
+       int value;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       value = ltc4261_get_value(data, attr->index);
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4261_show_bool(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ltc4261_data *data = ltc4261_update_device(dev);
+       u8 fault;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       fault = data->regs[LTC4261_FAULT] & attr->index;
+       if (fault)              /* Clear reported faults in chip register */
+               i2c_smbus_write_byte_data(client, LTC4261_FAULT, ~fault);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
+}
+
+/*
+ * These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4261_show_value, NULL, ltc4261_cmd_idx)
+
+#define LTC4261_BOOL(name, mask) \
+       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+       ltc4261_show_bool, NULL, (mask))
+
+/*
+ * Input voltages.
+ */
+LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
+LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
+
+/*
+ * Voltage alarms. The chip has only one set of voltage alarm status bits,
+ * triggered by input voltage alarms. In many designs, those alarms are
+ * associated with the ADIN2 sensor, due to the proximity of the ADIN2 pin
+ * to the OV pin. ADIN2 is, however, not available on all chip variants.
+ * To ensure that the alarm condition is reported to the user, report it
+ * with both voltage sensors.
+ */
+LTC4261_BOOL(in1_min_alarm, FAULT_UV);
+LTC4261_BOOL(in1_max_alarm, FAULT_OV);
+LTC4261_BOOL(in2_min_alarm, FAULT_UV);
+LTC4261_BOOL(in2_max_alarm, FAULT_OV);
+
+/* Currents (via sense resistor) */
+LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
+
+/* Overcurrent alarm */
+LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
+
+static struct attribute *ltc4261_attributes[] = {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+       NULL,
+};
+
+static const struct attribute_group ltc4261_group = {
+       .attrs = ltc4261_attributes,
+};
+
+static int ltc4261_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct ltc4261_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
+               dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
+                       adapter->id, client->addr, LTC4261_STATUS);
+               return -ENODEV;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto out_kzalloc;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Clear faults */
+       i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00);
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &ltc4261_group);
+       if (ret)
+               goto out_sysfs_create_group;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto out_hwmon_device_register;
+       }
+
+       return 0;
+
+out_hwmon_device_register:
+       sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+out_sysfs_create_group:
+       kfree(data);
+out_kzalloc:
+       return ret;
+}
+
+static int ltc4261_remove(struct i2c_client *client)
+{
+       struct ltc4261_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id ltc4261_id[] = {
+       {"ltc4261", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4261_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4261_driver = {
+       .driver = {
+                  .name = "ltc4261",
+                  },
+       .probe = ltc4261_probe,
+       .remove = ltc4261_remove,
+       .id_table = ltc4261_id,
+};
+
+static int __init ltc4261_init(void)
+{
+       return i2c_add_driver(&ltc4261_driver);
+}
+
+static void __exit ltc4261_exit(void)
+{
+       i2c_del_driver(&ltc4261_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("LTC4261 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4261_init);
+module_exit(ltc4261_exit);
index f11903936c8b3a51c3f8dddcb20318185952fa79..0798210590bc01f19136b76ef073e16f122ea11f 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -35,6 +34,7 @@
 #include <linux/cpu.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/smp.h>
 
 #define DRVNAME        "pkgtemp"
 
@@ -339,8 +339,7 @@ exit:
        return err;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void pkgtemp_device_remove(unsigned int cpu)
+static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p;
        unsigned int i;
@@ -387,12 +386,10 @@ static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb,
 static struct notifier_block pkgtemp_cpu_notifier __refdata = {
        .notifier_call = pkgtemp_cpu_callback,
 };
-#endif                         /* !CONFIG_HOTPLUG_CPU */
 
 static int __init pkgtemp_init(void)
 {
        int i, err = -ENODEV;
-       struct pdev_entry *p, *n;
 
        /* quick check if we run Intel */
        if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
@@ -402,31 +399,23 @@ static int __init pkgtemp_init(void)
        if (err)
                goto exit;
 
-       for_each_online_cpu(i) {
-               err = pkgtemp_device_add(i);
-               if (err)
-                       goto exit_devices_unreg;
-       }
+       for_each_online_cpu(i)
+               pkgtemp_device_add(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
                err = -ENODEV;
                goto exit_driver_unreg;
        }
+#endif
 
-#ifdef CONFIG_HOTPLUG_CPU
        register_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
        return 0;
 
-exit_devices_unreg:
-       mutex_lock(&pdev_list_mutex);
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
-               platform_device_unregister(p->pdev);
-               list_del(&p->list);
-               kfree(p);
-       }
-       mutex_unlock(&pdev_list_mutex);
+#ifndef CONFIG_HOTPLUG_CPU
 exit_driver_unreg:
        platform_driver_unregister(&pkgtemp_driver);
+#endif
 exit:
        return err;
 }
@@ -434,9 +423,8 @@ exit:
 static void __exit pkgtemp_exit(void)
 {
        struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
        unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
                platform_device_unregister(p->pdev);
index ffb793af680b7cf378e6e1cf63c5e9bfc7c378c7..ec7fad747adc51b6252c11e3b3a151208a8b9d32 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/hwmon.h>
 #include <linux/sysfs.h>
 #include <linux/hwmon-sysfs.h>
@@ -237,8 +235,7 @@ exit:
        return err;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void via_cputemp_device_remove(unsigned int cpu)
+static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p, *n;
        mutex_lock(&pdev_list_mutex);
@@ -272,7 +269,6 @@ static int __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb,
 static struct notifier_block via_cputemp_cpu_notifier __refdata = {
        .notifier_call = via_cputemp_cpu_callback,
 };
-#endif                         /* !CONFIG_HOTPLUG_CPU */
 
 static int __init via_cputemp_init(void)
 {
@@ -313,9 +309,7 @@ static int __init via_cputemp_init(void)
                goto exit_driver_unreg;
        }
 
-#ifdef CONFIG_HOTPLUG_CPU
        register_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
        return 0;
 
 exit_devices_unreg:
@@ -335,9 +329,8 @@ exit:
 static void __exit via_cputemp_exit(void)
 {
        struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
        unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
                platform_device_unregister(p->pdev);
index 4f93da31d3ad8c4dd9b6f6d719a6ea1571b00819..3cad8fecc3d3ced40637d8460ebc01afa70dc7dc 100644 (file)
@@ -101,12 +101,12 @@ struct cami2c {
 
 static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
 {
-       ctrl_outl(val, (unsigned long)cam->iobase + reg);
+       __raw_writel(val, (unsigned long)cam->iobase + reg);
 }
 
 static inline unsigned long IN32(struct cami2c *cam, int reg)
 {
-       return ctrl_inl((unsigned long)cam->iobase + reg);
+       return __raw_readl((unsigned long)cam->iobase + reg);
 }
 
 static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
index 598c49acaeb53eb7ae3d0bc9d0b4a1873901d5b2..2707f5e17158a1dfe3b65e112f1a7a14824c253c 100644 (file)
@@ -538,15 +538,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
 {
        struct resource *res;
        int ret = -ENXIO;
-       int q, m;
-       int k = 0;
-       int n = 0;
+       int n, k = 0;
 
        while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
                for (n = res->start; hook && n <= res->end; n++) {
                        if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
-                                       dev_name(&dev->dev), dev))
+                                       dev_name(&dev->dev), dev)) {
+                               for (n--; n >= res->start; n--)
+                                       free_irq(n, dev);
+
                                goto rollback;
+                       }
                }
                k++;
        }
@@ -554,16 +556,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
        if (hook)
                return k > 0 ? 0 : -ENOENT;
 
-       k--;
        ret = 0;
 
  rollback:
-       for (q = k; k >= 0; k--) {
-               for (m = n; m >= res->start; m--)
-                       free_irq(m, dev);
+       k--;
+
+       while (k >= 0) {
+               res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+               for (n = res->start; n <= res->end; n++)
+                       free_irq(n, dev);
 
-               res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
-               m = res->end;
+               k--;
        }
 
        return ret;
index cb3ccf3ed221ecef98c996fc50206b17ba1f1c1a..41665d2f9f93c1fa585533184468da72039fe7cf 100644 (file)
@@ -74,7 +74,7 @@ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
 static unsigned int mwait_substates;
 
 /* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
-static unsigned int lapic_timer_reliable_states;
+static unsigned int lapic_timer_reliable_states = (1 << 1);     /* Default to only C1 */
 
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
@@ -94,7 +94,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 3,
-               .power_usage = 1000,
                .target_residency = 6,
                .enter = &intel_idle },
        { /* MWAIT C2 */
@@ -103,7 +102,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 20,
-               .power_usage = 500,
                .target_residency = 80,
                .enter = &intel_idle },
        { /* MWAIT C3 */
@@ -112,11 +110,46 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x20,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 200,
-               .power_usage = 350,
                .target_residency = 800,
                .enter = &intel_idle },
 };
 
+static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
+       { /* MWAIT C0 */ },
+       { /* MWAIT C1 */
+               .name = "SNB-C1",
+               .desc = "MWAIT 0x00",
+               .driver_data = (void *) 0x00,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 1,
+               .target_residency = 4,
+               .enter = &intel_idle },
+       { /* MWAIT C2 */
+               .name = "SNB-C3",
+               .desc = "MWAIT 0x10",
+               .driver_data = (void *) 0x10,
+               .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 80,
+               .target_residency = 160,
+               .enter = &intel_idle },
+       { /* MWAIT C3 */
+               .name = "SNB-C6",
+               .desc = "MWAIT 0x20",
+               .driver_data = (void *) 0x20,
+               .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 104,
+               .target_residency = 208,
+               .enter = &intel_idle },
+       { /* MWAIT C4 */
+               .name = "SNB-C7",
+               .desc = "MWAIT 0x30",
+               .driver_data = (void *) 0x30,
+               .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 109,
+               .target_residency = 300,
+               .enter = &intel_idle },
+};
+
 static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
        { /* MWAIT C0 */ },
        { /* MWAIT C1 */
@@ -125,7 +158,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 1,
-               .power_usage = 1000,
                .target_residency = 4,
                .enter = &intel_idle },
        { /* MWAIT C2 */
@@ -134,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 20,
-               .power_usage = 500,
                .target_residency = 80,
                .enter = &intel_idle },
        { /* MWAIT C3 */ },
@@ -144,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x30,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 100,
-               .power_usage = 250,
                .target_residency = 400,
                .enter = &intel_idle },
        { /* MWAIT C5 */ },
@@ -154,7 +184,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .driver_data = (void *) 0x52,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 140,
-               .power_usage = 150,
                .target_residency = 560,
                .enter = &intel_idle },
 };
@@ -179,13 +208,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
        local_irq_disable();
 
        /*
-        * If the state flag indicates that the TLB will be flushed or if this
-        * is the deepest c-state supported, do a voluntary leave mm to avoid
-        * costly and mostly unnecessary wakeups for flushing the user TLB's
-        * associated with the active mm.
+        * leave_mm() to avoid costly and often unnecessary wakeups
+        * for flushing the user TLB's associated with the active mm.
         */
-       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED ||
-           (&dev->states[dev->state_count - 1] == state))
+       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
                leave_mm(cpu);
 
        if (!(lapic_timer_reliable_states & (1 << (cstate))))
@@ -269,9 +295,14 @@ static int intel_idle_probe(void)
 
        case 0x1C:      /* 28 - Atom Processor */
        case 0x26:      /* 38 - Lincroft Atom Processor */
-               lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+               lapic_timer_reliable_states = (1 << 1); /* C1 */
                cpuidle_state_table = atom_cstates;
                break;
+
+       case 0x2A:      /* SNB */
+       case 0x2D:      /* SNB Xeon */
+               cpuidle_state_table = snb_cstates;
+               break;
 #ifdef FUTURE_USE
        case 0x17:      /* 23 - Core 2 Duo */
                lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
deleted file mode 100644 (file)
index e02096c..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-config IEEE1394
-       tristate "Legacy alternative FireWire driver stack"
-       depends on PCI || BROKEN
-       help
-         IEEE 1394 describes a high performance serial bus, which is also
-         known as FireWire(tm) or i.Link(tm) and is used for connecting all
-         sorts of devices (most notably digital video cameras) to your
-         computer.
-
-         If you have FireWire hardware and want to use it, say Y here.  This
-         is the core support only, you will also need to select a driver for
-         your IEEE 1394 adapter.
-
-         To compile this driver as a module, say M here: the module will be
-         called ieee1394.
-
-         NOTE:
-         ieee1394 is superseded by the newer firewire-core driver.  See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_OHCI1394
-       tristate "OHCI-1394 controllers"
-       depends on PCI && IEEE1394
-       help
-         Enable this driver if you have an IEEE 1394 controller based on the
-         OHCI-1394 specification. The current driver is only tested with OHCI
-         chipsets made by Texas Instruments and NEC. Most third-party vendors
-         use one of these chipsets.  It should work with any OHCI-1394
-         compliant card, however.
-
-         To compile this driver as a module, say M here: the module will be
-         called ohci1394.
-
-         NOTE:
-         ohci1394 is superseded by the newer firewire-ohci driver.  See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-         If you want to install firewire-ohci and ohci1394 together, you
-         should configure them only as modules and blacklist the driver(s)
-         which you don't want to have auto-loaded.  Add either
-
-             blacklist ohci1394
-             blacklist video1394
-             blacklist dv1394
-         or
-             blacklist firewire-ohci
-
-         to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
-         depending on your distribution.
-
-comment "PCILynx controller requires I2C"
-       depends on IEEE1394 && I2C=n
-
-config IEEE1394_PCILYNX
-       tristate "PCILynx controller"
-       depends on PCI && IEEE1394 && I2C
-       select I2C_ALGOBIT
-       help
-         Say Y here if you have an IEEE-1394 controller with the Texas
-         Instruments PCILynx chip.  Note: this driver is written for revision
-         2 of this chip and may not work with revision 0.
-
-         To compile this driver as a module, say M here: the module will be
-         called pcilynx.
-
-         Only some old and now very rare PCI and CardBus cards and
-         PowerMacs G3 B&W contain the PCILynx controller.  Therefore
-         almost everybody can say N here.
-
-comment "SBP-2 support (for storage devices) requires SCSI"
-       depends on IEEE1394 && SCSI=n
-
-config IEEE1394_SBP2
-       tristate "Storage devices (SBP-2 protocol)"
-       depends on IEEE1394 && SCSI
-       help
-         This option enables you to use SBP-2 devices connected to an IEEE
-         1394 bus.  SBP-2 devices include storage devices like harddisks and
-         DVD drives, also some other FireWire devices like scanners.
-
-         You should also enable support for disks, CD-ROMs, etc. in the SCSI
-         configuration section.
-
-         To compile this driver as a module, say M here: the module will be
-         called sbp2.
-
-         NOTE:
-         sbp2 is superseded by the newer firewire-sbp2 driver. See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_SBP2_PHYS_DMA
-       bool "Enable replacement for physical DMA in SBP2"
-       depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
-       help
-         This builds sbp2 for use with non-OHCI host adapters which do not
-         support physical DMA or for when ohci1394 is run with phys_dma=0.
-         Physical DMA is data movement without assistance of the drivers'
-         interrupt handlers.  This option includes the interrupt handlers
-         that are required in absence of this hardware feature.
-
-         This option is buggy and currently broken on some architectures.
-         If unsure, say N.
-
-config IEEE1394_ETH1394_ROM_ENTRY
-       depends on IEEE1394
-       bool
-       default n
-
-config IEEE1394_ETH1394
-       tristate "IP networking over 1394 (experimental)"
-       depends on IEEE1394 && EXPERIMENTAL && INET
-       select IEEE1394_ETH1394_ROM_ENTRY
-       help
-         This driver implements a functional majority of RFC 2734: IPv4 over
-         1394.  It will provide IP connectivity with implementations of RFC
-         2734 found on other operating systems.  It will not communicate with
-         older versions of this driver found in stock kernels prior to 2.6.3.
-         This driver is still considered experimental.  It does not yet support
-         MCAP, therefore multicast support is significantly limited.
-
-         The module is called eth1394 although it does not emulate Ethernet.
-
-         NOTE:
-         eth1394 is superseded by the newer firewire-net driver. See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_RAWIO
-       tristate "raw1394 userspace interface"
-       depends on IEEE1394
-       help
-         This option adds support for the raw1394 device file which enables
-         direct communication of user programs with IEEE 1394 devices
-         (isochronous and asynchronous).  Almost all application programs
-         which access FireWire require this option.
-
-         To compile this driver as a module, say M here: the module will be
-         called raw1394.
-
-         NOTE:
-         raw1394 is superseded by the newer firewire-core driver. See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_VIDEO1394
-       tristate "video1394 userspace interface"
-       depends on IEEE1394 && IEEE1394_OHCI1394
-       help
-         This option adds support for the video1394 device files which enable
-         isochronous communication of user programs with IEEE 1394 devices,
-         especially video capture or export.  This interface is used by all
-         libdc1394 based programs and by several other programs, in addition to
-         the raw1394 interface.  It is generally not required for DV capture.
-
-         To compile this driver as a module, say M here: the module will be
-         called video1394.
-
-         NOTE:
-         video1394 is superseded by the newer firewire-core driver. See
-         http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-         further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_DV1394
-       tristate "dv1394 userspace interface (deprecated)"
-       depends on IEEE1394 && IEEE1394_OHCI1394
-       help
-         The dv1394 driver is unsupported and may be removed from Linux in a
-         future release.  Its functionality is now provided by either
-         raw1394 or firewire-core together with libraries such as libiec61883.
-
-config IEEE1394_VERBOSEDEBUG
-       bool "Excessive debugging output"
-       depends on IEEE1394
-       help
-         If you say Y here, you will get very verbose debugging logs from the
-         ieee1394 drivers, including sent and received packet headers.  This
-         will quickly result in large amounts of data sent to the system log.
-
-         Say Y if you really need the debugging output.  Everyone else says N.
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
deleted file mode 100644 (file)
index 1f8153b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the Linux IEEE 1394 implementation
-#
-
-ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-                highlevel.o csr.o nodemgr.o dma.o iso.o \
-                csr1212.o config_roms.o
-
-obj-$(CONFIG_IEEE1394) += ieee1394.o
-obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
-obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
-obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
-obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
-obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
-obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
-obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-
-obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
deleted file mode 100644 (file)
index 1b98120..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * ConfigROM  entries
- *
- * Copyright (C) 2004 Ben Collins
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/types.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "csr.h"
-#include "config_roms.h"
-
-struct hpsb_config_rom_entry {
-       const char *name;
-
-       /* Base initialization, called at module load */
-       int (*init)(void);
-
-       /* Cleanup called at module exit */
-       void (*cleanup)(void);
-
-       /* The flag added to host->config_roms */
-       unsigned int flag;
-};
-
-/* The default host entry. This must succeed. */
-int hpsb_default_host_entry(struct hpsb_host *host)
-{
-       struct csr1212_keyval *root;
-       struct csr1212_keyval *vend_id = NULL;
-       struct csr1212_keyval *text = NULL;
-       char csr_name[128];
-       int ret;
-
-       sprintf(csr_name, "Linux - %s", host->driver->name);
-       root = host->csr.rom->root_kv;
-
-       vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
-       text = csr1212_new_string_descriptor_leaf(csr_name);
-
-       if (!vend_id || !text) {
-               if (vend_id)
-                       csr1212_release_keyval(vend_id);
-               if (text)
-                       csr1212_release_keyval(text);
-               csr1212_destroy_csr(host->csr.rom);
-               return -ENOMEM;
-       }
-
-       csr1212_associate_keyval(vend_id, text);
-       csr1212_release_keyval(text);
-       ret = csr1212_attach_keyval_to_directory(root, vend_id);
-       csr1212_release_keyval(vend_id);
-       if (ret != CSR1212_SUCCESS) {
-               csr1212_destroy_csr(host->csr.rom);
-               return -ENOMEM;
-       }
-
-       host->update_config_rom = 1;
-
-       return 0;
-}
-
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-#include "eth1394.h"
-
-static struct csr1212_keyval *ip1394_ud;
-
-static int config_rom_ip1394_init(void)
-{
-       struct csr1212_keyval *spec_id = NULL;
-       struct csr1212_keyval *spec_desc = NULL;
-       struct csr1212_keyval *ver = NULL;
-       struct csr1212_keyval *ver_desc = NULL;
-       int ret = -ENOMEM;
-
-       ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
-
-       spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
-                                       ETHER1394_GASP_SPECIFIER_ID);
-       spec_desc = csr1212_new_string_descriptor_leaf("IANA");
-       ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
-                                   ETHER1394_GASP_VERSION);
-       ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
-
-       if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
-               goto ip1394_fail;
-
-       csr1212_associate_keyval(spec_id, spec_desc);
-       csr1212_associate_keyval(ver, ver_desc);
-       if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
-                       == CSR1212_SUCCESS &&
-           csr1212_attach_keyval_to_directory(ip1394_ud, ver)
-                       == CSR1212_SUCCESS)
-               ret = 0;
-
-ip1394_fail:
-       if (ret && ip1394_ud) {
-               csr1212_release_keyval(ip1394_ud);
-               ip1394_ud = NULL;
-       }
-
-       if (spec_id)
-               csr1212_release_keyval(spec_id);
-       if (spec_desc)
-               csr1212_release_keyval(spec_desc);
-       if (ver)
-               csr1212_release_keyval(ver);
-       if (ver_desc)
-               csr1212_release_keyval(ver_desc);
-
-       return ret;
-}
-
-static void config_rom_ip1394_cleanup(void)
-{
-       if (ip1394_ud) {
-               csr1212_release_keyval(ip1394_ud);
-               ip1394_ud = NULL;
-       }
-}
-
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
-{
-       if (!ip1394_ud)
-               return -ENODEV;
-
-       if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
-                                              ip1394_ud) != CSR1212_SUCCESS)
-               return -ENOMEM;
-
-       host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
-       host->update_config_rom = 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
-
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
-{
-       csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
-       host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
-       host->update_config_rom = 1;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
-
-static struct hpsb_config_rom_entry ip1394_entry = {
-       .name           = "ip1394",
-       .init           = config_rom_ip1394_init,
-       .cleanup        = config_rom_ip1394_cleanup,
-       .flag           = HPSB_CONFIG_ROM_ENTRY_IP1394,
-};
-
-#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
-
-static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-       &ip1394_entry,
-#endif
-};
-
-/* Initialize all config roms */
-int hpsb_init_config_roms(void)
-{
-       int i, error = 0;
-
-       for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
-               if (config_rom_entries[i]->init()) {
-                       HPSB_ERR("Failed to initialize config rom entry `%s'",
-                                config_rom_entries[i]->name);
-                       error = -1;
-               }
-
-       return error;
-}
-
-/* Cleanup all config roms */
-void hpsb_cleanup_config_roms(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
-               config_rom_entries[i]->cleanup();
-}
diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h
deleted file mode 100644 (file)
index 1f5cd1f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_CONFIG_ROMS_H
-#define _IEEE1394_CONFIG_ROMS_H
-
-struct hpsb_host;
-
-int hpsb_default_host_entry(struct hpsb_host *host);
-int hpsb_init_config_roms(void);
-void hpsb_cleanup_config_roms(void);
-
-/* List of flags to check if a host contains a certain extra config rom
- * entry. Available in the host->config_roms member. */
-#define HPSB_CONFIG_ROM_ENTRY_IP1394           0x00000001
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
-#endif
-
-#endif /* _IEEE1394_CONFIG_ROMS_H */
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
deleted file mode 100644 (file)
index d696f69..0000000
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * CSR implementation, iso/bus manager implementation.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        configuration ROM manipulation
- *
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/param.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "highlevel.h"
-#include "ieee1394_core.h"
-
-/* Module Parameters */
-/* this module parameter can be used to disable mapping of the FCP registers */
-
-static int fcp = 1;
-module_param(fcp, int, 0444);
-MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
-
-static struct csr1212_keyval *node_cap = NULL;
-
-static void add_host(struct hpsb_host *host);
-static void remove_host(struct hpsb_host *host);
-static void host_reset(struct hpsb_host *host);
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                    u64 addr, size_t length, u16 fl);
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-                    quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                    u64 addr, size_t length, u16 flags);
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-                     quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
-                      u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                          u64 addr, size_t length, u16 fl);
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
-static void release_addr_range(u64 addr, void *__host);
-
-static struct hpsb_highlevel csr_highlevel = {
-       .name =         "standard registers",
-       .add_host =     add_host,
-       .remove_host =  remove_host,
-       .host_reset =   host_reset,
-};
-
-static const struct hpsb_address_ops map_ops = {
-       .read = read_maps,
-};
-
-static const struct hpsb_address_ops fcp_ops = {
-       .write = write_fcp,
-};
-
-static const struct hpsb_address_ops reg_ops = {
-       .read = read_regs,
-       .write = write_regs,
-       .lock = lock_regs,
-       .lock64 = lock64_regs,
-};
-
-static const struct hpsb_address_ops config_rom_ops = {
-       .read = read_config_rom,
-};
-
-struct csr1212_bus_ops csr_bus_ops = {
-       .allocate_addr_range =  allocate_addr_range,
-       .release_addr =         release_addr_range,
-};
-
-
-static u16 csr_crc16(unsigned *data, int length)
-{
-        int check=0, i;
-        int shift, sum, next=0;
-
-        for (i = length; i; i--) {
-                for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
-                        next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-                }
-                check = next & 0xffff;
-                data++;
-        }
-
-        return check;
-}
-
-static void host_reset(struct hpsb_host *host)
-{
-        host->csr.state &= 0x300;
-
-        host->csr.bus_manager_id = 0x3f;
-        host->csr.bandwidth_available = 4915;
-       host->csr.channels_available_hi = 0xfffffffe;   /* pre-alloc ch 31 per 1394a-2000 */
-        host->csr.channels_available_lo = ~0;
-       host->csr.broadcast_channel = 0x80000000 | 31;
-
-       if (host->is_irm) {
-               if (host->driver->hw_csr_reg) {
-                       host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
-               }
-       }
-
-        host->csr.node_ids = host->node_id << 16;
-
-        if (!host->is_root) {
-                /* clear cmstr bit */
-                host->csr.state &= ~0x100;
-        }
-
-       be32_add_cpu(&host->csr.topology_map[1], 1);
-        host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
-                                                | host->selfid_count);
-        host->csr.topology_map[0] =
-                cpu_to_be32((host->selfid_count + 2) << 16
-                            | csr_crc16(host->csr.topology_map + 1,
-                                        host->selfid_count + 2));
-
-       be32_add_cpu(&host->csr.speed_map[1], 1);
-        host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
-                                             | csr_crc16(host->csr.speed_map+1,
-                                                         0x3f1));
-}
-
-/*
- * HI == seconds (bits 0:2)
- * LO == fractions of a second in units of 125usec (bits 19:31)
- *
- * Convert SPLIT_TIMEOUT to jiffies.
- * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
- */
-static inline void calculate_expire(struct csr_control *csr)
-{
-       unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
-                            (csr->split_timeout_lo >> 19) * 125;
-
-       csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
-       HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
-}
-
-
-static void add_host(struct hpsb_host *host)
-{
-       struct csr1212_keyval *root;
-       quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
-       hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
-                               CSR_REGISTER_BASE,
-                               CSR_REGISTER_BASE + CSR_CONFIG_ROM);
-       hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
-                               CSR_REGISTER_BASE + CSR_CONFIG_ROM,
-                               CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-       if (fcp) {
-               hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
-                                       CSR_REGISTER_BASE + CSR_FCP_COMMAND,
-                                       CSR_REGISTER_BASE + CSR_FCP_END);
-       }
-       hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
-                               CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
-                               CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
-       hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
-                               CSR_REGISTER_BASE + CSR_SPEED_MAP,
-                               CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
-
-        spin_lock_init(&host->csr.lock);
-
-        host->csr.state                 = 0;
-        host->csr.node_ids              = 0;
-        host->csr.split_timeout_hi      = 0;
-        host->csr.split_timeout_lo      = 800 << 19;
-       calculate_expire(&host->csr);
-        host->csr.cycle_time            = 0;
-        host->csr.bus_time              = 0;
-        host->csr.bus_manager_id        = 0x3f;
-        host->csr.bandwidth_available   = 4915;
-       host->csr.channels_available_hi = 0xfffffffe;   /* pre-alloc ch 31 per 1394a-2000 */
-        host->csr.channels_available_lo = ~0;
-       host->csr.broadcast_channel = 0x80000000 | 31;
-
-       if (host->is_irm) {
-               if (host->driver->hw_csr_reg) {
-                       host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
-               }
-       }
-
-       if (host->csr.max_rec >= 9)
-               host->csr.max_rom = 2;
-       else if (host->csr.max_rec >= 5)
-               host->csr.max_rom = 1;
-       else
-               host->csr.max_rom = 0;
-
-       host->csr.generation = 2;
-
-       bus_info[1] = IEEE1394_BUSID_MAGIC;
-       bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
-                                 (1 << CSR_CMC_SHIFT) |
-                                 (1 << CSR_ISC_SHIFT) |
-                                 (0 << CSR_BMC_SHIFT) |
-                                 (0 << CSR_PMC_SHIFT) |
-                                 (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
-                                 (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
-                                 (host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
-                                 (host->csr.generation << CSR_GENERATION_SHIFT) |
-                                 host->csr.lnk_spd);
-
-       bus_info[3] = cpu_to_be32(host->csr.guid_hi);
-       bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
-       /* The hardware copy of the bus info block will be set later when a
-        * bus reset is issued. */
-
-       csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
-
-       root = host->csr.rom->root_kv;
-
-       if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
-               HPSB_ERR("Failed to attach Node Capabilities to root directory");
-       }
-
-       host->update_config_rom = 1;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
-       quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
-       bus_info[1] = IEEE1394_BUSID_MAGIC;
-       bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
-                                 (0 << CSR_CMC_SHIFT) |
-                                 (0 << CSR_ISC_SHIFT) |
-                                 (0 << CSR_BMC_SHIFT) |
-                                 (0 << CSR_PMC_SHIFT) |
-                                 (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
-                                 (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
-                                 (0 << CSR_MAX_ROM_SHIFT) |
-                                 (0 << CSR_GENERATION_SHIFT) |
-                                 host->csr.lnk_spd);
-
-       bus_info[3] = cpu_to_be32(host->csr.guid_hi);
-       bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
-       csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
-
-       csr1212_init_local_csr(host->csr.rom, bus_info, 0);
-       host->update_config_rom = 1;
-}
-
-
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
-       size_t buffersize, unsigned char rom_version)
-{
-       unsigned long flags;
-       int ret;
-
-       HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-       if (rom_version != host->csr.generation)
-                ret = -1;
-       else if (buffersize > host->csr.rom->cache_head->size)
-               ret = -2;
-        else {
-               /* Just overwrite the generated ConfigROM image with new data,
-                * it can be regenerated later. */
-               memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
-               host->csr.rom->cache_head->len = buffersize;
-
-               if (host->driver->set_hw_config_rom)
-                       host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
-               /* Increment the generation number to keep some sort of sync
-                * with the newer ConfigROM manipulation method. */
-               host->csr.generation++;
-               if (host->csr.generation > 0xf || host->csr.generation < 2)
-                       host->csr.generation = 2;
-               ret=0;
-        }
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-        return ret;
-}
-
-
-/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, size_t length, u16 fl)
-{
-       unsigned long flags;
-        int csraddr = addr - CSR_REGISTER_BASE;
-        const char *src;
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-
-       if (csraddr < CSR_SPEED_MAP) {
-                src = ((char *)host->csr.topology_map) + csraddr
-                        - CSR_TOPOLOGY_MAP;
-        } else {
-                src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
-        }
-
-        memcpy(buffer, src, length);
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-        return RCODE_COMPLETE;
-}
-
-
-#define out if (--length == 0) break
-
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-        int oldcycle;
-        quadlet_t ret;
-
-        if ((csraddr | length) & 0x3)
-                return RCODE_TYPE_ERROR;
-
-        length /= 4;
-
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-                *(buf++) = cpu_to_be32(host->csr.state);
-                out;
-        case CSR_STATE_SET:
-                *(buf++) = cpu_to_be32(host->csr.state);
-                out;
-        case CSR_NODE_IDS:
-                *(buf++) = cpu_to_be32(host->csr.node_ids);
-                out;
-
-        case CSR_RESET_START:
-                return RCODE_TYPE_ERROR;
-
-                /* address gap - handled by default below */
-
-        case CSR_SPLIT_TIMEOUT_HI:
-                *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
-                out;
-        case CSR_SPLIT_TIMEOUT_LO:
-                *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_CYCLE_TIME:
-                oldcycle = host->csr.cycle_time;
-                host->csr.cycle_time =
-                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
-                if (oldcycle > host->csr.cycle_time) {
-                        /* cycle time wrapped around */
-                        host->csr.bus_time += 1 << 7;
-                }
-                *(buf++) = cpu_to_be32(host->csr.cycle_time);
-                out;
-        case CSR_BUS_TIME:
-                oldcycle = host->csr.cycle_time;
-                host->csr.cycle_time =
-                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
-                if (oldcycle > host->csr.cycle_time) {
-                        /* cycle time wrapped around */
-                        host->csr.bus_time += (1 << 7);
-                }
-                *(buf++) = cpu_to_be32(host->csr.bus_time
-                                       | (host->csr.cycle_time >> 25));
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUS_MANAGER_ID:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 0, 0, 0);
-                else
-                        ret = host->csr.bus_manager_id;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_BANDWIDTH_AVAILABLE:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 1, 0, 0);
-                else
-                        ret = host->csr.bandwidth_available;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_CHANNELS_AVAILABLE_HI:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 2, 0, 0);
-                else
-                        ret = host->csr.channels_available_hi;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_CHANNELS_AVAILABLE_LO:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 3, 0, 0);
-                else
-                        ret = host->csr.channels_available_lo;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-
-       case CSR_BROADCAST_CHANNEL:
-               *(buf++) = cpu_to_be32(host->csr.broadcast_channel);
-               out;
-
-                /* address gap to end - fall through to default */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-                     quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-
-        if ((csraddr | length) & 0x3)
-                return RCODE_TYPE_ERROR;
-
-        length /= 4;
-
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-                /* FIXME FIXME FIXME */
-                printk("doh, someone wants to mess with state clear\n");
-                out;
-        case CSR_STATE_SET:
-                printk("doh, someone wants to mess with state set\n");
-                out;
-
-        case CSR_NODE_IDS:
-                host->csr.node_ids &= NODE_MASK << 16;
-                host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
-                host->node_id = host->csr.node_ids >> 16;
-                host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
-                out;
-
-        case CSR_RESET_START:
-                /* FIXME - perform command reset */
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_SPLIT_TIMEOUT_HI:
-                host->csr.split_timeout_hi =
-                        be32_to_cpu(*(data++)) & 0x00000007;
-               calculate_expire(&host->csr);
-                out;
-        case CSR_SPLIT_TIMEOUT_LO:
-                host->csr.split_timeout_lo =
-                        be32_to_cpu(*(data++)) & 0xfff80000;
-               calculate_expire(&host->csr);
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_CYCLE_TIME:
-                /* should only be set by cycle start packet, automatically */
-                host->csr.cycle_time = be32_to_cpu(*data);
-                host->driver->devctl(host, SET_CYCLE_COUNTER,
-                                       be32_to_cpu(*(data++)));
-                out;
-        case CSR_BUS_TIME:
-                host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUS_MANAGER_ID:
-        case CSR_BANDWIDTH_AVAILABLE:
-        case CSR_CHANNELS_AVAILABLE_HI:
-        case CSR_CHANNELS_AVAILABLE_LO:
-                /* these are not writable, only lockable */
-                return RCODE_TYPE_ERROR;
-
-       case CSR_BROADCAST_CHANNEL:
-               /* only the valid bit can be written */
-               host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
-                        | (be32_to_cpu(*data) & 0x40000000);
-               out;
-
-                /* address gap to end - fall through */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-#undef out
-
-
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-        unsigned long flags;
-        quadlet_t *regptr = NULL;
-
-        if (csraddr & 0x3)
-               return RCODE_TYPE_ERROR;
-
-        if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
-            || extcode != EXTCODE_COMPARE_SWAP)
-                goto unsupported_lockreq;
-
-        data = be32_to_cpu(data);
-        arg = be32_to_cpu(arg);
-
-       /* Is somebody releasing the broadcast_channel on us? */
-       if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
-               /* Note: this is may not be the right way to handle
-                * the problem, so we should look into the proper way
-                * eventually. */
-               HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
-                         "broadcast channel 31.  Ignoring.",
-                         NODE_BUS_ARGS(host, nodeid));
-
-               data &= ~0x1;   /* keep broadcast channel allocated */
-       }
-
-        if (host->driver->hw_csr_reg) {
-                quadlet_t old;
-
-                old = host->driver->
-                        hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
-                                   data, arg);
-
-                *store = cpu_to_be32(old);
-                return RCODE_COMPLETE;
-        }
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-
-        switch (csraddr) {
-        case CSR_BUS_MANAGER_ID:
-                regptr = &host->csr.bus_manager_id;
-               *store = cpu_to_be32(*regptr);
-               if (*regptr == arg)
-                       *regptr = data;
-                break;
-
-        case CSR_BANDWIDTH_AVAILABLE:
-        {
-                quadlet_t bandwidth;
-                quadlet_t old;
-                quadlet_t new;
-
-                regptr = &host->csr.bandwidth_available;
-                old = *regptr;
-
-                /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
-                if (arg > 0x1fff) {
-                        *store = cpu_to_be32(old);     /* change nothing */
-                       break;
-                }
-                data &= 0x1fff;
-                if (arg >= data) {
-                        /* allocate bandwidth */
-                        bandwidth = arg - data;
-                        if (old >= bandwidth) {
-                                new = old - bandwidth;
-                                *store = cpu_to_be32(arg);
-                                *regptr = new;
-                        } else {
-                                *store = cpu_to_be32(old);
-                        }
-                } else {
-                        /* deallocate bandwidth */
-                        bandwidth = data - arg;
-                        if (old + bandwidth < 0x2000) {
-                                new = old + bandwidth;
-                                *store = cpu_to_be32(arg);
-                                *regptr = new;
-                        } else {
-                                *store = cpu_to_be32(old);
-                        }
-                }
-                break;
-        }
-
-        case CSR_CHANNELS_AVAILABLE_HI:
-        {
-                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
-                quadlet_t affected_channels = arg ^ data;
-
-                regptr = &host->csr.channels_available_hi;
-
-                if ((arg & affected_channels) == (*regptr & affected_channels)) {
-                        *regptr ^= affected_channels;
-                        *store = cpu_to_be32(arg);
-                } else {
-                        *store = cpu_to_be32(*regptr);
-                }
-
-                break;
-        }
-
-        case CSR_CHANNELS_AVAILABLE_LO:
-        {
-                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
-                quadlet_t affected_channels = arg ^ data;
-
-                regptr = &host->csr.channels_available_lo;
-
-                if ((arg & affected_channels) == (*regptr & affected_channels)) {
-                        *regptr ^= affected_channels;
-                        *store = cpu_to_be32(arg);
-                } else {
-                        *store = cpu_to_be32(*regptr);
-                }
-                break;
-        }
-        }
-
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-
-        return RCODE_COMPLETE;
-
- unsupported_lockreq:
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-        case CSR_STATE_SET:
-        case CSR_RESET_START:
-        case CSR_NODE_IDS:
-        case CSR_SPLIT_TIMEOUT_HI:
-        case CSR_SPLIT_TIMEOUT_LO:
-        case CSR_CYCLE_TIME:
-        case CSR_BUS_TIME:
-       case CSR_BROADCAST_CHANNEL:
-                return RCODE_TYPE_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented - fall through */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-}
-
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
-                      u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
-{
-       int csraddr = addr - CSR_REGISTER_BASE;
-       unsigned long flags;
-
-       data = be64_to_cpu(data);
-       arg = be64_to_cpu(arg);
-
-       if (csraddr & 0x3)
-               return RCODE_TYPE_ERROR;
-
-       if (csraddr != CSR_CHANNELS_AVAILABLE
-           || extcode != EXTCODE_COMPARE_SWAP)
-               goto unsupported_lock64req;
-
-       /* Is somebody releasing the broadcast_channel on us? */
-       if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
-               /* Note: this is may not be the right way to handle
-                * the problem, so we should look into the proper way
-                 * eventually. */
-               HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
-                         "broadcast channel 31.  Ignoring.",
-                         NODE_BUS_ARGS(host, nodeid));
-
-               data &= ~0x100000000ULL;        /* keep broadcast channel allocated */
-       }
-
-       if (host->driver->hw_csr_reg) {
-               quadlet_t data_hi, data_lo;
-               quadlet_t arg_hi, arg_lo;
-               quadlet_t old_hi, old_lo;
-
-               data_hi = data >> 32;
-               data_lo = data & 0xFFFFFFFF;
-               arg_hi = arg >> 32;
-               arg_lo = arg & 0xFFFFFFFF;
-
-               old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
-                                                  data_hi, arg_hi);
-
-               old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
-                                                  data_lo, arg_lo);
-
-               *store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
-       } else {
-               octlet_t old;
-               octlet_t affected_channels = arg ^ data;
-
-               spin_lock_irqsave(&host->csr.lock, flags);
-
-               old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
-
-               if ((arg & affected_channels) == (old & affected_channels)) {
-                       host->csr.channels_available_hi ^= (affected_channels >> 32);
-                       host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
-                       *store = cpu_to_be64(arg);
-               } else {
-                       *store = cpu_to_be64(old);
-               }
-
-               spin_unlock_irqrestore(&host->csr.lock, flags);
-       }
-
-       /* Is somebody erroneously releasing the broadcast_channel on us? */
-       if (host->csr.channels_available_hi & 0x1)
-               host->csr.channels_available_hi &= ~0x1;
-
-       return RCODE_COMPLETE;
-
- unsupported_lock64req:
-       switch (csraddr) {
-       case CSR_STATE_CLEAR:
-       case CSR_STATE_SET:
-       case CSR_RESET_START:
-       case CSR_NODE_IDS:
-       case CSR_SPLIT_TIMEOUT_HI:
-       case CSR_SPLIT_TIMEOUT_LO:
-       case CSR_CYCLE_TIME:
-       case CSR_BUS_TIME:
-       case CSR_BUS_MANAGER_ID:
-       case CSR_BROADCAST_CHANNEL:
-       case CSR_BUSY_TIMEOUT:
-       case CSR_BANDWIDTH_AVAILABLE:
-               return RCODE_TYPE_ERROR;
-
-       default:
-               return RCODE_ADDRESS_ERROR;
-       }
-}
-
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-                    quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-
-        if (length > 512)
-                return RCODE_TYPE_ERROR;
-
-        switch (csraddr) {
-        case CSR_FCP_COMMAND:
-                highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
-                break;
-        case CSR_FCP_RESPONSE:
-                highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
-                break;
-        default:
-                return RCODE_TYPE_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                          u64 addr, size_t length, u16 fl)
-{
-       u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
-
-       if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
-               return RCODE_COMPLETE;
-       else
-               return RCODE_ADDRESS_ERROR;
-}
-
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
-{
-       struct hpsb_host *host = (struct hpsb_host*)__host;
-
-       return hpsb_allocate_and_register_addrspace(&csr_highlevel,
-                                                   host,
-                                                   &config_rom_ops,
-                                                   size, alignment,
-                                                   CSR1212_UNITS_SPACE_BASE,
-                                                   CSR1212_UNITS_SPACE_END);
-}
-
-static void release_addr_range(u64 addr, void *__host)
-{
-       struct hpsb_host *host = (struct hpsb_host*)__host;
-       hpsb_unregister_addrspace(&csr_highlevel, host, addr);
-}
-
-
-int init_csr(void)
-{
-       node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
-       if (!node_cap) {
-               HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
-               return -ENOMEM;
-       }
-
-       hpsb_register_highlevel(&csr_highlevel);
-
-       return 0;
-}
-
-void cleanup_csr(void)
-{
-       if (node_cap)
-               csr1212_release_keyval(node_cap);
-        hpsb_unregister_highlevel(&csr_highlevel);
-}
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
deleted file mode 100644 (file)
index 90fb3f2..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef _IEEE1394_CSR_H
-#define _IEEE1394_CSR_H
-
-#include <linux/spinlock_types.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-
-#define CSR_REGISTER_BASE              0xfffff0000000ULL
-
-/* register offsets relative to CSR_REGISTER_BASE */
-#define CSR_STATE_CLEAR                        0x0
-#define CSR_STATE_SET                  0x4
-#define CSR_NODE_IDS                   0x8
-#define CSR_RESET_START                        0xc
-#define CSR_SPLIT_TIMEOUT_HI           0x18
-#define CSR_SPLIT_TIMEOUT_LO           0x1c
-#define CSR_CYCLE_TIME                 0x200
-#define CSR_BUS_TIME                   0x204
-#define CSR_BUSY_TIMEOUT               0x210
-#define CSR_BUS_MANAGER_ID             0x21c
-#define CSR_BANDWIDTH_AVAILABLE                0x220
-#define CSR_CHANNELS_AVAILABLE         0x224
-#define CSR_CHANNELS_AVAILABLE_HI      0x224
-#define CSR_CHANNELS_AVAILABLE_LO      0x228
-#define CSR_BROADCAST_CHANNEL          0x234
-#define CSR_CONFIG_ROM                 0x400
-#define CSR_CONFIG_ROM_END             0x800
-#define CSR_FCP_COMMAND                        0xB00
-#define CSR_FCP_RESPONSE               0xD00
-#define CSR_FCP_END                    0xF00
-#define CSR_TOPOLOGY_MAP               0x1000
-#define CSR_TOPOLOGY_MAP_END           0x1400
-#define CSR_SPEED_MAP                  0x2000
-#define CSR_SPEED_MAP_END              0x3000
-
-/* IEEE 1394 bus specific Configuration ROM Key IDs */
-#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
-
-/* IEEE 1394 Bus Information Block specifics */
-#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
-
-#define CSR_IRMC_SHIFT                 31
-#define CSR_CMC_SHIFT                  30
-#define CSR_ISC_SHIFT                  29
-#define CSR_BMC_SHIFT                  28
-#define CSR_PMC_SHIFT                  27
-#define CSR_CYC_CLK_ACC_SHIFT          16
-#define CSR_MAX_REC_SHIFT              12
-#define CSR_MAX_ROM_SHIFT              8
-#define CSR_GENERATION_SHIFT           4
-
-static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
-{
-       csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
-       csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
-}
-
-struct csr_control {
-       spinlock_t lock;
-
-       quadlet_t state;
-       quadlet_t node_ids;
-       quadlet_t split_timeout_hi, split_timeout_lo;
-       unsigned long expire;   /* Calculated from split_timeout */
-       quadlet_t cycle_time;
-       quadlet_t bus_time;
-       quadlet_t bus_manager_id;
-       quadlet_t bandwidth_available;
-       quadlet_t channels_available_hi, channels_available_lo;
-       quadlet_t broadcast_channel;
-
-       /* Bus Info */
-       quadlet_t guid_hi, guid_lo;
-       u8 cyc_clk_acc;
-       u8 max_rec;
-       u8 max_rom;
-       u8 generation;  /* Only use values between 0x2 and 0xf */
-       u8 lnk_spd;
-
-       unsigned long gen_timestamp[16];
-
-       struct csr1212_csr *rom;
-
-       quadlet_t topology_map[256];
-       quadlet_t speed_map[1024];
-};
-
-extern struct csr1212_bus_ops csr_bus_ops;
-
-int init_csr(void);
-void cleanup_csr(void);
-
-/* hpsb_update_config_rom() is deprecated */
-struct hpsb_host;
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
-                          size_t size, unsigned char rom_version);
-
-#endif /* _IEEE1394_CSR_H */
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
deleted file mode 100644 (file)
index e76cac6..0000000
+++ /dev/null
@@ -1,1467 +0,0 @@
-/*
- * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *    2. Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *    3. The name of the author may not be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* TODO List:
- * - Verify interface consistency: i.e., public functions that take a size
- *   parameter expect size to be in bytes.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/string.h>
-#include <asm/bug.h>
-#include <asm/byteorder.h>
-
-#include "csr1212.h"
-
-
-/* Permitted key type for each key id */
-#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
-#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
-#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
-#define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u8 csr1212_key_id_type_map[0x30] = {
-       __C,                    /* used by Apple iSight */
-       __D | __L,              /* Descriptor */
-       __I | __D | __L,        /* Bus_Dependent_Info */
-       __I | __D | __L,        /* Vendor */
-       __I,                    /* Hardware_Version */
-       0, 0,                   /* Reserved */
-       __D | __L | __I,        /* Module */
-       __I, 0, 0, 0,           /* used by Apple iSight, Reserved */
-       __I,                    /* Node_Capabilities */
-       __L,                    /* EUI_64 */
-       0, 0, 0,                /* Reserved */
-       __D,                    /* Unit */
-       __I,                    /* Specifier_ID */
-       __I,                    /* Version */
-       __I | __C | __D | __L,  /* Dependent_Info */
-       __L,                    /* Unit_Location */
-       0,                      /* Reserved */
-       __I,                    /* Model */
-       __D,                    /* Instance */
-       __L,                    /* Keyword */
-       __D,                    /* Feature */
-       __L,                    /* Extended_ROM */
-       __I,                    /* Extended_Key_Specifier_ID */
-       __I,                    /* Extended_Key */
-       __I | __C | __D | __L,  /* Extended_Data */
-       __L,                    /* Modifiable_Descriptor */
-       __I,                    /* Directory_ID */
-       __I,                    /* Revision */
-};
-#undef __I
-#undef __C
-#undef __D
-#undef __L
-
-
-#define quads_to_bytes(_q) ((_q) * sizeof(u32))
-#define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32))
-
-static void free_keyval(struct csr1212_keyval *kv)
-{
-       if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
-           (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
-               CSR1212_FREE(kv->value.leaf.data);
-
-       CSR1212_FREE(kv);
-}
-
-static u16 csr1212_crc16(const u32 *buffer, size_t length)
-{
-       int shift;
-       u32 data;
-       u16 sum, crc = 0;
-
-       for (; length; length--) {
-               data = be32_to_cpu(*buffer);
-               buffer++;
-               for (shift = 28; shift >= 0; shift -= 4 ) {
-                       sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
-                       crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-               }
-               crc &= 0xffff;
-       }
-
-       return cpu_to_be16(crc);
-}
-
-/* Microsoft computes the CRC with the bytes in reverse order. */
-static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
-{
-       int shift;
-       u32 data;
-       u16 sum, crc = 0;
-
-       for (; length; length--) {
-               data = le32_to_cpu(*buffer);
-               buffer++;
-               for (shift = 28; shift >= 0; shift -= 4 ) {
-                       sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
-                       crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-               }
-               crc &= 0xffff;
-       }
-
-       return cpu_to_be16(crc);
-}
-
-static struct csr1212_dentry *
-csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
-{
-       struct csr1212_dentry *pos;
-
-       for (pos = dir->value.directory.dentries_head;
-            pos != NULL; pos = pos->next)
-               if (pos->kv == kv)
-                       return pos;
-       return NULL;
-}
-
-static struct csr1212_keyval *
-csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
-{
-       struct csr1212_keyval *kv;
-
-       for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
-               if (kv->offset == offset)
-                       return kv;
-       return NULL;
-}
-
-
-/* Creation Routines */
-
-struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
-                                      size_t bus_info_size, void *private)
-{
-       struct csr1212_csr *csr;
-
-       csr = CSR1212_MALLOC(sizeof(*csr));
-       if (!csr)
-               return NULL;
-
-       csr->cache_head =
-               csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
-                                        CSR1212_CONFIG_ROM_SPACE_SIZE);
-       if (!csr->cache_head) {
-               CSR1212_FREE(csr);
-               return NULL;
-       }
-
-       /* The keyval key id is not used for the root node, but a valid key id
-        * that can be used for a directory needs to be passed to
-        * csr1212_new_directory(). */
-       csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
-       if (!csr->root_kv) {
-               CSR1212_FREE(csr->cache_head);
-               CSR1212_FREE(csr);
-               return NULL;
-       }
-
-       csr->bus_info_data = csr->cache_head->data;
-       csr->bus_info_len = bus_info_size;
-       csr->crc_len = bus_info_size;
-       csr->ops = ops;
-       csr->private = private;
-       csr->cache_tail = csr->cache_head;
-
-       return csr;
-}
-
-void csr1212_init_local_csr(struct csr1212_csr *csr,
-                           const u32 *bus_info_data, int max_rom)
-{
-       static const int mr_map[] = { 4, 64, 1024, 0 };
-
-       BUG_ON(max_rom & ~0x3);
-       csr->max_rom = mr_map[max_rom];
-       memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
-}
-
-static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
-{
-       struct csr1212_keyval *kv;
-
-       if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
-               return NULL;
-
-       kv = CSR1212_MALLOC(sizeof(*kv));
-       if (!kv)
-               return NULL;
-
-       atomic_set(&kv->refcnt, 1);
-       kv->key.type = type;
-       kv->key.id = key;
-       kv->associate = NULL;
-       kv->next = NULL;
-       kv->prev = NULL;
-       kv->offset = 0;
-       kv->valid = 0;
-       return kv;
-}
-
-struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
-{
-       struct csr1212_keyval *kv;
-
-       kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
-       if (!kv)
-               return NULL;
-
-       kv->value.immediate = value;
-       kv->valid = 1;
-       return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_leaf(u8 key, const void *data, size_t data_len)
-{
-       struct csr1212_keyval *kv;
-
-       kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
-       if (!kv)
-               return NULL;
-
-       if (data_len > 0) {
-               kv->value.leaf.data = CSR1212_MALLOC(data_len);
-               if (!kv->value.leaf.data) {
-                       CSR1212_FREE(kv);
-                       return NULL;
-               }
-
-               if (data)
-                       memcpy(kv->value.leaf.data, data, data_len);
-       } else {
-               kv->value.leaf.data = NULL;
-       }
-
-       kv->value.leaf.len = bytes_to_quads(data_len);
-       kv->offset = 0;
-       kv->valid = 1;
-
-       return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_csr_offset(u8 key, u32 csr_offset)
-{
-       struct csr1212_keyval *kv;
-
-       kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
-       if (!kv)
-               return NULL;
-
-       kv->value.csr_offset = csr_offset;
-
-       kv->offset = 0;
-       kv->valid = 1;
-       return kv;
-}
-
-struct csr1212_keyval *csr1212_new_directory(u8 key)
-{
-       struct csr1212_keyval *kv;
-
-       kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
-       if (!kv)
-               return NULL;
-
-       kv->value.directory.len = 0;
-       kv->offset = 0;
-       kv->value.directory.dentries_head = NULL;
-       kv->value.directory.dentries_tail = NULL;
-       kv->valid = 1;
-       return kv;
-}
-
-void csr1212_associate_keyval(struct csr1212_keyval *kv,
-                             struct csr1212_keyval *associate)
-{
-       BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
-              (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
-               associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
-               associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
-               associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
-               associate->key.id < 0x30) ||
-              (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
-               associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
-              (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-               associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
-              (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-               kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
-              (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
-               kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
-
-       if (kv->associate)
-               csr1212_release_keyval(kv->associate);
-
-       csr1212_keep_keyval(associate);
-       kv->associate = associate;
-}
-
-static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-                                               struct csr1212_keyval *kv,
-                                               bool keep_keyval)
-{
-       struct csr1212_dentry *dentry;
-
-       BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
-
-       dentry = CSR1212_MALLOC(sizeof(*dentry));
-       if (!dentry)
-               return -ENOMEM;
-
-       if (keep_keyval)
-               csr1212_keep_keyval(kv);
-       dentry->kv = kv;
-
-       dentry->next = NULL;
-       dentry->prev = dir->value.directory.dentries_tail;
-
-       if (!dir->value.directory.dentries_head)
-               dir->value.directory.dentries_head = dentry;
-
-       if (dir->value.directory.dentries_tail)
-               dir->value.directory.dentries_tail->next = dentry;
-       dir->value.directory.dentries_tail = dentry;
-
-       return CSR1212_SUCCESS;
-}
-
-int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-                                      struct csr1212_keyval *kv)
-{
-       return __csr1212_attach_keyval_to_directory(dir, kv, true);
-}
-
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
-       (&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
-       ((kv)->value.leaf.data[0] = \
-        cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
-                    ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
-       ((kv)->value.leaf.data[0] = \
-        cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
-                     CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
-                    ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
-
-static struct csr1212_keyval *
-csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
-                           const void *data, size_t data_len)
-{
-       struct csr1212_keyval *kv;
-
-       kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
-                             data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
-       if (!kv)
-               return NULL;
-
-       kmemcheck_annotate_variable(kv->value.leaf.data[0]);
-       CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
-       CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
-
-       if (data)
-               memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
-
-       return kv;
-}
-
-/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
-static int csr1212_check_minimal_ascii(const char *s)
-{
-       static const char minimal_ascii_table[] = {
-                                       /*  1   2   4   8  16  32  64  128 */
-               128,                    /* --, --, --, --, --, --, --, 07, */
-               4 + 16 + 32,            /* --, --, 0a, --, 0C, 0D, --, --, */
-               0,                      /* --, --, --, --, --, --, --, --, */
-               0,                      /* --, --, --, --, --, --, --, --, */
-               255 - 8 - 16,           /* 20, 21, 22, --, --, 25, 26, 27, */
-               255,                    /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
-               255,                    /* 30, 31, 32, 33, 34, 35, 36, 37, */
-               255,                    /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
-               255,                    /* 40, 41, 42, 43, 44, 45, 46, 47, */
-               255,                    /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
-               255,                    /* 50, 51, 52, 53, 54, 55, 56, 57, */
-               1 + 2 + 4 + 128,        /* 58, 59, 5a, --, --, --, --, 5f, */
-               255 - 1,                /* --, 61, 62, 63, 64, 65, 66, 67, */
-               255,                    /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
-               255,                    /* 70, 71, 72, 73, 74, 75, 76, 77, */
-               1 + 2 + 4,              /* 78, 79, 7a, --, --, --, --, --, */
-       };
-       int i, j;
-
-       for (; *s; s++) {
-               i = *s >> 3;            /*  i = *s / 8;         */
-               j = 1 << (*s & 3);      /*  j = 1 << (*s % 8);  */
-
-               if (i >= ARRAY_SIZE(minimal_ascii_table) ||
-                   !(minimal_ascii_table[i] & j))
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
-struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
-{
-       struct csr1212_keyval *kv;
-       u32 *text;
-       size_t str_len, quads;
-
-       if (!s || !*s || csr1212_check_minimal_ascii(s))
-               return NULL;
-
-       str_len = strlen(s);
-       quads = bytes_to_quads(str_len);
-       kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
-                                     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
-       if (!kv)
-               return NULL;
-
-       kv->value.leaf.data[1] = 0;     /* width, character_set, language */
-       text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
-       text[quads - 1] = 0;            /* padding */
-       memcpy(text, s, str_len);
-
-       return kv;
-}
-
-
-/* Destruction Routines */
-
-void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
-                                         struct csr1212_keyval *kv)
-{
-       struct csr1212_dentry *dentry;
-
-       if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
-               return;
-
-       dentry = csr1212_find_keyval(dir, kv);
-
-       if (!dentry)
-               return;
-
-       if (dentry->prev)
-               dentry->prev->next = dentry->next;
-       if (dentry->next)
-               dentry->next->prev = dentry->prev;
-       if (dir->value.directory.dentries_head == dentry)
-               dir->value.directory.dentries_head = dentry->next;
-       if (dir->value.directory.dentries_tail == dentry)
-               dir->value.directory.dentries_tail = dentry->prev;
-
-       CSR1212_FREE(dentry);
-
-       csr1212_release_keyval(kv);
-}
-
-/* This function is used to free the memory taken by a keyval.  If the given
- * keyval is a directory type, then any keyvals contained in that directory
- * will be destroyed as well if noone holds a reference on them.  By means of
- * list manipulation, this routine will descend a directory structure in a
- * non-recursive manner. */
-void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
-       struct csr1212_keyval *k, *a;
-       struct csr1212_dentry dentry;
-       struct csr1212_dentry *head, *tail;
-
-       if (!atomic_dec_and_test(&kv->refcnt))
-               return;
-
-       dentry.kv = kv;
-       dentry.next = NULL;
-       dentry.prev = NULL;
-
-       head = &dentry;
-       tail = head;
-
-       while (head) {
-               k = head->kv;
-
-               while (k) {
-                       /* must not dec_and_test kv->refcnt again */
-                       if (k != kv && !atomic_dec_and_test(&k->refcnt))
-                               break;
-
-                       a = k->associate;
-
-                       if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
-                               /* If the current entry is a directory, move all
-                                * the entries to the destruction list. */
-                               if (k->value.directory.dentries_head) {
-                                       tail->next =
-                                           k->value.directory.dentries_head;
-                                       k->value.directory.dentries_head->prev =
-                                           tail;
-                                       tail = k->value.directory.dentries_tail;
-                               }
-                       }
-                       free_keyval(k);
-                       k = a;
-               }
-
-               head = head->next;
-               if (head) {
-                       if (head->prev && head->prev != &dentry)
-                               CSR1212_FREE(head->prev);
-                       head->prev = NULL;
-               } else if (tail != &dentry) {
-                       CSR1212_FREE(tail);
-               }
-       }
-}
-
-void csr1212_destroy_csr(struct csr1212_csr *csr)
-{
-       struct csr1212_csr_rom_cache *c, *oc;
-       struct csr1212_cache_region *cr, *ocr;
-
-       csr1212_release_keyval(csr->root_kv);
-
-       c = csr->cache_head;
-       while (c) {
-               oc = c;
-               cr = c->filled_head;
-               while (cr) {
-                       ocr = cr;
-                       cr = cr->next;
-                       CSR1212_FREE(ocr);
-               }
-               c = c->next;
-               CSR1212_FREE(oc);
-       }
-
-       CSR1212_FREE(csr);
-}
-
-
-/* CSR Image Creation */
-
-static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
-{
-       struct csr1212_csr_rom_cache *cache;
-       u64 csr_addr;
-
-       BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
-              !csr->ops->release_addr || csr->max_rom < 1);
-
-       /* ROM size must be a multiple of csr->max_rom */
-       romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
-       csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
-                                                csr->private);
-       if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
-               return -ENOMEM;
-
-       if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
-               /* Invalid address returned from allocate_addr_range(). */
-               csr->ops->release_addr(csr_addr, csr->private);
-               return -ENOMEM;
-       }
-
-       cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
-                                        romsize);
-       if (!cache) {
-               csr->ops->release_addr(csr_addr, csr->private);
-               return -ENOMEM;
-       }
-
-       cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
-                                           CSR1212_KV_ID_EXTENDED_ROM);
-       if (!cache->ext_rom) {
-               csr->ops->release_addr(csr_addr, csr->private);
-               CSR1212_FREE(cache);
-               return -ENOMEM;
-       }
-
-       if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
-           CSR1212_SUCCESS) {
-               csr1212_release_keyval(cache->ext_rom);
-               csr->ops->release_addr(csr_addr, csr->private);
-               CSR1212_FREE(cache);
-               return -ENOMEM;
-       }
-       cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
-       cache->ext_rom->value.leaf.len = -1;
-       cache->ext_rom->value.leaf.data = cache->data;
-
-       /* Add cache to tail of cache list */
-       cache->prev = csr->cache_tail;
-       csr->cache_tail->next = cache;
-       csr->cache_tail = cache;
-       return CSR1212_SUCCESS;
-}
-
-static void csr1212_remove_cache(struct csr1212_csr *csr,
-                                struct csr1212_csr_rom_cache *cache)
-{
-       if (csr->cache_head == cache)
-               csr->cache_head = cache->next;
-       if (csr->cache_tail == cache)
-               csr->cache_tail = cache->prev;
-
-       if (cache->prev)
-               cache->prev->next = cache->next;
-       if (cache->next)
-               cache->next->prev = cache->prev;
-
-       if (cache->ext_rom) {
-               csr1212_detach_keyval_from_directory(csr->root_kv,
-                                                    cache->ext_rom);
-               csr1212_release_keyval(cache->ext_rom);
-       }
-
-       CSR1212_FREE(cache);
-}
-
-static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
-                                         struct csr1212_keyval **layout_tail)
-{
-       struct csr1212_dentry *dentry;
-       struct csr1212_keyval *dkv;
-       struct csr1212_keyval *last_extkey_spec = NULL;
-       struct csr1212_keyval *last_extkey = NULL;
-       int num_entries = 0;
-
-       for (dentry = dir->value.directory.dentries_head; dentry;
-            dentry = dentry->next) {
-               for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
-                       /* Special Case: Extended Key Specifier_ID */
-                       if (dkv->key.id ==
-                           CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-                               if (last_extkey_spec == NULL)
-                                       last_extkey_spec = dkv;
-                               else if (dkv->value.immediate !=
-                                        last_extkey_spec->value.immediate)
-                                       last_extkey_spec = dkv;
-                               else
-                                       continue;
-                       /* Special Case: Extended Key */
-                       } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-                               if (last_extkey == NULL)
-                                       last_extkey = dkv;
-                               else if (dkv->value.immediate !=
-                                        last_extkey->value.immediate)
-                                       last_extkey = dkv;
-                               else
-                                       continue;
-                       }
-
-                       num_entries += 1;
-
-                       switch (dkv->key.type) {
-                       default:
-                       case CSR1212_KV_TYPE_IMMEDIATE:
-                       case CSR1212_KV_TYPE_CSR_OFFSET:
-                               break;
-                       case CSR1212_KV_TYPE_LEAF:
-                       case CSR1212_KV_TYPE_DIRECTORY:
-                               /* Remove from list */
-                               if (dkv->prev && (dkv->prev->next == dkv))
-                                       dkv->prev->next = dkv->next;
-                               if (dkv->next && (dkv->next->prev == dkv))
-                                       dkv->next->prev = dkv->prev;
-                               //if (dkv == *layout_tail)
-                               //      *layout_tail = dkv->prev;
-
-                               /* Special case: Extended ROM leafs */
-                               if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
-                                       dkv->value.leaf.len = -1;
-                                       /* Don't add Extended ROM leafs in the
-                                        * layout list, they are handled
-                                        * differently. */
-                                       break;
-                               }
-
-                               /* Add to tail of list */
-                               dkv->next = NULL;
-                               dkv->prev = *layout_tail;
-                               (*layout_tail)->next = dkv;
-                               *layout_tail = dkv;
-                               break;
-                       }
-               }
-       }
-       return num_entries;
-}
-
-static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
-{
-       struct csr1212_keyval *ltail = kv;
-       size_t agg_size = 0;
-
-       while (kv) {
-               switch (kv->key.type) {
-               case CSR1212_KV_TYPE_LEAF:
-                       /* Add 1 quadlet for crc/len field */
-                       agg_size += kv->value.leaf.len + 1;
-                       break;
-
-               case CSR1212_KV_TYPE_DIRECTORY:
-                       kv->value.directory.len =
-                               csr1212_generate_layout_subdir(kv, &ltail);
-                       /* Add 1 quadlet for crc/len field */
-                       agg_size += kv->value.directory.len + 1;
-                       break;
-               }
-               kv = kv->next;
-       }
-       return quads_to_bytes(agg_size);
-}
-
-static struct csr1212_keyval *
-csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
-                          struct csr1212_keyval *start_kv, int start_pos)
-{
-       struct csr1212_keyval *kv = start_kv;
-       struct csr1212_keyval *okv = start_kv;
-       int pos = start_pos;
-       int kv_len = 0, okv_len = 0;
-
-       cache->layout_head = kv;
-
-       while (kv && pos < cache->size) {
-               /* Special case: Extended ROM leafs */
-               if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-                       kv->offset = cache->offset + pos;
-
-               switch (kv->key.type) {
-               case CSR1212_KV_TYPE_LEAF:
-                       kv_len = kv->value.leaf.len;
-                       break;
-
-               case CSR1212_KV_TYPE_DIRECTORY:
-                       kv_len = kv->value.directory.len;
-                       break;
-
-               default:
-                       /* Should never get here */
-                       WARN_ON(1);
-                       break;
-               }
-
-               pos += quads_to_bytes(kv_len + 1);
-
-               if (pos <= cache->size) {
-                       okv = kv;
-                       okv_len = kv_len;
-                       kv = kv->next;
-               }
-       }
-
-       cache->layout_tail = okv;
-       cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
-
-       return kv;
-}
-
-#define CSR1212_KV_KEY_SHIFT           24
-#define CSR1212_KV_KEY_TYPE_SHIFT      6
-#define CSR1212_KV_KEY_ID_MASK         0x3f
-#define CSR1212_KV_KEY_TYPE_MASK       0x3     /* after shift */
-
-static void
-csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
-{
-       struct csr1212_dentry *dentry;
-       struct csr1212_keyval *last_extkey_spec = NULL;
-       struct csr1212_keyval *last_extkey = NULL;
-       int index = 0;
-
-       for (dentry = dir->value.directory.dentries_head;
-            dentry;
-            dentry = dentry->next) {
-               struct csr1212_keyval *a;
-
-               for (a = dentry->kv; a; a = a->associate) {
-                       u32 value = 0;
-
-                       /* Special Case: Extended Key Specifier_ID */
-                       if (a->key.id ==
-                           CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-                               if (last_extkey_spec == NULL)
-                                       last_extkey_spec = a;
-                               else if (a->value.immediate !=
-                                        last_extkey_spec->value.immediate)
-                                       last_extkey_spec = a;
-                               else
-                                       continue;
-
-                       /* Special Case: Extended Key */
-                       } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-                               if (last_extkey == NULL)
-                                       last_extkey = a;
-                               else if (a->value.immediate !=
-                                        last_extkey->value.immediate)
-                                       last_extkey = a;
-                               else
-                                       continue;
-                       }
-
-                       switch (a->key.type) {
-                       case CSR1212_KV_TYPE_IMMEDIATE:
-                               value = a->value.immediate;
-                               break;
-                       case CSR1212_KV_TYPE_CSR_OFFSET:
-                               value = a->value.csr_offset;
-                               break;
-                       case CSR1212_KV_TYPE_LEAF:
-                               value = a->offset;
-                               value -= dir->offset + quads_to_bytes(1+index);
-                               value = bytes_to_quads(value);
-                               break;
-                       case CSR1212_KV_TYPE_DIRECTORY:
-                               value = a->offset;
-                               value -= dir->offset + quads_to_bytes(1+index);
-                               value = bytes_to_quads(value);
-                               break;
-                       default:
-                               /* Should never get here */
-                               WARN_ON(1);
-                               break;
-                       }
-
-                       value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
-                                CSR1212_KV_KEY_SHIFT;
-                       value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
-                                (CSR1212_KV_KEY_SHIFT +
-                                 CSR1212_KV_KEY_TYPE_SHIFT);
-                       data_buffer[index] = cpu_to_be32(value);
-                       index++;
-               }
-       }
-}
-
-struct csr1212_keyval_img {
-       u16 length;
-       u16 crc;
-
-       /* Must be last */
-       u32 data[0];    /* older gcc can't handle [] which is standard */
-};
-
-static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
-{
-       struct csr1212_keyval *kv, *nkv;
-       struct csr1212_keyval_img *kvi;
-
-       for (kv = cache->layout_head;
-            kv != cache->layout_tail->next;
-            kv = nkv) {
-               kvi = (struct csr1212_keyval_img *)(cache->data +
-                               bytes_to_quads(kv->offset - cache->offset));
-               switch (kv->key.type) {
-               default:
-               case CSR1212_KV_TYPE_IMMEDIATE:
-               case CSR1212_KV_TYPE_CSR_OFFSET:
-                       /* Should never get here */
-                       WARN_ON(1);
-                       break;
-
-               case CSR1212_KV_TYPE_LEAF:
-                       /* Don't copy over Extended ROM areas, they are
-                        * already filled out! */
-                       if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-                               memcpy(kvi->data, kv->value.leaf.data,
-                                      quads_to_bytes(kv->value.leaf.len));
-
-                       kvi->length = cpu_to_be16(kv->value.leaf.len);
-                       kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
-                       break;
-
-               case CSR1212_KV_TYPE_DIRECTORY:
-                       csr1212_generate_tree_subdir(kv, kvi->data);
-
-                       kvi->length = cpu_to_be16(kv->value.directory.len);
-                       kvi->crc = csr1212_crc16(kvi->data,
-                                                kv->value.directory.len);
-                       break;
-               }
-
-               nkv = kv->next;
-               if (kv->prev)
-                       kv->prev->next = NULL;
-               if (kv->next)
-                       kv->next->prev = NULL;
-               kv->prev = NULL;
-               kv->next = NULL;
-       }
-}
-
-/* This size is arbitrarily chosen.
- * The struct overhead is subtracted for more economic allocations. */
-#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
-
-int csr1212_generate_csr_image(struct csr1212_csr *csr)
-{
-       struct csr1212_bus_info_block_img *bi;
-       struct csr1212_csr_rom_cache *cache;
-       struct csr1212_keyval *kv;
-       size_t agg_size;
-       int ret;
-       int init_offset;
-
-       BUG_ON(!csr);
-
-       cache = csr->cache_head;
-
-       bi = (struct csr1212_bus_info_block_img*)cache->data;
-
-       bi->length = bytes_to_quads(csr->bus_info_len) - 1;
-       bi->crc_length = bi->length;
-       bi->crc = csr1212_crc16(bi->data, bi->crc_length);
-
-       csr->root_kv->next = NULL;
-       csr->root_kv->prev = NULL;
-
-       agg_size = csr1212_generate_layout_order(csr->root_kv);
-
-       init_offset = csr->bus_info_len;
-
-       for (kv = csr->root_kv, cache = csr->cache_head;
-            kv;
-            cache = cache->next) {
-               if (!cache) {
-                       /* Estimate approximate number of additional cache
-                        * regions needed (it assumes that the cache holding
-                        * the first 1K Config ROM space always exists). */
-                       int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
-                                               (2 * sizeof(u32))) + 1;
-
-                       /* Add additional cache regions, extras will be
-                        * removed later */
-                       for (; est_c; est_c--) {
-                               ret = csr1212_append_new_cache(csr,
-                                               CSR1212_EXTENDED_ROM_SIZE);
-                               if (ret != CSR1212_SUCCESS)
-                                       return ret;
-                       }
-                       /* Need to re-layout for additional cache regions */
-                       agg_size = csr1212_generate_layout_order(csr->root_kv);
-                       kv = csr->root_kv;
-                       cache = csr->cache_head;
-                       init_offset = csr->bus_info_len;
-               }
-               kv = csr1212_generate_positions(cache, kv, init_offset);
-               agg_size -= cache->len;
-               init_offset = sizeof(u32);
-       }
-
-       /* Remove unused, excess cache regions */
-       while (cache) {
-               struct csr1212_csr_rom_cache *oc = cache;
-
-               cache = cache->next;
-               csr1212_remove_cache(csr, oc);
-       }
-
-       /* Go through the list backward so that when done, the correct CRC
-        * will be calculated for the Extended ROM areas. */
-       for (cache = csr->cache_tail; cache; cache = cache->prev) {
-               /* Only Extended ROM caches should have this set. */
-               if (cache->ext_rom) {
-                       int leaf_size;
-
-                       /* Make sure the Extended ROM leaf is a multiple of
-                        * max_rom in size. */
-                       BUG_ON(csr->max_rom < 1);
-                       leaf_size = (cache->len + (csr->max_rom - 1)) &
-                               ~(csr->max_rom - 1);
-
-                       /* Zero out the unused ROM region */
-                       memset(cache->data + bytes_to_quads(cache->len), 0x00,
-                              leaf_size - cache->len);
-
-                       /* Subtract leaf header */
-                       leaf_size -= sizeof(u32);
-
-                       /* Update the Extended ROM leaf length */
-                       cache->ext_rom->value.leaf.len =
-                               bytes_to_quads(leaf_size);
-               } else {
-                       /* Zero out the unused ROM region */
-                       memset(cache->data + bytes_to_quads(cache->len), 0x00,
-                              cache->size - cache->len);
-               }
-
-               /* Copy the data into the cache buffer */
-               csr1212_fill_cache(cache);
-
-               if (cache != csr->cache_head) {
-                       /* Set the length and CRC of the extended ROM. */
-                       struct csr1212_keyval_img *kvi =
-                               (struct csr1212_keyval_img*)cache->data;
-                       u16 len = bytes_to_quads(cache->len) - 1;
-
-                       kvi->length = cpu_to_be16(len);
-                       kvi->crc = csr1212_crc16(kvi->data, len);
-               }
-       }
-
-       return CSR1212_SUCCESS;
-}
-
-int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
-{
-       struct csr1212_csr_rom_cache *cache;
-
-       for (cache = csr->cache_head; cache; cache = cache->next)
-               if (offset >= cache->offset &&
-                   (offset + len) <= (cache->offset + cache->size)) {
-                       memcpy(buffer, &cache->data[
-                                       bytes_to_quads(offset - cache->offset)],
-                              len);
-                       return CSR1212_SUCCESS;
-               }
-
-       return -ENOENT;
-}
-
-/*
- * Apparently there are many different wrong implementations of the CRC
- * algorithm.  We don't fail, we just warn... approximately once per GUID.
- */
-static void
-csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid)
-{
-       static u64 last_bad_eui64;
-       u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]);
-
-       if (csr1212_crc16(buffer, length) == crc ||
-           csr1212_msft_crc16(buffer, length) == crc ||
-           eui64 == last_bad_eui64)
-               return;
-
-       printk(KERN_DEBUG "ieee1394: config ROM CRC error\n");
-       last_bad_eui64 = eui64;
-}
-
-/* Parse a chunk of data as a Config ROM */
-
-static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
-{
-       struct csr1212_bus_info_block_img *bi;
-       struct csr1212_cache_region *cr;
-       int i;
-       int ret;
-
-       for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
-               ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-                               &csr->cache_head->data[bytes_to_quads(i)],
-                               csr->private);
-               if (ret != CSR1212_SUCCESS)
-                       return ret;
-
-               /* check ROM header's info_length */
-               if (i == 0 &&
-                   be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
-                   bytes_to_quads(csr->bus_info_len) - 1)
-                       return -EINVAL;
-       }
-
-       bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
-       csr->crc_len = quads_to_bytes(bi->crc_length);
-
-       /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
-        * is not always the case, so read the rest of the crc area 1 quadlet at
-        * a time. */
-       for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
-               ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-                               &csr->cache_head->data[bytes_to_quads(i)],
-                               csr->private);
-               if (ret != CSR1212_SUCCESS)
-                       return ret;
-       }
-
-       csr1212_check_crc(bi->data, bi->crc_length, bi->crc,
-                         &csr->bus_info_data[3]);
-
-       cr = CSR1212_MALLOC(sizeof(*cr));
-       if (!cr)
-               return -ENOMEM;
-
-       cr->next = NULL;
-       cr->prev = NULL;
-       cr->offset_start = 0;
-       cr->offset_end = csr->crc_len + 4;
-
-       csr->cache_head->filled_head = cr;
-       csr->cache_head->filled_tail = cr;
-
-       return CSR1212_SUCCESS;
-}
-
-#define CSR1212_KV_KEY(q)      (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(q)   (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL_MASK    0xffffff
-#define CSR1212_KV_VAL(q)      (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
-
-static int
-csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
-{
-       int ret = CSR1212_SUCCESS;
-       struct csr1212_keyval *k = NULL;
-       u32 offset;
-       bool keep_keyval = true;
-
-       switch (CSR1212_KV_KEY_TYPE(ki)) {
-       case CSR1212_KV_TYPE_IMMEDIATE:
-               k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
-                                         CSR1212_KV_VAL(ki));
-               if (!k) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               /* Don't keep local reference when parsing. */
-               keep_keyval = false;
-               break;
-
-       case CSR1212_KV_TYPE_CSR_OFFSET:
-               k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
-                                          CSR1212_KV_VAL(ki));
-               if (!k) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               /* Don't keep local reference when parsing. */
-               keep_keyval = false;
-               break;
-
-       default:
-               /* Compute the offset from 0xffff f000 0000. */
-               offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
-               if (offset == kv_pos) {
-                       /* Uh-oh.  Can't have a relative offset of 0 for Leaves
-                        * or Directories.  The Config ROM image is most likely
-                        * messed up, so we'll just abort here. */
-                       ret = -EIO;
-                       goto out;
-               }
-
-               k = csr1212_find_keyval_offset(dir, offset);
-
-               if (k)
-                       break;          /* Found it. */
-
-               if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
-                       k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
-               else
-                       k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
-
-               if (!k) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               /* Don't keep local reference when parsing. */
-               keep_keyval = false;
-               /* Contents not read yet so it's not valid. */
-               k->valid = 0;
-               k->offset = offset;
-
-               k->prev = dir;
-               k->next = dir->next;
-               dir->next->prev = k;
-               dir->next = k;
-       }
-       ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
-out:
-       if (ret != CSR1212_SUCCESS && k != NULL)
-               free_keyval(k);
-       return ret;
-}
-
-int csr1212_parse_keyval(struct csr1212_keyval *kv,
-                        struct csr1212_csr_rom_cache *cache)
-{
-       struct csr1212_keyval_img *kvi;
-       int i;
-       int ret = CSR1212_SUCCESS;
-       int kvi_len;
-
-       kvi = (struct csr1212_keyval_img*)
-               &cache->data[bytes_to_quads(kv->offset - cache->offset)];
-       kvi_len = be16_to_cpu(kvi->length);
-
-       /* GUID is wrong in here in case of extended ROM.  We don't care. */
-       csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]);
-
-       switch (kv->key.type) {
-       case CSR1212_KV_TYPE_DIRECTORY:
-               for (i = 0; i < kvi_len; i++) {
-                       u32 ki = kvi->data[i];
-
-                       /* Some devices put null entries in their unit
-                        * directories.  If we come across such an entry,
-                        * then skip it. */
-                       if (ki == 0x0)
-                               continue;
-                       ret = csr1212_parse_dir_entry(kv, ki,
-                                       kv->offset + quads_to_bytes(i + 1));
-               }
-               kv->value.directory.len = kvi_len;
-               break;
-
-       case CSR1212_KV_TYPE_LEAF:
-               if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
-                       size_t size = quads_to_bytes(kvi_len);
-
-                       kv->value.leaf.data = CSR1212_MALLOC(size);
-                       if (!kv->value.leaf.data) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-
-                       kv->value.leaf.len = kvi_len;
-                       memcpy(kv->value.leaf.data, kvi->data, size);
-               }
-               break;
-       }
-
-       kv->valid = 1;
-out:
-       return ret;
-}
-
-static int
-csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
-       struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
-       struct csr1212_keyval_img *kvi = NULL;
-       struct csr1212_csr_rom_cache *cache;
-       int cache_index;
-       u64 addr;
-       u32 *cache_ptr;
-       u16 kv_len = 0;
-
-       BUG_ON(!csr || !kv || csr->max_rom < 1);
-
-       /* First find which cache the data should be in (or go in if not read
-        * yet). */
-       for (cache = csr->cache_head; cache; cache = cache->next)
-               if (kv->offset >= cache->offset &&
-                   kv->offset < (cache->offset + cache->size))
-                       break;
-
-       if (!cache) {
-               u32 q, cache_size;
-
-               /* Only create a new cache for Extended ROM leaves. */
-               if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-                       return -EINVAL;
-
-               if (csr->ops->bus_read(csr,
-                                      CSR1212_REGISTER_SPACE_BASE + kv->offset,
-                                      &q, csr->private))
-                       return -EIO;
-
-               kv->value.leaf.len = be32_to_cpu(q) >> 16;
-
-               cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
-                             (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
-               cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
-               if (!cache)
-                       return -ENOMEM;
-
-               kv->value.leaf.data = &cache->data[1];
-               csr->cache_tail->next = cache;
-               cache->prev = csr->cache_tail;
-               cache->next = NULL;
-               csr->cache_tail = cache;
-               cache->filled_head =
-                       CSR1212_MALLOC(sizeof(*cache->filled_head));
-               if (!cache->filled_head)
-                       return -ENOMEM;
-
-               cache->filled_head->offset_start = 0;
-               cache->filled_head->offset_end = sizeof(u32);
-               cache->filled_tail = cache->filled_head;
-               cache->filled_head->next = NULL;
-               cache->filled_head->prev = NULL;
-               cache->data[0] = q;
-
-               /* Don't read the entire extended ROM now.  Pieces of it will
-                * be read when entries inside it are read. */
-               return csr1212_parse_keyval(kv, cache);
-       }
-
-       cache_index = kv->offset - cache->offset;
-
-       /* Now seach read portions of the cache to see if it is there. */
-       for (cr = cache->filled_head; cr; cr = cr->next) {
-               if (cache_index < cr->offset_start) {
-                       newcr = CSR1212_MALLOC(sizeof(*newcr));
-                       if (!newcr)
-                               return -ENOMEM;
-
-                       newcr->offset_start = cache_index & ~(csr->max_rom - 1);
-                       newcr->offset_end = newcr->offset_start;
-                       newcr->next = cr;
-                       newcr->prev = cr->prev;
-                       cr->prev = newcr;
-                       cr = newcr;
-                       break;
-               } else if ((cache_index >= cr->offset_start) &&
-                          (cache_index < cr->offset_end)) {
-                       kvi = (struct csr1212_keyval_img*)
-                               (&cache->data[bytes_to_quads(cache_index)]);
-                       kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
-                       break;
-               } else if (cache_index == cr->offset_end) {
-                       break;
-               }
-       }
-
-       if (!cr) {
-               cr = cache->filled_tail;
-               newcr = CSR1212_MALLOC(sizeof(*newcr));
-               if (!newcr)
-                       return -ENOMEM;
-
-               newcr->offset_start = cache_index & ~(csr->max_rom - 1);
-               newcr->offset_end = newcr->offset_start;
-               newcr->prev = cr;
-               newcr->next = cr->next;
-               cr->next = newcr;
-               cr = newcr;
-               cache->filled_tail = newcr;
-       }
-
-       while(!kvi || cr->offset_end < cache_index + kv_len) {
-               cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
-                                                       ~(csr->max_rom - 1))];
-
-               addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
-                       cr->offset_end) & ~(csr->max_rom - 1);
-
-               if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
-                       return -EIO;
-
-               cr->offset_end += csr->max_rom - (cr->offset_end &
-                                                 (csr->max_rom - 1));
-
-               if (!kvi && (cr->offset_end > cache_index)) {
-                       kvi = (struct csr1212_keyval_img*)
-                               (&cache->data[bytes_to_quads(cache_index)]);
-                       kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
-               }
-
-               if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
-                       /* The Leaf or Directory claims its length extends
-                        * beyond the ConfigROM image region and thus beyond the
-                        * end of our cache region.  Therefore, we abort now
-                        * rather than seg faulting later. */
-                       return -EIO;
-               }
-
-               ncr = cr->next;
-
-               if (ncr && (cr->offset_end >= ncr->offset_start)) {
-                       /* consolidate region entries */
-                       ncr->offset_start = cr->offset_start;
-
-                       if (cr->prev)
-                               cr->prev->next = cr->next;
-                       ncr->prev = cr->prev;
-                       if (cache->filled_head == cr)
-                               cache->filled_head = ncr;
-                       CSR1212_FREE(cr);
-                       cr = ncr;
-               }
-       }
-
-       return csr1212_parse_keyval(kv, cache);
-}
-
-struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
-       if (!kv)
-               return NULL;
-       if (!kv->valid)
-               if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
-                       return NULL;
-       return kv;
-}
-
-int csr1212_parse_csr(struct csr1212_csr *csr)
-{
-       struct csr1212_dentry *dentry;
-       int ret;
-
-       BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
-
-       ret = csr1212_parse_bus_info_block(csr);
-       if (ret != CSR1212_SUCCESS)
-               return ret;
-
-       /*
-        * There has been a buggy firmware with bus_info_block.max_rom > 0
-        * spotted which actually only supported quadlet read requests to the
-        * config ROM.  Therefore read everything quadlet by quadlet regardless
-        * of what the bus info block says.
-        */
-       csr->max_rom = 4;
-
-       csr->cache_head->layout_head = csr->root_kv;
-       csr->cache_head->layout_tail = csr->root_kv;
-
-       csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
-               csr->bus_info_len;
-
-       csr->root_kv->valid = 0;
-       csr->root_kv->next = csr->root_kv;
-       csr->root_kv->prev = csr->root_kv;
-       ret = csr1212_read_keyval(csr, csr->root_kv);
-       if (ret != CSR1212_SUCCESS)
-               return ret;
-
-       /* Scan through the Root directory finding all extended ROM regions
-        * and make cache regions for them */
-       for (dentry = csr->root_kv->value.directory.dentries_head;
-            dentry; dentry = dentry->next) {
-               if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
-                       !dentry->kv->valid) {
-                       ret = csr1212_read_keyval(csr, dentry->kv);
-                       if (ret != CSR1212_SUCCESS)
-                               return ret;
-               }
-       }
-
-       return CSR1212_SUCCESS;
-}
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
deleted file mode 100644 (file)
index a892d92..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * csr1212.h -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *    2. Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *    3. The name of the author may not be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __CSR1212_H__
-#define __CSR1212_H__
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/atomic.h>
-
-#define CSR1212_MALLOC(size)   kmalloc((size), GFP_KERNEL)
-#define CSR1212_FREE(ptr)      kfree(ptr)
-
-#define CSR1212_SUCCESS (0)
-
-
-/* CSR 1212 key types */
-#define CSR1212_KV_TYPE_IMMEDIATE              0
-#define CSR1212_KV_TYPE_CSR_OFFSET             1
-#define CSR1212_KV_TYPE_LEAF                   2
-#define CSR1212_KV_TYPE_DIRECTORY              3
-
-
-/* CSR 1212 key ids */
-#define CSR1212_KV_ID_DESCRIPTOR               0x01
-#define CSR1212_KV_ID_BUS_DEPENDENT_INFO       0x02
-#define CSR1212_KV_ID_VENDOR                   0x03
-#define CSR1212_KV_ID_HARDWARE_VERSION         0x04
-#define CSR1212_KV_ID_MODULE                   0x07
-#define CSR1212_KV_ID_NODE_CAPABILITIES                0x0C
-#define CSR1212_KV_ID_EUI_64                   0x0D
-#define CSR1212_KV_ID_UNIT                     0x11
-#define CSR1212_KV_ID_SPECIFIER_ID             0x12
-#define CSR1212_KV_ID_VERSION                  0x13
-#define CSR1212_KV_ID_DEPENDENT_INFO           0x14
-#define CSR1212_KV_ID_UNIT_LOCATION            0x15
-#define CSR1212_KV_ID_MODEL                    0x17
-#define CSR1212_KV_ID_INSTANCE                 0x18
-#define CSR1212_KV_ID_KEYWORD                  0x19
-#define CSR1212_KV_ID_FEATURE                  0x1A
-#define CSR1212_KV_ID_EXTENDED_ROM             0x1B
-#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID        0x1C
-#define CSR1212_KV_ID_EXTENDED_KEY             0x1D
-#define CSR1212_KV_ID_EXTENDED_DATA            0x1E
-#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR    0x1F
-#define CSR1212_KV_ID_DIRECTORY_ID             0x20
-#define CSR1212_KV_ID_REVISION                 0x21
-
-
-/* IEEE 1212 Address space map */
-#define CSR1212_ALL_SPACE_BASE                 (0x000000000000ULL)
-#define CSR1212_ALL_SPACE_SIZE                 (1ULL << 48)
-#define CSR1212_ALL_SPACE_END                  (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
-
-#define  CSR1212_MEMORY_SPACE_BASE             (0x000000000000ULL)
-#define  CSR1212_MEMORY_SPACE_SIZE             ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
-#define  CSR1212_MEMORY_SPACE_END              (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
-
-#define  CSR1212_PRIVATE_SPACE_BASE            (0xffffe0000000ULL)
-#define  CSR1212_PRIVATE_SPACE_SIZE            (256ULL * (1ULL << 20))
-#define  CSR1212_PRIVATE_SPACE_END             (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
-
-#define  CSR1212_REGISTER_SPACE_BASE           (0xfffff0000000ULL)
-#define  CSR1212_REGISTER_SPACE_SIZE           (256ULL * (1ULL << 20))
-#define  CSR1212_REGISTER_SPACE_END            (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
-
-#define  CSR1212_CSR_ARCH_REG_SPACE_BASE       (0xfffff0000000ULL)
-#define  CSR1212_CSR_ARCH_REG_SPACE_SIZE       (512)
-#define  CSR1212_CSR_ARCH_REG_SPACE_END                (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
-#define  CSR1212_CSR_ARCH_REG_SPACE_OFFSET     (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_BASE    (0xfffff0000200ULL)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE    (512)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_END     (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET  (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_CONFIG_ROM_SPACE_BASE         (0xfffff0000400ULL)
-#define  CSR1212_CONFIG_ROM_SPACE_SIZE         (1024)
-#define  CSR1212_CONFIG_ROM_SPACE_END          (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
-#define  CSR1212_CONFIG_ROM_SPACE_OFFSET       (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_UNITS_SPACE_BASE              (0xfffff0000800ULL)
-#define  CSR1212_UNITS_SPACE_SIZE              ((256ULL * (1ULL << 20)) - 2048)
-#define  CSR1212_UNITS_SPACE_END               (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
-#define  CSR1212_UNITS_SPACE_OFFSET            (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_INVALID_ADDR_SPACE            -1
-
-
-/* Config ROM image structures */
-struct csr1212_bus_info_block_img {
-       u8 length;
-       u8 crc_length;
-       u16 crc;
-
-       /* Must be last */
-       u32 data[0];    /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_leaf {
-       int len;
-       u32 *data;
-};
-
-struct csr1212_dentry {
-       struct csr1212_dentry *next, *prev;
-       struct csr1212_keyval *kv;
-};
-
-struct csr1212_directory {
-       int len;
-       struct csr1212_dentry *dentries_head, *dentries_tail;
-};
-
-struct csr1212_keyval {
-       struct {
-               u8 type;
-               u8 id;
-       } key;
-       union {
-               u32 immediate;
-               u32 csr_offset;
-               struct csr1212_leaf leaf;
-               struct csr1212_directory directory;
-       } value;
-       struct csr1212_keyval *associate;
-       atomic_t refcnt;
-
-       /* used in generating and/or parsing CSR image */
-       struct csr1212_keyval *next, *prev;     /* flat list of CSR elements */
-       u32 offset;     /* position in CSR from 0xffff f000 0000 */
-       u8 valid;       /* flag indicating keyval has valid data*/
-};
-
-
-struct csr1212_cache_region {
-       struct csr1212_cache_region *next, *prev;
-       u32 offset_start;       /* inclusive */
-       u32 offset_end;         /* exclusive */
-};
-
-struct csr1212_csr_rom_cache {
-       struct csr1212_csr_rom_cache *next, *prev;
-       struct csr1212_cache_region *filled_head, *filled_tail;
-       struct csr1212_keyval *layout_head, *layout_tail;
-       size_t size;
-       u32 offset;
-       struct csr1212_keyval *ext_rom;
-       size_t len;
-
-       /* Must be last */
-       u32 data[0];    /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_csr {
-       size_t bus_info_len;    /* bus info block length in bytes */
-       size_t crc_len;         /* crc length in bytes */
-       __be32 *bus_info_data;  /* bus info data incl bus name and EUI */
-
-       void *private;          /* private, bus specific data */
-       struct csr1212_bus_ops *ops;
-
-       struct csr1212_keyval *root_kv;
-
-       int max_rom;            /* max bytes readable in Config ROM region */
-
-       /* Items below used for image parsing and generation */
-       struct csr1212_csr_rom_cache *cache_head, *cache_tail;
-};
-
-struct csr1212_bus_ops {
-       /* This function is used by csr1212 to read additional information
-        * from remote nodes when parsing a Config ROM (i.e., read Config ROM
-        * entries located in the Units Space.  Must return 0 on success
-        * anything else indicates an error. */
-       int (*bus_read) (struct csr1212_csr *csr, u64 addr,
-                        void *buffer, void *private);
-
-       /* This function is used by csr1212 to allocate a region in units space
-        * in the event that Config ROM entries don't all fit in the predefined
-        * 1K region.  The void *private parameter is private member of struct
-        * csr1212_csr. */
-       u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
-
-       /* This function is used by csr1212 to release a region in units space
-        * that is no longer needed. */
-       void (*release_addr) (u64 addr, void *private);
-};
-
-
-/* Descriptor Leaf manipulation macros */
-#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
-       (be32_to_cpu((kv)->value.leaf.data[0]) >> \
-        CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
-       (be32_to_cpu((kv)->value.leaf.data[0]) & \
-        CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-
-
-/* Text Descriptor Leaf manipulation macros */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff  /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
-       (be32_to_cpu((kv)->value.leaf.data[1]) >> \
-        CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
-       ((be32_to_cpu((kv)->value.leaf.data[1]) >> \
-         CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
-        CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
-       (be32_to_cpu((kv)->value.leaf.data[1]) & \
-        CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
-       (&((kv)->value.leaf.data[2]))
-
-
-/* The following 2 function are for creating new Configuration ROM trees.  The
- * first function is used for both creating local trees and parsing remote
- * trees.  The second function adds pertinent information to local Configuration
- * ROM trees - namely data for the bus information block. */
-extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
-                                             size_t bus_info_size,
-                                             void *private);
-extern void csr1212_init_local_csr(struct csr1212_csr *csr,
-                                  const u32 *bus_info_data, int max_rom);
-
-
-/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
-extern void csr1212_destroy_csr(struct csr1212_csr *csr);
-
-
-/* The following set of functions are fore creating new keyvals for placement in
- * a Configuration ROM tree.  Code that creates new keyvals with these functions
- * must release those keyvals with csr1212_release_keyval() when they are no
- * longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
-extern struct csr1212_keyval *csr1212_new_directory(u8 key);
-extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-
-
-/* The following function manages association between keyvals.  Typically,
- * Descriptor Leaves and Directories will be associated with another keyval and
- * it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.
- * Take care with subsequent ROM modifications:  There is no function to remove
- * previously specified associations.
- */
-extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
-                                    struct csr1212_keyval *associate);
-
-
-/* The following functions manage the association of a keyval and directories.
- * A keyval may be attached to more than one directory. */
-extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-                                             struct csr1212_keyval *kv);
-extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
-                                                struct csr1212_keyval *kv);
-
-
-/* Creates a complete Configuration ROM image in the list of caches available
- * via csr->cache_head. */
-extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
-
-
-/* This is a convience function for reading a block of data out of one of the
- * caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
-                       u32 len);
-
-
-/* The following functions are in place for parsing Configuration ROM images.
- * csr1212_parse_keyval() is used should there be a need to directly parse a
- * Configuration ROM directly. */
-extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
-                               struct csr1212_csr_rom_cache *cache);
-extern int csr1212_parse_csr(struct csr1212_csr *csr);
-
-
-/* This function allocates a new cache which may be used for either parsing or
- * generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *
-csr1212_rom_cache_malloc(u32 offset, size_t size)
-{
-       struct csr1212_csr_rom_cache *cache;
-
-       cache = CSR1212_MALLOC(sizeof(*cache) + size);
-       if (!cache)
-               return NULL;
-
-       cache->next = NULL;
-       cache->prev = NULL;
-       cache->filled_head = NULL;
-       cache->filled_tail = NULL;
-       cache->layout_head = NULL;
-       cache->layout_tail = NULL;
-       cache->offset = offset;
-       cache->size = size;
-       cache->ext_rom = NULL;
-
-       return cache;
-}
-
-
-/* This function ensures that a keyval contains data when referencing a keyval
- * created by parsing a Configuration ROM. */
-extern struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-
-
-/* This function increments the reference count for a keyval should there be a
- * need for code to retain a keyval that has been parsed. */
-static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
-{
-       atomic_inc(&kv->refcnt);
-       smp_mb__after_atomic_inc();
-}
-
-
-/* This function decrements a keyval's reference count and will destroy the
- * keyval when there are no more users of the keyval.  This should be called by
- * any code that calls csr1212_keep_keyval() or any of the keyval creation
- * routines csr1212_new_*(). */
-extern void csr1212_release_keyval(struct csr1212_keyval *kv);
-
-
-/*
- * This macro allows for looping over the keyval entries in a directory and it
- * ensures that keyvals from remote ConfigROMs are parsed properly.
- *
- * struct csr1212_csr *_csr points to the CSR associated with dir.
- * struct csr1212_keyval *_kv points to the current keyval (loop index).
- * struct csr1212_keyval *_dir points to the directory to be looped.
- * struct csr1212_dentry *_pos is used internally for indexing.
- *
- * kv will be NULL upon exit of the loop.
- */
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos)              \
-       for (csr1212_get_keyval((_csr), (_dir)),                        \
-            _pos = (_dir)->value.directory.dentries_head,              \
-            _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
-            (_kv) && (_pos);                                           \
-            (_kv->associate == NULL) ?                                 \
-                    ((_pos = _pos->next), (_kv = (_pos) ?              \
-                               csr1212_get_keyval((_csr), _pos->kv) :  \
-                               NULL)) :                                \
-                    (_kv = csr1212_get_keyval((_csr), _kv->associate)))
-
-#endif /* __CSR1212_H__ */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
deleted file mode 100644 (file)
index d178699..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/scatterlist.h>
-
-#include "dma.h"
-
-/* dma_prog_region */
-
-void dma_prog_region_init(struct dma_prog_region *prog)
-{
-       prog->kvirt = NULL;
-       prog->dev = NULL;
-       prog->n_pages = 0;
-       prog->bus_addr = 0;
-}
-
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
-                         struct pci_dev *dev)
-{
-       /* round up to page size */
-       n_bytes = PAGE_ALIGN(n_bytes);
-
-       prog->n_pages = n_bytes >> PAGE_SHIFT;
-
-       prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
-       if (!prog->kvirt) {
-               printk(KERN_ERR
-                      "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
-               dma_prog_region_free(prog);
-               return -ENOMEM;
-       }
-
-       prog->dev = dev;
-
-       return 0;
-}
-
-void dma_prog_region_free(struct dma_prog_region *prog)
-{
-       if (prog->kvirt) {
-               pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
-                                   prog->kvirt, prog->bus_addr);
-       }
-
-       prog->kvirt = NULL;
-       prog->dev = NULL;
-       prog->n_pages = 0;
-       prog->bus_addr = 0;
-}
-
-/* dma_region */
-
-/**
- * dma_region_init - clear out all fields but do not allocate anything
- */
-void dma_region_init(struct dma_region *dma)
-{
-       dma->kvirt = NULL;
-       dma->dev = NULL;
-       dma->n_pages = 0;
-       dma->n_dma_pages = 0;
-       dma->sglist = NULL;
-}
-
-/**
- * dma_region_alloc - allocate the buffer and map it to the IOMMU
- */
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
-                    struct pci_dev *dev, int direction)
-{
-       unsigned int i;
-
-       /* round up to page size */
-       n_bytes = PAGE_ALIGN(n_bytes);
-
-       dma->n_pages = n_bytes >> PAGE_SHIFT;
-
-       dma->kvirt = vmalloc_32(n_bytes);
-       if (!dma->kvirt) {
-               printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
-               goto err;
-       }
-
-       /* Clear the ram out, no junk to the user */
-       memset(dma->kvirt, 0, n_bytes);
-
-       /* allocate scatter/gather list */
-       dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
-       if (!dma->sglist) {
-               printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
-               goto err;
-       }
-
-       sg_init_table(dma->sglist, dma->n_pages);
-
-       /* fill scatter/gather list with pages */
-       for (i = 0; i < dma->n_pages; i++) {
-               unsigned long va =
-                   (unsigned long)dma->kvirt + (i << PAGE_SHIFT);
-
-               sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
-                               PAGE_SIZE, 0);
-       }
-
-       /* map sglist to the IOMMU */
-       dma->n_dma_pages =
-           pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
-
-       if (dma->n_dma_pages == 0) {
-               printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
-               goto err;
-       }
-
-       dma->dev = dev;
-       dma->direction = direction;
-
-       return 0;
-
-      err:
-       dma_region_free(dma);
-       return -ENOMEM;
-}
-
-/**
- * dma_region_free - unmap and free the buffer
- */
-void dma_region_free(struct dma_region *dma)
-{
-       if (dma->n_dma_pages) {
-               pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
-                            dma->direction);
-               dma->n_dma_pages = 0;
-               dma->dev = NULL;
-       }
-
-       vfree(dma->sglist);
-       dma->sglist = NULL;
-
-       vfree(dma->kvirt);
-       dma->kvirt = NULL;
-       dma->n_pages = 0;
-}
-
-/* find the scatterlist index and remaining offset corresponding to a
-   given offset from the beginning of the buffer */
-static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
-                                 unsigned int start, unsigned long *rem)
-{
-       int i;
-       unsigned long off = offset;
-
-       for (i = start; i < dma->n_dma_pages; i++) {
-               if (off < sg_dma_len(&dma->sglist[i])) {
-                       *rem = off;
-                       break;
-               }
-
-               off -= sg_dma_len(&dma->sglist[i]);
-       }
-
-       BUG_ON(i >= dma->n_dma_pages);
-
-       return i;
-}
-
-/**
- * dma_region_offset_to_bus - get bus address of an offset within a DMA region
- *
- * Returns the DMA bus address of the byte with the given @offset relative to
- * the beginning of the @dma.
- */
-dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
-                                   unsigned long offset)
-{
-       unsigned long rem = 0;
-
-       struct scatterlist *sg =
-           &dma->sglist[dma_region_find(dma, offset, 0, &rem)];
-       return sg_dma_address(sg) + rem;
-}
-
-/**
- * dma_region_sync_for_cpu - sync the CPU's view of the buffer
- */
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
-                            unsigned long len)
-{
-       int first, last;
-       unsigned long rem = 0;
-
-       if (!len)
-               len = 1;
-
-       first = dma_region_find(dma, offset, 0, &rem);
-       last = dma_region_find(dma, rem + len - 1, first, &rem);
-
-       pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
-                               dma->direction);
-}
-
-/**
- * dma_region_sync_for_device - sync the IO bus' view of the buffer
- */
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
-                               unsigned long len)
-{
-       int first, last;
-       unsigned long rem = 0;
-
-       if (!len)
-               len = 1;
-
-       first = dma_region_find(dma, offset, 0, &rem);
-       last = dma_region_find(dma, rem + len - 1, first, &rem);
-
-       pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
-                                  last - first + 1, dma->direction);
-}
-
-#ifdef CONFIG_MMU
-
-static int dma_region_pagefault(struct vm_area_struct *vma,
-                               struct vm_fault *vmf)
-{
-       struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
-
-       if (!dma->kvirt)
-               return VM_FAULT_SIGBUS;
-
-       if (vmf->pgoff >= dma->n_pages)
-               return VM_FAULT_SIGBUS;
-
-       vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
-       get_page(vmf->page);
-       return 0;
-}
-
-static const struct vm_operations_struct dma_region_vm_ops = {
-       .fault = dma_region_pagefault,
-};
-
-/**
- * dma_region_mmap - map the buffer into a user space process
- */
-int dma_region_mmap(struct dma_region *dma, struct file *file,
-                   struct vm_area_struct *vma)
-{
-       unsigned long size;
-
-       if (!dma->kvirt)
-               return -EINVAL;
-
-       /* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
-       if (vma->vm_pgoff != 0)
-               return -EINVAL;
-
-       /* check the length */
-       size = vma->vm_end - vma->vm_start;
-       if (size > (dma->n_pages << PAGE_SHIFT))
-               return -EINVAL;
-
-       vma->vm_ops = &dma_region_vm_ops;
-       vma->vm_private_data = dma;
-       vma->vm_file = file;
-       vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
-
-       return 0;
-}
-
-#else                          /* CONFIG_MMU */
-
-int dma_region_mmap(struct dma_region *dma, struct file *file,
-                   struct vm_area_struct *vma)
-{
-       return -EINVAL;
-}
-
-#endif                         /* CONFIG_MMU */
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
deleted file mode 100644 (file)
index 467373c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_DMA_H
-#define IEEE1394_DMA_H
-
-#include <asm/types.h>
-
-struct file;
-struct pci_dev;
-struct scatterlist;
-struct vm_area_struct;
-
-/**
- * struct dma_prog_region - small contiguous DMA buffer
- * @kvirt:    kernel virtual address
- * @dev:      PCI device
- * @n_pages:  number of kernel pages
- * @bus_addr: base bus address
- *
- * a small, physically contiguous DMA buffer with random-access, synchronous
- * usage characteristics
- */
-struct dma_prog_region {
-       unsigned char *kvirt;
-       struct pci_dev *dev;
-       unsigned int n_pages;
-       dma_addr_t bus_addr;
-};
-
-/* clear out all fields but do not allocate any memory */
-void dma_prog_region_init(struct dma_prog_region *prog);
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
-                         struct pci_dev *dev);
-void dma_prog_region_free(struct dma_prog_region *prog);
-
-static inline dma_addr_t dma_prog_region_offset_to_bus(
-               struct dma_prog_region *prog, unsigned long offset)
-{
-       return prog->bus_addr + offset;
-}
-
-/**
- * struct dma_region - large non-contiguous DMA buffer
- * @virt:        kernel virtual address
- * @dev:         PCI device
- * @n_pages:     number of kernel pages
- * @n_dma_pages: number of IOMMU pages
- * @sglist:      IOMMU mapping
- * @direction:   PCI_DMA_TODEVICE, etc.
- *
- * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
- * usage characteristics
- */
-struct dma_region {
-       unsigned char *kvirt;
-       struct pci_dev *dev;
-       unsigned int n_pages;
-       unsigned int n_dma_pages;
-       struct scatterlist *sglist;
-       int direction;
-};
-
-void dma_region_init(struct dma_region *dma);
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
-                    struct pci_dev *dev, int direction);
-void dma_region_free(struct dma_region *dma);
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
-                            unsigned long len);
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
-                               unsigned long len);
-int  dma_region_mmap(struct dma_region *dma, struct file *file,
-                    struct vm_area_struct *vma);
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
-                                   unsigned long offset);
-
-/**
- * dma_region_i - macro to index into a DMA region (or dma_prog_region)
- */
-#define dma_region_i(_dma, _type, _index) \
-       ( ((_type*) ((_dma)->kvirt)) + (_index) )
-
-#endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
deleted file mode 100644 (file)
index 18b92cb..0000000
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *   video1394.h - driver for OHCI 1394 boards
- *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                          Peter Schlaile <udbz@rz.uni-karlsruhe.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_PRIVATE_H
-#define _DV_1394_PRIVATE_H
-
-#include "ieee1394.h"
-#include "ohci1394.h"
-#include "dma.h"
-
-/* data structures private to the dv1394 driver */
-/* none of this is exposed to user-space */
-
-
-/*
-   the 8-byte CIP (Common Isochronous Packet) header that precedes
-   each packet of DV data.
-
-   See the IEC 61883 standard.
-*/
-
-struct CIP_header { unsigned char b[8]; };
-
-static inline void fill_cip_header(struct CIP_header *cip,
-                                  unsigned char source_node_id,
-                                  unsigned long counter,
-                                  enum pal_or_ntsc format,
-                                  unsigned long timestamp)
-{
-       cip->b[0] = source_node_id;
-       cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
-       cip->b[2] = 0x00;
-       cip->b[3] = counter;
-
-       cip->b[4] = 0x80; /* const */
-
-       switch(format) {
-       case DV1394_PAL:
-               cip->b[5] = 0x80;
-               break;
-       case DV1394_NTSC:
-               cip->b[5] = 0x00;
-               break;
-       }
-
-       cip->b[6] = timestamp >> 8;
-       cip->b[7] = timestamp & 0xFF;
-}
-
-
-
-/*
-   DMA commands used to program the OHCI's DMA engine
-
-   See the Texas Instruments OHCI 1394 chipset documentation.
-*/
-
-struct output_more_immediate { __le32 q[8]; };
-struct output_more { __le32 q[4]; };
-struct output_last { __le32 q[4]; };
-struct input_more { __le32 q[4]; };
-struct input_last { __le32 q[4]; };
-
-/* outputs */
-
-static inline void fill_output_more_immediate(struct output_more_immediate *omi,
-                                             unsigned char tag,
-                                             unsigned char channel,
-                                             unsigned char sync_tag,
-                                             unsigned int  payload_size)
-{
-       omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
-       omi->q[1] = cpu_to_le32(0);
-       omi->q[2] = cpu_to_le32(0);
-       omi->q[3] = cpu_to_le32(0);
-
-       /* IT packet header */
-       omi->q[4] = cpu_to_le32(  (0x0 << 16)  /* IEEE1394_SPEED_100 */
-                                 | (tag << 14)
-                                 | (channel << 8)
-                                 | (TCODE_ISO_DATA << 4)
-                                 | (sync_tag) );
-
-       /* reserved field; mimic behavior of my Sony DSR-40 */
-       omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
-
-       omi->q[6] = cpu_to_le32(0);
-       omi->q[7] = cpu_to_le32(0);
-}
-
-static inline void fill_output_more(struct output_more *om,
-                                   unsigned int data_size,
-                                   unsigned long data_phys_addr)
-{
-       om->q[0] = cpu_to_le32(data_size);
-       om->q[1] = cpu_to_le32(data_phys_addr);
-       om->q[2] = cpu_to_le32(0);
-       om->q[3] = cpu_to_le32(0);
-}
-
-static inline void fill_output_last(struct output_last *ol,
-                                   int want_timestamp,
-                                   int want_interrupt,
-                                   unsigned int data_size,
-                                   unsigned long data_phys_addr)
-{
-       u32 temp = 0;
-       temp |= 1 << 28; /* OUTPUT_LAST */
-
-       if (want_timestamp) /* controller will update timestamp at DMA time */
-               temp |= 1 << 27;
-
-       if (want_interrupt)
-               temp |= 3 << 20;
-
-       temp |= 3 << 18; /* must take branch */
-       temp |= data_size;
-
-       ol->q[0] = cpu_to_le32(temp);
-       ol->q[1] = cpu_to_le32(data_phys_addr);
-       ol->q[2] = cpu_to_le32(0);
-       ol->q[3] = cpu_to_le32(0);
-}
-
-/* inputs */
-
-static inline void fill_input_more(struct input_more *im,
-                                  int want_interrupt,
-                                  unsigned int data_size,
-                                  unsigned long data_phys_addr)
-{
-       u32 temp =  2 << 28; /* INPUT_MORE */
-       temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-       if (want_interrupt)
-               temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
-       temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
-                              /* disable wait on sync field, not used in DV :-( */
-               temp |= data_size;
-
-       im->q[0] = cpu_to_le32(temp);
-       im->q[1] = cpu_to_le32(data_phys_addr);
-       im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
-       im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-static inline void fill_input_last(struct input_last *il,
-                                   int want_interrupt,
-                                   unsigned int data_size,
-                                   unsigned long data_phys_addr)
-{
-       u32 temp =  3 << 28; /* INPUT_LAST */
-       temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-       if (want_interrupt)
-               temp |= 3 << 20; /* enable interrupts */
-       temp |= 0xC << 16; /* enable branch to address */
-                              /* disable wait on sync field, not used in DV :-( */
-       temp |= data_size;
-
-       il->q[0] = cpu_to_le32(temp);
-       il->q[1] = cpu_to_le32(data_phys_addr);
-       il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
-       il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-
-
-/*
-   A "DMA descriptor block" consists of several contiguous DMA commands.
-   struct DMA_descriptor_block encapsulates all of the commands necessary
-   to send one packet of DV data.
-
-   There are three different types of these blocks:
-
-        1) command to send an empty packet (CIP header only, no DV data):
-
-           OUTPUT_MORE-Immediate <-- contains the iso header in-line
-           OUTPUT_LAST           <-- points to the CIP header
-
-       2) command to send a full packet when the DV data payload does NOT
-          cross a page boundary:
-
-           OUTPUT_MORE-Immediate <-- contains the iso header in-line
-           OUTPUT_MORE           <-- points to the CIP header
-           OUTPUT_LAST           <-- points to entire DV data payload
-
-       3) command to send a full packet when the DV payload DOES cross
-          a page boundary:
-
-           OUTPUT_MORE-Immediate <-- contains the iso header in-line
-           OUTPUT_MORE           <-- points to the CIP header
-           OUTPUT_MORE           <-- points to first part of DV data payload
-           OUTPUT_LAST           <-- points to second part of DV data payload
-
-   This struct describes all three block types using unions.
-
-   !!! It is vital that an even number of these descriptor blocks fit on one
-   page of memory, since a block cannot cross a page boundary !!!
-
- */
-
-struct DMA_descriptor_block {
-
-       union {
-               struct {
-                       /*  iso header, common to all output block types */
-                       struct output_more_immediate omi;
-
-                       union {
-                               /* empty packet */
-                               struct {
-                                       struct output_last ol;  /* CIP header */
-                               } empty;
-
-                               /* full packet */
-                               struct {
-                                       struct output_more om;  /* CIP header */
-
-                                       union {
-                                              /* payload does not cross page boundary */
-                                               struct {
-                                                       struct output_last ol;  /* data payload */
-                                               } nocross;
-
-                                              /* payload crosses page boundary */
-                                               struct {
-                                                       struct output_more om;  /* data payload */
-                                                       struct output_last ol;  /* data payload */
-                                               } cross;
-                                       } u;
-
-                               } full;
-                       } u;
-               } out;
-
-               struct {
-                       struct input_last il;
-               } in;
-
-       } u;
-
-       /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
-          by padding out to 128 bytes */
-       u32 __pad__[12];
-};
-
-
-/* struct frame contains all data associated with one frame in the
-   ringbuffer these are allocated when the DMA context is initialized
-   do_dv1394_init().  They are re-used after the card finishes
-   transmitting the frame. */
-
-struct video_card; /* forward declaration */
-
-struct frame {
-
-       /* points to the struct video_card that owns this frame */
-       struct video_card *video;
-
-       /* index of this frame in video_card->frames[] */
-       unsigned int frame_num;
-
-       /* FRAME_CLEAR - DMA program not set up, waiting for data
-          FRAME_READY - DMA program written, ready to transmit
-
-          Changes to these should be locked against the interrupt
-       */
-       enum {
-               FRAME_CLEAR = 0,
-               FRAME_READY
-       } state;
-
-       /* whether this frame has been DMA'ed already; used only from
-          the IRQ handler to determine whether the frame can be reset */
-       int done;
-
-
-       /* kernel virtual pointer to the start of this frame's data in
-          the user ringbuffer. Use only for CPU access; to get the DMA
-          bus address you must go through the video->user_dma mapping */
-       unsigned long data;
-
-       /* Max # of packets per frame */
-#define MAX_PACKETS 500
-
-
-       /* a PAGE_SIZE memory pool for allocating CIP headers
-          !header_pool must be aligned to PAGE_SIZE! */
-       struct CIP_header *header_pool;
-       dma_addr_t         header_pool_dma;
-
-
-       /* a physically contiguous memory pool for allocating DMA
-          descriptor blocks; usually around 64KB in size
-          !descriptor_pool must be aligned to PAGE_SIZE! */
-       struct DMA_descriptor_block *descriptor_pool;
-       dma_addr_t                   descriptor_pool_dma;
-       unsigned long                descriptor_pool_size;
-
-
-       /* # of packets allocated for this frame */
-       unsigned int n_packets;
-
-
-       /* below are several pointers (kernel virtual addresses, not
-          DMA bus addresses) to parts of the DMA program.  These are
-          set each time the DMA program is written in
-          frame_prepare(). They are used later on, e.g. from the
-          interrupt handler, to check the status of the frame */
-
-       /* points to status/timestamp field of first DMA packet */
-       /* (we'll check it later to monitor timestamp accuracy) */
-       __le32 *frame_begin_timestamp;
-
-       /* the timestamp we assigned to the first packet in the frame */
-       u32 assigned_timestamp;
-
-       /* pointer to the first packet's CIP header (where the timestamp goes) */
-       struct CIP_header *cip_syt1;
-
-       /* pointer to the second packet's CIP header
-          (only set if the first packet was empty) */
-       struct CIP_header *cip_syt2;
-
-       /* in order to figure out what caused an interrupt,
-          store pointers to the status fields of the two packets
-          that can cause interrupts. We'll check these from the
-          interrupt handler.
-       */
-       __le32 *mid_frame_timestamp;
-       __le32 *frame_end_timestamp;
-
-       /* branch address field of final packet. This is effectively
-          the "tail" in the chain of DMA descriptor blocks.
-          We will fill it with the address of the first DMA descriptor
-          block in the subsequent frame, once it is ready.
-       */
-       __le32 *frame_end_branch;
-
-       /* the number of descriptors in the first descriptor block
-          of the frame. Needed to start DMA */
-       int first_n_descriptors;
-};
-
-
-struct packet {
-       __le16  timestamp;
-       u16     invalid;
-       u16     iso_header;
-       __le16  data_length;
-       u32     cip_h1;
-       u32     cip_h2;
-       unsigned char data[480];
-       unsigned char padding[16]; /* force struct size =512 for page alignment */
-};
-
-
-/* allocate/free a frame */
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
-static void frame_delete(struct frame *f);
-
-/* reset f so that it can be used again */
-static void frame_reset(struct frame *f);
-
-/* struct video_card contains all data associated with one instance
-   of the dv1394 driver
-*/
-enum modes {
-       MODE_RECEIVE,
-       MODE_TRANSMIT
-};
-
-struct video_card {
-
-       /* ohci card to which this instance corresponds */
-       struct ti_ohci *ohci;
-
-       /* OHCI card id; the link between the VFS inode and a specific video_card
-          (essentially the device minor number) */
-       int id;
-
-       /* entry in dv1394_cards */
-       struct list_head list;
-
-       /* OHCI card IT DMA context number, -1 if not in use */
-       int ohci_it_ctx;
-       struct ohci1394_iso_tasklet it_tasklet;
-
-       /* register offsets for current IT DMA context, 0 if not in use */
-       u32 ohci_IsoXmitContextControlSet;
-       u32 ohci_IsoXmitContextControlClear;
-       u32 ohci_IsoXmitCommandPtr;
-
-       /* OHCI card IR DMA context number, -1 if not in use */
-       struct ohci1394_iso_tasklet ir_tasklet;
-       int ohci_ir_ctx;
-
-       /* register offsets for current IR DMA context, 0 if not in use */
-       u32 ohci_IsoRcvContextControlSet;
-       u32 ohci_IsoRcvContextControlClear;
-       u32 ohci_IsoRcvCommandPtr;
-       u32 ohci_IsoRcvContextMatch;
-
-
-       /* CONCURRENCY CONTROL */
-
-       /* there are THREE levels of locking associated with video_card. */
-
-       /*
-          1) the 'open' flag - this prevents more than one process from
-          opening the device. (the driver currently assumes only one opener).
-          This is a regular int, but use test_and_set_bit() (on bit zero) 
-          for atomicity.
-        */
-       unsigned long open;
-
-       /*
-          2) the spinlock - this provides mutual exclusion between the interrupt
-          handler and process-context operations. Generally you must take the
-          spinlock under the following conditions:
-            1) DMA (and hence the interrupt handler) may be running
-            AND
-            2) you need to operate on the video_card, especially active_frame
-
-            It is OK to play with video_card without taking the spinlock if
-            you are certain that DMA is not running. Even if DMA is running,
-            it is OK to *read* active_frame with the lock, then drop it
-            immediately. This is safe because the interrupt handler will never
-            advance active_frame onto a frame that is not READY (and the spinlock
-            must be held while marking a frame READY).
-
-            spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
-            which can be accessed from both process and interrupt context
-        */
-       spinlock_t spinlock;
-
-       /* flag to prevent spurious interrupts (which OHCI seems to
-          generate a lot :) from accessing the struct */
-       int dma_running;
-
-       /*
-         3) the sleeping mutex 'mtx' - this is used from process context only,
-         to serialize various operations on the video_card. Even though only one
-         open() is allowed, we still need to prevent multiple threads of execution
-         from entering calls like read, write, ioctl, etc.
-
-         I honestly can't think of a good reason to use dv1394 from several threads
-         at once, but we need to serialize anyway to prevent oopses =).
-
-         NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
-        */
-       struct mutex mtx;
-
-       /* people waiting for buffer space, please form a line here... */
-       wait_queue_head_t waitq;
-
-       /* support asynchronous I/O signals (SIGIO) */
-       struct fasync_struct *fasync;
-
-       /* the large, non-contiguous (rvmalloc()) ringbuffer for DV
-           data, exposed to user-space via mmap() */
-       unsigned long      dv_buf_size;
-       struct dma_region  dv_buf;
-
-       /* next byte in the ringbuffer that a write() call will fill */
-       size_t write_off;
-
-       struct frame *frames[DV1394_MAX_FRAMES];
-
-       /* n_frames also serves as an indicator that this struct video_card is
-          initialized and ready to run DMA buffers */
-
-       int n_frames;
-
-       /* this is the frame that is currently "owned" by the OHCI DMA controller
-          (set to -1 iff DMA is not running)
-
-          ! must lock against the interrupt handler when accessing it !
-
-          RULES:
-
-              Only the interrupt handler may change active_frame if DMA
-                 is running; if not, process may change it
-
-              If the next frame is READY, the interrupt handler will advance
-              active_frame when the current frame is finished.
-
-              If the next frame is CLEAR, the interrupt handler will re-transmit
-              the current frame, and the dropped_frames counter will be  incremented.
-
-              The interrupt handler will NEVER advance active_frame to a
-              frame that is not READY.
-       */
-       int active_frame;
-       int first_run;
-
-       /* the same locking rules apply to these three fields also: */
-
-       /* altered ONLY from process context. Must check first_clear_frame->state;
-          if it's READY, that means the ringbuffer is full with READY frames;
-          if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
-       unsigned int first_clear_frame;
-
-       /* altered both by process and interrupt */
-       unsigned int n_clear_frames;
-
-       /* only altered by the interrupt */
-       unsigned int dropped_frames;
-
-
-
-       /* the CIP accumulator and continuity counter are properties
-          of the DMA stream as a whole (not a single frame), so they
-          are stored here in the video_card */
-
-       unsigned long cip_accum;
-       unsigned long cip_n, cip_d;
-       unsigned int syt_offset;
-       unsigned int continuity_counter;
-
-       enum pal_or_ntsc pal_or_ntsc;
-
-       /* redundant, but simplifies the code somewhat */
-       unsigned int frame_size; /* in bytes */
-
-       /* the isochronous channel to use, -1 if video card is inactive */
-       int channel;
-
-
-       /* physically contiguous packet ringbuffer for receive */
-       struct dma_region packet_buf;
-       unsigned long  packet_buf_size;
-
-       unsigned int current_packet;
-       int first_frame;        /* received first start frame marker? */
-       enum modes mode;
-};
-
-/*
-   if the video_card is not initialized, then the ONLY fields that are valid are:
-   ohci
-   open
-   n_frames
-*/
-
-static inline int video_card_initialized(struct video_card *v)
-{
-       return v->n_frames > 0;
-}
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
-static int do_dv1394_init_default(struct video_card *video);
-static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
-
-
-/* NTSC empty packet rate accurate to within 0.01%,
-   calibrated against a Sony DSR-40 DVCAM deck */
-
-#define CIP_N_NTSC   68000000
-#define CIP_D_NTSC 1068000000
-
-#define CIP_N_PAL  1
-#define CIP_D_PAL 16
-
-#endif /* _DV_1394_PRIVATE_H */
-
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
deleted file mode 100644 (file)
index c5a031b..0000000
+++ /dev/null
@@ -1,2584 +0,0 @@
-/*
- * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *  video1394.c - video driver for OHCI 1394 boards
- *  Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- */
-
-/*
-  OVERVIEW
-
-  I designed dv1394 as a "pipe" that you can use to shoot DV onto a
-  FireWire bus. In transmission mode, dv1394 does the following:
-
-   1. accepts contiguous frames of DV data from user-space, via write()
-      or mmap() (see dv1394.h for the complete API)
-   2. wraps IEC 61883 packets around the DV data, inserting
-      empty synchronization packets as necessary
-   3. assigns accurate SYT timestamps to the outgoing packets
-   4. shoots them out using the OHCI card's IT DMA engine
-
-   Thanks to Dan Dennedy, we now have a receive mode that does the following:
-
-   1. accepts raw IEC 61883 packets from the OHCI card
-   2. re-assembles the DV data payloads into contiguous frames,
-      discarding empty packets
-   3. sends the DV data to user-space via read() or mmap()
-*/
-
-/*
-  TODO:
-
-  - tunable frame-drop behavior: either loop last frame, or halt transmission
-
-  - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
-    so that we don't rely on allocating 64KB of contiguous kernel memory
-    via pci_alloc_consistent()
-
-  DONE:
-  - during reception, better handling of dropped frames and continuity errors
-  - during reception, prevent DMA from bypassing the irq tasklets
-  - reduce irq rate during reception (1/250 packets).
-  - add many more internal buffers during reception with scatter/gather dma.
-  - add dbc (continuity) checking on receive, increment status.dropped_frames
-    if not continuous.
-  - restart IT DMA after a bus reset
-  - safely obtain and release ISO Tx channels in cooperation with OHCI driver
-  - map received DIF blocks to their proper location in DV frame (ensure
-    recovery if dropped packet)
-  - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
-  - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
-  - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
-  - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
-  - set video->id correctly
-  - store video_cards in an array indexed by OHCI card ID, rather than a list
-  - implement DMA context allocation to cooperate with other users of the OHCI
-  - fix all XXX showstoppers
-  - disable IR/IT DMA interrupts on shutdown
-  - flush pci writes to the card by issuing a read
-  - character device dispatching
-  - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
-  - keep all video_cards in a list (for open() via chardev), set file->private_data = video
-  - dv1394_poll should indicate POLLIN when receiving buffers are available
-  - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
-  - expose xmit and recv as separate devices (not exclusive)
-  - expose NTSC and PAL as separate devices (can be overridden)
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dv1394.h"
-#include "dv1394-private.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-
-/* DEBUG LEVELS:
-   0 - no debugging messages
-   1 - some debugging messages, but none during DMA frame transmission
-   2 - lots of messages, including during DMA frame transmission
-       (will cause underflows if your machine is too slow!)
-*/
-
-#define DV1394_DEBUG_LEVEL 0
-
-/* for debugging use ONLY: allow more than one open() of the device */
-/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
-
-#if DV1394_DEBUG_LEVEL >= 2
-#define irq_printk( args... ) printk( args )
-#else
-#define irq_printk( args... ) do {} while (0)
-#endif
-
-#if DV1394_DEBUG_LEVEL >= 1
-#define debug_printk( args... ) printk( args)
-#else
-#define debug_printk( args... ) do {} while (0)
-#endif
-
-/* issue a dummy PCI read to force the preceding write
-   to be posted to the PCI bus immediately */
-
-static inline void flush_pci_write(struct ti_ohci *ohci)
-{
-       mb();
-       reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void it_tasklet_func(unsigned long data);
-static void ir_tasklet_func(unsigned long data);
-
-#ifdef CONFIG_COMPAT
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
-                              unsigned long arg);
-#endif
-
-/* GLOBAL DATA */
-
-/* list of all video_cards */
-static LIST_HEAD(dv1394_cards);
-static DEFINE_SPINLOCK(dv1394_cards_lock);
-
-/* translate from a struct file* to the corresponding struct video_card* */
-
-static inline struct video_card* file_to_video_card(struct file *file)
-{
-       return file->private_data;
-}
-
-/*** FRAME METHODS *********************************************************/
-
-static void frame_reset(struct frame *f)
-{
-       f->state = FRAME_CLEAR;
-       f->done = 0;
-       f->n_packets = 0;
-       f->frame_begin_timestamp = NULL;
-       f->assigned_timestamp = 0;
-       f->cip_syt1 = NULL;
-       f->cip_syt2 = NULL;
-       f->mid_frame_timestamp = NULL;
-       f->frame_end_timestamp = NULL;
-       f->frame_end_branch = NULL;
-}
-
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
-{
-       struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
-       if (!f)
-               return NULL;
-
-       f->video = video;
-       f->frame_num = frame_num;
-
-       f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
-       if (!f->header_pool) {
-               printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
-               kfree(f);
-               return NULL;
-       }
-
-       debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
-                    (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
-
-       f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
-       /* make it an even # of pages */
-       f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
-
-       f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
-                                                 f->descriptor_pool_size,
-                                                 &f->descriptor_pool_dma);
-       if (!f->descriptor_pool) {
-               pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
-               kfree(f);
-               return NULL;
-       }
-
-       debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
-                    (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
-
-       f->data = 0;
-       frame_reset(f);
-
-       return f;
-}
-
-static void frame_delete(struct frame *f)
-{
-       pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
-       pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
-       kfree(f);
-}
-
-
-
-
-/*
-   frame_prepare() - build the DMA program for transmitting
-
-   Frame_prepare() must be called OUTSIDE the video->spinlock.
-   However, frame_prepare() must still be serialized, so
-   it should be called WITH the video->mtx taken.
- */
-
-static void frame_prepare(struct video_card *video, unsigned int this_frame)
-{
-       struct frame *f = video->frames[this_frame];
-       int last_frame;
-
-       struct DMA_descriptor_block *block;
-       dma_addr_t block_dma;
-       struct CIP_header *cip;
-       dma_addr_t cip_dma;
-
-       unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
-
-       /* these flags denote packets that need special attention */
-       int empty_packet, first_packet, last_packet, mid_packet;
-
-       __le32 *branch_address, *last_branch_address = NULL;
-       unsigned long data_p;
-       int first_packet_empty = 0;
-       u32 cycleTimer, ct_sec, ct_cyc, ct_off;
-       unsigned long irq_flags;
-
-       irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
-
-       full_packets = 0;
-
-
-
-       if (video->pal_or_ntsc == DV1394_PAL)
-               packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
-       else
-               packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
-
-       while ( full_packets < packets_per_frame ) {
-               empty_packet = first_packet = last_packet = mid_packet = 0;
-
-               data_p = f->data + full_packets * 480;
-
-               /************************************************/
-               /* allocate a descriptor block and a CIP header */
-               /************************************************/
-
-               /* note: these should NOT cross a page boundary (DMA restriction) */
-
-               if (f->n_packets >= MAX_PACKETS) {
-                       printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
-                       return;
-               }
-
-               /* the block surely won't cross a page boundary,
-                  since an even number of descriptor_blocks fit on a page */
-               block = &(f->descriptor_pool[f->n_packets]);
-
-               /* DMA address of the block = offset of block relative
-                   to the kernel base address of the descriptor pool
-                   + DMA base address of the descriptor pool */
-               block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-
-               /* the whole CIP pool fits on one page, so no worries about boundaries */
-               if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool)
-                   > PAGE_SIZE) {
-                       printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
-                       return;
-               }
-
-               cip = &(f->header_pool[f->n_packets]);
-
-               /* DMA address of the CIP header = offset of cip
-                  relative to kernel base address of the header pool
-                  + DMA base address of the header pool */
-               cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
-
-               /* is this an empty packet? */
-
-               if (video->cip_accum > (video->cip_d - video->cip_n)) {
-                       empty_packet = 1;
-                       payload_size = 8;
-                       video->cip_accum -= (video->cip_d - video->cip_n);
-               } else {
-                       payload_size = 488;
-                       video->cip_accum += video->cip_n;
-               }
-
-               /* there are three important packets each frame:
-
-                  the first packet in the frame - we ask the card to record the timestamp when
-                                                  this packet is actually sent, so we can monitor
-                                                  how accurate our timestamps are. Also, the first
-                                                  packet serves as a semaphore to let us know that
-                                                  it's OK to free the *previous* frame's DMA buffer
-
-                  the last packet in the frame -  this packet is used to detect buffer underflows.
-                                                  if this is the last ready frame, the last DMA block
-                                                  will have a branch back to the beginning of the frame
-                                                  (so that the card will re-send the frame on underflow).
-                                                  if this branch gets taken, we know that at least one
-                                                  frame has been dropped. When the next frame is ready,
-                                                  the branch is pointed to its first packet, and the
-                                                  semaphore is disabled.
-
-                  a "mid" packet slightly before the end of the frame - this packet should trigger
-                                  an interrupt so we can go and assign a timestamp to the first packet
-                                  in the next frame. We don't use the very last packet in the frame
-                                  for this purpose, because that would leave very little time to set
-                                  the timestamp before DMA starts on the next frame.
-               */
-
-               if (f->n_packets == 0) {
-                       first_packet = 1;
-               } else if ( full_packets == (packets_per_frame-1) ) {
-                       last_packet = 1;
-               } else if (f->n_packets == packets_per_frame) {
-                       mid_packet = 1;
-               }
-
-
-               /********************/
-               /* setup CIP header */
-               /********************/
-
-               /* the timestamp will be written later from the
-                  mid-frame interrupt handler. For now we just
-                  store the address of the CIP header(s) that
-                  need a timestamp. */
-
-               /* first packet in the frame needs a timestamp */
-               if (first_packet) {
-                       f->cip_syt1 = cip;
-                       if (empty_packet)
-                               first_packet_empty = 1;
-
-               } else if (first_packet_empty && (f->n_packets == 1) ) {
-                       /* if the first packet was empty, the second
-                          packet's CIP header also needs a timestamp */
-                       f->cip_syt2 = cip;
-               }
-
-               fill_cip_header(cip,
-                               /* the node ID number of the OHCI card */
-                               reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
-                               video->continuity_counter,
-                               video->pal_or_ntsc,
-                               0xFFFF /* the timestamp is filled in later */);
-
-               /* advance counter, only for full packets */
-               if ( ! empty_packet )
-                       video->continuity_counter++;
-
-               /******************************/
-               /* setup DMA descriptor block */
-               /******************************/
-
-               /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
-               fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
-
-               if (empty_packet) {
-                       /* second descriptor - OUTPUT_LAST for CIP header */
-                       fill_output_last( &(block->u.out.u.empty.ol),
-
-                                         /* want completion status on all interesting packets */
-                                         (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                         /* want interrupts on all interesting packets */
-                                         (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                         sizeof(struct CIP_header), /* data size */
-                                         cip_dma);
-
-                       if (first_packet)
-                               f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
-                       else if (mid_packet)
-                               f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
-                       else if (last_packet) {
-                               f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
-                               f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
-                       }
-
-                       branch_address = &(block->u.out.u.empty.ol.q[2]);
-                       n_descriptors = 3;
-                       if (first_packet)
-                               f->first_n_descriptors = n_descriptors;
-
-               } else { /* full packet */
-
-                       /* second descriptor - OUTPUT_MORE for CIP header */
-                       fill_output_more( &(block->u.out.u.full.om),
-                                         sizeof(struct CIP_header), /* data size */
-                                         cip_dma);
-
-
-                       /* third (and possibly fourth) descriptor - for DV data */
-                       /* the 480-byte payload can cross a page boundary; if so,
-                          we need to split it into two DMA descriptors */
-
-                       /* does the 480-byte data payload cross a page boundary? */
-                       if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
-
-                               /* page boundary crossed */
-
-                               fill_output_more( &(block->u.out.u.full.u.cross.om),
-                                                 /* data size - how much of data_p fits on the first page */
-                                                 PAGE_SIZE - (data_p % PAGE_SIZE),
-
-                                                 /* DMA address of data_p */
-                                                 dma_region_offset_to_bus(&video->dv_buf,
-                                                                          data_p - (unsigned long) video->dv_buf.kvirt));
-
-                               fill_output_last( &(block->u.out.u.full.u.cross.ol),
-
-                                                 /* want completion status on all interesting packets */
-                                                 (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                                 /* want interrupt on all interesting packets */
-                                                 (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                                 /* data size - remaining portion of data_p */
-                                                 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
-
-                                                 /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
-                                                 dma_region_offset_to_bus(&video->dv_buf,
-                                                                          data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
-
-                               if (first_packet)
-                                       f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-                               else if (mid_packet)
-                                       f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-                               else if (last_packet) {
-                                       f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-                                       f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
-                               }
-
-                               branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
-
-                               n_descriptors = 5;
-                               if (first_packet)
-                                       f->first_n_descriptors = n_descriptors;
-
-                               full_packets++;
-
-                       } else {
-                               /* fits on one page */
-
-                               fill_output_last( &(block->u.out.u.full.u.nocross.ol),
-
-                                                 /* want completion status on all interesting packets */
-                                                 (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                                 /* want interrupt on all interesting packets */
-                                                 (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-                                                 480, /* data size (480 bytes of DV data) */
-
-
-                                                 /* DMA address of data_p */
-                                                 dma_region_offset_to_bus(&video->dv_buf,
-                                                                          data_p - (unsigned long) video->dv_buf.kvirt));
-
-                               if (first_packet)
-                                       f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-                               else if (mid_packet)
-                                       f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-                               else if (last_packet) {
-                                       f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-                                       f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
-                               }
-
-                               branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
-
-                               n_descriptors = 4;
-                               if (first_packet)
-                                       f->first_n_descriptors = n_descriptors;
-
-                               full_packets++;
-                       }
-               }
-
-               /* link this descriptor block into the DMA program by filling in
-                  the branch address of the previous block */
-
-               /* note: we are not linked into the active DMA chain yet */
-
-               if (last_branch_address) {
-                       *(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
-               }
-
-               last_branch_address = branch_address;
-
-
-               f->n_packets++;
-
-       }
-
-       /* when we first assemble a new frame, set the final branch
-          to loop back up to the top */
-       *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
-       /* make the latest version of this frame visible to the PCI card */
-       dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
-
-       /* lock against DMA interrupt */
-       spin_lock_irqsave(&video->spinlock, irq_flags);
-
-       f->state = FRAME_READY;
-
-       video->n_clear_frames--;
-
-       last_frame = video->first_clear_frame - 1;
-       if (last_frame == -1)
-               last_frame = video->n_frames-1;
-
-       video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-
-       irq_printk("   frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
-                  this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
-
-       irq_printk("   begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
-                  (unsigned long) f->frame_begin_timestamp,
-                  (unsigned long) f->mid_frame_timestamp,
-                  (unsigned long) f->frame_end_timestamp,
-                  (unsigned long) f->frame_end_branch);
-
-       if (video->active_frame != -1) {
-
-               /* if DMA is already active, we are almost done */
-               /* just link us onto the active DMA chain */
-               if (video->frames[last_frame]->frame_end_branch) {
-                       u32 temp;
-
-                       /* point the previous frame's tail to this frame's head */
-                       *(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
-                       /* this write MUST precede the next one, or we could silently drop frames */
-                       wmb();
-
-                       /* disable the want_status semaphore on the last packet */
-                       temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
-                       temp &= 0xF7CFFFFF;
-                       *(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
-
-                       /* flush these writes to memory ASAP */
-                       flush_pci_write(video->ohci);
-
-                       /* NOTE:
-                          ideally the writes should be "atomic": if
-                          the OHCI card reads the want_status flag in
-                          between them, we'll falsely report a
-                          dropped frame. Hopefully this window is too
-                          small to really matter, and the consequence
-                          is rather harmless. */
-
-
-                       irq_printk("     new frame %d linked onto DMA chain\n", this_frame);
-
-               } else {
-                       printk(KERN_ERR "dv1394: last frame not ready???\n");
-               }
-
-       } else {
-
-               u32 transmit_sec, transmit_cyc;
-               u32 ts_cyc;
-
-               /* DMA is stopped, so this is the very first frame */
-               video->active_frame = this_frame;
-
-               /* set CommandPtr to address and size of first descriptor block */
-               reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
-                         video->frames[video->active_frame]->descriptor_pool_dma |
-                         f->first_n_descriptors);
-
-               /* assign a timestamp based on the current cycle time...
-                  We'll tell the card to begin DMA 100 cycles from now,
-                  and assign a timestamp 103 cycles from now */
-
-               cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
-
-               ct_sec = cycleTimer >> 25;
-               ct_cyc = (cycleTimer >> 12) & 0x1FFF;
-               ct_off = cycleTimer & 0xFFF;
-
-               transmit_sec = ct_sec;
-               transmit_cyc = ct_cyc + 100;
-
-               transmit_sec += transmit_cyc/8000;
-               transmit_cyc %= 8000;
-
-               ts_cyc = transmit_cyc + 3;
-               ts_cyc %= 8000;
-
-               f->assigned_timestamp = (ts_cyc&0xF) << 12;
-
-               /* now actually write the timestamp into the appropriate CIP headers */
-               if (f->cip_syt1) {
-                       f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
-                       f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
-               }
-               if (f->cip_syt2) {
-                       f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
-                       f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
-               }
-
-               /* --- start DMA --- */
-
-               /* clear all bits in ContextControl register */
-
-               reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
-               wmb();
-
-               /* the OHCI card has the ability to start ISO transmission on a
-                  particular cycle (start-on-cycle). This way we can ensure that
-                  the first DV frame will have an accurate timestamp.
-
-                  However, start-on-cycle only appears to work if the OHCI card
-                  is cycle master! Since the consequences of messing up the first
-                  timestamp are minimal*, just disable start-on-cycle for now.
-
-                  * my DV deck drops the first few frames before it "locks in;"
-                    so the first frame having an incorrect timestamp is inconsequential.
-               */
-
-#if 0
-               reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
-                         (1 << 31) /* enable start-on-cycle */
-                         | ( (transmit_sec & 0x3) << 29)
-                         | (transmit_cyc << 16));
-               wmb();
-#endif
-
-               video->dma_running = 1;
-
-               /* set the 'run' bit */
-               reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
-               flush_pci_write(video->ohci);
-
-               /* --- DMA should be running now --- */
-
-               debug_printk("    Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
-                            (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
-                            reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-                            reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-
-               debug_printk("    DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
-                            ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
-
-#if DV1394_DEBUG_LEVEL >= 2
-               {
-                       /* check if DMA is really running */
-                       int i = 0;
-                       while (i < 20) {
-                               mb();
-                               mdelay(1);
-                               if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
-                                       printk("DMA ACTIVE after %d msec\n", i);
-                                       break;
-                               }
-                               i++;
-                       }
-
-                       printk("set = %08x, cmdPtr = %08x\n",
-                              reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-                              reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
-                              );
-
-                       if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) &  (1 << 10)) ) {
-                               printk("DMA did NOT go active after 20ms, event = %x\n",
-                                      reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
-                       } else
-                               printk("DMA is RUNNING!\n");
-               }
-#endif
-
-       }
-
-
-       spin_unlock_irqrestore(&video->spinlock, irq_flags);
-}
-
-
-
-/*** RECEIVE FUNCTIONS *****************************************************/
-
-/*
-       frame method put_packet
-
-       map and copy the packet data to its location in the frame
-       based upon DIF section and sequence
-*/
-
-static void inline
-frame_put_packet (struct frame *f, struct packet *p)
-{
-       int section_type = p->data[0] >> 5;           /* section type is in bits 5 - 7 */
-       int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
-       int dif_block = p->data[2];
-
-       /* sanity check */
-       if (dif_sequence > 11 || dif_block > 149) return;
-
-       switch (section_type) {
-       case 0:           /* 1 Header block */
-               memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
-               break;
-
-       case 1:           /* 2 Subcode blocks */
-               memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
-               break;
-
-       case 2:           /* 3 VAUX blocks */
-               memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
-               break;
-
-       case 3:           /* 9 Audio blocks interleaved with video */
-               memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
-               break;
-
-       case 4:           /* 135 Video blocks interleaved with audio */
-               memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
-               break;
-
-       default:           /* we can not handle any other data */
-               break;
-       }
-}
-
-
-static void start_dma_receive(struct video_card *video)
-{
-       if (video->first_run == 1) {
-               video->first_run = 0;
-
-               /* start DMA once all of the frames are READY */
-               video->n_clear_frames = 0;
-               video->first_clear_frame = -1;
-               video->current_packet = 0;
-               video->active_frame = 0;
-
-               /* reset iso recv control register */
-               reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
-               wmb();
-
-               /* clear bufferFill, set isochHeader and speed (0=100) */
-               reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
-
-               /* match on all tags, listen on channel */
-               reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-
-               /* address and first descriptor block + Z=1 */
-               reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
-                         video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
-               wmb();
-
-               video->dma_running = 1;
-
-               /* run */
-               reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
-               flush_pci_write(video->ohci);
-
-               debug_printk("dv1394: DMA started\n");
-
-#if DV1394_DEBUG_LEVEL >= 2
-               {
-                       int i;
-
-                       for (i = 0; i < 1000; ++i) {
-                               mdelay(1);
-                               if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
-                                       printk("DMA ACTIVE after %d msec\n", i);
-                                       break;
-                               }
-                       }
-                       if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-                               printk("DEAD, event = %x\n",
-                                          reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-                       } else
-                               printk("RUNNING!\n");
-               }
-#endif
-       } else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-               debug_printk("DEAD, event = %x\n",
-                            reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
-               /* wake */
-               reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-       }
-}
-
-
-/*
-   receive_packets() - build the DMA program for receiving
-*/
-
-static void receive_packets(struct video_card *video)
-{
-       struct DMA_descriptor_block *block = NULL;
-       dma_addr_t block_dma = 0;
-       struct packet *data = NULL;
-       dma_addr_t data_dma = 0;
-       __le32 *last_branch_address = NULL;
-       unsigned long irq_flags;
-       int want_interrupt = 0;
-       struct frame *f = NULL;
-       int i, j;
-
-       spin_lock_irqsave(&video->spinlock, irq_flags);
-
-       for (j = 0; j < video->n_frames; j++) {
-
-               /* connect frames */
-               if (j > 0 && f != NULL && f->frame_end_branch != NULL)
-                       *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
-
-               f = video->frames[j];
-
-               for (i = 0; i < MAX_PACKETS; i++) {
-                       /* locate a descriptor block and packet from the buffer */
-                       block = &(f->descriptor_pool[i]);
-                       block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-                       data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
-                       data_dma = dma_region_offset_to_bus( &video->packet_buf,
-                                                            ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
-
-                       /* setup DMA descriptor block */
-                       want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
-                       fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
-
-                       /* link descriptors */
-                       last_branch_address = f->frame_end_branch;
-
-                       if (last_branch_address != NULL)
-                               *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
-                       f->frame_end_branch = &(block->u.in.il.q[2]);
-               }
-
-       } /* next j */
-
-       spin_unlock_irqrestore(&video->spinlock, irq_flags);
-
-}
-
-
-
-/*** MANAGEMENT FUNCTIONS **************************************************/
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
-{
-       unsigned long flags, new_buf_size;
-       int i;
-       u64 chan_mask;
-       int retval = -EINVAL;
-
-       debug_printk("dv1394: initialising %d\n", video->id);
-       if (init->api_version != DV1394_API_VERSION)
-               return -EINVAL;
-
-       /* first sanitize all the parameters */
-       if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
-               return -EINVAL;
-
-       if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
-               return -EINVAL;
-
-       if ( (init->syt_offset == 0) || (init->syt_offset > 50) )
-               /* default SYT offset is 3 cycles */
-               init->syt_offset = 3;
-
-       if (init->channel > 63)
-               init->channel = 63;
-
-       chan_mask = (u64)1 << init->channel;
-
-       /* calculate what size DMA buffer is needed */
-       if (init->format == DV1394_NTSC)
-               new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
-       else
-               new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
-
-       /* round up to PAGE_SIZE */
-       if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
-
-       /* don't allow the user to allocate the DMA buffer more than once */
-       if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
-               printk("dv1394: re-sizing the DMA buffer is not allowed\n");
-               return -EINVAL;
-       }
-
-       /* shutdown the card if it's currently active */
-       /* (the card should not be reset if the parameters are screwy) */
-
-       do_dv1394_shutdown(video, 0);
-
-       /* try to claim the ISO channel */
-       spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-       if (video->ohci->ISO_channel_usage & chan_mask) {
-               spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-               retval = -EBUSY;
-               goto err;
-       }
-       video->ohci->ISO_channel_usage |= chan_mask;
-       spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
-       video->channel = init->channel;
-
-       /* initialize misc. fields of video */
-       video->n_frames = init->n_frames;
-       video->pal_or_ntsc = init->format;
-
-       video->cip_accum = 0;
-       video->continuity_counter = 0;
-
-       video->active_frame = -1;
-       video->first_clear_frame = 0;
-       video->n_clear_frames = video->n_frames;
-       video->dropped_frames = 0;
-
-       video->write_off = 0;
-
-       video->first_run = 1;
-       video->current_packet = -1;
-       video->first_frame = 0;
-
-       if (video->pal_or_ntsc == DV1394_NTSC) {
-               video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
-               video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
-               video->frame_size = DV1394_NTSC_FRAME_SIZE;
-       } else {
-               video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
-               video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
-               video->frame_size = DV1394_PAL_FRAME_SIZE;
-       }
-
-       video->syt_offset = init->syt_offset;
-
-       /* find and claim DMA contexts on the OHCI card */
-
-       if (video->ohci_it_ctx == -1) {
-               ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
-                                         it_tasklet_func, (unsigned long) video);
-
-               if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {
-                       printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
-                       retval = -EBUSY;
-                       goto err;
-               }
-
-               video->ohci_it_ctx = video->it_tasklet.context;
-               debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
-       }
-
-       if (video->ohci_ir_ctx == -1) {
-               ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
-                                         ir_tasklet_func, (unsigned long) video);
-
-               if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
-                       printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
-                       retval = -EBUSY;
-                       goto err;
-               }
-               video->ohci_ir_ctx = video->ir_tasklet.context;
-               debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
-       }
-
-       /* allocate struct frames */
-       for (i = 0; i < init->n_frames; i++) {
-               video->frames[i] = frame_new(i, video);
-
-               if (!video->frames[i]) {
-                       printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
-                       retval = -ENOMEM;
-                       goto err;
-               }
-       }
-
-       if (!video->dv_buf.kvirt) {
-               /* allocate the ringbuffer */
-               retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
-               if (retval)
-                       goto err;
-
-               video->dv_buf_size = new_buf_size;
-
-               debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
-                            video->n_frames, video->dv_buf.n_pages,
-                            video->dv_buf.n_dma_pages, video->dv_buf_size);
-       }
-
-       /* set up the frame->data pointers */
-       for (i = 0; i < video->n_frames; i++)
-               video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
-
-       if (!video->packet_buf.kvirt) {
-               /* allocate packet buffer */
-               video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
-               if (video->packet_buf_size % PAGE_SIZE)
-                       video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
-
-               retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
-                                         video->ohci->dev, PCI_DMA_FROMDEVICE);
-               if (retval)
-                       goto err;
-
-               debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n",
-                                video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
-                                video->packet_buf.n_dma_pages, video->packet_buf_size);
-       }
-
-       /* set up register offsets for IT context */
-       /* IT DMA context registers are spaced 16 bytes apart */
-       video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
-       video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
-       video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
-
-       /* enable interrupts for IT context */
-       reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
-       debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
-
-       /* set up register offsets for IR context */
-       /* IR DMA context registers are spaced 32 bytes apart */
-       video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
-       video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
-       video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
-       video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
-
-       /* enable interrupts for IR context */
-       reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
-       debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
-
-       return 0;
-
-err:
-       do_dv1394_shutdown(video, 1);
-       return retval;
-}
-
-/* if the user doesn't bother to call ioctl(INIT) before starting
-   mmap() or read()/write(), just give him some default values */
-
-static int do_dv1394_init_default(struct video_card *video)
-{
-       struct dv1394_init init;
-
-       init.api_version = DV1394_API_VERSION;
-       init.n_frames = DV1394_MAX_FRAMES / 4;
-       init.channel = video->channel;
-       init.format = video->pal_or_ntsc;
-       init.cip_n = video->cip_n;
-       init.cip_d = video->cip_d;
-       init.syt_offset = video->syt_offset;
-
-       return do_dv1394_init(video, &init);
-}
-
-/* do NOT call from interrupt context */
-static void stop_dma(struct video_card *video)
-{
-       unsigned long flags;
-       int i;
-
-       /* no interrupts */
-       spin_lock_irqsave(&video->spinlock, flags);
-
-       video->dma_running = 0;
-
-       if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
-               goto out;
-
-       /* stop DMA if in progress */
-       if ( (video->active_frame != -1) ||
-           (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
-           (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) &  (1 << 10)) ) {
-
-               /* clear the .run bits */
-               reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
-               reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
-               flush_pci_write(video->ohci);
-
-               video->active_frame = -1;
-               video->first_run = 1;
-
-               /* wait until DMA really stops */
-               i = 0;
-               while (i < 1000) {
-
-                       /* wait 0.1 millisecond */
-                       udelay(100);
-
-                       if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
-                           (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
-                               /* still active */
-                               debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
-                               mb();
-                       } else {
-                               debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
-                               break;
-                       }
-
-                       i++;
-               }
-
-               if (i == 1000) {
-                       printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
-               }
-       }
-       else
-               debug_printk("dv1394: stop_dma: already stopped.\n");
-
-out:
-       spin_unlock_irqrestore(&video->spinlock, flags);
-}
-
-
-
-static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
-{
-       int i;
-
-       debug_printk("dv1394: shutdown...\n");
-
-       /* stop DMA if in progress */
-       stop_dma(video);
-
-       /* release the DMA contexts */
-       if (video->ohci_it_ctx != -1) {
-               video->ohci_IsoXmitContextControlSet = 0;
-               video->ohci_IsoXmitContextControlClear = 0;
-               video->ohci_IsoXmitCommandPtr = 0;
-
-               /* disable interrupts for IT context */
-               reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
-
-               /* remove tasklet */
-               ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
-               debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
-               video->ohci_it_ctx = -1;
-       }
-
-       if (video->ohci_ir_ctx != -1) {
-               video->ohci_IsoRcvContextControlSet = 0;
-               video->ohci_IsoRcvContextControlClear = 0;
-               video->ohci_IsoRcvCommandPtr = 0;
-               video->ohci_IsoRcvContextMatch = 0;
-
-               /* disable interrupts for IR context */
-               reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
-
-               /* remove tasklet */
-               ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
-               debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
-               video->ohci_ir_ctx = -1;
-       }
-
-       /* release the ISO channel */
-       if (video->channel != -1) {
-               u64 chan_mask;
-               unsigned long flags;
-
-               chan_mask = (u64)1 << video->channel;
-
-               spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-               video->ohci->ISO_channel_usage &= ~(chan_mask);
-               spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
-               video->channel = -1;
-       }
-
-       /* free the frame structs */
-       for (i = 0; i < DV1394_MAX_FRAMES; i++) {
-               if (video->frames[i])
-                       frame_delete(video->frames[i]);
-               video->frames[i] = NULL;
-       }
-
-       video->n_frames = 0;
-
-       /* we can't free the DMA buffer unless it is guaranteed that
-          no more user-space mappings exist */
-
-       if (free_dv_buf) {
-               dma_region_free(&video->dv_buf);
-               video->dv_buf_size = 0;
-       }
-
-       /* free packet buffer */
-       dma_region_free(&video->packet_buf);
-       video->packet_buf_size = 0;
-
-       debug_printk("dv1394: shutdown OK\n");
-}
-
-/*
-       **********************************
-       *** MMAP() THEORY OF OPERATION ***
-       **********************************
-
-        The ringbuffer cannot be re-allocated or freed while
-        a user program maintains a mapping of it. (note that a mapping
-       can persist even after the device fd is closed!)
-
-       So, only let the user process allocate the DMA buffer once.
-       To resize or deallocate it, you must close the device file
-       and open it again.
-
-       Previously Dan M. hacked out a scheme that allowed the DMA
-       buffer to change by forcefully unmapping it from the user's
-       address space. It was prone to error because it's very hard to
-       track all the places the buffer could have been mapped (we
-       would have had to walk the vma list of every process in the
-       system to be sure we found all the mappings!). Instead, we
-       force the user to choose one buffer size and stick with
-       it. This small sacrifice is worth the huge reduction in
-       error-prone code in dv1394.
-*/
-
-static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_card *video = file_to_video_card(file);
-       int retval = -EINVAL;
-
-       /*
-        * We cannot use the blocking variant mutex_lock here because .mmap
-        * is called with mmap_sem held, while .ioctl, .read, .write acquire
-        * video->mtx and subsequently call copy_to/from_user which will
-        * grab mmap_sem in case of a page fault.
-        */
-       if (!mutex_trylock(&video->mtx))
-               return -EAGAIN;
-
-       if ( ! video_card_initialized(video) ) {
-               retval = do_dv1394_init_default(video);
-               if (retval)
-                       goto out;
-       }
-
-       retval = dma_region_mmap(&video->dv_buf, file, vma);
-out:
-       mutex_unlock(&video->mtx);
-       return retval;
-}
-
-/*** DEVICE FILE INTERFACE *************************************************/
-
-/* no need to serialize, multiple threads OK */
-static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct video_card *video = file_to_video_card(file);
-       unsigned int mask = 0;
-       unsigned long flags;
-
-       poll_wait(file, &video->waitq, wait);
-
-       spin_lock_irqsave(&video->spinlock, flags);
-       if ( video->n_frames == 0 ) {
-
-       } else if ( video->active_frame == -1 ) {
-               /* nothing going on */
-               mask |= POLLOUT;
-       } else {
-               /* any clear/ready buffers? */
-               if (video->n_clear_frames >0)
-                       mask |= POLLOUT | POLLIN;
-       }
-       spin_unlock_irqrestore(&video->spinlock, flags);
-
-       return mask;
-}
-
-static int dv1394_fasync(int fd, struct file *file, int on)
-{
-       /* I just copied this code verbatim from Alan Cox's mouse driver example
-          (Documentation/DocBook/) */
-
-       struct video_card *video = file_to_video_card(file);
-
-       return fasync_helper(fd, file, on, &video->fasync);
-}
-
-static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct video_card *video = file_to_video_card(file);
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t ret;
-       size_t cnt;
-       unsigned long flags;
-       int target_frame;
-
-       /* serialize this to prevent multi-threaded mayhem */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&video->mtx))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&video->mtx))
-                       return -ERESTARTSYS;
-       }
-
-       if ( !video_card_initialized(video) ) {
-               ret = do_dv1394_init_default(video);
-               if (ret) {
-                       mutex_unlock(&video->mtx);
-                       return ret;
-               }
-       }
-
-       ret = 0;
-       add_wait_queue(&video->waitq, &wait);
-
-       while (count > 0) {
-
-               /* must set TASK_INTERRUPTIBLE *before* checking for free
-                  buffers; otherwise we could miss a wakeup if the interrupt
-                  fires between the check and the schedule() */
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               spin_lock_irqsave(&video->spinlock, flags);
-
-               target_frame = video->first_clear_frame;
-
-               spin_unlock_irqrestore(&video->spinlock, flags);
-
-               if (video->frames[target_frame]->state == FRAME_CLEAR) {
-
-                       /* how much room is left in the target frame buffer */
-                       cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
-               } else {
-                       /* buffer is already used */
-                       cnt = 0;
-               }
-
-               if (cnt > count)
-                       cnt = count;
-
-               if (cnt <= 0) {
-                       /* no room left, gotta wait */
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               break;
-                       }
-
-                       schedule();
-
-                       continue; /* start over from 'while(count > 0)...' */
-               }
-
-               if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-
-               video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-
-               if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
-                               frame_prepare(video, target_frame);
-       }
-
-       remove_wait_queue(&video->waitq, &wait);
-       set_current_state(TASK_RUNNING);
-       mutex_unlock(&video->mtx);
-       return ret;
-}
-
-
-static ssize_t dv1394_read(struct file *file,  char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct video_card *video = file_to_video_card(file);
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t ret;
-       size_t cnt;
-       unsigned long flags;
-       int target_frame;
-
-       /* serialize this to prevent multi-threaded mayhem */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&video->mtx))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&video->mtx))
-                       return -ERESTARTSYS;
-       }
-
-       if ( !video_card_initialized(video) ) {
-               ret = do_dv1394_init_default(video);
-               if (ret) {
-                       mutex_unlock(&video->mtx);
-                       return ret;
-               }
-               video->continuity_counter = -1;
-
-               receive_packets(video);
-
-               start_dma_receive(video);
-       }
-
-       ret = 0;
-       add_wait_queue(&video->waitq, &wait);
-
-       while (count > 0) {
-
-               /* must set TASK_INTERRUPTIBLE *before* checking for free
-                  buffers; otherwise we could miss a wakeup if the interrupt
-                  fires between the check and the schedule() */
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               spin_lock_irqsave(&video->spinlock, flags);
-
-               target_frame = video->first_clear_frame;
-
-               spin_unlock_irqrestore(&video->spinlock, flags);
-
-               if (target_frame >= 0 &&
-                       video->n_clear_frames > 0 &&
-                       video->frames[target_frame]->state == FRAME_CLEAR) {
-
-                       /* how much room is left in the target frame buffer */
-                       cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
-               } else {
-                       /* buffer is already used */
-                       cnt = 0;
-               }
-
-               if (cnt > count)
-                       cnt = count;
-
-               if (cnt <= 0) {
-                       /* no room left, gotta wait */
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               break;
-                       }
-
-                       schedule();
-
-                       continue; /* start over from 'while(count > 0)...' */
-               }
-
-               if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-               }
-
-               video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-
-               if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
-                       spin_lock_irqsave(&video->spinlock, flags);
-                       video->n_clear_frames--;
-                       video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-                       spin_unlock_irqrestore(&video->spinlock, flags);
-               }
-       }
-
-       remove_wait_queue(&video->waitq, &wait);
-       set_current_state(TASK_RUNNING);
-       mutex_unlock(&video->mtx);
-       return ret;
-}
-
-
-/*** DEVICE IOCTL INTERFACE ************************************************/
-
-static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct video_card *video = file_to_video_card(file);
-       unsigned long flags;
-       int ret = -EINVAL;
-       void __user *argp = (void __user *)arg;
-
-       DECLARE_WAITQUEUE(wait, current);
-
-       /* serialize this to prevent multi-threaded mayhem */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&video->mtx))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&video->mtx))
-                       return -ERESTARTSYS;
-       }
-
-       switch(cmd)
-       {
-       case DV1394_IOC_SUBMIT_FRAMES: {
-               unsigned int n_submit;
-
-               if ( !video_card_initialized(video) ) {
-                       ret = do_dv1394_init_default(video);
-                       if (ret)
-                               goto out;
-               }
-
-               n_submit = (unsigned int) arg;
-
-               if (n_submit > video->n_frames) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               while (n_submit > 0) {
-
-                       add_wait_queue(&video->waitq, &wait);
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       spin_lock_irqsave(&video->spinlock, flags);
-
-                       /* wait until video->first_clear_frame is really CLEAR */
-                       while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
-
-                               spin_unlock_irqrestore(&video->spinlock, flags);
-
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&video->waitq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       ret = -EINTR;
-                                       goto out;
-                               }
-
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-
-                               spin_lock_irqsave(&video->spinlock, flags);
-                       }
-                       spin_unlock_irqrestore(&video->spinlock, flags);
-
-                       remove_wait_queue(&video->waitq, &wait);
-                       set_current_state(TASK_RUNNING);
-
-                       frame_prepare(video, video->first_clear_frame);
-
-                       n_submit--;
-               }
-
-               ret = 0;
-               break;
-       }
-
-       case DV1394_IOC_WAIT_FRAMES: {
-               unsigned int n_wait;
-
-               if ( !video_card_initialized(video) ) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               n_wait = (unsigned int) arg;
-
-               /* since we re-run the last frame on underflow, we will
-                  never actually have n_frames clear frames; at most only
-                  n_frames - 1 */
-
-               if (n_wait > (video->n_frames-1) ) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               add_wait_queue(&video->waitq, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               spin_lock_irqsave(&video->spinlock, flags);
-
-               while (video->n_clear_frames < n_wait) {
-
-                       spin_unlock_irqrestore(&video->spinlock, flags);
-
-                       if (signal_pending(current)) {
-                               remove_wait_queue(&video->waitq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               ret = -EINTR;
-                               goto out;
-                       }
-
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       spin_lock_irqsave(&video->spinlock, flags);
-               }
-
-               spin_unlock_irqrestore(&video->spinlock, flags);
-
-               remove_wait_queue(&video->waitq, &wait);
-               set_current_state(TASK_RUNNING);
-               ret = 0;
-               break;
-       }
-
-       case DV1394_IOC_RECEIVE_FRAMES: {
-               unsigned int n_recv;
-
-               if ( !video_card_initialized(video) ) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               n_recv = (unsigned int) arg;
-
-               /* at least one frame must be active */
-               if (n_recv > (video->n_frames-1) ) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               spin_lock_irqsave(&video->spinlock, flags);
-
-               /* release the clear frames */
-               video->n_clear_frames -= n_recv;
-
-               /* advance the clear frame cursor */
-               video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
-
-               /* reset dropped_frames */
-               video->dropped_frames = 0;
-
-               spin_unlock_irqrestore(&video->spinlock, flags);
-
-               ret = 0;
-               break;
-       }
-
-       case DV1394_IOC_START_RECEIVE: {
-               if ( !video_card_initialized(video) ) {
-                       ret = do_dv1394_init_default(video);
-                       if (ret)
-                               goto out;
-               }
-
-               video->continuity_counter = -1;
-
-               receive_packets(video);
-
-               start_dma_receive(video);
-
-               ret = 0;
-               break;
-       }
-
-       case DV1394_IOC_INIT: {
-               struct dv1394_init init;
-               if (!argp) {
-                       ret = do_dv1394_init_default(video);
-               } else {
-                       if (copy_from_user(&init, argp, sizeof(init))) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       ret = do_dv1394_init(video, &init);
-               }
-               break;
-       }
-
-       case DV1394_IOC_SHUTDOWN:
-               do_dv1394_shutdown(video, 0);
-               ret = 0;
-               break;
-
-
-        case DV1394_IOC_GET_STATUS: {
-               struct dv1394_status status;
-
-               if ( !video_card_initialized(video) ) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               status.init.api_version = DV1394_API_VERSION;
-               status.init.channel = video->channel;
-               status.init.n_frames = video->n_frames;
-               status.init.format = video->pal_or_ntsc;
-               status.init.cip_n = video->cip_n;
-               status.init.cip_d = video->cip_d;
-               status.init.syt_offset = video->syt_offset;
-
-               status.first_clear_frame = video->first_clear_frame;
-
-               /* the rest of the fields need to be locked against the interrupt */
-               spin_lock_irqsave(&video->spinlock, flags);
-
-               status.active_frame = video->active_frame;
-               status.n_clear_frames = video->n_clear_frames;
-
-               status.dropped_frames = video->dropped_frames;
-
-               /* reset dropped_frames */
-               video->dropped_frames = 0;
-
-               spin_unlock_irqrestore(&video->spinlock, flags);
-
-               if (copy_to_user(argp, &status, sizeof(status))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               ret = 0;
-               break;
-       }
-
-       default:
-               break;
-       }
-
- out:
-       mutex_unlock(&video->mtx);
-       return ret;
-}
-
-/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
-
-static int dv1394_open(struct inode *inode, struct file *file)
-{
-       struct video_card *video = NULL;
-
-       if (file->private_data) {
-               video = file->private_data;
-
-       } else {
-               /* look up the card by ID */
-               unsigned long flags;
-               int idx = ieee1394_file_to_instance(file);
-
-               spin_lock_irqsave(&dv1394_cards_lock, flags);
-               if (!list_empty(&dv1394_cards)) {
-                       struct video_card *p;
-                       list_for_each_entry(p, &dv1394_cards, list) {
-                               if ((p->id) == idx) {
-                                       video = p;
-                                       break;
-                               }
-                       }
-               }
-               spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-               if (!video) {
-                       debug_printk("dv1394: OHCI card %d not found", idx);
-                       return -ENODEV;
-               }
-
-               file->private_data = (void*) video;
-       }
-
-#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
-
-       if ( test_and_set_bit(0, &video->open) ) {
-               /* video is already open by someone else */
-               return -EBUSY;
-       }
-
-#endif
-
-       printk(KERN_INFO "%s: NOTE, the dv1394 interface is unsupported "
-              "and will not be available in the new firewire driver stack. "
-              "Try libraw1394 based programs instead.\n", current->comm);
-
-       return nonseekable_open(inode, file);
-}
-
-
-static int dv1394_release(struct inode *inode, struct file *file)
-{
-       struct video_card *video = file_to_video_card(file);
-
-       /* OK to free the DMA buffer, no more mappings can exist */
-       do_dv1394_shutdown(video, 1);
-
-       /* give someone else a turn */
-       clear_bit(0, &video->open);
-
-       return 0;
-}
-
-
-/*** DEVICE DRIVER HANDLERS ************************************************/
-
-static void it_tasklet_func(unsigned long data)
-{
-       int wake = 0;
-       struct video_card *video = (struct video_card*) data;
-
-       spin_lock(&video->spinlock);
-
-       if (!video->dma_running)
-               goto out;
-
-       irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
-              reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-              reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
-              );
-
-
-       if ( (video->ohci_it_ctx != -1) &&
-           (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
-
-               struct frame *f;
-               unsigned int frame, i;
-
-
-               if (video->active_frame == -1)
-                       frame = 0;
-               else
-                       frame = video->active_frame;
-
-               /* check all the DMA-able frames */
-               for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
-
-                       irq_printk("IRQ checking frame %d...", frame);
-                       f = video->frames[frame];
-                       if (f->state != FRAME_READY) {
-                               irq_printk("clear, skipping\n");
-                               /* we don't own this frame */
-                               continue;
-                       }
-
-                       irq_printk("DMA\n");
-
-                       /* check the frame begin semaphore to see if we can free the previous frame */
-                       if ( *(f->frame_begin_timestamp) ) {
-                               int prev_frame;
-                               struct frame *prev_f;
-
-
-
-                               /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
-                               irq_printk("  BEGIN\n");
-
-                               prev_frame = frame - 1;
-                               if (prev_frame == -1)
-                                       prev_frame += video->n_frames;
-                               prev_f = video->frames[prev_frame];
-
-                               /* make sure we can actually garbage collect
-                                  this frame */
-                               if ( (prev_f->state == FRAME_READY) &&
-                                   prev_f->done && (!f->done) )
-                               {
-                                       frame_reset(prev_f);
-                                       video->n_clear_frames++;
-                                       wake = 1;
-                                       video->active_frame = frame;
-
-                                       irq_printk("  BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
-                               } else {
-                                       irq_printk("  BEGIN - can't free yet\n");
-                               }
-
-                               f->done = 1;
-                       }
-
-
-                       /* see if we need to set the timestamp for the next frame */
-                       if ( *(f->mid_frame_timestamp) ) {
-                               struct frame *next_frame;
-                               u32 begin_ts, ts_cyc, ts_off;
-
-                               *(f->mid_frame_timestamp) = 0;
-
-                               begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
-
-                               irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
-                                          begin_ts & 0x1FFF, begin_ts & 0xF,
-                                          f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
-
-                               /* prepare next frame and assign timestamp */
-                               next_frame = video->frames[ (frame+1) % video->n_frames ];
-
-                               if (next_frame->state == FRAME_READY) {
-                                       irq_printk("  MIDDLE - next frame is ready, good\n");
-                               } else {
-                                       debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
-                                       next_frame = f;
-                               }
-
-                               /* set the timestamp to the timestamp of the last frame sent,
-                                  plus the length of the last frame sent, plus the syt latency */
-                               ts_cyc = begin_ts & 0xF;
-                               /* advance one frame, plus syt latency (typically 2-3) */
-                               ts_cyc += f->n_packets + video->syt_offset ;
-
-                               ts_off = 0;
-
-                               ts_cyc += ts_off/3072;
-                               ts_off %= 3072;
-
-                               next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
-                               if (next_frame->cip_syt1) {
-                                       next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
-                                       next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
-                               }
-                               if (next_frame->cip_syt2) {
-                                       next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
-                                       next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
-                               }
-
-                       }
-
-                       /* see if the frame looped */
-                       if ( *(f->frame_end_timestamp) ) {
-
-                               *(f->frame_end_timestamp) = 0;
-
-                               debug_printk("  END - the frame looped at least once\n");
-
-                               video->dropped_frames++;
-                       }
-
-               } /* for (each frame) */
-       }
-
-       if (wake) {
-               kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-
-               /* wake readers/writers/ioctl'ers */
-               wake_up_interruptible(&video->waitq);
-       }
-
-out:
-       spin_unlock(&video->spinlock);
-}
-
-static void ir_tasklet_func(unsigned long data)
-{
-       int wake = 0;
-       struct video_card *video = (struct video_card*) data;
-
-       spin_lock(&video->spinlock);
-
-       if (!video->dma_running)
-               goto out;
-
-       if ( (video->ohci_ir_ctx != -1) &&
-           (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
-
-               int sof=0; /* start-of-frame flag */
-               struct frame *f;
-               u16 packet_length;
-               int i, dbc=0;
-               struct DMA_descriptor_block *block = NULL;
-               u16 xferstatus;
-
-               int next_i, prev_i;
-               struct DMA_descriptor_block *next = NULL;
-               dma_addr_t next_dma = 0;
-               struct DMA_descriptor_block *prev = NULL;
-
-               /* loop over all descriptors in all frames */
-               for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
-                       struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
-
-                       /* make sure we are seeing the latest changes to p */
-                       dma_region_sync_for_cpu(&video->packet_buf,
-                                               (unsigned long) p - (unsigned long) video->packet_buf.kvirt,
-                                               sizeof(struct packet));
-
-                       packet_length = le16_to_cpu(p->data_length);
-
-                       /* get the descriptor based on packet_buffer cursor */
-                       f = video->frames[video->current_packet / MAX_PACKETS];
-                       block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
-                       xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
-                       xferstatus &= 0x1F;
-                       irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
-
-                       /* get the current frame */
-                       f = video->frames[video->active_frame];
-
-                       /* exclude empty packet */
-                       if (packet_length > 8 && xferstatus == 0x11) {
-                               /* check for start of frame */
-                               /* DRD> Changed to check section type ([0]>>5==0)
-                                  and dif sequence ([1]>>4==0) */
-                               sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
-
-                               dbc = (int) (p->cip_h1 >> 24);
-                               if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
-                               {
-                                       printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
-                                       video->dropped_frames += video->n_clear_frames + 1;
-                                       video->first_frame = 0;
-                                       video->n_clear_frames = 0;
-                                       video->first_clear_frame = -1;
-                               }
-                               video->continuity_counter = dbc;
-
-                               if (!video->first_frame) {
-                                       if (sof) {
-                                               video->first_frame = 1;
-                                       }
-
-                               } else if (sof) {
-                                       /* close current frame */
-                                       frame_reset(f);  /* f->state = STATE_CLEAR */
-                                       video->n_clear_frames++;
-                                       if (video->n_clear_frames > video->n_frames) {
-                                               video->dropped_frames++;
-                                               printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
-                                               video->n_clear_frames = video->n_frames-1;
-                                               video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-                                       }
-                                       if (video->first_clear_frame == -1)
-                                               video->first_clear_frame = video->active_frame;
-
-                                       /* get the next frame */
-                                       video->active_frame = (video->active_frame + 1) % video->n_frames;
-                                       f = video->frames[video->active_frame];
-                                       irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
-                                                  video->active_frame, video->n_clear_frames, video->first_clear_frame);
-                               }
-                               if (video->first_frame) {
-                                       if (sof) {
-                                               /* open next frame */
-                                               f->state = FRAME_READY;
-                                       }
-
-                                       /* copy to buffer */
-                                       if (f->n_packets > (video->frame_size / 480)) {
-                                               printk(KERN_ERR "frame buffer overflow during receive\n");
-                                       }
-
-                                       frame_put_packet(f, p);
-
-                               } /* first_frame */
-                       }
-
-                       /* stop, end of ready packets */
-                       else if (xferstatus == 0) {
-                               break;
-                       }
-
-                       /* reset xferStatus & resCount */
-                       block->u.in.il.q[3] = cpu_to_le32(512);
-
-                       /* terminate dma chain at this (next) packet */
-                       next_i = video->current_packet;
-                       f = video->frames[next_i / MAX_PACKETS];
-                       next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
-                       next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-                       next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
-                       next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */
-
-                       /* link previous to next */
-                       prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
-                       f = video->frames[prev_i / MAX_PACKETS];
-                       prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
-                       if (prev_i % (MAX_PACKETS/2)) {
-                               prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */
-                       } else {
-                               prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
-                       }
-                       prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
-                       wmb();
-
-                       /* wake up DMA in case it fell asleep */
-                       reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-
-                       /* advance packet_buffer cursor */
-                       video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
-
-               } /* for all packets */
-
-               wake = 1; /* why the hell not? */
-
-       } /* receive interrupt */
-
-       if (wake) {
-               kill_fasync(&video->fasync, SIGIO, POLL_IN);
-
-               /* wake readers/writers/ioctl'ers */
-               wake_up_interruptible(&video->waitq);
-       }
-
-out:
-       spin_unlock(&video->spinlock);
-}
-
-static struct cdev dv1394_cdev;
-static const struct file_operations dv1394_fops=
-{
-       .owner =        THIS_MODULE,
-       .poll =         dv1394_poll,
-       .unlocked_ioctl = dv1394_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = dv1394_compat_ioctl,
-#endif
-       .mmap =         dv1394_mmap,
-       .open =         dv1394_open,
-       .write =        dv1394_write,
-       .read =         dv1394_read,
-       .release =      dv1394_release,
-       .fasync =       dv1394_fasync,
-       .llseek =       no_llseek,
-};
-
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id dv1394_id_table[] = {
-       {
-               .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
-               .version        = AVC_SW_VERSION_ENTRY & 0xffffff
-       },
-       { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver dv1394_driver = {
-       .name = "dv1394",
-};
-
-
-/*** IEEE1394 HPSB CALLBACKS ***********************************************/
-
-static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
-{
-       struct video_card *video;
-       unsigned long flags;
-       int i;
-
-       video = kzalloc(sizeof(*video), GFP_KERNEL);
-       if (!video) {
-               printk(KERN_ERR "dv1394: cannot allocate video_card\n");
-               return -1;
-       }
-
-       video->ohci = ohci;
-       /* lower 2 bits of id indicate which of four "plugs"
-          per host */
-       video->id = ohci->host->id << 2;
-       if (format == DV1394_NTSC)
-               video->id |= mode;
-       else
-               video->id |= 2 + mode;
-
-       video->ohci_it_ctx = -1;
-       video->ohci_ir_ctx = -1;
-
-       video->ohci_IsoXmitContextControlSet = 0;
-       video->ohci_IsoXmitContextControlClear = 0;
-       video->ohci_IsoXmitCommandPtr = 0;
-
-       video->ohci_IsoRcvContextControlSet = 0;
-       video->ohci_IsoRcvContextControlClear = 0;
-       video->ohci_IsoRcvCommandPtr = 0;
-       video->ohci_IsoRcvContextMatch = 0;
-
-       video->n_frames = 0; /* flag that video is not initialized */
-       video->channel = 63; /* default to broadcast channel */
-       video->active_frame = -1;
-
-       /* initialize the following */
-       video->pal_or_ntsc = format;
-       video->cip_n = 0; /* 0 = use builtin default */
-       video->cip_d = 0;
-       video->syt_offset = 0;
-       video->mode = mode;
-
-       for (i = 0; i < DV1394_MAX_FRAMES; i++)
-               video->frames[i] = NULL;
-
-       dma_region_init(&video->dv_buf);
-       video->dv_buf_size = 0;
-       dma_region_init(&video->packet_buf);
-       video->packet_buf_size = 0;
-
-       clear_bit(0, &video->open);
-       spin_lock_init(&video->spinlock);
-       video->dma_running = 0;
-       mutex_init(&video->mtx);
-       init_waitqueue_head(&video->waitq);
-       video->fasync = NULL;
-
-       spin_lock_irqsave(&dv1394_cards_lock, flags);
-       INIT_LIST_HEAD(&video->list);
-       list_add_tail(&video->list, &dv1394_cards);
-       spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-       debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
-       return 0;
-}
-
-static void dv1394_remove_host(struct hpsb_host *host)
-{
-       struct video_card *video, *tmp_video;
-       unsigned long flags;
-       int found_ohci_card = 0;
-
-       do {
-               video = NULL;
-               spin_lock_irqsave(&dv1394_cards_lock, flags);
-               list_for_each_entry(tmp_video, &dv1394_cards, list) {
-                       if ((tmp_video->id >> 2) == host->id) {
-                               list_del(&tmp_video->list);
-                               video = tmp_video;
-                               found_ohci_card = 1;
-                               break;
-                       }
-               }
-               spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-               if (video) {
-                       do_dv1394_shutdown(video, 1);
-                       kfree(video);
-               }
-       } while (video);
-
-       if (found_ohci_card)
-               device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
-                          IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
-}
-
-static void dv1394_add_host(struct hpsb_host *host)
-{
-       struct ti_ohci *ohci;
-       int id = host->id;
-
-       /* We only work with the OHCI-1394 driver */
-       if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-               return;
-
-       ohci = (struct ti_ohci *)host->hostdata;
-
-       device_create(hpsb_protocol_class, NULL,
-                     MKDEV(IEEE1394_MAJOR,
-                           IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
-                     NULL, "dv1394-%d", id);
-
-       dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
-       dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
-       dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
-       dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
-}
-
-
-/* Bus reset handler. In the event of a bus reset, we may need to
-   re-start the DMA contexts - otherwise the user program would
-   end up waiting forever.
-*/
-
-static void dv1394_host_reset(struct hpsb_host *host)
-{
-       struct video_card *video = NULL, *tmp_vid;
-       unsigned long flags;
-
-       /* We only work with the OHCI-1394 driver */
-       if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-               return;
-
-       /* find the corresponding video_cards */
-       spin_lock_irqsave(&dv1394_cards_lock, flags);
-       list_for_each_entry(tmp_vid, &dv1394_cards, list) {
-               if ((tmp_vid->id >> 2) == host->id) {
-                       video = tmp_vid;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-       if (!video)
-               return;
-
-
-       spin_lock_irqsave(&video->spinlock, flags);
-
-       if (!video->dma_running)
-               goto out;
-
-       /* check IT context */
-       if (video->ohci_it_ctx != -1) {
-               u32 ctx;
-
-               ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
-
-               /* if (RUN but not ACTIVE) */
-               if ( (ctx & (1<<15)) &&
-                   !(ctx & (1<<10)) ) {
-
-                       debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
-
-                       /* to be safe, assume a frame has been dropped. User-space programs
-                          should handle this condition like an underflow. */
-                       video->dropped_frames++;
-
-                       /* for some reason you must clear, then re-set the RUN bit to restart DMA */
-
-                       /* clear RUN */
-                       reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
-                       flush_pci_write(video->ohci);
-
-                       /* set RUN */
-                       reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
-                       flush_pci_write(video->ohci);
-
-                       /* set the WAKE bit (just in case; this isn't strictly necessary) */
-                       reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
-                       flush_pci_write(video->ohci);
-
-                       irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
-                                  reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-                                  reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-               }
-       }
-
-       /* check IR context */
-       if (video->ohci_ir_ctx != -1) {
-               u32 ctx;
-
-               ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
-
-               /* if (RUN but not ACTIVE) */
-               if ( (ctx & (1<<15)) &&
-                   !(ctx & (1<<10)) ) {
-
-                       debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
-
-                       /* to be safe, assume a frame has been dropped. User-space programs
-                          should handle this condition like an overflow. */
-                       video->dropped_frames++;
-
-                       /* for some reason you must clear, then re-set the RUN bit to restart DMA */
-                       /* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
-
-                       /* clear RUN */
-                       reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
-                       flush_pci_write(video->ohci);
-
-                       /* set RUN */
-                       reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
-                       flush_pci_write(video->ohci);
-
-                       /* set the WAKE bit (just in case; this isn't strictly necessary) */
-                       reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-                       flush_pci_write(video->ohci);
-
-                       irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
-                                  reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
-                                  reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
-               }
-       }
-
-out:
-       spin_unlock_irqrestore(&video->spinlock, flags);
-
-       /* wake readers/writers/ioctl'ers */
-       wake_up_interruptible(&video->waitq);
-}
-
-static struct hpsb_highlevel dv1394_highlevel = {
-       .name =         "dv1394",
-       .add_host =     dv1394_add_host,
-       .remove_host =  dv1394_remove_host,
-       .host_reset =   dv1394_host_reset,
-};
-
-#ifdef CONFIG_COMPAT
-
-#define DV1394_IOC32_INIT       _IOW('#', 0x06, struct dv1394_init32)
-#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32)
-
-struct dv1394_init32 {
-       u32 api_version;
-       u32 channel;
-       u32 n_frames;
-       u32 format;
-       u32 cip_n;
-       u32 cip_d;
-       u32 syt_offset;
-};
-
-struct dv1394_status32 {
-       struct dv1394_init32 init;
-       s32 active_frame;
-       u32 first_clear_frame;
-       u32 n_clear_frames;
-       u32 dropped_frames;
-};
-
-/* RED-PEN: this should use compat_alloc_userspace instead */
-
-static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct dv1394_init32 dv32;
-       struct dv1394_init dv;
-       mm_segment_t old_fs;
-       int ret;
-
-       if (file->f_op->unlocked_ioctl != dv1394_ioctl)
-               return -EFAULT;
-
-       if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
-               return -EFAULT;
-
-       dv.api_version = dv32.api_version;
-       dv.channel = dv32.channel;
-       dv.n_frames = dv32.n_frames;
-       dv.format = dv32.format;
-       dv.cip_n = (unsigned long)dv32.cip_n;
-       dv.cip_d = (unsigned long)dv32.cip_d;
-       dv.syt_offset = dv32.syt_offset;
-
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
-       set_fs(old_fs);
-
-       return ret;
-}
-
-static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct dv1394_status32 dv32;
-       struct dv1394_status dv;
-       mm_segment_t old_fs;
-       int ret;
-
-       if (file->f_op->unlocked_ioctl != dv1394_ioctl)
-               return -EFAULT;
-
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
-       set_fs(old_fs);
-
-       if (!ret) {
-               dv32.init.api_version = dv.init.api_version;
-               dv32.init.channel = dv.init.channel;
-               dv32.init.n_frames = dv.init.n_frames;
-               dv32.init.format = dv.init.format;
-               dv32.init.cip_n = (u32)dv.init.cip_n;
-               dv32.init.cip_d = (u32)dv.init.cip_d;
-               dv32.init.syt_offset = dv.init.syt_offset;
-               dv32.active_frame = dv.active_frame;
-               dv32.first_clear_frame = dv.first_clear_frame;
-               dv32.n_clear_frames = dv.n_clear_frames;
-               dv32.dropped_frames = dv.dropped_frames;
-
-               if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32)))
-                       ret = -EFAULT;
-       }
-
-       return ret;
-}
-
-
-
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
-                              unsigned long arg)
-{
-       switch (cmd) {
-       case DV1394_IOC_SHUTDOWN:
-       case DV1394_IOC_SUBMIT_FRAMES:
-       case DV1394_IOC_WAIT_FRAMES:
-       case DV1394_IOC_RECEIVE_FRAMES:
-       case DV1394_IOC_START_RECEIVE:
-               return dv1394_ioctl(file, cmd, arg);
-
-       case DV1394_IOC32_INIT:
-               return handle_dv1394_init(file, cmd, arg);
-       case DV1394_IOC32_GET_STATUS:
-               return handle_dv1394_get_status(file, cmd, arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-#endif /* CONFIG_COMPAT */
-
-
-/*** KERNEL MODULE HANDLERS ************************************************/
-
-MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
-MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
-MODULE_SUPPORTED_DEVICE("dv1394");
-MODULE_LICENSE("GPL");
-
-static void __exit dv1394_exit_module(void)
-{
-       hpsb_unregister_protocol(&dv1394_driver);
-       hpsb_unregister_highlevel(&dv1394_highlevel);
-       cdev_del(&dv1394_cdev);
-}
-
-static int __init dv1394_init_module(void)
-{
-       int ret;
-
-       cdev_init(&dv1394_cdev, &dv1394_fops);
-       dv1394_cdev.owner = THIS_MODULE;
-       ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16);
-       if (ret) {
-               printk(KERN_ERR "dv1394: unable to register character device\n");
-               return ret;
-       }
-
-       hpsb_register_highlevel(&dv1394_highlevel);
-
-       ret = hpsb_register_protocol(&dv1394_driver);
-       if (ret) {
-               printk(KERN_ERR "dv1394: failed to register protocol\n");
-               hpsb_unregister_highlevel(&dv1394_highlevel);
-               cdev_del(&dv1394_cdev);
-               return ret;
-       }
-
-       return 0;
-}
-
-module_init(dv1394_init_module);
-module_exit(dv1394_exit_module);
diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h
deleted file mode 100644 (file)
index 5807f52..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *   video1394.h - driver for OHCI 1394 boards
- *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                          Peter Schlaile <udbz@rz.uni-karlsruhe.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_H
-#define _DV_1394_H
-
-/* This is the public user-space interface. Try not to break it. */
-
-#define DV1394_API_VERSION 0x20011127
-
-/* ********************
-   **                **
-   **   DV1394 API   **
-   **                **
-   ********************
-
-   There are two methods of operating the DV1394 DV output device.
-
-   1)
-
-   The simplest is an interface based on write(): simply write
-   full DV frames of data to the device, and they will be transmitted
-   as quickly as possible. The FD may be set for non-blocking I/O,
-   in which case you can use select() or poll() to wait for output
-   buffer space.
-
-   To set the DV output parameters (e.g. whether you want NTSC or PAL
-   video), use the DV1394_INIT ioctl, passing in the parameters you
-   want in a struct dv1394_init.
-
-   Example 1:
-         To play a raw .DV file:   cat foo.DV > /dev/dv1394
-        (cat will use write() internally)
-
-   Example 2:
-           static struct dv1394_init init = {
-             0x63,        (broadcast channel)
-              4,           (four-frame ringbuffer)
-             DV1394_NTSC, (send NTSC video)
-             0, 0         (default empty packet rate)
-           }
-
-          ioctl(fd, DV1394_INIT, &init);
-
-          while (1) {
-                 read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
-                 write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
-           }
-
-   2)
-
-   For more control over buffering, and to avoid unnecessary copies
-   of the DV data, you can use the more sophisticated the mmap() interface.
-   First, call the DV1394_INIT ioctl to specify your parameters,
-   including the number of frames in the ringbuffer. Then, calling mmap()
-   on the dv1394 device will give you direct access to the ringbuffer
-   from which the DV card reads your frame data.
-
-   The ringbuffer is simply one large, contiguous region of memory
-   containing two or more frames of packed DV data. Each frame of DV data
-   is 120000 bytes (NTSC) or 144000 bytes (PAL).
-
-   Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
-   ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
-   or select()/poll() to wait until the frames are transmitted. Next, you'll
-   need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
-   frames are clear (ready to be filled with new DV data). Finally, use
-   DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
-
-
-   Example: here is what a four-frame ringbuffer might look like
-            during DV transmission:
-
-
-         frame 0   frame 1   frame 2   frame 3
-
-       *--------------------------------------*
-        | CLEAR   | DV data | DV data | CLEAR  |
-        *--------------------------------------*
-                   <ACTIVE>
-
-       transmission goes in this direction --->>>
-
-
-   The DV hardware is currently transmitting the data in frame 1.
-   Once frame 1 is finished, it will automatically transmit frame 2.
-   (if frame 2 finishes before frame 3 is submitted, the device
-   will continue to transmit frame 2, and will increase the dropped_frames
-   counter each time it repeats the transmission).
-
-
-   If you called DV1394_GET_STATUS at this instant, you would
-   receive the following values:
-
-                  n_frames          = 4
-                 active_frame      = 1
-                 first_clear_frame = 3
-                 n_clear_frames    = 2
-
-   At this point, you should write new DV data into frame 3 and optionally
-   frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
-   it may transmit the new frames.
-
-   ERROR HANDLING
-
-   An error (buffer underflow/overflow or a break in the DV stream due
-   to a 1394 bus reset) can be detected by checking the dropped_frames
-   field of struct dv1394_status (obtained through the
-   DV1394_GET_STATUS ioctl).
-
-   The best way to recover from such an error is to re-initialize
-   dv1394, either by using the DV1394_INIT ioctl call, or closing the
-   file descriptor and opening it again. (note that you must unmap all
-   ringbuffer mappings when closing the file descriptor, or else
-   dv1394 will still be considered 'in use').
-
-   MAIN LOOP
-
-   For maximum efficiency and robustness against bus errors, you are
-   advised to model the main loop of your application after the
-   following pseudo-code example:
-
-   (checks of system call return values omitted for brevity; always
-   check return values in your code!)
-
-   while ( frames left ) {
-
-    struct pollfd *pfd = ...;
-
-    pfd->fd = dv1394_fd;
-    pfd->revents = 0;
-    pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
-
-    (add other sources of I/O here)
-
-    poll(pfd, 1, -1); (or select(); add a timeout if you want)
-
-    if (pfd->revents) {
-         struct dv1394_status status;
-
-         ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
-
-        if (status.dropped_frames > 0) {
-             reset_dv1394();
-         } else {
-              for (int i = 0; i < status.n_clear_frames; i++) {
-                 copy_DV_frame();
-              }
-         }
-    }
-   }
-
-   where copy_DV_frame() reads or writes on the dv1394 file descriptor
-   (read/write mode) or copies data to/from the mmap ringbuffer and
-   then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
-   frames are availble (mmap mode).
-
-   reset_dv1394() is called in the event of a buffer
-   underflow/overflow or a halt in the DV stream (e.g. due to a 1394
-   bus reset). To guarantee recovery from the error, this function
-   should close the dv1394 file descriptor (and munmap() all
-   ringbuffer mappings, if you are using them), then re-open the
-   dv1394 device (and re-map the ringbuffer).
-
-*/
-
-
-/* maximum number of frames in the ringbuffer */
-#define DV1394_MAX_FRAMES 32
-
-/* number of *full* isochronous packets per DV frame */
-#define DV1394_NTSC_PACKETS_PER_FRAME 250
-#define DV1394_PAL_PACKETS_PER_FRAME  300
-
-/* size of one frame's worth of DV data, in bytes */
-#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
-#define DV1394_PAL_FRAME_SIZE  (480 * DV1394_PAL_PACKETS_PER_FRAME)
-
-
-/* ioctl() commands */
-#include "ieee1394-ioctl.h"
-
-
-enum pal_or_ntsc {
-       DV1394_NTSC = 0,
-       DV1394_PAL
-};
-
-
-
-
-/* this is the argument to DV1394_INIT */
-struct dv1394_init {
-       /* DV1394_API_VERSION */
-       unsigned int api_version;
-
-       /* isochronous transmission channel to use */
-       unsigned int channel;
-
-       /* number of frames in the ringbuffer. Must be at least 2
-          and at most DV1394_MAX_FRAMES. */
-       unsigned int n_frames;
-
-       /* send/receive PAL or NTSC video format */
-       enum pal_or_ntsc format;
-
-       /* the following are used only for transmission */
-
-       /* set these to zero unless you want a
-          non-default empty packet rate (see below) */
-       unsigned long cip_n;
-       unsigned long cip_d;
-
-       /* set this to zero unless you want a
-          non-default SYT cycle offset (default = 3 cycles) */
-       unsigned int syt_offset;
-};
-
-/* NOTE: you may only allocate the DV frame ringbuffer once each time
-   you open the dv1394 device. DV1394_INIT will fail if you call it a
-   second time with different 'n_frames' or 'format' arguments (which
-   would imply a different size for the ringbuffer). If you need a
-   different buffer size, simply close and re-open the device, then
-   initialize it with your new settings. */
-
-/* Q: What are cip_n and cip_d? */
-
-/*
-  A: DV video streams do not utilize 100% of the potential bandwidth offered
-  by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
-  DV devices must periodically insert empty packets into the 1394 data stream.
-  Typically there is one empty packet per 14-16 data-carrying packets.
-
-  Some DV devices will accept a wide range of empty packet rates, while others
-  require a precise rate. If the dv1394 driver produces empty packets at
-  a rate that your device does not accept, you may see ugly patterns on the
-  DV output, or even no output at all.
-
-  The default empty packet insertion rate seems to work for many people; if
-  your DV output is stable, you can simply ignore this discussion. However,
-  we have exposed the empty packet rate as a parameter to support devices that
-  do not work with the default rate.
-
-  The decision to insert an empty packet is made with a numerator/denominator
-  algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
-  You can alter the empty packet rate by passing non-zero values for cip_n
-  and cip_d to the INIT ioctl.
-
- */
-
-
-
-struct dv1394_status {
-       /* this embedded init struct returns the current dv1394
-          parameters in use */
-       struct dv1394_init init;
-
-       /* the ringbuffer frame that is currently being
-          displayed. (-1 if the device is not transmitting anything) */
-       int active_frame;
-
-       /* index of the first buffer (ahead of active_frame) that
-          is ready to be filled with data */
-       unsigned int first_clear_frame;
-
-       /* how many buffers, including first_clear_buffer, are
-          ready to be filled with data */
-       unsigned int n_clear_frames;
-
-       /* how many times the DV stream has underflowed, overflowed,
-          or otherwise encountered an error, since the previous call
-          to DV1394_GET_STATUS */
-       unsigned int dropped_frames;
-
-       /* N.B. The dropped_frames counter is only a lower bound on the actual
-          number of dropped frames, with the special case that if dropped_frames
-          is zero, then it is guaranteed that NO frames have been dropped
-          since the last call to DV1394_GET_STATUS.
-       */
-};
-
-
-#endif /* _DV_1394_H */
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
deleted file mode 100644 (file)
index 6340382..0000000
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
- * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
- *               2000 Bonin Franck <boninf@free.fr>
- *               2003 Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- */
-
-/*
- * This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses.
- *
- * TODO:
- * RFC 2734 related:
- * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
- *
- * Non-RFC 2734 related:
- * - Handle fragmented skb's coming from the networking layer.
- * - Move generic GASP reception to core 1394 code
- * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
- * - Stability improvements
- * - Performance enhancements
- * - Consider garbage collecting old partial datagrams after X amount of time
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/unaligned.h>
-#include <net/arp.h>
-
-#include "config_roms.h"
-#include "csr1212.h"
-#include "eth1394.h"
-#include "highlevel.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-
-#define ETH1394_PRINT_G(level, fmt, args...) \
-       printk(level "%s: " fmt, driver_name, ## args)
-
-#define ETH1394_PRINT(level, dev_name, fmt, args...) \
-       printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
-
-struct fragment_info {
-       struct list_head list;
-       int offset;
-       int len;
-};
-
-struct partial_datagram {
-       struct list_head list;
-       u16 dgl;
-       u16 dg_size;
-       __be16 ether_type;
-       struct sk_buff *skb;
-       char *pbuf;
-       struct list_head frag_info;
-};
-
-struct pdg_list {
-       struct list_head list;  /* partial datagram list per node       */
-       unsigned int sz;        /* partial datagram list size per node  */
-       spinlock_t lock;        /* partial datagram lock                */
-};
-
-struct eth1394_host_info {
-       struct hpsb_host *host;
-       struct net_device *dev;
-};
-
-struct eth1394_node_ref {
-       struct unit_directory *ud;
-       struct list_head list;
-};
-
-struct eth1394_node_info {
-       u16 maxpayload;         /* max payload                  */
-       u8 sspd;                /* max speed                    */
-       u64 fifo;               /* FIFO address                 */
-       struct pdg_list pdg;    /* partial RX datagram lists    */
-       int dgl;                /* outgoing datagram label      */
-};
-
-static const char driver_name[] = "eth1394";
-
-static struct kmem_cache *packet_task_cache;
-
-static struct hpsb_highlevel eth1394_highlevel;
-
-/* Use common.lf to determine header len */
-static const int hdr_type_len[] = {
-       sizeof(struct eth1394_uf_hdr),
-       sizeof(struct eth1394_ff_hdr),
-       sizeof(struct eth1394_sf_hdr),
-       sizeof(struct eth1394_sf_hdr)
-};
-
-static const u16 eth1394_speedto_maxpayload[] = {
-/*     S100, S200, S400, S800, S1600, S3200 */
-       512, 1024, 2048, 4096,  4096,  4096
-};
-
-MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
-MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
-MODULE_LICENSE("GPL");
-
-/*
- * The max_partial_datagrams parameter is the maximum number of fragmented
- * datagrams per node that eth1394 will keep in memory.  Providing an upper
- * bound allows us to limit the amount of memory that partial datagrams
- * consume in the event that some partial datagrams are never completed.
- */
-static int max_partial_datagrams = 25;
-module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_partial_datagrams,
-                "Maximum number of partially received fragmented datagrams "
-                "(default = 25).");
-
-
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-                           unsigned short type, const void *daddr,
-                           const void *saddr, unsigned len);
-static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(const struct sk_buff *skb,
-                                 unsigned char *haddr);
-static int ether1394_header_cache(const struct neighbour *neigh,
-                                 struct hh_cache *hh);
-static void ether1394_header_cache_update(struct hh_cache *hh,
-                                         const struct net_device *dev,
-                                         const unsigned char *haddr);
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
-                               struct net_device *dev);
-static void ether1394_iso(struct hpsb_iso *iso);
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
-                          quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host(struct hpsb_host *host);
-static void ether1394_remove_host(struct hpsb_host *host);
-static void ether1394_host_reset(struct hpsb_host *host);
-
-/* Function for incoming 1394 packets */
-static const struct hpsb_address_ops addr_ops = {
-       .write =        ether1394_write,
-};
-
-/* Ieee1394 highlevel driver functions */
-static struct hpsb_highlevel eth1394_highlevel = {
-       .name =         driver_name,
-       .add_host =     ether1394_add_host,
-       .remove_host =  ether1394_remove_host,
-       .host_reset =   ether1394_host_reset,
-};
-
-static int ether1394_recv_init(struct eth1394_priv *priv)
-{
-       unsigned int iso_buf_size;
-
-       /* FIXME: rawiso limits us to PAGE_SIZE */
-       iso_buf_size = min((unsigned int)PAGE_SIZE,
-                          2 * (1U << (priv->host->csr.max_rec + 1)));
-
-       priv->iso = hpsb_iso_recv_init(priv->host,
-                                      ETHER1394_GASP_BUFFERS * iso_buf_size,
-                                      ETHER1394_GASP_BUFFERS,
-                                      priv->broadcast_channel,
-                                      HPSB_ISO_DMA_PACKET_PER_BUFFER,
-                                      1, ether1394_iso);
-       if (priv->iso == NULL) {
-               ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
-               priv->bc_state = ETHER1394_BC_ERROR;
-               return -EAGAIN;
-       }
-
-       if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
-               priv->bc_state = ETHER1394_BC_STOPPED;
-       else
-               priv->bc_state = ETHER1394_BC_RUNNING;
-       return 0;
-}
-
-/* This is called after an "ifup" */
-static int ether1394_open(struct net_device *dev)
-{
-       struct eth1394_priv *priv = netdev_priv(dev);
-       int ret;
-
-       if (priv->bc_state == ETHER1394_BC_ERROR) {
-               ret = ether1394_recv_init(priv);
-               if (ret)
-                       return ret;
-       }
-       netif_start_queue(dev);
-       return 0;
-}
-
-/* This is called after an "ifdown" */
-static int ether1394_stop(struct net_device *dev)
-{
-       /* flush priv->wake */
-       flush_scheduled_work();
-
-       netif_stop_queue(dev);
-       return 0;
-}
-
-/* FIXME: What to do if we timeout? I think a host reset is probably in order,
- * so that's what we do. Should we increment the stat counters too?  */
-static void ether1394_tx_timeout(struct net_device *dev)
-{
-       struct hpsb_host *host =
-                       ((struct eth1394_priv *)netdev_priv(dev))->host;
-
-       ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
-       ether1394_host_reset(host);
-}
-
-static inline int ether1394_max_mtu(struct hpsb_host* host)
-{
-       return (1 << (host->csr.max_rec + 1))
-                       - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
-}
-
-static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
-{
-       int max_mtu;
-
-       if (new_mtu < 68)
-               return -EINVAL;
-
-       max_mtu = ether1394_max_mtu(
-                       ((struct eth1394_priv *)netdev_priv(dev))->host);
-       if (new_mtu > max_mtu) {
-               ETH1394_PRINT(KERN_INFO, dev->name,
-                             "Local node constrains MTU to %d\n", max_mtu);
-               return -ERANGE;
-       }
-
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-static void purge_partial_datagram(struct list_head *old)
-{
-       struct partial_datagram *pd;
-       struct list_head *lh, *n;
-       struct fragment_info *fi;
-
-       pd = list_entry(old, struct partial_datagram, list);
-
-       list_for_each_safe(lh, n, &pd->frag_info) {
-               fi = list_entry(lh, struct fragment_info, list);
-               list_del(lh);
-               kfree(fi);
-       }
-       list_del(old);
-       kfree_skb(pd->skb);
-       kfree(pd);
-}
-
-/******************************************
- * 1394 bus activity functions
- ******************************************/
-
-static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl,
-                                                 struct unit_directory *ud)
-{
-       struct eth1394_node_ref *node;
-
-       list_for_each_entry(node, inl, list)
-               if (node->ud == ud)
-                       return node;
-
-       return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl,
-                                                      u64 guid)
-{
-       struct eth1394_node_ref *node;
-
-       list_for_each_entry(node, inl, list)
-               if (node->ud->ne->guid == guid)
-                       return node;
-
-       return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
-                                                        nodeid_t nodeid)
-{
-       struct eth1394_node_ref *node;
-
-       list_for_each_entry(node, inl, list)
-               if (node->ud->ne->nodeid == nodeid)
-                       return node;
-
-       return NULL;
-}
-
-static int eth1394_new_node(struct eth1394_host_info *hi,
-                           struct unit_directory *ud)
-{
-       struct eth1394_priv *priv;
-       struct eth1394_node_ref *new_node;
-       struct eth1394_node_info *node_info;
-
-       new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
-       if (!new_node)
-               return -ENOMEM;
-
-       node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
-       if (!node_info) {
-               kfree(new_node);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&node_info->pdg.lock);
-       INIT_LIST_HEAD(&node_info->pdg.list);
-       node_info->pdg.sz = 0;
-       node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
-
-       dev_set_drvdata(&ud->device, node_info);
-       new_node->ud = ud;
-
-       priv = netdev_priv(hi->dev);
-       list_add_tail(&new_node->list, &priv->ip_node_list);
-       return 0;
-}
-
-static int eth1394_probe(struct device *dev)
-{
-       struct unit_directory *ud;
-       struct eth1394_host_info *hi;
-
-       ud = container_of(dev, struct unit_directory, device);
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-       if (!hi)
-               return -ENOENT;
-
-       return eth1394_new_node(hi, ud);
-}
-
-static int eth1394_remove(struct device *dev)
-{
-       struct unit_directory *ud;
-       struct eth1394_host_info *hi;
-       struct eth1394_priv *priv;
-       struct eth1394_node_ref *old_node;
-       struct eth1394_node_info *node_info;
-       struct list_head *lh, *n;
-       unsigned long flags;
-
-       ud = container_of(dev, struct unit_directory, device);
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-       if (!hi)
-               return -ENOENT;
-
-       priv = netdev_priv(hi->dev);
-
-       old_node = eth1394_find_node(&priv->ip_node_list, ud);
-       if (!old_node)
-               return 0;
-
-       list_del(&old_node->list);
-       kfree(old_node);
-
-       node_info = dev_get_drvdata(&ud->device);
-
-       spin_lock_irqsave(&node_info->pdg.lock, flags);
-       /* The partial datagram list should be empty, but we'll just
-        * make sure anyway... */
-       list_for_each_safe(lh, n, &node_info->pdg.list)
-               purge_partial_datagram(lh);
-       spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-
-       kfree(node_info);
-       dev_set_drvdata(&ud->device, NULL);
-       return 0;
-}
-
-static int eth1394_update(struct unit_directory *ud)
-{
-       struct eth1394_host_info *hi;
-       struct eth1394_priv *priv;
-       struct eth1394_node_ref *node;
-
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-       if (!hi)
-               return -ENOENT;
-
-       priv = netdev_priv(hi->dev);
-       node = eth1394_find_node(&priv->ip_node_list, ud);
-       if (node)
-               return 0;
-
-       return eth1394_new_node(hi, ud);
-}
-
-static const struct ieee1394_device_id eth1394_id_table[] = {
-       {
-               .match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
-                               IEEE1394_MATCH_VERSION),
-               .specifier_id = ETHER1394_GASP_SPECIFIER_ID,
-               .version = ETHER1394_GASP_VERSION,
-       },
-       {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
-
-static struct hpsb_protocol_driver eth1394_proto_driver = {
-       .name           = driver_name,
-       .id_table       = eth1394_id_table,
-       .update         = eth1394_update,
-       .driver         = {
-               .probe          = eth1394_probe,
-               .remove         = eth1394_remove,
-       },
-};
-
-static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
-{
-       unsigned long flags;
-       int i;
-       struct eth1394_priv *priv = netdev_priv(dev);
-       struct hpsb_host *host = priv->host;
-       u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
-       int max_speed = IEEE1394_SPEED_MAX;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       memset(priv->ud_list, 0, sizeof(priv->ud_list));
-       priv->bc_maxpayload = 512;
-
-       /* Determine speed limit */
-       /* FIXME: This is broken for nodes with link speed < PHY speed,
-        * and it is suboptimal for S200B...S800B hardware.
-        * The result of nodemgr's speed probe should be used somehow. */
-       for (i = 0; i < host->node_count; i++) {
-               /* take care of S100B...S400B PHY ports */
-               if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
-                       max_speed = IEEE1394_SPEED_100;
-                       break;
-               }
-               if (max_speed > host->speed[i])
-                       max_speed = host->speed[i];
-       }
-       priv->bc_sspd = max_speed;
-
-       if (set_mtu) {
-               /* Use the RFC 2734 default 1500 octets or the maximum payload
-                * as initial MTU */
-               dev->mtu = min(1500, ether1394_max_mtu(host));
-
-               /* Set our hardware address while we're at it */
-               memcpy(dev->dev_addr, &guid, sizeof(u64));
-               memset(dev->broadcast, 0xff, sizeof(u64));
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static const struct header_ops ether1394_header_ops = {
-       .create         = ether1394_header,
-       .rebuild        = ether1394_rebuild_header,
-       .cache          = ether1394_header_cache,
-       .cache_update   = ether1394_header_cache_update,
-       .parse          = ether1394_header_parse,
-};
-
-static const struct net_device_ops ether1394_netdev_ops = {
-       .ndo_open       = ether1394_open,
-       .ndo_stop       = ether1394_stop,
-       .ndo_start_xmit = ether1394_tx,
-       .ndo_tx_timeout = ether1394_tx_timeout,
-       .ndo_change_mtu = ether1394_change_mtu,
-};
-
-static void ether1394_init_dev(struct net_device *dev)
-{
-
-       dev->header_ops         = &ether1394_header_ops;
-       dev->netdev_ops         = &ether1394_netdev_ops;
-
-       dev->watchdog_timeo     = ETHER1394_TIMEOUT;
-       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
-       dev->features           = NETIF_F_HIGHDMA;
-       dev->addr_len           = ETH1394_ALEN;
-       dev->hard_header_len    = ETH1394_HLEN;
-       dev->type               = ARPHRD_IEEE1394;
-
-       /* FIXME: This value was copied from ether_setup(). Is it too much? */
-       dev->tx_queue_len       = 1000;
-}
-
-/*
- * Wake the queue up after commonly encountered transmit failure conditions are
- * hopefully over.  Currently only tlabel exhaustion is accounted for.
- */
-static void ether1394_wake_queue(struct work_struct *work)
-{
-       struct eth1394_priv *priv;
-       struct hpsb_packet *packet;
-
-       priv = container_of(work, struct eth1394_priv, wake);
-       packet = hpsb_alloc_packet(0);
-
-       /* This is really bad, but unjam the queue anyway. */
-       if (!packet)
-               goto out;
-
-       packet->host = priv->host;
-       packet->node_id = priv->wake_node;
-       /*
-        * A transaction label is all we really want.  If we get one, it almost
-        * always means we can get a lot more because the ieee1394 core recycled
-        * a whole batch of tlabels, at last.
-        */
-       if (hpsb_get_tlabel(packet) == 0)
-               hpsb_free_tlabel(packet);
-
-       hpsb_free_packet(packet);
-out:
-       netif_wake_queue(priv->wake_dev);
-}
-
-/*
- * This function is called every time a card is found. It is generally called
- * when the module is installed. This is where we add all of our ethernet
- * devices. One for each host.
- */
-static void ether1394_add_host(struct hpsb_host *host)
-{
-       struct eth1394_host_info *hi = NULL;
-       struct net_device *dev = NULL;
-       struct eth1394_priv *priv;
-       u64 fifo_addr;
-
-       if (hpsb_config_rom_ip1394_add(host) != 0) {
-               ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
-               return;
-       }
-
-       fifo_addr = hpsb_allocate_and_register_addrspace(
-                       &eth1394_highlevel, host, &addr_ops,
-                       ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
-                       CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
-       if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
-               ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
-               hpsb_config_rom_ip1394_remove(host);
-               return;
-       }
-
-       dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
-       if (dev == NULL) {
-               ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-               goto out;
-       }
-
-       SET_NETDEV_DEV(dev, &host->device);
-
-       priv = netdev_priv(dev);
-       INIT_LIST_HEAD(&priv->ip_node_list);
-       spin_lock_init(&priv->lock);
-       priv->host = host;
-       priv->local_fifo = fifo_addr;
-       INIT_WORK(&priv->wake, ether1394_wake_queue);
-       priv->wake_dev = dev;
-
-       hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
-       if (hi == NULL) {
-               ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-               goto out;
-       }
-
-       ether1394_reset_priv(dev, 1);
-
-       if (register_netdev(dev)) {
-               ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
-               goto out;
-       }
-
-       ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
-                     host->id);
-
-       hi->host = host;
-       hi->dev = dev;
-
-       /* Ignore validity in hopes that it will be set in the future.  It'll
-        * be checked when the eth device is opened. */
-       priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
-
-       ether1394_recv_init(priv);
-       return;
-out:
-       if (dev)
-               free_netdev(dev);
-       if (hi)
-               hpsb_destroy_hostinfo(&eth1394_highlevel, host);
-       hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
-       hpsb_config_rom_ip1394_remove(host);
-}
-
-/* Remove a card from our list */
-static void ether1394_remove_host(struct hpsb_host *host)
-{
-       struct eth1394_host_info *hi;
-       struct eth1394_priv *priv;
-
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-       if (!hi)
-               return;
-       priv = netdev_priv(hi->dev);
-       hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
-       hpsb_config_rom_ip1394_remove(host);
-       if (priv->iso)
-               hpsb_iso_shutdown(priv->iso);
-       unregister_netdev(hi->dev);
-       free_netdev(hi->dev);
-}
-
-/* A bus reset happened */
-static void ether1394_host_reset(struct hpsb_host *host)
-{
-       struct eth1394_host_info *hi;
-       struct eth1394_priv *priv;
-       struct net_device *dev;
-       struct list_head *lh, *n;
-       struct eth1394_node_ref *node;
-       struct eth1394_node_info *node_info;
-       unsigned long flags;
-
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-
-       /* This can happen for hosts that we don't use */
-       if (!hi)
-               return;
-
-       dev = hi->dev;
-       priv = netdev_priv(dev);
-
-       /* Reset our private host data, but not our MTU */
-       netif_stop_queue(dev);
-       ether1394_reset_priv(dev, 0);
-
-       list_for_each_entry(node, &priv->ip_node_list, list) {
-               node_info = dev_get_drvdata(&node->ud->device);
-
-               spin_lock_irqsave(&node_info->pdg.lock, flags);
-
-               list_for_each_safe(lh, n, &node_info->pdg.list)
-                       purge_partial_datagram(lh);
-
-               INIT_LIST_HEAD(&(node_info->pdg.list));
-               node_info->pdg.sz = 0;
-
-               spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-       }
-
-       netif_wake_queue(dev);
-}
-
-/******************************************
- * HW Header net device functions
- ******************************************/
-/* These functions have been adapted from net/ethernet/eth.c */
-
-/* Create a fake MAC header for an arbitrary protocol layer.
- * saddr=NULL means use device source address
- * daddr=NULL means leave destination address (eg unresolved arp). */
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-                           unsigned short type, const void *daddr,
-                           const void *saddr, unsigned len)
-{
-       struct eth1394hdr *eth =
-                       (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
-
-       eth->h_proto = htons(type);
-
-       if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
-               memset(eth->h_dest, 0, dev->addr_len);
-               return dev->hard_header_len;
-       }
-
-       if (daddr) {
-               memcpy(eth->h_dest, daddr, dev->addr_len);
-               return dev->hard_header_len;
-       }
-
-       return -dev->hard_header_len;
-}
-
-/* Rebuild the faked MAC header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- *
- * This routine CANNOT use cached dst->neigh!
- * Really, it is used only when dst->neigh is wrong.
- */
-static int ether1394_rebuild_header(struct sk_buff *skb)
-{
-       struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
-
-       if (eth->h_proto == htons(ETH_P_IP))
-               return arp_find((unsigned char *)&eth->h_dest, skb);
-
-       ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
-                     "unable to resolve type %04x addresses\n",
-                     ntohs(eth->h_proto));
-       return 0;
-}
-
-static int ether1394_header_parse(const struct sk_buff *skb,
-                                 unsigned char *haddr)
-{
-       memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
-       return ETH1394_ALEN;
-}
-
-static int ether1394_header_cache(const struct neighbour *neigh,
-                                 struct hh_cache *hh)
-{
-       __be16 type = hh->hh_type;
-       struct net_device *dev = neigh->dev;
-       struct eth1394hdr *eth =
-               (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
-
-       if (type == htons(ETH_P_802_3))
-               return -1;
-
-       eth->h_proto = type;
-       memcpy(eth->h_dest, neigh->ha, dev->addr_len);
-
-       hh->hh_len = ETH1394_HLEN;
-       return 0;
-}
-
-/* Called by Address Resolution module to notify changes in address. */
-static void ether1394_header_cache_update(struct hh_cache *hh,
-                                         const struct net_device *dev,
-                                         const unsigned char * haddr)
-{
-       memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
-}
-
-/******************************************
- * Datagram reception code
- ******************************************/
-
-/* Copied from net/ethernet/eth.c */
-static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-       struct eth1394hdr *eth;
-       unsigned char *rawp;
-
-       skb_reset_mac_header(skb);
-       skb_pull(skb, ETH1394_HLEN);
-       eth = eth1394_hdr(skb);
-
-       if (*eth->h_dest & 1) {
-               if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
-                       skb->pkt_type = PACKET_BROADCAST;
-#if 0
-               else
-                       skb->pkt_type = PACKET_MULTICAST;
-#endif
-       } else {
-               if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
-                       skb->pkt_type = PACKET_OTHERHOST;
-       }
-
-       if (ntohs(eth->h_proto) >= 1536)
-               return eth->h_proto;
-
-       rawp = skb->data;
-
-       if (*(unsigned short *)rawp == 0xFFFF)
-               return htons(ETH_P_802_3);
-
-       return htons(ETH_P_802_2);
-}
-
-/* Parse an encapsulated IP1394 header into an ethernet frame packet.
- * We also perform ARP translation here, if need be.  */
-static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
-                                nodeid_t srcid, nodeid_t destid,
-                                __be16 ether_type)
-{
-       struct eth1394_priv *priv = netdev_priv(dev);
-       __be64 dest_hw;
-       __be16 ret = 0;
-
-       /* Setup our hw addresses. We use these to build the ethernet header. */
-       if (destid == (LOCAL_BUS | ALL_NODES))
-               dest_hw = ~cpu_to_be64(0);  /* broadcast */
-       else
-               dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
-                                     priv->host->csr.guid_lo);
-
-       /* If this is an ARP packet, convert it. First, we want to make
-        * use of some of the fields, since they tell us a little bit
-        * about the sending machine.  */
-       if (ether_type == htons(ETH_P_ARP)) {
-               struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-               struct arphdr *arp = (struct arphdr *)skb->data;
-               unsigned char *arp_ptr = (unsigned char *)(arp + 1);
-               u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
-                                          ntohl(arp1394->fifo_lo);
-               u8 max_rec = min(priv->host->csr.max_rec,
-                                (u8)(arp1394->max_rec));
-               int sspd = arp1394->sspd;
-               u16 maxpayload;
-               struct eth1394_node_ref *node;
-               struct eth1394_node_info *node_info;
-               __be64 guid;
-
-               /* Sanity check. MacOSX seems to be sending us 131 in this
-                * field (atleast on my Panther G5). Not sure why. */
-               if (sspd > 5 || sspd < 0)
-                       sspd = 0;
-
-               maxpayload = min(eth1394_speedto_maxpayload[sspd],
-                                (u16)(1 << (max_rec + 1)));
-
-               guid = get_unaligned(&arp1394->s_uniq_id);
-               node = eth1394_find_node_guid(&priv->ip_node_list,
-                                             be64_to_cpu(guid));
-               if (!node)
-                       return cpu_to_be16(0);
-
-               node_info = dev_get_drvdata(&node->ud->device);
-
-               /* Update our speed/payload/fifo_offset table */
-               node_info->maxpayload = maxpayload;
-               node_info->sspd =       sspd;
-               node_info->fifo =       fifo_addr;
-
-               /* Now that we're done with the 1394 specific stuff, we'll
-                * need to alter some of the data.  Believe it or not, all
-                * that needs to be done is sender_IP_address needs to be
-                * moved, the destination hardware address get stuffed
-                * in and the hardware address length set to 8.
-                *
-                * IMPORTANT: The code below overwrites 1394 specific data
-                * needed above so keep the munging of the data for the
-                * higher level IP stack last. */
-
-               arp->ar_hln = 8;
-               arp_ptr += arp->ar_hln;         /* skip over sender unique id */
-               *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
-               arp_ptr += arp->ar_pln;         /* skip over sender IP addr */
-
-               if (arp->ar_op == htons(ARPOP_REQUEST))
-                       memset(arp_ptr, 0, sizeof(u64));
-               else
-                       memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
-       }
-
-       /* Now add the ethernet header. */
-       if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
-                           skb->len) >= 0)
-               ret = ether1394_type_trans(skb, dev);
-
-       return ret;
-}
-
-static int fragment_overlap(struct list_head *frag_list, int offset, int len)
-{
-       struct fragment_info *fi;
-       int end = offset + len;
-
-       list_for_each_entry(fi, frag_list, list)
-               if (offset < fi->offset + fi->len && end > fi->offset)
-                       return 1;
-
-       return 0;
-}
-
-static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
-{
-       struct partial_datagram *pd;
-
-       list_for_each_entry(pd, pdgl, list)
-               if (pd->dgl == dgl)
-                       return &pd->list;
-
-       return NULL;
-}
-
-/* Assumes that new fragment does not overlap any existing fragments */
-static int new_fragment(struct list_head *frag_info, int offset, int len)
-{
-       struct list_head *lh;
-       struct fragment_info *fi, *fi2, *new;
-
-       list_for_each(lh, frag_info) {
-               fi = list_entry(lh, struct fragment_info, list);
-               if (fi->offset + fi->len == offset) {
-                       /* The new fragment can be tacked on to the end */
-                       fi->len += len;
-                       /* Did the new fragment plug a hole? */
-                       fi2 = list_entry(lh->next, struct fragment_info, list);
-                       if (fi->offset + fi->len == fi2->offset) {
-                               /* glue fragments together */
-                               fi->len += fi2->len;
-                               list_del(lh->next);
-                               kfree(fi2);
-                       }
-                       return 0;
-               } else if (offset + len == fi->offset) {
-                       /* The new fragment can be tacked on to the beginning */
-                       fi->offset = offset;
-                       fi->len += len;
-                       /* Did the new fragment plug a hole? */
-                       fi2 = list_entry(lh->prev, struct fragment_info, list);
-                       if (fi2->offset + fi2->len == fi->offset) {
-                               /* glue fragments together */
-                               fi2->len += fi->len;
-                               list_del(lh);
-                               kfree(fi);
-                       }
-                       return 0;
-               } else if (offset > fi->offset + fi->len) {
-                       break;
-               } else if (offset + len < fi->offset) {
-                       lh = lh->prev;
-                       break;
-               }
-       }
-
-       new = kmalloc(sizeof(*new), GFP_ATOMIC);
-       if (!new)
-               return -ENOMEM;
-
-       new->offset = offset;
-       new->len = len;
-
-       list_add(&new->list, lh);
-       return 0;
-}
-
-static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
-                               int dgl, int dg_size, char *frag_buf,
-                               int frag_off, int frag_len)
-{
-       struct partial_datagram *new;
-
-       new = kmalloc(sizeof(*new), GFP_ATOMIC);
-       if (!new)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&new->frag_info);
-
-       if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
-               kfree(new);
-               return -ENOMEM;
-       }
-
-       new->dgl = dgl;
-       new->dg_size = dg_size;
-
-       new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
-       if (!new->skb) {
-               struct fragment_info *fi = list_entry(new->frag_info.next,
-                                                     struct fragment_info,
-                                                     list);
-               kfree(fi);
-               kfree(new);
-               return -ENOMEM;
-       }
-
-       skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
-       new->pbuf = skb_put(new->skb, dg_size);
-       memcpy(new->pbuf + frag_off, frag_buf, frag_len);
-
-       list_add(&new->list, pdgl);
-       return 0;
-}
-
-static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
-                                  char *frag_buf, int frag_off, int frag_len)
-{
-       struct partial_datagram *pd =
-                       list_entry(lh, struct partial_datagram, list);
-
-       if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
-               return -ENOMEM;
-
-       memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
-
-       /* Move list entry to beginnig of list so that oldest partial
-        * datagrams percolate to the end of the list */
-       list_move(lh, pdgl);
-       return 0;
-}
-
-static int is_datagram_complete(struct list_head *lh, int dg_size)
-{
-       struct partial_datagram *pd;
-       struct fragment_info *fi;
-
-       pd = list_entry(lh, struct partial_datagram, list);
-       fi = list_entry(pd->frag_info.next, struct fragment_info, list);
-
-       return (fi->len == dg_size);
-}
-
-/* Packet reception. We convert the IP1394 encapsulation header to an
- * ethernet header, and fill it with some of our other fields. This is
- * an incoming packet from the 1394 bus.  */
-static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
-                                 char *buf, int len)
-{
-       struct sk_buff *skb;
-       unsigned long flags;
-       struct eth1394_priv *priv = netdev_priv(dev);
-       union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
-       __be16 ether_type = cpu_to_be16(0);  /* initialized to clear warning */
-       int hdr_len;
-       struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
-       struct eth1394_node_info *node_info;
-
-       if (!ud) {
-               struct eth1394_node_ref *node;
-               node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
-               if (unlikely(!node)) {
-                       HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
-                                  "lookup failure: " NODE_BUS_FMT,
-                                  NODE_BUS_ARGS(priv->host, srcid));
-                       dev->stats.rx_dropped++;
-                       return -1;
-               }
-               ud = node->ud;
-
-               priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
-       }
-
-       node_info = dev_get_drvdata(&ud->device);
-
-       /* First, did we receive a fragmented or unfragmented datagram? */
-       hdr->words.word1 = ntohs(hdr->words.word1);
-
-       hdr_len = hdr_type_len[hdr->common.lf];
-
-       if (hdr->common.lf == ETH1394_HDR_LF_UF) {
-               /* An unfragmented datagram has been received by the ieee1394
-                * bus. Build an skbuff around it so we can pass it to the
-                * high level network layer. */
-
-               skb = dev_alloc_skb(len + dev->hard_header_len + 15);
-               if (unlikely(!skb)) {
-                       ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-                       dev->stats.rx_dropped++;
-                       return -1;
-               }
-               skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-               memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
-                      len - hdr_len);
-               ether_type = hdr->uf.ether_type;
-       } else {
-               /* A datagram fragment has been received, now the fun begins. */
-
-               struct list_head *pdgl, *lh;
-               struct partial_datagram *pd;
-               int fg_off;
-               int fg_len = len - hdr_len;
-               int dg_size;
-               int dgl;
-               int retval;
-               struct pdg_list *pdg = &(node_info->pdg);
-
-               hdr->words.word3 = ntohs(hdr->words.word3);
-               /* The 4th header word is reserved so no need to do ntohs() */
-
-               if (hdr->common.lf == ETH1394_HDR_LF_FF) {
-                       ether_type = hdr->ff.ether_type;
-                       dgl = hdr->ff.dgl;
-                       dg_size = hdr->ff.dg_size + 1;
-                       fg_off = 0;
-               } else {
-                       hdr->words.word2 = ntohs(hdr->words.word2);
-                       dgl = hdr->sf.dgl;
-                       dg_size = hdr->sf.dg_size + 1;
-                       fg_off = hdr->sf.fg_off;
-               }
-               spin_lock_irqsave(&pdg->lock, flags);
-
-               pdgl = &(pdg->list);
-               lh = find_partial_datagram(pdgl, dgl);
-
-               if (lh == NULL) {
-                       while (pdg->sz >= max_partial_datagrams) {
-                               /* remove the oldest */
-                               purge_partial_datagram(pdgl->prev);
-                               pdg->sz--;
-                       }
-
-                       retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
-                                                     buf + hdr_len, fg_off,
-                                                     fg_len);
-                       if (retval < 0) {
-                               spin_unlock_irqrestore(&pdg->lock, flags);
-                               goto bad_proto;
-                       }
-                       pdg->sz++;
-                       lh = find_partial_datagram(pdgl, dgl);
-               } else {
-                       pd = list_entry(lh, struct partial_datagram, list);
-
-                       if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
-                               /* Overlapping fragments, obliterate old
-                                * datagram and start new one. */
-                               purge_partial_datagram(lh);
-                               retval = new_partial_datagram(dev, pdgl, dgl,
-                                                             dg_size,
-                                                             buf + hdr_len,
-                                                             fg_off, fg_len);
-                               if (retval < 0) {
-                                       pdg->sz--;
-                                       spin_unlock_irqrestore(&pdg->lock, flags);
-                                       goto bad_proto;
-                               }
-                       } else {
-                               retval = update_partial_datagram(pdgl, lh,
-                                                                buf + hdr_len,
-                                                                fg_off, fg_len);
-                               if (retval < 0) {
-                                       /* Couldn't save off fragment anyway
-                                        * so might as well obliterate the
-                                        * datagram now. */
-                                       purge_partial_datagram(lh);
-                                       pdg->sz--;
-                                       spin_unlock_irqrestore(&pdg->lock, flags);
-                                       goto bad_proto;
-                               }
-                       } /* fragment overlap */
-               } /* new datagram or add to existing one */
-
-               pd = list_entry(lh, struct partial_datagram, list);
-
-               if (hdr->common.lf == ETH1394_HDR_LF_FF)
-                       pd->ether_type = ether_type;
-
-               if (is_datagram_complete(lh, dg_size)) {
-                       ether_type = pd->ether_type;
-                       pdg->sz--;
-                       skb = skb_get(pd->skb);
-                       purge_partial_datagram(lh);
-                       spin_unlock_irqrestore(&pdg->lock, flags);
-               } else {
-                       /* Datagram is not complete, we're done for the
-                        * moment. */
-                       spin_unlock_irqrestore(&pdg->lock, flags);
-                       return 0;
-               }
-       } /* unframgented datagram or fragmented one */
-
-       /* Write metadata, and then pass to the receive level */
-       skb->dev = dev;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;  /* don't check it */
-
-       /* Parse the encapsulation header. This actually does the job of
-        * converting to an ethernet frame header, aswell as arp
-        * conversion if needed. ARP conversion is easier in this
-        * direction, since we are using ethernet as our backend.  */
-       skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
-                                             ether_type);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       if (!skb->protocol) {
-               dev->stats.rx_errors++;
-               dev->stats.rx_dropped++;
-               dev_kfree_skb_any(skb);
-       } else if (netif_rx(skb) == NET_RX_DROP) {
-               dev->stats.rx_errors++;
-               dev->stats.rx_dropped++;
-       } else {
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += skb->len;
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-bad_proto:
-       if (netif_queue_stopped(dev))
-               netif_wake_queue(dev);
-
-       return 0;
-}
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
-                          quadlet_t *data, u64 addr, size_t len, u16 flags)
-{
-       struct eth1394_host_info *hi;
-
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-       if (unlikely(!hi)) {
-               ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
-                               host->id);
-               return RCODE_ADDRESS_ERROR;
-       }
-
-       if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
-               return RCODE_ADDRESS_ERROR;
-       else
-               return RCODE_COMPLETE;
-}
-
-static void ether1394_iso(struct hpsb_iso *iso)
-{
-       __be32 *data;
-       char *buf;
-       struct eth1394_host_info *hi;
-       struct net_device *dev;
-       unsigned int len;
-       u32 specifier_id;
-       u16 source_id;
-       int i;
-       int nready;
-
-       hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
-       if (unlikely(!hi)) {
-               ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
-                               iso->host->id);
-               return;
-       }
-
-       dev = hi->dev;
-
-       nready = hpsb_iso_n_ready(iso);
-       for (i = 0; i < nready; i++) {
-               struct hpsb_iso_packet_info *info =
-                       &iso->infos[(iso->first_packet + i) % iso->buf_packets];
-               data = (__be32 *)(iso->data_buf.kvirt + info->offset);
-
-               /* skip over GASP header */
-               buf = (char *)data + 8;
-               len = info->len - 8;
-
-               specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
-                              (be32_to_cpu(data[1]) & 0xff000000) >> 24;
-               source_id = be32_to_cpu(data[0]) >> 16;
-
-               if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
-                   || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
-                       /* This packet is not for us */
-                       continue;
-               }
-               ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES,
-                                      buf, len);
-       }
-
-       hpsb_iso_recv_release_packets(iso, i);
-
-}
-
-/******************************************
- * Datagram transmission code
- ******************************************/
-
-/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire
- * arphdr) is the same format as the ip1394 header, so they overlap.  The rest
- * needs to be munged a bit.  The remainder of the arphdr is formatted based
- * on hwaddr len and ipaddr len.  We know what they'll be, so it's easy to
- * judge.
- *
- * Now that the EUI is used for the hardware address all we need to do to make
- * this work for 1394 is to insert 2 quadlets that contain max_rec size,
- * speed, and unicast FIFO address information between the sender_unique_id
- * and the IP addresses.
- */
-static void ether1394_arp_to_1394arp(struct sk_buff *skb,
-                                    struct net_device *dev)
-{
-       struct eth1394_priv *priv = netdev_priv(dev);
-       struct arphdr *arp = (struct arphdr *)skb->data;
-       unsigned char *arp_ptr = (unsigned char *)(arp + 1);
-       struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-
-       arp1394->hw_addr_len    = 16;
-       arp1394->sip            = *(u32*)(arp_ptr + ETH1394_ALEN);
-       arp1394->max_rec        = priv->host->csr.max_rec;
-       arp1394->sspd           = priv->host->csr.lnk_spd;
-       arp1394->fifo_hi        = htons(priv->local_fifo >> 32);
-       arp1394->fifo_lo        = htonl(priv->local_fifo & ~0x0);
-}
-
-/* We need to encapsulate the standard header with our own. We use the
- * ethernet header's proto for our own. */
-static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
-                                              __be16 proto,
-                                              union eth1394_hdr *hdr,
-                                              u16 dg_size, u16 dgl)
-{
-       unsigned int adj_max_payload =
-                               max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
-
-       /* Does it all fit in one packet? */
-       if (dg_size <= adj_max_payload) {
-               hdr->uf.lf = ETH1394_HDR_LF_UF;
-               hdr->uf.ether_type = proto;
-       } else {
-               hdr->ff.lf = ETH1394_HDR_LF_FF;
-               hdr->ff.ether_type = proto;
-               hdr->ff.dg_size = dg_size - 1;
-               hdr->ff.dgl = dgl;
-               adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
-       }
-       return DIV_ROUND_UP(dg_size, adj_max_payload);
-}
-
-static unsigned int ether1394_encapsulate(struct sk_buff *skb,
-                                         unsigned int max_payload,
-                                         union eth1394_hdr *hdr)
-{
-       union eth1394_hdr *bufhdr;
-       int ftype = hdr->common.lf;
-       int hdrsz = hdr_type_len[ftype];
-       unsigned int adj_max_payload = max_payload - hdrsz;
-
-       switch (ftype) {
-       case ETH1394_HDR_LF_UF:
-               bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
-               bufhdr->words.word1 = htons(hdr->words.word1);
-               bufhdr->words.word2 = hdr->words.word2;
-               break;
-
-       case ETH1394_HDR_LF_FF:
-               bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
-               bufhdr->words.word1 = htons(hdr->words.word1);
-               bufhdr->words.word2 = hdr->words.word2;
-               bufhdr->words.word3 = htons(hdr->words.word3);
-               bufhdr->words.word4 = 0;
-
-               /* Set frag type here for future interior fragments */
-               hdr->common.lf = ETH1394_HDR_LF_IF;
-               hdr->sf.fg_off = 0;
-               break;
-
-       default:
-               hdr->sf.fg_off += adj_max_payload;
-               bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload);
-               if (max_payload >= skb->len)
-                       hdr->common.lf = ETH1394_HDR_LF_LF;
-               bufhdr->words.word1 = htons(hdr->words.word1);
-               bufhdr->words.word2 = htons(hdr->words.word2);
-               bufhdr->words.word3 = htons(hdr->words.word3);
-               bufhdr->words.word4 = 0;
-       }
-       return min(max_payload, skb->len);
-}
-
-static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
-{
-       struct hpsb_packet *p;
-
-       p = hpsb_alloc_packet(0);
-       if (p) {
-               p->host = host;
-               p->generation = get_hpsb_generation(host);
-               p->type = hpsb_async;
-       }
-       return p;
-}
-
-static int ether1394_prep_write_packet(struct hpsb_packet *p,
-                                      struct hpsb_host *host, nodeid_t node,
-                                      u64 addr, void *data, int tx_len)
-{
-       p->node_id = node;
-
-       if (hpsb_get_tlabel(p))
-               return -EAGAIN;
-
-       p->tcode = TCODE_WRITEB;
-       p->header_size = 16;
-       p->expect_response = 1;
-       p->header[0] =
-               p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
-       p->header[1] = host->node_id << 16 | addr >> 32;
-       p->header[2] = addr & 0xffffffff;
-       p->header[3] = tx_len << 16;
-       p->data_size = (tx_len + 3) & ~3;
-       p->data = data;
-
-       return 0;
-}
-
-static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
-                                      struct eth1394_priv *priv,
-                                      struct sk_buff *skb, int length)
-{
-       p->header_size = 4;
-       p->tcode = TCODE_STREAM_DATA;
-
-       p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
-                      TCODE_STREAM_DATA << 4;
-       p->data_size = length;
-       p->data = (quadlet_t *)skb->data - 2;
-       p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
-                                ETHER1394_GASP_SPECIFIER_ID_HI);
-       p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
-                                ETHER1394_GASP_VERSION);
-
-       p->speed_code = priv->bc_sspd;
-
-       /* prevent hpsb_send_packet() from overriding our speed code */
-       p->node_id = LOCAL_BUS | ALL_NODES;
-}
-
-static void ether1394_free_packet(struct hpsb_packet *packet)
-{
-       if (packet->tcode != TCODE_STREAM_DATA)
-               hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-}
-
-static void ether1394_complete_cb(void *__ptask);
-
-static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
-{
-       struct eth1394_priv *priv = ptask->priv;
-       struct hpsb_packet *packet = NULL;
-
-       packet = ether1394_alloc_common_packet(priv->host);
-       if (!packet)
-               return -ENOMEM;
-
-       if (ptask->tx_type == ETH1394_GASP) {
-               int length = tx_len + 2 * sizeof(quadlet_t);
-
-               ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
-       } else if (ether1394_prep_write_packet(packet, priv->host,
-                                              ptask->dest_node,
-                                              ptask->addr, ptask->skb->data,
-                                              tx_len)) {
-               hpsb_free_packet(packet);
-               return -EAGAIN;
-       }
-
-       ptask->packet = packet;
-       hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb,
-                                     ptask);
-
-       if (hpsb_send_packet(packet) < 0) {
-               ether1394_free_packet(packet);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/* Task function to be run when a datagram transmission is completed */
-static void ether1394_dg_complete(struct packet_task *ptask, int fail)
-{
-       struct sk_buff *skb = ptask->skb;
-       struct net_device *dev = skb->dev;
-       struct eth1394_priv *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* Statistics */
-       spin_lock_irqsave(&priv->lock, flags);
-       if (fail) {
-               dev->stats.tx_dropped++;
-               dev->stats.tx_errors++;
-       } else {
-               dev->stats.tx_bytes += skb->len;
-               dev->stats.tx_packets++;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       dev_kfree_skb_any(skb);
-       kmem_cache_free(packet_task_cache, ptask);
-}
-
-/* Callback for when a packet has been sent and the status of that packet is
- * known */
-static void ether1394_complete_cb(void *__ptask)
-{
-       struct packet_task *ptask = (struct packet_task *)__ptask;
-       struct hpsb_packet *packet = ptask->packet;
-       int fail = 0;
-
-       if (packet->tcode != TCODE_STREAM_DATA)
-               fail = hpsb_packet_success(packet);
-
-       ether1394_free_packet(packet);
-
-       ptask->outstanding_pkts--;
-       if (ptask->outstanding_pkts > 0 && !fail) {
-               int tx_len, err;
-
-               /* Add the encapsulation header to the fragment */
-               tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
-                                              &ptask->hdr);
-               err = ether1394_send_packet(ptask, tx_len);
-               if (err) {
-                       if (err == -EAGAIN)
-                               ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
-
-                       ether1394_dg_complete(ptask, 1);
-               }
-       } else {
-               ether1394_dg_complete(ptask, fail);
-       }
-}
-
-/* Transmit a packet (called by kernel) */
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
-                               struct net_device *dev)
-{
-       struct eth1394hdr hdr_buf;
-       struct eth1394_priv *priv = netdev_priv(dev);
-       __be16 proto;
-       unsigned long flags;
-       nodeid_t dest_node;
-       eth1394_tx_type tx_type;
-       unsigned int tx_len;
-       unsigned int max_payload;
-       u16 dg_size;
-       u16 dgl;
-       struct packet_task *ptask;
-       struct eth1394_node_ref *node;
-       struct eth1394_node_info *node_info = NULL;
-
-       ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
-       if (ptask == NULL)
-               goto fail;
-
-       /* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
-        * it does not set our validity bit. We need to compensate for
-        * that somewhere else, but not in eth1394. */
-#if 0
-       if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
-               goto fail;
-#endif
-
-       skb = skb_share_check(skb, GFP_ATOMIC);
-       if (!skb)
-               goto fail;
-
-       /* Get rid of the fake eth1394 header, but first make a copy.
-        * We might need to rebuild the header on tx failure. */
-       memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
-       skb_pull(skb, ETH1394_HLEN);
-
-       proto = hdr_buf.h_proto;
-       dg_size = skb->len;
-
-       /* Set the transmission type for the packet.  ARP packets and IP
-        * broadcast packets are sent via GASP. */
-       if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
-           proto == htons(ETH_P_ARP) ||
-           (proto == htons(ETH_P_IP) &&
-            IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
-               tx_type = ETH1394_GASP;
-               dest_node = LOCAL_BUS | ALL_NODES;
-               max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
-               BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-               dgl = priv->bc_dgl;
-               if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
-                       priv->bc_dgl++;
-       } else {
-               __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
-
-               node = eth1394_find_node_guid(&priv->ip_node_list,
-                                             be64_to_cpu(guid));
-               if (!node)
-                       goto fail;
-
-               node_info = dev_get_drvdata(&node->ud->device);
-               if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
-                       goto fail;
-
-               dest_node = node->ud->ne->nodeid;
-               max_payload = node_info->maxpayload;
-               BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-
-               dgl = node_info->dgl;
-               if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
-                       node_info->dgl++;
-               tx_type = ETH1394_WRREQ;
-       }
-
-       /* If this is an ARP packet, convert it */
-       if (proto == htons(ETH_P_ARP))
-               ether1394_arp_to_1394arp(skb, dev);
-
-       ptask->hdr.words.word1 = 0;
-       ptask->hdr.words.word2 = 0;
-       ptask->hdr.words.word3 = 0;
-       ptask->hdr.words.word4 = 0;
-       ptask->skb = skb;
-       ptask->priv = priv;
-       ptask->tx_type = tx_type;
-
-       if (tx_type != ETH1394_GASP) {
-               u64 addr;
-
-               spin_lock_irqsave(&priv->lock, flags);
-               addr = node_info->fifo;
-               spin_unlock_irqrestore(&priv->lock, flags);
-
-               ptask->addr = addr;
-               ptask->dest_node = dest_node;
-       }
-
-       ptask->tx_type = tx_type;
-       ptask->max_payload = max_payload;
-       ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
-                                       proto, &ptask->hdr, dg_size, dgl);
-
-       /* Add the encapsulation header to the fragment */
-       tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
-       dev->trans_start = jiffies;
-       if (ether1394_send_packet(ptask, tx_len)) {
-               if (dest_node == (LOCAL_BUS | ALL_NODES))
-                       goto fail;
-
-               /* At this point we want to restore the packet.  When we return
-                * here with NETDEV_TX_BUSY we will get another entrance in this
-                * routine with the same skb and we need it to look the same.
-                * So we pull 4 more bytes, then build the header again. */
-               skb_pull(skb, 4);
-               ether1394_header(skb, dev, ntohs(hdr_buf.h_proto),
-                                hdr_buf.h_dest, NULL, 0);
-
-               /* Most failures of ether1394_send_packet are recoverable. */
-               netif_stop_queue(dev);
-               priv->wake_node = dest_node;
-               schedule_work(&priv->wake);
-               kmem_cache_free(packet_task_cache, ptask);
-               return NETDEV_TX_BUSY;
-       }
-
-       return NETDEV_TX_OK;
-fail:
-       if (ptask)
-               kmem_cache_free(packet_task_cache, ptask);
-
-       if (skb != NULL)
-               dev_kfree_skb(skb);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       dev->stats.tx_dropped++;
-       dev->stats.tx_errors++;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return NETDEV_TX_OK;
-}
-
-static int __init ether1394_init_module(void)
-{
-       int err;
-
-       packet_task_cache = kmem_cache_create("packet_task",
-                                             sizeof(struct packet_task),
-                                             0, 0, NULL);
-       if (!packet_task_cache)
-               return -ENOMEM;
-
-       hpsb_register_highlevel(&eth1394_highlevel);
-       err = hpsb_register_protocol(&eth1394_proto_driver);
-       if (err) {
-               hpsb_unregister_highlevel(&eth1394_highlevel);
-               kmem_cache_destroy(packet_task_cache);
-       }
-       return err;
-}
-
-static void __exit ether1394_exit_module(void)
-{
-       hpsb_unregister_protocol(&eth1394_proto_driver);
-       hpsb_unregister_highlevel(&eth1394_highlevel);
-       kmem_cache_destroy(packet_task_cache);
-}
-
-module_init(ether1394_init_module);
-module_exit(ether1394_exit_module);
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
deleted file mode 100644 (file)
index d53bac4..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
- *           (C) 2001 Ben Collins <bcollins@debian.org>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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 __ETH1394_H
-#define __ETH1394_H
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-
-/* Register for incoming packets. This is 4096 bytes, which supports up to
- * S3200 (per Table 16-3 of IEEE 1394b-2002). */
-#define ETHER1394_REGION_ADDR_LEN      4096
-
-/* GASP identifier numbers for IPv4 over IEEE 1394 */
-#define ETHER1394_GASP_SPECIFIER_ID    0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
-#define ETHER1394_GASP_VERSION         1
-
-#define ETHER1394_GASP_OVERHEAD        (2 * sizeof(quadlet_t)) /* for GASP header */
-
-#define ETHER1394_GASP_BUFFERS 16
-
-#define NODE_SET               (ALL_NODES + 1)         /* Node set == 64 */
-
-enum eth1394_bc_states { ETHER1394_BC_ERROR,
-                        ETHER1394_BC_RUNNING,
-                        ETHER1394_BC_STOPPED };
-
-
-/* Private structure for our ethernet driver */
-struct eth1394_priv {
-       struct hpsb_host *host;         /* The card for this dev         */
-       u16 bc_maxpayload;              /* Max broadcast payload         */
-       u8 bc_sspd;                     /* Max broadcast speed           */
-       u64 local_fifo;                 /* Local FIFO Address            */
-       spinlock_t lock;                /* Private lock                  */
-       int broadcast_channel;          /* Async stream Broadcast Channel */
-       enum eth1394_bc_states bc_state; /* broadcast channel state      */
-       struct hpsb_iso *iso;           /* Async stream recv handle      */
-       int bc_dgl;                     /* Outgoing broadcast datagram label */
-       struct list_head ip_node_list;  /* List of IP capable nodes      */
-       struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
-
-       struct work_struct wake;        /* Wake up after xmit failure    */
-       struct net_device *wake_dev;    /* Stupid backlink for .wake     */
-       nodeid_t wake_node;             /* Destination of failed xmit    */
-};
-
-
-/* Define a fake hardware header format for the networking core.  Note that
- * header size cannot exceed 16 bytes as that is the size of the header cache.
- * Also, we do not need the source address in the header so we omit it and
- * keep the header to under 16 bytes */
-#define ETH1394_ALEN (8)
-#define ETH1394_HLEN (10)
-
-struct eth1394hdr {
-       unsigned char   h_dest[ETH1394_ALEN];   /* destination eth1394 addr     */
-       __be16          h_proto;                /* packet type ID field */
-}  __attribute__((packed));
-
-static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
-{
-       return (struct eth1394hdr *)skb_mac_header(skb);
-}
-
-typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
-
-/* IP1394 headers */
-
-/* Unfragmented */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
-       u16 lf:2;
-       u16 res:14;
-       __be16 ether_type;              /* Ethernet packet type */
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
-       u16 res:14;
-       u16 lf:2;
-       __be16 ether_type;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* First fragment */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
-       u16 lf:2;
-       u16 res1:2;
-       u16 dg_size:12;         /* Datagram size */
-       __be16 ether_type;              /* Ethernet packet type */
-       u16 dgl;                /* Datagram label */
-       u16 res2;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
-       u16 dg_size:12;
-       u16 res1:2;
-       u16 lf:2;
-       __be16 ether_type;
-       u16 dgl;
-       u16 res2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* XXX: Subsequent fragments, including last */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
-       u16 lf:2;
-       u16 res1:2;
-       u16 dg_size:12;         /* Datagram size */
-       u16 res2:4;
-       u16 fg_off:12;          /* Fragment offset */
-       u16 dgl;                /* Datagram label */
-       u16 res3;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
-       u16 dg_size:12;
-       u16 res1:2;
-       u16 lf:2;
-       u16 fg_off:12;
-       u16 res2:4;
-       u16 dgl;
-       u16 res3;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
-       u16 lf:2;
-       u16 pad1:14;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
-       u16 pad1:14;
-       u16 lf:2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-struct eth1394_hdr_words {
-       u16 word1;
-       u16 word2;
-       u16 word3;
-       u16 word4;
-};
-
-union eth1394_hdr {
-       struct eth1394_common_hdr common;
-       struct eth1394_uf_hdr uf;
-       struct eth1394_ff_hdr ff;
-       struct eth1394_sf_hdr sf;
-       struct eth1394_hdr_words words;
-};
-
-/* End of IP1394 headers */
-
-/* Fragment types */
-#define ETH1394_HDR_LF_UF      0       /* unfragmented         */
-#define ETH1394_HDR_LF_FF      1       /* first fragment       */
-#define ETH1394_HDR_LF_LF      2       /* last fragment        */
-#define ETH1394_HDR_LF_IF      3       /* interior fragment    */
-
-#define IP1394_HW_ADDR_LEN     16      /* As per RFC           */
-
-/* Our arp packet (ARPHRD_IEEE1394) */
-struct eth1394_arp {
-       u16 hw_type;            /* 0x0018       */
-       u16 proto_type;         /* 0x0806       */
-       u8 hw_addr_len;         /* 16           */
-       u8 ip_addr_len;         /* 4            */
-       u16 opcode;             /* ARP Opcode   */
-       /* Above is exactly the same format as struct arphdr */
-
-       __be64 s_uniq_id;       /* Sender's 64bit EUI           */
-       u8 max_rec;             /* Sender's max packet size             */
-       u8 sspd;                /* Sender's max speed                   */
-       __be16 fifo_hi;         /* hi 16bits of sender's FIFO addr      */
-       __be32 fifo_lo;         /* lo 32bits of sender's FIFO addr      */
-       u32 sip;                /* Sender's IP Address                  */
-       u32 tip;                /* IP Address of requested hw addr      */
-};
-
-/* Network timeout */
-#define ETHER1394_TIMEOUT      100000
-
-/* This is our task struct. It's used for the packet complete callback.  */
-struct packet_task {
-       struct sk_buff *skb;
-       int outstanding_pkts;
-       eth1394_tx_type tx_type;
-       int max_payload;
-       struct hpsb_packet *packet;
-       struct eth1394_priv *priv;
-       union eth1394_hdr hdr;
-       u64 addr;
-       u16 dest_node;
-};
-
-#endif /* __ETH1394_H */
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
deleted file mode 100644 (file)
index 4bc4435..0000000
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Christian Toegel <christian.toegel@gmx.at>
- *        unregister address space
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        unregister address space
- *
- */
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-
-struct hl_host_info {
-       struct list_head list;
-       struct hpsb_host *host;
-       size_t size;
-       unsigned long key;
-       void *data;
-};
-
-
-static LIST_HEAD(hl_drivers);
-static DECLARE_RWSEM(hl_drivers_sem);
-
-static LIST_HEAD(hl_irqs);
-static DEFINE_RWLOCK(hl_irqs_lock);
-
-static DEFINE_RWLOCK(addr_space_lock);
-
-
-static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
-                                           struct hpsb_host *host)
-{
-       struct hl_host_info *hi = NULL;
-
-       if (!hl || !host)
-               return NULL;
-
-       read_lock(&hl->host_info_lock);
-       list_for_each_entry(hi, &hl->host_info_list, list) {
-               if (hi->host == host) {
-                       read_unlock(&hl->host_info_lock);
-                       return hi;
-               }
-       }
-       read_unlock(&hl->host_info_lock);
-       return NULL;
-}
-
-/**
- * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
- *
- * Returns a per @host and @hl driver data structure that was previously stored
- * by hpsb_create_hostinfo.
- */
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
-       struct hl_host_info *hi = hl_get_hostinfo(hl, host);
-
-       return hi ? hi->data : NULL;
-}
-
-/**
- * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
- *
- * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
- * to this @hl driver and @host.  If @data_size is zero, then the return here is
- * only valid for error checking.
- */
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          size_t data_size)
-{
-       struct hl_host_info *hi;
-       void *data;
-       unsigned long flags;
-
-       hi = hl_get_hostinfo(hl, host);
-       if (hi) {
-               HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
-                        " exists", hl->name);
-               return NULL;
-       }
-
-       hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
-       if (!hi)
-               return NULL;
-
-       if (data_size) {
-               data = hi->data = hi + 1;
-               hi->size = data_size;
-       } else
-               data = hi;
-
-       hi->host = host;
-
-       write_lock_irqsave(&hl->host_info_lock, flags);
-       list_add_tail(&hi->list, &hl->host_info_list);
-       write_unlock_irqrestore(&hl->host_info_lock, flags);
-
-       return data;
-}
-
-/**
- * hpsb_set_hostinfo - set the hostinfo pointer to something useful
- *
- * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
- */
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                     void *data)
-{
-       struct hl_host_info *hi;
-
-       hi = hl_get_hostinfo(hl, host);
-       if (hi) {
-               if (!hi->size && !hi->data) {
-                       hi->data = data;
-                       return 0;
-               } else
-                       HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
-                                "already has data", hl->name);
-       } else
-               HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
-                        hl->name);
-       return -EINVAL;
-}
-
-/**
- * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
- *
- * Free and remove the hostinfo pointer bound to this @hl driver and @host.
- */
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
-       struct hl_host_info *hi;
-
-       hi = hl_get_hostinfo(hl, host);
-       if (hi) {
-               unsigned long flags;
-               write_lock_irqsave(&hl->host_info_lock, flags);
-               list_del(&hi->list);
-               write_unlock_irqrestore(&hl->host_info_lock, flags);
-               kfree(hi);
-       }
-       return;
-}
-
-/**
- * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
- *
- * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
- * @host.
- */
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          unsigned long key)
-{
-       struct hl_host_info *hi;
-
-       hi = hl_get_hostinfo(hl, host);
-       if (hi)
-               hi->key = key;
-       return;
-}
-
-/**
- * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
- */
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
-{
-       struct hl_host_info *hi;
-       void *data = NULL;
-
-       if (!hl)
-               return NULL;
-
-       read_lock(&hl->host_info_lock);
-       list_for_each_entry(hi, &hl->host_info_list, list) {
-               if (hi->key == key) {
-                       data = hi->data;
-                       break;
-               }
-       }
-       read_unlock(&hl->host_info_lock);
-       return data;
-}
-
-static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
-{
-       struct hpsb_highlevel *hl = __data;
-
-       hl->add_host(host);
-
-       if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
-               HPSB_ERR("Failed to generate Configuration ROM image for host "
-                        "%s-%d", hl->name, host->id);
-       return 0;
-}
-
-/**
- * hpsb_register_highlevel - register highlevel driver
- *
- * The name pointer in @hl has to stay valid at all times because the string is
- * not copied.
- */
-void hpsb_register_highlevel(struct hpsb_highlevel *hl)
-{
-       unsigned long flags;
-
-       hpsb_init_highlevel(hl);
-       INIT_LIST_HEAD(&hl->addr_list);
-
-       down_write(&hl_drivers_sem);
-       list_add_tail(&hl->hl_list, &hl_drivers);
-       up_write(&hl_drivers_sem);
-
-       write_lock_irqsave(&hl_irqs_lock, flags);
-       list_add_tail(&hl->irq_list, &hl_irqs);
-       write_unlock_irqrestore(&hl_irqs_lock, flags);
-
-       if (hl->add_host)
-               nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
-       return;
-}
-
-static void __delete_addr(struct hpsb_address_serve *as)
-{
-       list_del(&as->host_list);
-       list_del(&as->hl_list);
-       kfree(as);
-}
-
-static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                             int update_cr)
-{
-       unsigned long flags;
-       struct list_head *lh, *next;
-       struct hpsb_address_serve *as;
-
-       /* First, let the highlevel driver unreg */
-       if (hl->remove_host)
-               hl->remove_host(host);
-
-       /* Remove any addresses that are matched for this highlevel driver
-        * and this particular host. */
-       write_lock_irqsave(&addr_space_lock, flags);
-       list_for_each_safe (lh, next, &hl->addr_list) {
-               as = list_entry(lh, struct hpsb_address_serve, hl_list);
-               if (as->host == host)
-                       __delete_addr(as);
-       }
-       write_unlock_irqrestore(&addr_space_lock, flags);
-
-       /* Now update the config-rom to reflect anything removed by the
-        * highlevel driver. */
-       if (update_cr && host->update_config_rom &&
-           hpsb_update_config_rom_image(host) < 0)
-               HPSB_ERR("Failed to generate Configuration ROM image for host "
-                        "%s-%d", hl->name, host->id);
-
-       /* Finally remove all the host info associated between these two. */
-       hpsb_destroy_hostinfo(hl, host);
-}
-
-static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
-{
-       struct hpsb_highlevel *hl = __data;
-
-       __unregister_host(hl, host, 1);
-       return 0;
-}
-
-/**
- * hpsb_unregister_highlevel - unregister highlevel driver
- */
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
-{
-       unsigned long flags;
-
-       write_lock_irqsave(&hl_irqs_lock, flags);
-       list_del(&hl->irq_list);
-       write_unlock_irqrestore(&hl_irqs_lock, flags);
-
-       down_write(&hl_drivers_sem);
-       list_del(&hl->hl_list);
-       up_write(&hl_drivers_sem);
-
-       nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
-}
-
-/**
- * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses.  This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets.  The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation.  Address spaces can be
- * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
-                                        struct hpsb_host *host,
-                                        const struct hpsb_address_ops *ops,
-                                        u64 size, u64 alignment,
-                                        u64 start, u64 end)
-{
-       struct hpsb_address_serve *as, *a1, *a2;
-       struct list_head *entry;
-       u64 retval = CSR1212_INVALID_ADDR_SPACE;
-       unsigned long flags;
-       u64 align_mask = ~(alignment - 1);
-
-       if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
-           (hweight64(alignment) != 1)) {
-               HPSB_ERR("%s called with invalid alignment: 0x%048llx",
-                        __func__, (unsigned long long)alignment);
-               return retval;
-       }
-
-       /* default range,
-        * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
-       if (start == CSR1212_INVALID_ADDR_SPACE &&
-           end   == CSR1212_INVALID_ADDR_SPACE) {
-               start = host->middle_addr_space;
-               end   = CSR1212_ALL_SPACE_END;
-       }
-
-       if (((start|end) & ~align_mask) || (start >= end) ||
-           (end > CSR1212_ALL_SPACE_END)) {
-               HPSB_ERR("%s called with invalid addresses "
-                        "(start = %012Lx  end = %012Lx)", __func__,
-                        (unsigned long long)start,(unsigned long long)end);
-               return retval;
-       }
-
-       as = kmalloc(sizeof(*as), GFP_KERNEL);
-       if (!as)
-               return retval;
-
-       INIT_LIST_HEAD(&as->host_list);
-       INIT_LIST_HEAD(&as->hl_list);
-       as->op = ops;
-       as->host = host;
-
-       write_lock_irqsave(&addr_space_lock, flags);
-       list_for_each(entry, &host->addr_space) {
-               u64 a1sa, a1ea;
-               u64 a2sa, a2ea;
-
-               a1 = list_entry(entry, struct hpsb_address_serve, host_list);
-               a2 = list_entry(entry->next, struct hpsb_address_serve,
-                               host_list);
-
-               a1sa = a1->start & align_mask;
-               a1ea = (a1->end + alignment -1) & align_mask;
-               a2sa = a2->start & align_mask;
-               a2ea = (a2->end + alignment -1) & align_mask;
-
-               if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
-                   (a2sa > start)) {
-                       as->start = max(start, a1ea);
-                       as->end = as->start + size;
-                       list_add(&as->host_list, entry);
-                       list_add_tail(&as->hl_list, &hl->addr_list);
-                       retval = as->start;
-                       break;
-               }
-       }
-       write_unlock_irqrestore(&addr_space_lock, flags);
-
-       if (retval == CSR1212_INVALID_ADDR_SPACE)
-               kfree(as);
-       return retval;
-}
-
-/**
- * hpsb_register_addrspace - register a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses.  This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets.  The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation.  Address spaces can be
- * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                           const struct hpsb_address_ops *ops,
-                           u64 start, u64 end)
-{
-       struct hpsb_address_serve *as;
-       struct list_head *lh;
-       int retval = 0;
-       unsigned long flags;
-
-       if (((start|end) & 3) || (start >= end) ||
-           (end > CSR1212_ALL_SPACE_END)) {
-               HPSB_ERR("%s called with invalid addresses", __func__);
-               return 0;
-       }
-
-       as = kmalloc(sizeof(*as), GFP_KERNEL);
-       if (!as)
-               return 0;
-
-       INIT_LIST_HEAD(&as->host_list);
-       INIT_LIST_HEAD(&as->hl_list);
-       as->op = ops;
-       as->start = start;
-       as->end = end;
-       as->host = host;
-
-       write_lock_irqsave(&addr_space_lock, flags);
-       list_for_each(lh, &host->addr_space) {
-               struct hpsb_address_serve *as_this =
-                       list_entry(lh, struct hpsb_address_serve, host_list);
-               struct hpsb_address_serve *as_next =
-                       list_entry(lh->next, struct hpsb_address_serve,
-                                  host_list);
-
-               if (as_this->end > as->start)
-                       break;
-
-               if (as_next->start >= as->end) {
-                       list_add(&as->host_list, lh);
-                       list_add_tail(&as->hl_list, &hl->addr_list);
-                       retval = 1;
-                       break;
-               }
-       }
-       write_unlock_irqrestore(&addr_space_lock, flags);
-
-       if (retval == 0)
-               kfree(as);
-       return retval;
-}
-
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                             u64 start)
-{
-       int retval = 0;
-       struct hpsb_address_serve *as;
-       struct list_head *lh, *next;
-       unsigned long flags;
-
-       write_lock_irqsave(&addr_space_lock, flags);
-       list_for_each_safe (lh, next, &hl->addr_list) {
-               as = list_entry(lh, struct hpsb_address_serve, hl_list);
-               if (as->start == start && as->host == host) {
-                       __delete_addr(as);
-                       retval = 1;
-                       break;
-               }
-       }
-       write_unlock_irqrestore(&addr_space_lock, flags);
-       return retval;
-}
-
-static const struct hpsb_address_ops dummy_ops;
-
-/* dummy address spaces as lower and upper bounds of the host's a.s. list */
-static void init_hpsb_highlevel(struct hpsb_host *host)
-{
-       INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
-       INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
-       INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
-       INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
-
-       host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
-
-       host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
-       host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
-
-       list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
-       list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
-}
-
-void highlevel_add_host(struct hpsb_host *host)
-{
-       struct hpsb_highlevel *hl;
-
-       init_hpsb_highlevel(host);
-
-       down_read(&hl_drivers_sem);
-       list_for_each_entry(hl, &hl_drivers, hl_list) {
-               if (hl->add_host)
-                       hl->add_host(host);
-       }
-       up_read(&hl_drivers_sem);
-       if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
-               HPSB_ERR("Failed to generate Configuration ROM image for host "
-                        "%s-%d", hl->name, host->id);
-}
-
-void highlevel_remove_host(struct hpsb_host *host)
-{
-       struct hpsb_highlevel *hl;
-
-       down_read(&hl_drivers_sem);
-       list_for_each_entry(hl, &hl_drivers, hl_list)
-               __unregister_host(hl, host, 0);
-       up_read(&hl_drivers_sem);
-}
-
-void highlevel_host_reset(struct hpsb_host *host)
-{
-       unsigned long flags;
-       struct hpsb_highlevel *hl;
-
-       read_lock_irqsave(&hl_irqs_lock, flags);
-       list_for_each_entry(hl, &hl_irqs, irq_list) {
-               if (hl->host_reset)
-                       hl->host_reset(host);
-       }
-       read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                          void *data, size_t length)
-{
-       unsigned long flags;
-       struct hpsb_highlevel *hl;
-       int cts = ((quadlet_t *)data)[0] >> 4;
-
-       read_lock_irqsave(&hl_irqs_lock, flags);
-       list_for_each_entry(hl, &hl_irqs, irq_list) {
-               if (hl->fcp_request)
-                       hl->fcp_request(host, nodeid, direction, cts, data,
-                                       length);
-       }
-       read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-/*
- * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
- *
- * These functions are called to handle transactions. They are called when a
- * packet arrives.  The flags argument contains the second word of the first
- * header quadlet of the incoming packet (containing transaction label, retry
- * code, transaction code and priority).  These functions either return a
- * response code or a negative number.  In the first case a response will be
- * generated.  In the latter case, no response will be sent and the driver which
- * handled the request will send the response itself.
- */
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
-                  unsigned int length, u16 flags)
-{
-       struct hpsb_address_serve *as;
-       unsigned int partlength;
-       int rcode = RCODE_ADDRESS_ERROR;
-
-       read_lock(&addr_space_lock);
-       list_for_each_entry(as, &host->addr_space, host_list) {
-               if (as->start > addr)
-                       break;
-
-               if (as->end > addr) {
-                       partlength = min(as->end - addr, (u64) length);
-
-                       if (as->op->read)
-                               rcode = as->op->read(host, nodeid, data,
-                                                    addr, partlength, flags);
-                       else
-                               rcode = RCODE_TYPE_ERROR;
-
-                       data += partlength;
-                       length -= partlength;
-                       addr += partlength;
-
-                       if ((rcode != RCODE_COMPLETE) || !length)
-                               break;
-               }
-       }
-       read_unlock(&addr_space_lock);
-
-       if (length && (rcode == RCODE_COMPLETE))
-               rcode = RCODE_ADDRESS_ERROR;
-       return rcode;
-}
-
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
-                   u64 addr, unsigned int length, u16 flags)
-{
-       struct hpsb_address_serve *as;
-       unsigned int partlength;
-       int rcode = RCODE_ADDRESS_ERROR;
-
-       read_lock(&addr_space_lock);
-       list_for_each_entry(as, &host->addr_space, host_list) {
-               if (as->start > addr)
-                       break;
-
-               if (as->end > addr) {
-                       partlength = min(as->end - addr, (u64) length);
-
-                       if (as->op->write)
-                               rcode = as->op->write(host, nodeid, destid,
-                                                     data, addr, partlength,
-                                                     flags);
-                       else
-                               rcode = RCODE_TYPE_ERROR;
-
-                       data += partlength;
-                       length -= partlength;
-                       addr += partlength;
-
-                       if ((rcode != RCODE_COMPLETE) || !length)
-                               break;
-               }
-       }
-       read_unlock(&addr_space_lock);
-
-       if (length && (rcode == RCODE_COMPLETE))
-               rcode = RCODE_ADDRESS_ERROR;
-       return rcode;
-}
-
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                  u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-                  u16 flags)
-{
-       struct hpsb_address_serve *as;
-       int rcode = RCODE_ADDRESS_ERROR;
-
-       read_lock(&addr_space_lock);
-       list_for_each_entry(as, &host->addr_space, host_list) {
-               if (as->start > addr)
-                       break;
-
-               if (as->end > addr) {
-                       if (as->op->lock)
-                               rcode = as->op->lock(host, nodeid, store, addr,
-                                                    data, arg, ext_tcode,
-                                                    flags);
-                       else
-                               rcode = RCODE_TYPE_ERROR;
-                       break;
-               }
-       }
-       read_unlock(&addr_space_lock);
-       return rcode;
-}
-
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                    u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-                    u16 flags)
-{
-       struct hpsb_address_serve *as;
-       int rcode = RCODE_ADDRESS_ERROR;
-
-       read_lock(&addr_space_lock);
-
-       list_for_each_entry(as, &host->addr_space, host_list) {
-               if (as->start > addr)
-                       break;
-
-               if (as->end > addr) {
-                       if (as->op->lock64)
-                               rcode = as->op->lock64(host, nodeid, store,
-                                                      addr, data, arg,
-                                                      ext_tcode, flags);
-                       else
-                               rcode = RCODE_TYPE_ERROR;
-                       break;
-               }
-       }
-       read_unlock(&addr_space_lock);
-       return rcode;
-}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
deleted file mode 100644 (file)
index 9dba89f..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifndef IEEE1394_HIGHLEVEL_H
-#define IEEE1394_HIGHLEVEL_H
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-struct module;
-
-#include "ieee1394_types.h"
-
-struct hpsb_host;
-
-/* internal to ieee1394 core */
-struct hpsb_address_serve {
-       struct list_head host_list;     /* per host list */
-       struct list_head hl_list;       /* hpsb_highlevel list */
-       const struct hpsb_address_ops *op;
-       struct hpsb_host *host;
-       u64 start;      /* first address handled, quadlet aligned */
-       u64 end;        /* first address behind, quadlet aligned */
-};
-
-/* Only the following structures are of interest to actual highlevel drivers. */
-
-struct hpsb_highlevel {
-       const char *name;
-
-       /* Any of the following pointers can legally be NULL. */
-
-       /* New host initialized.  Will also be called during
-        * hpsb_register_highlevel for all hosts already installed. */
-       void (*add_host)(struct hpsb_host *host);
-
-       /* Host about to be removed.  Will also be called during
-        * hpsb_unregister_highlevel once for each host. */
-       void (*remove_host)(struct hpsb_host *host);
-
-       /* Host experienced bus reset with possible configuration changes.
-        * Note that this one may occur during interrupt/bottom half handling.
-        * You can not expect to be able to do stock hpsb_reads. */
-       void (*host_reset)(struct hpsb_host *host);
-
-       /* A write request was received on either the FCP_COMMAND (direction =
-        * 0) or the FCP_RESPONSE (direction = 1) register.  The cts arg
-        * contains the cts field (first byte of data). */
-       void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
-                           int cts, u8 *data, size_t length);
-
-       /* These are initialized by the subsystem when the
-        * hpsb_higlevel is registered. */
-       struct list_head hl_list;
-       struct list_head irq_list;
-       struct list_head addr_list;
-
-       struct list_head host_info_list;
-       rwlock_t host_info_lock;
-};
-
-struct hpsb_address_ops {
-       /*
-        * Null function pointers will make the respective operation complete
-        * with RCODE_TYPE_ERROR.  Makes for easy to implement read-only
-        * registers (just leave everything but read NULL).
-        *
-        * All functions shall return appropriate IEEE 1394 rcodes.
-        */
-
-       /* These functions have to implement block reads for themselves.
-        *
-        * These functions either return a response code or a negative number.
-        * In the first case a response will be generated.  In the latter case,
-        * no response will be sent and the driver which handled the request
-        * will send the response itself. */
-       int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, size_t length, u16 flags);
-       int (*write)(struct hpsb_host *host, int nodeid, int destid,
-                    quadlet_t *data, u64 addr, size_t length, u16 flags);
-
-       /* Lock transactions: write results of ext_tcode operation into
-        * *store. */
-       int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-                   u16 flags);
-       int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-                     u16 flags);
-};
-
-void highlevel_add_host(struct hpsb_host *host);
-void highlevel_remove_host(struct hpsb_host *host);
-void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
-                  unsigned int length, u16 flags);
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
-                   u64 addr, unsigned int length, u16 flags);
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                  u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-                  u16 flags);
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                    u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-                    u16 flags);
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                          void *data, size_t length);
-
-/**
- * hpsb_init_highlevel - initialize a struct hpsb_highlevel
- *
- * This is only necessary if hpsb_get_hostinfo_bykey can be called
- * before hpsb_register_highlevel.
- */
-static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
-{
-       rwlock_init(&hl->host_info_lock);
-       INIT_LIST_HEAD(&hl->host_info_list);
-}
-void hpsb_register_highlevel(struct hpsb_highlevel *hl);
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
-
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
-                                        struct hpsb_host *host,
-                                        const struct hpsb_address_ops *ops,
-                                        u64 size, u64 alignment,
-                                        u64 start, u64 end);
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                           const struct hpsb_address_ops *ops,
-                           u64 start, u64 end);
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                             u64 start);
-
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          size_t data_size);
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          unsigned long key);
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                     void *data);
-
-#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
deleted file mode 100644 (file)
index e947d8f..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Low level (host adapter) management.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * Copyright (C) 1999 Emanuel Pirker
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-#include "csr.h"
-#include "config_roms.h"
-
-
-static void delayed_reset_bus(struct work_struct *work)
-{
-       struct hpsb_host *host =
-               container_of(work, struct hpsb_host, delayed_reset.work);
-       u8 generation = host->csr.generation + 1;
-
-       /* The generation field rolls over to 2 rather than 0 per IEEE
-        * 1394a-2000. */
-       if (generation > 0xf || generation < 2)
-               generation = 2;
-
-       csr_set_bus_info_generation(host->csr.rom, generation);
-       if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
-               /* CSR image creation failed.
-                * Reset generation field and do not issue a bus reset. */
-               csr_set_bus_info_generation(host->csr.rom,
-                                           host->csr.generation);
-               return;
-       }
-
-       host->csr.generation = generation;
-
-       host->update_config_rom = 0;
-       if (host->driver->set_hw_config_rom)
-               host->driver->set_hw_config_rom(host,
-                                               host->csr.rom->bus_info_data);
-
-       host->csr.gen_timestamp[host->csr.generation] = jiffies;
-       hpsb_reset_bus(host, SHORT_RESET);
-}
-
-static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
-{
-       return 0;
-}
-
-static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
-{
-       return -1;
-}
-
-static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
-                       unsigned long arg)
-{
-       return -1;
-}
-
-static struct hpsb_host_driver dummy_driver = {
-       .transmit_packet = dummy_transmit_packet,
-       .devctl =          dummy_devctl,
-       .isoctl =          dummy_isoctl
-};
-
-static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
-{
-       int *hostnum = __data;
-
-       if (host->id == *hostnum)
-               return 1;
-
-       return 0;
-}
-
-static DEFINE_MUTEX(host_num_alloc);
-
-/**
- * hpsb_alloc_host - allocate a new host controller.
- * @drv: the driver that will manage the host controller
- * @extra: number of extra bytes to allocate for the driver
- *
- * Allocate a &hpsb_host and initialize the general subsystem specific
- * fields.  If the driver needs to store per host data, as drivers
- * usually do, the amount of memory required can be specified by the
- * @extra parameter.  Once allocated, the driver should initialize the
- * driver specific parts, enable the controller and make it available
- * to the general subsystem using hpsb_add_host().
- *
- * Return Value: a pointer to the &hpsb_host if successful, %NULL if
- * no memory was available.
- */
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
-                                 struct device *dev)
-{
-       struct hpsb_host *h;
-       int i;
-       int hostnum = 0;
-
-       h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
-       if (!h)
-               return NULL;
-
-       h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
-       if (!h->csr.rom)
-               goto fail;
-
-       h->hostdata = h + 1;
-       h->driver = drv;
-
-       INIT_LIST_HEAD(&h->pending_packets);
-       INIT_LIST_HEAD(&h->addr_space);
-
-       for (i = 2; i < 16; i++)
-               h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
-
-       atomic_set(&h->generation, 0);
-
-       INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
-       
-       init_timer(&h->timeout);
-       h->timeout.data = (unsigned long) h;
-       h->timeout.function = abort_timedouts;
-       h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
-
-       h->topology_map = h->csr.topology_map + 3;
-       h->speed_map = (u8 *)(h->csr.speed_map + 2);
-
-       mutex_lock(&host_num_alloc);
-       while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
-               hostnum++;
-       mutex_unlock(&host_num_alloc);
-       h->id = hostnum;
-
-       memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
-       h->device.parent = dev;
-       set_dev_node(&h->device, dev_to_node(dev));
-       dev_set_name(&h->device, "fw-host%d", h->id);
-
-       h->host_dev.parent = &h->device;
-       h->host_dev.class = &hpsb_host_class;
-       dev_set_name(&h->host_dev, "fw-host%d", h->id);
-
-       if (device_register(&h->device))
-               goto fail;
-       if (device_register(&h->host_dev)) {
-               device_unregister(&h->device);
-               goto fail;
-       }
-       get_device(&h->device);
-
-       return h;
-
-fail:
-       kfree(h);
-       return NULL;
-}
-
-int hpsb_add_host(struct hpsb_host *host)
-{
-       if (hpsb_default_host_entry(host))
-               return -ENOMEM;
-
-       highlevel_add_host(host);
-       return 0;
-}
-
-void hpsb_resume_host(struct hpsb_host *host)
-{
-       if (host->driver->set_hw_config_rom)
-               host->driver->set_hw_config_rom(host,
-                                               host->csr.rom->bus_info_data);
-       host->driver->devctl(host, RESET_BUS, SHORT_RESET);
-}
-
-void hpsb_remove_host(struct hpsb_host *host)
-{
-       host->is_shutdown = 1;
-
-       cancel_delayed_work(&host->delayed_reset);
-       flush_scheduled_work();
-
-       host->driver = &dummy_driver;
-       highlevel_remove_host(host);
-
-       device_unregister(&host->host_dev);
-       device_unregister(&host->device);
-}
-
-/**
- * hpsb_update_config_rom_image - updates configuration ROM image of a host
- *
- * Updates the configuration ROM image of a host.  rom_version must be the
- * current version, otherwise it will fail with return value -1. If this
- * host does not support config-rom-update, it will return -%EINVAL.
- * Return value 0 indicates success.
- */
-int hpsb_update_config_rom_image(struct hpsb_host *host)
-{
-       unsigned long reset_delay;
-       int next_gen = host->csr.generation + 1;
-
-       if (!host->update_config_rom)
-               return -EINVAL;
-
-       if (next_gen > 0xf)
-               next_gen = 2;
-
-       /* Stop the delayed interrupt, we're about to change the config rom and
-        * it would be a waste to do a bus reset twice. */
-       cancel_delayed_work(&host->delayed_reset);
-
-       /* IEEE 1394a-2000 prohibits using the same generation number
-        * twice in a 60 second period. */
-       if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
-               /* Wait 60 seconds from the last time this generation number was
-                * used. */
-               reset_delay =
-                       (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
-       else
-               /* Wait 1 second in case some other code wants to change the
-                * Config ROM in the near future. */
-               reset_delay = HZ;
-
-       PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
-       schedule_delayed_work(&host->delayed_reset, reset_delay);
-
-       return 0;
-}
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
deleted file mode 100644 (file)
index 49c3590..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef _IEEE1394_HOSTS_H
-#define _IEEE1394_HOSTS_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-#include <asm/atomic.h>
-
-struct pci_dev;
-struct module;
-
-#include "ieee1394_types.h"
-#include "csr.h"
-#include "highlevel.h"
-
-struct hpsb_packet;
-struct hpsb_iso;
-
-struct hpsb_host {
-       struct list_head host_list;
-
-       void *hostdata;
-
-       atomic_t generation;
-
-       struct list_head pending_packets;
-       struct timer_list timeout;
-       unsigned long timeout_interval;
-
-       int node_count;      /* number of identified nodes on this bus */
-       int selfid_count;    /* total number of SelfIDs received */
-       int nodes_active;    /* number of nodes with active link layer */
-
-       nodeid_t node_id;    /* node ID of this host */
-       nodeid_t irm_id;     /* ID of this bus' isochronous resource manager */
-       nodeid_t busmgr_id;  /* ID of this bus' bus manager */
-
-       /* this nodes state */
-       unsigned in_bus_reset:1;
-       unsigned is_shutdown:1;
-       unsigned resume_packet_sent:1;
-
-       /* this nodes' duties on the bus */
-       unsigned is_root:1;
-       unsigned is_cycmst:1;
-       unsigned is_irm:1;
-       unsigned is_busmgr:1;
-
-       int reset_retries;
-       quadlet_t *topology_map;
-       u8 *speed_map;
-
-       int id;
-       struct hpsb_host_driver *driver;
-       struct pci_dev *pdev;
-       struct device device;
-       struct device host_dev;
-
-       struct delayed_work delayed_reset;
-       unsigned config_roms:31;
-       unsigned update_config_rom:1;
-
-       struct list_head addr_space;
-       u64 low_addr_space;     /* upper bound of physical DMA area */
-       u64 middle_addr_space;  /* upper bound of posted write area */
-
-       u8 speed[ALL_NODES];    /* speed between each node and local node */
-
-       /* per node tlabel allocation */
-       u8 next_tl[ALL_NODES];
-       struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
-
-       struct csr_control csr;
-
-       struct hpsb_address_serve dummy_zero_addr;
-       struct hpsb_address_serve dummy_max_addr;
-};
-
-enum devctl_cmd {
-       /* Host is requested to reset its bus and cancel all outstanding async
-        * requests.  If arg == 1, it shall also attempt to become root on the
-        * bus.  Return void. */
-       RESET_BUS,
-
-       /* Arg is void, return value is the hardware cycle counter value. */
-       GET_CYCLE_COUNTER,
-
-       /* Set the hardware cycle counter to the value in arg, return void.
-        * FIXME - setting is probably not required. */
-       SET_CYCLE_COUNTER,
-
-       /* Configure hardware for new bus ID in arg, return void. */
-       SET_BUS_ID,
-
-       /* If arg true, start sending cycle start packets, stop if arg == 0.
-        * Return void. */
-       ACT_CYCLE_MASTER,
-
-       /* Cancel all outstanding async requests without resetting the bus.
-        * Return void. */
-       CANCEL_REQUESTS,
-};
-
-enum isoctl_cmd {
-       /* rawiso API - see iso.h for the meanings of these commands
-        * (they correspond exactly to the hpsb_iso_* API functions)
-        * INIT = allocate resources
-        * START = begin transmission/reception
-        * STOP = halt transmission/reception
-        * QUEUE/RELEASE = produce/consume packets
-        * SHUTDOWN = deallocate resources
-        */
-
-       XMIT_INIT,
-       XMIT_START,
-       XMIT_STOP,
-       XMIT_QUEUE,
-       XMIT_SHUTDOWN,
-
-       RECV_INIT,
-       RECV_LISTEN_CHANNEL,   /* multi-channel only */
-       RECV_UNLISTEN_CHANNEL, /* multi-channel only */
-       RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
-       RECV_START,
-       RECV_STOP,
-       RECV_RELEASE,
-       RECV_SHUTDOWN,
-       RECV_FLUSH
-};
-
-enum reset_types {
-       /* 166 microsecond reset -- only type of reset available on
-          non-1394a capable controllers */
-       LONG_RESET,
-
-       /* Short (arbitrated) reset -- only available on 1394a capable
-          controllers */
-       SHORT_RESET,
-
-       /* Variants that set force_root before issueing the bus reset */
-       LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
-
-       /* Variants that clear force_root before issueing the bus reset */
-       LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
-};
-
-struct hpsb_host_driver {
-       struct module *owner;
-       const char *name;
-
-       /* The hardware driver may optionally support a function that is used
-        * to set the hardware ConfigROM if the hardware supports handling
-        * reads to the ConfigROM on its own. */
-       void (*set_hw_config_rom)(struct hpsb_host *host,
-                                 __be32 *config_rom);
-
-       /* This function shall implement packet transmission based on
-        * packet->type.  It shall CRC both parts of the packet (unless
-        * packet->type == raw) and do byte-swapping as necessary or instruct
-        * the hardware to do so.  It can return immediately after the packet
-        * was queued for sending.  After sending, hpsb_sent_packet() has to be
-        * called.  Return 0 on success, negative errno on failure.
-        * NOTE: The function must be callable in interrupt context.
-        */
-       int (*transmit_packet)(struct hpsb_host *host,
-                              struct hpsb_packet *packet);
-
-       /* This function requests miscellanous services from the driver, see
-        * above for command codes and expected actions.  Return -1 for unknown
-        * command, though that should never happen.
-        */
-       int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
-
-        /* ISO transmission/reception functions. Return 0 on success, -1
-         * (or -EXXX errno code) on failure. If the low-level driver does not
-         * support the new ISO API, set isoctl to NULL.
-         */
-       int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
-                     unsigned long arg);
-
-       /* This function is mainly to redirect local CSR reads/locks to the iso
-        * management registers (bus manager id, bandwidth available, channels
-        * available) to the hardware registers in OHCI.  reg is 0,1,2,3 for bus
-        * mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
-        * as OHCI uses).  data and compare are the new data and expected data
-        * respectively, return value is the old value.
-        */
-       quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
-                                quadlet_t data, quadlet_t compare);
-};
-
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
-                                 struct device *dev);
-int hpsb_add_host(struct hpsb_host *host);
-void hpsb_resume_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *host);
-int hpsb_update_config_rom_image(struct hpsb_host *host);
-
-#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
deleted file mode 100644 (file)
index 46878fe..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Base file for all ieee1394 ioctl's.
- * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
- */
-
-#ifndef __IEEE1394_IOCTL_H
-#define __IEEE1394_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/* DV1394 Gets 10 */
-
-/* Get the driver ready to transmit video.  pass a struct dv1394_init* as
- * the parameter (see below), or NULL to get default parameters */
-#define DV1394_IOC_INIT                        _IOW('#', 0x06, struct dv1394_init)
-
-/* Stop transmitting video and free the ringbuffer */
-#define DV1394_IOC_SHUTDOWN            _IO ('#', 0x07)
-
-/* Submit N new frames to be transmitted, where the index of the first new
- * frame is first_clear_buffer, and the index of the last new frame is
- * (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_SUBMIT_FRAMES       _IO ('#', 0x08)
-
-/* Block until N buffers are clear (pass N as the parameter) Because we
- * re-transmit the last frame on underrun, there will at most be n_frames
- * - 1 clear frames at any time */
-#define DV1394_IOC_WAIT_FRAMES         _IO ('#', 0x09)
-
-/* Capture new frames that have been received, where the index of the
- * first new frame is first_clear_buffer, and the index of the last new
- * frame is (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_RECEIVE_FRAMES      _IO ('#', 0x0a)
-
-/* Tell card to start receiving DMA */
-#define DV1394_IOC_START_RECEIVE       _IO ('#', 0x0b)
-
-/* Pass a struct dv1394_status* as the parameter */
-#define DV1394_IOC_GET_STATUS          _IOR('#', 0x0c, struct dv1394_status)
-
-
-/* Video1394 Gets 10 */
-
-#define VIDEO1394_IOC_LISTEN_CHANNEL           \
-       _IOWR('#', 0x10, struct video1394_mmap)
-#define VIDEO1394_IOC_UNLISTEN_CHANNEL         \
-       _IOW ('#', 0x11, int)
-#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER      \
-       _IOW ('#', 0x12, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER       \
-       _IOWR('#', 0x13, struct video1394_wait)
-#define VIDEO1394_IOC_TALK_CHANNEL             \
-       _IOWR('#', 0x14, struct video1394_mmap)
-#define VIDEO1394_IOC_UNTALK_CHANNEL           \
-       _IOW ('#', 0x15, int)
-/*
- * This one is broken: it really wanted
- * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
- * but got just a "size_t"
- */
-#define VIDEO1394_IOC_TALK_QUEUE_BUFFER        \
-       _IOW ('#', 0x16, size_t)
-#define VIDEO1394_IOC_TALK_WAIT_BUFFER         \
-       _IOW ('#', 0x17, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_POLL_BUFFER       \
-       _IOWR('#', 0x18, struct video1394_wait)
-
-
-/* Raw1394's ISO interface */
-#define RAW1394_IOC_ISO_XMIT_INIT              \
-       _IOW ('#', 0x1a, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_INIT              \
-       _IOWR('#', 0x1b, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_START             \
-       _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
-#define RAW1394_IOC_ISO_XMIT_START             \
-       _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
-#define RAW1394_IOC_ISO_XMIT_RECV_STOP         \
-       _IO  ('#', 0x1e)
-#define RAW1394_IOC_ISO_GET_STATUS             \
-       _IOR ('#', 0x1f, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_SHUTDOWN               \
-       _IO  ('#', 0x20)
-#define RAW1394_IOC_ISO_QUEUE_ACTIVITY         \
-       _IO  ('#', 0x21)
-#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL    \
-       _IOW ('#', 0x22, unsigned char)
-#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL  \
-       _IOW ('#', 0x23, unsigned char)
-#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK  \
-       _IOW ('#', 0x24, __u64)
-#define RAW1394_IOC_ISO_RECV_PACKETS           \
-       _IOW ('#', 0x25, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS   \
-       _IOW ('#', 0x26, unsigned int)
-#define RAW1394_IOC_ISO_XMIT_PACKETS           \
-       _IOW ('#', 0x27, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_XMIT_SYNC              \
-       _IO  ('#', 0x28)
-#define RAW1394_IOC_ISO_RECV_FLUSH             \
-       _IO  ('#', 0x29)
-#define RAW1394_IOC_GET_CYCLE_TIMER            \
-       _IOR ('#', 0x30, struct raw1394_cycle_timer)
-
-#endif /* __IEEE1394_IOCTL_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
deleted file mode 100644 (file)
index af320e2..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Generic IEEE 1394 definitions
- */
-
-#ifndef _IEEE1394_IEEE1394_H
-#define _IEEE1394_IEEE1394_H
-
-#define TCODE_WRITEQ           0x0
-#define TCODE_WRITEB           0x1
-#define TCODE_WRITE_RESPONSE   0x2
-#define TCODE_READQ            0x4
-#define TCODE_READB            0x5
-#define TCODE_READQ_RESPONSE   0x6
-#define TCODE_READB_RESPONSE   0x7
-#define TCODE_CYCLE_START      0x8
-#define TCODE_LOCK_REQUEST     0x9
-#define TCODE_ISO_DATA         0xa
-#define TCODE_STREAM_DATA      0xa
-#define TCODE_LOCK_RESPONSE    0xb
-
-#define RCODE_COMPLETE         0x0
-#define RCODE_CONFLICT_ERROR   0x4
-#define RCODE_DATA_ERROR       0x5
-#define RCODE_TYPE_ERROR       0x6
-#define RCODE_ADDRESS_ERROR    0x7
-
-#define EXTCODE_MASK_SWAP      0x1
-#define EXTCODE_COMPARE_SWAP   0x2
-#define EXTCODE_FETCH_ADD      0x3
-#define EXTCODE_LITTLE_ADD     0x4
-#define EXTCODE_BOUNDED_ADD    0x5
-#define EXTCODE_WRAP_ADD       0x6
-
-#define ACK_COMPLETE           0x1
-#define ACK_PENDING            0x2
-#define ACK_BUSY_X             0x4
-#define ACK_BUSY_A             0x5
-#define ACK_BUSY_B             0x6
-#define ACK_TARDY              0xb
-#define ACK_CONFLICT_ERROR     0xc
-#define ACK_DATA_ERROR         0xd
-#define ACK_TYPE_ERROR         0xe
-#define ACK_ADDRESS_ERROR      0xf
-
-/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE              (-1)
-#define ACKX_SEND_ERROR                (-2)
-#define ACKX_ABORTED           (-3)
-#define ACKX_TIMEOUT           (-4)
-
-#define IEEE1394_SPEED_100     0x00
-#define IEEE1394_SPEED_200     0x01
-#define IEEE1394_SPEED_400     0x02
-#define IEEE1394_SPEED_800     0x03
-#define IEEE1394_SPEED_1600    0x04
-#define IEEE1394_SPEED_3200    0x05
-#define IEEE1394_SPEED_MAX     IEEE1394_SPEED_3200
-
-/* Maps speed values above to a string representation */
-extern const char *hpsb_speedto_str[];
-
-/* 1394a cable PHY packets */
-#define SELFID_PWRCL_NO_POWER          0x0
-#define SELFID_PWRCL_PROVIDE_15W       0x1
-#define SELFID_PWRCL_PROVIDE_30W       0x2
-#define SELFID_PWRCL_PROVIDE_45W       0x3
-#define SELFID_PWRCL_USE_1W            0x4
-#define SELFID_PWRCL_USE_3W            0x5
-#define SELFID_PWRCL_USE_6W            0x6
-#define SELFID_PWRCL_USE_10W           0x7
-
-#define SELFID_PORT_CHILD              0x3
-#define SELFID_PORT_PARENT             0x2
-#define SELFID_PORT_NCONN              0x1
-#define SELFID_PORT_NONE               0x0
-
-#define SELFID_SPEED_UNKNOWN           0x3     /* 1394b PHY */
-
-#define PHYPACKET_LINKON                       0x40000000
-#define PHYPACKET_PHYCONFIG_R                  0x00800000
-#define PHYPACKET_PHYCONFIG_T                  0x00400000
-#define EXTPHYPACKET_TYPE_PING                 0x00000000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE    0x00040000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED   0x00140000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE     0x000C0000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED    0x001C0000
-#define EXTPHYPACKET_TYPE_REMOTECOMMAND                0x00200000
-#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION   0x00280000
-#define EXTPHYPACKET_TYPE_RESUME               0x003C0000
-
-#define EXTPHYPACKET_TYPEMASK                  0xC0FC0000
-
-#define PHYPACKET_PORT_SHIFT           24
-#define PHYPACKET_GAPCOUNT_SHIFT       16
-
-/* 1394a PHY register map bitmasks */
-#define PHY_00_PHYSICAL_ID     0xFC
-#define PHY_00_R               0x02 /* Root */
-#define PHY_00_PS              0x01 /* Power Status*/
-#define PHY_01_RHB             0x80 /* Root Hold-Off */
-#define PHY_01_IBR             0x80 /* Initiate Bus Reset */
-#define PHY_01_GAP_COUNT       0x3F
-#define PHY_02_EXTENDED                0xE0 /* 0x7 for 1394a-compliant PHY */
-#define PHY_02_TOTAL_PORTS     0x1F
-#define PHY_03_MAX_SPEED       0xE0
-#define PHY_03_DELAY           0x0F
-#define PHY_04_LCTRL           0x80 /* Link Active Report Control */
-#define PHY_04_CONTENDER       0x40
-#define PHY_04_JITTER          0x38
-#define PHY_04_PWR_CLASS       0x07 /* Power Class */
-#define PHY_05_WATCHDOG                0x80
-#define PHY_05_ISBR            0x40 /* Initiate Short Bus Reset */
-#define PHY_05_LOOP            0x20 /* Loop Detect */
-#define PHY_05_PWR_FAIL                0x10 /* Cable Power Failure Detect */
-#define PHY_05_TIMEOUT         0x08 /* Arbitration State Machine Timeout */
-#define PHY_05_PORT_EVENT      0x04 /* Port Event Detect */
-#define PHY_05_ENAB_ACCEL      0x02 /* Enable Arbitration Acceleration */
-#define PHY_05_ENAB_MULTI      0x01 /* Ena. Multispeed Packet Concatenation */
-
-#include <asm/byteorder.h>
-
-/* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC   cpu_to_be32(0x31333934)
-
-#ifdef __BIG_ENDIAN_BITFIELD
-
-struct selfid {
-       u32 packet_identifier:2; /* always binary 10 */
-       u32 phy_id:6;
-       /* byte */
-       u32 extended:1; /* if true is struct ext_selfid */
-       u32 link_active:1;
-       u32 gap_count:6;
-       /* byte */
-       u32 speed:2;
-       u32 phy_delay:2;
-       u32 contender:1;
-       u32 power_class:3;
-       /* byte */
-       u32 port0:2;
-       u32 port1:2;
-       u32 port2:2;
-       u32 initiated_reset:1;
-       u32 more_packets:1;
-} __attribute__((packed));
-
-struct ext_selfid {
-       u32 packet_identifier:2; /* always binary 10 */
-       u32 phy_id:6;
-       /* byte */
-       u32 extended:1; /* if false is struct selfid */
-       u32 seq_nr:3;
-       u32 reserved:2;
-       u32 porta:2;
-       /* byte */
-       u32 portb:2;
-       u32 portc:2;
-       u32 portd:2;
-       u32 porte:2;
-       /* byte */
-       u32 portf:2;
-       u32 portg:2;
-       u32 porth:2;
-       u32 reserved2:1;
-       u32 more_packets:1;
-} __attribute__((packed));
-
-#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
-
-/*
- * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine.  Without swapping.
- */
-
-struct selfid {
-       u32 phy_id:6;
-       u32 packet_identifier:2; /* always binary 10 */
-       /* byte */
-       u32 gap_count:6;
-       u32 link_active:1;
-       u32 extended:1; /* if true is struct ext_selfid */
-       /* byte */
-       u32 power_class:3;
-       u32 contender:1;
-       u32 phy_delay:2;
-       u32 speed:2;
-       /* byte */
-       u32 more_packets:1;
-       u32 initiated_reset:1;
-       u32 port2:2;
-       u32 port1:2;
-       u32 port0:2;
-} __attribute__((packed));
-
-struct ext_selfid {
-       u32 phy_id:6;
-       u32 packet_identifier:2; /* always binary 10 */
-       /* byte */
-       u32 porta:2;
-       u32 reserved:2;
-       u32 seq_nr:3;
-       u32 extended:1; /* if false is struct selfid */
-       /* byte */
-       u32 porte:2;
-       u32 portd:2;
-       u32 portc:2;
-       u32 portb:2;
-       /* byte */
-       u32 more_packets:1;
-       u32 reserved2:1;
-       u32 porth:2;
-       u32 portg:2;
-       u32 portf:2;
-} __attribute__((packed));
-
-#else
-#error What? PDP endian?
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
deleted file mode 100644 (file)
index 8723380..0000000
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Core support: hpsb_packet management, packet handling and forwarding to
- *               highlevel or lowlevel code
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        loopback functionality in hpsb_send_packet
- *        allow highlevel drivers to disable automatic response generation
- *              and to generate responses themselves (deferred)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/bitops.h>
-#include <linux/kdev_t.h>
-#include <linux/freezer.h>
-#include <linux/suspend.h>
-#include <linux/kthread.h>
-#include <linux/preempt.h>
-#include <linux/time.h>
-
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394_types.h"
-#include "ieee1394.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ieee1394_transactions.h"
-#include "csr.h"
-#include "nodemgr.h"
-#include "dma.h"
-#include "iso.h"
-#include "config_roms.h"
-
-/*
- * Disable the nodemgr detection and config rom reading functionality.
- */
-static int disable_nodemgr;
-module_param(disable_nodemgr, int, 0444);
-MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
-
-/* Disable Isochronous Resource Manager functionality */
-int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
-MODULE_PARM_DESC(disable_irm,
-                "Disable Isochronous Resource Manager functionality.");
-
-/* We are GPL, so treat us special */
-MODULE_LICENSE("GPL");
-
-/* Some globals used */
-const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
-struct class *hpsb_protocol_class;
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
-{
-       int i;
-
-       size /= 4;
-       size = (size > 4 ? 4 : size);
-
-       printk(KERN_DEBUG "ieee1394: %s", text);
-       if (speed > -1 && speed < 6)
-               printk(" at %s", hpsb_speedto_str[speed]);
-       printk(":");
-       for (i = 0; i < size; i++)
-               printk(" %08x", data[i]);
-       printk("\n");
-}
-#else
-#define dump_packet(a,b,c,d) do {} while (0)
-#endif
-
-static void abort_requests(struct hpsb_host *host);
-static void queue_packet_complete(struct hpsb_packet *packet);
-
-
-/**
- * hpsb_set_packet_complete_task - set task that runs when a packet completes
- * @packet: the packet whose completion we want the task added to
- * @routine: function to call
- * @data: data (if any) to pass to the above function
- *
- * Set the task that runs when a packet completes. You cannot call this more
- * than once on a single packet before it is sent.
- *
- * Typically, the complete @routine is responsible to call hpsb_free_packet().
- */
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
-                                  void (*routine)(void *), void *data)
-{
-       WARN_ON(packet->complete_routine != NULL);
-       packet->complete_routine = routine;
-       packet->complete_data = data;
-       return;
-}
-
-/**
- * hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated, in bytes
- *
- * This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context.  A header block is always included and
- * initialized with zeros.  Its size is big enough to contain all possible 1394
- * headers.  The data block is only allocated if @data_size is not zero.
- *
- * For packets for which responses will be received the @data_size has to be big
- * enough to contain the response's data block since no further allocation
- * occurs at response matching time.
- *
- * The packet's generation value will be set to the current generation number
- * for ease of use.  Remember to overwrite it with your own recorded generation
- * number if you can not be sure that your code will not race with a bus reset.
- *
- * Return value: A pointer to a &struct hpsb_packet or NULL on allocation
- * failure.
- */
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
-{
-       struct hpsb_packet *packet;
-
-       data_size = ((data_size + 3) & ~3);
-
-       packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
-       if (!packet)
-               return NULL;
-
-       packet->state = hpsb_unused;
-       packet->generation = -1;
-       INIT_LIST_HEAD(&packet->driver_list);
-       INIT_LIST_HEAD(&packet->queue);
-       atomic_set(&packet->refcnt, 1);
-
-       if (data_size) {
-               packet->data = packet->embedded_data;
-               packet->allocated_data_size = data_size;
-       }
-       return packet;
-}
-
-/**
- * hpsb_free_packet - free packet and data associated with it
- * @packet: packet to free (is NULL safe)
- *
- * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
- */
-void hpsb_free_packet(struct hpsb_packet *packet)
-{
-       if (packet && atomic_dec_and_test(&packet->refcnt)) {
-               BUG_ON(!list_empty(&packet->driver_list) ||
-                      !list_empty(&packet->queue));
-               kfree(packet);
-       }
-}
-
-/**
- * hpsb_reset_bus - initiate bus reset on the given host
- * @host: host controller whose bus to reset
- * @type: one of enum reset_types
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_reset_bus(struct hpsb_host *host, int type)
-{
-       if (!host->in_bus_reset) {
-               host->driver->devctl(host, RESET_BUS, type);
-               return 0;
-       } else {
-               return 1;
-       }
-}
-
-/**
- * hpsb_read_cycle_timer - read cycle timer register and system time
- * @host: host whose isochronous cycle timer register is read
- * @cycle_timer: address of bitfield to return the register contents
- * @local_time: address to return the system time
- *
- * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
- * format is also read from non-OHCI controllers. * @local_time contains the
- * system time in microseconds since the Epoch, read at the moment when the
- * cycle timer was read.
- *
- * Return value: 0 for success or error number otherwise.
- */
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
-                         u64 *local_time)
-{
-       int ctr;
-       struct timeval tv;
-       unsigned long flags;
-
-       if (!host || !cycle_timer || !local_time)
-               return -EINVAL;
-
-       preempt_disable();
-       local_irq_save(flags);
-
-       ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-       if (ctr)
-               do_gettimeofday(&tv);
-
-       local_irq_restore(flags);
-       preempt_enable();
-
-       if (!ctr)
-               return -EIO;
-       *cycle_timer = ctr;
-       *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
-       return 0;
-}
-
-/**
- * hpsb_bus_reset - notify a bus reset to the core
- *
- * For host driver module usage.  Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_bus_reset(struct hpsb_host *host)
-{
-       if (host->in_bus_reset) {
-               HPSB_NOTICE("%s called while bus reset already in progress",
-                           __func__);
-               return 1;
-       }
-
-       abort_requests(host);
-       host->in_bus_reset = 1;
-       host->irm_id = -1;
-       host->is_irm = 0;
-       host->busmgr_id = -1;
-       host->is_busmgr = 0;
-       host->is_cycmst = 0;
-       host->node_count = 0;
-       host->selfid_count = 0;
-
-       return 0;
-}
-
-
-/*
- * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in
- * case verification failed.
- */
-static int check_selfids(struct hpsb_host *host)
-{
-       int nodeid = -1;
-       int rest_of_selfids = host->selfid_count;
-       struct selfid *sid = (struct selfid *)host->topology_map;
-       struct ext_selfid *esid;
-       int esid_seq = 23;
-
-       host->nodes_active = 0;
-
-       while (rest_of_selfids--) {
-               if (!sid->extended) {
-                       nodeid++;
-                       esid_seq = 0;
-
-                       if (sid->phy_id != nodeid) {
-                               HPSB_INFO("SelfIDs failed monotony check with "
-                                         "%d", sid->phy_id);
-                               return 0;
-                       }
-
-                       if (sid->link_active) {
-                               host->nodes_active++;
-                               if (sid->contender)
-                                       host->irm_id = LOCAL_BUS | sid->phy_id;
-                       }
-               } else {
-                       esid = (struct ext_selfid *)sid;
-
-                       if ((esid->phy_id != nodeid)
-                           || (esid->seq_nr != esid_seq)) {
-                               HPSB_INFO("SelfIDs failed monotony check with "
-                                         "%d/%d", esid->phy_id, esid->seq_nr);
-                               return 0;
-                       }
-                       esid_seq++;
-               }
-               sid++;
-       }
-
-       esid = (struct ext_selfid *)(sid - 1);
-       while (esid->extended) {
-               if ((esid->porta == SELFID_PORT_PARENT) ||
-                   (esid->portb == SELFID_PORT_PARENT) ||
-                   (esid->portc == SELFID_PORT_PARENT) ||
-                   (esid->portd == SELFID_PORT_PARENT) ||
-                   (esid->porte == SELFID_PORT_PARENT) ||
-                   (esid->portf == SELFID_PORT_PARENT) ||
-                   (esid->portg == SELFID_PORT_PARENT) ||
-                   (esid->porth == SELFID_PORT_PARENT)) {
-                       HPSB_INFO("SelfIDs failed root check on "
-                                 "extended SelfID");
-                       return 0;
-               }
-               esid--;
-       }
-
-       sid = (struct selfid *)esid;
-       if ((sid->port0 == SELFID_PORT_PARENT) ||
-           (sid->port1 == SELFID_PORT_PARENT) ||
-           (sid->port2 == SELFID_PORT_PARENT)) {
-               HPSB_INFO("SelfIDs failed root check");
-               return 0;
-       }
-
-       host->node_count = nodeid + 1;
-       return 1;
-}
-
-static void build_speed_map(struct hpsb_host *host, int nodecount)
-{
-       u8 cldcnt[nodecount];
-       u8 *map = host->speed_map;
-       u8 *speedcap = host->speed;
-       u8 local_link_speed = host->csr.lnk_spd;
-       struct selfid *sid;
-       struct ext_selfid *esid;
-       int i, j, n;
-
-       for (i = 0; i < (nodecount * 64); i += 64) {
-               for (j = 0; j < nodecount; j++) {
-                       map[i+j] = IEEE1394_SPEED_MAX;
-               }
-       }
-
-       for (i = 0; i < nodecount; i++) {
-               cldcnt[i] = 0;
-       }
-
-       /* find direct children count and speed */
-       for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
-                    n = nodecount - 1;
-            (void *)sid >= (void *)host->topology_map; sid--) {
-               if (sid->extended) {
-                       esid = (struct ext_selfid *)sid;
-
-                       if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;
-                } else {
-                       if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;
-                       if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;
-
-                       speedcap[n] = sid->speed;
-                       if (speedcap[n] > local_link_speed)
-                               speedcap[n] = local_link_speed;
-                       n--;
-               }
-       }
-
-       /* set self mapping */
-       for (i = 0; i < nodecount; i++) {
-               map[64*i + i] = speedcap[i];
-       }
-
-       /* fix up direct children count to total children count;
-        * also fix up speedcaps for sibling and parent communication */
-       for (i = 1; i < nodecount; i++) {
-               for (j = cldcnt[i], n = i - 1; j > 0; j--) {
-                       cldcnt[i] += cldcnt[n];
-                       speedcap[n] = min(speedcap[n], speedcap[i]);
-                       n -= cldcnt[n] + 1;
-               }
-       }
-
-       for (n = 0; n < nodecount; n++) {
-               for (i = n - cldcnt[n]; i <= n; i++) {
-                       for (j = 0; j < (n - cldcnt[n]); j++) {
-                               map[j*64 + i] = map[i*64 + j] =
-                                       min(map[i*64 + j], speedcap[n]);
-                       }
-                       for (j = n + 1; j < nodecount; j++) {
-                               map[j*64 + i] = map[i*64 + j] =
-                                       min(map[i*64 + j], speedcap[n]);
-                       }
-               }
-       }
-
-       /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */
-       if (local_link_speed > SELFID_SPEED_UNKNOWN)
-               for (i = 0; i < nodecount; i++)
-                       if (speedcap[i] == SELFID_SPEED_UNKNOWN)
-                               speedcap[i] = local_link_speed;
-}
-
-
-/**
- * hpsb_selfid_received - hand over received selfid packet to the core
- *
- * For host driver module usage.  Safe to use in interrupt context.
- *
- * The host driver should have done a successful complement check (second
- * quadlet is complement of first) beforehand.
- */
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
-{
-       if (host->in_bus_reset) {
-               HPSB_VERBOSE("Including SelfID 0x%x", sid);
-               host->topology_map[host->selfid_count++] = sid;
-       } else {
-               HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
-                           sid, NODEID_TO_BUS(host->node_id));
-       }
-}
-
-/**
- * hpsb_selfid_complete - notify completion of SelfID stage to the core
- *
- * For host driver module usage.  Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
-{
-       if (!host->in_bus_reset)
-               HPSB_NOTICE("SelfID completion called outside of bus reset!");
-
-       host->node_id = LOCAL_BUS | phyid;
-       host->is_root = isroot;
-
-       if (!check_selfids(host)) {
-               if (host->reset_retries++ < 20) {
-                       /* selfid stage did not complete without error */
-                       HPSB_NOTICE("Error in SelfID stage, resetting");
-                       host->in_bus_reset = 0;
-                       /* this should work from ohci1394 now... */
-                       hpsb_reset_bus(host, LONG_RESET);
-                       return;
-               } else {
-                       HPSB_NOTICE("Stopping out-of-control reset loop");
-                       HPSB_NOTICE("Warning - topology map and speed map will not be valid");
-                       host->reset_retries = 0;
-               }
-       } else {
-               host->reset_retries = 0;
-               build_speed_map(host, host->node_count);
-       }
-
-       HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
-                    "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
-
-       /* irm_id is kept up to date by check_selfids() */
-       if (host->irm_id == host->node_id) {
-               host->is_irm = 1;
-       } else {
-               host->is_busmgr = 0;
-               host->is_irm = 0;
-       }
-
-       if (isroot) {
-               host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
-               host->is_cycmst = 1;
-       }
-       atomic_inc(&host->generation);
-       host->in_bus_reset = 0;
-       highlevel_host_reset(host);
-}
-
-static DEFINE_SPINLOCK(pending_packets_lock);
-
-/**
- * hpsb_packet_sent - notify core of sending a packet
- *
- * For host driver module usage.  Safe to call from within a transmit packet
- * routine.
- *
- * Notify core of sending a packet.  Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic).
- */
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
-                     int ackcode)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pending_packets_lock, flags);
-
-       packet->ack_code = ackcode;
-
-       if (packet->no_waiter || packet->state == hpsb_complete) {
-               /* if packet->no_waiter, must not have a tlabel allocated */
-               spin_unlock_irqrestore(&pending_packets_lock, flags);
-               hpsb_free_packet(packet);
-               return;
-       }
-
-       atomic_dec(&packet->refcnt);    /* drop HC's reference */
-       /* here the packet must be on the host->pending_packets queue */
-
-       if (ackcode != ACK_PENDING || !packet->expect_response) {
-               packet->state = hpsb_complete;
-               list_del_init(&packet->queue);
-               spin_unlock_irqrestore(&pending_packets_lock, flags);
-               queue_packet_complete(packet);
-               return;
-       }
-
-       packet->state = hpsb_pending;
-       packet->sendtime = jiffies;
-
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-       mod_timer(&host->timeout, jiffies + host->timeout_interval);
-}
-
-/**
- * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
- * @host: host that PHY config packet gets sent through
- * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
- * @gapcnt: gap count value to set (-1 = don't set gap count)
- *
- * This function sends a PHY config packet on the bus through the specified
- * host.
- *
- * Return value: 0 for success or negative error number otherwise.
- */
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
-{
-       struct hpsb_packet *packet;
-       quadlet_t d = 0;
-       int retval = 0;
-
-       if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
-          (rootid == -1 && gapcnt == -1)) {
-               HPSB_DEBUG("Invalid Parameter: rootid = %d   gapcnt = %d",
-                          rootid, gapcnt);
-               return -EINVAL;
-       }
-
-       if (rootid != -1)
-               d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
-       if (gapcnt != -1)
-               d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
-
-       packet = hpsb_make_phypacket(host, d);
-       if (!packet)
-               return -ENOMEM;
-
-       packet->generation = get_hpsb_generation(host);
-       retval = hpsb_send_packet_and_wait(packet);
-       hpsb_free_packet(packet);
-
-       return retval;
-}
-
-/**
- * hpsb_send_packet - transmit a packet on the bus
- * @packet: packet to send
- *
- * The packet is sent through the host specified in the packet->host field.
- * Before sending, the packet's transmit speed is automatically determined
- * using the local speed map when it is an async, non-broadcast packet.
- *
- * Possibilities for failure are that host is either not initialized, in bus
- * reset, the packet's generation number doesn't match the current generation
- * number or the host reports a transmit error.
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet(struct hpsb_packet *packet)
-{
-       struct hpsb_host *host = packet->host;
-
-       if (host->is_shutdown)
-               return -EINVAL;
-       if (host->in_bus_reset ||
-           (packet->generation != get_hpsb_generation(host)))
-               return -EAGAIN;
-
-       packet->state = hpsb_queued;
-
-       /* This just seems silly to me */
-       WARN_ON(packet->no_waiter && packet->expect_response);
-
-       if (!packet->no_waiter || packet->expect_response) {
-               unsigned long flags;
-
-               atomic_inc(&packet->refcnt);
-               /* Set the initial "sendtime" to 10 seconds from now, to
-                  prevent premature expiry.  If a packet takes more than
-                  10 seconds to hit the wire, we have bigger problems :) */
-               packet->sendtime = jiffies + 10 * HZ;
-               spin_lock_irqsave(&pending_packets_lock, flags);
-               list_add_tail(&packet->queue, &host->pending_packets);
-               spin_unlock_irqrestore(&pending_packets_lock, flags);
-       }
-
-       if (packet->node_id == host->node_id) {
-               /* it is a local request, so handle it locally */
-
-               quadlet_t *data;
-               size_t size = packet->data_size + packet->header_size;
-
-               data = kmalloc(size, GFP_ATOMIC);
-               if (!data) {
-                       HPSB_ERR("unable to allocate memory for concatenating header and data");
-                       return -ENOMEM;
-               }
-
-               memcpy(data, packet->header, packet->header_size);
-
-               if (packet->data_size)
-                       memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
-
-               dump_packet("send packet local", packet->header, packet->header_size, -1);
-
-               hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
-               hpsb_packet_received(host, data, size, 0);
-
-               kfree(data);
-
-               return 0;
-       }
-
-       if (packet->type == hpsb_async &&
-           NODEID_TO_NODE(packet->node_id) != ALL_NODES)
-               packet->speed_code =
-                       host->speed[NODEID_TO_NODE(packet->node_id)];
-
-       dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
-
-       return host->driver->transmit_packet(host, packet);
-}
-
-/* We could just use complete() directly as the packet complete
- * callback, but this is more typesafe, in the sense that we get a
- * compiler error if the prototype for complete() changes. */
-
-static void complete_packet(void *data)
-{
-       complete((struct completion *) data);
-}
-
-/**
- * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
- * @packet: packet to send
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
-{
-       struct completion done;
-       int retval;
-
-       init_completion(&done);
-       hpsb_set_packet_complete_task(packet, complete_packet, &done);
-       retval = hpsb_send_packet(packet);
-       if (retval == 0)
-               wait_for_completion(&done);
-
-       return retval;
-}
-
-static void send_packet_nocare(struct hpsb_packet *packet)
-{
-       if (hpsb_send_packet(packet) < 0) {
-               hpsb_free_packet(packet);
-       }
-}
-
-static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
-                                      size_t buffer_size, int tcode)
-{
-       size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
-
-       if (unlikely(ret > buffer_size))
-               ret = buffer_size;
-
-       if (unlikely(ret + header_size != packet_size))
-               HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
-                        packet_size, tcode);
-       return ret;
-}
-
-static void handle_packet_response(struct hpsb_host *host, int tcode,
-                                  quadlet_t *data, size_t size)
-{
-       struct hpsb_packet *packet;
-       int tlabel = (data[0] >> 10) & 0x3f;
-       size_t header_size;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pending_packets_lock, flags);
-
-       list_for_each_entry(packet, &host->pending_packets, queue)
-               if (packet->tlabel == tlabel &&
-                   packet->node_id == (data[1] >> 16))
-                       goto found;
-
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-       HPSB_DEBUG("unsolicited response packet received - %s",
-                  "no tlabel match");
-       dump_packet("contents", data, 16, -1);
-       return;
-
-found:
-       switch (packet->tcode) {
-       case TCODE_WRITEQ:
-       case TCODE_WRITEB:
-               if (unlikely(tcode != TCODE_WRITE_RESPONSE))
-                       break;
-               header_size = 12;
-               size = 0;
-               goto dequeue;
-
-       case TCODE_READQ:
-               if (unlikely(tcode != TCODE_READQ_RESPONSE))
-                       break;
-               header_size = 16;
-               size = 0;
-               goto dequeue;
-
-       case TCODE_READB:
-               if (unlikely(tcode != TCODE_READB_RESPONSE))
-                       break;
-               header_size = 16;
-               size = packet_size_to_data_size(size, header_size,
-                                               packet->allocated_data_size,
-                                               tcode);
-               goto dequeue;
-
-       case TCODE_LOCK_REQUEST:
-               if (unlikely(tcode != TCODE_LOCK_RESPONSE))
-                       break;
-               header_size = 16;
-               size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
-                                               header_size,
-                                               packet->allocated_data_size,
-                                               tcode);
-               goto dequeue;
-       }
-
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-       HPSB_DEBUG("unsolicited response packet received - %s",
-                  "tcode mismatch");
-       dump_packet("contents", data, 16, -1);
-       return;
-
-dequeue:
-       list_del_init(&packet->queue);
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-       if (packet->state == hpsb_queued) {
-               packet->sendtime = jiffies;
-               packet->ack_code = ACK_PENDING;
-       }
-       packet->state = hpsb_complete;
-
-       memcpy(packet->header, data, header_size);
-       if (size)
-               memcpy(packet->data, data + 4, size);
-
-       queue_packet_complete(packet);
-}
-
-
-static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
-                                              quadlet_t *data, size_t dsize)
-{
-       struct hpsb_packet *p;
-
-       p = hpsb_alloc_packet(dsize);
-       if (unlikely(p == NULL)) {
-               /* FIXME - send data_error response */
-               HPSB_ERR("out of memory, cannot send response packet");
-               return NULL;
-       }
-
-       p->type = hpsb_async;
-       p->state = hpsb_unused;
-       p->host = host;
-       p->node_id = data[1] >> 16;
-       p->tlabel = (data[0] >> 10) & 0x3f;
-       p->no_waiter = 1;
-
-       p->generation = get_hpsb_generation(host);
-
-       if (dsize % 4)
-               p->data[dsize / 4] = 0;
-
-       return p;
-}
-
-#define PREP_ASYNC_HEAD_RCODE(tc) \
-       packet->tcode = tc; \
-       packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
-               | (1 << 8) | (tc << 4); \
-       packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
-       packet->header[2] = 0
-
-static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
-                             quadlet_t data)
-{
-       PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
-       packet->header[3] = data;
-       packet->header_size = 16;
-       packet->data_size = 0;
-}
-
-static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
-                              int length)
-{
-       if (rcode != RCODE_COMPLETE)
-               length = 0;
-
-       PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
-       packet->header[3] = length << 16;
-       packet->header_size = 16;
-       packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
-{
-       PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
-       packet->header_size = 12;
-       packet->data_size = 0;
-}
-
-static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
-                         int length)
-{
-       if (rcode != RCODE_COMPLETE)
-               length = 0;
-
-       PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
-       packet->header[3] = (length << 16) | extcode;
-       packet->header_size = 16;
-       packet->data_size = length;
-}
-
-static void handle_incoming_packet(struct hpsb_host *host, int tcode,
-                                  quadlet_t *data, size_t size,
-                                  int write_acked)
-{
-       struct hpsb_packet *packet;
-       int length, rcode, extcode;
-       quadlet_t buffer;
-       nodeid_t source = data[1] >> 16;
-       nodeid_t dest = data[0] >> 16;
-       u16 flags = (u16) data[0];
-       u64 addr;
-
-       /* FIXME?
-        * Out-of-bounds lengths are left for highlevel_read|write to cap. */
-
-       switch (tcode) {
-       case TCODE_WRITEQ:
-               addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-               rcode = highlevel_write(host, source, dest, data + 3,
-                                       addr, 4, flags);
-               goto handle_write_request;
-
-       case TCODE_WRITEB:
-               addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-               rcode = highlevel_write(host, source, dest, data + 4,
-                                       addr, data[3] >> 16, flags);
-handle_write_request:
-               if (rcode < 0 || write_acked ||
-                   NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
-                       return;
-               /* not a broadcast write, reply */
-               packet = create_reply_packet(host, data, 0);
-               if (packet) {
-                       fill_async_write_resp(packet, rcode);
-                       send_packet_nocare(packet);
-               }
-               return;
-
-       case TCODE_READQ:
-               addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-               rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
-               if (rcode < 0)
-                       return;
-
-               packet = create_reply_packet(host, data, 0);
-               if (packet) {
-                       fill_async_readquad_resp(packet, rcode, buffer);
-                       send_packet_nocare(packet);
-               }
-               return;
-
-       case TCODE_READB:
-               length = data[3] >> 16;
-               packet = create_reply_packet(host, data, length);
-               if (!packet)
-                       return;
-
-               addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-               rcode = highlevel_read(host, source, packet->data, addr,
-                                      length, flags);
-               if (rcode < 0) {
-                       hpsb_free_packet(packet);
-                       return;
-               }
-               fill_async_readblock_resp(packet, rcode, length);
-               send_packet_nocare(packet);
-               return;
-
-       case TCODE_LOCK_REQUEST:
-               length = data[3] >> 16;
-               extcode = data[3] & 0xffff;
-               addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-
-               packet = create_reply_packet(host, data, 8);
-               if (!packet)
-                       return;
-
-               if (extcode == 0 || extcode >= 7) {
-                       /* let switch default handle error */
-                       length = 0;
-               }
-
-               switch (length) {
-               case 4:
-                       rcode = highlevel_lock(host, source, packet->data, addr,
-                                              data[4], 0, extcode, flags);
-                       fill_async_lock_resp(packet, rcode, extcode, 4);
-                       break;
-               case 8:
-                       if (extcode != EXTCODE_FETCH_ADD &&
-                           extcode != EXTCODE_LITTLE_ADD) {
-                               rcode = highlevel_lock(host, source,
-                                                      packet->data, addr,
-                                                      data[5], data[4],
-                                                      extcode, flags);
-                               fill_async_lock_resp(packet, rcode, extcode, 4);
-                       } else {
-                               rcode = highlevel_lock64(host, source,
-                                            (octlet_t *)packet->data, addr,
-                                            *(octlet_t *)(data + 4), 0ULL,
-                                            extcode, flags);
-                               fill_async_lock_resp(packet, rcode, extcode, 8);
-                       }
-                       break;
-               case 16:
-                       rcode = highlevel_lock64(host, source,
-                                                (octlet_t *)packet->data, addr,
-                                                *(octlet_t *)(data + 6),
-                                                *(octlet_t *)(data + 4),
-                                                extcode, flags);
-                       fill_async_lock_resp(packet, rcode, extcode, 8);
-                       break;
-               default:
-                       rcode = RCODE_TYPE_ERROR;
-                       fill_async_lock_resp(packet, rcode, extcode, 0);
-               }
-
-               if (rcode < 0)
-                       hpsb_free_packet(packet);
-               else
-                       send_packet_nocare(packet);
-               return;
-       }
-}
-
-/**
- * hpsb_packet_received - hand over received packet to the core
- *
- * For host driver module usage.
- *
- * The contents of data are expected to be the full packet but with the CRCs
- * left out (data block follows header immediately), with the header (i.e. the
- * first four quadlets) in machine byte order and the data block in big endian.
- * *@data can be safely overwritten after this call.
- *
- * If the packet is a write request, @write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise.  This argument is ignored for any
- * other packet type.
- */
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
-                         int write_acked)
-{
-       int tcode;
-
-       if (unlikely(host->in_bus_reset)) {
-               HPSB_DEBUG("received packet during reset; ignoring");
-               return;
-       }
-
-       dump_packet("received packet", data, size, -1);
-
-       tcode = (data[0] >> 4) & 0xf;
-
-       switch (tcode) {
-       case TCODE_WRITE_RESPONSE:
-       case TCODE_READQ_RESPONSE:
-       case TCODE_READB_RESPONSE:
-       case TCODE_LOCK_RESPONSE:
-               handle_packet_response(host, tcode, data, size);
-               break;
-
-       case TCODE_WRITEQ:
-       case TCODE_WRITEB:
-       case TCODE_READQ:
-       case TCODE_READB:
-       case TCODE_LOCK_REQUEST:
-               handle_incoming_packet(host, tcode, data, size, write_acked);
-               break;
-
-       case TCODE_CYCLE_START:
-               /* simply ignore this packet if it is passed on */
-               break;
-
-       default:
-               HPSB_DEBUG("received packet with bogus transaction code %d",
-                          tcode);
-               break;
-       }
-}
-
-static void abort_requests(struct hpsb_host *host)
-{
-       struct hpsb_packet *packet, *p;
-       struct list_head tmp;
-       unsigned long flags;
-
-       host->driver->devctl(host, CANCEL_REQUESTS, 0);
-
-       INIT_LIST_HEAD(&tmp);
-       spin_lock_irqsave(&pending_packets_lock, flags);
-       list_splice_init(&host->pending_packets, &tmp);
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-       list_for_each_entry_safe(packet, p, &tmp, queue) {
-               list_del_init(&packet->queue);
-               packet->state = hpsb_complete;
-               packet->ack_code = ACKX_ABORTED;
-               queue_packet_complete(packet);
-       }
-}
-
-void abort_timedouts(unsigned long __opaque)
-{
-       struct hpsb_host *host = (struct hpsb_host *)__opaque;
-       struct hpsb_packet *packet, *p;
-       struct list_head tmp;
-       unsigned long flags, expire, j;
-
-       spin_lock_irqsave(&host->csr.lock, flags);
-       expire = host->csr.expire;
-       spin_unlock_irqrestore(&host->csr.lock, flags);
-
-       j = jiffies;
-       INIT_LIST_HEAD(&tmp);
-       spin_lock_irqsave(&pending_packets_lock, flags);
-
-       list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
-               if (time_before(packet->sendtime + expire, j))
-                       list_move_tail(&packet->queue, &tmp);
-               else
-                       /* Since packets are added to the tail, the oldest
-                        * ones are first, always. When we get to one that
-                        * isn't timed out, the rest aren't either. */
-                       break;
-       }
-       if (!list_empty(&host->pending_packets))
-               mod_timer(&host->timeout, j + host->timeout_interval);
-
-       spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-       list_for_each_entry_safe(packet, p, &tmp, queue) {
-               list_del_init(&packet->queue);
-               packet->state = hpsb_complete;
-               packet->ack_code = ACKX_TIMEOUT;
-               queue_packet_complete(packet);
-       }
-}
-
-static struct task_struct *khpsbpkt_thread;
-static LIST_HEAD(hpsbpkt_queue);
-
-static void queue_packet_complete(struct hpsb_packet *packet)
-{
-       unsigned long flags;
-
-       if (packet->no_waiter) {
-               hpsb_free_packet(packet);
-               return;
-       }
-       if (packet->complete_routine != NULL) {
-               spin_lock_irqsave(&pending_packets_lock, flags);
-               list_add_tail(&packet->queue, &hpsbpkt_queue);
-               spin_unlock_irqrestore(&pending_packets_lock, flags);
-               wake_up_process(khpsbpkt_thread);
-       }
-       return;
-}
-
-/*
- * Kernel thread which handles packets that are completed.  This way the
- * packet's "complete" function is asynchronously run in process context.
- * Only packets which have a "complete" function may be sent here.
- */
-static int hpsbpkt_thread(void *__hi)
-{
-       struct hpsb_packet *packet, *p;
-       struct list_head tmp;
-       int may_schedule;
-
-       while (!kthread_should_stop()) {
-
-               INIT_LIST_HEAD(&tmp);
-               spin_lock_irq(&pending_packets_lock);
-               list_splice_init(&hpsbpkt_queue, &tmp);
-               spin_unlock_irq(&pending_packets_lock);
-
-               list_for_each_entry_safe(packet, p, &tmp, queue) {
-                       list_del_init(&packet->queue);
-                       packet->complete_routine(packet->complete_data);
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irq(&pending_packets_lock);
-               may_schedule = list_empty(&hpsbpkt_queue);
-               spin_unlock_irq(&pending_packets_lock);
-               if (may_schedule)
-                       schedule();
-               __set_current_state(TASK_RUNNING);
-       }
-       return 0;
-}
-
-static int __init ieee1394_init(void)
-{
-       int i, ret;
-
-       /* non-fatal error */
-       if (hpsb_init_config_roms()) {
-               HPSB_ERR("Failed to initialize some config rom entries.\n");
-               HPSB_ERR("Some features may not be available\n");
-       }
-
-       khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
-       if (IS_ERR(khpsbpkt_thread)) {
-               HPSB_ERR("Failed to start hpsbpkt thread!\n");
-               ret = PTR_ERR(khpsbpkt_thread);
-               goto exit_cleanup_config_roms;
-       }
-
-       if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
-               HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
-               ret = -ENODEV;
-               goto exit_release_kernel_thread;
-       }
-
-       ret = bus_register(&ieee1394_bus_type);
-       if (ret < 0) {
-               HPSB_INFO("bus register failed");
-               goto release_chrdev;
-       }
-
-       for (i = 0; fw_bus_attrs[i]; i++) {
-               ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-               if (ret < 0) {
-                       while (i >= 0) {
-                               bus_remove_file(&ieee1394_bus_type,
-                                               fw_bus_attrs[i--]);
-                       }
-                       bus_unregister(&ieee1394_bus_type);
-                       goto release_chrdev;
-               }
-       }
-
-       ret = class_register(&hpsb_host_class);
-       if (ret < 0)
-               goto release_all_bus;
-
-       hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
-       if (IS_ERR(hpsb_protocol_class)) {
-               ret = PTR_ERR(hpsb_protocol_class);
-               goto release_class_host;
-       }
-
-       ret = init_csr();
-       if (ret) {
-               HPSB_INFO("init csr failed");
-               ret = -ENOMEM;
-               goto release_class_protocol;
-       }
-
-       if (disable_nodemgr) {
-               HPSB_INFO("nodemgr and IRM functionality disabled");
-               /* We shouldn't contend for IRM with nodemgr disabled, since
-                  nodemgr implements functionality required of ieee1394a-2000
-                  IRMs */
-               hpsb_disable_irm = 1;
-
-               return 0;
-       }
-
-       if (hpsb_disable_irm) {
-               HPSB_INFO("IRM functionality disabled");
-       }
-
-       ret = init_ieee1394_nodemgr();
-       if (ret < 0) {
-               HPSB_INFO("init nodemgr failed");
-               goto cleanup_csr;
-       }
-
-       return 0;
-
-cleanup_csr:
-       cleanup_csr();
-release_class_protocol:
-       class_destroy(hpsb_protocol_class);
-release_class_host:
-       class_unregister(&hpsb_host_class);
-release_all_bus:
-       for (i = 0; fw_bus_attrs[i]; i++)
-               bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-       bus_unregister(&ieee1394_bus_type);
-release_chrdev:
-       unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-exit_release_kernel_thread:
-       kthread_stop(khpsbpkt_thread);
-exit_cleanup_config_roms:
-       hpsb_cleanup_config_roms();
-       return ret;
-}
-
-static void __exit ieee1394_cleanup(void)
-{
-       int i;
-
-       if (!disable_nodemgr)
-               cleanup_ieee1394_nodemgr();
-
-       cleanup_csr();
-
-       class_destroy(hpsb_protocol_class);
-       class_unregister(&hpsb_host_class);
-       for (i = 0; fw_bus_attrs[i]; i++)
-               bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-       bus_unregister(&ieee1394_bus_type);
-
-       kthread_stop(khpsbpkt_thread);
-
-       hpsb_cleanup_config_roms();
-
-       unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-}
-
-fs_initcall(ieee1394_init);
-module_exit(ieee1394_cleanup);
-
-/* Exported symbols */
-
-/** hosts.c **/
-EXPORT_SYMBOL(hpsb_alloc_host);
-EXPORT_SYMBOL(hpsb_add_host);
-EXPORT_SYMBOL(hpsb_resume_host);
-EXPORT_SYMBOL(hpsb_remove_host);
-EXPORT_SYMBOL(hpsb_update_config_rom_image);
-
-/** ieee1394_core.c **/
-EXPORT_SYMBOL(hpsb_speedto_str);
-EXPORT_SYMBOL(hpsb_protocol_class);
-EXPORT_SYMBOL(hpsb_set_packet_complete_task);
-EXPORT_SYMBOL(hpsb_alloc_packet);
-EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_read_cycle_timer);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-
-/** ieee1394_transactions.c **/
-EXPORT_SYMBOL(hpsb_get_tlabel);
-EXPORT_SYMBOL(hpsb_free_tlabel);
-EXPORT_SYMBOL(hpsb_make_readpacket);
-EXPORT_SYMBOL(hpsb_make_writepacket);
-EXPORT_SYMBOL(hpsb_make_streampacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_lock64packet);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-EXPORT_SYMBOL(hpsb_packet_success);
-
-/** highlevel.c **/
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_unregister_addrspace);
-EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_get_hostinfo);
-EXPORT_SYMBOL(hpsb_create_hostinfo);
-EXPORT_SYMBOL(hpsb_destroy_hostinfo);
-EXPORT_SYMBOL(hpsb_set_hostinfo_key);
-EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
-EXPORT_SYMBOL(hpsb_set_hostinfo);
-
-/** nodemgr.c **/
-EXPORT_SYMBOL(hpsb_node_fill_packet);
-EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(__hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-
-/** csr.c **/
-EXPORT_SYMBOL(hpsb_update_config_rom);
-
-/** dma.c **/
-EXPORT_SYMBOL(dma_prog_region_init);
-EXPORT_SYMBOL(dma_prog_region_alloc);
-EXPORT_SYMBOL(dma_prog_region_free);
-EXPORT_SYMBOL(dma_region_init);
-EXPORT_SYMBOL(dma_region_alloc);
-EXPORT_SYMBOL(dma_region_free);
-EXPORT_SYMBOL(dma_region_sync_for_cpu);
-EXPORT_SYMBOL(dma_region_sync_for_device);
-EXPORT_SYMBOL(dma_region_mmap);
-EXPORT_SYMBOL(dma_region_offset_to_bus);
-
-/** iso.c **/
-EXPORT_SYMBOL(hpsb_iso_xmit_init);
-EXPORT_SYMBOL(hpsb_iso_recv_init);
-EXPORT_SYMBOL(hpsb_iso_xmit_start);
-EXPORT_SYMBOL(hpsb_iso_recv_start);
-EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
-EXPORT_SYMBOL(hpsb_iso_stop);
-EXPORT_SYMBOL(hpsb_iso_shutdown);
-EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
-EXPORT_SYMBOL(hpsb_iso_xmit_sync);
-EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
-EXPORT_SYMBOL(hpsb_iso_n_ready);
-EXPORT_SYMBOL(hpsb_iso_packet_sent);
-EXPORT_SYMBOL(hpsb_iso_packet_received);
-EXPORT_SYMBOL(hpsb_iso_wake);
-EXPORT_SYMBOL(hpsb_iso_recv_flush);
-
-/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_get_keyval);
-EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_release_keyval);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
deleted file mode 100644 (file)
index 28b9f58..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef _IEEE1394_CORE_H
-#define _IEEE1394_CORE_H
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <asm/atomic.h>
-
-#include "hosts.h"
-#include "ieee1394_types.h"
-
-struct hpsb_packet {
-       /* This struct is basically read-only for hosts with the exception of
-        * the data buffer contents and driver_list. */
-
-       /* This can be used for host driver internal linking.
-        *
-        * NOTE: This must be left in init state when the driver is done
-        * with it (e.g. by using list_del_init()), since the core does
-        * some sanity checks to make sure the packet is not on a
-        * driver_list when free'ing it. */
-       struct list_head driver_list;
-
-       nodeid_t node_id;
-
-       /* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
-       enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
-
-       /* Okay, this is core internal and a no care for hosts.
-        * queued   = queued for sending
-        * pending  = sent, waiting for response
-        * complete = processing completed, successful or not
-        */
-       enum {
-               hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
-       } __attribute__((packed)) state;
-
-       /* These are core-internal. */
-       signed char tlabel;
-       signed char ack_code;
-       unsigned char tcode;
-
-       unsigned expect_response:1;
-       unsigned no_waiter:1;
-
-       /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
-       unsigned speed_code:2;
-
-       struct hpsb_host *host;
-       unsigned int generation;
-
-       atomic_t refcnt;
-       struct list_head queue;
-
-       /* Function (and possible data to pass to it) to call when this
-        * packet is completed.  */
-       void (*complete_routine)(void *);
-       void *complete_data;
-
-       /* Store jiffies for implementing bus timeouts. */
-       unsigned long sendtime;
-
-       /* Core-internal.  */
-       size_t allocated_data_size;     /* as allocated */
-
-       /* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
-       size_t data_size;               /* as filled in */
-       size_t header_size;             /* as filled in, not counting the CRC */
-
-       /* Buffers */
-       quadlet_t *data;                /* can be DMA-mapped */
-       quadlet_t header[5];
-       quadlet_t embedded_data[0];     /* keep as last member */
-};
-
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
-                                  void (*routine)(void *), void *data);
-static inline struct hpsb_packet *driver_packet(struct list_head *l)
-{
-       return list_entry(l, struct hpsb_packet, driver_list);
-}
-void abort_timedouts(unsigned long __opaque);
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
-void hpsb_free_packet(struct hpsb_packet *packet);
-
-/**
- * get_hpsb_generation - generation counter for the complete 1394 subsystem
- *
- * Generation gets incremented on every change in the subsystem (notably on bus
- * resets). Use the functions, not the variable.
- */
-static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
-{
-       return atomic_read(&host->generation);
-}
-
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-int hpsb_send_packet(struct hpsb_packet *packet);
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-int hpsb_reset_bus(struct hpsb_host *host, int type);
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
-                         u64 *local_time);
-
-int hpsb_bus_reset(struct hpsb_host *host);
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
-                     int ackcode);
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
-                         int write_acked);
-
-/*
- * CHARACTER DEVICE DISPATCHING
- *
- * All ieee1394 character device drivers share the same major number
- * (major 171).  The 256 minor numbers are allocated to the various
- * task-specific interfaces (raw1394, video1394, dv1394, etc) in
- * blocks of 16.
- *
- * The core ieee1394.o module allocates the device number region
- * 171:0-255, the various drivers must then cdev_add() their cdev
- * objects to handle their respective sub-regions.
- *
- * Minor device number block allocations:
- *
- * Block 0  (  0- 15)  raw1394
- * Block 1  ( 16- 31)  video1394
- * Block 2  ( 32- 47)  dv1394
- *
- * Blocks 3-14 free for future allocation
- *
- * Block 15 (240-255)  reserved for drivers under development, etc.
- */
-
-#define IEEE1394_MAJOR                  171
-
-#define IEEE1394_MINOR_BLOCK_RAW1394      0
-#define IEEE1394_MINOR_BLOCK_VIDEO1394    1
-#define IEEE1394_MINOR_BLOCK_DV1394       2
-#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
-
-#define IEEE1394_CORE_DEV        MKDEV(IEEE1394_MAJOR, 0)
-#define IEEE1394_RAW1394_DEV     MKDEV(IEEE1394_MAJOR, \
-                                       IEEE1394_MINOR_BLOCK_RAW1394 * 16)
-#define IEEE1394_VIDEO1394_DEV   MKDEV(IEEE1394_MAJOR, \
-                                       IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
-#define IEEE1394_DV1394_DEV      MKDEV(IEEE1394_MAJOR, \
-                                       IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
-                                       IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
-
-/**
- * ieee1394_file_to_instance - get the index within a minor number block
- */
-static inline unsigned char ieee1394_file_to_instance(struct file *file)
-{
-       int idx = cdev_index(file->f_path.dentry->d_inode);
-       if (idx < 0)
-               idx = 0;
-       return idx;
-}
-
-extern int hpsb_disable_irm;
-
-/* Our sysfs bus entry */
-extern struct bus_type ieee1394_bus_type;
-extern struct class hpsb_host_class;
-extern struct class *hpsb_protocol_class;
-
-#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h
deleted file mode 100644 (file)
index dd5500e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_HOTPLUG_H
-#define _IEEE1394_HOTPLUG_H
-
-/* Unit spec id and sw version entry for some protocols */
-#define AVC_UNIT_SPEC_ID_ENTRY         0x0000A02D
-#define AVC_SW_VERSION_ENTRY           0x00010001
-#define CAMERA_UNIT_SPEC_ID_ENTRY      0x0000A02D
-#define CAMERA_SW_VERSION_ENTRY                0x00000100
-
-/* /include/linux/mod_devicetable.h defines:
- *     IEEE1394_MATCH_VENDOR_ID
- *     IEEE1394_MATCH_MODEL_ID
- *     IEEE1394_MATCH_SPECIFIER_ID
- *     IEEE1394_MATCH_VERSION
- *     struct ieee1394_device_id
- */
-#include <linux/mod_devicetable.h>
-
-#endif /* _IEEE1394_HOTPLUG_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
deleted file mode 100644 (file)
index 675b313..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Transaction support.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/hardirq.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/sched.h>  /* because linux/wait.h is broken if CONFIG_SMP=n */
-#include <linux/wait.h>
-
-#include <asm/bug.h>
-#include <asm/errno.h>
-#include <asm/system.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-
-#define PREP_ASYNC_HEAD_ADDRESS(tc) \
-        packet->tcode = tc; \
-        packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
-                | (1 << 8) | (tc << 4); \
-        packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
-        packet->header[2] = addr & 0xffffffff
-
-#ifndef HPSB_DEBUG_TLABELS
-static
-#endif
-DEFINE_SPINLOCK(hpsb_tlabel_lock);
-
-static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
-
-static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
-{
-       PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
-       packet->header_size = 12;
-       packet->data_size = 0;
-       packet->expect_response = 1;
-}
-
-static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
-                                int length)
-{
-       PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
-       packet->header[3] = length << 16;
-       packet->header_size = 16;
-       packet->data_size = 0;
-       packet->expect_response = 1;
-}
-
-static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
-                                quadlet_t data)
-{
-       PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
-       packet->header[3] = data;
-       packet->header_size = 16;
-       packet->data_size = 0;
-       packet->expect_response = 1;
-}
-
-static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
-                                 int length)
-{
-       PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
-       packet->header[3] = length << 16;
-       packet->header_size = 16;
-       packet->expect_response = 1;
-       packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
-                           int length)
-{
-       PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
-       packet->header[3] = (length << 16) | extcode;
-       packet->header_size = 16;
-       packet->data_size = length;
-       packet->expect_response = 1;
-}
-
-static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
-{
-       packet->header[0] = data;
-       packet->header[1] = ~data;
-       packet->header_size = 8;
-       packet->data_size = 0;
-       packet->expect_response = 0;
-       packet->type = hpsb_raw;        /* No CRC added */
-       packet->speed_code = IEEE1394_SPEED_100;        /* Force speed to be 100Mbps */
-}
-
-static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
-                                    int channel, int tag, int sync)
-{
-       packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
-           | (TCODE_STREAM_DATA << 4) | sync;
-
-       packet->header_size = 4;
-       packet->data_size = length;
-       packet->type = hpsb_async;
-       packet->tcode = TCODE_ISO_DATA;
-}
-
-/* same as hpsb_get_tlabel, except that it returns immediately */
-static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
-{
-       unsigned long flags, *tp;
-       u8 *next;
-       int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
-       /* Broadcast transactions are complete once the request has been sent.
-        * Use the same transaction label for all broadcast transactions. */
-       if (unlikely(n == ALL_NODES)) {
-               packet->tlabel = 0;
-               return 0;
-       }
-       tp = packet->host->tl_pool[n].map;
-       next = &packet->host->next_tl[n];
-
-       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-       tlabel = find_next_zero_bit(tp, 64, *next);
-       if (tlabel > 63)
-               tlabel = find_first_zero_bit(tp, 64);
-       if (tlabel > 63) {
-               spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-               return -EAGAIN;
-       }
-       __set_bit(tlabel, tp);
-       *next = (tlabel + 1) & 63;
-       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-       packet->tlabel = tlabel;
-       return 0;
-}
-
-/**
- * hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet whose tlabel and tl_pool we set
- *
- * Every asynchronous transaction on the 1394 bus needs a transaction
- * label to match the response to the request.  This label has to be
- * different from any other transaction label in an outstanding request to
- * the same node to make matching possible without ambiguity.
- *
- * There are 64 different tlabels, so an allocated tlabel has to be freed
- * with hpsb_free_tlabel() after the transaction is complete (unless it's
- * reused again for the same target node).
- *
- * Return value: Zero on success, otherwise non-zero. A non-zero return
- * generally means there are no available tlabels. If this is called out
- * of interrupt or atomic context, then it will sleep until can return a
- * tlabel or a signal is received.
- */
-int hpsb_get_tlabel(struct hpsb_packet *packet)
-{
-       if (irqs_disabled() || in_atomic())
-               return hpsb_get_tlabel_atomic(packet);
-
-       /* NB: The macro wait_event_interruptible() is called with a condition
-        * argument with side effect.  This is only possible because the side
-        * effect does not occur until the condition became true, and
-        * wait_event_interruptible() won't evaluate the condition again after
-        * that. */
-       return wait_event_interruptible(tlabel_wq,
-                                       !hpsb_get_tlabel_atomic(packet));
-}
-
-/**
- * hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whose tlabel and tl_pool needs to be cleared
- *
- * Frees the transaction label allocated with hpsb_get_tlabel().  The
- * tlabel has to be freed after the transaction is complete (i.e. response
- * was received for a split transaction or packet was sent for a unified
- * transaction).
- *
- * A tlabel must not be freed twice.
- */
-void hpsb_free_tlabel(struct hpsb_packet *packet)
-{
-       unsigned long flags, *tp;
-       int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
-       if (unlikely(n == ALL_NODES))
-               return;
-       tp = packet->host->tl_pool[n].map;
-       tlabel = packet->tlabel;
-       BUG_ON(tlabel > 63 || tlabel < 0);
-
-       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-       BUG_ON(!__test_and_clear_bit(tlabel, tp));
-       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-       wake_up_interruptible(&tlabel_wq);
-}
-
-/**
- * hpsb_packet_success - Make sense of the ack and reply codes
- *
- * Make sense of the ack and reply codes and return more convenient error codes:
- * 0 = success.  -%EBUSY = node is busy, try again.  -%EAGAIN = error which can
- * probably resolved by retry.  -%EREMOTEIO = node suffers from an internal
- * error.  -%EACCES = this transaction is not allowed on requested address.
- * -%EINVAL = invalid address at node.
- */
-int hpsb_packet_success(struct hpsb_packet *packet)
-{
-       switch (packet->ack_code) {
-       case ACK_PENDING:
-               switch ((packet->header[1] >> 12) & 0xf) {
-               case RCODE_COMPLETE:
-                       return 0;
-               case RCODE_CONFLICT_ERROR:
-                       return -EAGAIN;
-               case RCODE_DATA_ERROR:
-                       return -EREMOTEIO;
-               case RCODE_TYPE_ERROR:
-                       return -EACCES;
-               case RCODE_ADDRESS_ERROR:
-                       return -EINVAL;
-               default:
-                       HPSB_ERR("received reserved rcode %d from node %d",
-                                (packet->header[1] >> 12) & 0xf,
-                                packet->node_id);
-                       return -EAGAIN;
-               }
-
-       case ACK_BUSY_X:
-       case ACK_BUSY_A:
-       case ACK_BUSY_B:
-               return -EBUSY;
-
-       case ACK_TYPE_ERROR:
-               return -EACCES;
-
-       case ACK_COMPLETE:
-               if (packet->tcode == TCODE_WRITEQ
-                   || packet->tcode == TCODE_WRITEB) {
-                       return 0;
-               } else {
-                       HPSB_ERR("impossible ack_complete from node %d "
-                                "(tcode %d)", packet->node_id, packet->tcode);
-                       return -EAGAIN;
-               }
-
-       case ACK_DATA_ERROR:
-               if (packet->tcode == TCODE_WRITEB
-                   || packet->tcode == TCODE_LOCK_REQUEST) {
-                       return -EAGAIN;
-               } else {
-                       HPSB_ERR("impossible ack_data_error from node %d "
-                                "(tcode %d)", packet->node_id, packet->tcode);
-                       return -EAGAIN;
-               }
-
-       case ACK_ADDRESS_ERROR:
-               return -EINVAL;
-
-       case ACK_TARDY:
-       case ACK_CONFLICT_ERROR:
-       case ACKX_NONE:
-       case ACKX_SEND_ERROR:
-       case ACKX_ABORTED:
-       case ACKX_TIMEOUT:
-               /* error while sending */
-               return -EAGAIN;
-
-       default:
-               HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
-                        packet->ack_code, packet->node_id, packet->tcode);
-               return -EAGAIN;
-       }
-}
-
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
-                                        u64 addr, size_t length)
-{
-       struct hpsb_packet *packet;
-
-       if (length == 0)
-               return NULL;
-
-       packet = hpsb_alloc_packet(length);
-       if (!packet)
-               return NULL;
-
-       packet->host = host;
-       packet->node_id = node;
-
-       if (hpsb_get_tlabel(packet)) {
-               hpsb_free_packet(packet);
-               return NULL;
-       }
-
-       if (length == 4)
-               fill_async_readquad(packet, addr);
-       else
-               fill_async_readblock(packet, addr, length);
-
-       return packet;
-}
-
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
-                                         u64 addr, quadlet_t * buffer,
-                                         size_t length)
-{
-       struct hpsb_packet *packet;
-
-       if (length == 0)
-               return NULL;
-
-       packet = hpsb_alloc_packet(length);
-       if (!packet)
-               return NULL;
-
-       if (length % 4) {       /* zero padding bytes */
-               packet->data[length >> 2] = 0;
-       }
-       packet->host = host;
-       packet->node_id = node;
-
-       if (hpsb_get_tlabel(packet)) {
-               hpsb_free_packet(packet);
-               return NULL;
-       }
-
-       if (length == 4) {
-               fill_async_writequad(packet, addr, buffer ? *buffer : 0);
-       } else {
-               fill_async_writeblock(packet, addr, length);
-               if (buffer)
-                       memcpy(packet->data, buffer, length);
-       }
-
-       return packet;
-}
-
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
-                                          int length, int channel, int tag,
-                                          int sync)
-{
-       struct hpsb_packet *packet;
-
-       if (length == 0)
-               return NULL;
-
-       packet = hpsb_alloc_packet(length);
-       if (!packet)
-               return NULL;
-
-       if (length % 4) {       /* zero padding bytes */
-               packet->data[length >> 2] = 0;
-       }
-       packet->host = host;
-
-       /* Because it is too difficult to determine all PHY speeds and link
-        * speeds here, we use S100... */
-       packet->speed_code = IEEE1394_SPEED_100;
-
-       /* ...and prevent hpsb_send_packet() from overriding it. */
-       packet->node_id = LOCAL_BUS | ALL_NODES;
-
-       if (hpsb_get_tlabel(packet)) {
-               hpsb_free_packet(packet);
-               return NULL;
-       }
-
-       fill_async_stream_packet(packet, length, channel, tag, sync);
-       if (buffer)
-               memcpy(packet->data, buffer, length);
-
-       return packet;
-}
-
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
-                                        u64 addr, int extcode,
-                                        quadlet_t * data, quadlet_t arg)
-{
-       struct hpsb_packet *p;
-       u32 length;
-
-       p = hpsb_alloc_packet(8);
-       if (!p)
-               return NULL;
-
-       p->host = host;
-       p->node_id = node;
-       if (hpsb_get_tlabel(p)) {
-               hpsb_free_packet(p);
-               return NULL;
-       }
-
-       switch (extcode) {
-       case EXTCODE_FETCH_ADD:
-       case EXTCODE_LITTLE_ADD:
-               length = 4;
-               if (data)
-                       p->data[0] = *data;
-               break;
-       default:
-               length = 8;
-               if (data) {
-                       p->data[0] = arg;
-                       p->data[1] = *data;
-               }
-               break;
-       }
-       fill_async_lock(p, addr, extcode, length);
-
-       return p;
-}
-
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
-                                          nodeid_t node, u64 addr, int extcode,
-                                          octlet_t * data, octlet_t arg)
-{
-       struct hpsb_packet *p;
-       u32 length;
-
-       p = hpsb_alloc_packet(16);
-       if (!p)
-               return NULL;
-
-       p->host = host;
-       p->node_id = node;
-       if (hpsb_get_tlabel(p)) {
-               hpsb_free_packet(p);
-               return NULL;
-       }
-
-       switch (extcode) {
-       case EXTCODE_FETCH_ADD:
-       case EXTCODE_LITTLE_ADD:
-               length = 8;
-               if (data) {
-                       p->data[0] = *data >> 32;
-                       p->data[1] = *data & 0xffffffff;
-               }
-               break;
-       default:
-               length = 16;
-               if (data) {
-                       p->data[0] = arg >> 32;
-                       p->data[1] = arg & 0xffffffff;
-                       p->data[2] = *data >> 32;
-                       p->data[3] = *data & 0xffffffff;
-               }
-               break;
-       }
-       fill_async_lock(p, addr, extcode, length);
-
-       return p;
-}
-
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
-{
-       struct hpsb_packet *p;
-
-       p = hpsb_alloc_packet(0);
-       if (!p)
-               return NULL;
-
-       p->host = host;
-       fill_phy_packet(p, data);
-
-       return p;
-}
-
-/*
- * FIXME - these functions should probably read from / write to user space to
- * avoid in kernel buffers for user space callers
- */
-
-/**
- * hpsb_read - generic read function
- *
- * Recognizes the local node ID and act accordingly.  Automatically uses a
- * quadlet read request if @length == 4 and and a block read request otherwise.
- * It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, quadlet_t * buffer, size_t length)
-{
-       struct hpsb_packet *packet;
-       int retval = 0;
-
-       if (length == 0)
-               return -EINVAL;
-
-       packet = hpsb_make_readpacket(host, node, addr, length);
-
-       if (!packet) {
-               return -ENOMEM;
-       }
-
-       packet->generation = generation;
-       retval = hpsb_send_packet_and_wait(packet);
-       if (retval < 0)
-               goto hpsb_read_fail;
-
-       retval = hpsb_packet_success(packet);
-
-       if (retval == 0) {
-               if (length == 4) {
-                       *buffer = packet->header[3];
-               } else {
-                       memcpy(buffer, packet->data, length);
-               }
-       }
-
-      hpsb_read_fail:
-       hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-
-       return retval;
-}
-
-/**
- * hpsb_write - generic write function
- *
- * Recognizes the local node ID and act accordingly.  Automatically uses a
- * quadlet write request if @length == 4 and and a block write request
- * otherwise.  It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-              u64 addr, quadlet_t * buffer, size_t length)
-{
-       struct hpsb_packet *packet;
-       int retval;
-
-       if (length == 0)
-               return -EINVAL;
-
-       packet = hpsb_make_writepacket(host, node, addr, buffer, length);
-
-       if (!packet)
-               return -ENOMEM;
-
-       packet->generation = generation;
-       retval = hpsb_send_packet_and_wait(packet);
-       if (retval < 0)
-               goto hpsb_write_fail;
-
-       retval = hpsb_packet_success(packet);
-
-      hpsb_write_fail:
-       hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-
-       return retval;
-}
-
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
-{
-       struct hpsb_packet *packet;
-       int retval = 0;
-
-       packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
-       if (!packet)
-               return -ENOMEM;
-
-       packet->generation = generation;
-       retval = hpsb_send_packet_and_wait(packet);
-       if (retval < 0)
-               goto hpsb_lock_fail;
-
-       retval = hpsb_packet_success(packet);
-
-       if (retval == 0)
-               *data = packet->data[0];
-
-hpsb_lock_fail:
-       hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-
-       return retval;
-}
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
deleted file mode 100644 (file)
index 20b693b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _IEEE1394_TRANSACTIONS_H
-#define _IEEE1394_TRANSACTIONS_H
-
-#include <linux/types.h>
-
-#include "ieee1394_types.h"
-
-struct hpsb_packet;
-struct hpsb_host;
-
-int hpsb_get_tlabel(struct hpsb_packet *packet);
-void hpsb_free_tlabel(struct hpsb_packet *packet);
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
-                                        u64 addr, size_t length);
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
-                                        u64 addr, int extcode, quadlet_t *data,
-                                        quadlet_t arg);
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
-                                          nodeid_t node, u64 addr, int extcode,
-                                          octlet_t *data, octlet_t arg);
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
-                                         nodeid_t node, u64 addr,
-                                         quadlet_t *buffer, size_t length);
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
-                                           int length, int channel, int tag,
-                                          int sync);
-int hpsb_packet_success(struct hpsb_packet *packet);
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-              u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-
-#ifdef HPSB_DEBUG_TLABELS
-extern spinlock_t hpsb_tlabel_lock;
-#endif
-
-#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
deleted file mode 100644 (file)
index 9803aaa..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _IEEE1394_TYPES_H
-#define _IEEE1394_TYPES_H
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-typedef u32 quadlet_t;
-typedef u64 octlet_t;
-typedef u16 nodeid_t;
-
-typedef u8  byte_t;
-typedef u64 nodeaddr_t;
-typedef u16 arm_length_t;
-
-#define BUS_MASK  0xffc0
-#define BUS_SHIFT 6
-#define NODE_MASK 0x003f
-#define LOCAL_BUS 0xffc0
-#define ALL_NODES 0x003f
-
-#define NODEID_TO_BUS(nodeid)  ((nodeid & BUS_MASK) >> BUS_SHIFT)
-#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK)
-
-/* Can be used to consistently print a node/bus ID. */
-#define NODE_BUS_FMT           "%d-%02d:%04d"
-#define NODE_BUS_ARGS(__host, __nodeid)        \
-       __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
-
-#define HPSB_PRINT(level, fmt, args...) \
-       printk(level "ieee1394: " fmt "\n" , ## args)
-
-#define HPSB_DEBUG(fmt, args...)       HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_INFO(fmt, args...)                HPSB_PRINT(KERN_INFO, fmt , ## args)
-#define HPSB_NOTICE(fmt, args...)      HPSB_PRINT(KERN_NOTICE, fmt , ## args)
-#define HPSB_WARN(fmt, args...)                HPSB_PRINT(KERN_WARNING, fmt , ## args)
-#define HPSB_ERR(fmt, args...)         HPSB_PRINT(KERN_ERR, fmt , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define HPSB_VERBOSE(fmt, args...)     HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_DEBUG_TLABELS
-#else
-#define HPSB_VERBOSE(fmt, args...)     do {} while (0)
-#endif
-
-#ifdef __BIG_ENDIAN
-
-static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
-{
-       void *tmp = dest;
-       u32 *src = (u32 *)__src;
-
-       count /= 4;
-       while (count--)
-               *dest++ = swab32p(src++);
-       return tmp;
-}
-
-#else
-
-static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
-{
-       return memcpy(dest, src, count);
-}
-
-#endif /* __BIG_ENDIAN */
-
-#endif /* _IEEE1394_TYPES_H */
diff --git a/drivers/ieee1394/init_ohci1394_dma.c b/drivers/ieee1394/init_ohci1394_dma.c
deleted file mode 100644 (file)
index ddaab6e..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers
- *
- * Copyright (C) 2006-2007      Bernhard Kaindl <bk@suse.de>
- *
- * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c
- * this file has functions to:
- * - scan the PCI very early on boot for all OHCI 1394-compliant controllers
- * - reset and initialize them and make them join the IEEE1394 bus and
- * - enable physical DMA on them to allow remote debugging
- *
- * All code and data is marked as __init and __initdata, respective as
- * during boot, all OHCI1394 controllers may be claimed by the firewire
- * stack and at this point, this code should not touch them anymore.
- *
- * To use physical DMA after the initialization of the firewire stack,
- * be sure that the stack enables it and (re-)attach after the bus reset
- * which may be caused by the firewire stack initialization.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/interrupt.h>   /* for ohci1394.h */
-#include <linux/delay.h>
-#include <linux/pci.h>         /* for PCI defines */
-#include <linux/init_ohci1394_dma.h>
-#include <asm/pci-direct.h>    /* for direct PCI config space access */
-#include <asm/fixmap.h>
-
-#include "ieee1394_types.h"
-#include "ohci1394.h"
-
-int __initdata init_ohci1394_dma_early;
-
-/* Reads a PHY register of an OHCI-1394 controller */
-static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
-       int i;
-       quadlet_t r;
-
-       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
-                       break;
-               mdelay(1);
-       }
-       r = reg_read(ohci, OHCI1394_PhyControl);
-
-       return (r & 0x00ff0000) >> 16;
-}
-
-/* Writes to a PHY register of an OHCI-1394 controller */
-static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-       int i;
-
-       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               u32 r = reg_read(ohci, OHCI1394_PhyControl);
-               if (!(r & 0x00004000))
-                       break;
-               mdelay(1);
-       }
-}
-
-/* Resets an OHCI-1394 controller (for sane state before initialization) */
-static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
-       int i;
-
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (!(reg_read(ohci, OHCI1394_HCControlSet)
-                                  & OHCI1394_HCControl_softReset))
-                       break;
-               mdelay(1);
-       }
-}
-
-/* Basic OHCI-1394 register and port inititalization */
-static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
-{
-       quadlet_t bus_options;
-       int num_ports, i;
-
-       /* Put some defaults to these undefined bus options */
-       bus_options = reg_read(ohci, OHCI1394_BusOptions);
-       bus_options |=  0x60000000; /* Enable CMC and ISC */
-       bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
-       bus_options &= ~0x18000000; /* Disable PMC and BMC */
-       reg_write(ohci, OHCI1394_BusOptions, bus_options);
-
-       /* Set the bus number */
-       reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
-       /* Enable posted writes */
-       reg_write(ohci, OHCI1394_HCControlSet,
-                       OHCI1394_HCControl_postedWriteEnable);
-
-       /* Clear link control register */
-       reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-       /* enable phys */
-       reg_write(ohci, OHCI1394_LinkControlSet,
-                       OHCI1394_LinkControl_RcvPhyPkt);
-
-       /* Don't accept phy packets into AR request context */
-       reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
-
-       /* Clear the Isochonouys interrupt masks */
-       reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
-       /* Accept asyncronous transfer requests from all nodes for now */
-       reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
-
-       /* Specify asyncronous transfer retries */
-       reg_write(ohci, OHCI1394_ATRetries,
-                 OHCI1394_MAX_AT_REQ_RETRIES |
-                 (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
-                 (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
-       /* We don't want hardware swapping */
-       reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
-       /* Enable link */
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
-       /* If anything is connected to a port, make sure it is enabled */
-       num_ports = get_phy_reg(ohci, 2) & 0xf;
-       for (i = 0; i < num_ports; i++) {
-               unsigned int status;
-
-               set_phy_reg(ohci, 7, i);
-               status = get_phy_reg(ohci, 8);
-
-               if (status & 0x20)
-                       set_phy_reg(ohci, 8, status & ~1);
-       }
-}
-
-/**
- * init_ohci1394_wait_for_busresets - wait until bus resets are completed
- *
- * OHCI1394 initialization itself and any device going on- or offline
- * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec
- * specifies that physical DMA is disabled on each bus reset and it
- * has to be enabled after each bus reset when needed. We resort
- * to polling here because on early boot, we have no interrupts.
- */
-static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
-{
-       int i, events;
-
-       for (i=0; i < 9; i++) {
-               mdelay(200);
-               events = reg_read(ohci, OHCI1394_IntEventSet);
-               if (events & OHCI1394_busReset)
-                       reg_write(ohci, OHCI1394_IntEventClear,
-                                       OHCI1394_busReset);
-       }
-}
-
-/**
- * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging
- * This enables remote DMA access over IEEE1394 from every host for the low
- * 4GB of address space. DMA accesses above 4GB are not available currently.
- */
-static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
-{
-       reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
-       reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
-       reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
-}
-
-/**
- * init_ohci1394_reset_and_init_dma - init controller and enable DMA
- * This initializes the given controller and enables physical DMA engine in it.
- */
-static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
-{
-       /* Start off with a soft reset, clears everything to a sane state. */
-       init_ohci1394_soft_reset(ohci);
-
-       /* Accessing some registers without LPS enabled may cause lock up */
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
-       /* Disable and clear interrupts */
-       reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
-       mdelay(50); /* Wait 50msec to make sure we have full link enabled */
-
-       init_ohci1394_initialize(ohci);
-       /*
-        * The initialization causes at least one IEEE1394 bus reset. Enabling
-        * physical DMA only works *after* *all* bus resets have calmed down:
-        */
-       init_ohci1394_wait_for_busresets(ohci);
-
-       /* We had to wait and do this now if we want to debug early problems */
-       init_ohci1394_enable_physical_dma(ohci);
-}
-
-/**
- * init_ohci1394_controller - Map the registers of the controller and init DMA
- * This maps the registers of the specified controller and initializes it
- */
-static inline void __init init_ohci1394_controller(int num, int slot, int func)
-{
-       unsigned long ohci_base;
-       struct ti_ohci ohci;
-
-       printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
-                        " at %02x:%02x.%x\n", num, slot, func);
-
-       ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2))
-                                                  & PCI_BASE_ADDRESS_MEM_MASK;
-
-       set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
-
-       ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
-
-       init_ohci1394_reset_and_init_dma(&ohci);
-}
-
-/**
- * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them
- * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them
- */
-void __init init_ohci1394_dma_on_all_controllers(void)
-{
-       int num, slot, func;
-
-       if (!early_pci_allowed())
-               return;
-
-       /* Poor man's PCI discovery, the only thing we can do at early boot */
-       for (num = 0; num < 32; num++) {
-               for (slot = 0; slot < 32; slot++) {
-                       for (func = 0; func < 8; func++) {
-                               u32 class = read_pci_config(num,slot,func,
-                                                       PCI_CLASS_REVISION);
-                               if ((class == 0xffffffff))
-                                       continue; /* No device at this func */
-
-                               if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
-                                       continue; /* Not an OHCI-1394 device */
-
-                               init_ohci1394_controller(num, slot, func);
-                               break; /* Assume one controller per device */
-                       }
-               }
-       }
-       printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n");
-}
-
-/**
- * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization
- */
-static int __init setup_ohci1394_dma(char *opt)
-{
-       if (!strcmp(opt, "early"))
-               init_ohci1394_dma_early = 1;
-       return 0;
-}
-
-/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */
-early_param("ohci1394_dma", setup_ohci1394_dma);
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
deleted file mode 100644 (file)
index 1cf6487..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include "hosts.h"
-#include "iso.h"
-
-/**
- * hpsb_iso_stop - stop DMA
- */
-void hpsb_iso_stop(struct hpsb_iso *iso)
-{
-       if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
-               return;
-
-       iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
-                                 XMIT_STOP : RECV_STOP, 0);
-       iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
-}
-
-/**
- * hpsb_iso_shutdown - deallocate buffer and DMA context
- */
-void hpsb_iso_shutdown(struct hpsb_iso *iso)
-{
-       if (iso->flags & HPSB_ISO_DRIVER_INIT) {
-               hpsb_iso_stop(iso);
-               iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
-                                         XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
-               iso->flags &= ~HPSB_ISO_DRIVER_INIT;
-       }
-
-       dma_region_free(&iso->data_buf);
-       kfree(iso);
-}
-
-static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
-                                            enum hpsb_iso_type type,
-                                            unsigned int data_buf_size,
-                                            unsigned int buf_packets,
-                                            int channel, int dma_mode,
-                                            int irq_interval,
-                                            void (*callback) (struct hpsb_iso
-                                                              *))
-{
-       struct hpsb_iso *iso;
-       int dma_direction;
-
-       /* make sure driver supports the ISO API */
-       if (!host->driver->isoctl) {
-               printk(KERN_INFO
-                      "ieee1394: host driver '%s' does not support the rawiso API\n",
-                      host->driver->name);
-               return NULL;
-       }
-
-       /* sanitize parameters */
-
-       if (buf_packets < 2)
-               buf_packets = 2;
-
-       if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
-           || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
-               dma_mode = HPSB_ISO_DMA_DEFAULT;
-
-       if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
-               irq_interval = buf_packets / 4;
-       if (irq_interval == 0)  /* really interrupt for each packet */
-               irq_interval = 1;
-
-       if (channel < -1 || channel >= 64)
-               return NULL;
-
-       /* channel = -1 is OK for multi-channel recv but not for xmit */
-       if (type == HPSB_ISO_XMIT && channel < 0)
-               return NULL;
-
-       /* allocate and write the struct hpsb_iso */
-
-       iso =
-           kmalloc(sizeof(*iso) +
-                   buf_packets * sizeof(struct hpsb_iso_packet_info),
-                   GFP_KERNEL);
-       if (!iso)
-               return NULL;
-
-       iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
-
-       iso->type = type;
-       iso->host = host;
-       iso->hostdata = NULL;
-       iso->callback = callback;
-       init_waitqueue_head(&iso->waitq);
-       iso->channel = channel;
-       iso->irq_interval = irq_interval;
-       iso->dma_mode = dma_mode;
-       dma_region_init(&iso->data_buf);
-       iso->buf_size = PAGE_ALIGN(data_buf_size);
-       iso->buf_packets = buf_packets;
-       iso->pkt_dma = 0;
-       iso->first_packet = 0;
-       spin_lock_init(&iso->lock);
-
-       if (iso->type == HPSB_ISO_XMIT) {
-               iso->n_ready_packets = iso->buf_packets;
-               dma_direction = PCI_DMA_TODEVICE;
-       } else {
-               iso->n_ready_packets = 0;
-               dma_direction = PCI_DMA_FROMDEVICE;
-       }
-
-       atomic_set(&iso->overflows, 0);
-       iso->bytes_discarded = 0;
-       iso->flags = 0;
-       iso->prebuffer = 0;
-
-       /* allocate the packet buffer */
-       if (dma_region_alloc
-           (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
-               goto err;
-
-       return iso;
-
-      err:
-       hpsb_iso_shutdown(iso);
-       return NULL;
-}
-
-/**
- * hpsb_iso_n_ready - returns number of packets ready to send or receive
- */
-int hpsb_iso_n_ready(struct hpsb_iso *iso)
-{
-       unsigned long flags;
-       int val;
-
-       spin_lock_irqsave(&iso->lock, flags);
-       val = iso->n_ready_packets;
-       spin_unlock_irqrestore(&iso->lock, flags);
-
-       return val;
-}
-
-/**
- * hpsb_iso_xmit_init - allocate the buffer and DMA context
- */
-struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
-                                   unsigned int data_buf_size,
-                                   unsigned int buf_packets,
-                                   int channel,
-                                   int speed,
-                                   int irq_interval,
-                                   void (*callback) (struct hpsb_iso *))
-{
-       struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
-                                                   data_buf_size, buf_packets,
-                                                   channel,
-                                                   HPSB_ISO_DMA_DEFAULT,
-                                                   irq_interval, callback);
-       if (!iso)
-               return NULL;
-
-       iso->speed = speed;
-
-       /* tell the driver to start working */
-       if (host->driver->isoctl(iso, XMIT_INIT, 0))
-               goto err;
-
-       iso->flags |= HPSB_ISO_DRIVER_INIT;
-       return iso;
-
-      err:
-       hpsb_iso_shutdown(iso);
-       return NULL;
-}
-
-/**
- * hpsb_iso_recv_init - allocate the buffer and DMA context
- *
- * Note, if channel = -1, multi-channel receive is enabled.
- */
-struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
-                                   unsigned int data_buf_size,
-                                   unsigned int buf_packets,
-                                   int channel,
-                                   int dma_mode,
-                                   int irq_interval,
-                                   void (*callback) (struct hpsb_iso *))
-{
-       struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
-                                                   data_buf_size, buf_packets,
-                                                   channel, dma_mode,
-                                                   irq_interval, callback);
-       if (!iso)
-               return NULL;
-
-       /* tell the driver to start working */
-       if (host->driver->isoctl(iso, RECV_INIT, 0))
-               goto err;
-
-       iso->flags |= HPSB_ISO_DRIVER_INIT;
-       return iso;
-
-      err:
-       hpsb_iso_shutdown(iso);
-       return NULL;
-}
-
-/**
- * hpsb_iso_recv_listen_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
-{
-       if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
-               return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_unlisten_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
-{
-       if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
-               return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_set_channel_mask
- *
- * multi-channel only
- */
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
-       if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
-               return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
-                                        (unsigned long)&mask);
-}
-
-/**
- * hpsb_iso_recv_flush - check for arrival of new packets
- *
- * check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached)
- */
-int hpsb_iso_recv_flush(struct hpsb_iso *iso)
-{
-       if (iso->type != HPSB_ISO_RECV)
-               return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
-}
-
-static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
-       int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
-       if (retval)
-               return retval;
-
-       iso->flags |= HPSB_ISO_DRIVER_STARTED;
-       return retval;
-}
-
-/**
- * hpsb_iso_xmit_start - start DMA
- */
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
-{
-       if (iso->type != HPSB_ISO_XMIT)
-               return -1;
-
-       if (iso->flags & HPSB_ISO_DRIVER_STARTED)
-               return 0;
-
-       if (cycle < -1)
-               cycle = -1;
-       else if (cycle >= 8000)
-               cycle %= 8000;
-
-       iso->xmit_cycle = cycle;
-
-       if (prebuffer < 0)
-               prebuffer = iso->buf_packets - 1;
-       else if (prebuffer == 0)
-               prebuffer = 1;
-
-       if (prebuffer >= iso->buf_packets)
-               prebuffer = iso->buf_packets - 1;
-
-       iso->prebuffer = prebuffer;
-
-       /* remember the starting cycle; DMA will commence from xmit_queue_packets()
-          once enough packets have been buffered */
-       iso->start_cycle = cycle;
-
-       return 0;
-}
-
-/**
- * hpsb_iso_recv_start - start DMA
- */
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
-       int retval = 0;
-       int isoctl_args[3];
-
-       if (iso->type != HPSB_ISO_RECV)
-               return -1;
-
-       if (iso->flags & HPSB_ISO_DRIVER_STARTED)
-               return 0;
-
-       if (cycle < -1)
-               cycle = -1;
-       else if (cycle >= 8000)
-               cycle %= 8000;
-
-       isoctl_args[0] = cycle;
-
-       if (tag_mask < 0)
-               /* match all tags */
-               tag_mask = 0xF;
-       isoctl_args[1] = tag_mask;
-
-       isoctl_args[2] = sync;
-
-       retval =
-           iso->host->driver->isoctl(iso, RECV_START,
-                                     (unsigned long)&isoctl_args[0]);
-       if (retval)
-               return retval;
-
-       iso->flags |= HPSB_ISO_DRIVER_STARTED;
-       return retval;
-}
-
-/* check to make sure the user has not supplied bogus values of offset/len
- * that would cause the kernel to access memory outside the buffer */
-static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
-                                    unsigned int offset, unsigned short len,
-                                    unsigned int *out_offset,
-                                    unsigned short *out_len)
-{
-       if (offset >= iso->buf_size)
-               return -EFAULT;
-
-       /* make sure the packet does not go beyond the end of the buffer */
-       if (offset + len > iso->buf_size)
-               return -EFAULT;
-
-       /* check for wrap-around */
-       if (offset + len < offset)
-               return -EFAULT;
-
-       /* now we can trust 'offset' and 'length' */
-       *out_offset = offset;
-       *out_len = len;
-
-       return 0;
-}
-
-/**
- * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
- *
- * @offset is relative to the beginning of the DMA buffer, where the packet's
- * data payload should already have been placed.
- */
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
-                              u8 tag, u8 sy)
-{
-       struct hpsb_iso_packet_info *info;
-       unsigned long flags;
-       int rv;
-
-       if (iso->type != HPSB_ISO_XMIT)
-               return -EINVAL;
-
-       /* is there space in the buffer? */
-       if (iso->n_ready_packets <= 0) {
-               return -EBUSY;
-       }
-
-       info = &iso->infos[iso->first_packet];
-
-       /* check for bogus offset/length */
-       if (hpsb_iso_check_offset_len
-           (iso, offset, len, &info->offset, &info->len))
-               return -EFAULT;
-
-       info->tag = tag;
-       info->sy = sy;
-
-       spin_lock_irqsave(&iso->lock, flags);
-
-       rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
-       if (rv)
-               goto out;
-
-       /* increment cursors */
-       iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
-       iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
-       iso->n_ready_packets--;
-
-       if (iso->prebuffer != 0) {
-               iso->prebuffer--;
-               if (iso->prebuffer <= 0) {
-                       iso->prebuffer = 0;
-                       rv = do_iso_xmit_start(iso, iso->start_cycle);
-               }
-       }
-
-      out:
-       spin_unlock_irqrestore(&iso->lock, flags);
-       return rv;
-}
-
-/**
- * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
- */
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
-{
-       if (iso->type != HPSB_ISO_XMIT)
-               return -EINVAL;
-
-       return wait_event_interruptible(iso->waitq,
-                                       hpsb_iso_n_ready(iso) ==
-                                       iso->buf_packets);
-}
-
-/**
- * hpsb_iso_packet_sent
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been transmitted to the bus (interrupt context is
- * OK).  @cycle is the _exact_ cycle the packet was sent on.  @error should be
- * non-zero if some sort of error occurred when sending the packet.
- */
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&iso->lock, flags);
-
-       /* predict the cycle of the next packet to be queued */
-
-       /* jump ahead by the number of packets that are already buffered */
-       cycle += iso->buf_packets - iso->n_ready_packets;
-       cycle %= 8000;
-
-       iso->xmit_cycle = cycle;
-       iso->n_ready_packets++;
-       iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-
-       if (iso->n_ready_packets == iso->buf_packets || error != 0) {
-               /* the buffer has run empty! */
-               atomic_inc(&iso->overflows);
-       }
-
-       spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_packet_received
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been received (interrupt context is OK).
- */
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-                             u16 total_len, u16 cycle, u8 channel, u8 tag,
-                             u8 sy)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&iso->lock, flags);
-
-       if (iso->n_ready_packets == iso->buf_packets) {
-               /* overflow! */
-               atomic_inc(&iso->overflows);
-               /* Record size of this discarded packet */
-               iso->bytes_discarded += total_len;
-       } else {
-               struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
-               info->offset = offset;
-               info->len = len;
-               info->total_len = total_len;
-               info->cycle = cycle;
-               info->channel = channel;
-               info->tag = tag;
-               info->sy = sy;
-
-               iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-               iso->n_ready_packets++;
-       }
-
-       spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_recv_release_packets - release packets, reuse buffer
- *
- * @n_packets have been read out of the buffer, re-use the buffer space
- */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
-{
-       unsigned long flags;
-       unsigned int i;
-       int rv = 0;
-
-       if (iso->type != HPSB_ISO_RECV)
-               return -1;
-
-       spin_lock_irqsave(&iso->lock, flags);
-       for (i = 0; i < n_packets; i++) {
-               rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
-                                              (unsigned long)&iso->infos[iso->
-                                                                         first_packet]);
-               if (rv)
-                       break;
-
-               iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
-               iso->n_ready_packets--;
-
-               /* release memory from packets discarded when queue was full  */
-               if (iso->n_ready_packets == 0) {        /* Release only after all prior packets handled */
-                       if (iso->bytes_discarded != 0) {
-                               struct hpsb_iso_packet_info inf;
-                               inf.total_len = iso->bytes_discarded;
-                               iso->host->driver->isoctl(iso, RECV_RELEASE,
-                                                         (unsigned long)&inf);
-                               iso->bytes_discarded = 0;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&iso->lock, flags);
-       return rv;
-}
-
-/**
- * hpsb_iso_wake
- *
- * Available to low-level drivers.
- *
- * Call to wake waiting processes after buffer space has opened up.
- */
-void hpsb_iso_wake(struct hpsb_iso *iso)
-{
-       wake_up_interruptible(&iso->waitq);
-
-       if (iso->callback)
-               iso->callback(iso);
-}
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
deleted file mode 100644 (file)
index c2089c0..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_ISO_H
-#define IEEE1394_ISO_H
-
-#include <linux/spinlock_types.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-#include <asm/types.h>
-
-#include "dma.h"
-
-struct hpsb_host;
-
-/* high-level ISO interface */
-
-/*
- * This API sends and receives isochronous packets on a large,
- * virtually-contiguous kernel memory buffer. The buffer may be mapped
- * into a user-space process for zero-copy transmission and reception.
- *
- * There are no explicit boundaries between packets in the buffer. A
- * packet may be transmitted or received at any location. However,
- * low-level drivers may impose certain restrictions on alignment or
- * size of packets. (e.g. in OHCI no packet may cross a page boundary,
- * and packets should be quadlet-aligned)
- */
-
-/* Packet descriptor - the API maintains a ring buffer of these packet
- * descriptors in kernel memory (hpsb_iso.infos[]).  */
-struct hpsb_iso_packet_info {
-       /* offset of data payload relative to the first byte of the buffer */
-       __u32 offset;
-
-       /* length of the data payload, in bytes (not including the isochronous
-        * header) */
-       __u16 len;
-
-       /* (recv only) the cycle number (mod 8000) on which the packet was
-        * received */
-       __u16 cycle;
-
-       /* (recv only) channel on which the packet was received */
-       __u8 channel;
-
-       /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
-       __u8 tag;
-       __u8 sy;
-
-       /* length in bytes of the packet including header/trailer.
-        * MUST be at structure end, since the first part of this structure is
-        * also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
-        * copied to userspace and is accessed there through libraw1394. */
-       __u16 total_len;
-};
-
-enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
-
-/* The mode of the dma when receiving iso data. Must be supported by chip */
-enum raw1394_iso_dma_recv_mode {
-       HPSB_ISO_DMA_DEFAULT = -1,
-       HPSB_ISO_DMA_OLD_ABI = 0,
-       HPSB_ISO_DMA_BUFFERFILL = 1,
-       HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
-};
-
-struct hpsb_iso {
-       enum hpsb_iso_type type;
-
-       /* pointer to low-level driver and its private data */
-       struct hpsb_host *host;
-       void *hostdata;
-
-       /* a function to be called (from interrupt context) after
-        * outgoing packets have been sent, or incoming packets have
-        * arrived */
-       void (*callback)(struct hpsb_iso*);
-
-       /* wait for buffer space */
-       wait_queue_head_t waitq;
-
-       int speed; /* IEEE1394_SPEED_100, 200, or 400 */
-       int channel; /* -1 if multichannel */
-       int dma_mode; /* dma receive mode */
-
-
-       /* greatest # of packets between interrupts - controls
-        * the maximum latency of the buffer */
-       int irq_interval;
-
-       /* the buffer for packet data payloads */
-       struct dma_region data_buf;
-
-       /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
-       unsigned int buf_size;
-
-       /* # of packets in the ringbuffer */
-       unsigned int buf_packets;
-
-       /* protects packet cursors */
-       spinlock_t lock;
-
-       /* the index of the next packet that will be produced
-          or consumed by the user */
-       int first_packet;
-
-       /* the index of the next packet that will be transmitted
-          or received by the 1394 hardware */
-       int pkt_dma;
-
-       /* how many packets, starting at first_packet:
-        * (transmit) are ready to be filled with data
-        * (receive)  contain received data */
-       int n_ready_packets;
-
-       /* how many times the buffer has overflowed or underflowed */
-       atomic_t overflows;
-       /* how many cycles were skipped for a given context */
-       atomic_t skips;
-
-       /* Current number of bytes lost in discarded packets */
-       int bytes_discarded;
-
-       /* private flags to track initialization progress */
-#define HPSB_ISO_DRIVER_INIT     (1<<0)
-#define HPSB_ISO_DRIVER_STARTED  (1<<1)
-       unsigned int flags;
-
-       /* # of packets left to prebuffer (xmit only) */
-       int prebuffer;
-
-       /* starting cycle for DMA (xmit only) */
-       int start_cycle;
-
-       /* cycle at which next packet will be transmitted,
-        * -1 if not known */
-       int xmit_cycle;
-
-       /* ringbuffer of packet descriptors in regular kernel memory
-        * XXX Keep this last, since we use over-allocated memory from
-        * this entry to fill this field. */
-       struct hpsb_iso_packet_info *infos;
-};
-
-/* functions available to high-level drivers (e.g. raw1394) */
-
-struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
-                                   unsigned int data_buf_size,
-                                   unsigned int buf_packets,
-                                   int channel,
-                                   int speed,
-                                   int irq_interval,
-                                   void (*callback)(struct hpsb_iso*));
-struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
-                                   unsigned int data_buf_size,
-                                   unsigned int buf_packets,
-                                   int channel,
-                                   int dma_mode,
-                                   int irq_interval,
-                                   void (*callback)(struct hpsb_iso*));
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
-                       int prebuffer);
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
-                       int tag_mask, int sync);
-void hpsb_iso_stop(struct hpsb_iso *iso);
-void hpsb_iso_shutdown(struct hpsb_iso *iso);
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
-                              u8 tag, u8 sy);
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
-                                 unsigned int n_packets);
-int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-int hpsb_iso_n_ready(struct hpsb_iso *iso);
-
-/* the following are callbacks available to low-level drivers */
-
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-                             u16 total_len, u16 cycle, u8 channel, u8 tag,
-                             u8 sy);
-void hpsb_iso_wake(struct hpsb_iso *iso);
-
-#endif /* IEEE1394_ISO_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
deleted file mode 100644 (file)
index 1835021..0000000
+++ /dev/null
@@ -1,1901 +0,0 @@
-/*
- * Node information (ConfigROM) collection and management.
- *
- * Copyright (C) 2000          Andreas E. Bombe
- *               2001-2003     Ben Collins <bcollins@debian.net>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitmap.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/freezer.h>
-#include <asm/atomic.h>
-
-#include "csr.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "ieee1394_transactions.h"
-#include "nodemgr.h"
-
-static int ignore_drivers;
-module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
-
-struct nodemgr_csr_info {
-       struct hpsb_host *host;
-       nodeid_t nodeid;
-       unsigned int generation;
-
-       kmemcheck_bitfield_begin(flags);
-       unsigned int speed_unverified:1;
-       kmemcheck_bitfield_end(flags);
-};
-
-
-/*
- * Correct the speed map entry.  This is necessary
- *  - for nodes with link speed < phy speed,
- *  - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
- * A possible speed is determined by trial and error, using quadlet reads.
- */
-static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
-                              quadlet_t *buffer)
-{
-       quadlet_t q;
-       u8 i, *speed, old_speed, good_speed;
-       int error;
-
-       speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
-       old_speed = *speed;
-       good_speed = IEEE1394_SPEED_MAX + 1;
-
-       /* Try every speed from S100 to old_speed.
-        * If we did it the other way around, a too low speed could be caught
-        * if the retry succeeded for some other reason, e.g. because the link
-        * just finished its initialization. */
-       for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
-               *speed = i;
-               error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
-                                 &q, 4);
-               if (error)
-                       break;
-               *buffer = q;
-               good_speed = i;
-       }
-       if (good_speed <= IEEE1394_SPEED_MAX) {
-               HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
-                          NODE_BUS_ARGS(ci->host, ci->nodeid),
-                          hpsb_speedto_str[good_speed]);
-               *speed = good_speed;
-               ci->speed_unverified = 0;
-               return 0;
-       }
-       *speed = old_speed;
-       return error;
-}
-
-static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr,
-                           void *buffer, void *__ci)
-{
-       struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
-       int i, error;
-
-       for (i = 1; ; i++) {
-               error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
-                                 buffer, 4);
-               if (!error) {
-                       ci->speed_unverified = 0;
-                       break;
-               }
-               /* Give up after 3rd failure. */
-               if (i == 3)
-                       break;
-
-               /* The ieee1394_core guessed the node's speed capability from
-                * the self ID.  Check whether a lower speed works. */
-               if (ci->speed_unverified) {
-                       error = nodemgr_check_speed(ci, addr, buffer);
-                       if (!error)
-                               break;
-               }
-               if (msleep_interruptible(334))
-                       return -EINTR;
-       }
-       return error;
-}
-
-static struct csr1212_bus_ops nodemgr_csr_ops = {
-       .bus_read =     nodemgr_bus_read,
-};
-
-
-/*
- * Basically what we do here is start off retrieving the bus_info block.
- * From there will fill in some info about the node, verify it is of IEEE
- * 1394 type, and that the crc checks out ok. After that we start off with
- * the root directory, and subdirectories. To do this, we retrieve the
- * quadlet header for a directory, find out the length, and retrieve the
- * complete directory entry (be it a leaf or a directory). We then process
- * it and add the info to our structure for that particular node.
- *
- * We verify CRC's along the way for each directory/block/leaf. The entire
- * node structure is generic, and simply stores the information in a way
- * that's easy to parse by the protocol interface.
- */
-
-/*
- * The nodemgr relies heavily on the Driver Model for device callbacks and
- * driver/device mappings. The old nodemgr used to handle all this itself,
- * but now we are much simpler because of the LDM.
- */
-
-struct host_info {
-       struct hpsb_host *host;
-       struct list_head list;
-       struct task_struct *thread;
-};
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
-
-struct bus_type ieee1394_bus_type = {
-       .name           = "ieee1394",
-       .match          = nodemgr_bus_match,
-};
-
-static void host_cls_release(struct device *dev)
-{
-       put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
-}
-
-struct class hpsb_host_class = {
-       .name           = "ieee1394_host",
-       .dev_release    = host_cls_release,
-};
-
-static void ne_cls_release(struct device *dev)
-{
-       put_device(&container_of((dev), struct node_entry, node_dev)->device);
-}
-
-static struct class nodemgr_ne_class = {
-       .name           = "ieee1394_node",
-       .dev_release    = ne_cls_release,
-};
-
-static void ud_cls_release(struct device *dev)
-{
-       put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
-}
-
-/* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway.
- */
-static struct class nodemgr_ud_class = {
-       .name           = "ieee1394",
-       .dev_release    = ud_cls_release,
-       .dev_uevent     = nodemgr_uevent,
-};
-
-static struct hpsb_highlevel nodemgr_highlevel;
-
-
-static void nodemgr_release_ud(struct device *dev)
-{
-       struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
-       if (ud->vendor_name_kv)
-               csr1212_release_keyval(ud->vendor_name_kv);
-       if (ud->model_name_kv)
-               csr1212_release_keyval(ud->model_name_kv);
-
-       kfree(ud);
-}
-
-static void nodemgr_release_ne(struct device *dev)
-{
-       struct node_entry *ne = container_of(dev, struct node_entry, device);
-
-       if (ne->vendor_name_kv)
-               csr1212_release_keyval(ne->vendor_name_kv);
-
-       kfree(ne);
-}
-
-
-static void nodemgr_release_host(struct device *dev)
-{
-       struct hpsb_host *host = container_of(dev, struct hpsb_host, device);
-
-       csr1212_destroy_csr(host->csr.rom);
-
-       kfree(host);
-}
-
-static int nodemgr_ud_platform_data;
-
-static struct device nodemgr_dev_template_ud = {
-       .bus            = &ieee1394_bus_type,
-       .release        = nodemgr_release_ud,
-       .platform_data  = &nodemgr_ud_platform_data,
-};
-
-static struct device nodemgr_dev_template_ne = {
-       .bus            = &ieee1394_bus_type,
-       .release        = nodemgr_release_ne,
-};
-
-/* This dummy driver prevents the host devices from being scanned. We have no
- * useful drivers for them yet, and there would be a deadlock possible if the
- * driver core scans the host device while the host's low-level driver (i.e.
- * the host's parent device) is being removed. */
-static struct device_driver nodemgr_mid_layer_driver = {
-       .bus            = &ieee1394_bus_type,
-       .name           = "nodemgr",
-       .owner          = THIS_MODULE,
-};
-
-struct device nodemgr_dev_template_host = {
-       .bus            = &ieee1394_bus_type,
-       .release        = nodemgr_release_host,
-};
-
-
-#define fw_attr(class, class_type, field, type, format_string)         \
-static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\
-{                                                                      \
-       class_type *class;                                              \
-       class = container_of(dev, class_type, device);                  \
-       return sprintf(buf, format_string, (type)class->field);         \
-}                                                                      \
-static struct device_attribute dev_attr_##class##_##field = {          \
-       .attr = {.name = __stringify(field), .mode = S_IRUGO },         \
-       .show   = fw_show_##class##_##field,                            \
-};
-
-#define fw_attr_td(class, class_type, td_kv)                           \
-static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\
-{                                                                      \
-       int len;                                                        \
-       class_type *class = container_of(dev, class_type, device);      \
-       len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t);   \
-       memcpy(buf,                                                     \
-              CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv),      \
-              len);                                                    \
-       while (buf[len - 1] == '\0')                                    \
-               len--;                                                  \
-       buf[len++] = '\n';                                              \
-       buf[len] = '\0';                                                \
-       return len;                                                     \
-}                                                                      \
-static struct device_attribute dev_attr_##class##_##td_kv = {          \
-       .attr = {.name = __stringify(td_kv), .mode = S_IRUGO },         \
-       .show   = fw_show_##class##_##td_kv,                            \
-};
-
-
-#define fw_drv_attr(field, type, format_string)                        \
-static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
-{                                                              \
-       struct hpsb_protocol_driver *driver;                    \
-       driver = container_of(drv, struct hpsb_protocol_driver, driver); \
-       return sprintf(buf, format_string, (type)driver->field);\
-}                                                              \
-static struct driver_attribute driver_attr_drv_##field = {     \
-       .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
-       .show   = fw_drv_show_##field,                          \
-};
-
-
-static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct node_entry *ne = container_of(dev, struct node_entry, device);
-
-       return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
-                      "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n",
-                      ne->busopt.irmc,
-                      ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-                      ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
-                      ne->busopt.max_rec,
-                      ne->busopt.max_rom,
-                      ne->busopt.cyc_clk_acc);
-}
-static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-
-
-#ifdef HPSB_DEBUG_TLABELS
-static ssize_t fw_show_ne_tlabels_free(struct device *dev,
-                                      struct device_attribute *attr, char *buf)
-{
-       struct node_entry *ne = container_of(dev, struct node_entry, device);
-       unsigned long flags;
-       unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
-       int tf;
-
-       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-       tf = 64 - bitmap_weight(tp, 64);
-       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-       return sprintf(buf, "%d\n", tf);
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-
-
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
-                                      struct device_attribute *attr, char *buf)
-{
-       struct node_entry *ne = container_of(dev, struct node_entry, device);
-       unsigned long flags;
-       unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
-       u64 tm;
-
-       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-#if (BITS_PER_LONG <= 32)
-       tm = ((u64)tp[0] << 32) + tp[1];
-#else
-       tm = tp[0];
-#endif
-       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-       return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);
-}
-static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
-#endif /* HPSB_DEBUG_TLABELS */
-
-
-static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-       int state = simple_strtoul(buf, NULL, 10);
-
-       if (state == 1) {
-               ud->ignore_driver = 1;
-               device_release_driver(dev);
-       } else if (state == 0)
-               ud->ignore_driver = 0;
-
-       return count;
-}
-static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
-       return sprintf(buf, "%d\n", ud->ignore_driver);
-}
-static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver);
-
-
-static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,
-                            size_t count)
-{
-       int error = 0;
-
-       if (simple_strtoul(buf, NULL, 10) == 1)
-               error = bus_rescan_devices(&ieee1394_bus_type);
-       return error ? error : count;
-}
-static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
-{
-       return sprintf(buf, "You can force a rescan of the bus for "
-                       "drivers by writing a 1 to this file\n");
-}
-static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan);
-
-
-static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count)
-{
-       int state = simple_strtoul(buf, NULL, 10);
-
-       if (state == 1)
-               ignore_drivers = 1;
-       else if (state == 0)
-               ignore_drivers = 0;
-
-       return count;
-}
-static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf)
-{
-       return sprintf(buf, "%d\n", ignore_drivers);
-}
-static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers);
-
-
-struct bus_attribute *const fw_bus_attrs[] = {
-       &bus_attr_rescan,
-       &bus_attr_ignore_drivers,
-       NULL
-};
-
-
-fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
-
-fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
-fw_attr_td(ne, struct node_entry, vendor_name_kv)
-
-fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
-fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
-
-static struct device_attribute *const fw_ne_attrs[] = {
-       &dev_attr_ne_guid,
-       &dev_attr_ne_guid_vendor_id,
-       &dev_attr_ne_capabilities,
-       &dev_attr_ne_vendor_id,
-       &dev_attr_ne_nodeid,
-       &dev_attr_bus_options,
-#ifdef HPSB_DEBUG_TLABELS
-       &dev_attr_tlabels_free,
-       &dev_attr_tlabels_mask,
-#endif
-};
-
-
-
-fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n")
-fw_attr(ud, struct unit_directory, length, int, "%d\n")
-/* These are all dependent on the value being provided */
-fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
-fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr_td(ud, struct unit_directory, model_name_kv)
-
-static struct device_attribute *const fw_ud_attrs[] = {
-       &dev_attr_ud_address,
-       &dev_attr_ud_length,
-       &dev_attr_ignore_driver,
-};
-
-
-fw_attr(host, struct hpsb_host, node_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n")
-fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_root, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_irm, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n")
-
-static struct device_attribute *const fw_host_attrs[] = {
-       &dev_attr_host_node_count,
-       &dev_attr_host_selfid_count,
-       &dev_attr_host_nodes_active,
-       &dev_attr_host_in_bus_reset,
-       &dev_attr_host_is_root,
-       &dev_attr_host_is_cycmst,
-       &dev_attr_host_is_irm,
-       &dev_attr_host_is_busmgr,
-};
-
-
-static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
-{
-       struct hpsb_protocol_driver *driver;
-       const struct ieee1394_device_id *id;
-       int length = 0;
-       char *scratch = buf;
-
-       driver = container_of(drv, struct hpsb_protocol_driver, driver);
-       id = driver->id_table;
-       if (!id)
-               return 0;
-
-       for (; id->match_flags != 0; id++) {
-               int need_coma = 0;
-
-               if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
-                       length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id);
-                       scratch = buf + length;
-                       need_coma++;
-               }
-
-               if (id->match_flags & IEEE1394_MATCH_MODEL_ID) {
-                       length += sprintf(scratch, "%smodel_id=0x%06x",
-                                         need_coma++ ? "," : "",
-                                         id->model_id);
-                       scratch = buf + length;
-               }
-
-               if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) {
-                       length += sprintf(scratch, "%sspecifier_id=0x%06x",
-                                         need_coma++ ? "," : "",
-                                         id->specifier_id);
-                       scratch = buf + length;
-               }
-
-               if (id->match_flags & IEEE1394_MATCH_VERSION) {
-                       length += sprintf(scratch, "%sversion=0x%06x",
-                                         need_coma++ ? "," : "",
-                                         id->version);
-                       scratch = buf + length;
-               }
-
-               if (need_coma) {
-                       *scratch++ = '\n';
-                       length++;
-               }
-       }
-
-       return length;
-}
-static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL);
-
-
-fw_drv_attr(name, const char *, "%s\n")
-
-static struct driver_attribute *const fw_drv_attrs[] = {
-       &driver_attr_drv_name,
-       &driver_attr_device_ids,
-};
-
-
-static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
-{
-       struct device_driver *drv = &driver->driver;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
-               if (driver_create_file(drv, fw_drv_attrs[i]))
-                       goto fail;
-       return;
-fail:
-       HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver)
-{
-       struct device_driver *drv = &driver->driver;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
-               driver_remove_file(drv, fw_drv_attrs[i]);
-}
-
-
-static void nodemgr_create_ne_dev_files(struct node_entry *ne)
-{
-       struct device *dev = &ne->device;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
-               if (device_create_file(dev, fw_ne_attrs[i]))
-                       goto fail;
-       return;
-fail:
-       HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_create_host_dev_files(struct hpsb_host *host)
-{
-       struct device *dev = &host->device;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
-               if (device_create_file(dev, fw_host_attrs[i]))
-                       goto fail;
-       return;
-fail:
-       HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
-                                              nodeid_t nodeid);
-
-static void nodemgr_update_host_dev_links(struct hpsb_host *host)
-{
-       struct device *dev = &host->device;
-       struct node_entry *ne;
-
-       sysfs_remove_link(&dev->kobj, "irm_id");
-       sysfs_remove_link(&dev->kobj, "busmgr_id");
-       sysfs_remove_link(&dev->kobj, "host_id");
-
-       if ((ne = find_entry_by_nodeid(host, host->irm_id)) &&
-           sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"))
-               goto fail;
-       if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) &&
-           sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"))
-               goto fail;
-       if ((ne = find_entry_by_nodeid(host, host->node_id)) &&
-           sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id"))
-               goto fail;
-       return;
-fail:
-       HPSB_ERR("Failed to update sysfs attributes for host %d", host->id);
-}
-
-static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
-{
-       struct device *dev = &ud->device;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
-               if (device_create_file(dev, fw_ud_attrs[i]))
-                       goto fail;
-       if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
-               if (device_create_file(dev, &dev_attr_ud_specifier_id))
-                       goto fail;
-       if (ud->flags & UNIT_DIRECTORY_VERSION)
-               if (device_create_file(dev, &dev_attr_ud_version))
-                       goto fail;
-       if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
-               if (device_create_file(dev, &dev_attr_ud_vendor_id))
-                       goto fail;
-               if (ud->vendor_name_kv &&
-                   device_create_file(dev, &dev_attr_ud_vendor_name_kv))
-                       goto fail;
-       }
-       if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
-               if (device_create_file(dev, &dev_attr_ud_model_id))
-                       goto fail;
-               if (ud->model_name_kv &&
-                   device_create_file(dev, &dev_attr_ud_model_name_kv))
-                       goto fail;
-       }
-       return;
-fail:
-       HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
-{
-       struct hpsb_protocol_driver *driver;
-       struct unit_directory *ud;
-       const struct ieee1394_device_id *id;
-
-       /* We only match unit directories */
-       if (dev->platform_data != &nodemgr_ud_platform_data)
-               return 0;
-
-       ud = container_of(dev, struct unit_directory, device);
-       if (ud->ne->in_limbo || ud->ignore_driver)
-               return 0;
-
-       /* We only match drivers of type hpsb_protocol_driver */
-       if (drv == &nodemgr_mid_layer_driver)
-               return 0;
-
-       driver = container_of(drv, struct hpsb_protocol_driver, driver);
-       id = driver->id_table;
-       if (!id)
-               return 0;
-
-       for (; id->match_flags != 0; id++) {
-               if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
-                   id->vendor_id != ud->vendor_id)
-                       continue;
-
-               if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
-                   id->model_id != ud->model_id)
-                       continue;
-
-               if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
-                   id->specifier_id != ud->specifier_id)
-                       continue;
-
-               if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
-                   id->version != ud->version)
-                       continue;
-
-               return 1;
-       }
-
-       return 0;
-}
-
-
-static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
-
-static int match_ne(struct device *dev, void *data)
-{
-       struct unit_directory *ud;
-       struct node_entry *ne = data;
-
-       ud = container_of(dev, struct unit_directory, unit_dev);
-       return ud->ne == ne;
-}
-
-static void nodemgr_remove_uds(struct node_entry *ne)
-{
-       struct device *dev;
-       struct unit_directory *ud;
-
-       /* Use class_find device to iterate the devices. Since this code
-        * may be called from other contexts besides the knodemgrds,
-        * protect it by nodemgr_serialize_remove_uds.
-        */
-       mutex_lock(&nodemgr_serialize_remove_uds);
-       for (;;) {
-               dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne);
-               if (!dev)
-                       break;
-               ud = container_of(dev, struct unit_directory, unit_dev);
-               put_device(dev);
-               device_unregister(&ud->unit_dev);
-               device_unregister(&ud->device);
-       }
-       mutex_unlock(&nodemgr_serialize_remove_uds);
-}
-
-
-static void nodemgr_remove_ne(struct node_entry *ne)
-{
-       struct device *dev;
-
-       dev = get_device(&ne->device);
-       if (!dev)
-               return;
-
-       HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                  NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
-       nodemgr_remove_uds(ne);
-
-       device_unregister(&ne->node_dev);
-       device_unregister(dev);
-
-       put_device(dev);
-}
-
-static int remove_host_dev(struct device *dev, void *data)
-{
-       if (dev->bus == &ieee1394_bus_type)
-               nodemgr_remove_ne(container_of(dev, struct node_entry,
-                                 device));
-       return 0;
-}
-
-static void nodemgr_remove_host_dev(struct device *dev)
-{
-       device_for_each_child(dev, NULL, remove_host_dev);
-       sysfs_remove_link(&dev->kobj, "irm_id");
-       sysfs_remove_link(&dev->kobj, "busmgr_id");
-       sysfs_remove_link(&dev->kobj, "host_id");
-}
-
-
-static void nodemgr_update_bus_options(struct node_entry *ne)
-{
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-       static const u16 mr[] = { 4, 64, 1024, 0};
-#endif
-       quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
-
-       ne->busopt.irmc         = (busoptions >> 31) & 1;
-       ne->busopt.cmc          = (busoptions >> 30) & 1;
-       ne->busopt.isc          = (busoptions >> 29) & 1;
-       ne->busopt.bmc          = (busoptions >> 28) & 1;
-       ne->busopt.pmc          = (busoptions >> 27) & 1;
-       ne->busopt.cyc_clk_acc  = (busoptions >> 16) & 0xff;
-       ne->busopt.max_rec      = 1 << (((busoptions >> 12) & 0xf) + 1);
-       ne->busopt.max_rom      = (busoptions >> 8) & 0x3;
-       ne->busopt.generation   = (busoptions >> 4) & 0xf;
-       ne->busopt.lnkspd       = busoptions & 0x7;
-
-       HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
-                    "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
-                    busoptions, ne->busopt.irmc, ne->busopt.cmc,
-                    ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
-                    ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
-                    mr[ne->busopt.max_rom],
-                    ne->busopt.generation, ne->busopt.lnkspd);
-}
-
-
-static struct node_entry *nodemgr_create_node(octlet_t guid,
-                               struct csr1212_csr *csr, struct hpsb_host *host,
-                               nodeid_t nodeid, unsigned int generation)
-{
-       struct node_entry *ne;
-
-       ne = kzalloc(sizeof(*ne), GFP_KERNEL);
-       if (!ne)
-               goto fail_alloc;
-
-       ne->host = host;
-       ne->nodeid = nodeid;
-       ne->generation = generation;
-       ne->needs_probe = true;
-
-       ne->guid = guid;
-       ne->guid_vendor_id = (guid >> 40) & 0xffffff;
-       ne->csr = csr;
-
-       memcpy(&ne->device, &nodemgr_dev_template_ne,
-              sizeof(ne->device));
-       ne->device.parent = &host->device;
-       dev_set_name(&ne->device, "%016Lx", (unsigned long long)(ne->guid));
-
-       ne->node_dev.parent = &ne->device;
-       ne->node_dev.class = &nodemgr_ne_class;
-       dev_set_name(&ne->node_dev, "%016Lx", (unsigned long long)(ne->guid));
-
-       if (device_register(&ne->device))
-               goto fail_devreg;
-       if (device_register(&ne->node_dev))
-               goto fail_classdevreg;
-       get_device(&ne->device);
-
-       nodemgr_create_ne_dev_files(ne);
-
-       nodemgr_update_bus_options(ne);
-
-       HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                  (host->node_id == nodeid) ? "Host" : "Node",
-                  NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
-       return ne;
-
-fail_classdevreg:
-       device_unregister(&ne->device);
-fail_devreg:
-       kfree(ne);
-fail_alloc:
-       HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
-       return NULL;
-}
-
-static int match_ne_guid(struct device *dev, void *data)
-{
-       struct node_entry *ne;
-       u64 *guid = data;
-
-       ne = container_of(dev, struct node_entry, node_dev);
-       return ne->guid == *guid;
-}
-
-static struct node_entry *find_entry_by_guid(u64 guid)
-{
-       struct device *dev;
-       struct node_entry *ne;
-
-       dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid);
-       if (!dev)
-               return NULL;
-       ne = container_of(dev, struct node_entry, node_dev);
-       put_device(dev);
-
-       return ne;
-}
-
-struct match_nodeid_parameter {
-       struct hpsb_host *host;
-       nodeid_t nodeid;
-};
-
-static int match_ne_nodeid(struct device *dev, void *data)
-{
-       int found = 0;
-       struct node_entry *ne;
-       struct match_nodeid_parameter *p = data;
-
-       if (!dev)
-               goto ret;
-       ne = container_of(dev, struct node_entry, node_dev);
-       if (ne->host == p->host && ne->nodeid == p->nodeid)
-               found = 1;
-ret:
-       return found;
-}
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
-                                              nodeid_t nodeid)
-{
-       struct device *dev;
-       struct node_entry *ne;
-       struct match_nodeid_parameter p;
-
-       p.host = host;
-       p.nodeid = nodeid;
-
-       dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid);
-       if (!dev)
-               return NULL;
-       ne = container_of(dev, struct node_entry, node_dev);
-       put_device(dev);
-
-       return ne;
-}
-
-
-static void nodemgr_register_device(struct node_entry *ne, 
-       struct unit_directory *ud, struct device *parent)
-{
-       memcpy(&ud->device, &nodemgr_dev_template_ud,
-              sizeof(ud->device));
-
-       ud->device.parent = parent;
-
-       dev_set_name(&ud->device, "%s-%u", dev_name(&ne->device), ud->id);
-
-       ud->unit_dev.parent = &ud->device;
-       ud->unit_dev.class = &nodemgr_ud_class;
-       dev_set_name(&ud->unit_dev, "%s-%u", dev_name(&ne->device), ud->id);
-
-       if (device_register(&ud->device))
-               goto fail_devreg;
-       if (device_register(&ud->unit_dev))
-               goto fail_classdevreg;
-       get_device(&ud->device);
-
-       nodemgr_create_ud_dev_files(ud);
-
-       return;
-
-fail_classdevreg:
-       device_unregister(&ud->device);
-fail_devreg:
-       HPSB_ERR("Failed to create unit %s", dev_name(&ud->device));
-}      
-
-
-/* This implementation currently only scans the config rom and its
- * immediate unit directories looking for software_id and
- * software_version entries, in order to get driver autoloading working. */
-static struct unit_directory *nodemgr_process_unit_directory
-       (struct node_entry *ne, struct csr1212_keyval *ud_kv,
-        unsigned int *id, struct unit_directory *parent)
-{
-       struct unit_directory *ud;
-       struct unit_directory *ud_child = NULL;
-       struct csr1212_dentry *dentry;
-       struct csr1212_keyval *kv;
-       u8 last_key_id = 0;
-
-       ud = kzalloc(sizeof(*ud), GFP_KERNEL);
-       if (!ud)
-               goto unit_directory_error;
-
-       ud->ne = ne;
-       ud->ignore_driver = ignore_drivers;
-       ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE;
-       ud->directory_id = ud->address & 0xffffff;
-       ud->ud_kv = ud_kv;
-       ud->id = (*id)++;
-
-       /* inherit vendor_id from root directory if none exists in unit dir */
-       ud->vendor_id = ne->vendor_id;
-
-       csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
-               switch (kv->key.id) {
-               case CSR1212_KV_ID_VENDOR:
-                       if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
-                               ud->vendor_id = kv->value.immediate;
-                               ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-                       }
-                       break;
-
-               case CSR1212_KV_ID_MODEL:
-                       ud->model_id = kv->value.immediate;
-                       ud->flags |= UNIT_DIRECTORY_MODEL_ID;
-                       break;
-
-               case CSR1212_KV_ID_SPECIFIER_ID:
-                       ud->specifier_id = kv->value.immediate;
-                       ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
-                       break;
-
-               case CSR1212_KV_ID_VERSION:
-                       ud->version = kv->value.immediate;
-                       ud->flags |= UNIT_DIRECTORY_VERSION;
-                       break;
-
-               case CSR1212_KV_ID_DESCRIPTOR:
-                       if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
-                           CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
-                           CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
-                           CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
-                           CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
-                           CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
-                               switch (last_key_id) {
-                               case CSR1212_KV_ID_VENDOR:
-                                       csr1212_keep_keyval(kv);
-                                       ud->vendor_name_kv = kv;
-                                       break;
-
-                               case CSR1212_KV_ID_MODEL:
-                                       csr1212_keep_keyval(kv);
-                                       ud->model_name_kv = kv;
-                                       break;
-
-                               }
-                       } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
-                       break;
-
-               case CSR1212_KV_ID_DEPENDENT_INFO:
-                       /* Logical Unit Number */
-                       if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
-                               if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
-                                       ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL);
-                                       if (!ud_child)
-                                               goto unit_directory_error;
-                                       nodemgr_register_device(ne, ud_child, &ne->device);
-                                       ud_child = NULL;
-                                       
-                                       ud->id = (*id)++;
-                               }
-                               ud->lun = kv->value.immediate;
-                               ud->flags |= UNIT_DIRECTORY_HAS_LUN;
-
-                       /* Logical Unit Directory */
-                       } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
-                               /* This should really be done in SBP2 as this is
-                                * doing SBP2 specific parsing.
-                                */
-                               
-                               /* first register the parent unit */
-                               ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
-                               if (ud->device.bus != &ieee1394_bus_type)
-                                       nodemgr_register_device(ne, ud, &ne->device);
-                               
-                               /* process the child unit */
-                               ud_child = nodemgr_process_unit_directory(ne, kv, id, ud);
-
-                               if (ud_child == NULL)
-                                       break;
-                               
-                               /* inherit unspecified values, the driver core picks it up */
-                               if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
-                                   !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
-                               {
-                                       ud_child->flags |=  UNIT_DIRECTORY_MODEL_ID;
-                                       ud_child->model_id = ud->model_id;
-                               }
-                               if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
-                                   !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
-                               {
-                                       ud_child->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
-                                       ud_child->specifier_id = ud->specifier_id;
-                               }
-                               if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
-                                   !(ud_child->flags & UNIT_DIRECTORY_VERSION))
-                               {
-                                       ud_child->flags |=  UNIT_DIRECTORY_VERSION;
-                                       ud_child->version = ud->version;
-                               }
-                               
-                               /* register the child unit */
-                               ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
-                               nodemgr_register_device(ne, ud_child, &ud->device);
-                       }
-
-                       break;
-
-               case CSR1212_KV_ID_DIRECTORY_ID:
-                       ud->directory_id = kv->value.immediate;
-                       break;
-
-               default:
-                       break;
-               }
-               last_key_id = kv->key.id;
-       }
-       
-       /* do not process child units here and only if not already registered */
-       if (!parent && ud->device.bus != &ieee1394_bus_type)
-               nodemgr_register_device(ne, ud, &ne->device);
-
-       return ud;
-
-unit_directory_error:
-       kfree(ud);
-       return NULL;
-}
-
-
-static void nodemgr_process_root_directory(struct node_entry *ne)
-{
-       unsigned int ud_id = 0;
-       struct csr1212_dentry *dentry;
-       struct csr1212_keyval *kv, *vendor_name_kv = NULL;
-       u8 last_key_id = 0;
-
-       ne->needs_probe = false;
-
-       csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {
-               switch (kv->key.id) {
-               case CSR1212_KV_ID_VENDOR:
-                       ne->vendor_id = kv->value.immediate;
-                       break;
-
-               case CSR1212_KV_ID_NODE_CAPABILITIES:
-                       ne->capabilities = kv->value.immediate;
-                       break;
-
-               case CSR1212_KV_ID_UNIT:
-                       nodemgr_process_unit_directory(ne, kv, &ud_id, NULL);
-                       break;
-
-               case CSR1212_KV_ID_DESCRIPTOR:
-                       if (last_key_id == CSR1212_KV_ID_VENDOR) {
-                               if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
-                                   CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
-                                   CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
-                                   CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
-                                   CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
-                                   CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
-                                       csr1212_keep_keyval(kv);
-                                       vendor_name_kv = kv;
-                               }
-                       }
-                       break;
-               }
-               last_key_id = kv->key.id;
-       }
-
-       if (ne->vendor_name_kv) {
-               kv = ne->vendor_name_kv;
-               ne->vendor_name_kv = vendor_name_kv;
-               csr1212_release_keyval(kv);
-       } else if (vendor_name_kv) {
-               ne->vendor_name_kv = vendor_name_kv;
-               if (device_create_file(&ne->device,
-                                      &dev_attr_ne_vendor_name_kv) != 0)
-                       HPSB_ERR("Failed to add sysfs attribute");
-       }
-}
-
-#ifdef CONFIG_HOTPLUG
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       struct unit_directory *ud;
-       int retval = 0;
-       /* ieee1394:venNmoNspNverN */
-       char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
-
-       if (!dev)
-               return -ENODEV;
-
-       ud = container_of(dev, struct unit_directory, unit_dev);
-
-       if (ud->ne->in_limbo || ud->ignore_driver)
-               return -ENODEV;
-
-#define PUT_ENVP(fmt,val)                                      \
-do {                                                           \
-       retval = add_uevent_var(env, fmt, val);         \
-       if (retval)                                             \
-               return retval;                                  \
-} while (0)
-
-       PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
-       PUT_ENVP("MODEL_ID=%06x", ud->model_id);
-       PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
-       PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
-       PUT_ENVP("VERSION=%06x", ud->version);
-       snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
-                       ud->vendor_id,
-                       ud->model_id,
-                       ud->specifier_id,
-                       ud->version);
-       PUT_ENVP("MODALIAS=%s", buf);
-
-#undef PUT_ENVP
-
-       return 0;
-}
-
-#else
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       return -ENODEV;
-}
-
-#endif /* CONFIG_HOTPLUG */
-
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *drv,
-                            struct module *owner)
-{
-       int error;
-
-       drv->driver.bus = &ieee1394_bus_type;
-       drv->driver.owner = owner;
-       drv->driver.name = drv->name;
-
-       /* This will cause a probe for devices */
-       error = driver_register(&drv->driver);
-       if (!error)
-               nodemgr_create_drv_files(drv);
-       return error;
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
-{
-       nodemgr_remove_drv_files(driver);
-       /* This will subsequently disconnect all devices that our driver
-        * is attached to. */
-       driver_unregister(&driver->driver);
-}
-
-
-/*
- * This function updates nodes that were present on the bus before the
- * reset and still are after the reset.  The nodeid and the config rom
- * may have changed, and the drivers managing this device must be
- * informed that this device just went through a bus reset, to allow
- * the to take whatever actions required.
- */
-static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
-                               nodeid_t nodeid, unsigned int generation)
-{
-       if (ne->nodeid != nodeid) {
-               HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,
-                          NODE_BUS_ARGS(ne->host, ne->nodeid),
-                          NODE_BUS_ARGS(ne->host, nodeid));
-               ne->nodeid = nodeid;
-       }
-
-       if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {
-               kfree(ne->csr->private);
-               csr1212_destroy_csr(ne->csr);
-               ne->csr = csr;
-
-               /* If the node's configrom generation has changed, we
-                * unregister all the unit directories. */
-               nodemgr_remove_uds(ne);
-
-               nodemgr_update_bus_options(ne);
-
-               /* Mark the node as new, so it gets re-probed */
-               ne->needs_probe = true;
-       } else {
-               /* old cache is valid, so update its generation */
-               struct nodemgr_csr_info *ci = ne->csr->private;
-               ci->generation = generation;
-               /* free the partially filled now unneeded new cache */
-               kfree(csr->private);
-               csr1212_destroy_csr(csr);
-       }
-
-       /* Finally, mark the node current */
-       smp_wmb();
-       ne->generation = generation;
-
-       if (ne->in_limbo) {
-               device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
-               ne->in_limbo = false;
-
-               HPSB_DEBUG("Node reactivated: "
-                          "ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                          NODE_BUS_ARGS(ne->host, ne->nodeid),
-                          (unsigned long long)ne->guid);
-       }
-}
-
-static void nodemgr_node_scan_one(struct hpsb_host *host,
-                                 nodeid_t nodeid, int generation)
-{
-       struct node_entry *ne;
-       octlet_t guid;
-       struct csr1212_csr *csr;
-       struct nodemgr_csr_info *ci;
-       u8 *speed;
-
-       ci = kmalloc(sizeof(*ci), GFP_KERNEL);
-       kmemcheck_annotate_bitfield(ci, flags);
-       if (!ci)
-               return;
-
-       ci->host = host;
-       ci->nodeid = nodeid;
-       ci->generation = generation;
-
-       /* Prepare for speed probe which occurs when reading the ROM */
-       speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
-       if (*speed > host->csr.lnk_spd)
-               *speed = host->csr.lnk_spd;
-       ci->speed_unverified = *speed > IEEE1394_SPEED_100;
-
-       /* We need to detect when the ConfigROM's generation has changed,
-        * so we only update the node's info when it needs to be.  */
-
-       csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);
-       if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {
-               HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,
-                        NODE_BUS_ARGS(host, nodeid));
-               if (csr)
-                       csr1212_destroy_csr(csr);
-               kfree(ci);
-               return;
-       }
-
-       if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {
-               /* This isn't a 1394 device, but we let it slide. There
-                * was a report of a device with broken firmware which
-                * reported '2394' instead of '1394', which is obviously a
-                * mistake. One would hope that a non-1394 device never
-                * gets connected to Firewire bus. If someone does, we
-                * shouldn't be held responsible, so we'll allow it with a
-                * warning.  */
-               HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
-                         NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);
-       }
-
-       guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);
-       ne = find_entry_by_guid(guid);
-
-       if (ne && ne->host != host && ne->in_limbo) {
-               /* Must have moved this device from one host to another */
-               nodemgr_remove_ne(ne);
-               ne = NULL;
-       }
-
-       if (!ne)
-               nodemgr_create_node(guid, csr, host, nodeid, generation);
-       else
-               nodemgr_update_node(ne, csr, nodeid, generation);
-}
-
-
-static void nodemgr_node_scan(struct hpsb_host *host, int generation)
-{
-       int count;
-       struct selfid *sid = (struct selfid *)host->topology_map;
-       nodeid_t nodeid = LOCAL_BUS;
-
-       /* Scan each node on the bus */
-       for (count = host->selfid_count; count; count--, sid++) {
-               if (sid->extended)
-                       continue;
-
-               if (!sid->link_active) {
-                       nodeid++;
-                       continue;
-               }
-               nodemgr_node_scan_one(host, nodeid++, generation);
-       }
-}
-
-static void nodemgr_pause_ne(struct node_entry *ne)
-{
-       HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                  NODE_BUS_ARGS(ne->host, ne->nodeid),
-                  (unsigned long long)ne->guid);
-
-       ne->in_limbo = true;
-       WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
-}
-
-static int update_pdrv(struct device *dev, void *data)
-{
-       struct unit_directory *ud;
-       struct device_driver *drv;
-       struct hpsb_protocol_driver *pdrv;
-       struct node_entry *ne = data;
-       int error;
-
-       ud = container_of(dev, struct unit_directory, unit_dev);
-       if (ud->ne == ne) {
-               drv = get_driver(ud->device.driver);
-               if (drv) {
-                       error = 0;
-                       pdrv = container_of(drv, struct hpsb_protocol_driver,
-                                           driver);
-                       if (pdrv->update) {
-                               device_lock(&ud->device);
-                               error = pdrv->update(ud);
-                               device_unlock(&ud->device);
-                       }
-                       if (error)
-                               device_release_driver(&ud->device);
-                       put_driver(drv);
-               }
-       }
-
-       return 0;
-}
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
-{
-       class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv);
-}
-
-/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3.  This
- * seems like an optional service but in the end it is practically mandatory
- * as a consequence of these clauses.
- *
- * Note that we cannot do a broadcast write to all nodes at once because some
- * pre-1394a devices would hang. */
-static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
-{
-       const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
-       quadlet_t bc_remote, bc_local;
-       int error;
-
-       if (!ne->host->is_irm || ne->generation != generation ||
-           ne->nodeid == ne->host->node_id)
-               return;
-
-       bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
-
-       /* Check if the register is implemented and 1394a compliant. */
-       error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
-                         sizeof(bc_remote));
-       if (!error && bc_remote & cpu_to_be32(0x80000000) &&
-           bc_remote != bc_local)
-               hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
-}
-
-
-static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne,
-                            int generation)
-{
-       struct device *dev;
-
-       if (ne->host != host || ne->in_limbo)
-               return;
-
-       dev = get_device(&ne->device);
-       if (!dev)
-               return;
-
-       nodemgr_irm_write_bc(ne, generation);
-
-       /* If "needs_probe", then this is either a new or changed node we
-        * rescan totally. If the generation matches for an existing node
-        * (one that existed prior to the bus reset) we send update calls
-        * down to the drivers. Otherwise, this is a dead node and we
-        * suspend it. */
-       if (ne->needs_probe)
-               nodemgr_process_root_directory(ne);
-       else if (ne->generation == generation)
-               nodemgr_update_pdrv(ne);
-       else
-               nodemgr_pause_ne(ne);
-
-       put_device(dev);
-}
-
-struct node_probe_parameter {
-       struct hpsb_host *host;
-       int generation;
-       bool probe_now;
-};
-
-static int node_probe(struct device *dev, void *data)
-{
-       struct node_probe_parameter *p = data;
-       struct node_entry *ne;
-
-       if (p->generation != get_hpsb_generation(p->host))
-               return -EAGAIN;
-
-       ne = container_of(dev, struct node_entry, node_dev);
-       if (ne->needs_probe == p->probe_now)
-               nodemgr_probe_ne(p->host, ne, p->generation);
-       return 0;
-}
-
-static int nodemgr_node_probe(struct hpsb_host *host, int generation)
-{
-       struct node_probe_parameter p;
-
-       p.host = host;
-       p.generation = generation;
-       /*
-        * Do some processing of the nodes we've probed. This pulls them
-        * into the sysfs layer if needed, and can result in processing of
-        * unit-directories, or just updating the node and it's
-        * unit-directories.
-        *
-        * Run updates before probes. Usually, updates are time-critical
-        * while probes are time-consuming.
-        *
-        * Meanwhile, another bus reset may have happened. In this case we
-        * skip everything here and let the next bus scan handle it.
-        * Otherwise we may prematurely remove nodes which are still there.
-        */
-       p.probe_now = false;
-       if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
-               return 0;
-
-       p.probe_now = true;
-       if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
-               return 0;
-       /*
-        * Now let's tell the bus to rescan our devices. This may seem
-        * like overhead, but the driver-model core will only scan a
-        * device for a driver when either the device is added, or when a
-        * new driver is added. A bus reset is a good reason to rescan
-        * devices that were there before.  For example, an sbp2 device
-        * may become available for login, if the host that held it was
-        * just removed.
-        */
-       if (bus_rescan_devices(&ieee1394_bus_type) != 0)
-               HPSB_DEBUG("bus_rescan_devices had an error");
-
-       return 1;
-}
-
-static int remove_nodes_in_limbo(struct device *dev, void *data)
-{
-       struct node_entry *ne;
-
-       if (dev->bus != &ieee1394_bus_type)
-               return 0;
-
-       ne = container_of(dev, struct node_entry, device);
-       if (ne->in_limbo)
-               nodemgr_remove_ne(ne);
-
-       return 0;
-}
-
-static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host)
-{
-       device_for_each_child(&host->device, NULL, remove_nodes_in_limbo);
-}
-
-static int nodemgr_send_resume_packet(struct hpsb_host *host)
-{
-       struct hpsb_packet *packet;
-       int error = -ENOMEM;
-
-       packet = hpsb_make_phypacket(host,
-                       EXTPHYPACKET_TYPE_RESUME |
-                       NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
-       if (packet) {
-               packet->no_waiter = 1;
-               packet->generation = get_hpsb_generation(host);
-               error = hpsb_send_packet(packet);
-       }
-       if (error)
-               HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
-                         host->id);
-       return error;
-}
-
-/* Perform a few high-level IRM responsibilities. */
-static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
-{
-       quadlet_t bc;
-
-       /* if irm_id == -1 then there is no IRM on this bus */
-       if (!host->is_irm || host->irm_id == (nodeid_t)-1)
-               return 1;
-
-       /* We are a 1394a-2000 compliant IRM. Set the validity bit. */
-       host->csr.broadcast_channel |= 0x40000000;
-
-       /* If there is no bus manager then we should set the root node's
-        * force_root bit to promote bus stability per the 1394
-        * spec. (8.4.2.6) */
-       if (host->busmgr_id == 0xffff && host->node_count > 1)
-       {
-               u16 root_node = host->node_count - 1;
-
-               /* get cycle master capability flag from root node */
-               if (host->is_cycmst ||
-                   (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
-                               (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
-                               &bc, sizeof(quadlet_t)) &&
-                    be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
-                       hpsb_send_phy_config(host, root_node, -1);
-               else {
-                       HPSB_DEBUG("The root node is not cycle master capable; "
-                                  "selecting a new root node and resetting...");
-
-                       if (cycles >= 5) {
-                               /* Oh screw it! Just leave the bus as it is */
-                               HPSB_DEBUG("Stopping reset loop for IRM sanity");
-                               return 1;
-                       }
-
-                       hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
-                       hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
-                       return 0;
-               }
-       }
-
-       /* Some devices suspend their ports while being connected to an inactive
-        * host adapter, i.e. if connected before the low-level driver is
-        * loaded.  They become visible either when physically unplugged and
-        * replugged, or when receiving a resume packet.  Send one once. */
-       if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
-               host->resume_packet_sent = 1;
-
-       return 1;
-}
-
-/* We need to ensure that if we are not the IRM, that the IRM node is capable of
- * everything we can do, otherwise issue a bus reset and try to become the IRM
- * ourselves. */
-static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles)
-{
-       quadlet_t bc;
-       int status;
-
-       if (hpsb_disable_irm || host->is_irm)
-               return 1;
-
-       status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
-                          get_hpsb_generation(host),
-                          (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
-                          &bc, sizeof(quadlet_t));
-
-       if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
-               /* The current irm node does not have a valid BROADCAST_CHANNEL
-                * register and we do, so reset the bus with force_root set */
-               HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
-
-               if (cycles >= 5) {
-                       /* Oh screw it! Just leave the bus as it is */
-                       HPSB_DEBUG("Stopping reset loop for IRM sanity");
-                       return 1;
-               }
-
-               hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
-               hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
-               return 0;
-       }
-
-       return 1;
-}
-
-static int nodemgr_host_thread(void *data)
-{
-       struct hpsb_host *host = data;
-       unsigned int g, generation = 0;
-       int i, reset_cycles = 0;
-
-       set_freezable();
-       /* Setup our device-model entries */
-       nodemgr_create_host_dev_files(host);
-
-       for (;;) {
-               /* Sleep until next bus reset */
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (get_hpsb_generation(host) == generation &&
-                   !kthread_should_stop())
-                       schedule();
-               __set_current_state(TASK_RUNNING);
-
-               /* Thread may have been woken up to freeze or to exit */
-               if (try_to_freeze())
-                       continue;
-               if (kthread_should_stop())
-                       goto exit;
-
-               /* Pause for 1/4 second in 1/16 second intervals,
-                * to make sure things settle down. */
-               g = get_hpsb_generation(host);
-               for (i = 0; i < 4 ; i++) {
-                       msleep_interruptible(63);
-                       try_to_freeze();
-                       if (kthread_should_stop())
-                               goto exit;
-
-                       /* Now get the generation in which the node ID's we collect
-                        * are valid.  During the bus scan we will use this generation
-                        * for the read transactions, so that if another reset occurs
-                        * during the scan the transactions will fail instead of
-                        * returning bogus data. */
-                       generation = get_hpsb_generation(host);
-
-                       /* If we get a reset before we are done waiting, then
-                        * start the waiting over again */
-                       if (generation != g)
-                               g = generation, i = 0;
-               }
-
-               if (!nodemgr_check_irm_capability(host, reset_cycles) ||
-                   !nodemgr_do_irm_duties(host, reset_cycles)) {
-                       reset_cycles++;
-                       continue;
-               }
-               reset_cycles = 0;
-
-               /* Scan our nodes to get the bus options and create node
-                * entries. This does not do the sysfs stuff, since that
-                * would trigger uevents and such, which is a bad idea at
-                * this point. */
-               nodemgr_node_scan(host, generation);
-
-               /* This actually does the full probe, with sysfs
-                * registration. */
-               if (!nodemgr_node_probe(host, generation))
-                       continue;
-
-               /* Update some of our sysfs symlinks */
-               nodemgr_update_host_dev_links(host);
-
-               /* Sleep 3 seconds */
-               for (i = 3000/200; i; i--) {
-                       msleep_interruptible(200);
-                       try_to_freeze();
-                       if (kthread_should_stop())
-                               goto exit;
-
-                       if (generation != get_hpsb_generation(host))
-                               break;
-               }
-               /* Remove nodes which are gone, unless a bus reset happened */
-               if (!i)
-                       nodemgr_remove_nodes_in_limbo(host);
-       }
-exit:
-       HPSB_VERBOSE("NodeMgr: Exiting thread");
-       return 0;
-}
-
-struct per_host_parameter {
-       void *data;
-       int (*cb)(struct hpsb_host *, void *);
-};
-
-static int per_host(struct device *dev, void *data)
-{
-       struct hpsb_host *host;
-       struct per_host_parameter *p = data;
-
-       host = container_of(dev, struct hpsb_host, host_dev);
-       return p->cb(host, p->data);
-}
-
-/**
- * nodemgr_for_each_host - call a function for each IEEE 1394 host
- * @data: an address to supply to the callback
- * @cb: function to call for each host
- *
- * Iterate the hosts, calling a given function with supplied data for each host.
- * If the callback fails on a host, i.e. if it returns a non-zero value, the
- * iteration is stopped.
- *
- * Return value: 0 on success, non-zero on failure (same as returned by last run
- * of the callback).
- */
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
-{
-       struct per_host_parameter p;
-
-       p.cb = cb;
-       p.data = data;
-       return class_for_each_device(&hpsb_host_class, NULL, &p, per_host);
-}
-
-/* The following two convenience functions use a struct node_entry
- * for addressing a node on the bus.  They are intended for use by any
- * process context, not just the nodemgr thread, so we need to be a
- * little careful when reading out the node ID and generation.  The
- * thing that can go wrong is that we get the node ID, then a bus
- * reset occurs, and then we read the generation.  The node ID is
- * possibly invalid, but the generation is current, and we end up
- * sending a packet to a the wrong node.
- *
- * The solution is to make sure we read the generation first, so that
- * if a reset occurs in the process, we end up with a stale generation
- * and the transactions will fail instead of silently using wrong node
- * ID's.
- */
-
-/**
- * hpsb_node_fill_packet - fill some destination information into a packet
- * @ne: destination node
- * @packet: packet to fill in
- *
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the node entry (host, node ID, bus generation number).
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
-{
-       packet->host = ne->host;
-       packet->generation = ne->generation;
-       smp_rmb();
-       packet->node_id = ne->nodeid;
-}
-
-int hpsb_node_write(struct node_entry *ne, u64 addr,
-                   quadlet_t *buffer, size_t length)
-{
-       unsigned int generation = ne->generation;
-
-       smp_rmb();
-       return hpsb_write(ne->host, ne->nodeid, generation,
-                         addr, buffer, length);
-}
-
-static void nodemgr_add_host(struct hpsb_host *host)
-{
-       struct host_info *hi;
-
-       hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
-       if (!hi) {
-               HPSB_ERR("NodeMgr: out of memory in add host");
-               return;
-       }
-       hi->host = host;
-       hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d",
-                                host->id);
-       if (IS_ERR(hi->thread)) {
-               HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
-               hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
-       }
-}
-
-static void nodemgr_host_reset(struct hpsb_host *host)
-{
-       struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
-       if (hi) {
-               HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
-               wake_up_process(hi->thread);
-       }
-}
-
-static void nodemgr_remove_host(struct hpsb_host *host)
-{
-       struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
-       if (hi) {
-               kthread_stop(hi->thread);
-               nodemgr_remove_host_dev(&host->device);
-       }
-}
-
-static struct hpsb_highlevel nodemgr_highlevel = {
-       .name =         "Node manager",
-       .add_host =     nodemgr_add_host,
-       .host_reset =   nodemgr_host_reset,
-       .remove_host =  nodemgr_remove_host,
-};
-
-int init_ieee1394_nodemgr(void)
-{
-       int error;
-
-       error = class_register(&nodemgr_ne_class);
-       if (error)
-               goto fail_ne;
-       error = class_register(&nodemgr_ud_class);
-       if (error)
-               goto fail_ud;
-       error = driver_register(&nodemgr_mid_layer_driver);
-       if (error)
-               goto fail_ml;
-       /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
-       nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
-
-       hpsb_register_highlevel(&nodemgr_highlevel);
-       return 0;
-
-fail_ml:
-       class_unregister(&nodemgr_ud_class);
-fail_ud:
-       class_unregister(&nodemgr_ne_class);
-fail_ne:
-       return error;
-}
-
-void cleanup_ieee1394_nodemgr(void)
-{
-       hpsb_unregister_highlevel(&nodemgr_highlevel);
-       driver_unregister(&nodemgr_mid_layer_driver);
-       class_unregister(&nodemgr_ud_class);
-       class_unregister(&nodemgr_ne_class);
-}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
deleted file mode 100644 (file)
index 749b271..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2000  Andreas E. Bombe
- *               2001  Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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 _IEEE1394_NODEMGR_H
-#define _IEEE1394_NODEMGR_H
-
-#include <linux/device.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-
-struct csr1212_csr;
-struct csr1212_keyval;
-struct hpsb_host;
-struct ieee1394_device_id;
-
-/* This is the start of a Node entry structure. It should be a stable API
- * for which to gather info from the Node Manager about devices attached
- * to the bus.  */
-struct bus_options {
-       u8      irmc;           /* Iso Resource Manager Capable */
-       u8      cmc;            /* Cycle Master Capable */
-       u8      isc;            /* Iso Capable */
-       u8      bmc;            /* Bus Master Capable */
-       u8      pmc;            /* Power Manager Capable (PNP spec) */
-       u8      cyc_clk_acc;    /* Cycle clock accuracy */
-       u8      max_rom;        /* Maximum block read supported in the CSR */
-       u8      generation;     /* Incremented when configrom changes */
-       u8      lnkspd;         /* Link speed */
-       u16     max_rec;        /* Maximum packet size node can receive */
-};
-
-#define UNIT_DIRECTORY_VENDOR_ID               0x01
-#define UNIT_DIRECTORY_MODEL_ID                        0x02
-#define UNIT_DIRECTORY_SPECIFIER_ID            0x04
-#define UNIT_DIRECTORY_VERSION                 0x08
-#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY       0x10
-#define UNIT_DIRECTORY_LUN_DIRECTORY           0x20
-#define UNIT_DIRECTORY_HAS_LUN                 0x40
-
-/*
- * A unit directory corresponds to a protocol supported by the
- * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
- * unit directory for each of these protocols.
- */
-struct unit_directory {
-       struct node_entry *ne;  /* The node which this directory belongs to */
-       octlet_t address;       /* Address of the unit directory on the node */
-       u8 flags;               /* Indicates which entries were read */
-
-       quadlet_t vendor_id;
-       struct csr1212_keyval *vendor_name_kv;
-
-       quadlet_t model_id;
-       struct csr1212_keyval *model_name_kv;
-       quadlet_t specifier_id;
-       quadlet_t version;
-       quadlet_t directory_id;
-
-       unsigned int id;
-
-       int ignore_driver;
-
-       int length;             /* Number of quadlets */
-
-       struct device device;
-       struct device unit_dev;
-
-       struct csr1212_keyval *ud_kv;
-       u32 lun;                /* logical unit number immediate value */
-};
-
-struct node_entry {
-       u64 guid;                       /* GUID of this node */
-       u32 guid_vendor_id;             /* Top 24bits of guid */
-
-       struct hpsb_host *host;         /* Host this node is attached to */
-       nodeid_t nodeid;                /* NodeID */
-       struct bus_options busopt;      /* Bus Options */
-       bool needs_probe;
-       unsigned int generation;        /* Synced with hpsb generation */
-
-       /* The following is read from the config rom */
-       u32 vendor_id;
-       struct csr1212_keyval *vendor_name_kv;
-
-       u32 capabilities;
-
-       struct device device;
-       struct device node_dev;
-
-       /* Means this node is not attached anymore */
-       bool in_limbo;
-
-       struct csr1212_csr *csr;
-};
-
-struct hpsb_protocol_driver {
-       /* The name of the driver, e.g. SBP2 or IP1394 */
-       const char *name;
-
-       /*
-        * The device id table describing the protocols and/or devices
-        * supported by this driver.  This is used by the nodemgr to
-        * decide if a driver could support a given node, but the
-        * probe function below can implement further protocol
-        * dependent or vendor dependent checking.
-        */
-       const struct ieee1394_device_id *id_table;
-
-       /*
-        * The update function is called when the node has just
-        * survived a bus reset, i.e. it is still present on the bus.
-        * However, it may be necessary to reestablish the connection
-        * or login into the node again, depending on the protocol. If the
-        * probe fails (returns non-zero), we unbind the driver from this
-        * device.
-        */
-       int (*update)(struct unit_directory *ud);
-
-       /* Our LDM structure */
-       struct device_driver driver;
-};
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
-static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
-{
-       return __hpsb_register_protocol(driver, THIS_MODULE);
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
-
-static inline int hpsb_node_entry_valid(struct node_entry *ne)
-{
-       return ne->generation == get_hpsb_generation(ne->host);
-}
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
-int hpsb_node_write(struct node_entry *ne, u64 addr,
-                   quadlet_t *buffer, size_t length);
-static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
-                                quadlet_t *buffer, size_t length)
-{
-       unsigned int g = ne->generation;
-
-       smp_rmb();
-       return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
-}
-static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
-                                quadlet_t *buffer, quadlet_t arg)
-{
-       unsigned int g = ne->generation;
-
-       smp_rmb();
-       return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
-}
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
-
-int init_ieee1394_nodemgr(void);
-void cleanup_ieee1394_nodemgr(void);
-
-/* The template for a host device */
-extern struct device nodemgr_dev_template_host;
-
-/* Bus attributes we export */
-extern struct bus_attribute *const fw_bus_attrs[];
-
-#endif /* _IEEE1394_NODEMGR_H */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
deleted file mode 100644 (file)
index 5081502..0000000
+++ /dev/null
@@ -1,3590 +0,0 @@
-/*
- * ohci1394.c - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Gord Peters <GordPeters@smarttech.com>
- *              2001      Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- */
-
-/*
- * Things known to be working:
- * . Async Request Transmit
- * . Async Response Receive
- * . Async Request Receive
- * . Async Response Transmit
- * . Iso Receive
- * . DMA mmap for iso receive
- * . Config ROM generation
- *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * . Async Stream Packets Transmit (Receive done via Iso interface)
- *
- * Things not implemented:
- * . DMA error recovery
- *
- * Known bugs:
- * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
- *   added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk
- */
-
-/*
- * Acknowledgments:
- *
- * Adam J Richter <adam@yggdrasil.com>
- *  . Use of pci_class to find device
- *
- * Emilie Chung        <emilie.chung@axis.com>
- *  . Tip on Async Request Filter
- *
- * Pascal Drolet <pascal.drolet@informission.ca>
- *  . Various tips for optimization and functionnalities
- *
- * Robert Ficklin <rficklin@westengineering.com>
- *  . Loop in irq_handler
- *
- * James Goodwin <jamesg@Filanet.com>
- *  . Various tips on initialization, self-id reception, etc.
- *
- * Albrecht Dress <ad@mpifr-bonn.mpg.de>
- *  . Apple PowerBook detection
- *
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- *  . Reset the board properly before leaving + misc cleanups
- *
- * Leon van Stuivenberg <leonvs@iae.nl>
- *  . Bug fixes
- *
- * Ben Collins <bcollins@debian.org>
- *  . Working big-endian support
- *  . Updated to 2.4.x module scheme (PCI aswell)
- *  . Config ROM generation
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *  . Reworked code for initiating bus resets
- *    (long, short, with or without hold-off)
- *
- * Nandu Santhi <contactnandu@users.sourceforge.net>
- *  . Added support for nVidia nForce2 onboard Firewire chipset
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/irq.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "dma.h"
-#include "iso.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ohci1394.h"
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define OHCI1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef OHCI1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
-
-/* print card specific information */
-#define PRINT(level, fmt, args...) \
-printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-
-/* Module Parameters */
-static int phys_dma = 1;
-module_param(phys_dma, int, 0444);
-MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1).");
-
-static void dma_trm_tasklet(unsigned long data);
-static void dma_trm_reset(struct dma_trm_ctx *d);
-
-static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
-                            enum context_type type, int ctx, int num_desc,
-                            int buf_size, int split_buf_size, int context_base);
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
-
-static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
-                            enum context_type type, int ctx, int num_desc,
-                            int context_base);
-
-static void ohci1394_pci_remove(struct pci_dev *pdev);
-
-#ifndef __LITTLE_ENDIAN
-static const size_t hdr_sizes[] = {
-       3,      /* TCODE_WRITEQ */
-       4,      /* TCODE_WRITEB */
-       3,      /* TCODE_WRITE_RESPONSE */
-       0,      /* reserved */
-       3,      /* TCODE_READQ */
-       4,      /* TCODE_READB */
-       3,      /* TCODE_READQ_RESPONSE */
-       4,      /* TCODE_READB_RESPONSE */
-       1,      /* TCODE_CYCLE_START */
-       4,      /* TCODE_LOCK_REQUEST */
-       2,      /* TCODE_ISO_DATA */
-       4,      /* TCODE_LOCK_RESPONSE */
-               /* rest is reserved or link-internal */
-};
-
-static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
-{
-       size_t size;
-
-       if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
-               return;
-
-       size = hdr_sizes[tcode];
-       while (size--)
-               data[size] = le32_to_cpu(data[size]);
-}
-#else
-#define header_le32_to_cpu(w,x) do {} while (0)
-#endif /* !LITTLE_ENDIAN */
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
-       int i;
-       unsigned long flags;
-       quadlet_t r;
-
-       spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
-       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
-                       break;
-
-               mdelay(1);
-       }
-
-       r = reg_read(ohci, OHCI1394_PhyControl);
-
-       if (i >= OHCI_LOOP_COUNT)
-               PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",
-                      r, r & 0x80000000, i);
-
-       spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
-       return (r & 0x00ff0000) >> 16;
-}
-
-static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-       int i;
-       unsigned long flags;
-       u32 r = 0;
-
-       spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
-       reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               r = reg_read(ohci, OHCI1394_PhyControl);
-               if (!(r & 0x00004000))
-                       break;
-
-               mdelay(1);
-       }
-
-       if (i == OHCI_LOOP_COUNT)
-               PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",
-                      r, r & 0x00004000, i);
-
-       spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
-       return;
-}
-
-/* Or's our value into the current value */
-static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-       u8 old;
-
-       old = get_phy_reg (ohci, addr);
-       old |= data;
-       set_phy_reg (ohci, addr, old);
-
-       return;
-}
-
-static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
-                               int phyid, int isroot)
-{
-       quadlet_t *q = ohci->selfid_buf_cpu;
-       quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
-       size_t size;
-       quadlet_t q0, q1;
-
-       /* Check status of self-id reception */
-
-       if (ohci->selfid_swap)
-               q0 = le32_to_cpu(q[0]);
-       else
-               q0 = q[0];
-
-       if ((self_id_count & 0x80000000) ||
-           ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
-               PRINT(KERN_ERR,
-                     "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
-                     self_id_count, q0, ohci->self_id_errors);
-
-               /* Tip by James Goodwin <jamesg@Filanet.com>:
-                * We had an error, generate another bus reset in response.  */
-               if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
-                       set_phy_reg_mask (ohci, 1, 0x40);
-                       ohci->self_id_errors++;
-               } else {
-                       PRINT(KERN_ERR,
-                             "Too many errors on SelfID error reception, giving up!");
-               }
-               return;
-       }
-
-       /* SelfID Ok, reset error counter. */
-       ohci->self_id_errors = 0;
-
-       size = ((self_id_count & 0x00001FFC) >> 2) - 1;
-       q++;
-
-       while (size > 0) {
-               if (ohci->selfid_swap) {
-                       q0 = le32_to_cpu(q[0]);
-                       q1 = le32_to_cpu(q[1]);
-               } else {
-                       q0 = q[0];
-                       q1 = q[1];
-               }
-
-               if (q0 == ~q1) {
-                       DBGMSG ("SelfID packet 0x%x received", q0);
-                       hpsb_selfid_received(host, cpu_to_be32(q0));
-                       if (((q0 & 0x3f000000) >> 24) == phyid)
-                               DBGMSG ("SelfID for this node is 0x%08x", q0);
-               } else {
-                       PRINT(KERN_ERR,
-                             "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
-               }
-               q += 2;
-               size -= 2;
-       }
-
-       DBGMSG("SelfID complete");
-
-       return;
-}
-
-static void ohci_soft_reset(struct ti_ohci *ohci) {
-       int i;
-
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
-                       break;
-               mdelay(1);
-       }
-       DBGMSG ("Soft reset finished");
-}
-
-
-/* Generate the dma receive prgs and start the context */
-static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
-{
-       struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-       int i;
-
-       ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-       for (i=0; i<d->num_desc; i++) {
-               u32 c;
-
-               c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
-               if (generate_irq)
-                       c |= DMA_CTL_IRQ;
-
-               d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
-
-               /* End of descriptor list? */
-               if (i + 1 < d->num_desc) {
-                       d->prg_cpu[i]->branchAddress =
-                               cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
-               } else {
-                       d->prg_cpu[i]->branchAddress =
-                               cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
-               }
-
-               d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
-               d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
-       }
-
-        d->buf_ind = 0;
-        d->buf_offset = 0;
-
-       if (d->type == DMA_CTX_ISO) {
-               /* Clear contextControl */
-               reg_write(ohci, d->ctrlClear, 0xffffffff);
-
-               /* Set bufferFill, isochHeader, multichannel for IR context */
-               reg_write(ohci, d->ctrlSet, 0xd0000000);
-
-               /* Set the context match register to match on all tags */
-               reg_write(ohci, d->ctxtMatch, 0xf0000000);
-
-               /* Clear the multi channel mask high and low registers */
-               reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
-               /* Set up isoRecvIntMask to generate interrupts */
-               reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
-       }
-
-       /* Tell the controller where the first AR program is */
-       reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
-
-       /* Run context */
-       reg_write(ohci, d->ctrlSet, 0x00008000);
-
-       DBGMSG("Receive DMA ctx=%d initialized", d->ctx);
-}
-
-/* Initialize the dma transmit context */
-static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
-{
-       struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-
-       /* Stop the context */
-       ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-        d->prg_ind = 0;
-       d->sent_ind = 0;
-       d->free_prgs = d->num_desc;
-        d->branchAddrPtr = NULL;
-       INIT_LIST_HEAD(&d->fifo_list);
-       INIT_LIST_HEAD(&d->pending_list);
-
-       if (d->type == DMA_CTX_ISO) {
-               /* enable interrupts */
-               reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
-       }
-
-       DBGMSG("Transmit DMA ctx=%d initialized", d->ctx);
-}
-
-/* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
-{
-       u32 tmp;
-
-       reg_write(ohci, reg, 0xffffffff);
-       tmp = reg_read(ohci, reg);
-
-       DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
-
-       /* Count the number of contexts */
-       return hweight32(tmp);
-}
-
-/* Global initialization */
-static void ohci_initialize(struct ti_ohci *ohci)
-{
-       quadlet_t buf;
-       int num_ports, i;
-
-       spin_lock_init(&ohci->phy_reg_lock);
-
-       /* Put some defaults to these undefined bus options */
-       buf = reg_read(ohci, OHCI1394_BusOptions);
-       buf |=  0x60000000; /* Enable CMC and ISC */
-       if (hpsb_disable_irm)
-               buf &= ~0x80000000;
-       else
-               buf |=  0x80000000; /* Enable IRMC */
-       buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
-       buf &= ~0x18000000; /* Disable PMC and BMC */
-       reg_write(ohci, OHCI1394_BusOptions, buf);
-
-       /* Set the bus number */
-       reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
-       /* Enable posted writes */
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
-
-       /* Clear link control register */
-       reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-       /* Enable cycle timer and cycle master and set the IRM
-        * contender bit in our self ID packets if appropriate. */
-       reg_write(ohci, OHCI1394_LinkControlSet,
-                 OHCI1394_LinkControl_CycleTimerEnable |
-                 OHCI1394_LinkControl_CycleMaster);
-       i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
-       if (hpsb_disable_irm)
-               i &= ~PHY_04_CONTENDER;
-       else
-               i |= PHY_04_CONTENDER;
-       set_phy_reg(ohci, 4, i);
-
-       /* Set up self-id dma buffer */
-       reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
-
-       /* enable self-id */
-       reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
-
-       /* Set the Config ROM mapping register */
-       reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
-
-       /* Now get our max packet size */
-       ohci->max_packet_size =
-               1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-               
-       /* Clear the interrupt mask */
-       reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
-       /* Clear the interrupt mask */
-       reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
-       /* Initialize AR dma */
-       initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
-       initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
-
-       /* Initialize AT dma */
-       initialize_dma_trm_ctx(&ohci->at_req_context);
-       initialize_dma_trm_ctx(&ohci->at_resp_context);
-       
-       /* Accept AR requests from all nodes */
-       reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
-
-       /* Set the address range of the physical response unit.
-        * Most controllers do not implement it as a writable register though.
-        * They will keep a hardwired offset of 0x00010000 and show 0x0 as
-        * register content.
-        * To actually enable physical responses is the job of our interrupt
-        * handler which programs the physical request filter. */
-       reg_write(ohci, OHCI1394_PhyUpperBound,
-                 OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16);
-
-       DBGMSG("physUpperBoundOffset=%08x",
-              reg_read(ohci, OHCI1394_PhyUpperBound));
-
-       /* Specify AT retries */
-       reg_write(ohci, OHCI1394_ATRetries,
-                 OHCI1394_MAX_AT_REQ_RETRIES |
-                 (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
-                 (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
-       /* We don't want hardware swapping */
-       reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
-       /* Enable interrupts */
-       reg_write(ohci, OHCI1394_IntMaskSet,
-                 OHCI1394_unrecoverableError |
-                 OHCI1394_masterIntEnable |
-                 OHCI1394_busReset |
-                 OHCI1394_selfIDComplete |
-                 OHCI1394_RSPkt |
-                 OHCI1394_RQPkt |
-                 OHCI1394_respTxComplete |
-                 OHCI1394_reqTxComplete |
-                 OHCI1394_isochRx |
-                 OHCI1394_isochTx |
-                 OHCI1394_postedWriteErr |
-                 OHCI1394_cycleTooLong |
-                 OHCI1394_cycleInconsistent);
-
-       /* Enable link */
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
-       buf = reg_read(ohci, OHCI1394_Version);
-       PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
-             "MMIO=[%llx-%llx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
-             ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
-             ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
-             (unsigned long long)pci_resource_start(ohci->dev, 0),
-             (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
-             ohci->max_packet_size,
-             ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
-
-       /* Check all of our ports to make sure that if anything is
-        * connected, we enable that port. */
-       num_ports = get_phy_reg(ohci, 2) & 0xf;
-       for (i = 0; i < num_ports; i++) {
-               unsigned int status;
-
-               set_phy_reg(ohci, 7, i);
-               status = get_phy_reg(ohci, 8);
-
-               if (status & 0x20)
-                       set_phy_reg(ohci, 8, status & ~1);
-       }
-
-        /* Serial EEPROM Sanity check. */
-        if ((ohci->max_packet_size < 512) ||
-           (ohci->max_packet_size > 4096)) {
-               /* Serial EEPROM contents are suspect, set a sane max packet
-                * size and print the raw contents for bug reports if verbose
-                * debug is enabled. */
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-               int i;
-#endif
-
-               PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
-                      "attempting to set max_packet_size to 512 bytes");
-               reg_write(ohci, OHCI1394_BusOptions,
-                         (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
-               ohci->max_packet_size = 512;
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-               PRINT(KERN_DEBUG, "    EEPROM Present: %d",
-                     (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
-               reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
-
-               for (i = 0;
-                    ((i < 1000) &&
-                     (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
-                       udelay(10);
-
-               for (i = 0; i < 0x20; i++) {
-                       reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
-                       PRINT(KERN_DEBUG, "    EEPROM %02x: %02x", i,
-                             (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
-               }
-#endif
-       }
-}
-
-/*
- * Insert a packet in the DMA fifo and generate the DMA prg
- * FIXME: rewrite the program in order to accept packets crossing
- *        page boundaries.
- *        check also that a single dma descriptor doesn't cross a
- *        page boundary.
- */
-static void insert_packet(struct ti_ohci *ohci,
-                         struct dma_trm_ctx *d, struct hpsb_packet *packet)
-{
-       u32 cycleTimer;
-       int idx = d->prg_ind;
-
-       DBGMSG("Inserting packet for node " NODE_BUS_FMT
-              ", tlabel=%d, tcode=0x%x, speed=%d",
-              NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
-              packet->tcode, packet->speed_code);
-
-       d->prg_cpu[idx]->begin.address = 0;
-       d->prg_cpu[idx]->begin.branchAddress = 0;
-
-       if (d->type == DMA_CTX_ASYNC_RESP) {
-               /*
-                * For response packets, we need to put a timeout value in
-                * the 16 lower bits of the status... let's try 1 sec timeout
-                */
-               cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-               d->prg_cpu[idx]->begin.status = cpu_to_le32(
-                       (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
-                       ((cycleTimer&0x01fff000)>>12));
-
-               DBGMSG("cycleTimer: %08x timeStamp: %08x",
-                      cycleTimer, d->prg_cpu[idx]->begin.status);
-       } else 
-               d->prg_cpu[idx]->begin.status = 0;
-
-        if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
-
-                if (packet->type == hpsb_raw) {
-                       d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
-                        d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
-                        d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
-                } else {
-                        d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
-                                (packet->header[0] & 0xFFFF);
-
-                       if (packet->tcode == TCODE_ISO_DATA) {
-                               /* Sending an async stream packet */
-                               d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-                       } else {
-                               /* Sending a normal async request or response */
-                               d->prg_cpu[idx]->data[1] =
-                                       (packet->header[1] & 0xFFFF) |
-                                       (packet->header[0] & 0xFFFF0000);
-                               d->prg_cpu[idx]->data[2] = packet->header[2];
-                               d->prg_cpu[idx]->data[3] = packet->header[3];
-                       }
-                       header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-                }
-
-                if (packet->data_size) { /* block transmit */
-                       if (packet->tcode == TCODE_STREAM_DATA){
-                               d->prg_cpu[idx]->begin.control =
-                                       cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-                                                   DMA_CTL_IMMEDIATE | 0x8);
-                       } else {
-                               d->prg_cpu[idx]->begin.control =
-                                       cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-                                                   DMA_CTL_IMMEDIATE | 0x10);
-                       }
-                        d->prg_cpu[idx]->end.control =
-                                cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-                                           DMA_CTL_IRQ |
-                                           DMA_CTL_BRANCH |
-                                           packet->data_size);
-                        /*
-                         * Check that the packet data buffer
-                         * does not cross a page boundary.
-                        *
-                        * XXX Fix this some day. eth1394 seems to trigger
-                        * it, but ignoring it doesn't seem to cause a
-                        * problem.
-                         */
-#if 0
-                        if (cross_bound((unsigned long)packet->data,
-                                        packet->data_size)>0) {
-                                /* FIXME: do something about it */
-                                PRINT(KERN_ERR,
-                                      "%s: packet data addr: %p size %Zd bytes "
-                                     "cross page boundary", __func__,
-                                      packet->data, packet->data_size);
-                        }
-#endif
-                        d->prg_cpu[idx]->end.address = cpu_to_le32(
-                                pci_map_single(ohci->dev, packet->data,
-                                               packet->data_size,
-                                               PCI_DMA_TODEVICE));
-
-                        d->prg_cpu[idx]->end.branchAddress = 0;
-                        d->prg_cpu[idx]->end.status = 0;
-                        if (d->branchAddrPtr)
-                                *(d->branchAddrPtr) =
-                                       cpu_to_le32(d->prg_bus[idx] | 0x3);
-                        d->branchAddrPtr =
-                                &(d->prg_cpu[idx]->end.branchAddress);
-                } else { /* quadlet transmit */
-                        if (packet->type == hpsb_raw)
-                                d->prg_cpu[idx]->begin.control =
-                                       cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-                                                   DMA_CTL_IMMEDIATE |
-                                                   DMA_CTL_IRQ |
-                                                   DMA_CTL_BRANCH |
-                                                   (packet->header_size + 4));
-                        else
-                                d->prg_cpu[idx]->begin.control =
-                                       cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-                                                   DMA_CTL_IMMEDIATE |
-                                                   DMA_CTL_IRQ |
-                                                   DMA_CTL_BRANCH |
-                                                   packet->header_size);
-
-                        if (d->branchAddrPtr)
-                                *(d->branchAddrPtr) =
-                                       cpu_to_le32(d->prg_bus[idx] | 0x2);
-                        d->branchAddrPtr =
-                                &(d->prg_cpu[idx]->begin.branchAddress);
-                }
-
-        } else { /* iso packet */
-                d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
-                        (packet->header[0] & 0xFFFF);
-                d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-               header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-
-                d->prg_cpu[idx]->begin.control =
-                       cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-                                   DMA_CTL_IMMEDIATE | 0x8);
-                d->prg_cpu[idx]->end.control =
-                       cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-                                   DMA_CTL_UPDATE |
-                                   DMA_CTL_IRQ |
-                                   DMA_CTL_BRANCH |
-                                   packet->data_size);
-                d->prg_cpu[idx]->end.address = cpu_to_le32(
-                               pci_map_single(ohci->dev, packet->data,
-                               packet->data_size, PCI_DMA_TODEVICE));
-
-                d->prg_cpu[idx]->end.branchAddress = 0;
-                d->prg_cpu[idx]->end.status = 0;
-                DBGMSG("Iso xmit context info: header[%08x %08x]\n"
-                       "                       begin=%08x %08x %08x %08x\n"
-                       "                             %08x %08x %08x %08x\n"
-                       "                       end  =%08x %08x %08x %08x",
-                       d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
-                       d->prg_cpu[idx]->begin.control,
-                       d->prg_cpu[idx]->begin.address,
-                       d->prg_cpu[idx]->begin.branchAddress,
-                       d->prg_cpu[idx]->begin.status,
-                       d->prg_cpu[idx]->data[0],
-                       d->prg_cpu[idx]->data[1],
-                       d->prg_cpu[idx]->data[2],
-                       d->prg_cpu[idx]->data[3],
-                       d->prg_cpu[idx]->end.control,
-                       d->prg_cpu[idx]->end.address,
-                       d->prg_cpu[idx]->end.branchAddress,
-                       d->prg_cpu[idx]->end.status);
-                if (d->branchAddrPtr)
-                       *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
-                d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
-        }
-       d->free_prgs--;
-
-       /* queue the packet in the appropriate context queue */
-       list_add_tail(&packet->driver_list, &d->fifo_list);
-       d->prg_ind = (d->prg_ind + 1) % d->num_desc;
-}
-
-/*
- * This function fills the FIFO with the (eventual) pending packets
- * and runs or wakes up the DMA prg if necessary.
- *
- * The function MUST be called with the d->lock held.
- */
-static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
-{
-       struct hpsb_packet *packet, *ptmp;
-       int idx = d->prg_ind;
-       int z = 0;
-
-       /* insert the packets into the dma fifo */
-       list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
-               if (!d->free_prgs)
-                       break;
-
-               /* For the first packet only */
-               if (!z)
-                       z = (packet->data_size) ? 3 : 2;
-
-               /* Insert the packet */
-               list_del_init(&packet->driver_list);
-               insert_packet(ohci, d, packet);
-       }
-
-       /* Nothing must have been done, either no free_prgs or no packets */
-       if (z == 0)
-               return;
-
-       /* Is the context running ? (should be unless it is
-          the first packet to be sent in this context) */
-       if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
-               u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-
-               DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
-               reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
-
-               /* Check that the node id is valid, and not 63 */
-               if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
-                       PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
-               else
-                       reg_write(ohci, d->ctrlSet, 0x8000);
-       } else {
-               /* Wake up the dma context if necessary */
-               if (!(reg_read(ohci, d->ctrlSet) & 0x400))
-                       DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
-
-               /* do this always, to avoid race condition */
-               reg_write(ohci, d->ctrlSet, 0x1000);
-       }
-
-       return;
-}
-
-/* Transmission of an async or iso packet */
-static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
-       struct ti_ohci *ohci = host->hostdata;
-       struct dma_trm_ctx *d;
-       unsigned long flags;
-
-       if (packet->data_size > ohci->max_packet_size) {
-               PRINT(KERN_ERR,
-                     "Transmit packet size %Zd is too big",
-                     packet->data_size);
-               return -EOVERFLOW;
-       }
-
-       if (packet->type == hpsb_raw)
-               d = &ohci->at_req_context;
-       else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
-               d = &ohci->at_resp_context;
-       else
-               d = &ohci->at_req_context;
-
-       spin_lock_irqsave(&d->lock,flags);
-
-       list_add_tail(&packet->driver_list, &d->pending_list);
-
-       dma_trm_flush(ohci, d);
-
-       spin_unlock_irqrestore(&d->lock,flags);
-
-       return 0;
-}
-
-static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
-       struct ti_ohci *ohci = host->hostdata;
-       int retval = 0, phy_reg;
-
-       switch (cmd) {
-       case RESET_BUS:
-               switch (arg) {
-               case SHORT_RESET:
-                       phy_reg = get_phy_reg(ohci, 5);
-                       phy_reg |= 0x40;
-                       set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-                       break;
-               case LONG_RESET:
-                       phy_reg = get_phy_reg(ohci, 1);
-                       phy_reg |= 0x40;
-                       set_phy_reg(ohci, 1, phy_reg); /* set IBR */
-                       break;
-               case SHORT_RESET_NO_FORCE_ROOT:
-                       phy_reg = get_phy_reg(ohci, 1);
-                       if (phy_reg & 0x80) {
-                               phy_reg &= ~0x80;
-                               set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
-                       }
-
-                       phy_reg = get_phy_reg(ohci, 5);
-                       phy_reg |= 0x40;
-                       set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-                       break;
-               case LONG_RESET_NO_FORCE_ROOT:
-                       phy_reg = get_phy_reg(ohci, 1);
-                       phy_reg &= ~0x80;
-                       phy_reg |= 0x40;
-                       set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
-                       break;
-               case SHORT_RESET_FORCE_ROOT:
-                       phy_reg = get_phy_reg(ohci, 1);
-                       if (!(phy_reg & 0x80)) {
-                               phy_reg |= 0x80;
-                               set_phy_reg(ohci, 1, phy_reg); /* set RHB */
-                       }
-
-                       phy_reg = get_phy_reg(ohci, 5);
-                       phy_reg |= 0x40;
-                       set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-                       break;
-               case LONG_RESET_FORCE_ROOT:
-                       phy_reg = get_phy_reg(ohci, 1);
-                       phy_reg |= 0xc0;
-                       set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
-                       break;
-               default:
-                       retval = -1;
-               }
-               break;
-
-       case GET_CYCLE_COUNTER:
-               retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-               break;
-
-       case SET_CYCLE_COUNTER:
-               reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
-               break;
-
-       case SET_BUS_ID:
-               PRINT(KERN_ERR, "devctl command SET_BUS_ID err");
-               break;
-
-       case ACT_CYCLE_MASTER:
-               if (arg) {
-                       /* check if we are root and other nodes are present */
-                       u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-                       if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
-                               /*
-                                * enable cycleTimer, cycleMaster
-                                */
-                               DBGMSG("Cycle master enabled");
-                               reg_write(ohci, OHCI1394_LinkControlSet,
-                                         OHCI1394_LinkControl_CycleTimerEnable |
-                                         OHCI1394_LinkControl_CycleMaster);
-                       }
-               } else {
-                       /* disable cycleTimer, cycleMaster, cycleSource */
-                       reg_write(ohci, OHCI1394_LinkControlClear,
-                                 OHCI1394_LinkControl_CycleTimerEnable |
-                                 OHCI1394_LinkControl_CycleMaster |
-                                 OHCI1394_LinkControl_CycleSource);
-               }
-               break;
-
-       case CANCEL_REQUESTS:
-               DBGMSG("Cancel request received");
-               dma_trm_reset(&ohci->at_req_context);
-               dma_trm_reset(&ohci->at_resp_context);
-               break;
-
-       default:
-               PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
-                       cmd);
-               break;
-       }
-       return retval;
-}
-
-/***********************************
- * rawiso ISO reception            *
- ***********************************/
-
-/*
-  We use either buffer-fill or packet-per-buffer DMA mode. The DMA
-  buffer is split into "blocks" (regions described by one DMA
-  descriptor). Each block must be one page or less in size, and
-  must not cross a page boundary.
-
-  There is one little wrinkle with buffer-fill mode: a packet that
-  starts in the final block may wrap around into the first block. But
-  the user API expects all packets to be contiguous. Our solution is
-  to keep the very last page of the DMA buffer in reserve - if a
-  packet spans the gap, we copy its tail into this page.
-*/
-
-struct ohci_iso_recv {
-       struct ti_ohci *ohci;
-
-       struct ohci1394_iso_tasklet task;
-       int task_active;
-
-       enum { BUFFER_FILL_MODE = 0,
-              PACKET_PER_BUFFER_MODE = 1 } dma_mode;
-
-       /* memory and PCI mapping for the DMA descriptors */
-       struct dma_prog_region prog;
-       struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
-
-       /* how many DMA blocks fit in the buffer */
-       unsigned int nblocks;
-
-       /* stride of DMA blocks */
-       unsigned int buf_stride;
-
-       /* number of blocks to batch between interrupts */
-       int block_irq_interval;
-
-       /* block that DMA will finish next */
-       int block_dma;
-
-       /* (buffer-fill only) block that the reader will release next */
-       int block_reader;
-
-       /* (buffer-fill only) bytes of buffer the reader has released,
-          less than one block */
-       int released_bytes;
-
-       /* (buffer-fill only) buffer offset at which the next packet will appear */
-       int dma_offset;
-
-       /* OHCI DMA context control registers */
-       u32 ContextControlSet;
-       u32 ContextControlClear;
-       u32 CommandPtr;
-       u32 ContextMatch;
-};
-
-static void ohci_iso_recv_task(unsigned long data);
-static void ohci_iso_recv_stop(struct hpsb_iso *iso);
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
-static int  ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
-static void ohci_iso_recv_program(struct hpsb_iso *iso);
-
-static int ohci_iso_recv_init(struct hpsb_iso *iso)
-{
-       struct ti_ohci *ohci = iso->host->hostdata;
-       struct ohci_iso_recv *recv;
-       int ctx;
-       int ret = -ENOMEM;
-
-       recv = kmalloc(sizeof(*recv), GFP_KERNEL);
-       if (!recv)
-               return -ENOMEM;
-
-       iso->hostdata = recv;
-       recv->ohci = ohci;
-       recv->task_active = 0;
-       dma_prog_region_init(&recv->prog);
-       recv->block = NULL;
-
-       /* use buffer-fill mode, unless irq_interval is 1
-          (note: multichannel requires buffer-fill) */
-
-       if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) ||
-            iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) {
-               recv->dma_mode = PACKET_PER_BUFFER_MODE;
-       } else {
-               recv->dma_mode = BUFFER_FILL_MODE;
-       }
-
-       /* set nblocks, buf_stride, block_irq_interval */
-
-       if (recv->dma_mode == BUFFER_FILL_MODE) {
-               recv->buf_stride = PAGE_SIZE;
-
-               /* one block per page of data in the DMA buffer, minus the final guard page */
-               recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
-               if (recv->nblocks < 3) {
-                       DBGMSG("ohci_iso_recv_init: DMA buffer too small");
-                       goto err;
-               }
-
-               /* iso->irq_interval is in packets - translate that to blocks */
-               if (iso->irq_interval == 1)
-                       recv->block_irq_interval = 1;
-               else
-                       recv->block_irq_interval = iso->irq_interval *
-                                                       ((recv->nblocks+1)/iso->buf_packets);
-               if (recv->block_irq_interval*4 > recv->nblocks)
-                       recv->block_irq_interval = recv->nblocks/4;
-               if (recv->block_irq_interval < 1)
-                       recv->block_irq_interval = 1;
-
-       } else {
-               int max_packet_size;
-
-               recv->nblocks = iso->buf_packets;
-               recv->block_irq_interval = iso->irq_interval;
-               if (recv->block_irq_interval * 4 > iso->buf_packets)
-                       recv->block_irq_interval = iso->buf_packets / 4;
-               if (recv->block_irq_interval < 1)
-                       recv->block_irq_interval = 1;
-
-               /* choose a buffer stride */
-               /* must be a power of 2, and <= PAGE_SIZE */
-
-               max_packet_size = iso->buf_size / iso->buf_packets;
-
-               for (recv->buf_stride = 8; recv->buf_stride < max_packet_size;
-                   recv->buf_stride *= 2);
-
-               if (recv->buf_stride*iso->buf_packets > iso->buf_size ||
-                  recv->buf_stride > PAGE_SIZE) {
-                       /* this shouldn't happen, but anyway... */
-                       DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride");
-                       goto err;
-               }
-       }
-
-       recv->block_reader = 0;
-       recv->released_bytes = 0;
-       recv->block_dma = 0;
-       recv->dma_offset = 0;
-
-       /* size of DMA program = one descriptor per block */
-       if (dma_prog_region_alloc(&recv->prog,
-                                sizeof(struct dma_cmd) * recv->nblocks,
-                                recv->ohci->dev))
-               goto err;
-
-       recv->block = (struct dma_cmd*) recv->prog.kvirt;
-
-       ohci1394_init_iso_tasklet(&recv->task,
-                                 iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
-                                                      OHCI_ISO_RECEIVE,
-                                 ohci_iso_recv_task, (unsigned long) iso);
-
-       if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
-               ret = -EBUSY;
-               goto err;
-       }
-
-       recv->task_active = 1;
-
-       /* recv context registers are spaced 32 bytes apart */
-       ctx = recv->task.context;
-       recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
-       recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
-       recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
-       recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
-
-       if (iso->channel == -1) {
-               /* clear multi-channel selection mask */
-               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
-               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
-       }
-
-       /* write the DMA program */
-       ohci_iso_recv_program(iso);
-
-       DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
-              " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
-              recv->dma_mode == BUFFER_FILL_MODE ?
-              "buffer-fill" : "packet-per-buffer",
-              iso->buf_size/PAGE_SIZE, iso->buf_size,
-              recv->nblocks, recv->buf_stride, recv->block_irq_interval);
-
-       return 0;
-
-err:
-       ohci_iso_recv_shutdown(iso);
-       return ret;
-}
-
-static void ohci_iso_recv_stop(struct hpsb_iso *iso)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-
-       /* disable interrupts */
-       reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
-
-       /* halt DMA */
-       ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
-}
-
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-
-       if (recv->task_active) {
-               ohci_iso_recv_stop(iso);
-               ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
-               recv->task_active = 0;
-       }
-
-       dma_prog_region_free(&recv->prog);
-       kfree(recv);
-       iso->hostdata = NULL;
-}
-
-/* set up a "gapped" ring buffer DMA program */
-static void ohci_iso_recv_program(struct hpsb_iso *iso)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-       int blk;
-
-       /* address of 'branch' field in previous DMA descriptor */
-       u32 *prev_branch = NULL;
-
-       for (blk = 0; blk < recv->nblocks; blk++) {
-               u32 control;
-
-               /* the DMA descriptor */
-               struct dma_cmd *cmd = &recv->block[blk];
-
-               /* offset of the DMA descriptor relative to the DMA prog buffer */
-               unsigned long prog_offset = blk * sizeof(struct dma_cmd);
-
-               /* offset of this packet's data within the DMA buffer */
-               unsigned long buf_offset = blk * recv->buf_stride;
-
-               if (recv->dma_mode == BUFFER_FILL_MODE) {
-                       control = 2 << 28; /* INPUT_MORE */
-               } else {
-                       control = 3 << 28; /* INPUT_LAST */
-               }
-
-               control |= 8 << 24; /* s = 1, update xferStatus and resCount */
-
-               /* interrupt on last block, and at intervals */
-               if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
-                       control |= 3 << 20; /* want interrupt */
-               }
-
-               control |= 3 << 18; /* enable branch to address */
-               control |= recv->buf_stride;
-
-               cmd->control = cpu_to_le32(control);
-               cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
-               cmd->branchAddress = 0; /* filled in on next loop */
-               cmd->status = cpu_to_le32(recv->buf_stride);
-
-               /* link the previous descriptor to this one */
-               if (prev_branch) {
-                       *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
-               }
-
-               prev_branch = &cmd->branchAddress;
-       }
-
-       /* the final descriptor's branch address and Z should be left at 0 */
-}
-
-/* listen or unlisten to a specific channel (multi-channel mode only) */
-static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-       int reg, i;
-
-       if (channel < 32) {
-               reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
-               i = channel;
-       } else {
-               reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
-               i = channel - 32;
-       }
-
-       reg_write(recv->ohci, reg, (1 << i));
-
-       /* issue a dummy read to force all PCI writes to be posted immediately */
-       mb();
-       reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-       int i;
-
-       for (i = 0; i < 64; i++) {
-               if (mask & (1ULL << i)) {
-                       if (i < 32)
-                               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
-                       else
-                               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
-               } else {
-                       if (i < 32)
-                               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
-                       else
-                               reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
-               }
-       }
-
-       /* issue a dummy read to force all PCI writes to be posted immediately */
-       mb();
-       reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-       struct ti_ohci *ohci = recv->ohci;
-       u32 command, contextMatch;
-
-       reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
-       wmb();
-
-       /* always keep ISO headers */
-       command = (1 << 30);
-
-       if (recv->dma_mode == BUFFER_FILL_MODE)
-               command |= (1 << 31);
-
-       reg_write(recv->ohci, recv->ContextControlSet, command);
-
-       /* match on specified tags */
-       contextMatch = tag_mask << 28;
-
-       if (iso->channel == -1) {
-               /* enable multichannel reception */
-               reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
-       } else {
-               /* listen on channel */
-               contextMatch |= iso->channel;
-       }
-
-       if (cycle != -1) {
-               u32 seconds;
-
-               /* enable cycleMatch */
-               reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
-
-               /* set starting cycle */
-               cycle &= 0x1FFF;
-
-               /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
-                  just snarf them from the current time */
-               seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
-               /* advance one second to give some extra time for DMA to start */
-               seconds += 1;
-
-               cycle |= (seconds & 3) << 13;
-
-               contextMatch |= cycle << 12;
-       }
-
-       if (sync != -1) {
-               /* set sync flag on first DMA descriptor */
-               struct dma_cmd *cmd = &recv->block[recv->block_dma];
-               cmd->control |= cpu_to_le32(DMA_CTL_WAIT);
-
-               /* match sync field */
-               contextMatch |= (sync&0xf)<<8;
-       }
-
-       reg_write(recv->ohci, recv->ContextMatch, contextMatch);
-
-       /* address of first descriptor block */
-       command = dma_prog_region_offset_to_bus(&recv->prog,
-                                               recv->block_dma * sizeof(struct dma_cmd));
-       command |= 1; /* Z=1 */
-
-       reg_write(recv->ohci, recv->CommandPtr, command);
-
-       /* enable interrupts */
-       reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
-
-       wmb();
-
-       /* run */
-       reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
-
-       /* issue a dummy read of the cycle timer register to force
-          all PCI writes to be posted immediately */
-       mb();
-       reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-
-       /* check RUN */
-       if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
-               PRINT(KERN_ERR,
-                     "Error starting IR DMA (ContextControl 0x%08x)\n",
-                     reg_read(recv->ohci, recv->ContextControlSet));
-               return -1;
-       }
-
-       return 0;
-}
-
-static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
-{
-       /* re-use the DMA descriptor for the block */
-       /* by linking the previous descriptor to it */
-
-       int next_i = block;
-       int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
-
-       struct dma_cmd *next = &recv->block[next_i];
-       struct dma_cmd *prev = &recv->block[prev_i];
-       
-       /* ignore out-of-range requests */
-       if ((block < 0) || (block > recv->nblocks))
-               return;
-
-       /* 'next' becomes the new end of the DMA chain,
-          so disable branch and enable interrupt */
-       next->branchAddress = 0;
-       next->control |= cpu_to_le32(3 << 20);
-       next->status = cpu_to_le32(recv->buf_stride);
-
-       /* link prev to next */
-       prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
-                                                                       sizeof(struct dma_cmd) * next_i)
-                                         | 1); /* Z=1 */
-
-       /* disable interrupt on previous DMA descriptor, except at intervals */
-       if ((prev_i % recv->block_irq_interval) == 0) {
-               prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
-       } else {
-               prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
-       }
-       wmb();
-
-       /* wake up DMA in case it fell asleep */
-       reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
-}
-
-static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
-                                            struct hpsb_iso_packet_info *info)
-{
-       /* release the memory where the packet was */
-       recv->released_bytes += info->total_len;
-
-       /* have we released enough memory for one block? */
-       while (recv->released_bytes > recv->buf_stride) {
-               ohci_iso_recv_release_block(recv, recv->block_reader);
-               recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
-               recv->released_bytes -= recv->buf_stride;
-       }
-}
-
-static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
-       struct ohci_iso_recv *recv = iso->hostdata;
-       if (recv->dma_mode == BUFFER_FILL_MODE) {
-               ohci_iso_recv_bufferfill_release(recv, info);
-       } else {
-               ohci_iso_recv_release_block(recv, info - iso->infos);
-       }
-}
-
-/* parse all packets from blocks that have been fully received */
-static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-       int wake = 0;
-       int runaway = 0;
-       struct ti_ohci *ohci = recv->ohci;
-
-       while (1) {
-               /* we expect the next parsable packet to begin at recv->dma_offset */
-               /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
-
-               unsigned int offset;
-               unsigned short len, cycle, total_len;
-               unsigned char channel, tag, sy;
-
-               unsigned char *p = iso->data_buf.kvirt;
-
-               unsigned int this_block = recv->dma_offset/recv->buf_stride;
-
-               /* don't loop indefinitely */
-               if (runaway++ > 100000) {
-                       atomic_inc(&iso->overflows);
-                       PRINT(KERN_ERR,
-                             "IR DMA error - Runaway during buffer parsing!\n");
-                       break;
-               }
-
-               /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
-               if (this_block == recv->block_dma)
-                       break;
-
-               wake = 1;
-
-               /* parse data length, tag, channel, and sy */
-
-               /* note: we keep our own local copies of 'len' and 'offset'
-                  so the user can't mess with them by poking in the mmap area */
-
-               len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
-
-               if (len > 4096) {
-                       PRINT(KERN_ERR,
-                             "IR DMA error - bogus 'len' value %u\n", len);
-               }
-
-               channel = p[recv->dma_offset+1] & 0x3F;
-               tag = p[recv->dma_offset+1] >> 6;
-               sy = p[recv->dma_offset+0] & 0xF;
-
-               /* advance to data payload */
-               recv->dma_offset += 4;
-
-               /* check for wrap-around */
-               if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-                       recv->dma_offset -= recv->buf_stride*recv->nblocks;
-               }
-
-               /* dma_offset now points to the first byte of the data payload */
-               offset = recv->dma_offset;
-
-               /* advance to xferStatus/timeStamp */
-               recv->dma_offset += len;
-
-               total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
-               /* payload is padded to 4 bytes */
-               if (len % 4) {
-                       recv->dma_offset += 4 - (len%4);
-                       total_len += 4 - (len%4);
-               }
-
-               /* check for wrap-around */
-               if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-                       /* uh oh, the packet data wraps from the last
-                           to the first DMA block - make the packet
-                           contiguous by copying its "tail" into the
-                           guard page */
-
-                       int guard_off = recv->buf_stride*recv->nblocks;
-                       int tail_len = len - (guard_off - offset);
-
-                       if (tail_len > 0  && tail_len < recv->buf_stride) {
-                               memcpy(iso->data_buf.kvirt + guard_off,
-                                      iso->data_buf.kvirt,
-                                      tail_len);
-                       }
-
-                       recv->dma_offset -= recv->buf_stride*recv->nblocks;
-               }
-
-               /* parse timestamp */
-               cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
-               cycle &= 0x1FFF;
-
-               /* advance to next packet */
-               recv->dma_offset += 4;
-
-               /* check for wrap-around */
-               if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-                       recv->dma_offset -= recv->buf_stride*recv->nblocks;
-               }
-
-               hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
-       }
-
-       if (wake)
-               hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-       int loop;
-       struct ti_ohci *ohci = recv->ohci;
-
-       /* loop over all blocks */
-       for (loop = 0; loop < recv->nblocks; loop++) {
-
-               /* check block_dma to see if it's done */
-               struct dma_cmd *im = &recv->block[recv->block_dma];
-
-               /* check the DMA descriptor for new writes to xferStatus */
-               u16 xferstatus = le32_to_cpu(im->status) >> 16;
-
-               /* rescount is the number of bytes *remaining to be written* in the block */
-               u16 rescount = le32_to_cpu(im->status) & 0xFFFF;
-
-               unsigned char event = xferstatus & 0x1F;
-
-               if (!event) {
-                       /* nothing has happened to this block yet */
-                       break;
-               }
-
-               if (event != 0x11) {
-                       atomic_inc(&iso->overflows);
-                       PRINT(KERN_ERR,
-                             "IR DMA error - OHCI error code 0x%02x\n", event);
-               }
-
-               if (rescount != 0) {
-                       /* the card is still writing to this block;
-                          we can't touch it until it's done */
-                       break;
-               }
-
-               /* OK, the block is finished... */
-
-               /* sync our view of the block */
-               dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
-
-               /* reset the DMA descriptor */
-               im->status = recv->buf_stride;
-
-               /* advance block_dma */
-               recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
-
-               if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
-                       atomic_inc(&iso->overflows);
-                       DBGMSG("ISO reception overflow - "
-                              "ran out of DMA blocks");
-               }
-       }
-
-       /* parse any packets that have arrived */
-       ohci_iso_recv_bufferfill_parse(iso, recv);
-}
-
-static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-       int count;
-       int wake = 0;
-       struct ti_ohci *ohci = recv->ohci;
-
-       /* loop over the entire buffer */
-       for (count = 0; count < recv->nblocks; count++) {
-               u32 packet_len = 0;
-
-               /* pointer to the DMA descriptor */
-               struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
-
-               /* check the DMA descriptor for new writes to xferStatus */
-               u16 xferstatus = le32_to_cpu(il->status) >> 16;
-               u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
-
-               unsigned char event = xferstatus & 0x1F;
-
-               if (!event) {
-                       /* this packet hasn't come in yet; we are done for now */
-                       goto out;
-               }
-
-               if (event == 0x11) {
-                       /* packet received successfully! */
-
-                       /* rescount is the number of bytes *remaining* in the packet buffer,
-                          after the packet was written */
-                       packet_len = recv->buf_stride - rescount;
-
-               } else if (event == 0x02) {
-                       PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n");
-               } else if (event) {
-                       PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event);
-               }
-
-               /* sync our view of the buffer */
-               dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
-
-               /* record the per-packet info */
-               {
-                       /* iso header is 8 bytes ahead of the data payload */
-                       unsigned char *hdr;
-
-                       unsigned int offset;
-                       unsigned short cycle;
-                       unsigned char channel, tag, sy;
-
-                       offset = iso->pkt_dma * recv->buf_stride;
-                       hdr = iso->data_buf.kvirt + offset;
-
-                       /* skip iso header */
-                       offset += 8;
-                       packet_len -= 8;
-
-                       cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
-                       channel = hdr[5] & 0x3F;
-                       tag = hdr[5] >> 6;
-                       sy = hdr[4] & 0xF;
-
-                       hpsb_iso_packet_received(iso, offset, packet_len,
-                                       recv->buf_stride, cycle, channel, tag, sy);
-               }
-
-               /* reset the DMA descriptor */
-               il->status = recv->buf_stride;
-
-               wake = 1;
-               recv->block_dma = iso->pkt_dma;
-       }
-
-out:
-       if (wake)
-               hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_task(unsigned long data)
-{
-       struct hpsb_iso *iso = (struct hpsb_iso*) data;
-       struct ohci_iso_recv *recv = iso->hostdata;
-
-       if (recv->dma_mode == BUFFER_FILL_MODE)
-               ohci_iso_recv_bufferfill_task(iso, recv);
-       else
-               ohci_iso_recv_packetperbuf_task(iso, recv);
-}
-
-/***********************************
- * rawiso ISO transmission         *
- ***********************************/
-
-struct ohci_iso_xmit {
-       struct ti_ohci *ohci;
-       struct dma_prog_region prog;
-       struct ohci1394_iso_tasklet task;
-       int task_active;
-       int last_cycle;
-       atomic_t skips;
-
-       u32 ContextControlSet;
-       u32 ContextControlClear;
-       u32 CommandPtr;
-};
-
-/* transmission DMA program:
-   one OUTPUT_MORE_IMMEDIATE for the IT header
-   one OUTPUT_LAST for the buffer data */
-
-struct iso_xmit_cmd {
-       struct dma_cmd output_more_immediate;
-       u8 iso_hdr[8];
-       u32 unused[2];
-       struct dma_cmd output_last;
-};
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso);
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
-static void ohci_iso_xmit_task(unsigned long data);
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso)
-{
-       struct ohci_iso_xmit *xmit;
-       unsigned int prog_size;
-       int ctx;
-       int ret = -ENOMEM;
-
-       xmit = kmalloc(sizeof(*xmit), GFP_KERNEL);
-       if (!xmit)
-               return -ENOMEM;
-
-       iso->hostdata = xmit;
-       xmit->ohci = iso->host->hostdata;
-       xmit->task_active = 0;
-       xmit->last_cycle = -1;
-       atomic_set(&iso->skips, 0);
-
-       dma_prog_region_init(&xmit->prog);
-
-       prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
-
-       if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
-               goto err;
-
-       ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
-                                 ohci_iso_xmit_task, (unsigned long) iso);
-
-       if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
-               ret = -EBUSY;
-               goto err;
-       }
-
-       xmit->task_active = 1;
-
-       /* xmit context registers are spaced 16 bytes apart */
-       ctx = xmit->task.context;
-       xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
-       xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
-       xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
-
-       return 0;
-
-err:
-       ohci_iso_xmit_shutdown(iso);
-       return ret;
-}
-
-static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
-{
-       struct ohci_iso_xmit *xmit = iso->hostdata;
-       struct ti_ohci *ohci = xmit->ohci;
-
-       /* disable interrupts */
-       reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
-
-       /* halt DMA */
-       if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
-               /* XXX the DMA context will lock up if you try to send too much data! */
-               PRINT(KERN_ERR,
-                     "you probably exceeded the OHCI card's bandwidth limit - "
-                     "reload the module and reduce xmit bandwidth");
-       }
-}
-
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
-{
-       struct ohci_iso_xmit *xmit = iso->hostdata;
-
-       if (xmit->task_active) {
-               ohci_iso_xmit_stop(iso);
-               ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
-               xmit->task_active = 0;
-       }
-
-       dma_prog_region_free(&xmit->prog);
-       kfree(xmit);
-       iso->hostdata = NULL;
-}
-
-static void ohci_iso_xmit_task(unsigned long data)
-{
-       struct hpsb_iso *iso = (struct hpsb_iso*) data;
-       struct ohci_iso_xmit *xmit = iso->hostdata;
-       struct ti_ohci *ohci = xmit->ohci;
-       int wake = 0;
-       int count;
-
-       /* check the whole buffer if necessary, starting at pkt_dma */
-       for (count = 0; count < iso->buf_packets; count++) {
-               int cycle;
-
-               /* DMA descriptor */
-               struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
-
-               /* check for new writes to xferStatus */
-               u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
-               u8  event = xferstatus & 0x1F;
-
-               if (!event) {
-                       /* packet hasn't been sent yet; we are done for now */
-                       break;
-               }
-
-               if (event != 0x11)
-                       PRINT(KERN_ERR,
-                             "IT DMA error - OHCI error code 0x%02x\n", event);
-
-               /* at least one packet went out, so wake up the writer */
-               wake = 1;
-
-               /* parse cycle */
-               cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
-
-               if (xmit->last_cycle > -1) {
-                       int cycle_diff = cycle - xmit->last_cycle;
-                       int skip;
-
-                       /* unwrap */
-                       if (cycle_diff < 0) {
-                               cycle_diff += 8000;
-                               if (cycle_diff < 0)
-                                       PRINT(KERN_ERR, "bogus cycle diff %d\n",
-                                             cycle_diff);
-                       }
-
-                       skip = cycle_diff - 1;
-                       if (skip > 0) {
-                               DBGMSG("skipped %d cycles without packet loss", skip);
-                               atomic_add(skip, &iso->skips);
-                       }
-               }
-               xmit->last_cycle = cycle;
-
-               /* tell the subsystem the packet has gone out */
-               hpsb_iso_packet_sent(iso, cycle, event != 0x11);
-
-               /* reset the DMA descriptor for next time */
-               cmd->output_last.status = 0;
-       }
-
-       if (wake)
-               hpsb_iso_wake(iso);
-}
-
-static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
-       struct ohci_iso_xmit *xmit = iso->hostdata;
-       struct ti_ohci *ohci = xmit->ohci;
-
-       int next_i, prev_i;
-       struct iso_xmit_cmd *next, *prev;
-
-       unsigned int offset;
-       unsigned short len;
-       unsigned char tag, sy;
-
-       /* check that the packet doesn't cross a page boundary
-          (we could allow this if we added OUTPUT_MORE descriptor support) */
-       if (cross_bound(info->offset, info->len)) {
-               PRINT(KERN_ERR,
-                     "rawiso xmit: packet %u crosses a page boundary",
-                     iso->first_packet);
-               return -EINVAL;
-       }
-
-       offset = info->offset;
-       len = info->len;
-       tag = info->tag;
-       sy = info->sy;
-
-       /* sync up the card's view of the buffer */
-       dma_region_sync_for_device(&iso->data_buf, offset, len);
-
-       /* append first_packet to the DMA chain */
-       /* by linking the previous descriptor to it */
-       /* (next will become the new end of the DMA chain) */
-
-       next_i = iso->first_packet;
-       prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
-
-       next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
-       prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
-
-       /* set up the OUTPUT_MORE_IMMEDIATE descriptor */
-       memset(next, 0, sizeof(struct iso_xmit_cmd));
-       next->output_more_immediate.control = cpu_to_le32(0x02000008);
-
-       /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
-
-       /* tcode = 0xA, and sy */
-       next->iso_hdr[0] = 0xA0 | (sy & 0xF);
-
-       /* tag and channel number */
-       next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
-
-       /* transmission speed */
-       next->iso_hdr[2] = iso->speed & 0x7;
-
-       /* payload size */
-       next->iso_hdr[6] = len & 0xFF;
-       next->iso_hdr[7] = len >> 8;
-
-       /* set up the OUTPUT_LAST */
-       next->output_last.control = cpu_to_le32(1 << 28);
-       next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
-       next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
-       next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
-       next->output_last.control |= cpu_to_le32(len);
-
-       /* payload bus address */
-       next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
-
-       /* leave branchAddress at zero for now */
-
-       /* re-write the previous DMA descriptor to chain to this one */
-
-       /* set prev branch address to point to next (Z=3) */
-       prev->output_last.branchAddress = cpu_to_le32(
-               dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
-
-       /*
-        * Link the skip address to this descriptor itself. This causes a
-        * context to skip a cycle whenever lost cycles or FIFO overruns occur,
-        * without dropping the data at that point the application should then
-        * decide whether this is an error condition or not. Some protocols
-        * can deal with this by dropping some rate-matching padding packets.
-        */
-       next->output_more_immediate.branchAddress =
-                       prev->output_last.branchAddress;
-
-       /* disable interrupt, unless required by the IRQ interval */
-       if (prev_i % iso->irq_interval) {
-               prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
-       } else {
-               prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
-       }
-
-       wmb();
-
-       /* wake DMA in case it is sleeping */
-       reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
-
-       /* issue a dummy read of the cycle timer to force all PCI
-          writes to be posted immediately */
-       mb();
-       reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
-
-       return 0;
-}
-
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
-       struct ohci_iso_xmit *xmit = iso->hostdata;
-       struct ti_ohci *ohci = xmit->ohci;
-
-       /* clear out the control register */
-       reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
-       wmb();
-
-       /* address and length of first descriptor block (Z=3) */
-       reg_write(xmit->ohci, xmit->CommandPtr,
-                 dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
-
-       /* cycle match */
-       if (cycle != -1) {
-               u32 start = cycle & 0x1FFF;
-
-               /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
-                  just snarf them from the current time */
-               u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
-               /* advance one second to give some extra time for DMA to start */
-               seconds += 1;
-
-               start |= (seconds & 3) << 13;
-
-               reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
-       }
-
-       /* enable interrupts */
-       reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
-
-       /* run */
-       reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
-       mb();
-
-       /* wait 100 usec to give the card time to go active */
-       udelay(100);
-
-       /* check the RUN bit */
-       if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
-               PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n",
-                     reg_read(xmit->ohci, xmit->ContextControlSet));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
-{
-
-       switch(cmd) {
-       case XMIT_INIT:
-               return ohci_iso_xmit_init(iso);
-       case XMIT_START:
-               return ohci_iso_xmit_start(iso, arg);
-       case XMIT_STOP:
-               ohci_iso_xmit_stop(iso);
-               return 0;
-       case XMIT_QUEUE:
-               return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
-       case XMIT_SHUTDOWN:
-               ohci_iso_xmit_shutdown(iso);
-               return 0;
-
-       case RECV_INIT:
-               return ohci_iso_recv_init(iso);
-       case RECV_START: {
-               int *args = (int*) arg;
-               return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
-       }
-       case RECV_STOP:
-               ohci_iso_recv_stop(iso);
-               return 0;
-       case RECV_RELEASE:
-               ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
-               return 0;
-       case RECV_FLUSH:
-               ohci_iso_recv_task((unsigned long) iso);
-               return 0;
-       case RECV_SHUTDOWN:
-               ohci_iso_recv_shutdown(iso);
-               return 0;
-       case RECV_LISTEN_CHANNEL:
-               ohci_iso_recv_change_channel(iso, arg, 1);
-               return 0;
-       case RECV_UNLISTEN_CHANNEL:
-               ohci_iso_recv_change_channel(iso, arg, 0);
-               return 0;
-       case RECV_SET_CHANNEL_MASK:
-               ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
-               return 0;
-
-       default:
-               PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
-                       cmd);
-               break;
-       }
-       return -EINVAL;
-}
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-static void dma_trm_reset(struct dma_trm_ctx *d)
-{
-       unsigned long flags;
-       LIST_HEAD(packet_list);
-       struct ti_ohci *ohci = d->ohci;
-       struct hpsb_packet *packet, *ptmp;
-
-       ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-       /* Lock the context, reset it and release it. Move the packets
-        * that were pending in the context to packet_list and free
-        * them after releasing the lock. */
-
-       spin_lock_irqsave(&d->lock, flags);
-
-       list_splice_init(&d->fifo_list, &packet_list);
-       list_splice_init(&d->pending_list, &packet_list);
-
-       d->branchAddrPtr = NULL;
-       d->sent_ind = d->prg_ind;
-       d->free_prgs = d->num_desc;
-
-       spin_unlock_irqrestore(&d->lock, flags);
-
-       if (list_empty(&packet_list))
-               return;
-
-       PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx);
-
-       /* Now process subsystem callbacks for the packets from this
-        * context. */
-       list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) {
-               list_del_init(&packet->driver_list);
-               hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED);
-       }
-}
-
-static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
-                                      quadlet_t rx_event,
-                                      quadlet_t tx_event)
-{
-       struct ohci1394_iso_tasklet *t;
-       unsigned long mask;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-       list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
-               mask = 1 << t->context;
-
-               if (t->type == OHCI_ISO_TRANSMIT) {
-                       if (tx_event & mask)
-                               tasklet_schedule(&t->tasklet);
-               } else {
-                       /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */
-                       if (rx_event & mask)
-                               tasklet_schedule(&t->tasklet);
-               }
-       }
-
-       spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
-{
-       quadlet_t event, node_id;
-       struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
-       struct hpsb_host *host = ohci->host;
-       int phyid = -1, isroot = 0;
-       unsigned long flags;
-
-       /* Read and clear the interrupt event register.  Don't clear
-        * the busReset event, though. This is done when we get the
-        * selfIDComplete interrupt. */
-       spin_lock_irqsave(&ohci->event_lock, flags);
-       event = reg_read(ohci, OHCI1394_IntEventClear);
-       reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
-       spin_unlock_irqrestore(&ohci->event_lock, flags);
-
-       if (!event)
-               return IRQ_NONE;
-
-       /* If event is ~(u32)0 cardbus card was ejected.  In this case
-        * we just return, and clean up in the ohci1394_pci_remove
-        * function. */
-       if (event == ~(u32) 0) {
-               DBGMSG("Device removed.");
-               return IRQ_NONE;
-       }
-
-       DBGMSG("IntEvent: %08x", event);
-
-       if (event & OHCI1394_unrecoverableError) {
-               int ctx;
-               PRINT(KERN_ERR, "Unrecoverable error!");
-
-               if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
-                       PRINT(KERN_ERR, "Async Req Tx Context died: "
-                               "ctrl[%08x] cmdptr[%08x]",
-                               reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
-                               reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
-
-               if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
-                       PRINT(KERN_ERR, "Async Rsp Tx Context died: "
-                               "ctrl[%08x] cmdptr[%08x]",
-                               reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
-                               reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
-
-               if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
-                       PRINT(KERN_ERR, "Async Req Rcv Context died: "
-                               "ctrl[%08x] cmdptr[%08x]",
-                               reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
-                               reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
-
-               if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
-                       PRINT(KERN_ERR, "Async Rsp Rcv Context died: "
-                               "ctrl[%08x] cmdptr[%08x]",
-                               reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
-                               reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
-
-               for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
-                       if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
-                               PRINT(KERN_ERR, "Iso Xmit %d Context died: "
-                                       "ctrl[%08x] cmdptr[%08x]", ctx,
-                                       reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
-                                       reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
-               }
-
-               for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
-                       if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
-                               PRINT(KERN_ERR, "Iso Recv %d Context died: "
-                                       "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
-                                       reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
-                                       reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
-                                       reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
-               }
-
-               event &= ~OHCI1394_unrecoverableError;
-       }
-       if (event & OHCI1394_postedWriteErr) {
-               PRINT(KERN_ERR, "physical posted write error");
-               /* no recovery strategy yet, had to involve protocol drivers */
-               event &= ~OHCI1394_postedWriteErr;
-       }
-       if (event & OHCI1394_cycleTooLong) {
-               if(printk_ratelimit())
-                       PRINT(KERN_WARNING, "isochronous cycle too long");
-               else
-                       DBGMSG("OHCI1394_cycleTooLong");
-               reg_write(ohci, OHCI1394_LinkControlSet,
-                         OHCI1394_LinkControl_CycleMaster);
-               event &= ~OHCI1394_cycleTooLong;
-       }
-       if (event & OHCI1394_cycleInconsistent) {
-               /* We subscribe to the cycleInconsistent event only to
-                * clear the corresponding event bit... otherwise,
-                * isochronous cycleMatch DMA won't work. */
-               DBGMSG("OHCI1394_cycleInconsistent");
-               event &= ~OHCI1394_cycleInconsistent;
-       }
-       if (event & OHCI1394_busReset) {
-               /* The busReset event bit can't be cleared during the
-                * selfID phase, so we disable busReset interrupts, to
-                * avoid burying the cpu in interrupt requests. */
-               spin_lock_irqsave(&ohci->event_lock, flags);
-               reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-
-               if (ohci->check_busreset) {
-                       int loop_count = 0;
-
-                       udelay(10);
-
-                       while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-                               reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-
-                               spin_unlock_irqrestore(&ohci->event_lock, flags);
-                               udelay(10);
-                               spin_lock_irqsave(&ohci->event_lock, flags);
-
-                               /* The loop counter check is to prevent the driver
-                                * from remaining in this state forever. For the
-                                * initial bus reset, the loop continues for ever
-                                * and the system hangs, until some device is plugged-in
-                                * or out manually into a port! The forced reset seems
-                                * to solve this problem. This mainly effects nForce2. */
-                               if (loop_count > 10000) {
-                                       ohci_devctl(host, RESET_BUS, LONG_RESET);
-                                       DBGMSG("Detected bus-reset loop. Forced a bus reset!");
-                                       loop_count = 0;
-                               }
-
-                               loop_count++;
-                       }
-               }
-               spin_unlock_irqrestore(&ohci->event_lock, flags);
-               if (!host->in_bus_reset) {
-                       DBGMSG("irq_handler: Bus reset requested");
-
-                       /* Subsystem call */
-                       hpsb_bus_reset(ohci->host);
-               }
-               event &= ~OHCI1394_busReset;
-       }
-       if (event & OHCI1394_reqTxComplete) {
-               struct dma_trm_ctx *d = &ohci->at_req_context;
-               DBGMSG("Got reqTxComplete interrupt "
-                      "status=0x%08X", reg_read(ohci, d->ctrlSet));
-               if (reg_read(ohci, d->ctrlSet) & 0x800)
-                       ohci1394_stop_context(ohci, d->ctrlClear,
-                                             "reqTxComplete");
-               else
-                       dma_trm_tasklet((unsigned long)d);
-                       //tasklet_schedule(&d->task);
-               event &= ~OHCI1394_reqTxComplete;
-       }
-       if (event & OHCI1394_respTxComplete) {
-               struct dma_trm_ctx *d = &ohci->at_resp_context;
-               DBGMSG("Got respTxComplete interrupt "
-                      "status=0x%08X", reg_read(ohci, d->ctrlSet));
-               if (reg_read(ohci, d->ctrlSet) & 0x800)
-                       ohci1394_stop_context(ohci, d->ctrlClear,
-                                             "respTxComplete");
-               else
-                       tasklet_schedule(&d->task);
-               event &= ~OHCI1394_respTxComplete;
-       }
-       if (event & OHCI1394_RQPkt) {
-               struct dma_rcv_ctx *d = &ohci->ar_req_context;
-               DBGMSG("Got RQPkt interrupt status=0x%08X",
-                      reg_read(ohci, d->ctrlSet));
-               if (reg_read(ohci, d->ctrlSet) & 0x800)
-                       ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
-               else
-                       tasklet_schedule(&d->task);
-               event &= ~OHCI1394_RQPkt;
-       }
-       if (event & OHCI1394_RSPkt) {
-               struct dma_rcv_ctx *d = &ohci->ar_resp_context;
-               DBGMSG("Got RSPkt interrupt status=0x%08X",
-                      reg_read(ohci, d->ctrlSet));
-               if (reg_read(ohci, d->ctrlSet) & 0x800)
-                       ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
-               else
-                       tasklet_schedule(&d->task);
-               event &= ~OHCI1394_RSPkt;
-       }
-       if (event & OHCI1394_isochRx) {
-               quadlet_t rx_event;
-
-               rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
-               reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
-               ohci_schedule_iso_tasklets(ohci, rx_event, 0);
-               event &= ~OHCI1394_isochRx;
-       }
-       if (event & OHCI1394_isochTx) {
-               quadlet_t tx_event;
-
-               tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
-               reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
-               ohci_schedule_iso_tasklets(ohci, 0, tx_event);
-               event &= ~OHCI1394_isochTx;
-       }
-       if (event & OHCI1394_selfIDComplete) {
-               if (host->in_bus_reset) {
-                       node_id = reg_read(ohci, OHCI1394_NodeID);
-
-                       if (!(node_id & 0x80000000)) {
-                               PRINT(KERN_ERR,
-                                     "SelfID received, but NodeID invalid "
-                                     "(probably new bus reset occurred): %08X",
-                                     node_id);
-                               goto selfid_not_valid;
-                       }
-
-                       phyid =  node_id & 0x0000003f;
-                       isroot = (node_id & 0x40000000) != 0;
-
-                       DBGMSG("SelfID interrupt received "
-                             "(phyid %d, %s)", phyid,
-                             (isroot ? "root" : "not root"));
-
-                       handle_selfid(ohci, host, phyid, isroot);
-
-                       /* Clear the bus reset event and re-enable the
-                        * busReset interrupt.  */
-                       spin_lock_irqsave(&ohci->event_lock, flags);
-                       reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-                       reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
-                       spin_unlock_irqrestore(&ohci->event_lock, flags);
-
-                       /* Turn on phys dma reception.
-                        *
-                        * TODO: Enable some sort of filtering management.
-                        */
-                       if (phys_dma) {
-                               reg_write(ohci, OHCI1394_PhyReqFilterHiSet,
-                                         0xffffffff);
-                               reg_write(ohci, OHCI1394_PhyReqFilterLoSet,
-                                         0xffffffff);
-                       }
-
-                       DBGMSG("PhyReqFilter=%08x%08x",
-                              reg_read(ohci, OHCI1394_PhyReqFilterHiSet),
-                              reg_read(ohci, OHCI1394_PhyReqFilterLoSet));
-
-                       hpsb_selfid_complete(host, phyid, isroot);
-               } else
-                       PRINT(KERN_ERR,
-                             "SelfID received outside of bus reset sequence");
-
-selfid_not_valid:
-               event &= ~OHCI1394_selfIDComplete;
-       }
-
-       /* Make sure we handle everything, just in case we accidentally
-        * enabled an interrupt that we didn't write a handler for.  */
-       if (event)
-               PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x",
-                     event);
-
-       return IRQ_HANDLED;
-}
-
-/* Put the buffer back into the dma context */
-static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
-{
-       struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-       DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
-
-       d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
-       d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
-       idx = (idx + d->num_desc - 1 ) % d->num_desc;
-       d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
-
-       /* To avoid a race, ensure 1394 interface hardware sees the inserted
-        * context program descriptors before it sees the wakeup bit set. */
-       wmb();
-       
-       /* wake up the dma context if necessary */
-       if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-               PRINT(KERN_INFO,
-                     "Waking dma ctx=%d ... processing is probably too slow",
-                     d->ctx);
-       }
-
-       /* do this always, to avoid race condition */
-       reg_write(ohci, d->ctrlSet, 0x1000);
-}
-
-#define cond_le32_to_cpu(data, noswap) \
-       (noswap ? data : le32_to_cpu(data))
-
-static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
-                           -1, 0, -1, 0, -1, -1, 16, -1};
-
-/*
- * Determine the length of a packet in the buffer
- * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
- */
-static inline int packet_length(struct dma_rcv_ctx *d, int idx,
-                               quadlet_t *buf_ptr, int offset,
-                               unsigned char tcode, int noswap)
-{
-       int length = -1;
-
-       if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
-               length = TCODE_SIZE[tcode];
-               if (length == 0) {
-                       if (offset + 12 >= d->buf_size) {
-                               length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
-                                               [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
-                       } else {
-                               length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
-                       }
-                       length += 20;
-               }
-       } else if (d->type == DMA_CTX_ISO) {
-               /* Assumption: buffer fill mode with header/trailer */
-               length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
-       }
-
-       if (length > 0 && length % 4)
-               length += 4 - (length % 4);
-
-       return length;
-}
-
-/* Tasklet that processes dma receive buffers */
-static void dma_rcv_tasklet (unsigned long data)
-{
-       struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
-       struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-       unsigned int split_left, idx, offset, rescount;
-       unsigned char tcode;
-       int length, bytes_left, ack;
-       unsigned long flags;
-       quadlet_t *buf_ptr;
-       char *split_ptr;
-       char msg[256];
-
-       spin_lock_irqsave(&d->lock, flags);
-
-       idx = d->buf_ind;
-       offset = d->buf_offset;
-       buf_ptr = d->buf_cpu[idx] + offset/4;
-
-       rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-       bytes_left = d->buf_size - rescount - offset;
-
-       while (bytes_left > 0) {
-               tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
-
-               /* packet_length() will return < 4 for an error */
-               length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
-
-               if (length < 4) { /* something is wrong */
-                       sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
-                               tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
-                               d->ctx, length);
-                       ohci1394_stop_context(ohci, d->ctrlClear, msg);
-                       spin_unlock_irqrestore(&d->lock, flags);
-                       return;
-               }
-
-               /* The first case is where we have a packet that crosses
-                * over more than one descriptor. The next case is where
-                * it's all in the first descriptor.  */
-               if ((offset + length) > d->buf_size) {
-                       DBGMSG("Split packet rcv'd");
-                       if (length > d->split_buf_size) {
-                               ohci1394_stop_context(ohci, d->ctrlClear,
-                                            "Split packet size exceeded");
-                               d->buf_ind = idx;
-                               d->buf_offset = offset;
-                               spin_unlock_irqrestore(&d->lock, flags);
-                               return;
-                       }
-
-                       if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
-                           == d->buf_size) {
-                               /* Other part of packet not written yet.
-                                * this should never happen I think
-                                * anyway we'll get it on the next call.  */
-                               PRINT(KERN_INFO,
-                                     "Got only half a packet!");
-                               d->buf_ind = idx;
-                               d->buf_offset = offset;
-                               spin_unlock_irqrestore(&d->lock, flags);
-                               return;
-                       }
-
-                       split_left = length;
-                       split_ptr = (char *)d->spb;
-                       memcpy(split_ptr,buf_ptr,d->buf_size-offset);
-                       split_left -= d->buf_size-offset;
-                       split_ptr += d->buf_size-offset;
-                       insert_dma_buffer(d, idx);
-                       idx = (idx+1) % d->num_desc;
-                       buf_ptr = d->buf_cpu[idx];
-                       offset=0;
-
-                       while (split_left >= d->buf_size) {
-                               memcpy(split_ptr,buf_ptr,d->buf_size);
-                               split_ptr += d->buf_size;
-                               split_left -= d->buf_size;
-                               insert_dma_buffer(d, idx);
-                               idx = (idx+1) % d->num_desc;
-                               buf_ptr = d->buf_cpu[idx];
-                       }
-
-                       if (split_left > 0) {
-                               memcpy(split_ptr, buf_ptr, split_left);
-                               offset = split_left;
-                               buf_ptr += offset/4;
-                       }
-               } else {
-                       DBGMSG("Single packet rcv'd");
-                       memcpy(d->spb, buf_ptr, length);
-                       offset += length;
-                       buf_ptr += length/4;
-                       if (offset==d->buf_size) {
-                               insert_dma_buffer(d, idx);
-                               idx = (idx+1) % d->num_desc;
-                               buf_ptr = d->buf_cpu[idx];
-                               offset=0;
-                       }
-               }
-
-               /* We get one phy packet to the async descriptor for each
-                * bus reset. We always ignore it.  */
-               if (tcode != OHCI1394_TCODE_PHY) {
-                       if (!ohci->no_swap_incoming)
-                               header_le32_to_cpu(d->spb, tcode);
-                       DBGMSG("Packet received from node"
-                               " %d ack=0x%02X spd=%d tcode=0x%X"
-                               " length=%d ctx=%d tlabel=%d",
-                               (d->spb[1]>>16)&0x3f,
-                               (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
-                               (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
-                               tcode, length, d->ctx,
-                               (d->spb[0]>>10)&0x3f);
-
-                       ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
-                               == 0x11) ? 1 : 0;
-
-                       hpsb_packet_received(ohci->host, d->spb,
-                                            length-4, ack);
-               }
-#ifdef OHCI1394_DEBUG
-               else
-                       PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded",
-                              d->ctx);
-#endif
-
-               rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
-               bytes_left = d->buf_size - rescount - offset;
-
-       }
-
-       d->buf_ind = idx;
-       d->buf_offset = offset;
-
-       spin_unlock_irqrestore(&d->lock, flags);
-}
-
-/* Bottom half that processes sent packets */
-static void dma_trm_tasklet (unsigned long data)
-{
-       struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
-       struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-       struct hpsb_packet *packet, *ptmp;
-       unsigned long flags;
-       u32 status, ack;
-        size_t datasize;
-
-       spin_lock_irqsave(&d->lock, flags);
-
-       list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) {
-                datasize = packet->data_size;
-               if (datasize && packet->type != hpsb_raw)
-                       status = le32_to_cpu(
-                               d->prg_cpu[d->sent_ind]->end.status) >> 16;
-               else
-                       status = le32_to_cpu(
-                               d->prg_cpu[d->sent_ind]->begin.status) >> 16;
-
-               if (status == 0)
-                       /* this packet hasn't been sent yet*/
-                       break;
-
-#ifdef OHCI1394_DEBUG
-               if (datasize)
-                       if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa)
-                               DBGMSG("Stream packet sent to channel %d tcode=0x%X "
-                                      "ack=0x%X spd=%d dataLength=%d ctx=%d",
-                                      (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f,
-                                      (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
-                                      status&0x1f, (status>>5)&0x3,
-                                      le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16,
-                                      d->ctx);
-                       else
-                               DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-                                      "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
-                                      (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
-                                      (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
-                                      (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
-                                      status&0x1f, (status>>5)&0x3,
-                                      le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16,
-                                      d->ctx);
-               else
-                       DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-                              "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
-                                        >>16)&0x3f,
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
-                                        >>4)&0xf,
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
-                                        >>10)&0x3f,
-                                status&0x1f, (status>>5)&0x3,
-                                le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
-                                d->ctx);
-#endif
-
-               if (status & 0x10) {
-                       ack = status & 0xf;
-               } else {
-                       switch (status & 0x1f) {
-                       case EVT_NO_STATUS: /* that should never happen */
-                       case EVT_RESERVED_A: /* that should never happen */
-                       case EVT_LONG_PACKET: /* that should never happen */
-                               PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_MISSING_ACK:
-                               ack = ACKX_TIMEOUT;
-                               break;
-                       case EVT_UNDERRUN:
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_OVERRUN: /* that should never happen */
-                               PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_DESCRIPTOR_READ:
-                       case EVT_DATA_READ:
-                       case EVT_DATA_WRITE:
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_BUS_RESET: /* that should never happen */
-                               PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_TIMEOUT:
-                               ack = ACKX_TIMEOUT;
-                               break;
-                       case EVT_TCODE_ERR:
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_RESERVED_B: /* that should never happen */
-                       case EVT_RESERVED_C: /* that should never happen */
-                               PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       case EVT_UNKNOWN:
-                       case EVT_FLUSHED:
-                               ack = ACKX_SEND_ERROR;
-                               break;
-                       default:
-                               PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
-                               ack = ACKX_SEND_ERROR;
-                               BUG();
-                       }
-               }
-
-               list_del_init(&packet->driver_list);
-               hpsb_packet_sent(ohci->host, packet, ack);
-
-               if (datasize)
-                       pci_unmap_single(ohci->dev,
-                                        cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
-                                        datasize, PCI_DMA_TODEVICE);
-
-               d->sent_ind = (d->sent_ind+1)%d->num_desc;
-               d->free_prgs++;
-       }
-
-       dma_trm_flush(ohci, d);
-
-       spin_unlock_irqrestore(&d->lock, flags);
-}
-
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
-{
-       int i;
-       struct ti_ohci *ohci = d->ohci;
-
-       if (ohci == NULL)
-               return;
-
-       DBGMSG("Freeing dma_rcv_ctx %d", d->ctx);
-
-       if (d->buf_cpu) {
-               for (i=0; i<d->num_desc; i++)
-                       if (d->buf_cpu[i] && d->buf_bus[i])
-                               pci_free_consistent(
-                                       ohci->dev, d->buf_size,
-                                       d->buf_cpu[i], d->buf_bus[i]);
-               kfree(d->buf_cpu);
-               kfree(d->buf_bus);
-       }
-       if (d->prg_cpu) {
-               for (i=0; i<d->num_desc; i++)
-                       if (d->prg_cpu[i] && d->prg_bus[i])
-                               pci_pool_free(d->prg_pool, d->prg_cpu[i],
-                                             d->prg_bus[i]);
-               pci_pool_destroy(d->prg_pool);
-               kfree(d->prg_cpu);
-               kfree(d->prg_bus);
-       }
-       kfree(d->spb);
-
-       /* Mark this context as freed. */
-       d->ohci = NULL;
-}
-
-static int
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
-                 enum context_type type, int ctx, int num_desc,
-                 int buf_size, int split_buf_size, int context_base)
-{
-       int i, len;
-       static int num_allocs;
-       static char pool_name[20];
-
-       d->ohci = ohci;
-       d->type = type;
-       d->ctx = ctx;
-
-       d->num_desc = num_desc;
-       d->buf_size = buf_size;
-       d->split_buf_size = split_buf_size;
-
-       d->ctrlSet = 0;
-       d->ctrlClear = 0;
-       d->cmdPtr = 0;
-
-       d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC);
-       d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC);
-
-       if (d->buf_cpu == NULL || d->buf_bus == NULL) {
-               PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer");
-               free_dma_rcv_ctx(d);
-               return -ENOMEM;
-       }
-
-       d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC);
-       d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC);
-
-       if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-               PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg");
-               free_dma_rcv_ctx(d);
-               return -ENOMEM;
-       }
-
-       d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
-
-       if (d->spb == NULL) {
-               PRINT(KERN_ERR, "Failed to allocate %s", "split buffer");
-               free_dma_rcv_ctx(d);
-               return -ENOMEM;
-       }
-       
-       len = sprintf(pool_name, "ohci1394_rcv_prg");
-       sprintf(pool_name+len, "%d", num_allocs);
-       d->prg_pool = pci_pool_create(pool_name, ohci->dev,
-                               sizeof(struct dma_cmd), 4, 0);
-       if(d->prg_pool == NULL)
-       {
-               PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
-               free_dma_rcv_ctx(d);
-               return -ENOMEM;
-       }
-       num_allocs++;
-
-       for (i=0; i<d->num_desc; i++) {
-               d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
-                                                    d->buf_size,
-                                                    d->buf_bus+i);
-
-               if (d->buf_cpu[i] != NULL) {
-                       memset(d->buf_cpu[i], 0, d->buf_size);
-               } else {
-                       PRINT(KERN_ERR,
-                             "Failed to allocate %s", "DMA buffer");
-                       free_dma_rcv_ctx(d);
-                       return -ENOMEM;
-               }
-
-               d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
-                if (d->prg_cpu[i] != NULL) {
-                        memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
-               } else {
-                       PRINT(KERN_ERR,
-                             "Failed to allocate %s", "DMA prg");
-                       free_dma_rcv_ctx(d);
-                       return -ENOMEM;
-               }
-       }
-
-        spin_lock_init(&d->lock);
-
-       d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-       d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-       d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-
-       tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d);
-       return 0;
-}
-
-static void free_dma_trm_ctx(struct dma_trm_ctx *d)
-{
-       int i;
-       struct ti_ohci *ohci = d->ohci;
-
-       if (ohci == NULL)
-               return;
-
-       DBGMSG("Freeing dma_trm_ctx %d", d->ctx);
-
-       if (d->prg_cpu) {
-               for (i=0; i<d->num_desc; i++)
-                       if (d->prg_cpu[i] && d->prg_bus[i])
-                               pci_pool_free(d->prg_pool, d->prg_cpu[i],
-                                             d->prg_bus[i]);
-               pci_pool_destroy(d->prg_pool);
-               kfree(d->prg_cpu);
-               kfree(d->prg_bus);
-       }
-
-       /* Mark this context as freed. */
-       d->ohci = NULL;
-}
-
-static int
-alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
-                 enum context_type type, int ctx, int num_desc,
-                 int context_base)
-{
-       int i, len;
-       static char pool_name[20];
-       static int num_allocs=0;
-
-       d->ohci = ohci;
-       d->type = type;
-       d->ctx = ctx;
-       d->num_desc = num_desc;
-       d->ctrlSet = 0;
-       d->ctrlClear = 0;
-       d->cmdPtr = 0;
-
-       d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL);
-       d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL);
-
-       if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-               PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg");
-               free_dma_trm_ctx(d);
-               return -ENOMEM;
-       }
-
-       len = sprintf(pool_name, "ohci1394_trm_prg");
-       sprintf(pool_name+len, "%d", num_allocs);
-       d->prg_pool = pci_pool_create(pool_name, ohci->dev,
-                               sizeof(struct at_dma_prg), 4, 0);
-       if (d->prg_pool == NULL) {
-               PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
-               free_dma_trm_ctx(d);
-               return -ENOMEM;
-       }
-       num_allocs++;
-
-       for (i = 0; i < d->num_desc; i++) {
-               d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
-                if (d->prg_cpu[i] != NULL) {
-                        memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
-               } else {
-                       PRINT(KERN_ERR,
-                             "Failed to allocate %s", "AT DMA prg");
-                       free_dma_trm_ctx(d);
-                       return -ENOMEM;
-               }
-       }
-
-        spin_lock_init(&d->lock);
-
-       /* initialize tasklet */
-       d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-       d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-       d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-       tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d);
-       return 0;
-}
-
-static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom)
-{
-       struct ti_ohci *ohci = host->hostdata;
-
-       reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
-       reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
-
-       memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
-}
-
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
-                                 quadlet_t data, quadlet_t compare)
-{
-       struct ti_ohci *ohci = host->hostdata;
-       int i;
-
-       reg_write(ohci, OHCI1394_CSRData, data);
-       reg_write(ohci, OHCI1394_CSRCompareData, compare);
-       reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
-
-       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
-                       break;
-
-               mdelay(1);
-       }
-
-       return reg_read(ohci, OHCI1394_CSRData);
-}
-
-static struct hpsb_host_driver ohci1394_driver = {
-       .owner =                THIS_MODULE,
-       .name =                 OHCI1394_DRIVER_NAME,
-       .set_hw_config_rom =    ohci_set_hw_config_rom,
-       .transmit_packet =      ohci_transmit,
-       .devctl =               ohci_devctl,
-       .isoctl =               ohci_isoctl,
-       .hw_csr_reg =           ohci_hw_csr_reg,
-};
-
-/***********************************
- * PCI Driver Interface functions  *
- ***********************************/
-
-#ifdef CONFIG_PPC_PMAC
-static void ohci1394_pmac_on(struct pci_dev *dev)
-{
-       if (machine_is(powermac)) {
-               struct device_node *ofn = pci_device_to_OF_node(dev);
-
-               if (ofn) {
-                       pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1);
-                       pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1);
-               }
-       }
-}
-
-static void ohci1394_pmac_off(struct pci_dev *dev)
-{
-       if (machine_is(powermac)) {
-               struct device_node *ofn = pci_device_to_OF_node(dev);
-
-               if (ofn) {
-                       pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0);
-                       pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0);
-               }
-       }
-}
-#else
-#define ohci1394_pmac_on(dev)
-#define ohci1394_pmac_off(dev)
-#endif /* CONFIG_PPC_PMAC */
-
-static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
-                                       const struct pci_device_id *ent)
-{
-       struct hpsb_host *host;
-       struct ti_ohci *ohci;   /* shortcut to currently handled device */
-       resource_size_t ohci_base;
-       int err = -ENOMEM;
-
-       ohci1394_pmac_on(dev);
-       if (pci_enable_device(dev)) {
-               PRINT_G(KERN_ERR, "Failed to enable OHCI hardware");
-               err = -ENXIO;
-               goto err;
-       }
-        pci_set_master(dev);
-
-       host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev);
-       if (!host) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure");
-               goto err;
-       }
-       ohci = host->hostdata;
-       ohci->dev = dev;
-       ohci->host = host;
-       ohci->init_state = OHCI_INIT_ALLOC_HOST;
-       host->pdev = dev;
-       pci_set_drvdata(dev, ohci);
-
-       /* We don't want hardware swapping */
-       pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
-
-       /* Some oddball Apple controllers do not order the selfid
-        * properly, so we make up for it here.  */
-#ifndef __LITTLE_ENDIAN
-       /* XXX: Need a better way to check this. I'm wondering if we can
-        * read the values of the OHCI1394_PCI_HCI_Control and the
-        * noByteSwapData registers to see if they were not cleared to
-        * zero. Should this work? Obviously it's not defined what these
-        * registers will read when they aren't supported. Bleh! */
-       if (dev->vendor == PCI_VENDOR_ID_APPLE &&
-           dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
-               ohci->no_swap_incoming = 1;
-               ohci->selfid_swap = 0;
-       } else
-               ohci->selfid_swap = 1;
-#endif
-
-
-#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
-#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
-#endif
-
-       /* These chipsets require a bit of extra care when checking after
-        * a busreset.  */
-       if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
-            dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
-           (dev->vendor ==  PCI_VENDOR_ID_NVIDIA &&
-            dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
-               ohci->check_busreset = 1;
-
-       /* We hardwire the MMIO length, since some CardBus adaptors
-        * fail to report the right length.  Anyway, the ohci spec
-        * clearly says it's 2kb, so this shouldn't be a problem. */
-       ohci_base = pci_resource_start(dev, 0);
-       if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
-               PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
-                     (unsigned long long)pci_resource_len(dev, 0));
-
-       if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
-                               OHCI1394_DRIVER_NAME)) {
-               PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable",
-                       (unsigned long long)ohci_base,
-                       (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
-
-       ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
-       if (ohci->registers == NULL) {
-               PRINT_G(KERN_ERR, "Failed to remap registers");
-               err = -ENXIO;
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
-       DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers);
-
-       /* csr_config rom allocation */
-       ohci->csr_config_rom_cpu =
-               pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
-                                    &ohci->csr_config_rom_bus);
-       if (ohci->csr_config_rom_cpu == NULL) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom");
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
-
-       /* self-id dma buffer allocation */
-       ohci->selfid_buf_cpu =
-               pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
-                      &ohci->selfid_buf_bus);
-       if (ohci->selfid_buf_cpu == NULL) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer");
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
-
-       if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
-               PRINT(KERN_INFO, "SelfID buffer %p is not aligned on "
-                     "8Kb boundary... may cause problems on some CXD3222 chip",
-                     ohci->selfid_buf_cpu);
-
-       /* No self-id errors at startup */
-       ohci->self_id_errors = 0;
-
-       ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
-       /* AR DMA request context allocation */
-       if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
-                             DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
-                             AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
-                             OHCI1394_AsReqRcvContextBase) < 0) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context");
-               goto err;
-       }
-       /* AR DMA response context allocation */
-       if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
-                             DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
-                             AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
-                             OHCI1394_AsRspRcvContextBase) < 0) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context");
-               goto err;
-       }
-       /* AT DMA request context */
-       if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
-                             DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
-                             OHCI1394_AsReqTrContextBase) < 0) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context");
-               goto err;
-       }
-       /* AT DMA response context */
-       if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
-                             DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
-                             OHCI1394_AsRspTrContextBase) < 0) {
-               PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context");
-               goto err;
-       }
-       /* Start off with a soft reset, to clear everything to a sane
-        * state. */
-       ohci_soft_reset(ohci);
-
-       /* Now enable LPS, which we need in order to start accessing
-        * most of the registers.  In fact, on some cards (ALI M5251),
-        * accessing registers in the SClk domain without LPS enabled
-        * will lock up the machine. */
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
-       /* Disable and clear interrupts */
-       reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
-       /* Flush MMIO writes and wait to make sure we have full link enabled. */
-       reg_read(ohci, OHCI1394_Version);
-       msleep(50);
-
-       /* Determine the number of available IR and IT contexts. */
-       ohci->nb_iso_rcv_ctx =
-               get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-       ohci->nb_iso_xmit_ctx =
-               get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-
-       /* Set the usage bits for non-existent contexts so they can't
-        * be allocated */
-       ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
-       ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
-
-       INIT_LIST_HEAD(&ohci->iso_tasklet_list);
-       spin_lock_init(&ohci->iso_tasklet_list_lock);
-       ohci->ISO_channel_usage = 0;
-        spin_lock_init(&ohci->IR_channel_lock);
-
-       spin_lock_init(&ohci->event_lock);
-
-       /*
-        * interrupts are disabled, all right, but... due to IRQF_SHARED we
-        * might get called anyway.  We'll see no event, of course, but
-        * we need to get to that "no event", so enough should be initialized
-        * by that point.
-        */
-       err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
-                         OHCI1394_DRIVER_NAME, ohci);
-       if (err) {
-               PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_HAVE_IRQ;
-       ohci_initialize(ohci);
-
-       /* Set certain csr values */
-       host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
-       host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
-       host->csr.cyc_clk_acc = 100;  /* how do we determine clk accuracy? */
-       host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
-       host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
-
-       if (phys_dma) {
-               host->low_addr_space =
-                       (u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16;
-               if (!host->low_addr_space)
-                       host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED;
-       }
-       host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE;
-
-       /* Tell the highlevel this host is ready */
-       if (hpsb_add_host(host)) {
-               PRINT_G(KERN_ERR, "Failed to register host with highlevel");
-               goto err;
-       }
-       ohci->init_state = OHCI_INIT_DONE;
-
-       return 0;
-err:
-       ohci1394_pci_remove(dev);
-       return err;
-}
-
-static void ohci1394_pci_remove(struct pci_dev *dev)
-{
-       struct ti_ohci *ohci;
-       struct device *device;
-
-       ohci = pci_get_drvdata(dev);
-       if (!ohci)
-               goto out;
-
-       device = get_device(&ohci->host->device);
-
-       switch (ohci->init_state) {
-       case OHCI_INIT_DONE:
-               hpsb_remove_host(ohci->host);
-
-               /* Clear out BUS Options */
-               reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
-               reg_write(ohci, OHCI1394_BusOptions,
-                         (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
-                         0x00ff0000);
-               memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
-
-       case OHCI_INIT_HAVE_IRQ:
-               /* Clear interrupt registers */
-               reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-               reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
-               /* Disable IRM Contender */
-               set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-
-               /* Clear link control register */
-               reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-               /* Let all other nodes know to ignore us */
-               ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
-               /* Soft reset before we start - this disables
-                * interrupts and clears linkEnable and LPS. */
-               ohci_soft_reset(ohci);
-               free_irq(dev->irq, ohci);
-
-       case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
-               /* The ohci_soft_reset() stops all DMA contexts, so we
-                * dont need to do this.  */
-               free_dma_rcv_ctx(&ohci->ar_req_context);
-               free_dma_rcv_ctx(&ohci->ar_resp_context);
-               free_dma_trm_ctx(&ohci->at_req_context);
-               free_dma_trm_ctx(&ohci->at_resp_context);
-
-       case OHCI_INIT_HAVE_SELFID_BUFFER:
-               pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE,
-                                   ohci->selfid_buf_cpu,
-                                   ohci->selfid_buf_bus);
-
-       case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
-               pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN,
-                                   ohci->csr_config_rom_cpu,
-                                   ohci->csr_config_rom_bus);
-
-       case OHCI_INIT_HAVE_IOMAPPING:
-               iounmap(ohci->registers);
-
-       case OHCI_INIT_HAVE_MEM_REGION:
-               release_mem_region(pci_resource_start(dev, 0),
-                                  OHCI1394_REGISTER_SIZE);
-
-       case OHCI_INIT_ALLOC_HOST:
-               pci_set_drvdata(dev, NULL);
-       }
-
-       if (device)
-               put_device(device);
-out:
-       ohci1394_pmac_off(dev);
-}
-
-#ifdef CONFIG_PM
-static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       int err;
-       struct ti_ohci *ohci = pci_get_drvdata(dev);
-
-       if (!ohci) {
-               printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
-                      OHCI1394_DRIVER_NAME);
-               return -ENXIO;
-       }
-       DBGMSG("suspend called");
-
-       /* Clear the async DMA contexts and stop using the controller */
-       hpsb_bus_reset(ohci->host);
-
-       /* See ohci1394_pci_remove() for comments on this sequence */
-       reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
-       reg_write(ohci, OHCI1394_BusOptions,
-                 (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
-                 0x00ff0000);
-       reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-       set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-       reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-       ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-       ohci_soft_reset(ohci);
-
-       free_irq(dev->irq, ohci);
-       err = pci_save_state(dev);
-       if (err) {
-               PRINT(KERN_ERR, "pci_save_state failed with %d", err);
-               return err;
-       }
-       err = pci_set_power_state(dev, pci_choose_state(dev, state));
-       if (err)
-               DBGMSG("pci_set_power_state failed with %d", err);
-       ohci1394_pmac_off(dev);
-
-       return 0;
-}
-
-static int ohci1394_pci_resume(struct pci_dev *dev)
-{
-       int err;
-       struct ti_ohci *ohci = pci_get_drvdata(dev);
-
-       if (!ohci) {
-               printk(KERN_ERR "%s: tried to resume nonexisting host\n",
-                      OHCI1394_DRIVER_NAME);
-               return -ENXIO;
-       }
-       DBGMSG("resume called");
-
-       ohci1394_pmac_on(dev);
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-       err = pci_enable_device(dev);
-       if (err) {
-               PRINT(KERN_ERR, "pci_enable_device failed with %d", err);
-               return err;
-       }
-
-       /* See ohci1394_pci_probe() for comments on this sequence */
-       ohci_soft_reset(ohci);
-       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-       reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-       reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-       reg_read(ohci, OHCI1394_Version);
-       msleep(50);
-
-       err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
-                         OHCI1394_DRIVER_NAME, ohci);
-       if (err) {
-               PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
-               return err;
-       }
-
-       ohci_initialize(ohci);
-
-       hpsb_resume_host(ohci->host);
-       return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct pci_device_id ohci1394_pci_tbl[] = {
-       {
-               .class =        PCI_CLASS_SERIAL_FIREWIRE_OHCI,
-               .class_mask =   PCI_ANY_ID,
-               .vendor =       PCI_ANY_ID,
-               .device =       PCI_ANY_ID,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
-static struct pci_driver ohci1394_pci_driver = {
-       .name =         OHCI1394_DRIVER_NAME,
-       .id_table =     ohci1394_pci_tbl,
-       .probe =        ohci1394_pci_probe,
-       .remove =       ohci1394_pci_remove,
-#ifdef CONFIG_PM
-       .resume =       ohci1394_pci_resume,
-       .suspend =      ohci1394_pci_suspend,
-#endif
-};
-
-/***********************************
- * OHCI1394 Video Interface        *
- ***********************************/
-
-/* essentially the only purpose of this code is to allow another
-   module to hook into ohci's interrupt handler */
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
-       int i=0;
-
-       /* stop the channel program if it's still running */
-       reg_write(ohci, reg, 0x8000);
-
-       /* Wait until it effectively stops */
-       while (reg_read(ohci, reg) & 0x400) {
-               i++;
-               if (i>5000) {
-                       PRINT(KERN_ERR,
-                             "Runaway loop while stopping context: %s...", msg ? msg : "");
-                       return 1;
-               }
-
-               mb();
-               udelay(10);
-       }
-       if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg);
-       return 0;
-}
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
-                              void (*func)(unsigned long), unsigned long data)
-{
-       tasklet_init(&tasklet->tasklet, func, data);
-       tasklet->type = type;
-       /* We init the tasklet->link field, so we can list_del() it
-        * without worrying whether it was added to the list or not. */
-       INIT_LIST_HEAD(&tasklet->link);
-}
-
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
-                                 struct ohci1394_iso_tasklet *tasklet)
-{
-       unsigned long flags, *usage;
-       int n, i, r = -EBUSY;
-
-       if (tasklet->type == OHCI_ISO_TRANSMIT) {
-               n = ohci->nb_iso_xmit_ctx;
-               usage = &ohci->it_ctx_usage;
-       }
-       else {
-               n = ohci->nb_iso_rcv_ctx;
-               usage = &ohci->ir_ctx_usage;
-
-               /* only one receive context can be multichannel (OHCI sec 10.4.1) */
-               if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
-                       if (test_and_set_bit(0, &ohci->ir_multichannel_used)) {
-                               return r;
-                       }
-               }
-       }
-
-       spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-       for (i = 0; i < n; i++)
-               if (!test_and_set_bit(i, usage)) {
-                       tasklet->context = i;
-                       list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
-                       r = 0;
-                       break;
-               }
-
-       spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-
-       return r;
-}
-
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
-                                    struct ohci1394_iso_tasklet *tasklet)
-{
-       unsigned long flags;
-
-       tasklet_kill(&tasklet->tasklet);
-
-       spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-       if (tasklet->type == OHCI_ISO_TRANSMIT)
-               clear_bit(tasklet->context, &ohci->it_ctx_usage);
-       else {
-               clear_bit(tasklet->context, &ohci->ir_ctx_usage);
-
-               if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
-                       clear_bit(0, &ohci->ir_multichannel_used);
-               }
-       }
-
-       list_del(&tasklet->link);
-
-       spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
-
-/***********************************
- * General module initialization   *
- ***********************************/
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
-
-static void __exit ohci1394_cleanup (void)
-{
-       pci_unregister_driver(&ohci1394_pci_driver);
-}
-
-static int __init ohci1394_init(void)
-{
-       return pci_register_driver(&ohci1394_pci_driver);
-}
-
-module_init(ohci1394_init);
-module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
deleted file mode 100644 (file)
index 7fb8ab9..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ohci1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Gord Peters <GordPeters@smarttech.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _OHCI1394_H
-#define _OHCI1394_H
-
-#include "ieee1394_types.h"
-#include <asm/io.h>
-
-#define OHCI1394_DRIVER_NAME      "ohci1394"
-
-#define OHCI1394_MAX_AT_REQ_RETRIES    0xf
-#define OHCI1394_MAX_AT_RESP_RETRIES   0x2
-#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
-#define OHCI1394_MAX_SELF_ID_ERRORS    16
-
-#define AR_REQ_NUM_DESC                4               /* number of AR req descriptors */
-#define AR_REQ_BUF_SIZE                PAGE_SIZE       /* size of AR req buffers */
-#define AR_REQ_SPLIT_BUF_SIZE  PAGE_SIZE       /* split packet buffer */
-
-#define AR_RESP_NUM_DESC       4               /* number of AR resp descriptors */
-#define AR_RESP_BUF_SIZE       PAGE_SIZE       /* size of AR resp buffers */
-#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE       /* split packet buffer */
-
-#define IR_NUM_DESC            16              /* number of IR descriptors */
-#define IR_BUF_SIZE            PAGE_SIZE       /* 4096 bytes/buffer */
-#define IR_SPLIT_BUF_SIZE      PAGE_SIZE       /* split packet buffer */
-
-#define IT_NUM_DESC            16      /* number of IT descriptors */
-
-#define AT_REQ_NUM_DESC                32      /* number of AT req descriptors */
-#define AT_RESP_NUM_DESC       32      /* number of AT resp descriptors */
-
-#define OHCI_LOOP_COUNT                100     /* Number of loops for reg read waits */
-
-#define OHCI_CONFIG_ROM_LEN    1024    /* Length of the mapped configrom space */
-
-#define OHCI1394_SI_DMA_BUF_SIZE       8192 /* length of the selfid buffer */
-
-/* PCI configuration space addresses */
-#define OHCI1394_PCI_HCI_Control 0x40
-
-struct dma_cmd {
-        u32 control;
-        u32 address;
-        u32 branchAddress;
-        u32 status;
-};
-
-/*
- * FIXME:
- * It is important that a single at_dma_prg does not cross a page boundary
- * The proper way to do it would be to do the check dynamically as the
- * programs are inserted into the AT fifo.
- */
-struct at_dma_prg {
-       struct dma_cmd begin;
-       quadlet_t data[4];
-       struct dma_cmd end;
-       quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-/* identify whether a DMA context is asynchronous or isochronous */
-enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
-
-/* DMA receive context */
-struct dma_rcv_ctx {
-       struct ti_ohci *ohci;
-       enum context_type type;
-       int ctx;
-       unsigned int num_desc;
-
-       unsigned int buf_size;
-       unsigned int split_buf_size;
-
-       /* dma block descriptors */
-        struct dma_cmd **prg_cpu;
-        dma_addr_t *prg_bus;
-       struct pci_pool *prg_pool;
-
-       /* dma buffers */
-        quadlet_t **buf_cpu;
-        dma_addr_t *buf_bus;
-
-        unsigned int buf_ind;
-        unsigned int buf_offset;
-        quadlet_t *spb;
-        spinlock_t lock;
-        struct tasklet_struct task;
-       int ctrlClear;
-       int ctrlSet;
-       int cmdPtr;
-       int ctxtMatch;
-};
-
-/* DMA transmit context */
-struct dma_trm_ctx {
-       struct ti_ohci *ohci;
-       enum context_type type;
-       int ctx;
-       unsigned int num_desc;
-
-       /* dma block descriptors */
-        struct at_dma_prg **prg_cpu;
-       dma_addr_t *prg_bus;
-       struct pci_pool *prg_pool;
-
-        unsigned int prg_ind;
-        unsigned int sent_ind;
-       int free_prgs;
-        quadlet_t *branchAddrPtr;
-
-       /* list of packets inserted in the AT FIFO */
-       struct list_head fifo_list;
-
-       /* list of pending packets to be inserted in the AT FIFO */
-       struct list_head pending_list;
-
-        spinlock_t lock;
-        struct tasklet_struct task;
-       int ctrlClear;
-       int ctrlSet;
-       int cmdPtr;
-};
-
-struct ohci1394_iso_tasklet {
-       struct tasklet_struct tasklet;
-       struct list_head link;
-       int context;
-       enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
-              OHCI_ISO_MULTICHANNEL_RECEIVE } type;
-};
-
-struct ti_ohci {
-        struct pci_dev *dev;
-
-       enum {
-               OHCI_INIT_ALLOC_HOST,
-               OHCI_INIT_HAVE_MEM_REGION,
-               OHCI_INIT_HAVE_IOMAPPING,
-               OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
-               OHCI_INIT_HAVE_SELFID_BUFFER,
-               OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
-               OHCI_INIT_HAVE_IRQ,
-               OHCI_INIT_DONE,
-       } init_state;
-
-        /* remapped memory spaces */
-        void __iomem *registers;
-
-       /* dma buffer for self-id packets */
-        quadlet_t *selfid_buf_cpu;
-        dma_addr_t selfid_buf_bus;
-
-       /* buffer for csr config rom */
-        quadlet_t *csr_config_rom_cpu;
-        dma_addr_t csr_config_rom_bus;
-       int csr_config_rom_length;
-
-       unsigned int max_packet_size;
-
-        /* async receive */
-       struct dma_rcv_ctx ar_resp_context;
-       struct dma_rcv_ctx ar_req_context;
-
-       /* async transmit */
-       struct dma_trm_ctx at_resp_context;
-       struct dma_trm_ctx at_req_context;
-
-        /* iso receive */
-       int nb_iso_rcv_ctx;
-       unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
-       unsigned long ir_multichannel_used; /* ditto */
-        spinlock_t IR_channel_lock;
-
-        /* iso transmit */
-       int nb_iso_xmit_ctx;
-       unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
-
-        u64 ISO_channel_usage;
-
-        /* IEEE-1394 part follows */
-        struct hpsb_host *host;
-
-        int phyid, isroot;
-
-        spinlock_t phy_reg_lock;
-       spinlock_t event_lock;
-
-       int self_id_errors;
-
-       /* Tasklets for iso receive and transmit, used by video1394
-        * and dv1394 */
-       struct list_head iso_tasklet_list;
-       spinlock_t iso_tasklet_list_lock;
-
-       /* Swap the selfid buffer? */
-       unsigned int selfid_swap:1;
-       /* Some Apple chipset seem to swap incoming headers for us */
-       unsigned int no_swap_incoming:1;
-
-       /* Force extra paranoia checking on bus-reset handling */
-       unsigned int check_busreset:1;
-};
-
-static inline int cross_bound(unsigned long addr, unsigned int size)
-{
-       if (size == 0)
-               return 0;
-
-       if (size > PAGE_SIZE)
-               return 1;
-
-       if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
-               return 1;
-
-       return 0;
-}
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
-{
-        writel(data, ohci->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
-{
-        return readl(ohci->registers + offset);
-}
-
-
-/* 2 KiloBytes of register space */
-#define OHCI1394_REGISTER_SIZE                0x800
-
-/* Offsets relative to context bases defined below */
-
-#define OHCI1394_ContextControlSet            0x000
-#define OHCI1394_ContextControlClear          0x004
-#define OHCI1394_ContextCommandPtr            0x00C
-
-/* register map */
-#define OHCI1394_Version                      0x000
-#define OHCI1394_GUID_ROM                     0x004
-#define OHCI1394_ATRetries                    0x008
-#define OHCI1394_CSRData                      0x00C
-#define OHCI1394_CSRCompareData               0x010
-#define OHCI1394_CSRControl                   0x014
-#define OHCI1394_ConfigROMhdr                 0x018
-#define OHCI1394_BusID                        0x01C
-#define OHCI1394_BusOptions                   0x020
-#define OHCI1394_GUIDHi                       0x024
-#define OHCI1394_GUIDLo                       0x028
-#define OHCI1394_ConfigROMmap                 0x034
-#define OHCI1394_PostedWriteAddressLo         0x038
-#define OHCI1394_PostedWriteAddressHi         0x03C
-#define OHCI1394_VendorID                     0x040
-#define OHCI1394_HCControlSet                 0x050
-#define OHCI1394_HCControlClear               0x054
-#define  OHCI1394_HCControl_noByteSwap         0x40000000
-#define  OHCI1394_HCControl_programPhyEnable   0x00800000
-#define  OHCI1394_HCControl_aPhyEnhanceEnable  0x00400000
-#define  OHCI1394_HCControl_LPS                        0x00080000
-#define  OHCI1394_HCControl_postedWriteEnable  0x00040000
-#define  OHCI1394_HCControl_linkEnable         0x00020000
-#define  OHCI1394_HCControl_softReset          0x00010000
-#define OHCI1394_SelfIDBuffer                 0x064
-#define OHCI1394_SelfIDCount                  0x068
-#define OHCI1394_IRMultiChanMaskHiSet         0x070
-#define OHCI1394_IRMultiChanMaskHiClear       0x074
-#define OHCI1394_IRMultiChanMaskLoSet         0x078
-#define OHCI1394_IRMultiChanMaskLoClear       0x07C
-#define OHCI1394_IntEventSet                  0x080
-#define OHCI1394_IntEventClear                0x084
-#define OHCI1394_IntMaskSet                   0x088
-#define OHCI1394_IntMaskClear                 0x08C
-#define OHCI1394_IsoXmitIntEventSet           0x090
-#define OHCI1394_IsoXmitIntEventClear         0x094
-#define OHCI1394_IsoXmitIntMaskSet            0x098
-#define OHCI1394_IsoXmitIntMaskClear          0x09C
-#define OHCI1394_IsoRecvIntEventSet           0x0A0
-#define OHCI1394_IsoRecvIntEventClear         0x0A4
-#define OHCI1394_IsoRecvIntMaskSet            0x0A8
-#define OHCI1394_IsoRecvIntMaskClear          0x0AC
-#define OHCI1394_InitialBandwidthAvailable    0x0B0
-#define OHCI1394_InitialChannelsAvailableHi   0x0B4
-#define OHCI1394_InitialChannelsAvailableLo   0x0B8
-#define OHCI1394_FairnessControl              0x0DC
-#define OHCI1394_LinkControlSet               0x0E0
-#define OHCI1394_LinkControlClear             0x0E4
-#define  OHCI1394_LinkControl_RcvSelfID                0x00000200
-#define  OHCI1394_LinkControl_RcvPhyPkt                0x00000400
-#define  OHCI1394_LinkControl_CycleTimerEnable 0x00100000
-#define  OHCI1394_LinkControl_CycleMaster      0x00200000
-#define  OHCI1394_LinkControl_CycleSource      0x00400000
-#define OHCI1394_NodeID                       0x0E8
-#define OHCI1394_PhyControl                   0x0EC
-#define OHCI1394_IsochronousCycleTimer        0x0F0
-#define OHCI1394_AsReqFilterHiSet             0x100
-#define OHCI1394_AsReqFilterHiClear           0x104
-#define OHCI1394_AsReqFilterLoSet             0x108
-#define OHCI1394_AsReqFilterLoClear           0x10C
-#define OHCI1394_PhyReqFilterHiSet            0x110
-#define OHCI1394_PhyReqFilterHiClear          0x114
-#define OHCI1394_PhyReqFilterLoSet            0x118
-#define OHCI1394_PhyReqFilterLoClear          0x11C
-#define OHCI1394_PhyUpperBound                0x120
-
-#define OHCI1394_AsReqTrContextBase           0x180
-#define OHCI1394_AsReqTrContextControlSet     0x180
-#define OHCI1394_AsReqTrContextControlClear   0x184
-#define OHCI1394_AsReqTrCommandPtr            0x18C
-
-#define OHCI1394_AsRspTrContextBase           0x1A0
-#define OHCI1394_AsRspTrContextControlSet     0x1A0
-#define OHCI1394_AsRspTrContextControlClear   0x1A4
-#define OHCI1394_AsRspTrCommandPtr            0x1AC
-
-#define OHCI1394_AsReqRcvContextBase          0x1C0
-#define OHCI1394_AsReqRcvContextControlSet    0x1C0
-#define OHCI1394_AsReqRcvContextControlClear  0x1C4
-#define OHCI1394_AsReqRcvCommandPtr           0x1CC
-
-#define OHCI1394_AsRspRcvContextBase          0x1E0
-#define OHCI1394_AsRspRcvContextControlSet    0x1E0
-#define OHCI1394_AsRspRcvContextControlClear  0x1E4
-#define OHCI1394_AsRspRcvCommandPtr           0x1EC
-
-/* Isochronous transmit registers */
-/* Add (16 * n) for context n */
-#define OHCI1394_IsoXmitContextBase           0x200
-#define OHCI1394_IsoXmitContextControlSet     0x200
-#define OHCI1394_IsoXmitContextControlClear   0x204
-#define OHCI1394_IsoXmitCommandPtr            0x20C
-
-/* Isochronous receive registers */
-/* Add (32 * n) for context n */
-#define OHCI1394_IsoRcvContextBase            0x400
-#define OHCI1394_IsoRcvContextControlSet      0x400
-#define OHCI1394_IsoRcvContextControlClear    0x404
-#define OHCI1394_IsoRcvCommandPtr             0x40C
-#define OHCI1394_IsoRcvContextMatch           0x410
-
-/* Interrupts Mask/Events */
-
-#define OHCI1394_reqTxComplete           0x00000001
-#define OHCI1394_respTxComplete          0x00000002
-#define OHCI1394_ARRQ                    0x00000004
-#define OHCI1394_ARRS                    0x00000008
-#define OHCI1394_RQPkt                   0x00000010
-#define OHCI1394_RSPkt                   0x00000020
-#define OHCI1394_isochTx                 0x00000040
-#define OHCI1394_isochRx                 0x00000080
-#define OHCI1394_postedWriteErr          0x00000100
-#define OHCI1394_lockRespErr             0x00000200
-#define OHCI1394_selfIDComplete          0x00010000
-#define OHCI1394_busReset                0x00020000
-#define OHCI1394_phy                     0x00080000
-#define OHCI1394_cycleSynch              0x00100000
-#define OHCI1394_cycle64Seconds          0x00200000
-#define OHCI1394_cycleLost               0x00400000
-#define OHCI1394_cycleInconsistent       0x00800000
-#define OHCI1394_unrecoverableError      0x01000000
-#define OHCI1394_cycleTooLong            0x02000000
-#define OHCI1394_phyRegRcvd              0x04000000
-#define OHCI1394_masterIntEnable         0x80000000
-
-/* DMA Control flags */
-#define DMA_CTL_OUTPUT_MORE              0x00000000
-#define DMA_CTL_OUTPUT_LAST              0x10000000
-#define DMA_CTL_INPUT_MORE               0x20000000
-#define DMA_CTL_INPUT_LAST               0x30000000
-#define DMA_CTL_UPDATE                   0x08000000
-#define DMA_CTL_IMMEDIATE                0x02000000
-#define DMA_CTL_IRQ                      0x00300000
-#define DMA_CTL_BRANCH                   0x000c0000
-#define DMA_CTL_WAIT                     0x00030000
-
-/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
-#define EVT_NO_STATUS          0x0     /* No event status */
-#define EVT_RESERVED_A         0x1     /* Reserved, not used !!! */
-#define EVT_LONG_PACKET                0x2     /* The revc data was longer than the buf */
-#define EVT_MISSING_ACK                0x3     /* A subaction gap was detected before an ack
-                                          arrived, or recv'd ack had a parity error */
-#define EVT_UNDERRUN           0x4     /* Underrun on corresponding FIFO, packet
-                                          truncated */
-#define EVT_OVERRUN            0x5     /* A recv FIFO overflowed on reception of ISO
-                                          packet */
-#define EVT_DESCRIPTOR_READ    0x6     /* An unrecoverable error occurred while host was
-                                          reading a descriptor block */
-#define EVT_DATA_READ          0x7     /* An error occurred while host controller was
-                                          attempting to read from host memory in the data
-                                          stage of descriptor processing */
-#define EVT_DATA_WRITE         0x8     /* An error occurred while host controller was
-                                          attempting to write either during the data stage
-                                          of descriptor processing, or when processing a single
-                                          16-bit host memory write */
-#define EVT_BUS_RESET          0x9     /* Identifies a PHY packet in the recv buffer as
-                                          being a synthesized bus reset packet */
-#define EVT_TIMEOUT            0xa     /* Indicates that the asynchronous transmit response
-                                          packet expired and was not transmitted, or that an
-                                          IT DMA context experienced a skip processing overflow */
-#define EVT_TCODE_ERR          0xb     /* A bad tCode is associated with this packet.
-                                          The packet was flushed */
-#define EVT_RESERVED_B         0xc     /* Reserved, not used !!! */
-#define EVT_RESERVED_C         0xd     /* Reserved, not used !!! */
-#define EVT_UNKNOWN            0xe     /* An error condition has occurred that cannot be
-                                          represented by any other event codes defined herein. */
-#define EVT_FLUSHED            0xf     /* Send by the link side of output FIFO when asynchronous
-                                          packets are being flushed due to a bus reset. */
-
-#define OHCI1394_TCODE_PHY               0xE
-
-/* Node offset map (phys DMA area, posted write area).
- * The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
- * be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
- * OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
- * constants given by the OHCI spec.
- */
-#define OHCI1394_PHYS_UPPER_BOUND_FIXED                0x000100000000ULL /* 4 GB */
-#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED   0x010000000000ULL /* 1 TB */
-#define OHCI1394_MIDDLE_ADDRESS_SPACE          0xffff00000000ULL
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
-                              int type,
-                              void (*func)(unsigned long),
-                              unsigned long data);
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
-                                 struct ohci1394_iso_tasklet *tasklet);
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
-                                    struct ohci1394_iso_tasklet *tasklet);
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
-struct ti_ohci *ohci1394_get_struct(int card_num);
-
-#endif
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
deleted file mode 100644 (file)
index bf47fee..0000000
+++ /dev/null
@@ -1,1554 +0,0 @@
-/*
- * pcilynx.c - Texas Instruments PCILynx driver
- * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
- *                         Stephan Linz <linz@mazet.de>
- *                         Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- */
-
-/*
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        reading bus info block (containing GUID) from serial
- *            eeprom via i2c and storing it in config ROM
- *        Reworked code for initiating bus resets
- *            (long, short, with or without hold-off)
- *        Enhancements in async and iso send code
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kdev_t.h>
-#include <linux/dma-mapping.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "pcilynx.h"
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-#else
-#define PRINT_GD(level, fmt, args...) do {} while (0)
-#define PRINTD(level, card, fmt, args...) do {} while (0)
-#endif
-
-
-/* Module Parameters */
-static int skip_eeprom;
-module_param(skip_eeprom, int, 0444);
-MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
-
-
-static struct hpsb_host_driver lynx_driver;
-static unsigned int card_id;
-
-
-
-/*
- * I2C stuff
- */
-
-/* the i2c stuff was inspired by i2c-philips-par.c */
-
-static void bit_setscl(void *data, int state)
-{
-       if (state) {
-                 ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
-       } else {
-                 ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
-       }
-       reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static void bit_setsda(void *data, int state)
-{
-       if (state) {
-                 ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
-       } else {
-                 ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
-       }
-       reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static int bit_getscl(void *data)
-{
-       return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
-}
-
-static int bit_getsda(void *data)
-{
-       return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
-}
-
-static struct i2c_algo_bit_data bit_data = {
-       .setsda                 = bit_setsda,
-       .setscl                 = bit_setscl,
-       .getsda                 = bit_getsda,
-       .getscl                 = bit_getscl,
-       .udelay                 = 5,
-       .timeout                = 100,
-};
-
-
-/*
- * PCL handling functions.
- */
-
-static pcl_t alloc_pcl(struct ti_lynx *lynx)
-{
-        u8 m;
-        int i, j;
-
-        spin_lock(&lynx->lock);
-        /* FIXME - use ffz() to make this readable */
-        for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {
-                m = lynx->pcl_bmap[i];
-                for (j = 0; j < 8; j++) {
-                        if (m & 1<<j) {
-                                continue;
-                        }
-                        m |= 1<<j;
-                        lynx->pcl_bmap[i] = m;
-                        spin_unlock(&lynx->lock);
-                        return 8 * i + j;
-                }
-        }
-        spin_unlock(&lynx->lock);
-
-        return -1;
-}
-
-
-#if 0
-static void free_pcl(struct ti_lynx *lynx, pcl_t pclid)
-{
-        int off, bit;
-
-        off = pclid / 8;
-        bit = pclid % 8;
-
-        if (pclid < 0) {
-                return;
-        }
-
-        spin_lock(&lynx->lock);
-        if (lynx->pcl_bmap[off] & 1<<bit) {
-                lynx->pcl_bmap[off] &= ~(1<<bit);
-        } else {
-                PRINT(KERN_ERR, lynx->id,
-                      "attempted to free unallocated PCL %d", pclid);
-        }
-        spin_unlock(&lynx->lock);
-}
-
-/* functions useful for debugging */
-static void pretty_print_pcl(const struct ti_pcl *pcl)
-{
-        int i;
-
-        printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",
-               pcl->next, pcl->user_data, pcl->pcl_status,
-               pcl->remaining_transfer_count, pcl->next_data_buffer);
-
-        printk("PCL");
-        for (i=0; i<13; i++) {
-                printk(" c%x:%08x d%x:%08x",
-                       i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);
-                if (!(i & 0x3) && (i != 12)) printk("\nPCL");
-        }
-        printk("\n");
-}
-
-static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        struct ti_pcl pcl;
-
-        get_pcl(lynx, pclid, &pcl);
-        pretty_print_pcl(&pcl);
-}
-#endif
-
-
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-
-static int get_phy_reg(struct ti_lynx *lynx, int addr)
-{
-        int retval;
-        int i = 0;
-
-        unsigned long flags;
-
-        if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id,
-                      "%s: PHY register address %d out of range",
-                     __func__, addr);
-                return -1;
-        }
-
-        spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
-        reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));
-        do {
-                retval = reg_read(lynx, LINK_PHY);
-
-                if (i > 10000) {
-                        PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
-                             __func__);
-                        retval = -1;
-                        break;
-                }
-                i++;
-        } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));
-
-        reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);
-        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
-        if (retval != -1) {
-                return retval & 0xff;
-        } else {
-                return -1;
-        }
-}
-
-static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
-{
-        unsigned long flags;
-
-        if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id,
-                     "%s: PHY register address %d out of range", __func__, addr);
-                return -1;
-        }
-
-        if (val > 0xff) {
-                PRINT(KERN_ERR, lynx->id,
-                     "%s: PHY register value %d out of range", __func__, val);
-                return -1;
-        }
-
-        spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
-        reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)
-                  | LINK_PHY_WDATA(val));
-
-        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
-        return 0;
-}
-
-static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
-{
-        int reg;
-
-        if (page > 7) {
-                PRINT(KERN_ERR, lynx->id,
-                     "%s: PHY page %d out of range", __func__, page);
-                return -1;
-        }
-
-        reg = get_phy_reg(lynx, 7);
-        if (reg != -1) {
-                reg &= 0x1f;
-                reg |= (page << 5);
-                set_phy_reg(lynx, 7, reg);
-                return 0;
-        } else {
-                return -1;
-        }
-}
-
-#if 0 /* not needed at this time */
-static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
-{
-        int reg;
-
-        if (port > 15) {
-                PRINT(KERN_ERR, lynx->id,
-                     "%s: PHY port %d out of range", __func__, port);
-                return -1;
-        }
-
-        reg = get_phy_reg(lynx, 7);
-        if (reg != -1) {
-                reg &= 0xf0;
-                reg |= port;
-                set_phy_reg(lynx, 7, reg);
-                return 0;
-        } else {
-                return -1;
-        }
-}
-#endif
-
-static u32 get_phy_vendorid(struct ti_lynx *lynx)
-{
-        u32 pvid = 0;
-        sel_phy_reg_page(lynx, 1);
-        pvid |= (get_phy_reg(lynx, 10) << 16);
-        pvid |= (get_phy_reg(lynx, 11) << 8);
-        pvid |= get_phy_reg(lynx, 12);
-        PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);
-        return pvid;
-}
-
-static u32 get_phy_productid(struct ti_lynx *lynx)
-{
-        u32 id = 0;
-        sel_phy_reg_page(lynx, 1);
-        id |= (get_phy_reg(lynx, 13) << 16);
-        id |= (get_phy_reg(lynx, 14) << 8);
-        id |= get_phy_reg(lynx, 15);
-        PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);
-        return id;
-}
-
-static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
-                                     struct hpsb_host *host)
-{
-        quadlet_t lsid;
-        char phyreg[7];
-        int i;
-
-        phyreg[0] = lynx->phy_reg0;
-        for (i = 1; i < 7; i++) {
-                phyreg[i] = get_phy_reg(lynx, i);
-        }
-
-        /* FIXME? We assume a TSB21LV03A phy here.  This code doesn't support
-           more than 3 ports on the PHY anyway. */
-
-        lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
-        lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
-        lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
-       if (!hpsb_disable_irm)
-               lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
-        /* lsid |= 1 << 11; *//* set contender (hack) */
-        lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
-
-        for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */
-                if (phyreg[3 + i] & 0x4) {
-                        lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
-                                << (6 - i*2);
-                } else {
-                        lsid |= 1 << (6 - i*2);
-                }
-        }
-
-        cpu_to_be32s(&lsid);
-        PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
-        return lsid;
-}
-
-static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host)
-{
-        quadlet_t *q = lynx->rcv_page;
-        int phyid, isroot, size;
-        quadlet_t lsid = 0;
-        int i;
-
-        if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return;
-
-        size = lynx->selfid_size;
-        phyid = lynx->phy_reg0;
-
-        i = (size > 16 ? 16 : size) / 4 - 1;
-        while (i >= 0) {
-                cpu_to_be32s(&q[i]);
-                i--;
-        }
-
-        if (!lynx->phyic.reg_1394a) {
-                lsid = generate_own_selfid(lynx, host);
-        }
-
-        isroot = (phyid & 2) != 0;
-        phyid >>= 2;
-        PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",
-              phyid, (isroot ? "root" : "not root"));
-        reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);
-
-        if (!lynx->phyic.reg_1394a && !size) {
-                hpsb_selfid_received(host, lsid);
-        }
-
-        while (size > 0) {
-                struct selfid *sid = (struct selfid *)q;
-
-                if (!lynx->phyic.reg_1394a && !sid->extended
-                    && (sid->phy_id == (phyid + 1))) {
-                        hpsb_selfid_received(host, lsid);
-                }
-
-                if (q[0] == ~q[1]) {
-                        PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd",
-                              q[0]);
-                        hpsb_selfid_received(host, q[0]);
-                } else {
-                        PRINT(KERN_INFO, lynx->id,
-                              "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
-                }
-                q += 2;
-                size -= 8;
-        }
-
-        if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {
-                hpsb_selfid_received(host, lsid);
-        }
-
-        hpsb_selfid_complete(host, phyid, isroot);
-
-        if (host->in_bus_reset) return; /* in bus reset again */
-
-        if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here
-        reg_set_bits(lynx, LINK_CONTROL,
-                     LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN
-                     | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);
-}
-
-
-
-/* This must be called with the respective queue_lock held. */
-static void send_next(struct ti_lynx *lynx, int what)
-{
-        struct ti_pcl pcl;
-        struct lynx_send_data *d;
-        struct hpsb_packet *packet;
-
-#if 0 /* has been removed from ieee1394 core */
-        d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
-#else
-       d = &lynx->async;
-#endif
-        if (!list_empty(&d->pcl_queue)) {
-                PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
-                BUG();
-        }
-
-        packet = driver_packet(d->queue.next);
-       list_move_tail(&packet->driver_list, &d->pcl_queue);
-
-        d->header_dma = pci_map_single(lynx->dev, packet->header,
-                                       packet->header_size, PCI_DMA_TODEVICE);
-        if (packet->data_size) {
-                d->data_dma = pci_map_single(lynx->dev, packet->data,
-                                             packet->data_size,
-                                             PCI_DMA_TODEVICE);
-        } else {
-                d->data_dma = 0;
-        }
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.pcl_status = 0;
-        pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[0].pointer = d->header_dma;
-        pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
-        pcl.buffer[1].pointer = d->data_dma;
-
-        switch (packet->type) {
-        case hpsb_async:
-                pcl.buffer[0].control |= PCL_CMD_XMT;
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case hpsb_iso:
-                pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
-                break;
-#endif
-        case hpsb_raw:
-                pcl.buffer[0].control |= PCL_CMD_UNFXMT;
-                break;
-        }
-
-        put_pcl(lynx, d->pcl, &pcl);
-        run_pcl(lynx, d->pcl_start, d->channel);
-}
-
-
-/* called from subsystem core */
-static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        struct lynx_send_data *d;
-        unsigned long flags;
-
-        if (packet->data_size >= 4096) {
-                PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)",
-                      packet->data_size);
-                return -EOVERFLOW;
-        }
-
-        switch (packet->type) {
-        case hpsb_async:
-        case hpsb_raw:
-                d = &lynx->async;
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case hpsb_iso:
-                d = &lynx->iso_send;
-                break;
-#endif
-        default:
-                PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
-                      packet->type);
-                return -EINVAL;
-        }
-
-        if (packet->tcode == TCODE_WRITEQ
-            || packet->tcode == TCODE_READQ_RESPONSE) {
-                cpu_to_be32s(&packet->header[3]);
-        }
-
-        spin_lock_irqsave(&d->queue_lock, flags);
-
-       list_add_tail(&packet->driver_list, &d->queue);
-       if (list_empty(&d->pcl_queue))
-                send_next(lynx, packet->type);
-
-        spin_unlock_irqrestore(&d->queue_lock, flags);
-
-        return 0;
-}
-
-
-/* called from subsystem core */
-static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        int retval = 0;
-        struct hpsb_packet *packet;
-       LIST_HEAD(packet_list);
-        unsigned long flags;
-       int phy_reg;
-
-        switch (cmd) {
-        case RESET_BUS:
-                if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) {
-                        retval = 0;
-                        break;
-                }
-
-               switch (arg) {
-               case SHORT_RESET:
-                       if (lynx->phyic.reg_1394a) {
-                               phy_reg = get_phy_reg(lynx, 5);
-                               if (phy_reg == -1) {
-                                       PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                                       retval = -1;
-                                       break;
-                               }
-                               phy_reg |= 0x40;
-
-                               PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request");
-
-                               lynx->selfid_size = -1;
-                               lynx->phy_reg0 = -1;
-                               set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-                               break;
-                       } else {
-                               PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-                               /* fall through to long bus reset */
-                       }
-               case LONG_RESET:
-                       phy_reg = get_phy_reg(lynx, 1);
-                       if (phy_reg == -1) {
-                               PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                               retval = -1;
-                               break;
-                       }
-                       phy_reg |= 0x40;
-
-                       PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request");
-
-                       lynx->selfid_size = -1;
-                       lynx->phy_reg0 = -1;
-                       set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
-                       break;
-               case SHORT_RESET_NO_FORCE_ROOT:
-                       if (lynx->phyic.reg_1394a) {
-                               phy_reg = get_phy_reg(lynx, 1);
-                               if (phy_reg == -1) {
-                                       PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                                       retval = -1;
-                                       break;
-                               }
-                               if (phy_reg & 0x80) {
-                                       phy_reg &= ~0x80;
-                                       set_phy_reg(lynx, 1, phy_reg); /* clear RHB */
-                               }
-
-                               phy_reg = get_phy_reg(lynx, 5);
-                               if (phy_reg == -1) {
-                                       PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                                       retval = -1;
-                                       break;
-                               }
-                               phy_reg |= 0x40;
-
-                               PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request");
-
-                               lynx->selfid_size = -1;
-                               lynx->phy_reg0 = -1;
-                               set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-                               break;
-                       } else {
-                               PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-                               /* fall through to long bus reset */
-                       }
-               case LONG_RESET_NO_FORCE_ROOT:
-                       phy_reg = get_phy_reg(lynx, 1);
-                       if (phy_reg == -1) {
-                               PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                               retval = -1;
-                               break;
-                       }
-                       phy_reg &= ~0x80;
-                       phy_reg |= 0x40;
-
-                       PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request");
-
-                       lynx->selfid_size = -1;
-                       lynx->phy_reg0 = -1;
-                       set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
-                       break;
-               case SHORT_RESET_FORCE_ROOT:
-                       if (lynx->phyic.reg_1394a) {
-                               phy_reg = get_phy_reg(lynx, 1);
-                               if (phy_reg == -1) {
-                                       PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                                       retval = -1;
-                                       break;
-                               }
-                               if (!(phy_reg & 0x80)) {
-                                       phy_reg |= 0x80;
-                                       set_phy_reg(lynx, 1, phy_reg); /* set RHB */
-                               }
-
-                               phy_reg = get_phy_reg(lynx, 5);
-                               if (phy_reg == -1) {
-                                       PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                                       retval = -1;
-                                       break;
-                               }
-                               phy_reg |= 0x40;
-
-                               PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request");
-
-                               lynx->selfid_size = -1;
-                               lynx->phy_reg0 = -1;
-                               set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-                               break;
-                       } else {
-                               PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-                               /* fall through to long bus reset */
-                       }
-               case LONG_RESET_FORCE_ROOT:
-                       phy_reg = get_phy_reg(lynx, 1);
-                       if (phy_reg == -1) {
-                               PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-                               retval = -1;
-                               break;
-                       }
-                       phy_reg |= 0xc0;
-
-                       PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request");
-
-                       lynx->selfid_size = -1;
-                       lynx->phy_reg0 = -1;
-                       set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */
-                       break;
-               default:
-                       PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg);
-                       retval = -1;
-               }
-
-                break;
-
-        case GET_CYCLE_COUNTER:
-                retval = reg_read(lynx, CYCLE_TIMER);
-                break;
-
-        case SET_CYCLE_COUNTER:
-                reg_write(lynx, CYCLE_TIMER, arg);
-                break;
-
-        case SET_BUS_ID:
-                reg_write(lynx, LINK_ID,
-                          (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));
-                break;
-
-        case ACT_CYCLE_MASTER:
-                if (arg) {
-                        reg_set_bits(lynx, LINK_CONTROL,
-                                     LINK_CONTROL_CYCMASTER);
-                } else {
-                        reg_clear_bits(lynx, LINK_CONTROL,
-                                       LINK_CONTROL_CYCMASTER);
-                }
-                break;
-
-        case CANCEL_REQUESTS:
-                spin_lock_irqsave(&lynx->async.queue_lock, flags);
-
-                reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);
-               list_splice_init(&lynx->async.queue, &packet_list);
-
-                if (list_empty(&lynx->async.pcl_queue)) {
-                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-                        PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-
-                        PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
-
-                        get_pcl(lynx, lynx->async.pcl, &pcl);
-
-                        packet = driver_packet(lynx->async.pcl_queue.next);
-                       list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-
-                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
-                                ack = ACKX_ABORTED;
-                        }
-                        hpsb_packet_sent(host, packet, ack);
-                }
-
-               while (!list_empty(&packet_list)) {
-                       packet = driver_packet(packet_list.next);
-                       list_del_init(&packet->driver_list);
-                       hpsb_packet_sent(host, packet, ACKX_ABORTED);
-               }
-
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case ISO_LISTEN_CHANNEL:
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-                if (lynx->iso_rcv.chan_count++ == 0) {
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                                  DMA_WORD1_CMP_ENABLE_MASTER);
-                }
-
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-                break;
-
-        case ISO_UNLISTEN_CHANNEL:
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-                if (--lynx->iso_rcv.chan_count == 0) {
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                                  0);
-                }
-
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-                break;
-#endif
-        default:
-                PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
-                retval = -1;
-        }
-
-        return retval;
-}
-
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-
-static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
-{
-        struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
-        struct hpsb_host *host = lynx->host;
-        u32 intmask;
-        u32 linkint;
-
-        linkint = reg_read(lynx, LINK_INT_STATUS);
-        intmask = reg_read(lynx, PCI_INT_STATUS);
-
-        if (!(intmask & PCI_INT_INT_PEND))
-               return IRQ_NONE;
-
-        PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,
-               linkint);
-
-        reg_write(lynx, LINK_INT_STATUS, linkint);
-        reg_write(lynx, PCI_INT_STATUS, intmask);
-
-        if (intmask & PCI_INT_1394) {
-                if (linkint & LINK_INT_PHY_TIMEOUT) {
-                        PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
-                }
-                if (linkint & LINK_INT_PHY_BUSRESET) {
-                        PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
-                        lynx->selfid_size = -1;
-                        lynx->phy_reg0 = -1;
-                        if (!host->in_bus_reset)
-                                hpsb_bus_reset(host);
-                }
-                if (linkint & LINK_INT_PHY_REG_RCVD) {
-                        u32 reg;
-
-                        spin_lock(&lynx->phy_reg_lock);
-                        reg = reg_read(lynx, LINK_PHY);
-                        spin_unlock(&lynx->phy_reg_lock);
-
-                        if (!host->in_bus_reset) {
-                                PRINT(KERN_INFO, lynx->id,
-                                      "phy reg received without reset");
-                        } else if (reg & 0xf00) {
-                                PRINT(KERN_INFO, lynx->id,
-                                      "unsolicited phy reg %d received",
-                                      (reg >> 8) & 0xf);
-                        } else {
-                                lynx->phy_reg0 = reg & 0xff;
-                                handle_selfid(lynx, host);
-                        }
-                }
-                if (linkint & LINK_INT_ISO_STUCK) {
-                        PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");
-                }
-                if (linkint & LINK_INT_ASYNC_STUCK) {
-                        PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");
-                }
-                if (linkint & LINK_INT_SENT_REJECT) {
-                        PRINT(KERN_INFO, lynx->id, "sent reject");
-                }
-                if (linkint & LINK_INT_TX_INVALID_TC) {
-                        PRINT(KERN_INFO, lynx->id, "invalid transaction code");
-                }
-                if (linkint & LINK_INT_GRF_OVERFLOW) {
-                        /* flush FIFO if overflow happens during reset */
-                        if (host->in_bus_reset)
-                                reg_write(lynx, FIFO_CONTROL,
-                                          FIFO_CONTROL_GRF_FLUSH);
-                        PRINT(KERN_INFO, lynx->id, "GRF overflow");
-                }
-                if (linkint & LINK_INT_ITF_UNDERFLOW) {
-                        PRINT(KERN_INFO, lynx->id, "ITF underflow");
-                }
-                if (linkint & LINK_INT_ATF_UNDERFLOW) {
-                        PRINT(KERN_INFO, lynx->id, "ATF underflow");
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
-                PRINTD(KERN_DEBUG, lynx->id, "iso receive");
-
-                spin_lock(&lynx->iso_rcv.lock);
-
-                lynx->iso_rcv.stat[lynx->iso_rcv.next] =
-                        reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));
-
-                lynx->iso_rcv.used++;
-                lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;
-
-                if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
-                    || !lynx->iso_rcv.chan_count) {
-                        PRINTD(KERN_DEBUG, lynx->id, "stopped");
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-                }
-
-                run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,
-                            CHANNEL_ISO_RCV);
-
-                spin_unlock(&lynx->iso_rcv.lock);
-
-               tasklet_schedule(&lynx->iso_rcv.tq);
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {
-                PRINTD(KERN_DEBUG, lynx->id, "async sent");
-                spin_lock(&lynx->async.queue_lock);
-
-                if (list_empty(&lynx->async.pcl_queue)) {
-                        spin_unlock(&lynx->async.queue_lock);
-                        PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-                        struct hpsb_packet *packet;
-
-                        get_pcl(lynx, lynx->async.pcl, &pcl);
-
-                        packet = driver_packet(lynx->async.pcl_queue.next);
-                        list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-
-                        if (!list_empty(&lynx->async.queue)) {
-                                send_next(lynx, hpsb_async);
-                        }
-
-                        spin_unlock(&lynx->async.queue_lock);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
-                                ack = ACKX_SEND_ERROR;
-                        }
-                        hpsb_packet_sent(host, packet, ack);
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {
-                PRINTD(KERN_DEBUG, lynx->id, "iso sent");
-                spin_lock(&lynx->iso_send.queue_lock);
-
-                if (list_empty(&lynx->iso_send.pcl_queue)) {
-                        spin_unlock(&lynx->iso_send.queue_lock);
-                        PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-                        struct hpsb_packet *packet;
-
-                        get_pcl(lynx, lynx->iso_send.pcl, &pcl);
-
-                        packet = driver_packet(lynx->iso_send.pcl_queue.next);
-                        list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-#if 0 /* has been removed from ieee1394 core */
-                        if (!list_empty(&lynx->iso_send.queue)) {
-                                send_next(lynx, hpsb_iso);
-                        }
-#endif
-                        spin_unlock(&lynx->iso_send.queue_lock);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "iso send packet was not completed");
-                                ack = ACKX_SEND_ERROR;
-                        }
-
-                        hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {
-                /* general receive DMA completed */
-                int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV));
-
-                PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
-                       stat & 0x1fff);
-
-                if (stat & DMA_CHAN_STAT_SELFID) {
-                        lynx->selfid_size = stat & 0x1fff;
-                        handle_selfid(lynx, host);
-                } else {
-                        quadlet_t *q_data = lynx->rcv_page;
-                        if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
-                            || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
-                                cpu_to_be32s(q_data + 3);
-                        }
-                        hpsb_packet_received(host, q_data, stat & 0x1fff, 0);
-                }
-
-                run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-        }
-
-       return IRQ_HANDLED;
-}
-
-
-static void iso_rcv_bh(struct ti_lynx *lynx)
-{
-        unsigned int idx;
-        quadlet_t *data;
-        unsigned long flags;
-
-        spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-        while (lynx->iso_rcv.used) {
-                idx = lynx->iso_rcv.last;
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-
-                data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]
-                        + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;
-
-                if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) {
-                        PRINT(KERN_ERR, lynx->id,
-                              "iso length mismatch 0x%08x/0x%08x", *data,
-                              lynx->iso_rcv.stat[idx]);
-                }
-
-                if (lynx->iso_rcv.stat[idx]
-                    & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {
-                        PRINT(KERN_INFO, lynx->id,
-                              "iso receive error on %d to 0x%p", idx, data);
-                } else {
-                        hpsb_packet_received(lynx->host, data,
-                                             lynx->iso_rcv.stat[idx] & 0x1fff,
-                                             0);
-                }
-
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-                lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;
-                lynx->iso_rcv.used--;
-        }
-
-        if (lynx->iso_rcv.chan_count) {
-                reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                          DMA_WORD1_CMP_ENABLE_MASTER);
-        }
-        spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-}
-
-
-static void remove_card(struct pci_dev *dev)
-{
-        struct ti_lynx *lynx;
-       struct device *lynx_dev;
-        int i;
-
-        lynx = pci_get_drvdata(dev);
-        if (!lynx) return;
-        pci_set_drvdata(dev, NULL);
-
-       lynx_dev = get_device(&lynx->host->device);
-
-        switch (lynx->state) {
-        case is_host:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                hpsb_remove_host(lynx->host);
-        case have_intr:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                free_irq(lynx->dev->irq, lynx);
-
-               /* Disable IRM Contender and LCtrl */
-               if (lynx->phyic.reg_1394a)
-                       set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4));
-
-               /* Let all other nodes know to ignore us */
-               lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
-        case have_iomappings:
-                reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-                /* Fix buggy cards with autoboot pin not tied low: */
-                reg_write(lynx, DMA0_CHAN_CTRL, 0);
-                iounmap(lynx->registers);
-                iounmap(lynx->local_rom);
-                iounmap(lynx->local_ram);
-                iounmap(lynx->aux_port);
-        case have_1394_buffers:
-                for (i = 0; i < ISORCV_PAGES; i++) {
-                        if (lynx->iso_rcv.page[i]) {
-                                pci_free_consistent(lynx->dev, PAGE_SIZE,
-                                                    lynx->iso_rcv.page[i],
-                                                    lynx->iso_rcv.page_dma[i]);
-                        }
-                }
-                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
-                                    lynx->rcv_page_dma);
-        case have_aux_buf:
-        case have_pcl_mem:
-                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
-                                    lynx->pcl_mem_dma);
-        case clear:
-                /* do nothing - already freed */
-                ;
-        }
-
-       tasklet_kill(&lynx->iso_rcv.tq);
-
-       if (lynx_dev)
-               put_device(lynx_dev);
-}
-
-
-static int __devinit add_card(struct pci_dev *dev,
-                              const struct pci_device_id *devid_is_unused)
-{
-#define FAIL(fmt, args...) do { \
-        PRINT_G(KERN_ERR, fmt , ## args); \
-        remove_card(dev); \
-        return error; \
-        } while (0)
-
-       char irq_buf[16];
-       struct hpsb_host *host;
-        struct ti_lynx *lynx; /* shortcut to currently handled device */
-        struct ti_pcl pcl;
-        u32 *pcli;
-        int i;
-        int error;
-
-        error = -ENXIO;
-
-        if (pci_set_dma_mask(dev, DMA_BIT_MASK(32)))
-                FAIL("DMA address limits not supported for PCILynx hardware");
-        if (pci_enable_device(dev))
-                FAIL("failed to enable PCILynx hardware");
-        pci_set_master(dev);
-
-        error = -ENOMEM;
-
-       host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx), &dev->dev);
-        if (!host) FAIL("failed to allocate control structure memory");
-
-        lynx = host->hostdata;
-       lynx->id = card_id++;
-        lynx->dev = dev;
-        lynx->state = clear;
-       lynx->host = host;
-        host->pdev = dev;
-        pci_set_drvdata(dev, lynx);
-
-        spin_lock_init(&lynx->lock);
-        spin_lock_init(&lynx->phy_reg_lock);
-
-        lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
-                                             &lynx->pcl_mem_dma);
-
-        if (lynx->pcl_mem != NULL) {
-                lynx->state = have_pcl_mem;
-                PRINT(KERN_INFO, lynx->id,
-                      "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,
-                      lynx->pcl_mem);
-        } else {
-                FAIL("failed to allocate PCL memory area");
-        }
-
-        lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
-                                              &lynx->rcv_page_dma);
-        if (lynx->rcv_page == NULL) {
-                FAIL("failed to allocate receive buffer");
-        }
-        lynx->state = have_1394_buffers;
-
-        for (i = 0; i < ISORCV_PAGES; i++) {
-                lynx->iso_rcv.page[i] =
-                        pci_alloc_consistent(dev, PAGE_SIZE,
-                                             &lynx->iso_rcv.page_dma[i]);
-                if (lynx->iso_rcv.page[i] == NULL) {
-                        FAIL("failed to allocate iso receive buffers");
-                }
-        }
-
-        lynx->registers = ioremap_nocache(pci_resource_start(dev,0),
-                                          PCILYNX_MAX_REGISTER);
-        lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);
-        lynx->aux_port  = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
-        lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),
-                                  PCILYNX_MAX_MEMORY);
-        lynx->state = have_iomappings;
-
-        if (lynx->registers == NULL) {
-                FAIL("failed to remap registers - card not accessible");
-        }
-
-        reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-        /* Fix buggy cards with autoboot pin not tied low: */
-        reg_write(lynx, DMA0_CHAN_CTRL, 0);
-
-       sprintf (irq_buf, "%d", dev->irq);
-
-        if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED,
-                         PCILYNX_DRIVER_NAME, lynx)) {
-                PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);
-                lynx->state = have_intr;
-        } else {
-                FAIL("failed to allocate shared interrupt %s", irq_buf);
-        }
-
-        /* alloc_pcl return values are not checked, it is expected that the
-         * provided PCL space is sufficient for the initial allocations */
-        lynx->rcv_pcl = alloc_pcl(lynx);
-        lynx->rcv_pcl_start = alloc_pcl(lynx);
-        lynx->async.pcl = alloc_pcl(lynx);
-        lynx->async.pcl_start = alloc_pcl(lynx);
-        lynx->iso_send.pcl = alloc_pcl(lynx);
-        lynx->iso_send.pcl_start = alloc_pcl(lynx);
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
-        }
-        lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
-
-        /* all allocations successful - simple init stuff follows */
-
-        reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
-
-       tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
-                    (unsigned long)lynx);
-
-        spin_lock_init(&lynx->iso_rcv.lock);
-
-        spin_lock_init(&lynx->async.queue_lock);
-        lynx->async.channel = CHANNEL_ASYNC_SEND;
-        spin_lock_init(&lynx->iso_send.queue_lock);
-        lynx->iso_send.channel = CHANNEL_ISO_SEND;
-
-        PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "
-              "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,
-              lynx->local_ram, lynx->aux_port);
-
-        /* now, looking for PHY register set */
-        if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
-                lynx->phyic.reg_1394a = 1;
-                PRINT(KERN_INFO, lynx->id,
-                      "found 1394a conform PHY (using extended register set)");
-                lynx->phyic.vendor = get_phy_vendorid(lynx);
-                lynx->phyic.product = get_phy_productid(lynx);
-        } else {
-                lynx->phyic.reg_1394a = 0;
-                PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
-        }
-
-        lynx->selfid_size = -1;
-        lynx->phy_reg0 = -1;
-
-       INIT_LIST_HEAD(&lynx->async.queue);
-       INIT_LIST_HEAD(&lynx->async.pcl_queue);
-       INIT_LIST_HEAD(&lynx->iso_send.queue);
-       INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);
-
-        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
-        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-
-        pcl.buffer[0].control = PCL_CMD_RCV | 16;
-#ifndef __BIG_ENDIAN
-       pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-       pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-
-        pcl.buffer[0].pointer = lynx->rcv_page_dma;
-        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
-        put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->async.pcl);
-        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
-        put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                int page = i / ISORCV_PER_PAGE;
-                int sec = i % ISORCV_PER_PAGE;
-
-                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
-                        + sec * MAX_ISORCV_SIZE;
-                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
-                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
-        }
-
-        pcli = (u32 *)&pcl;
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
-        }
-        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
-        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
-        reg_write(lynx, FIFO_SIZES, 0x003030a0);
-        /* 20 byte threshold before triggering PCI transfer */
-        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
-        /* threshold on both send FIFOs before transmitting:
-           FIFO size - cache line size - 1 */
-        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
-        i = 0x30 - i - 1;
-        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
-        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
-                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
-                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK
-                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
-                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
-                  | LINK_INT_ATF_UNDERFLOW);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
-                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
-                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
-                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
-        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
-        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
-        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
-                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
-                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
-                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
-
-       if (!lynx->phyic.reg_1394a) {
-               if (!hpsb_disable_irm) {
-                       /* attempt to enable contender bit -FIXME- would this
-                        * work elsewhere? */
-                       reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
-                       reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
-               }
-       } else {
-               /* set the contender (if appropriate) and LCtrl bit in the
-                * extended PHY register set. (Should check that PHY_02_EXTENDED
-                * is set in register 2?)
-                */
-               i = get_phy_reg(lynx, 4);
-               i |= PHY_04_LCTRL;
-               if (hpsb_disable_irm)
-                       i &= ~PHY_04_CONTENDER;
-               else
-                       i |= PHY_04_CONTENDER;
-               if (i != -1) set_phy_reg(lynx, 4, i);
-       }
-       
-        if (!skip_eeprom)
-        {
-               /* needed for i2c communication with serial eeprom */
-               struct i2c_adapter *i2c_ad;
-               struct i2c_algo_bit_data i2c_adapter_data;
-
-               error = -ENOMEM;
-               i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL);
-               if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
-
-               strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name));
-                i2c_adapter_data = bit_data;
-                i2c_ad->algo_data = &i2c_adapter_data;
-                i2c_adapter_data.data = lynx;
-               i2c_ad->dev.parent = &dev->dev;
-
-               PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
-                      reg_read(lynx, SERIAL_EEPROM_CONTROL));
-
-               /* reset hardware to sane state */
-               lynx->i2c_driven_state = 0x00000070;
-               reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
-
-               if (i2c_bit_add_bus(i2c_ad) < 0)
-               {
-                       kfree(i2c_ad);
-                       error = -ENXIO;
-                       FAIL("unable to register i2c");
-               }
-               else
-               {
-                        /* do i2c stuff */
-                        unsigned char i2c_cmd = 0x10;
-                        struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
-                                                  { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
-                                                };
-
-                       /* we use i2c_transfer because we have no i2c_client
-                          at hand */
-                        if (i2c_transfer(i2c_ad, msg, 2) < 0) {
-                                PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
-                               /* FIXME: probably we should rewrite the max_rec, max_ROM(1394a),
-                                * generation(1394a) and link_spd(1394a) field and recalculate
-                                * the CRC */
-
-                                for (i = 0; i < 5 ; i++)
-                                        PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
-                                              i, be32_to_cpu(lynx->bus_info_block[i]));
-
-                                /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
-                               if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
-                                   (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC))
-                                {
-                                        PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
-                                } else {
-                                       kfree(i2c_ad);
-                                       error = -ENXIO;
-                                       FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
-                                }
-
-                        }
-
-                       i2c_del_adapter(i2c_ad);
-                       kfree(i2c_ad);
-                }
-        }
-
-       host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
-       host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
-       host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
-       host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
-       if (!lynx->phyic.reg_1394a)
-               host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
-       else
-               host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
-
-       if (hpsb_add_host(host)) {
-               error = -ENOMEM;
-               FAIL("Failed to register host with highlevel");
-       }
-
-       lynx->state = is_host;
-
-       return 0;
-#undef FAIL
-}
-
-
-static struct pci_device_id pci_table[] = {
-       {
-                .vendor =    PCI_VENDOR_ID_TI,
-                .device =    PCI_DEVICE_ID_TI_PCILYNX,
-                .subvendor = PCI_ANY_ID,
-                .subdevice = PCI_ANY_ID,
-       },
-       { }                     /* Terminating entry */
-};
-
-static struct pci_driver lynx_pci_driver = {
-        .name =     PCILYNX_DRIVER_NAME,
-        .id_table = pci_table,
-        .probe =    add_card,
-        .remove =   remove_card,
-};
-
-static struct hpsb_host_driver lynx_driver = {
-       .owner =           THIS_MODULE,
-       .name =            PCILYNX_DRIVER_NAME,
-       .set_hw_config_rom = NULL,
-        .transmit_packet = lynx_transmit,
-        .devctl =          lynx_devctl,
-       .isoctl =          NULL,
-};
-
-MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
-MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("pcilynx");
-MODULE_DEVICE_TABLE(pci, pci_table);
-
-static int __init pcilynx_init(void)
-{
-        int ret;
-
-        ret = pci_register_driver(&lynx_pci_driver);
-        if (ret < 0) {
-                PRINT_G(KERN_ERR, "PCI module init failed");
-                return ret;
-        }
-
-        return 0;
-}
-
-static void __exit pcilynx_cleanup(void)
-{
-        pci_unregister_driver(&lynx_pci_driver);
-}
-
-
-module_init(pcilynx_init);
-module_exit(pcilynx_cleanup);
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
deleted file mode 100644 (file)
index 693a169..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-#ifndef __PCILYNX_H__
-#define __PCILYNX_H__
-
-
-#define PCILYNX_DRIVER_NAME      "pcilynx"
-#define PCILYNX_MAJOR            177
-
-#define PCILYNX_MINOR_AUX_START  0
-#define PCILYNX_MINOR_ROM_START  16
-#define PCILYNX_MINOR_RAM_START  32
-
-#define PCILYNX_MAX_REGISTER     0xfff
-#define PCILYNX_MAX_MEMORY       0xffff
-
-#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
-#define MAX_PCILYNX_CARDS        4
-#define LOCALRAM_SIZE            4096
-
-#define NUM_ISORCV_PCL           4
-#define MAX_ISORCV_SIZE          2048
-#define ISORCV_PER_PAGE          (PAGE_SIZE / MAX_ISORCV_SIZE)
-#define ISORCV_PAGES             (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
-
-#define CHANNEL_LOCALBUS         0
-#define CHANNEL_ASYNC_RCV        1
-#define CHANNEL_ISO_RCV          2
-#define CHANNEL_ASYNC_SEND       3
-#define CHANNEL_ISO_SEND         4
-
-#define PCILYNX_CONFIG_ROM_LENGTH   1024
-
-typedef int pcl_t;
-
-struct ti_lynx {
-        int id; /* sequential card number */
-
-        spinlock_t lock;
-
-        struct pci_dev *dev;
-
-        struct {
-                unsigned reg_1394a:1;
-                u32 vendor;
-                u32 product;
-        } phyic;
-
-        enum { clear, have_intr, have_aux_buf, have_pcl_mem,
-               have_1394_buffers, have_iomappings, is_host } state;
-
-        /* remapped memory spaces */
-        void __iomem *registers;
-        void __iomem *local_rom;
-        void __iomem *local_ram;
-        void __iomem *aux_port;
-       __be32 bus_info_block[5];
-
-        /*
-         * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
-         * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
-         * the following is an allocation bitmap
-         */
-        u8 pcl_bmap[LOCALRAM_SIZE / 1024];
-
-       /* point to PCLs memory area if needed */
-       void *pcl_mem;
-        dma_addr_t pcl_mem_dma;
-
-        /* PCLs for local mem / aux transfers */
-        pcl_t dmem_pcl;
-
-        /* IEEE-1394 part follows */
-        struct hpsb_host *host;
-
-        int phyid, isroot;
-        int selfid_size;
-        int phy_reg0;
-
-        spinlock_t phy_reg_lock;
-
-        pcl_t rcv_pcl_start, rcv_pcl;
-        void *rcv_page;
-        dma_addr_t rcv_page_dma;
-        int rcv_active;
-
-        struct lynx_send_data {
-                pcl_t pcl_start, pcl;
-                struct list_head queue;
-                struct list_head pcl_queue; /* this queue contains at most one packet */
-                spinlock_t queue_lock;
-                dma_addr_t header_dma, data_dma;
-                int channel;
-        } async, iso_send;
-
-        struct {
-                pcl_t pcl[NUM_ISORCV_PCL];
-                u32 stat[NUM_ISORCV_PCL];
-                void *page[ISORCV_PAGES];
-                dma_addr_t page_dma[ISORCV_PAGES];
-                pcl_t pcl_start;
-                int chan_count;
-                int next, last, used, running;
-                struct tasklet_struct tq;
-                spinlock_t lock;
-        } iso_rcv;
-
-       u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
-};
-
-/* the per-file data structure for mem space access */
-struct memdata {
-        struct ti_lynx *lynx;
-        int cid;
-        atomic_t aux_intr_last_seen;
-       /* enum values are the same as LBUS_ADDR_SEL_* values below */
-        enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
-};
-
-
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
-{
-        writel(data, lynx->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
-{
-        return readl(lynx->registers + offset);
-}
-
-static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
-                                u32 mask)
-{
-        reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
-}
-
-static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
-                                  u32 mask)
-{
-        reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
-}
-
-
-
-/* chip register definitions follow */
-
-#define PCI_LATENCY_CACHELINE             0x0c
-
-#define MISC_CONTROL                      0x40
-#define MISC_CONTROL_SWRESET              (1<<0)
-
-#define SERIAL_EEPROM_CONTROL             0x44
-
-#define PCI_INT_STATUS                    0x48
-#define PCI_INT_ENABLE                    0x4c
-/* status and enable have identical bit numbers */
-#define PCI_INT_INT_PEND                  (1<<31)
-#define PCI_INT_FORCED_INT                (1<<30)
-#define PCI_INT_SLV_ADR_PERR              (1<<28)
-#define PCI_INT_SLV_DAT_PERR              (1<<27)
-#define PCI_INT_MST_DAT_PERR              (1<<26)
-#define PCI_INT_MST_DEV_TIMEOUT           (1<<25)
-#define PCI_INT_INTERNAL_SLV_TIMEOUT      (1<<23)
-#define PCI_INT_AUX_TIMEOUT               (1<<18)
-#define PCI_INT_AUX_INT                   (1<<17)
-#define PCI_INT_1394                      (1<<16)
-#define PCI_INT_DMA4_PCL                  (1<<9)
-#define PCI_INT_DMA4_HLT                  (1<<8)
-#define PCI_INT_DMA3_PCL                  (1<<7)
-#define PCI_INT_DMA3_HLT                  (1<<6)
-#define PCI_INT_DMA2_PCL                  (1<<5)
-#define PCI_INT_DMA2_HLT                  (1<<4)
-#define PCI_INT_DMA1_PCL                  (1<<3)
-#define PCI_INT_DMA1_HLT                  (1<<2)
-#define PCI_INT_DMA0_PCL                  (1<<1)
-#define PCI_INT_DMA0_HLT                  (1<<0)
-/* all DMA interrupts combined: */
-#define PCI_INT_DMA_ALL                   0x3ff
-
-#define PCI_INT_DMA_HLT(chan)             (1 << (chan * 2))
-#define PCI_INT_DMA_PCL(chan)             (1 << (chan * 2 + 1))
-
-#define LBUS_ADDR                         0xb4
-#define LBUS_ADDR_SEL_RAM                 (0x0<<16)
-#define LBUS_ADDR_SEL_ROM                 (0x1<<16)
-#define LBUS_ADDR_SEL_AUX                 (0x2<<16)
-#define LBUS_ADDR_SEL_ZV                  (0x3<<16)
-
-#define GPIO_CTRL_A                       0xb8
-#define GPIO_CTRL_B                       0xbc
-#define GPIO_DATA_BASE                    0xc0
-
-#define DMA_BREG(base, chan)              (base + chan * 0x20)
-#define DMA_SREG(base, chan)              (base + chan * 0x10)
-
-#define DMA0_PREV_PCL                     0x100
-#define DMA1_PREV_PCL                     0x120
-#define DMA2_PREV_PCL                     0x140
-#define DMA3_PREV_PCL                     0x160
-#define DMA4_PREV_PCL                     0x180
-#define DMA_PREV_PCL(chan)                (DMA_BREG(DMA0_PREV_PCL, chan))
-
-#define DMA0_CURRENT_PCL                  0x104
-#define DMA1_CURRENT_PCL                  0x124
-#define DMA2_CURRENT_PCL                  0x144
-#define DMA3_CURRENT_PCL                  0x164
-#define DMA4_CURRENT_PCL                  0x184
-#define DMA_CURRENT_PCL(chan)             (DMA_BREG(DMA0_CURRENT_PCL, chan))
-
-#define DMA0_CHAN_STAT                    0x10c
-#define DMA1_CHAN_STAT                    0x12c
-#define DMA2_CHAN_STAT                    0x14c
-#define DMA3_CHAN_STAT                    0x16c
-#define DMA4_CHAN_STAT                    0x18c
-#define DMA_CHAN_STAT(chan)               (DMA_BREG(DMA0_CHAN_STAT, chan))
-/* CHAN_STATUS registers share bits */
-#define DMA_CHAN_STAT_SELFID              (1<<31)
-#define DMA_CHAN_STAT_ISOPKT              (1<<30)
-#define DMA_CHAN_STAT_PCIERR              (1<<29)
-#define DMA_CHAN_STAT_PKTERR              (1<<28)
-#define DMA_CHAN_STAT_PKTCMPL             (1<<27)
-#define DMA_CHAN_STAT_SPECIALACK          (1<<14)
-
-
-#define DMA0_CHAN_CTRL                    0x110
-#define DMA1_CHAN_CTRL                    0x130
-#define DMA2_CHAN_CTRL                    0x150
-#define DMA3_CHAN_CTRL                    0x170
-#define DMA4_CHAN_CTRL                    0x190
-#define DMA_CHAN_CTRL(chan)               (DMA_BREG(DMA0_CHAN_CTRL, chan))
-/* CHAN_CTRL registers share bits */
-#define DMA_CHAN_CTRL_ENABLE              (1<<31)
-#define DMA_CHAN_CTRL_BUSY                (1<<30)
-#define DMA_CHAN_CTRL_LINK                (1<<29)
-
-#define DMA0_READY                        0x114
-#define DMA1_READY                        0x134
-#define DMA2_READY                        0x154
-#define DMA3_READY                        0x174
-#define DMA4_READY                        0x194
-#define DMA_READY(chan)                   (DMA_BREG(DMA0_READY, chan))
-
-#define DMA_GLOBAL_REGISTER               0x908
-
-#define FIFO_SIZES                        0xa00
-
-#define FIFO_CONTROL                      0xa10
-#define FIFO_CONTROL_GRF_FLUSH            (1<<4)
-#define FIFO_CONTROL_ITF_FLUSH            (1<<3)
-#define FIFO_CONTROL_ATF_FLUSH            (1<<2)
-
-#define FIFO_XMIT_THRESHOLD               0xa14
-
-#define DMA0_WORD0_CMP_VALUE              0xb00
-#define DMA1_WORD0_CMP_VALUE              0xb10
-#define DMA2_WORD0_CMP_VALUE              0xb20
-#define DMA3_WORD0_CMP_VALUE              0xb30
-#define DMA4_WORD0_CMP_VALUE              0xb40
-#define DMA_WORD0_CMP_VALUE(chan)         (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
-
-#define DMA0_WORD0_CMP_ENABLE             0xb04
-#define DMA1_WORD0_CMP_ENABLE             0xb14
-#define DMA2_WORD0_CMP_ENABLE             0xb24
-#define DMA3_WORD0_CMP_ENABLE             0xb34
-#define DMA4_WORD0_CMP_ENABLE             0xb44
-#define DMA_WORD0_CMP_ENABLE(chan)        (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
-
-#define DMA0_WORD1_CMP_VALUE              0xb08
-#define DMA1_WORD1_CMP_VALUE              0xb18
-#define DMA2_WORD1_CMP_VALUE              0xb28
-#define DMA3_WORD1_CMP_VALUE              0xb38
-#define DMA4_WORD1_CMP_VALUE              0xb48
-#define DMA_WORD1_CMP_VALUE(chan)         (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
-
-#define DMA0_WORD1_CMP_ENABLE             0xb0c
-#define DMA1_WORD1_CMP_ENABLE             0xb1c
-#define DMA2_WORD1_CMP_ENABLE             0xb2c
-#define DMA3_WORD1_CMP_ENABLE             0xb3c
-#define DMA4_WORD1_CMP_ENABLE             0xb4c
-#define DMA_WORD1_CMP_ENABLE(chan)        (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
-/* word 1 compare enable flags */
-#define DMA_WORD1_CMP_MATCH_OTHERBUS      (1<<15)
-#define DMA_WORD1_CMP_MATCH_BROADCAST     (1<<14)
-#define DMA_WORD1_CMP_MATCH_BUS_BCAST     (1<<13)
-#define DMA_WORD1_CMP_MATCH_LOCAL_NODE    (1<<12)
-#define DMA_WORD1_CMP_MATCH_EXACT         (1<<11)
-#define DMA_WORD1_CMP_ENABLE_SELF_ID      (1<<10)
-#define DMA_WORD1_CMP_ENABLE_MASTER       (1<<8)
-
-#define LINK_ID                           0xf00
-#define LINK_ID_BUS(id)                   (id<<22)
-#define LINK_ID_NODE(id)                  (id<<16)
-
-#define LINK_CONTROL                      0xf04
-#define LINK_CONTROL_BUSY                 (1<<29)
-#define LINK_CONTROL_TX_ISO_EN            (1<<26)
-#define LINK_CONTROL_RX_ISO_EN            (1<<25)
-#define LINK_CONTROL_TX_ASYNC_EN          (1<<24)
-#define LINK_CONTROL_RX_ASYNC_EN          (1<<23)
-#define LINK_CONTROL_RESET_TX             (1<<21)
-#define LINK_CONTROL_RESET_RX             (1<<20)
-#define LINK_CONTROL_CYCMASTER            (1<<11)
-#define LINK_CONTROL_CYCSOURCE            (1<<10)
-#define LINK_CONTROL_CYCTIMEREN           (1<<9)
-#define LINK_CONTROL_RCV_CMP_VALID        (1<<7)
-#define LINK_CONTROL_SNOOP_ENABLE         (1<<6)
-
-#define CYCLE_TIMER                       0xf08
-
-#define LINK_PHY                          0xf0c
-#define LINK_PHY_READ                     (1<<31)
-#define LINK_PHY_WRITE                    (1<<30)
-#define LINK_PHY_ADDR(addr)               (addr<<24)
-#define LINK_PHY_WDATA(data)              (data<<16)
-#define LINK_PHY_RADDR(addr)              (addr<<8)
-
-
-#define LINK_INT_STATUS                   0xf14
-#define LINK_INT_ENABLE                   0xf18
-/* status and enable have identical bit numbers */
-#define LINK_INT_LINK_INT                 (1<<31)
-#define LINK_INT_PHY_TIMEOUT              (1<<30)
-#define LINK_INT_PHY_REG_RCVD             (1<<29)
-#define LINK_INT_PHY_BUSRESET             (1<<28)
-#define LINK_INT_TX_RDY                   (1<<26)
-#define LINK_INT_RX_DATA_RDY              (1<<25)
-#define LINK_INT_ISO_STUCK                (1<<20)
-#define LINK_INT_ASYNC_STUCK              (1<<19)
-#define LINK_INT_SENT_REJECT              (1<<17)
-#define LINK_INT_HDR_ERR                  (1<<16)
-#define LINK_INT_TX_INVALID_TC            (1<<15)
-#define LINK_INT_CYC_SECOND               (1<<11)
-#define LINK_INT_CYC_START                (1<<10)
-#define LINK_INT_CYC_DONE                 (1<<9)
-#define LINK_INT_CYC_PENDING              (1<<8)
-#define LINK_INT_CYC_LOST                 (1<<7)
-#define LINK_INT_CYC_ARB_FAILED           (1<<6)
-#define LINK_INT_GRF_OVERFLOW             (1<<5)
-#define LINK_INT_ITF_UNDERFLOW            (1<<4)
-#define LINK_INT_ATF_UNDERFLOW            (1<<3)
-#define LINK_INT_ISOARB_FAILED            (1<<0)
-
-/* PHY specifics */
-#define PHY_VENDORID_TI                 0x800028
-#define PHY_PRODUCTID_TSB41LV03         0x000000
-
-
-/* this is the physical layout of a PCL, its size is 128 bytes */
-struct ti_pcl {
-        u32 next;
-        u32 async_error_next;
-        u32 user_data;
-        u32 pcl_status;
-        u32 remaining_transfer_count;
-        u32 next_data_buffer;
-        struct {
-                u32 control;
-                u32 pointer;
-        } buffer[13] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#include <linux/stddef.h>
-#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
-
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           const struct ti_pcl *pcl)
-{
-        memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
-                    (u32 *)pcl, sizeof(struct ti_pcl));
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           struct ti_pcl *pcl)
-{
-        memcpy_le32((u32 *)pcl,
-                    (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
-                    sizeof(struct ti_pcl));
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
-}
-
-
-#if defined (__BIG_ENDIAN)
-typedef struct ti_pcl pcltmp_t;
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                                      pcltmp_t *tmp)
-{
-        get_pcl(lynx, pclid, tmp);
-        return tmp;
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                              pcltmp_t *tmp)
-{
-        put_pcl(lynx, pclid, tmp);
-}
-
-#else
-typedef int pcltmp_t; /* just a dummy */
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                                      pcltmp_t *tmp)
-{
-        return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                              pcltmp_t *tmp)
-{
-}
-#endif
-
-
-static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
-                               int dmachan)
-{
-        reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
-                  pcl_bus(lynx, pclid) + idx * 4);
-        reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
-                  DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
-}
-
-static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
-{
-        run_sub_pcl(lynx, pclid, 0, dmachan);
-}
-
-#define PCL_NEXT_INVALID (1<<0)
-
-/* transfer commands */
-#define PCL_CMD_RCV            (0x1<<24)
-#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
-#define PCL_CMD_XMT            (0x2<<24)
-#define PCL_CMD_UNFXMT         (0xc<<24)
-#define PCL_CMD_PCI_TO_LBUS    (0x8<<24)
-#define PCL_CMD_LBUS_TO_PCI    (0x9<<24)
-
-/* aux commands */
-#define PCL_CMD_NOP            (0x0<<24)
-#define PCL_CMD_LOAD           (0x3<<24)
-#define PCL_CMD_STOREQ         (0x4<<24)
-#define PCL_CMD_STORED         (0xb<<24)
-#define PCL_CMD_STORE0         (0x5<<24)
-#define PCL_CMD_STORE1         (0x6<<24)
-#define PCL_CMD_COMPARE        (0xe<<24)
-#define PCL_CMD_SWAP_COMPARE   (0xf<<24)
-#define PCL_CMD_ADD            (0xd<<24)
-#define PCL_CMD_BRANCH         (0x7<<24)
-
-/* BRANCH condition codes */
-#define PCL_COND_DMARDY_SET    (0x1<<20)
-#define PCL_COND_DMARDY_CLEAR  (0x2<<20)
-
-#define PCL_GEN_INTR           (1<<19)
-#define PCL_LAST_BUFF          (1<<18)
-#define PCL_LAST_CMD           (PCL_LAST_BUFF)
-#define PCL_WAITSTAT           (1<<17)
-#define PCL_BIGENDIAN          (1<<16)
-#define PCL_ISOMODE            (1<<12)
-
-#endif
diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h
deleted file mode 100644 (file)
index 7a225a4..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef IEEE1394_RAW1394_PRIVATE_H
-#define IEEE1394_RAW1394_PRIVATE_H
-
-/* header for definitions that are private to the raw1394 driver
-   and not visible to user-space */
-
-#define RAW1394_DEVICE_MAJOR      171
-#define RAW1394_DEVICE_NAME       "raw1394"
-
-#define RAW1394_MAX_USER_CSR_DIRS      16
-
-struct iso_block_store {
-        atomic_t refcount;
-        size_t data_size;
-        quadlet_t data[0];
-};
-
-enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
-                        RAW1394_ISO_RECV = 1,
-                        RAW1394_ISO_XMIT = 2 };
-
-struct file_info {
-        struct list_head list;
-
-       struct mutex state_mutex;
-        enum { opened, initialized, connected } state;
-        unsigned int protocol_version;
-
-        struct hpsb_host *host;
-
-        struct list_head req_pending;  /* protected by reqlists_lock */
-        struct list_head req_complete; /* protected by reqlists_lock */
-        spinlock_t reqlists_lock;
-        wait_queue_head_t wait_complete;
-
-        struct list_head addr_list;    /* protected by host_info_lock */
-
-        u8 __user *fcp_buffer;
-
-        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
-
-       /* new rawiso API */
-       enum raw1394_iso_state iso_state;
-       struct hpsb_iso *iso_handle;
-
-       /* User space's CSR1212 dynamic ConfigROM directories */
-       struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
-
-       /* Legacy ConfigROM update flag */
-       u8 cfgrom_upd;
-};
-
-struct arm_addr {
-        struct list_head addr_list; /* file_info list */
-        u64    start, end;
-        u64    arm_tag;
-        u8     access_rights;
-        u8     notification_options;
-        u8     client_transactions;
-        u64    recvb;
-        u16    rec_length;
-        u8     *addr_space_buffer; /* accessed by read/write/lock requests */
-};
-
-struct pending_request {
-        struct list_head list;
-        struct file_info *file_info;
-        struct hpsb_packet *packet;
-        struct iso_block_store *ibs;
-        quadlet_t *data;
-        int free_data;
-        struct raw1394_request req;
-};
-
-struct host_info {
-        struct list_head list;
-        struct hpsb_host *host;
-        struct list_head file_info_list;  /* protected by host_info_lock */
-};
-
-#endif  /* IEEE1394_RAW1394_PRIVATE_H */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
deleted file mode 100644 (file)
index f340142..0000000
+++ /dev/null
@@ -1,3096 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Raw interface to the bus
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *                     2002 Christian Toegel <christian.toegel@gmx.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        configuration ROM manipulation
- *        address range mapping
- *        adaptation for new (transparent) loopback mechanism
- *        sending of arbitrary async packets
- * Christian Toegel <christian.toegel@gmx.at>
- *        address range mapping
- *        lock64 request
- *        transmit physical packet
- *        busreset notification control (switch on/off)
- *        busreset with selection of type (short/long)
- *        request_reply
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/compat.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-#include "raw1394.h"
-#include "raw1394-private.h"
-
-#define int2ptr(x) ((void __user *)(unsigned long)x)
-#define ptr2int(x) ((u64)(unsigned long)(void __user *)x)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define RAW1394_DEBUG
-#endif
-
-#ifdef RAW1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-static LIST_HEAD(host_info_list);
-static int host_count;
-static DEFINE_SPINLOCK(host_info_lock);
-static atomic_t internal_generation = ATOMIC_INIT(0);
-
-static atomic_t iso_buffer_size;
-static const int iso_buffer_max = 4 * 1024 * 1024;     /* 4 MB */
-
-static struct hpsb_highlevel raw1394_highlevel;
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
-                   u64 addr, size_t length, u16 flags);
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
-                    quadlet_t * data, u64 addr, size_t length, u16 flags);
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-                   u16 flags);
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-                     u16 flags);
-static const struct hpsb_address_ops arm_ops = {
-       .read = arm_read,
-       .write = arm_write,
-       .lock = arm_lock,
-       .lock64 = arm_lock64,
-};
-
-static void queue_complete_cb(struct pending_request *req);
-
-static struct pending_request *__alloc_pending_request(gfp_t flags)
-{
-       struct pending_request *req;
-
-       req = kzalloc(sizeof(*req), flags);
-       if (req)
-               INIT_LIST_HEAD(&req->list);
-
-       return req;
-}
-
-static inline struct pending_request *alloc_pending_request(void)
-{
-       return __alloc_pending_request(GFP_KERNEL);
-}
-
-static void free_pending_request(struct pending_request *req)
-{
-       if (req->ibs) {
-               if (atomic_dec_and_test(&req->ibs->refcount)) {
-                       atomic_sub(req->ibs->data_size, &iso_buffer_size);
-                       kfree(req->ibs);
-               }
-       } else if (req->free_data) {
-               kfree(req->data);
-       }
-       hpsb_free_packet(req->packet);
-       kfree(req);
-}
-
-/* fi->reqlists_lock must be taken */
-static void __queue_complete_req(struct pending_request *req)
-{
-       struct file_info *fi = req->file_info;
-
-       list_move_tail(&req->list, &fi->req_complete);
-       wake_up(&fi->wait_complete);
-}
-
-static void queue_complete_req(struct pending_request *req)
-{
-       unsigned long flags;
-       struct file_info *fi = req->file_info;
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       __queue_complete_req(req);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void queue_complete_cb(struct pending_request *req)
-{
-       struct hpsb_packet *packet = req->packet;
-       int rcode = (packet->header[1] >> 12) & 0xf;
-
-       switch (packet->ack_code) {
-       case ACKX_NONE:
-       case ACKX_SEND_ERROR:
-               req->req.error = RAW1394_ERROR_SEND_ERROR;
-               break;
-       case ACKX_ABORTED:
-               req->req.error = RAW1394_ERROR_ABORTED;
-               break;
-       case ACKX_TIMEOUT:
-               req->req.error = RAW1394_ERROR_TIMEOUT;
-               break;
-       default:
-               req->req.error = (packet->ack_code << 16) | rcode;
-               break;
-       }
-
-       if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
-               req->req.length = 0;
-       }
-
-       if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
-           (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
-           (req->req.type == RAW1394_REQ_ASYNC_STREAM) ||
-           (req->req.type == RAW1394_REQ_LOCK) ||
-           (req->req.type == RAW1394_REQ_LOCK64))
-               hpsb_free_tlabel(packet);
-
-       queue_complete_req(req);
-}
-
-static void add_host(struct hpsb_host *host)
-{
-       struct host_info *hi;
-       unsigned long flags;
-
-       hi = kmalloc(sizeof(*hi), GFP_KERNEL);
-
-       if (hi) {
-               INIT_LIST_HEAD(&hi->list);
-               hi->host = host;
-               INIT_LIST_HEAD(&hi->file_info_list);
-
-               spin_lock_irqsave(&host_info_lock, flags);
-               list_add_tail(&hi->list, &host_info_list);
-               host_count++;
-               spin_unlock_irqrestore(&host_info_lock, flags);
-       }
-
-       atomic_inc(&internal_generation);
-}
-
-static struct host_info *find_host_info(struct hpsb_host *host)
-{
-       struct host_info *hi;
-
-       list_for_each_entry(hi, &host_info_list, list)
-           if (hi->host == host)
-               return hi;
-
-       return NULL;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
-       struct host_info *hi;
-       unsigned long flags;
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(host);
-
-       if (hi != NULL) {
-               list_del(&hi->list);
-               host_count--;
-               /*
-                  FIXME: address ranges should be removed
-                  and fileinfo states should be initialized
-                  (including setting generation to
-                  internal-generation ...)
-                */
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-
-       if (hi == NULL) {
-               printk(KERN_ERR "raw1394: attempt to remove unknown host "
-                      "0x%p\n", host);
-               return;
-       }
-
-       kfree(hi);
-
-       atomic_inc(&internal_generation);
-}
-
-static void host_reset(struct hpsb_host *host)
-{
-       unsigned long flags;
-       struct host_info *hi;
-       struct file_info *fi;
-       struct pending_request *req;
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(host);
-
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       if (fi->notification == RAW1394_NOTIFY_ON) {
-                               req = __alloc_pending_request(GFP_ATOMIC);
-
-                               if (req != NULL) {
-                                       req->file_info = fi;
-                                       req->req.type = RAW1394_REQ_BUS_RESET;
-                                       req->req.generation =
-                                           get_hpsb_generation(host);
-                                       req->req.misc = (host->node_id << 16)
-                                           | host->node_count;
-                                       if (fi->protocol_version > 3) {
-                                               req->req.misc |=
-                                                   (NODEID_TO_NODE
-                                                    (host->irm_id)
-                                                    << 8);
-                                       }
-
-                                       queue_complete_req(req);
-                               }
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                       int cts, u8 * data, size_t length)
-{
-       unsigned long flags;
-       struct host_info *hi;
-       struct file_info *fi;
-       struct pending_request *req, *req_next;
-       struct iso_block_store *ibs = NULL;
-       LIST_HEAD(reqs);
-
-       if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
-               HPSB_INFO("dropped fcp request");
-               return;
-       }
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(host);
-
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       if (!fi->fcp_buffer)
-                               continue;
-
-                       req = __alloc_pending_request(GFP_ATOMIC);
-                       if (!req)
-                               break;
-
-                       if (!ibs) {
-                               ibs = kmalloc(sizeof(*ibs) + length,
-                                             GFP_ATOMIC);
-                               if (!ibs) {
-                                       kfree(req);
-                                       break;
-                               }
-
-                               atomic_add(length, &iso_buffer_size);
-                               atomic_set(&ibs->refcount, 0);
-                               ibs->data_size = length;
-                               memcpy(ibs->data, data, length);
-                       }
-
-                       atomic_inc(&ibs->refcount);
-
-                       req->file_info = fi;
-                       req->ibs = ibs;
-                       req->data = ibs->data;
-                       req->req.type = RAW1394_REQ_FCP_REQUEST;
-                       req->req.generation = get_hpsb_generation(host);
-                       req->req.misc = nodeid | (direction << 16);
-                       req->req.recvb = ptr2int(fi->fcp_buffer);
-                       req->req.length = length;
-
-                       list_add_tail(&req->list, &reqs);
-               }
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-
-       list_for_each_entry_safe(req, req_next, &reqs, list)
-           queue_complete_req(req);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_raw1394_req {
-       __u32 type;
-       __s32 error;
-       __u32 misc;
-
-       __u32 generation;
-       __u32 length;
-
-       __u64 address;
-
-       __u64 tag;
-
-       __u64 sendb;
-       __u64 recvb;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-static const char __user *raw1394_compat_write(const char __user *buf)
-{
-       struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-       struct raw1394_request __user *r;
-
-       r = compat_alloc_user_space(sizeof(struct raw1394_request));
-
-#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x))
-
-       if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) ||
-           C(address) ||
-           C(tag) ||
-           C(sendb) ||
-           C(recvb))
-               return (__force const char __user *)ERR_PTR(-EFAULT);
-
-       return (const char __user *)r;
-}
-#undef C
-
-#define P(x) __put_user(r->x, &cr->x)
-
-static int
-raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
-{
-       struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-
-       if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
-           P(type) ||
-           P(error) ||
-           P(misc) ||
-           P(generation) ||
-           P(length) ||
-           P(address) ||
-           P(tag) ||
-           P(sendb) ||
-           P(recvb))
-               return -EFAULT;
-
-       return sizeof(struct compat_raw1394_req);
-}
-#undef P
-
-#endif
-
-/* get next completed request  (caller must hold fi->reqlists_lock) */
-static inline struct pending_request *__next_complete_req(struct file_info *fi)
-{
-       struct list_head *lh;
-       struct pending_request *req = NULL;
-
-       if (!list_empty(&fi->req_complete)) {
-               lh = fi->req_complete.next;
-               list_del(lh);
-               req = list_entry(lh, struct pending_request, list);
-       }
-       return req;
-}
-
-/* atomically get next completed request */
-static struct pending_request *next_complete_req(struct file_info *fi)
-{
-       unsigned long flags;
-       struct pending_request *req;
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       req = __next_complete_req(fi);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-       return req;
-}
-
-static ssize_t raw1394_read(struct file *file, char __user * buffer,
-                           size_t count, loff_t * offset_is_ignored)
-{
-       struct file_info *fi = file->private_data;
-       struct pending_request *req;
-       ssize_t ret;
-
-#ifdef CONFIG_COMPAT
-       if (count == sizeof(struct compat_raw1394_req)) {
-               /* ok */
-       } else
-#endif
-       if (count != sizeof(struct raw1394_request)) {
-               return -EINVAL;
-       }
-
-       if (!access_ok(VERIFY_WRITE, buffer, count)) {
-               return -EFAULT;
-       }
-
-       if (file->f_flags & O_NONBLOCK) {
-               if (!(req = next_complete_req(fi)))
-                       return -EAGAIN;
-       } else {
-               /*
-                * NB: We call the macro wait_event_interruptible() with a
-                * condition argument with side effect.  This is only possible
-                * because the side effect does not occur until the condition
-                * became true, and wait_event_interruptible() won't evaluate
-                * the condition again after that.
-                */
-               if (wait_event_interruptible(fi->wait_complete,
-                                            (req = next_complete_req(fi))))
-                       return -ERESTARTSYS;
-       }
-
-       if (req->req.length) {
-               if (copy_to_user(int2ptr(req->req.recvb), req->data,
-                                req->req.length)) {
-                       req->req.error = RAW1394_ERROR_MEMFAULT;
-               }
-       }
-
-#ifdef CONFIG_COMPAT
-       if (count == sizeof(struct compat_raw1394_req) &&
-           sizeof(struct compat_raw1394_req) !=
-                       sizeof(struct raw1394_request)) {
-               ret = raw1394_compat_read(buffer, &req->req);
-       } else
-#endif
-       {
-               if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               ret = (ssize_t) sizeof(struct raw1394_request);
-       }
-      out:
-       free_pending_request(req);
-       return ret;
-}
-
-static int state_opened(struct file_info *fi, struct pending_request *req)
-{
-       if (req->req.type == RAW1394_REQ_INITIALIZE) {
-               switch (req->req.misc) {
-               case RAW1394_KERNELAPI_VERSION:
-               case 3:
-                       fi->state = initialized;
-                       fi->protocol_version = req->req.misc;
-                       req->req.error = RAW1394_ERROR_NONE;
-                       req->req.generation = atomic_read(&internal_generation);
-                       break;
-
-               default:
-                       req->req.error = RAW1394_ERROR_COMPAT;
-                       req->req.misc = RAW1394_KERNELAPI_VERSION;
-               }
-       } else {
-               req->req.error = RAW1394_ERROR_STATE_ORDER;
-       }
-
-       req->req.length = 0;
-       queue_complete_req(req);
-       return 0;
-}
-
-static int state_initialized(struct file_info *fi, struct pending_request *req)
-{
-       unsigned long flags;
-       struct host_info *hi;
-       struct raw1394_khost_list *khl;
-
-       if (req->req.generation != atomic_read(&internal_generation)) {
-               req->req.error = RAW1394_ERROR_GENERATION;
-               req->req.generation = atomic_read(&internal_generation);
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       switch (req->req.type) {
-       case RAW1394_REQ_LIST_CARDS:
-               spin_lock_irqsave(&host_info_lock, flags);
-               khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC);
-
-               if (khl) {
-                       req->req.misc = host_count;
-                       req->data = (quadlet_t *) khl;
-
-                       list_for_each_entry(hi, &host_info_list, list) {
-                               khl->nodes = hi->host->node_count;
-                               strcpy(khl->name, hi->host->driver->name);
-                               khl++;
-                       }
-               }
-               spin_unlock_irqrestore(&host_info_lock, flags);
-
-               if (khl) {
-                       req->req.error = RAW1394_ERROR_NONE;
-                       req->req.length = min(req->req.length,
-                                             (u32) (sizeof
-                                                    (struct raw1394_khost_list)
-                                                    * req->req.misc));
-                       req->free_data = 1;
-               } else {
-                       return -ENOMEM;
-               }
-               break;
-
-       case RAW1394_REQ_SET_CARD:
-               spin_lock_irqsave(&host_info_lock, flags);
-               if (req->req.misc >= host_count) {
-                       req->req.error = RAW1394_ERROR_INVALID_ARG;
-                       goto out_set_card;
-               }
-               list_for_each_entry(hi, &host_info_list, list)
-                       if (!req->req.misc--)
-                               break;
-               get_device(&hi->host->device); /* FIXME handle failure case */
-               list_add_tail(&fi->list, &hi->file_info_list);
-
-               /* prevent unloading of the host's low-level driver */
-               if (!try_module_get(hi->host->driver->owner)) {
-                       req->req.error = RAW1394_ERROR_ABORTED;
-                       goto out_set_card;
-               }
-               WARN_ON(fi->host);
-               fi->host = hi->host;
-               fi->state = connected;
-
-               req->req.error = RAW1394_ERROR_NONE;
-               req->req.generation = get_hpsb_generation(fi->host);
-               req->req.misc = (fi->host->node_id << 16)
-                               | fi->host->node_count;
-               if (fi->protocol_version > 3)
-                       req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
-out_set_card:
-               spin_unlock_irqrestore(&host_info_lock, flags);
-
-               req->req.length = 0;
-               break;
-
-       default:
-               req->req.error = RAW1394_ERROR_STATE_ORDER;
-               req->req.length = 0;
-               break;
-       }
-
-       queue_complete_req(req);
-       return 0;
-}
-
-static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
-{
-       if (req->req.misc) {
-               if (fi->fcp_buffer) {
-                       req->req.error = RAW1394_ERROR_ALREADY;
-               } else {
-                       fi->fcp_buffer = int2ptr(req->req.recvb);
-               }
-       } else {
-               if (!fi->fcp_buffer) {
-                       req->req.error = RAW1394_ERROR_ALREADY;
-               } else {
-                       fi->fcp_buffer = NULL;
-               }
-       }
-
-       req->req.length = 0;
-       queue_complete_req(req);
-}
-
-static int handle_async_request(struct file_info *fi,
-                               struct pending_request *req, int node)
-{
-       unsigned long flags;
-       struct hpsb_packet *packet = NULL;
-       u64 addr = req->req.address & 0xffffffffffffULL;
-
-       switch (req->req.type) {
-       case RAW1394_REQ_ASYNC_READ:
-               DBGMSG("read_request called");
-               packet =
-                   hpsb_make_readpacket(fi->host, node, addr, req->req.length);
-
-               if (!packet)
-                       return -ENOMEM;
-
-               if (req->req.length == 4)
-                       req->data = &packet->header[3];
-               else
-                       req->data = packet->data;
-
-               break;
-
-       case RAW1394_REQ_ASYNC_WRITE:
-               DBGMSG("write_request called");
-
-               packet = hpsb_make_writepacket(fi->host, node, addr, NULL,
-                                              req->req.length);
-               if (!packet)
-                       return -ENOMEM;
-
-               if (req->req.length == 4) {
-                       if (copy_from_user
-                           (&packet->header[3], int2ptr(req->req.sendb),
-                            req->req.length))
-                               req->req.error = RAW1394_ERROR_MEMFAULT;
-               } else {
-                       if (copy_from_user
-                           (packet->data, int2ptr(req->req.sendb),
-                            req->req.length))
-                               req->req.error = RAW1394_ERROR_MEMFAULT;
-               }
-
-               req->req.length = 0;
-               break;
-
-       case RAW1394_REQ_ASYNC_STREAM:
-               DBGMSG("stream_request called");
-
-               packet =
-                   hpsb_make_streampacket(fi->host, NULL, req->req.length,
-                                          node & 0x3f /*channel */ ,
-                                          (req->req.misc >> 16) & 0x3,
-                                          req->req.misc & 0xf);
-               if (!packet)
-                       return -ENOMEM;
-
-               if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                                  req->req.length))
-                       req->req.error = RAW1394_ERROR_MEMFAULT;
-
-               req->req.length = 0;
-               break;
-
-       case RAW1394_REQ_LOCK:
-               DBGMSG("lock_request called");
-               if ((req->req.misc == EXTCODE_FETCH_ADD)
-                   || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                       if (req->req.length != 4) {
-                               req->req.error = RAW1394_ERROR_INVALID_ARG;
-                               break;
-                       }
-               } else {
-                       if (req->req.length != 8) {
-                               req->req.error = RAW1394_ERROR_INVALID_ARG;
-                               break;
-                       }
-               }
-
-               packet = hpsb_make_lockpacket(fi->host, node, addr,
-                                             req->req.misc, NULL, 0);
-               if (!packet)
-                       return -ENOMEM;
-
-               if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                                  req->req.length)) {
-                       req->req.error = RAW1394_ERROR_MEMFAULT;
-                       break;
-               }
-
-               req->data = packet->data;
-               req->req.length = 4;
-               break;
-
-       case RAW1394_REQ_LOCK64:
-               DBGMSG("lock64_request called");
-               if ((req->req.misc == EXTCODE_FETCH_ADD)
-                   || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                       if (req->req.length != 8) {
-                               req->req.error = RAW1394_ERROR_INVALID_ARG;
-                               break;
-                       }
-               } else {
-                       if (req->req.length != 16) {
-                               req->req.error = RAW1394_ERROR_INVALID_ARG;
-                               break;
-                       }
-               }
-               packet = hpsb_make_lock64packet(fi->host, node, addr,
-                                               req->req.misc, NULL, 0);
-               if (!packet)
-                       return -ENOMEM;
-
-               if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                                  req->req.length)) {
-                       req->req.error = RAW1394_ERROR_MEMFAULT;
-                       break;
-               }
-
-               req->data = packet->data;
-               req->req.length = 8;
-               break;
-
-       default:
-               req->req.error = RAW1394_ERROR_STATE_ORDER;
-       }
-
-       req->packet = packet;
-
-       if (req->req.error) {
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       hpsb_set_packet_complete_task(packet,
-                                     (void (*)(void *))queue_complete_cb, req);
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       list_add_tail(&req->list, &fi->req_pending);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-       packet->generation = req->req.generation;
-
-       if (hpsb_send_packet(packet) < 0) {
-               req->req.error = RAW1394_ERROR_SEND_ERROR;
-               req->req.length = 0;
-               hpsb_free_tlabel(packet);
-               queue_complete_req(req);
-       }
-       return 0;
-}
-
-static int handle_async_send(struct file_info *fi, struct pending_request *req)
-{
-       unsigned long flags;
-       struct hpsb_packet *packet;
-       int header_length = req->req.misc & 0xffff;
-       int expect_response = req->req.misc >> 16;
-       size_t data_size;
-
-       if (header_length > req->req.length || header_length < 12 ||
-           header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
-               req->req.error = RAW1394_ERROR_INVALID_ARG;
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       data_size = req->req.length - header_length;
-       packet = hpsb_alloc_packet(data_size);
-       req->packet = packet;
-       if (!packet)
-               return -ENOMEM;
-
-       if (copy_from_user(packet->header, int2ptr(req->req.sendb),
-                          header_length)) {
-               req->req.error = RAW1394_ERROR_MEMFAULT;
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       if (copy_from_user
-           (packet->data, int2ptr(req->req.sendb) + header_length,
-            data_size)) {
-               req->req.error = RAW1394_ERROR_MEMFAULT;
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       packet->type = hpsb_async;
-       packet->node_id = packet->header[0] >> 16;
-       packet->tcode = (packet->header[0] >> 4) & 0xf;
-       packet->tlabel = (packet->header[0] >> 10) & 0x3f;
-       packet->host = fi->host;
-       packet->expect_response = expect_response;
-       packet->header_size = header_length;
-       packet->data_size = data_size;
-
-       req->req.length = 0;
-       hpsb_set_packet_complete_task(packet,
-                                     (void (*)(void *))queue_complete_cb, req);
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       list_add_tail(&req->list, &fi->req_pending);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-       /* Update the generation of the packet just before sending. */
-       packet->generation = req->req.generation;
-
-       if (hpsb_send_packet(packet) < 0) {
-               req->req.error = RAW1394_ERROR_SEND_ERROR;
-               queue_complete_req(req);
-       }
-
-       return 0;
-}
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
-                   u64 addr, size_t length, u16 flags)
-{
-       unsigned long irqflags;
-       struct pending_request *req;
-       struct host_info *hi;
-       struct file_info *fi = NULL;
-       struct list_head *entry;
-       struct arm_addr *arm_addr = NULL;
-       struct arm_request *arm_req = NULL;
-       struct arm_response *arm_resp = NULL;
-       int found = 0, size = 0, rcode = -1;
-       struct arm_request_response *arm_req_resp = NULL;
-
-       DBGMSG("arm_read  called by node: %X "
-              "addr: %4.4x %8.8x length: %Zu", nodeid,
-              (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-              length);
-       spin_lock_irqsave(&host_info_lock, irqflags);
-       hi = find_host_info(host);      /* search address-entry */
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       entry = fi->addr_list.next;
-                       while (entry != &(fi->addr_list)) {
-                               arm_addr =
-                                   list_entry(entry, struct arm_addr,
-                                              addr_list);
-                               if (((arm_addr->start) <= (addr))
-                                   && ((arm_addr->end) >= (addr + length))) {
-                                       found = 1;
-                                       break;
-                               }
-                               entry = entry->next;
-                       }
-                       if (found) {
-                               break;
-                       }
-               }
-       }
-       rcode = -1;
-       if (!found) {
-               printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
-                      " -> rcode_address_error\n");
-               spin_unlock_irqrestore(&host_info_lock, irqflags);
-               return (RCODE_ADDRESS_ERROR);
-       } else {
-               DBGMSG("arm_read addr_entry FOUND");
-       }
-       if (arm_addr->rec_length < length) {
-               DBGMSG("arm_read blocklength too big -> rcode_data_error");
-               rcode = RCODE_DATA_ERROR;       /* hardware error, data is unavailable */
-       }
-       if (rcode == -1) {
-               if (arm_addr->access_rights & ARM_READ) {
-                       if (!(arm_addr->client_transactions & ARM_READ)) {
-                               memcpy(buffer,
-                                      (arm_addr->addr_space_buffer) + (addr -
-                                                                       (arm_addr->
-                                                                        start)),
-                                      length);
-                               DBGMSG("arm_read -> (rcode_complete)");
-                               rcode = RCODE_COMPLETE;
-                       }
-               } else {
-                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                       DBGMSG("arm_read -> rcode_type_error (access denied)");
-               }
-       }
-       if (arm_addr->notification_options & ARM_READ) {
-               DBGMSG("arm_read -> entering notification-section");
-               req = __alloc_pending_request(GFP_ATOMIC);
-               if (!req) {
-                       DBGMSG("arm_read -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               if (rcode == RCODE_COMPLETE) {
-                       size =
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response) +
-                           length * sizeof(byte_t) +
-                           sizeof(struct arm_request_response);
-               } else {
-                       size =
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response) +
-                           sizeof(struct arm_request_response);
-               }
-               req->data = kmalloc(size, GFP_ATOMIC);
-               if (!(req->data)) {
-                       free_pending_request(req);
-                       DBGMSG("arm_read -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               req->free_data = 1;
-               req->file_info = fi;
-               req->req.type = RAW1394_REQ_ARM;
-               req->req.generation = get_hpsb_generation(host);
-               req->req.misc =
-                   (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
-               req->req.tag = arm_addr->arm_tag;
-               req->req.recvb = arm_addr->recvb;
-               req->req.length = size;
-               arm_req_resp = (struct arm_request_response *)(req->data);
-               arm_req = (struct arm_request *)((byte_t *) (req->data) +
-                                                (sizeof
-                                                 (struct
-                                                  arm_request_response)));
-               arm_resp =
-                   (struct arm_response *)((byte_t *) (arm_req) +
-                                           (sizeof(struct arm_request)));
-               arm_req->buffer = NULL;
-               arm_resp->buffer = NULL;
-               if (rcode == RCODE_COMPLETE) {
-                       byte_t *buf =
-                           (byte_t *) arm_resp + sizeof(struct arm_response);
-                       memcpy(buf,
-                              (arm_addr->addr_space_buffer) + (addr -
-                                                               (arm_addr->
-                                                                start)),
-                              length);
-                       arm_resp->buffer =
-                           int2ptr((arm_addr->recvb) +
-                                   sizeof(struct arm_request_response) +
-                                   sizeof(struct arm_request) +
-                                   sizeof(struct arm_response));
-               }
-               arm_resp->buffer_length =
-                   (rcode == RCODE_COMPLETE) ? length : 0;
-               arm_resp->response_code = rcode;
-               arm_req->buffer_length = 0;
-               arm_req->generation = req->req.generation;
-               arm_req->extended_transaction_code = 0;
-               arm_req->destination_offset = addr;
-               arm_req->source_nodeid = nodeid;
-               arm_req->destination_nodeid = host->node_id;
-               arm_req->tlabel = (flags >> 10) & 0x3f;
-               arm_req->tcode = (flags >> 4) & 0x0f;
-               arm_req_resp->request = int2ptr((arm_addr->recvb) +
-                                               sizeof(struct
-                                                      arm_request_response));
-               arm_req_resp->response =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request));
-               queue_complete_req(req);
-       }
-       spin_unlock_irqrestore(&host_info_lock, irqflags);
-       return (rcode);
-}
-
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
-                    quadlet_t * data, u64 addr, size_t length, u16 flags)
-{
-       unsigned long irqflags;
-       struct pending_request *req;
-       struct host_info *hi;
-       struct file_info *fi = NULL;
-       struct list_head *entry;
-       struct arm_addr *arm_addr = NULL;
-       struct arm_request *arm_req = NULL;
-       struct arm_response *arm_resp = NULL;
-       int found = 0, size = 0, rcode = -1;
-       struct arm_request_response *arm_req_resp = NULL;
-
-       DBGMSG("arm_write called by node: %X "
-              "addr: %4.4x %8.8x length: %Zu", nodeid,
-              (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-              length);
-       spin_lock_irqsave(&host_info_lock, irqflags);
-       hi = find_host_info(host);      /* search address-entry */
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       entry = fi->addr_list.next;
-                       while (entry != &(fi->addr_list)) {
-                               arm_addr =
-                                   list_entry(entry, struct arm_addr,
-                                              addr_list);
-                               if (((arm_addr->start) <= (addr))
-                                   && ((arm_addr->end) >= (addr + length))) {
-                                       found = 1;
-                                       break;
-                               }
-                               entry = entry->next;
-                       }
-                       if (found) {
-                               break;
-                       }
-               }
-       }
-       rcode = -1;
-       if (!found) {
-               printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
-                      " -> rcode_address_error\n");
-               spin_unlock_irqrestore(&host_info_lock, irqflags);
-               return (RCODE_ADDRESS_ERROR);
-       } else {
-               DBGMSG("arm_write addr_entry FOUND");
-       }
-       if (arm_addr->rec_length < length) {
-               DBGMSG("arm_write blocklength too big -> rcode_data_error");
-               rcode = RCODE_DATA_ERROR;       /* hardware error, data is unavailable */
-       }
-       if (rcode == -1) {
-               if (arm_addr->access_rights & ARM_WRITE) {
-                       if (!(arm_addr->client_transactions & ARM_WRITE)) {
-                               memcpy((arm_addr->addr_space_buffer) +
-                                      (addr - (arm_addr->start)), data,
-                                      length);
-                               DBGMSG("arm_write -> (rcode_complete)");
-                               rcode = RCODE_COMPLETE;
-                       }
-               } else {
-                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                       DBGMSG("arm_write -> rcode_type_error (access denied)");
-               }
-       }
-       if (arm_addr->notification_options & ARM_WRITE) {
-               DBGMSG("arm_write -> entering notification-section");
-               req = __alloc_pending_request(GFP_ATOMIC);
-               if (!req) {
-                       DBGMSG("arm_write -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request my be retried */
-               }
-               size =
-                   sizeof(struct arm_request) + sizeof(struct arm_response) +
-                   (length) * sizeof(byte_t) +
-                   sizeof(struct arm_request_response);
-               req->data = kmalloc(size, GFP_ATOMIC);
-               if (!(req->data)) {
-                       free_pending_request(req);
-                       DBGMSG("arm_write -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               req->free_data = 1;
-               req->file_info = fi;
-               req->req.type = RAW1394_REQ_ARM;
-               req->req.generation = get_hpsb_generation(host);
-               req->req.misc =
-                   (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
-               req->req.tag = arm_addr->arm_tag;
-               req->req.recvb = arm_addr->recvb;
-               req->req.length = size;
-               arm_req_resp = (struct arm_request_response *)(req->data);
-               arm_req = (struct arm_request *)((byte_t *) (req->data) +
-                                                (sizeof
-                                                 (struct
-                                                  arm_request_response)));
-               arm_resp =
-                   (struct arm_response *)((byte_t *) (arm_req) +
-                                           (sizeof(struct arm_request)));
-               arm_resp->buffer = NULL;
-               memcpy((byte_t *) arm_resp + sizeof(struct arm_response),
-                      data, length);
-               arm_req->buffer = int2ptr((arm_addr->recvb) +
-                                         sizeof(struct arm_request_response) +
-                                         sizeof(struct arm_request) +
-                                         sizeof(struct arm_response));
-               arm_req->buffer_length = length;
-               arm_req->generation = req->req.generation;
-               arm_req->extended_transaction_code = 0;
-               arm_req->destination_offset = addr;
-               arm_req->source_nodeid = nodeid;
-               arm_req->destination_nodeid = destid;
-               arm_req->tlabel = (flags >> 10) & 0x3f;
-               arm_req->tcode = (flags >> 4) & 0x0f;
-               arm_resp->buffer_length = 0;
-               arm_resp->response_code = rcode;
-               arm_req_resp->request = int2ptr((arm_addr->recvb) +
-                                               sizeof(struct
-                                                      arm_request_response));
-               arm_req_resp->response =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request));
-               queue_complete_req(req);
-       }
-       spin_unlock_irqrestore(&host_info_lock, irqflags);
-       return (rcode);
-}
-
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-                   u16 flags)
-{
-       unsigned long irqflags;
-       struct pending_request *req;
-       struct host_info *hi;
-       struct file_info *fi = NULL;
-       struct list_head *entry;
-       struct arm_addr *arm_addr = NULL;
-       struct arm_request *arm_req = NULL;
-       struct arm_response *arm_resp = NULL;
-       int found = 0, size = 0, rcode = -1;
-       quadlet_t old, new;
-       struct arm_request_response *arm_req_resp = NULL;
-
-       if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-           ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-               DBGMSG("arm_lock  called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
-                      nodeid, (u16) ((addr >> 32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
-                      be32_to_cpu(data));
-       } else {
-               DBGMSG("arm_lock  called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
-                      nodeid, (u16) ((addr >> 32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
-                      be32_to_cpu(data), be32_to_cpu(arg));
-       }
-       spin_lock_irqsave(&host_info_lock, irqflags);
-       hi = find_host_info(host);      /* search address-entry */
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       entry = fi->addr_list.next;
-                       while (entry != &(fi->addr_list)) {
-                               arm_addr =
-                                   list_entry(entry, struct arm_addr,
-                                              addr_list);
-                               if (((arm_addr->start) <= (addr))
-                                   && ((arm_addr->end) >=
-                                       (addr + sizeof(*store)))) {
-                                       found = 1;
-                                       break;
-                               }
-                               entry = entry->next;
-                       }
-                       if (found) {
-                               break;
-                       }
-               }
-       }
-       rcode = -1;
-       if (!found) {
-               printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
-                      " -> rcode_address_error\n");
-               spin_unlock_irqrestore(&host_info_lock, irqflags);
-               return (RCODE_ADDRESS_ERROR);
-       } else {
-               DBGMSG("arm_lock addr_entry FOUND");
-       }
-       if (rcode == -1) {
-               if (arm_addr->access_rights & ARM_LOCK) {
-                       if (!(arm_addr->client_transactions & ARM_LOCK)) {
-                               memcpy(&old,
-                                      (arm_addr->addr_space_buffer) + (addr -
-                                                                       (arm_addr->
-                                                                        start)),
-                                      sizeof(old));
-                               switch (ext_tcode) {
-                               case (EXTCODE_MASK_SWAP):
-                                       new = data | (old & ~arg);
-                                       break;
-                               case (EXTCODE_COMPARE_SWAP):
-                                       if (old == arg) {
-                                               new = data;
-                                       } else {
-                                               new = old;
-                                       }
-                                       break;
-                               case (EXTCODE_FETCH_ADD):
-                                       new =
-                                           cpu_to_be32(be32_to_cpu(data) +
-                                                       be32_to_cpu(old));
-                                       break;
-                               case (EXTCODE_LITTLE_ADD):
-                                       new =
-                                           cpu_to_le32(le32_to_cpu(data) +
-                                                       le32_to_cpu(old));
-                                       break;
-                               case (EXTCODE_BOUNDED_ADD):
-                                       if (old != arg) {
-                                               new =
-                                                   cpu_to_be32(be32_to_cpu
-                                                               (data) +
-                                                               be32_to_cpu
-                                                               (old));
-                                       } else {
-                                               new = old;
-                                       }
-                                       break;
-                               case (EXTCODE_WRAP_ADD):
-                                       if (old != arg) {
-                                               new =
-                                                   cpu_to_be32(be32_to_cpu
-                                                               (data) +
-                                                               be32_to_cpu
-                                                               (old));
-                                       } else {
-                                               new = data;
-                                       }
-                                       break;
-                               default:
-                                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                                       printk(KERN_ERR
-                                              "raw1394: arm_lock FAILED "
-                                              "ext_tcode not allowed -> rcode_type_error\n");
-                                       break;
-                               }       /*switch */
-                               if (rcode == -1) {
-                                       DBGMSG("arm_lock -> (rcode_complete)");
-                                       rcode = RCODE_COMPLETE;
-                                       memcpy(store, &old, sizeof(*store));
-                                       memcpy((arm_addr->addr_space_buffer) +
-                                              (addr - (arm_addr->start)),
-                                              &new, sizeof(*store));
-                               }
-                       }
-               } else {
-                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                       DBGMSG("arm_lock -> rcode_type_error (access denied)");
-               }
-       }
-       if (arm_addr->notification_options & ARM_LOCK) {
-               byte_t *buf1, *buf2;
-               DBGMSG("arm_lock -> entering notification-section");
-               req = __alloc_pending_request(GFP_ATOMIC);
-               if (!req) {
-                       DBGMSG("arm_lock -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);     /* maximum */
-               req->data = kmalloc(size, GFP_ATOMIC);
-               if (!(req->data)) {
-                       free_pending_request(req);
-                       DBGMSG("arm_lock -> rcode_conflict_error");
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               req->free_data = 1;
-               arm_req_resp = (struct arm_request_response *)(req->data);
-               arm_req = (struct arm_request *)((byte_t *) (req->data) +
-                                                (sizeof
-                                                 (struct
-                                                  arm_request_response)));
-               arm_resp =
-                   (struct arm_response *)((byte_t *) (arm_req) +
-                                           (sizeof(struct arm_request)));
-               buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
-               buf2 = buf1 + 2 * sizeof(*store);
-               if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-                   (ext_tcode == EXTCODE_LITTLE_ADD)) {
-                       arm_req->buffer_length = sizeof(*store);
-                       memcpy(buf1, &data, sizeof(*store));
-
-               } else {
-                       arm_req->buffer_length = 2 * sizeof(*store);
-                       memcpy(buf1, &arg, sizeof(*store));
-                       memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
-               }
-               if (rcode == RCODE_COMPLETE) {
-                       arm_resp->buffer_length = sizeof(*store);
-                       memcpy(buf2, &old, sizeof(*store));
-               } else {
-                       arm_resp->buffer_length = 0;
-               }
-               req->file_info = fi;
-               req->req.type = RAW1394_REQ_ARM;
-               req->req.generation = get_hpsb_generation(host);
-               req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
-                                (ARM_LOCK & 0xFF));
-               req->req.tag = arm_addr->arm_tag;
-               req->req.recvb = arm_addr->recvb;
-               req->req.length = size;
-               arm_req->generation = req->req.generation;
-               arm_req->extended_transaction_code = ext_tcode;
-               arm_req->destination_offset = addr;
-               arm_req->source_nodeid = nodeid;
-               arm_req->destination_nodeid = host->node_id;
-               arm_req->tlabel = (flags >> 10) & 0x3f;
-               arm_req->tcode = (flags >> 4) & 0x0f;
-               arm_resp->response_code = rcode;
-               arm_req_resp->request = int2ptr((arm_addr->recvb) +
-                                               sizeof(struct
-                                                      arm_request_response));
-               arm_req_resp->response =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request));
-               arm_req->buffer =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response));
-               arm_resp->buffer =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response) + 2 * sizeof(*store));
-               queue_complete_req(req);
-       }
-       spin_unlock_irqrestore(&host_info_lock, irqflags);
-       return (rcode);
-}
-
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-                     u16 flags)
-{
-       unsigned long irqflags;
-       struct pending_request *req;
-       struct host_info *hi;
-       struct file_info *fi = NULL;
-       struct list_head *entry;
-       struct arm_addr *arm_addr = NULL;
-       struct arm_request *arm_req = NULL;
-       struct arm_response *arm_resp = NULL;
-       int found = 0, size = 0, rcode = -1;
-       octlet_t old, new;
-       struct arm_request_response *arm_req_resp = NULL;
-
-       if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-           ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-               DBGMSG("arm_lock64 called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
-                      nodeid, (u16) ((addr >> 32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF,
-                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
-       } else {
-               DBGMSG("arm_lock64 called by node: %X "
-                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
-                      "%8.8X %8.8X ",
-                      nodeid, (u16) ((addr >> 32) & 0xFFFF),
-                      (u32) (addr & 0xFFFFFFFF),
-                      ext_tcode & 0xFF,
-                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
-                      (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF),
-                      (u32) (be64_to_cpu(arg) & 0xFFFFFFFF));
-       }
-       spin_lock_irqsave(&host_info_lock, irqflags);
-       hi = find_host_info(host);      /* search addressentry in file_info's for host */
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       entry = fi->addr_list.next;
-                       while (entry != &(fi->addr_list)) {
-                               arm_addr =
-                                   list_entry(entry, struct arm_addr,
-                                              addr_list);
-                               if (((arm_addr->start) <= (addr))
-                                   && ((arm_addr->end) >=
-                                       (addr + sizeof(*store)))) {
-                                       found = 1;
-                                       break;
-                               }
-                               entry = entry->next;
-                       }
-                       if (found) {
-                               break;
-                       }
-               }
-       }
-       rcode = -1;
-       if (!found) {
-               printk(KERN_ERR
-                      "raw1394: arm_lock64 FAILED addr_entry not found"
-                      " -> rcode_address_error\n");
-               spin_unlock_irqrestore(&host_info_lock, irqflags);
-               return (RCODE_ADDRESS_ERROR);
-       } else {
-               DBGMSG("arm_lock64 addr_entry FOUND");
-       }
-       if (rcode == -1) {
-               if (arm_addr->access_rights & ARM_LOCK) {
-                       if (!(arm_addr->client_transactions & ARM_LOCK)) {
-                               memcpy(&old,
-                                      (arm_addr->addr_space_buffer) + (addr -
-                                                                       (arm_addr->
-                                                                        start)),
-                                      sizeof(old));
-                               switch (ext_tcode) {
-                               case (EXTCODE_MASK_SWAP):
-                                       new = data | (old & ~arg);
-                                       break;
-                               case (EXTCODE_COMPARE_SWAP):
-                                       if (old == arg) {
-                                               new = data;
-                                       } else {
-                                               new = old;
-                                       }
-                                       break;
-                               case (EXTCODE_FETCH_ADD):
-                                       new =
-                                           cpu_to_be64(be64_to_cpu(data) +
-                                                       be64_to_cpu(old));
-                                       break;
-                               case (EXTCODE_LITTLE_ADD):
-                                       new =
-                                           cpu_to_le64(le64_to_cpu(data) +
-                                                       le64_to_cpu(old));
-                                       break;
-                               case (EXTCODE_BOUNDED_ADD):
-                                       if (old != arg) {
-                                               new =
-                                                   cpu_to_be64(be64_to_cpu
-                                                               (data) +
-                                                               be64_to_cpu
-                                                               (old));
-                                       } else {
-                                               new = old;
-                                       }
-                                       break;
-                               case (EXTCODE_WRAP_ADD):
-                                       if (old != arg) {
-                                               new =
-                                                   cpu_to_be64(be64_to_cpu
-                                                               (data) +
-                                                               be64_to_cpu
-                                                               (old));
-                                       } else {
-                                               new = data;
-                                       }
-                                       break;
-                               default:
-                                       printk(KERN_ERR
-                                              "raw1394: arm_lock64 FAILED "
-                                              "ext_tcode not allowed -> rcode_type_error\n");
-                                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                                       break;
-                               }       /*switch */
-                               if (rcode == -1) {
-                                       DBGMSG
-                                           ("arm_lock64 -> (rcode_complete)");
-                                       rcode = RCODE_COMPLETE;
-                                       memcpy(store, &old, sizeof(*store));
-                                       memcpy((arm_addr->addr_space_buffer) +
-                                              (addr - (arm_addr->start)),
-                                              &new, sizeof(*store));
-                               }
-                       }
-               } else {
-                       rcode = RCODE_TYPE_ERROR;       /* function not allowed */
-                       DBGMSG
-                           ("arm_lock64 -> rcode_type_error (access denied)");
-               }
-       }
-       if (arm_addr->notification_options & ARM_LOCK) {
-               byte_t *buf1, *buf2;
-               DBGMSG("arm_lock64 -> entering notification-section");
-               req = __alloc_pending_request(GFP_ATOMIC);
-               if (!req) {
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       DBGMSG("arm_lock64 -> rcode_conflict_error");
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);     /* maximum */
-               req->data = kmalloc(size, GFP_ATOMIC);
-               if (!(req->data)) {
-                       free_pending_request(req);
-                       spin_unlock_irqrestore(&host_info_lock, irqflags);
-                       DBGMSG("arm_lock64 -> rcode_conflict_error");
-                       return (RCODE_CONFLICT_ERROR);  /* A resource conflict was detected.
-                                                          The request may be retried */
-               }
-               req->free_data = 1;
-               arm_req_resp = (struct arm_request_response *)(req->data);
-               arm_req = (struct arm_request *)((byte_t *) (req->data) +
-                                                (sizeof
-                                                 (struct
-                                                  arm_request_response)));
-               arm_resp =
-                   (struct arm_response *)((byte_t *) (arm_req) +
-                                           (sizeof(struct arm_request)));
-               buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
-               buf2 = buf1 + 2 * sizeof(*store);
-               if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-                   (ext_tcode == EXTCODE_LITTLE_ADD)) {
-                       arm_req->buffer_length = sizeof(*store);
-                       memcpy(buf1, &data, sizeof(*store));
-
-               } else {
-                       arm_req->buffer_length = 2 * sizeof(*store);
-                       memcpy(buf1, &arg, sizeof(*store));
-                       memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
-               }
-               if (rcode == RCODE_COMPLETE) {
-                       arm_resp->buffer_length = sizeof(*store);
-                       memcpy(buf2, &old, sizeof(*store));
-               } else {
-                       arm_resp->buffer_length = 0;
-               }
-               req->file_info = fi;
-               req->req.type = RAW1394_REQ_ARM;
-               req->req.generation = get_hpsb_generation(host);
-               req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
-                                (ARM_LOCK & 0xFF));
-               req->req.tag = arm_addr->arm_tag;
-               req->req.recvb = arm_addr->recvb;
-               req->req.length = size;
-               arm_req->generation = req->req.generation;
-               arm_req->extended_transaction_code = ext_tcode;
-               arm_req->destination_offset = addr;
-               arm_req->source_nodeid = nodeid;
-               arm_req->destination_nodeid = host->node_id;
-               arm_req->tlabel = (flags >> 10) & 0x3f;
-               arm_req->tcode = (flags >> 4) & 0x0f;
-               arm_resp->response_code = rcode;
-               arm_req_resp->request = int2ptr((arm_addr->recvb) +
-                                               sizeof(struct
-                                                      arm_request_response));
-               arm_req_resp->response =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request));
-               arm_req->buffer =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response));
-               arm_resp->buffer =
-                   int2ptr((arm_addr->recvb) +
-                           sizeof(struct arm_request_response) +
-                           sizeof(struct arm_request) +
-                           sizeof(struct arm_response) + 2 * sizeof(*store));
-               queue_complete_req(req);
-       }
-       spin_unlock_irqrestore(&host_info_lock, irqflags);
-       return (rcode);
-}
-
-static int arm_register(struct file_info *fi, struct pending_request *req)
-{
-       int retval;
-       struct arm_addr *addr;
-       struct host_info *hi;
-       struct file_info *fi_hlp = NULL;
-       struct list_head *entry;
-       struct arm_addr *arm_addr = NULL;
-       int same_host, another_host;
-       unsigned long flags;
-
-       DBGMSG("arm_register called "
-              "addr(Offset): %8.8x %8.8x length: %u "
-              "rights: %2.2X notify: %2.2X "
-              "max_blk_len: %4.4X",
-              (u32) ((req->req.address >> 32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF),
-              req->req.length, ((req->req.misc >> 8) & 0xFF),
-              (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF));
-       /* check addressrange */
-       if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
-           (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) !=
-            0)) {
-               req->req.length = 0;
-               return (-EINVAL);
-       }
-       /* addr-list-entry for fileinfo */
-       addr = kmalloc(sizeof(*addr), GFP_KERNEL);
-       if (!addr) {
-               req->req.length = 0;
-               return (-ENOMEM);
-       }
-       /* allocation of addr_space_buffer */
-       addr->addr_space_buffer = vmalloc(req->req.length);
-       if (!(addr->addr_space_buffer)) {
-               kfree(addr);
-               req->req.length = 0;
-               return (-ENOMEM);
-       }
-       /* initialization of addr_space_buffer */
-       if ((req->req.sendb) == (unsigned long)NULL) {
-               /* init: set 0 */
-               memset(addr->addr_space_buffer, 0, req->req.length);
-       } else {
-               /* init: user -> kernel */
-               if (copy_from_user
-                   (addr->addr_space_buffer, int2ptr(req->req.sendb),
-                    req->req.length)) {
-                       vfree(addr->addr_space_buffer);
-                       kfree(addr);
-                       return (-EFAULT);
-               }
-       }
-       INIT_LIST_HEAD(&addr->addr_list);
-       addr->arm_tag = req->req.tag;
-       addr->start = req->req.address;
-       addr->end = req->req.address + req->req.length;
-       addr->access_rights = (u8) (req->req.misc & 0x0F);
-       addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
-       addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
-       addr->access_rights |= addr->client_transactions;
-       addr->notification_options |= addr->client_transactions;
-       addr->recvb = req->req.recvb;
-       addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(fi->host);
-       same_host = 0;
-       another_host = 0;
-       /* same host with address-entry containing same addressrange ? */
-       list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-               entry = fi_hlp->addr_list.next;
-               while (entry != &(fi_hlp->addr_list)) {
-                       arm_addr =
-                           list_entry(entry, struct arm_addr, addr_list);
-                       if ((arm_addr->start == addr->start)
-                           && (arm_addr->end == addr->end)) {
-                               DBGMSG("same host ownes same "
-                                      "addressrange -> EALREADY");
-                               same_host = 1;
-                               break;
-                       }
-                       entry = entry->next;
-               }
-               if (same_host) {
-                       break;
-               }
-       }
-       if (same_host) {
-               /* addressrange occupied by same host */
-               spin_unlock_irqrestore(&host_info_lock, flags);
-               vfree(addr->addr_space_buffer);
-               kfree(addr);
-               return (-EALREADY);
-       }
-       /* another host with valid address-entry containing same addressrange */
-       list_for_each_entry(hi, &host_info_list, list) {
-               if (hi->host != fi->host) {
-                       list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                               entry = fi_hlp->addr_list.next;
-                               while (entry != &(fi_hlp->addr_list)) {
-                                       arm_addr =
-                                           list_entry(entry, struct arm_addr,
-                                                      addr_list);
-                                       if ((arm_addr->start == addr->start)
-                                           && (arm_addr->end == addr->end)) {
-                                               DBGMSG
-                                                   ("another host ownes same "
-                                                    "addressrange");
-                                               another_host = 1;
-                                               break;
-                                       }
-                                       entry = entry->next;
-                               }
-                               if (another_host) {
-                                       break;
-                               }
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-
-       if (another_host) {
-               DBGMSG("another hosts entry is valid -> SUCCESS");
-               if (copy_to_user(int2ptr(req->req.recvb),
-                                &addr->start, sizeof(u64))) {
-                       printk(KERN_ERR "raw1394: arm_register failed "
-                              " address-range-entry is invalid -> EFAULT !!!\n");
-                       vfree(addr->addr_space_buffer);
-                       kfree(addr);
-                       return (-EFAULT);
-               }
-               free_pending_request(req);      /* immediate success or fail */
-               /* INSERT ENTRY */
-               spin_lock_irqsave(&host_info_lock, flags);
-               list_add_tail(&addr->addr_list, &fi->addr_list);
-               spin_unlock_irqrestore(&host_info_lock, flags);
-               return 0;
-       }
-       retval =
-           hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
-                                   req->req.address,
-                                   req->req.address + req->req.length);
-       if (retval) {
-               /* INSERT ENTRY */
-               spin_lock_irqsave(&host_info_lock, flags);
-               list_add_tail(&addr->addr_list, &fi->addr_list);
-               spin_unlock_irqrestore(&host_info_lock, flags);
-       } else {
-               DBGMSG("arm_register failed errno: %d \n", retval);
-               vfree(addr->addr_space_buffer);
-               kfree(addr);
-               return (-EALREADY);
-       }
-       free_pending_request(req);      /* immediate success or fail */
-       return 0;
-}
-
-static int arm_unregister(struct file_info *fi, struct pending_request *req)
-{
-       int found = 0;
-       int retval = 0;
-       struct list_head *entry;
-       struct arm_addr *addr = NULL;
-       struct host_info *hi;
-       struct file_info *fi_hlp = NULL;
-       struct arm_addr *arm_addr = NULL;
-       int another_host;
-       unsigned long flags;
-
-       DBGMSG("arm_Unregister called addr(Offset): "
-              "%8.8x %8.8x",
-              (u32) ((req->req.address >> 32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF));
-       spin_lock_irqsave(&host_info_lock, flags);
-       /* get addr */
-       entry = fi->addr_list.next;
-       while (entry != &(fi->addr_list)) {
-               addr = list_entry(entry, struct arm_addr, addr_list);
-               if (addr->start == req->req.address) {
-                       found = 1;
-                       break;
-               }
-               entry = entry->next;
-       }
-       if (!found) {
-               DBGMSG("arm_Unregister addr not found");
-               spin_unlock_irqrestore(&host_info_lock, flags);
-               return (-EINVAL);
-       }
-       DBGMSG("arm_Unregister addr found");
-       another_host = 0;
-       /* another host with valid address-entry containing
-          same addressrange */
-       list_for_each_entry(hi, &host_info_list, list) {
-               if (hi->host != fi->host) {
-                       list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-                               entry = fi_hlp->addr_list.next;
-                               while (entry != &(fi_hlp->addr_list)) {
-                                       arm_addr = list_entry(entry,
-                                                             struct arm_addr,
-                                                             addr_list);
-                                       if (arm_addr->start == addr->start) {
-                                               DBGMSG("another host ownes "
-                                                      "same addressrange");
-                                               another_host = 1;
-                                               break;
-                                       }
-                                       entry = entry->next;
-                               }
-                               if (another_host) {
-                                       break;
-                               }
-                       }
-               }
-       }
-       if (another_host) {
-               DBGMSG("delete entry from list -> success");
-               list_del(&addr->addr_list);
-               spin_unlock_irqrestore(&host_info_lock, flags);
-               vfree(addr->addr_space_buffer);
-               kfree(addr);
-               free_pending_request(req);      /* immediate success or fail */
-               return 0;
-       }
-       retval =
-           hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
-                                     addr->start);
-       if (!retval) {
-               printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
-               spin_unlock_irqrestore(&host_info_lock, flags);
-               return (-EINVAL);
-       }
-       DBGMSG("delete entry from list -> success");
-       list_del(&addr->addr_list);
-       spin_unlock_irqrestore(&host_info_lock, flags);
-       vfree(addr->addr_space_buffer);
-       kfree(addr);
-       free_pending_request(req);      /* immediate success or fail */
-       return 0;
-}
-
-/* Copy data from ARM buffer(s) to user buffer. */
-static int arm_get_buf(struct file_info *fi, struct pending_request *req)
-{
-       struct arm_addr *arm_addr = NULL;
-       unsigned long flags;
-       unsigned long offset;
-
-       struct list_head *entry;
-
-       DBGMSG("arm_get_buf "
-              "addr(Offset): %04X %08X length: %u",
-              (u32) ((req->req.address >> 32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       entry = fi->addr_list.next;
-       while (entry != &(fi->addr_list)) {
-               arm_addr = list_entry(entry, struct arm_addr, addr_list);
-               if ((arm_addr->start <= req->req.address) &&
-                   (arm_addr->end > req->req.address)) {
-                       if (req->req.address + req->req.length <= arm_addr->end) {
-                               offset = req->req.address - arm_addr->start;
-                               spin_unlock_irqrestore(&host_info_lock, flags);
-
-                               DBGMSG
-                                   ("arm_get_buf copy_to_user( %08X, %p, %u )",
-                                    (u32) req->req.recvb,
-                                    arm_addr->addr_space_buffer + offset,
-                                    (u32) req->req.length);
-                               if (copy_to_user
-                                   (int2ptr(req->req.recvb),
-                                    arm_addr->addr_space_buffer + offset,
-                                    req->req.length))
-                                       return (-EFAULT);
-
-                               /* We have to free the request, because we
-                                * queue no response, and therefore nobody
-                                * will free it. */
-                               free_pending_request(req);
-                               return 0;
-                       } else {
-                               DBGMSG("arm_get_buf request exceeded mapping");
-                               spin_unlock_irqrestore(&host_info_lock, flags);
-                               return (-EINVAL);
-                       }
-               }
-               entry = entry->next;
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-       return (-EINVAL);
-}
-
-/* Copy data from user buffer to ARM buffer(s). */
-static int arm_set_buf(struct file_info *fi, struct pending_request *req)
-{
-       struct arm_addr *arm_addr = NULL;
-       unsigned long flags;
-       unsigned long offset;
-
-       struct list_head *entry;
-
-       DBGMSG("arm_set_buf "
-              "addr(Offset): %04X %08X length: %u",
-              (u32) ((req->req.address >> 32) & 0xFFFF),
-              (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       entry = fi->addr_list.next;
-       while (entry != &(fi->addr_list)) {
-               arm_addr = list_entry(entry, struct arm_addr, addr_list);
-               if ((arm_addr->start <= req->req.address) &&
-                   (arm_addr->end > req->req.address)) {
-                       if (req->req.address + req->req.length <= arm_addr->end) {
-                               offset = req->req.address - arm_addr->start;
-                               spin_unlock_irqrestore(&host_info_lock, flags);
-
-                               DBGMSG
-                                   ("arm_set_buf copy_from_user( %p, %08X, %u )",
-                                    arm_addr->addr_space_buffer + offset,
-                                    (u32) req->req.sendb,
-                                    (u32) req->req.length);
-                               if (copy_from_user
-                                   (arm_addr->addr_space_buffer + offset,
-                                    int2ptr(req->req.sendb),
-                                    req->req.length))
-                                       return (-EFAULT);
-
-                               /* We have to free the request, because we
-                                * queue no response, and therefore nobody
-                                * will free it. */
-                               free_pending_request(req);
-                               return 0;
-                       } else {
-                               DBGMSG("arm_set_buf request exceeded mapping");
-                               spin_unlock_irqrestore(&host_info_lock, flags);
-                               return (-EINVAL);
-                       }
-               }
-               entry = entry->next;
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-       return (-EINVAL);
-}
-
-static int reset_notification(struct file_info *fi, struct pending_request *req)
-{
-       DBGMSG("reset_notification called - switch %s ",
-              (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
-       if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
-           (req->req.misc == RAW1394_NOTIFY_ON)) {
-               fi->notification = (u8) req->req.misc;
-               free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-               return 0;
-       }
-       /* error EINVAL (22) invalid argument */
-       return (-EINVAL);
-}
-
-static int write_phypacket(struct file_info *fi, struct pending_request *req)
-{
-       struct hpsb_packet *packet = NULL;
-       int retval = 0;
-       quadlet_t data;
-       unsigned long flags;
-
-       data = be32_to_cpu((u32) req->req.sendb);
-       DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
-       packet = hpsb_make_phypacket(fi->host, data);
-       if (!packet)
-               return -ENOMEM;
-       req->req.length = 0;
-       req->packet = packet;
-       hpsb_set_packet_complete_task(packet,
-                                     (void (*)(void *))queue_complete_cb, req);
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       list_add_tail(&req->list, &fi->req_pending);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-       packet->generation = req->req.generation;
-       retval = hpsb_send_packet(packet);
-       DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
-       if (retval < 0) {
-               req->req.error = RAW1394_ERROR_SEND_ERROR;
-               req->req.length = 0;
-               queue_complete_req(req);
-       }
-       return 0;
-}
-
-static int get_config_rom(struct file_info *fi, struct pending_request *req)
-{
-       int ret = 0;
-       quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
-       int status;
-
-       if (!data)
-               return -ENOMEM;
-
-       status =
-           csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
-                        data, req->req.length);
-       if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
-               ret = -EFAULT;
-       if (copy_to_user
-           (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
-            sizeof(fi->host->csr.rom->cache_head->len)))
-               ret = -EFAULT;
-       if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
-                        sizeof(fi->host->csr.generation)))
-               ret = -EFAULT;
-       if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
-               ret = -EFAULT;
-       kfree(data);
-       if (ret >= 0) {
-               free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-       }
-       return ret;
-}
-
-static int update_config_rom(struct file_info *fi, struct pending_request *req)
-{
-       int ret = 0;
-       quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-       if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
-               ret = -EFAULT;
-       } else {
-               int status = hpsb_update_config_rom(fi->host,
-                                                   data, req->req.length,
-                                                   (unsigned char)req->req.
-                                                   misc);
-               if (copy_to_user
-                   (int2ptr(req->req.recvb), &status, sizeof(status)))
-                       ret = -ENOMEM;
-       }
-       kfree(data);
-       if (ret >= 0) {
-               free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-               fi->cfgrom_upd = 1;
-       }
-       return ret;
-}
-
-static int modify_config_rom(struct file_info *fi, struct pending_request *req)
-{
-       struct csr1212_keyval *kv;
-       struct csr1212_csr_rom_cache *cache;
-       struct csr1212_dentry *dentry;
-       u32 dr;
-       int ret = 0;
-
-       if (req->req.misc == ~0) {
-               if (req->req.length == 0)
-                       return -EINVAL;
-
-               /* Find an unused slot */
-               for (dr = 0;
-                    dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
-                    dr++) ;
-
-               if (dr == RAW1394_MAX_USER_CSR_DIRS)
-                       return -ENOMEM;
-
-               fi->csr1212_dirs[dr] =
-                   csr1212_new_directory(CSR1212_KV_ID_VENDOR);
-               if (!fi->csr1212_dirs[dr])
-                       return -ENOMEM;
-       } else {
-               dr = req->req.misc;
-               if (!fi->csr1212_dirs[dr])
-                       return -EINVAL;
-
-               /* Delete old stuff */
-               for (dentry =
-                    fi->csr1212_dirs[dr]->value.directory.dentries_head;
-                    dentry; dentry = dentry->next) {
-                       csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-                                                            root_kv,
-                                                            dentry->kv);
-               }
-
-               if (req->req.length == 0) {
-                       csr1212_release_keyval(fi->csr1212_dirs[dr]);
-                       fi->csr1212_dirs[dr] = NULL;
-
-                       hpsb_update_config_rom_image(fi->host);
-                       free_pending_request(req);
-                       return 0;
-               }
-       }
-
-       cache = csr1212_rom_cache_malloc(0, req->req.length);
-       if (!cache) {
-               csr1212_release_keyval(fi->csr1212_dirs[dr]);
-               fi->csr1212_dirs[dr] = NULL;
-               return -ENOMEM;
-       }
-
-       cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL);
-       if (!cache->filled_head) {
-               csr1212_release_keyval(fi->csr1212_dirs[dr]);
-               fi->csr1212_dirs[dr] = NULL;
-               CSR1212_FREE(cache);
-               return -ENOMEM;
-       }
-       cache->filled_tail = cache->filled_head;
-
-       if (copy_from_user(cache->data, int2ptr(req->req.sendb),
-                          req->req.length)) {
-               csr1212_release_keyval(fi->csr1212_dirs[dr]);
-               fi->csr1212_dirs[dr] = NULL;
-               ret = -EFAULT;
-       } else {
-               cache->len = req->req.length;
-               cache->filled_head->offset_start = 0;
-               cache->filled_head->offset_end = cache->size - 1;
-
-               cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
-
-               ret = CSR1212_SUCCESS;
-               /* parse all the items */
-               for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
-                    kv = kv->next) {
-                       ret = csr1212_parse_keyval(kv, cache);
-               }
-
-               /* attach top level items to the root directory */
-               for (dentry =
-                    fi->csr1212_dirs[dr]->value.directory.dentries_head;
-                    ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
-                       ret =
-                           csr1212_attach_keyval_to_directory(fi->host->csr.
-                                                              rom->root_kv,
-                                                              dentry->kv);
-               }
-
-               if (ret == CSR1212_SUCCESS) {
-                       ret = hpsb_update_config_rom_image(fi->host);
-
-                       if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
-                                                    &dr, sizeof(dr))) {
-                               ret = -ENOMEM;
-                       }
-               }
-       }
-       kfree(cache->filled_head);
-       CSR1212_FREE(cache);
-
-       if (ret >= 0) {
-               /* we have to free the request, because we queue no response,
-                * and therefore nobody will free it */
-               free_pending_request(req);
-               return 0;
-       } else {
-               for (dentry =
-                    fi->csr1212_dirs[dr]->value.directory.dentries_head;
-                    dentry; dentry = dentry->next) {
-                       csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-                                                            root_kv,
-                                                            dentry->kv);
-               }
-               csr1212_release_keyval(fi->csr1212_dirs[dr]);
-               fi->csr1212_dirs[dr] = NULL;
-               return ret;
-       }
-}
-
-static int state_connected(struct file_info *fi, struct pending_request *req)
-{
-       int node = req->req.address >> 48;
-
-       req->req.error = RAW1394_ERROR_NONE;
-
-       switch (req->req.type) {
-
-       case RAW1394_REQ_ECHO:
-               queue_complete_req(req);
-               return 0;
-
-       case RAW1394_REQ_ARM_REGISTER:
-               return arm_register(fi, req);
-
-       case RAW1394_REQ_ARM_UNREGISTER:
-               return arm_unregister(fi, req);
-
-       case RAW1394_REQ_ARM_SET_BUF:
-               return arm_set_buf(fi, req);
-
-       case RAW1394_REQ_ARM_GET_BUF:
-               return arm_get_buf(fi, req);
-
-       case RAW1394_REQ_RESET_NOTIFY:
-               return reset_notification(fi, req);
-
-       case RAW1394_REQ_ISO_SEND:
-       case RAW1394_REQ_ISO_LISTEN:
-               printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
-               req->req.error = RAW1394_ERROR_COMPAT;
-               req->req.misc = RAW1394_KERNELAPI_VERSION;
-               queue_complete_req(req);
-               return 0;
-
-       case RAW1394_REQ_FCP_LISTEN:
-               handle_fcp_listen(fi, req);
-               return 0;
-
-       case RAW1394_REQ_RESET_BUS:
-               if (req->req.misc == RAW1394_LONG_RESET) {
-                       DBGMSG("busreset called (type: LONG)");
-                       hpsb_reset_bus(fi->host, LONG_RESET);
-                       free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                       return 0;
-               }
-               if (req->req.misc == RAW1394_SHORT_RESET) {
-                       DBGMSG("busreset called (type: SHORT)");
-                       hpsb_reset_bus(fi->host, SHORT_RESET);
-                       free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                       return 0;
-               }
-               /* error EINVAL (22) invalid argument */
-               return (-EINVAL);
-       case RAW1394_REQ_GET_ROM:
-               return get_config_rom(fi, req);
-
-       case RAW1394_REQ_UPDATE_ROM:
-               return update_config_rom(fi, req);
-
-       case RAW1394_REQ_MODIFY_ROM:
-               return modify_config_rom(fi, req);
-       }
-
-       if (req->req.generation != get_hpsb_generation(fi->host)) {
-               req->req.error = RAW1394_ERROR_GENERATION;
-               req->req.generation = get_hpsb_generation(fi->host);
-               req->req.length = 0;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       switch (req->req.type) {
-       case RAW1394_REQ_PHYPACKET:
-               return write_phypacket(fi, req);
-       case RAW1394_REQ_ASYNC_SEND:
-               return handle_async_send(fi, req);
-       }
-
-       if (req->req.length == 0) {
-               req->req.error = RAW1394_ERROR_INVALID_ARG;
-               queue_complete_req(req);
-               return 0;
-       }
-
-       return handle_async_request(fi, req, node);
-}
-
-static ssize_t raw1394_write(struct file *file, const char __user * buffer,
-                            size_t count, loff_t * offset_is_ignored)
-{
-       struct file_info *fi = file->private_data;
-       struct pending_request *req;
-       ssize_t retval = -EBADFD;
-
-#ifdef CONFIG_COMPAT
-       if (count == sizeof(struct compat_raw1394_req) &&
-           sizeof(struct compat_raw1394_req) !=
-                       sizeof(struct raw1394_request)) {
-               buffer = raw1394_compat_write(buffer);
-               if (IS_ERR((__force void *)buffer))
-                       return PTR_ERR((__force void *)buffer);
-       } else
-#endif
-       if (count != sizeof(struct raw1394_request)) {
-               return -EINVAL;
-       }
-
-       req = alloc_pending_request();
-       if (req == NULL) {
-               return -ENOMEM;
-       }
-       req->file_info = fi;
-
-       if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
-               free_pending_request(req);
-               return -EFAULT;
-       }
-
-       if (!mutex_trylock(&fi->state_mutex)) {
-               free_pending_request(req);
-               return -EAGAIN;
-       }
-
-       switch (fi->state) {
-       case opened:
-               retval = state_opened(fi, req);
-               break;
-
-       case initialized:
-               retval = state_initialized(fi, req);
-               break;
-
-       case connected:
-               retval = state_connected(fi, req);
-               break;
-       }
-
-       mutex_unlock(&fi->state_mutex);
-
-       if (retval < 0) {
-               free_pending_request(req);
-       } else {
-               BUG_ON(retval);
-               retval = count;
-       }
-
-       return retval;
-}
-
-/* rawiso operations */
-
-/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the
- * completion queue (reqlists_lock must be taken) */
-static inline int __rawiso_event_in_queue(struct file_info *fi)
-{
-       struct pending_request *req;
-
-       list_for_each_entry(req, &fi->req_complete, list)
-           if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
-               return 1;
-
-       return 0;
-}
-
-/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */
-static void queue_rawiso_event(struct file_info *fi)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-
-       /* only one ISO activity event may be in the queue */
-       if (!__rawiso_event_in_queue(fi)) {
-               struct pending_request *req =
-                   __alloc_pending_request(GFP_ATOMIC);
-
-               if (req) {
-                       req->file_info = fi;
-                       req->req.type = RAW1394_REQ_RAWISO_ACTIVITY;
-                       req->req.generation = get_hpsb_generation(fi->host);
-                       __queue_complete_req(req);
-               } else {
-                       /* on allocation failure, signal an overflow */
-                       if (fi->iso_handle) {
-                               atomic_inc(&fi->iso_handle->overflows);
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void rawiso_activity_cb(struct hpsb_iso *iso)
-{
-       unsigned long flags;
-       struct host_info *hi;
-       struct file_info *fi;
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(iso->host);
-
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       if (fi->iso_handle == iso)
-                               queue_rawiso_event(fi);
-               }
-       }
-
-       spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-/* helper function - gather all the kernel iso status bits for returning to user-space */
-static void raw1394_iso_fill_status(struct hpsb_iso *iso,
-                                   struct raw1394_iso_status *stat)
-{
-       int overflows = atomic_read(&iso->overflows);
-       int skips = atomic_read(&iso->skips);
-
-       stat->config.data_buf_size = iso->buf_size;
-       stat->config.buf_packets = iso->buf_packets;
-       stat->config.channel = iso->channel;
-       stat->config.speed = iso->speed;
-       stat->config.irq_interval = iso->irq_interval;
-       stat->n_packets = hpsb_iso_n_ready(iso);
-       stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
-       stat->xmit_cycle = iso->xmit_cycle;
-}
-
-static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_iso_status stat;
-
-       if (!fi->host)
-               return -EINVAL;
-
-       if (copy_from_user(&stat, uaddr, sizeof(stat)))
-               return -EFAULT;
-
-       fi->iso_handle = hpsb_iso_xmit_init(fi->host,
-                                           stat.config.data_buf_size,
-                                           stat.config.buf_packets,
-                                           stat.config.channel,
-                                           stat.config.speed,
-                                           stat.config.irq_interval,
-                                           rawiso_activity_cb);
-       if (!fi->iso_handle)
-               return -ENOMEM;
-
-       fi->iso_state = RAW1394_ISO_XMIT;
-
-       raw1394_iso_fill_status(fi->iso_handle, &stat);
-       if (copy_to_user(uaddr, &stat, sizeof(stat)))
-               return -EFAULT;
-
-       /* queue an event to get things started */
-       rawiso_activity_cb(fi->iso_handle);
-
-       return 0;
-}
-
-static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_iso_status stat;
-
-       if (!fi->host)
-               return -EINVAL;
-
-       if (copy_from_user(&stat, uaddr, sizeof(stat)))
-               return -EFAULT;
-
-       fi->iso_handle = hpsb_iso_recv_init(fi->host,
-                                           stat.config.data_buf_size,
-                                           stat.config.buf_packets,
-                                           stat.config.channel,
-                                           stat.config.dma_mode,
-                                           stat.config.irq_interval,
-                                           rawiso_activity_cb);
-       if (!fi->iso_handle)
-               return -ENOMEM;
-
-       fi->iso_state = RAW1394_ISO_RECV;
-
-       raw1394_iso_fill_status(fi->iso_handle, &stat);
-       if (copy_to_user(uaddr, &stat, sizeof(stat)))
-               return -EFAULT;
-       return 0;
-}
-
-static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_iso_status stat;
-       struct hpsb_iso *iso = fi->iso_handle;
-
-       raw1394_iso_fill_status(fi->iso_handle, &stat);
-       if (copy_to_user(uaddr, &stat, sizeof(stat)))
-               return -EFAULT;
-
-       /* reset overflow counter */
-       atomic_set(&iso->overflows, 0);
-       /* reset skip counter */
-       atomic_set(&iso->skips, 0);
-
-       return 0;
-}
-
-/* copy N packet_infos out of the ringbuffer into user-supplied array */
-static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_iso_packets upackets;
-       unsigned int packet = fi->iso_handle->first_packet;
-       int i;
-
-       if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
-               return -EFAULT;
-
-       if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
-               return -EINVAL;
-
-       /* ensure user-supplied buffer is accessible and big enough */
-       if (!access_ok(VERIFY_WRITE, upackets.infos,
-                      upackets.n_packets *
-                      sizeof(struct raw1394_iso_packet_info)))
-               return -EFAULT;
-
-       /* copy the packet_infos out */
-       for (i = 0; i < upackets.n_packets; i++) {
-               if (__copy_to_user(&upackets.infos[i],
-                                  &fi->iso_handle->infos[packet],
-                                  sizeof(struct raw1394_iso_packet_info)))
-                       return -EFAULT;
-
-               packet = (packet + 1) % fi->iso_handle->buf_packets;
-       }
-
-       return 0;
-}
-
-/* copy N packet_infos from user to ringbuffer, and queue them for transmission */
-static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_iso_packets upackets;
-       int i, rv;
-
-       if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
-               return -EFAULT;
-
-       if (upackets.n_packets >= fi->iso_handle->buf_packets)
-               return -EINVAL;
-
-       if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
-               return -EAGAIN;
-
-       /* ensure user-supplied buffer is accessible and big enough */
-       if (!access_ok(VERIFY_READ, upackets.infos,
-                      upackets.n_packets *
-                      sizeof(struct raw1394_iso_packet_info)))
-               return -EFAULT;
-
-       /* copy the infos structs in and queue the packets */
-       for (i = 0; i < upackets.n_packets; i++) {
-               struct raw1394_iso_packet_info info;
-
-               if (__copy_from_user(&info, &upackets.infos[i],
-                                    sizeof(struct raw1394_iso_packet_info)))
-                       return -EFAULT;
-
-               rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
-                                               info.len, info.tag, info.sy);
-               if (rv)
-                       return rv;
-       }
-
-       return 0;
-}
-
-static void raw1394_iso_shutdown(struct file_info *fi)
-{
-       if (fi->iso_handle)
-               hpsb_iso_shutdown(fi->iso_handle);
-
-       fi->iso_handle = NULL;
-       fi->iso_state = RAW1394_ISO_INACTIVE;
-}
-
-static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_cycle_timer ct;
-       int err;
-
-       err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
-       if (!err)
-               if (copy_to_user(uaddr, &ct, sizeof(ct)))
-                       err = -EFAULT;
-       return err;
-}
-
-/* mmap the rawiso xmit/recv buffer */
-static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct file_info *fi = file->private_data;
-       int ret;
-
-       if (!mutex_trylock(&fi->state_mutex))
-               return -EAGAIN;
-
-       if (fi->iso_state == RAW1394_ISO_INACTIVE)
-               ret = -EINVAL;
-       else
-               ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
-
-       mutex_unlock(&fi->state_mutex);
-
-       return ret;
-}
-
-static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd,
-                                  void __user *argp)
-{
-       switch (cmd) {
-       case RAW1394_IOC_ISO_XMIT_INIT:
-               return raw1394_iso_xmit_init(fi, argp);
-       case RAW1394_IOC_ISO_RECV_INIT:
-               return raw1394_iso_recv_init(fi, argp);
-       default:
-               return -EINVAL;
-       }
-}
-
-static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd,
-                              unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-       case RAW1394_IOC_ISO_RECV_START:{
-                       int args[3];
-
-                       if (copy_from_user(&args[0], argp, sizeof(args)))
-                               return -EFAULT;
-                       return hpsb_iso_recv_start(fi->iso_handle,
-                                                  args[0], args[1], args[2]);
-               }
-       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-               hpsb_iso_stop(fi->iso_handle);
-               return 0;
-       case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-               return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
-       case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-               return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
-       case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
-                       u64 mask;
-
-                       if (copy_from_user(&mask, argp, sizeof(mask)))
-                               return -EFAULT;
-                       return hpsb_iso_recv_set_channel_mask(fi->iso_handle,
-                                                             mask);
-               }
-       case RAW1394_IOC_ISO_GET_STATUS:
-               return raw1394_iso_get_status(fi, argp);
-       case RAW1394_IOC_ISO_RECV_PACKETS:
-               return raw1394_iso_recv_packets(fi, argp);
-       case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-               return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
-       case RAW1394_IOC_ISO_RECV_FLUSH:
-               return hpsb_iso_recv_flush(fi->iso_handle);
-       case RAW1394_IOC_ISO_SHUTDOWN:
-               raw1394_iso_shutdown(fi);
-               return 0;
-       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-               queue_rawiso_event(fi);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd,
-                              void __user *argp)
-{
-       switch (cmd) {
-       case RAW1394_IOC_ISO_XMIT_START:{
-                       int args[2];
-
-                       if (copy_from_user(&args[0], argp, sizeof(args)))
-                               return -EFAULT;
-                       return hpsb_iso_xmit_start(fi->iso_handle,
-                                                  args[0], args[1]);
-               }
-       case RAW1394_IOC_ISO_XMIT_SYNC:
-               return hpsb_iso_xmit_sync(fi->iso_handle);
-       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-               hpsb_iso_stop(fi->iso_handle);
-               return 0;
-       case RAW1394_IOC_ISO_GET_STATUS:
-               return raw1394_iso_get_status(fi, argp);
-       case RAW1394_IOC_ISO_XMIT_PACKETS:
-               return raw1394_iso_send_packets(fi, argp);
-       case RAW1394_IOC_ISO_SHUTDOWN:
-               raw1394_iso_shutdown(fi);
-               return 0;
-       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-               queue_rawiso_event(fi);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-/* ioctl is only used for rawiso operations */
-static long raw1394_ioctl(struct file *file, unsigned int cmd,
-                         unsigned long arg)
-{
-       struct file_info *fi = file->private_data;
-       void __user *argp = (void __user *)arg;
-       long ret;
-
-       /* state-independent commands */
-       switch(cmd) {
-       case RAW1394_IOC_GET_CYCLE_TIMER:
-               return raw1394_read_cycle_timer(fi, argp);
-       default:
-               break;
-       }
-
-       if (!mutex_trylock(&fi->state_mutex))
-               return -EAGAIN;
-
-       switch (fi->iso_state) {
-       case RAW1394_ISO_INACTIVE:
-               ret = raw1394_ioctl_inactive(fi, cmd, argp);
-               break;
-       case RAW1394_ISO_RECV:
-               ret = raw1394_ioctl_recv(fi, cmd, arg);
-               break;
-       case RAW1394_ISO_XMIT:
-               ret = raw1394_ioctl_xmit(fi, cmd, argp);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       mutex_unlock(&fi->state_mutex);
-
-       return ret;
-}
-
-#ifdef CONFIG_COMPAT
-struct raw1394_iso_packets32 {
-        __u32 n_packets;
-        compat_uptr_t infos;
-} __attribute__((packed));
-
-struct raw1394_cycle_timer32 {
-        __u32 cycle_timer;
-        __u64 local_time;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-#define RAW1394_IOC_ISO_RECV_PACKETS32          \
-        _IOW ('#', 0x25, struct raw1394_iso_packets32)
-#define RAW1394_IOC_ISO_XMIT_PACKETS32          \
-        _IOW ('#', 0x27, struct raw1394_iso_packets32)
-#define RAW1394_IOC_GET_CYCLE_TIMER32           \
-        _IOR ('#', 0x30, struct raw1394_cycle_timer32)
-
-static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
-                                          struct raw1394_iso_packets32 __user *arg)
-{
-       compat_uptr_t infos32;
-       void __user *infos;
-       long err = -EFAULT;
-       struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
-
-       if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) &&
-           !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
-               infos = compat_ptr(infos32);
-               if (!copy_to_user(&dst->infos, &infos, sizeof infos))
-                       err = raw1394_ioctl(file, cmd, (unsigned long)dst);
-       }
-       return err;
-}
-
-static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr)
-{
-       struct raw1394_cycle_timer32 ct;
-       int err;
-
-       err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
-       if (!err)
-               if (copy_to_user(uaddr, &ct, sizeof(ct)))
-                       err = -EFAULT;
-       return err;
-}
-
-static long raw1394_compat_ioctl(struct file *file,
-                                unsigned int cmd, unsigned long arg)
-{
-       struct file_info *fi = file->private_data;
-       void __user *argp = (void __user *)arg;
-       long err;
-
-       switch (cmd) {
-       /* These requests have same format as long as 'int' has same size. */
-       case RAW1394_IOC_ISO_RECV_INIT:
-       case RAW1394_IOC_ISO_RECV_START:
-       case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-       case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-       case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:
-       case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-       case RAW1394_IOC_ISO_RECV_FLUSH:
-       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-       case RAW1394_IOC_ISO_XMIT_INIT:
-       case RAW1394_IOC_ISO_XMIT_START:
-       case RAW1394_IOC_ISO_XMIT_SYNC:
-       case RAW1394_IOC_ISO_GET_STATUS:
-       case RAW1394_IOC_ISO_SHUTDOWN:
-       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-               err = raw1394_ioctl(file, cmd, arg);
-               break;
-       /* These request have different format. */
-       case RAW1394_IOC_ISO_RECV_PACKETS32:
-               err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp);
-               break;
-       case RAW1394_IOC_ISO_XMIT_PACKETS32:
-               err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp);
-               break;
-       case RAW1394_IOC_GET_CYCLE_TIMER32:
-               err = raw1394_read_cycle_timer32(fi, argp);
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-
-       return err;
-}
-#endif
-
-static unsigned int raw1394_poll(struct file *file, poll_table * pt)
-{
-       struct file_info *fi = file->private_data;
-       unsigned int mask = POLLOUT | POLLWRNORM;
-       unsigned long flags;
-
-       poll_wait(file, &fi->wait_complete, pt);
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       if (!list_empty(&fi->req_complete)) {
-               mask |= POLLIN | POLLRDNORM;
-       }
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-       return mask;
-}
-
-static int raw1394_open(struct inode *inode, struct file *file)
-{
-       struct file_info *fi;
-
-       fi = kzalloc(sizeof(*fi), GFP_KERNEL);
-       if (!fi)
-               return -ENOMEM;
-
-       fi->notification = (u8) RAW1394_NOTIFY_ON;      /* busreset notification */
-
-       INIT_LIST_HEAD(&fi->list);
-       mutex_init(&fi->state_mutex);
-       fi->state = opened;
-       INIT_LIST_HEAD(&fi->req_pending);
-       INIT_LIST_HEAD(&fi->req_complete);
-       spin_lock_init(&fi->reqlists_lock);
-       init_waitqueue_head(&fi->wait_complete);
-       INIT_LIST_HEAD(&fi->addr_list);
-
-       file->private_data = fi;
-
-       return nonseekable_open(inode, file);
-}
-
-static int raw1394_release(struct inode *inode, struct file *file)
-{
-       struct file_info *fi = file->private_data;
-       struct list_head *lh;
-       struct pending_request *req;
-       int i, fail;
-       int retval = 0;
-       struct list_head *entry;
-       struct arm_addr *addr = NULL;
-       struct host_info *hi;
-       struct file_info *fi_hlp = NULL;
-       struct arm_addr *arm_addr = NULL;
-       int another_host;
-       int csr_mod = 0;
-       unsigned long flags;
-
-       if (fi->iso_state != RAW1394_ISO_INACTIVE)
-               raw1394_iso_shutdown(fi);
-
-       spin_lock_irqsave(&host_info_lock, flags);
-
-       fail = 0;
-       /* set address-entries invalid */
-
-       while (!list_empty(&fi->addr_list)) {
-               another_host = 0;
-               lh = fi->addr_list.next;
-               addr = list_entry(lh, struct arm_addr, addr_list);
-               /* another host with valid address-entry containing
-                  same addressrange? */
-               list_for_each_entry(hi, &host_info_list, list) {
-                       if (hi->host != fi->host) {
-                               list_for_each_entry(fi_hlp, &hi->file_info_list,
-                                                   list) {
-                                       entry = fi_hlp->addr_list.next;
-                                       while (entry != &(fi_hlp->addr_list)) {
-                                               arm_addr = list_entry(entry, struct
-                                                                     arm_addr,
-                                                                     addr_list);
-                                               if (arm_addr->start ==
-                                                   addr->start) {
-                                                       DBGMSG
-                                                           ("raw1394_release: "
-                                                            "another host ownes "
-                                                            "same addressrange");
-                                                       another_host = 1;
-                                                       break;
-                                               }
-                                               entry = entry->next;
-                                       }
-                                       if (another_host) {
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               if (!another_host) {
-                       DBGMSG("raw1394_release: call hpsb_arm_unregister");
-                       retval =
-                           hpsb_unregister_addrspace(&raw1394_highlevel,
-                                                     fi->host, addr->start);
-                       if (!retval) {
-                               ++fail;
-                               printk(KERN_ERR
-                                      "raw1394_release arm_Unregister failed\n");
-                       }
-               }
-               DBGMSG("raw1394_release: delete addr_entry from list");
-               list_del(&addr->addr_list);
-               vfree(addr->addr_space_buffer);
-               kfree(addr);
-       }                       /* while */
-       spin_unlock_irqrestore(&host_info_lock, flags);
-       if (fail > 0) {
-               printk(KERN_ERR "raw1394: during addr_list-release "
-                      "error(s) occurred \n");
-       }
-
-       for (;;) {
-               /* This locked section guarantees that neither
-                * complete nor pending requests exist once i!=0 */
-               spin_lock_irqsave(&fi->reqlists_lock, flags);
-               while ((req = __next_complete_req(fi)))
-                       free_pending_request(req);
-
-               i = list_empty(&fi->req_pending);
-               spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-               if (i)
-                       break;
-               /*
-                * Sleep until more requests can be freed.
-                *
-                * NB: We call the macro wait_event() with a condition argument
-                * with side effect.  This is only possible because the side
-                * effect does not occur until the condition became true, and
-                * wait_event() won't evaluate the condition again after that.
-                */
-               wait_event(fi->wait_complete, (req = next_complete_req(fi)));
-               free_pending_request(req);
-       }
-
-       /* Remove any sub-trees left by user space programs */
-       for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
-               struct csr1212_dentry *dentry;
-               if (!fi->csr1212_dirs[i])
-                       continue;
-               for (dentry =
-                    fi->csr1212_dirs[i]->value.directory.dentries_head; dentry;
-                    dentry = dentry->next) {
-                       csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-                                                            root_kv,
-                                                            dentry->kv);
-               }
-               csr1212_release_keyval(fi->csr1212_dirs[i]);
-               fi->csr1212_dirs[i] = NULL;
-               csr_mod = 1;
-       }
-
-       if ((csr_mod || fi->cfgrom_upd)
-           && hpsb_update_config_rom_image(fi->host) < 0)
-               HPSB_ERR
-                   ("Failed to generate Configuration ROM image for host %d",
-                    fi->host->id);
-
-       if (fi->state == connected) {
-               spin_lock_irqsave(&host_info_lock, flags);
-               list_del(&fi->list);
-               spin_unlock_irqrestore(&host_info_lock, flags);
-
-               put_device(&fi->host->device);
-       }
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       if (fi->host)
-               module_put(fi->host->driver->owner);
-       spin_unlock_irqrestore(&host_info_lock, flags);
-
-       kfree(fi);
-
-       return 0;
-}
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id raw1394_id_table[] = {
-       {
-        .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-        .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
-        .version = AVC_SW_VERSION_ENTRY & 0xffffff},
-       {
-        .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-        .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-        .version = CAMERA_SW_VERSION_ENTRY & 0xffffff},
-       {
-        .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-        .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-        .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff},
-       {
-        .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-        .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-        .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff},
-       {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver raw1394_driver = {
-       .name = "raw1394",
-};
-
-/******************************************************************************/
-
-static struct hpsb_highlevel raw1394_highlevel = {
-       .name = RAW1394_DEVICE_NAME,
-       .add_host = add_host,
-       .remove_host = remove_host,
-       .host_reset = host_reset,
-       .fcp_request = fcp_request,
-};
-
-static struct cdev raw1394_cdev;
-static const struct file_operations raw1394_fops = {
-       .owner = THIS_MODULE,
-       .read = raw1394_read,
-       .write = raw1394_write,
-       .mmap = raw1394_mmap,
-       .unlocked_ioctl = raw1394_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = raw1394_compat_ioctl,
-#endif
-       .poll = raw1394_poll,
-       .open = raw1394_open,
-       .release = raw1394_release,
-       .llseek = no_llseek,
-};
-
-static int __init init_raw1394(void)
-{
-       int ret = 0;
-
-       hpsb_register_highlevel(&raw1394_highlevel);
-
-       if (IS_ERR
-           (device_create(hpsb_protocol_class, NULL,
-                          MKDEV(IEEE1394_MAJOR,
-                                IEEE1394_MINOR_BLOCK_RAW1394 * 16),
-                          NULL, RAW1394_DEVICE_NAME))) {
-               ret = -EFAULT;
-               goto out_unreg;
-       }
-
-       cdev_init(&raw1394_cdev, &raw1394_fops);
-       raw1394_cdev.owner = THIS_MODULE;
-       ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
-       if (ret) {
-               HPSB_ERR("raw1394 failed to register minor device block");
-               goto out_dev;
-       }
-
-       HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
-
-       ret = hpsb_register_protocol(&raw1394_driver);
-       if (ret) {
-               HPSB_ERR("raw1394: failed to register protocol");
-               cdev_del(&raw1394_cdev);
-               goto out_dev;
-       }
-
-       goto out;
-
-      out_dev:
-       device_destroy(hpsb_protocol_class,
-                      MKDEV(IEEE1394_MAJOR,
-                            IEEE1394_MINOR_BLOCK_RAW1394 * 16));
-      out_unreg:
-       hpsb_unregister_highlevel(&raw1394_highlevel);
-      out:
-       return ret;
-}
-
-static void __exit cleanup_raw1394(void)
-{
-       device_destroy(hpsb_protocol_class,
-                      MKDEV(IEEE1394_MAJOR,
-                            IEEE1394_MINOR_BLOCK_RAW1394 * 16));
-       cdev_del(&raw1394_cdev);
-       hpsb_unregister_highlevel(&raw1394_highlevel);
-       hpsb_unregister_protocol(&raw1394_driver);
-}
-
-module_init(init_raw1394);
-module_exit(cleanup_raw1394);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
deleted file mode 100644 (file)
index 963ac20..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef IEEE1394_RAW1394_H
-#define IEEE1394_RAW1394_H
-
-/* header for the raw1394 API that is exported to user-space */
-
-#define RAW1394_KERNELAPI_VERSION 4
-
-/* state: opened */
-#define RAW1394_REQ_INITIALIZE    1
-
-/* state: initialized */
-#define RAW1394_REQ_LIST_CARDS    2
-#define RAW1394_REQ_SET_CARD      3
-
-/* state: connected */
-#define RAW1394_REQ_ASYNC_READ      100
-#define RAW1394_REQ_ASYNC_WRITE     101
-#define RAW1394_REQ_LOCK            102
-#define RAW1394_REQ_LOCK64          103
-#define RAW1394_REQ_ISO_SEND        104 /* removed ABI, now a no-op */
-#define RAW1394_REQ_ASYNC_SEND      105
-#define RAW1394_REQ_ASYNC_STREAM    106
-
-#define RAW1394_REQ_ISO_LISTEN      200 /* removed ABI, now a no-op */
-#define RAW1394_REQ_FCP_LISTEN      201
-#define RAW1394_REQ_RESET_BUS       202
-#define RAW1394_REQ_GET_ROM         203
-#define RAW1394_REQ_UPDATE_ROM      204
-#define RAW1394_REQ_ECHO            205
-#define RAW1394_REQ_MODIFY_ROM      206
-
-#define RAW1394_REQ_ARM_REGISTER    300
-#define RAW1394_REQ_ARM_UNREGISTER  301
-#define RAW1394_REQ_ARM_SET_BUF     302
-#define RAW1394_REQ_ARM_GET_BUF     303
-
-#define RAW1394_REQ_RESET_NOTIFY    400
-
-#define RAW1394_REQ_PHYPACKET       500
-
-/* kernel to user */
-#define RAW1394_REQ_BUS_RESET        10000
-#define RAW1394_REQ_ISO_RECEIVE      10001
-#define RAW1394_REQ_FCP_REQUEST      10002
-#define RAW1394_REQ_ARM              10003
-#define RAW1394_REQ_RAWISO_ACTIVITY  10004
-
-/* error codes */
-#define RAW1394_ERROR_NONE        0
-#define RAW1394_ERROR_COMPAT      (-1001)
-#define RAW1394_ERROR_STATE_ORDER (-1002)
-#define RAW1394_ERROR_GENERATION  (-1003)
-#define RAW1394_ERROR_INVALID_ARG (-1004)
-#define RAW1394_ERROR_MEMFAULT    (-1005)
-#define RAW1394_ERROR_ALREADY     (-1006)
-
-#define RAW1394_ERROR_EXCESSIVE   (-1020)
-#define RAW1394_ERROR_UNTIDY_LEN  (-1021)
-
-#define RAW1394_ERROR_SEND_ERROR  (-1100)
-#define RAW1394_ERROR_ABORTED     (-1101)
-#define RAW1394_ERROR_TIMEOUT     (-1102)
-
-/* arm_codes */
-#define ARM_READ   1
-#define ARM_WRITE  2
-#define ARM_LOCK   4
-
-#define RAW1394_LONG_RESET  0
-#define RAW1394_SHORT_RESET 1
-
-/* busresetnotify ... */
-#define RAW1394_NOTIFY_OFF 0
-#define RAW1394_NOTIFY_ON  1
-
-#include <asm/types.h>
-
-struct raw1394_request {
-        __u32 type;
-        __s32 error;
-        __u32 misc;
-
-        __u32 generation;
-        __u32 length;
-
-        __u64 address;
-
-        __u64 tag;
-
-        __u64 sendb;
-        __u64 recvb;
-};
-
-struct raw1394_khost_list {
-        __u32 nodes;
-        __u8 name[32];
-};
-
-typedef struct arm_request {
-        __u16           destination_nodeid;
-        __u16           source_nodeid;
-        __u64           destination_offset;
-        __u8            tlabel;
-        __u8            tcode;
-        __u8            extended_transaction_code;
-        __u32           generation;
-        __u16           buffer_length;
-        __u8            __user *buffer;
-} *arm_request_t;
-
-typedef struct arm_response {
-        __s32           response_code;
-        __u16           buffer_length;
-        __u8            __user *buffer;
-} *arm_response_t;
-
-typedef struct arm_request_response {
-        struct arm_request  __user *request;
-        struct arm_response __user *response;
-} *arm_request_response_t;
-
-/* rawiso API */
-#include "ieee1394-ioctl.h"
-
-/* per-packet metadata embedded in the ringbuffer */
-/* must be identical to hpsb_iso_packet_info in iso.h! */
-struct raw1394_iso_packet_info {
-       __u32 offset;
-       __u16 len;
-       __u16 cycle;   /* recv only */
-       __u8  channel; /* recv only */
-       __u8  tag;
-       __u8  sy;
-};
-
-/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
-struct raw1394_iso_packets {
-       __u32 n_packets;
-       struct raw1394_iso_packet_info __user *infos;
-};
-
-struct raw1394_iso_config {
-       /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
-       __u32 data_buf_size;
-
-       /* # of packets to buffer */
-       __u32 buf_packets;
-
-       /* iso channel (set to -1 for multi-channel recv) */
-       __s32 channel;
-
-       /* xmit only - iso transmission speed */
-       __u8 speed;
-
-       /* The mode of the dma when receiving iso data. Must be supported by chip */
-       __u8 dma_mode;
-
-       /* max. latency of buffer, in packets (-1 if you don't care) */
-       __s32 irq_interval;
-};
-
-/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
-struct raw1394_iso_status {
-       /* current settings */
-       struct raw1394_iso_config config;
-
-       /* number of packets waiting to be filled with data (ISO transmission)
-          or containing data received (ISO reception) */
-       __u32 n_packets;
-
-       /* approximate number of packets dropped due to overflow or
-          underflow of the packet buffer (a value of zero guarantees
-          that no packets have been dropped) */
-       __u32 overflows;
-
-       /* cycle number at which next packet will be transmitted;
-          -1 if not known */
-       __s16 xmit_cycle;
-};
-
-/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
-struct raw1394_cycle_timer {
-       /* contents of Isochronous Cycle Timer register,
-          as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
-       __u32 cycle_timer;
-
-       /* local time in microseconds since Epoch,
-          simultaneously read with cycle timer */
-       __u64 local_time;
-};
-#endif /* IEEE1394_RAW1394_H */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
deleted file mode 100644 (file)
index d6e251a..0000000
+++ /dev/null
@@ -1,2138 +0,0 @@
-/*
- * sbp2.c - SBP-2 protocol driver for IEEE-1394
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com (JSG)
- *
- * Copyright (C) 2003 Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- */
-
-/*
- * Brief Description:
- *
- * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394
- * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level
- * driver. It also registers as a SCSI lower-level driver in order to accept
- * SCSI commands for transport using SBP-2.
- *
- * You may access any attached SBP-2 (usually storage devices) as regular
- * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc..
- *
- * See http://www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2
- * specification and for where to purchase the official standard.
- *
- * TODO:
- *   - look into possible improvements of the SCSI error handlers
- *   - handle Unit_Characteristics.mgt_ORB_timeout and .ORB_size
- *   - handle Logical_Unit_Number.ordered
- *   - handle src == 1 in status blocks
- *   - reimplement the DMA mapping in absence of physical DMA so that
- *     bus_to_virt is no longer required
- *   - debug the handling of absent physical DMA
- *   - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection
- *     (this is easy but depends on the previous two TODO items)
- *   - make the parameter serialize_io configurable per device
- *   - move all requests to fetch agent registers into non-atomic context,
- *     replace all usages of sbp2util_node_write_no_wait by true transactions
- * Grep for inline FIXME comments below.
- */
-
-#include <linux/blkdev.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/errno.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-#include <asm/io.h> /* for bus_to_virt */
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "sbp2.h"
-
-/*
- * Module load parameter definitions
- */
-
-/*
- * Change max_speed on module load if you have a bad IEEE-1394
- * controller that has trouble running 2KB packets at 400mb.
- *
- * NOTE: On certain OHCI parts I have seen short packets on async transmit
- * (probably due to PCI latency/throughput issues with the part). You can
- * bump down the speed if you are running into problems.
- */
-static int sbp2_max_speed = IEEE1394_SPEED_MAX;
-module_param_named(max_speed, sbp2_max_speed, int, 0644);
-MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, "
-                "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)");
-
-/*
- * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs.
- * This is and always has been buggy in multiple subtle ways. See above TODOs.
- */
-static int sbp2_serialize_io = 1;
-module_param_named(serialize_io, sbp2_serialize_io, bool, 0444);
-MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
-                "(default = Y, faster but buggy = N)");
-
-/*
- * Adjust max_sectors if you'd like to influence how many sectors each SCSI
- * command can transfer at most. Please note that some older SBP-2 bridge
- * chips are broken for transfers greater or equal to 128KB, therefore
- * max_sectors used to be a safe 255 sectors for many years. We now have a
- * default of 0 here which means that we let the SCSI stack choose a limit.
- *
- * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds
- * module parameter or in the sbp2_workarounds_table[], will override the
- * value of max_sectors. We should use sbp2_workarounds_table[] to cover any
- * bridge chip which becomes known to need the 255 sectors limit.
- */
-static int sbp2_max_sectors;
-module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
-MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
-                "(default = 0 = use SCSI stack's default)");
-
-/*
- * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
- * do an exclusive login, as it's generally unsafe to have two hosts
- * talking to a single sbp2 device at the same time (filesystem coherency,
- * etc.). If you're running an sbp2 device that supports multiple logins,
- * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, e.g. OpenGFS, Oracle Cluster
- * File System, or Lustre, then set exclusive_login to zero.
- *
- * So far only bridges from Oxford Semiconductor are known to support
- * concurrent logins. Depending on firmware, four or two concurrent logins
- * are possible on OXFW911 and newer Oxsemi bridges.
- */
-static int sbp2_exclusive_login = 1;
-module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
-MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
-                "(default = Y, use N for concurrent initiators)");
-
-/*
- * If any of the following workarounds is required for your device to work,
- * please submit the kernel messages logged by sbp2 to the linux1394-devel
- * mailing list.
- *
- * - 128kB max transfer
- *   Limit transfer size. Necessary for some old bridges.
- *
- * - 36 byte inquiry
- *   When scsi_mod probes the device, let the inquiry command look like that
- *   from MS Windows.
- *
- * - skip mode page 8
- *   Suppress sending of mode_sense for mode page 8 if the device pretends to
- *   support the SCSI Primary Block commands instead of Reduced Block Commands.
- *
- * - fix capacity
- *   Tell sd_mod to correct the last sector number reported by read_capacity.
- *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
- *   Don't use this with devices which don't have this bug.
- *
- * - delay inquiry
- *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
- *
- * - power condition
- *   Set the power condition field in the START STOP UNIT commands sent by
- *   sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
- *   Some disks need this to spin down or to resume properly.
- *
- * - override internal blacklist
- *   Instead of adding to the built-in blacklist, use only the workarounds
- *   specified in the module load parameter.
- *   Useful if a blacklist entry interfered with a non-broken device.
- */
-static int sbp2_default_workarounds;
-module_param_named(workarounds, sbp2_default_workarounds, int, 0644);
-MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
-       ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
-       ", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
-       ", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
-       ", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
-       ", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
-       ", set power condition in start stop unit = "
-                                 __stringify(SBP2_WORKAROUND_POWER_CONDITION)
-       ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
-       ", or a combination)");
-
-/*
- * This influences the format of the sysfs attribute
- * /sys/bus/scsi/devices/.../ieee1394_id.
- *
- * The default format is like in older kernels:  %016Lx:%d:%d
- * It contains the target's EUI-64, a number given to the logical unit by
- * the ieee1394 driver's nodemgr (starting at 0), and the LUN.
- *
- * The long format is:  %016Lx:%06x:%04x
- * It contains the target's EUI-64, the unit directory's directory_ID as per
- * IEEE 1212 clause 7.7.19, and the LUN.  This format comes closest to the
- * format of SBP(-3) target port and logical unit identifier as per SAM (SCSI
- * Architecture Model) rev.2 to 4 annex A.  Therefore and because it is
- * independent of the implementation of the ieee1394 nodemgr, the longer format
- * is recommended for future use.
- */
-static int sbp2_long_sysfs_ieee1394_id;
-module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644);
-MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs "
-                "(default = backwards-compatible = N, SAM-conforming = Y)");
-
-
-#define SBP2_INFO(fmt, args...)        HPSB_INFO("sbp2: "fmt, ## args)
-#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
-
-/*
- * Globals
- */
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32);
-static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *,
-                                     void (*)(struct scsi_cmnd *));
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *);
-static int sbp2_start_device(struct sbp2_lu *);
-static void sbp2_remove_device(struct sbp2_lu *);
-static int sbp2_login_device(struct sbp2_lu *);
-static int sbp2_reconnect_device(struct sbp2_lu *);
-static int sbp2_logout_device(struct sbp2_lu *);
-static void sbp2_host_reset(struct hpsb_host *);
-static int sbp2_handle_status_write(struct hpsb_host *, int, int, quadlet_t *,
-                                   u64, size_t, u16);
-static int sbp2_agent_reset(struct sbp2_lu *, int);
-static void sbp2_parse_unit_directory(struct sbp2_lu *,
-                                     struct unit_directory *);
-static int sbp2_set_busy_timeout(struct sbp2_lu *);
-static int sbp2_max_speed_and_size(struct sbp2_lu *);
-
-
-static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa };
-
-static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
-
-static struct hpsb_highlevel sbp2_highlevel = {
-       .name           = SBP2_DEVICE_NAME,
-       .host_reset     = sbp2_host_reset,
-};
-
-static const struct hpsb_address_ops sbp2_ops = {
-       .write          = sbp2_handle_status_write
-};
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *,
-                                    u64, size_t, u16);
-static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64,
-                                   size_t, u16);
-
-static const struct hpsb_address_ops sbp2_physdma_ops = {
-       .read           = sbp2_handle_physdma_read,
-       .write          = sbp2_handle_physdma_write,
-};
-#endif
-
-
-/*
- * Interface to driver core and IEEE 1394 core
- */
-static const struct ieee1394_device_id sbp2_id_table[] = {
-       {
-        .match_flags   = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-        .specifier_id  = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
-        .version       = SBP2_SW_VERSION_ENTRY & 0xffffff},
-       {}
-};
-MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
-
-static int sbp2_probe(struct device *);
-static int sbp2_remove(struct device *);
-static int sbp2_update(struct unit_directory *);
-
-static struct hpsb_protocol_driver sbp2_driver = {
-       .name           = SBP2_DEVICE_NAME,
-       .id_table       = sbp2_id_table,
-       .update         = sbp2_update,
-       .driver         = {
-               .probe          = sbp2_probe,
-               .remove         = sbp2_remove,
-       },
-};
-
-
-/*
- * Interface to SCSI core
- */
-static int sbp2scsi_queuecommand(struct scsi_cmnd *,
-                                void (*)(struct scsi_cmnd *));
-static int sbp2scsi_abort(struct scsi_cmnd *);
-static int sbp2scsi_reset(struct scsi_cmnd *);
-static int sbp2scsi_slave_alloc(struct scsi_device *);
-static int sbp2scsi_slave_configure(struct scsi_device *);
-static void sbp2scsi_slave_destroy(struct scsi_device *);
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *,
-                                          struct device_attribute *, char *);
-
-static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
-
-static struct device_attribute *sbp2_sysfs_sdev_attrs[] = {
-       &dev_attr_ieee1394_id,
-       NULL
-};
-
-static struct scsi_host_template sbp2_shost_template = {
-       .module                  = THIS_MODULE,
-       .name                    = "SBP-2 IEEE-1394",
-       .proc_name               = SBP2_DEVICE_NAME,
-       .queuecommand            = sbp2scsi_queuecommand,
-       .eh_abort_handler        = sbp2scsi_abort,
-       .eh_device_reset_handler = sbp2scsi_reset,
-       .slave_alloc             = sbp2scsi_slave_alloc,
-       .slave_configure         = sbp2scsi_slave_configure,
-       .slave_destroy           = sbp2scsi_slave_destroy,
-       .this_id                 = -1,
-       .sg_tablesize            = SG_ALL,
-       .use_clustering          = ENABLE_CLUSTERING,
-       .cmd_per_lun             = SBP2_MAX_CMDS,
-       .can_queue               = SBP2_MAX_CMDS,
-       .sdev_attrs              = sbp2_sysfs_sdev_attrs,
-};
-
-#define SBP2_ROM_VALUE_WILDCARD ~0         /* match all */
-#define SBP2_ROM_VALUE_MISSING  0xff000000 /* not present in the unit dir. */
-
-/*
- * List of devices with known bugs.
- *
- * The firmware_revision field, masked with 0xffff00, is the best indicator
- * for the type of bridge chip of a device.  It yields a few false positives
- * but this did not break correctly behaving devices so far.
- */
-static const struct {
-       u32 firmware_revision;
-       u32 model;
-       unsigned workarounds;
-} sbp2_workarounds_table[] = {
-       /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
-               .firmware_revision      = 0x002800,
-               .model                  = 0x001010,
-               .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
-                                         SBP2_WORKAROUND_MODE_SENSE_8 |
-                                         SBP2_WORKAROUND_POWER_CONDITION,
-       },
-       /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
-               .firmware_revision      = 0x002800,
-               .model                  = 0x000000,
-               .workarounds            = SBP2_WORKAROUND_POWER_CONDITION,
-       },
-       /* Initio bridges, actually only needed for some older ones */ {
-               .firmware_revision      = 0x000200,
-               .model                  = SBP2_ROM_VALUE_WILDCARD,
-               .workarounds            = SBP2_WORKAROUND_INQUIRY_36,
-       },
-       /* PL-3507 bridge with Prolific firmware */ {
-               .firmware_revision      = 0x012800,
-               .model                  = SBP2_ROM_VALUE_WILDCARD,
-               .workarounds            = SBP2_WORKAROUND_POWER_CONDITION,
-       },
-       /* Symbios bridge */ {
-               .firmware_revision      = 0xa0b800,
-               .model                  = SBP2_ROM_VALUE_WILDCARD,
-               .workarounds            = SBP2_WORKAROUND_128K_MAX_TRANS,
-       },
-       /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
-               .firmware_revision      = 0x002600,
-               .model                  = SBP2_ROM_VALUE_WILDCARD,
-               .workarounds            = SBP2_WORKAROUND_128K_MAX_TRANS,
-       },
-       /*
-        * iPod 2nd generation: needs 128k max transfer size workaround
-        * iPod 3rd generation: needs fix capacity workaround
-        */
-       {
-               .firmware_revision      = 0x0a2700,
-               .model                  = 0x000000,
-               .workarounds            = SBP2_WORKAROUND_128K_MAX_TRANS |
-                                         SBP2_WORKAROUND_FIX_CAPACITY,
-       },
-       /* iPod 4th generation */ {
-               .firmware_revision      = 0x0a2700,
-               .model                  = 0x000021,
-               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
-       },
-       /* iPod mini */ {
-               .firmware_revision      = 0x0a2700,
-               .model                  = 0x000022,
-               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
-       },
-       /* iPod mini */ {
-               .firmware_revision      = 0x0a2700,
-               .model                  = 0x000023,
-               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
-       },
-       /* iPod Photo */ {
-               .firmware_revision      = 0x0a2700,
-               .model                  = 0x00007e,
-               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
-       }
-};
-
-/**************************************
- * General utility functions
- **************************************/
-
-#ifndef __BIG_ENDIAN
-/*
- * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
- */
-static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
-{
-       u32 *temp = buffer;
-
-       for (length = (length >> 2); length--; )
-               temp[length] = be32_to_cpu(temp[length]);
-}
-
-/*
- * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
- */
-static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
-{
-       u32 *temp = buffer;
-
-       for (length = (length >> 2); length--; )
-               temp[length] = cpu_to_be32(temp[length]);
-}
-#else /* BIG_ENDIAN */
-/* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
-#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq);
-
-/*
- * Waits for completion of an SBP-2 access request.
- * Returns nonzero if timed out or prematurely interrupted.
- */
-static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout)
-{
-       long leftover;
-
-       leftover = wait_event_interruptible_timeout(
-                       sbp2_access_wq, lu->access_complete, timeout);
-       lu->access_complete = 0;
-       return leftover <= 0;
-}
-
-static void sbp2_free_packet(void *packet)
-{
-       hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-}
-
-/*
- * This is much like hpsb_node_write(), except it ignores the response
- * subaction and returns immediately. Can be used from atomic context.
- */
-static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
-                                      quadlet_t *buf, size_t len)
-{
-       struct hpsb_packet *packet;
-
-       packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len);
-       if (!packet)
-               return -ENOMEM;
-
-       hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet);
-       hpsb_node_fill_packet(ne, packet);
-       if (hpsb_send_packet(packet) < 0) {
-               sbp2_free_packet(packet);
-               return -EIO;
-       }
-       return 0;
-}
-
-static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset,
-                                       quadlet_t *data, size_t len)
-{
-       /* There is a small window after a bus reset within which the node
-        * entry's generation is current but the reconnect wasn't completed. */
-       if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET))
-               return;
-
-       if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset,
-                           data, len))
-               SBP2_ERR("sbp2util_notify_fetch_agent failed.");
-
-       /* Now accept new SCSI commands, unless a bus reset happended during
-        * hpsb_node_write. */
-       if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET))
-               scsi_unblock_requests(lu->shost);
-}
-
-static void sbp2util_write_orb_pointer(struct work_struct *work)
-{
-       struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-       quadlet_t data[2];
-
-       data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id);
-       data[1] = lu->last_orb_dma;
-       sbp2util_cpu_to_be32_buffer(data, 8);
-       sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);
-}
-
-static void sbp2util_write_doorbell(struct work_struct *work)
-{
-       struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-
-       sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);
-}
-
-static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
-{
-       struct sbp2_command_info *cmd;
-       struct device *dmadev = lu->hi->host->device.parent;
-       int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
-       for (i = 0; i < orbs; i++) {
-               cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-               if (!cmd)
-                       goto failed_alloc;
-
-               cmd->command_orb_dma =
-                   dma_map_single(dmadev, &cmd->command_orb,
-                                  sizeof(struct sbp2_command_orb),
-                                  DMA_TO_DEVICE);
-               if (dma_mapping_error(dmadev, cmd->command_orb_dma))
-                       goto failed_orb;
-
-               cmd->sge_dma =
-                   dma_map_single(dmadev, &cmd->scatter_gather_element,
-                                  sizeof(cmd->scatter_gather_element),
-                                  DMA_TO_DEVICE);
-               if (dma_mapping_error(dmadev, cmd->sge_dma))
-                       goto failed_sge;
-
-               INIT_LIST_HEAD(&cmd->list);
-               list_add_tail(&cmd->list, &lu->cmd_orb_completed);
-       }
-       return 0;
-
-failed_sge:
-       dma_unmap_single(dmadev, cmd->command_orb_dma,
-                        sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-failed_orb:
-       kfree(cmd);
-failed_alloc:
-       return -ENOMEM;
-}
-
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
-                                            struct hpsb_host *host)
-{
-       struct list_head *lh, *next;
-       struct sbp2_command_info *cmd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       if (!list_empty(&lu->cmd_orb_completed))
-               list_for_each_safe(lh, next, &lu->cmd_orb_completed) {
-                       cmd = list_entry(lh, struct sbp2_command_info, list);
-                       dma_unmap_single(host->device.parent,
-                                        cmd->command_orb_dma,
-                                        sizeof(struct sbp2_command_orb),
-                                        DMA_TO_DEVICE);
-                       dma_unmap_single(host->device.parent, cmd->sge_dma,
-                                        sizeof(cmd->scatter_gather_element),
-                                        DMA_TO_DEVICE);
-                       kfree(cmd);
-               }
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-       return;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding command ORB.
- * Only looks at the in-use list.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_orb(
-                               struct sbp2_lu *lu, dma_addr_t orb)
-{
-       struct sbp2_command_info *cmd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       if (!list_empty(&lu->cmd_orb_inuse))
-               list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
-                       if (cmd->command_orb_dma == orb) {
-                               spin_unlock_irqrestore(
-                                               &lu->cmd_orb_lock, flags);
-                               return cmd;
-                       }
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-       return NULL;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding SCpnt.
- * Only looks at the in-use list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
-                               struct sbp2_lu *lu, void *SCpnt)
-{
-       struct sbp2_command_info *cmd;
-
-       if (!list_empty(&lu->cmd_orb_inuse))
-               list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
-                       if (cmd->Current_SCpnt == SCpnt)
-                               return cmd;
-       return NULL;
-}
-
-static struct sbp2_command_info *sbp2util_allocate_command_orb(
-                               struct sbp2_lu *lu,
-                               struct scsi_cmnd *Current_SCpnt,
-                               void (*Current_done)(struct scsi_cmnd *))
-{
-       struct list_head *lh;
-       struct sbp2_command_info *cmd = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       if (!list_empty(&lu->cmd_orb_completed)) {
-               lh = lu->cmd_orb_completed.next;
-               list_del(lh);
-               cmd = list_entry(lh, struct sbp2_command_info, list);
-               cmd->Current_done = Current_done;
-               cmd->Current_SCpnt = Current_SCpnt;
-               list_add_tail(&cmd->list, &lu->cmd_orb_inuse);
-       } else
-               SBP2_ERR("%s: no orbs available", __func__);
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-       return cmd;
-}
-
-/*
- * Unmaps the DMAs of a command and moves the command to the completed ORB list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
-                                           struct sbp2_command_info *cmd)
-{
-       if (scsi_sg_count(cmd->Current_SCpnt))
-               dma_unmap_sg(lu->ud->ne->host->device.parent,
-                            scsi_sglist(cmd->Current_SCpnt),
-                            scsi_sg_count(cmd->Current_SCpnt),
-                            cmd->Current_SCpnt->sc_data_direction);
-       list_move_tail(&cmd->list, &lu->cmd_orb_completed);
-}
-
-/*
- * Is lu valid? Is the 1394 node still present?
- */
-static inline int sbp2util_node_is_available(struct sbp2_lu *lu)
-{
-       return lu && lu->ne && !lu->ne->in_limbo;
-}
-
-/*********************************************
- * IEEE-1394 core driver stack related section
- *********************************************/
-
-static int sbp2_probe(struct device *dev)
-{
-       struct unit_directory *ud;
-       struct sbp2_lu *lu;
-
-       ud = container_of(dev, struct unit_directory, device);
-
-       /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
-        * instead. */
-       if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)
-               return -ENODEV;
-
-       lu = sbp2_alloc_device(ud);
-       if (!lu)
-               return -ENOMEM;
-
-       sbp2_parse_unit_directory(lu, ud);
-       return sbp2_start_device(lu);
-}
-
-static int sbp2_remove(struct device *dev)
-{
-       struct unit_directory *ud;
-       struct sbp2_lu *lu;
-       struct scsi_device *sdev;
-
-       ud = container_of(dev, struct unit_directory, device);
-       lu = dev_get_drvdata(&ud->device);
-       if (!lu)
-               return 0;
-
-       if (lu->shost) {
-               /* Get rid of enqueued commands if there is no chance to
-                * send them. */
-               if (!sbp2util_node_is_available(lu))
-                       sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT);
-               /* scsi_remove_device() may trigger shutdown functions of SCSI
-                * highlevel drivers which would deadlock if blocked. */
-               atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN);
-               scsi_unblock_requests(lu->shost);
-       }
-       sdev = lu->sdev;
-       if (sdev) {
-               lu->sdev = NULL;
-               scsi_remove_device(sdev);
-       }
-
-       sbp2_logout_device(lu);
-       sbp2_remove_device(lu);
-
-       return 0;
-}
-
-static int sbp2_update(struct unit_directory *ud)
-{
-       struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
-
-       if (sbp2_reconnect_device(lu) != 0) {
-               /*
-                * Reconnect failed.  If another bus reset happened,
-                * let nodemgr proceed and call sbp2_update again later
-                * (or sbp2_remove if this node went away).
-                */
-               if (!hpsb_node_entry_valid(lu->ne))
-                       return 0;
-               /*
-                * Or the target rejected the reconnect because we weren't
-                * fast enough.  Try a regular login, but first log out
-                * just in case of any weirdness.
-                */
-               sbp2_logout_device(lu);
-
-               if (sbp2_login_device(lu) != 0) {
-                       if (!hpsb_node_entry_valid(lu->ne))
-                               return 0;
-
-                       /* Maybe another initiator won the login. */
-                       SBP2_ERR("Failed to reconnect to sbp2 device!");
-                       return -EBUSY;
-               }
-       }
-
-       sbp2_set_busy_timeout(lu);
-       sbp2_agent_reset(lu, 1);
-       sbp2_max_speed_and_size(lu);
-
-       /* Complete any pending commands with busy (so they get retried)
-        * and remove them from our queue. */
-       sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-
-       /* Accept new commands unless there was another bus reset in the
-        * meantime. */
-       if (hpsb_node_entry_valid(lu->ne)) {
-               atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
-               scsi_unblock_requests(lu->shost);
-       }
-       return 0;
-}
-
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
-{
-       struct sbp2_fwhost_info *hi;
-       struct Scsi_Host *shost = NULL;
-       struct sbp2_lu *lu = NULL;
-       unsigned long flags;
-
-       lu = kzalloc(sizeof(*lu), GFP_KERNEL);
-       if (!lu) {
-               SBP2_ERR("failed to create lu");
-               goto failed_alloc;
-       }
-
-       lu->ne = ud->ne;
-       lu->ud = ud;
-       lu->speed_code = IEEE1394_SPEED_100;
-       lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
-       lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
-       INIT_LIST_HEAD(&lu->cmd_orb_inuse);
-       INIT_LIST_HEAD(&lu->cmd_orb_completed);
-       INIT_LIST_HEAD(&lu->lu_list);
-       spin_lock_init(&lu->cmd_orb_lock);
-       atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
-       INIT_WORK(&lu->protocol_work, NULL);
-
-       dev_set_drvdata(&ud->device, lu);
-
-       hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
-       if (!hi) {
-               hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host,
-                                         sizeof(*hi));
-               if (!hi) {
-                       SBP2_ERR("failed to allocate hostinfo");
-                       goto failed_alloc;
-               }
-               hi->host = ud->ne->host;
-               INIT_LIST_HEAD(&hi->logical_units);
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-               /* Handle data movement if physical dma is not
-                * enabled or not supported on host controller */
-               if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host,
-                                            &sbp2_physdma_ops,
-                                            0x0ULL, 0xfffffffcULL)) {
-                       SBP2_ERR("failed to register lower 4GB address range");
-                       goto failed_alloc;
-               }
-#endif
-       }
-
-       if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
-               BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
-                                           SBP2_MAX_SEG_SIZE));
-
-       /* Prevent unloading of the 1394 host */
-       if (!try_module_get(hi->host->driver->owner)) {
-               SBP2_ERR("failed to get a reference on 1394 host driver");
-               goto failed_alloc;
-       }
-
-       lu->hi = hi;
-
-       write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-       list_add_tail(&lu->lu_list, &hi->logical_units);
-       write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-       /* Register the status FIFO address range. We could use the same FIFO
-        * for targets at different nodes. However we need different FIFOs per
-        * target in order to support multi-unit devices.
-        * The FIFO is located out of the local host controller's physical range
-        * but, if possible, within the posted write area. Status writes will
-        * then be performed as unified transactions. This slightly reduces
-        * bandwidth usage, and some Prolific based devices seem to require it.
-        */
-       lu->status_fifo_addr = hpsb_allocate_and_register_addrspace(
-                       &sbp2_highlevel, ud->ne->host, &sbp2_ops,
-                       sizeof(struct sbp2_status_block), sizeof(quadlet_t),
-                       ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END);
-       if (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
-               SBP2_ERR("failed to allocate status FIFO address range");
-               goto failed_alloc;
-       }
-
-       shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long));
-       if (!shost) {
-               SBP2_ERR("failed to register scsi host");
-               goto failed_alloc;
-       }
-
-       shost->hostdata[0] = (unsigned long)lu;
-       shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
-
-       if (!scsi_add_host(shost, &ud->device)) {
-               lu->shost = shost;
-               return lu;
-       }
-
-       SBP2_ERR("failed to add scsi host");
-       scsi_host_put(shost);
-
-failed_alloc:
-       sbp2_remove_device(lu);
-       return NULL;
-}
-
-static void sbp2_host_reset(struct hpsb_host *host)
-{
-       struct sbp2_fwhost_info *hi;
-       struct sbp2_lu *lu;
-       unsigned long flags;
-
-       hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-       if (!hi)
-               return;
-
-       read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-
-       list_for_each_entry(lu, &hi->logical_units, lu_list)
-               if (atomic_cmpxchg(&lu->state,
-                                  SBP2LU_STATE_RUNNING, SBP2LU_STATE_IN_RESET)
-                   == SBP2LU_STATE_RUNNING)
-                       scsi_block_requests(lu->shost);
-
-       read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-}
-
-static int sbp2_start_device(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       int error;
-
-       lu->login_response = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_login_response),
-                                    &lu->login_response_dma, GFP_KERNEL);
-       if (!lu->login_response)
-               goto alloc_fail;
-
-       lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_query_logins_orb),
-                                    &lu->query_logins_orb_dma, GFP_KERNEL);
-       if (!lu->query_logins_orb)
-               goto alloc_fail;
-
-       lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_query_logins_response),
-                                    &lu->query_logins_response_dma, GFP_KERNEL);
-       if (!lu->query_logins_response)
-               goto alloc_fail;
-
-       lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_reconnect_orb),
-                                    &lu->reconnect_orb_dma, GFP_KERNEL);
-       if (!lu->reconnect_orb)
-               goto alloc_fail;
-
-       lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_logout_orb),
-                                    &lu->logout_orb_dma, GFP_KERNEL);
-       if (!lu->logout_orb)
-               goto alloc_fail;
-
-       lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
-                                    sizeof(struct sbp2_login_orb),
-                                    &lu->login_orb_dma, GFP_KERNEL);
-       if (!lu->login_orb)
-               goto alloc_fail;
-
-       if (sbp2util_create_command_orb_pool(lu))
-               goto alloc_fail;
-
-       /* Wait a second before trying to log in. Previously logged in
-        * initiators need a chance to reconnect. */
-       if (msleep_interruptible(1000)) {
-               sbp2_remove_device(lu);
-               return -EINTR;
-       }
-
-       if (sbp2_login_device(lu)) {
-               sbp2_remove_device(lu);
-               return -EBUSY;
-       }
-
-       sbp2_set_busy_timeout(lu);
-       sbp2_agent_reset(lu, 1);
-       sbp2_max_speed_and_size(lu);
-
-       if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
-               ssleep(SBP2_INQUIRY_DELAY);
-
-       error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
-       if (error) {
-               SBP2_ERR("scsi_add_device failed");
-               sbp2_logout_device(lu);
-               sbp2_remove_device(lu);
-               return error;
-       }
-
-       return 0;
-
-alloc_fail:
-       SBP2_ERR("Could not allocate memory for lu");
-       sbp2_remove_device(lu);
-       return -ENOMEM;
-}
-
-static void sbp2_remove_device(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi;
-       unsigned long flags;
-
-       if (!lu)
-               return;
-       hi = lu->hi;
-       if (!hi)
-               goto no_hi;
-
-       if (lu->shost) {
-               scsi_remove_host(lu->shost);
-               scsi_host_put(lu->shost);
-       }
-       flush_scheduled_work();
-       sbp2util_remove_command_orb_pool(lu, hi->host);
-
-       write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-       list_del(&lu->lu_list);
-       write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-       if (lu->login_response)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_login_response),
-                                   lu->login_response,
-                                   lu->login_response_dma);
-       if (lu->login_orb)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_login_orb),
-                                   lu->login_orb,
-                                   lu->login_orb_dma);
-       if (lu->reconnect_orb)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_reconnect_orb),
-                                   lu->reconnect_orb,
-                                   lu->reconnect_orb_dma);
-       if (lu->logout_orb)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_logout_orb),
-                                   lu->logout_orb,
-                                   lu->logout_orb_dma);
-       if (lu->query_logins_orb)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_query_logins_orb),
-                                   lu->query_logins_orb,
-                                   lu->query_logins_orb_dma);
-       if (lu->query_logins_response)
-               dma_free_coherent(hi->host->device.parent,
-                                   sizeof(struct sbp2_query_logins_response),
-                                   lu->query_logins_response,
-                                   lu->query_logins_response_dma);
-
-       if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE)
-               hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
-                                         lu->status_fifo_addr);
-
-       dev_set_drvdata(&lu->ud->device, NULL);
-
-       module_put(hi->host->driver->owner);
-no_hi:
-       kfree(lu);
-}
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-/*
- * Deal with write requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid,
-                                    int destid, quadlet_t *data, u64 addr,
-                                    size_t length, u16 flags)
-{
-       memcpy(bus_to_virt((u32) addr), data, length);
-       return RCODE_COMPLETE;
-}
-
-/*
- * Deal with read requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid,
-                                   quadlet_t *data, u64 addr, size_t length,
-                                   u16 flags)
-{
-       memcpy(data, bus_to_virt((u32) addr), length);
-       return RCODE_COMPLETE;
-}
-#endif
-
-/**************************************
- * SBP-2 protocol related section
- **************************************/
-
-static int sbp2_query_logins(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       quadlet_t data[2];
-       int max_logins;
-       int active_logins;
-
-       lu->query_logins_orb->reserved1 = 0x0;
-       lu->query_logins_orb->reserved2 = 0x0;
-
-       lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma;
-       lu->query_logins_orb->query_response_hi =
-                       ORB_SET_NODE_ID(hi->host->node_id);
-       lu->query_logins_orb->lun_misc =
-                       ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
-       lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
-       lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
-       lu->query_logins_orb->reserved_resp_length =
-               ORB_SET_QUERY_LOGINS_RESP_LENGTH(
-                       sizeof(struct sbp2_query_logins_response));
-
-       lu->query_logins_orb->status_fifo_hi =
-               ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-       lu->query_logins_orb->status_fifo_lo =
-               ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-       sbp2util_cpu_to_be32_buffer(lu->query_logins_orb,
-                                   sizeof(struct sbp2_query_logins_orb));
-
-       memset(lu->query_logins_response, 0,
-              sizeof(struct sbp2_query_logins_response));
-
-       data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-       data[1] = lu->query_logins_orb_dma;
-       sbp2util_cpu_to_be32_buffer(data, 8);
-
-       hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
-       if (sbp2util_access_timeout(lu, 2*HZ)) {
-               SBP2_INFO("Error querying logins to SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) {
-               SBP2_INFO("Error querying logins to SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-               SBP2_INFO("Error querying logins to SBP-2 device - failed");
-               return -EIO;
-       }
-
-       sbp2util_cpu_to_be32_buffer(lu->query_logins_response,
-                                   sizeof(struct sbp2_query_logins_response));
-
-       max_logins = RESPONSE_GET_MAX_LOGINS(
-                       lu->query_logins_response->length_max_logins);
-       SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
-
-       active_logins = RESPONSE_GET_ACTIVE_LOGINS(
-                       lu->query_logins_response->length_max_logins);
-       SBP2_INFO("Number of active logins: %d", active_logins);
-
-       if (active_logins >= max_logins) {
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int sbp2_login_device(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       quadlet_t data[2];
-
-       if (!lu->login_orb)
-               return -EIO;
-
-       if (!sbp2_exclusive_login && sbp2_query_logins(lu)) {
-               SBP2_INFO("Device does not support any more concurrent logins");
-               return -EIO;
-       }
-
-       /* assume no password */
-       lu->login_orb->password_hi = 0;
-       lu->login_orb->password_lo = 0;
-
-       lu->login_orb->login_response_lo = lu->login_response_dma;
-       lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-       lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
-
-       /* one second reconnect time */
-       lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0);
-       lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);
-       lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1);
-       lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
-       lu->login_orb->passwd_resp_lengths =
-               ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-
-       lu->login_orb->status_fifo_hi =
-               ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-       lu->login_orb->status_fifo_lo =
-               ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-       sbp2util_cpu_to_be32_buffer(lu->login_orb,
-                                   sizeof(struct sbp2_login_orb));
-
-       memset(lu->login_response, 0, sizeof(struct sbp2_login_response));
-
-       data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-       data[1] = lu->login_orb_dma;
-       sbp2util_cpu_to_be32_buffer(data, 8);
-
-       hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
-       /* wait up to 20 seconds for login status */
-       if (sbp2util_access_timeout(lu, 20*HZ)) {
-               SBP2_ERR("Error logging into SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       /* make sure that the returned status matches the login ORB */
-       if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) {
-               SBP2_ERR("Error logging into SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-               SBP2_ERR("Error logging into SBP-2 device - failed");
-               return -EIO;
-       }
-
-       sbp2util_cpu_to_be32_buffer(lu->login_response,
-                                   sizeof(struct sbp2_login_response));
-       lu->command_block_agent_addr =
-                       ((u64)lu->login_response->command_block_agent_hi) << 32;
-       lu->command_block_agent_addr |=
-                       ((u64)lu->login_response->command_block_agent_lo);
-       lu->command_block_agent_addr &= 0x0000ffffffffffffULL;
-
-       SBP2_INFO("Logged into SBP-2 device");
-       return 0;
-}
-
-static int sbp2_logout_device(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       quadlet_t data[2];
-       int error;
-
-       lu->logout_orb->reserved1 = 0x0;
-       lu->logout_orb->reserved2 = 0x0;
-       lu->logout_orb->reserved3 = 0x0;
-       lu->logout_orb->reserved4 = 0x0;
-
-       lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
-       lu->logout_orb->login_ID_misc |=
-                       ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
-       lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
-       lu->logout_orb->reserved5 = 0x0;
-       lu->logout_orb->status_fifo_hi =
-               ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-       lu->logout_orb->status_fifo_lo =
-               ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-       sbp2util_cpu_to_be32_buffer(lu->logout_orb,
-                                   sizeof(struct sbp2_logout_orb));
-
-       data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-       data[1] = lu->logout_orb_dma;
-       sbp2util_cpu_to_be32_buffer(data, 8);
-
-       error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-       if (error)
-               return error;
-
-       /* wait up to 1 second for the device to complete logout */
-       if (sbp2util_access_timeout(lu, HZ))
-               return -EIO;
-
-       SBP2_INFO("Logged out of SBP-2 device");
-       return 0;
-}
-
-static int sbp2_reconnect_device(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       quadlet_t data[2];
-       int error;
-
-       lu->reconnect_orb->reserved1 = 0x0;
-       lu->reconnect_orb->reserved2 = 0x0;
-       lu->reconnect_orb->reserved3 = 0x0;
-       lu->reconnect_orb->reserved4 = 0x0;
-
-       lu->reconnect_orb->login_ID_misc =
-                       ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
-       lu->reconnect_orb->login_ID_misc |=
-                       ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
-       lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
-       lu->reconnect_orb->reserved5 = 0x0;
-       lu->reconnect_orb->status_fifo_hi =
-               ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-       lu->reconnect_orb->status_fifo_lo =
-               ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-       sbp2util_cpu_to_be32_buffer(lu->reconnect_orb,
-                                   sizeof(struct sbp2_reconnect_orb));
-
-       data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-       data[1] = lu->reconnect_orb_dma;
-       sbp2util_cpu_to_be32_buffer(data, 8);
-
-       error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-       if (error)
-               return error;
-
-       /* wait up to 1 second for reconnect status */
-       if (sbp2util_access_timeout(lu, HZ)) {
-               SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       /* make sure that the returned status matches the reconnect ORB */
-       if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) {
-               SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
-               return -EIO;
-       }
-
-       if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-               SBP2_ERR("Error reconnecting to SBP-2 device - failed");
-               return -EIO;
-       }
-
-       SBP2_INFO("Reconnected to SBP-2 device");
-       return 0;
-}
-
-/*
- * Set the target node's Single Phase Retry limit. Affects the target's retry
- * behaviour if our node is too busy to accept requests.
- */
-static int sbp2_set_busy_timeout(struct sbp2_lu *lu)
-{
-       quadlet_t data;
-
-       data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
-       if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4))
-               SBP2_ERR("%s error", __func__);
-       return 0;
-}
-
-static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
-                                     struct unit_directory *ud)
-{
-       struct csr1212_keyval *kv;
-       struct csr1212_dentry *dentry;
-       u64 management_agent_addr;
-       u32 firmware_revision, model;
-       unsigned workarounds;
-       int i;
-
-       management_agent_addr = 0;
-       firmware_revision = SBP2_ROM_VALUE_MISSING;
-       model = ud->flags & UNIT_DIRECTORY_MODEL_ID ?
-                               ud->model_id : SBP2_ROM_VALUE_MISSING;
-
-       csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
-               switch (kv->key.id) {
-               case CSR1212_KV_ID_DEPENDENT_INFO:
-                       if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET)
-                               management_agent_addr =
-                                   CSR1212_REGISTER_SPACE_BASE +
-                                   (kv->value.csr_offset << 2);
-
-                       else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE)
-                               lu->lun = ORB_SET_LUN(kv->value.immediate);
-                       break;
-
-
-               case SBP2_FIRMWARE_REVISION_KEY:
-                       firmware_revision = kv->value.immediate;
-                       break;
-
-               default:
-                       /* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY
-                        * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */
-
-                       /* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
-                        * Its "ordered" bit has consequences for command ORB
-                        * list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */
-                       break;
-               }
-       }
-
-       workarounds = sbp2_default_workarounds;
-
-       if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
-               for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
-                       if (sbp2_workarounds_table[i].firmware_revision !=
-                           SBP2_ROM_VALUE_WILDCARD &&
-                           sbp2_workarounds_table[i].firmware_revision !=
-                           (firmware_revision & 0xffff00))
-                               continue;
-                       if (sbp2_workarounds_table[i].model !=
-                           SBP2_ROM_VALUE_WILDCARD &&
-                           sbp2_workarounds_table[i].model != model)
-                               continue;
-                       workarounds |= sbp2_workarounds_table[i].workarounds;
-                       break;
-               }
-
-       if (workarounds)
-               SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x "
-                         "(firmware_revision 0x%06x, vendor_id 0x%06x,"
-                         " model_id 0x%06x)",
-                         NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
-                         workarounds, firmware_revision, ud->vendor_id,
-                         model);
-
-       /* We would need one SCSI host template for each target to adjust
-        * max_sectors on the fly, therefore warn only. */
-       if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
-           (sbp2_max_sectors * 512) > (128 * 1024))
-               SBP2_INFO("Node " NODE_BUS_FMT ": Bridge only supports 128KB "
-                         "max transfer size. WARNING: Current max_sectors "
-                         "setting is larger than 128KB (%d sectors)",
-                         NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
-                         sbp2_max_sectors);
-
-       /* If this is a logical unit directory entry, process the parent
-        * to get the values. */
-       if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
-               struct unit_directory *parent_ud = container_of(
-                       ud->device.parent, struct unit_directory, device);
-               sbp2_parse_unit_directory(lu, parent_ud);
-       } else {
-               lu->management_agent_addr = management_agent_addr;
-               lu->workarounds = workarounds;
-               if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
-                       lu->lun = ORB_SET_LUN(ud->lun);
-       }
-}
-
-#define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
-
-/*
- * This function is called in order to determine the max speed and packet
- * size we can use in our ORBs. Note, that we (the driver and host) only
- * initiate the transaction. The SBP-2 device actually transfers the data
- * (by reading from the DMA area we tell it). This means that the SBP-2
- * device decides the actual maximum data it can transfer. We just tell it
- * the speed that it needs to use, and the max_rec the host supports, and
- * it takes care of the rest.
- */
-static int sbp2_max_speed_and_size(struct sbp2_lu *lu)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       u8 payload;
-
-       lu->speed_code = hi->host->speed[NODEID_TO_NODE(lu->ne->nodeid)];
-
-       if (lu->speed_code > sbp2_max_speed) {
-               lu->speed_code = sbp2_max_speed;
-               SBP2_INFO("Reducing speed to %s",
-                         hpsb_speedto_str[sbp2_max_speed]);
-       }
-
-       /* Payload size is the lesser of what our speed supports and what
-        * our host supports.  */
-       payload = min(sbp2_speedto_max_payload[lu->speed_code],
-                     (u8) (hi->host->csr.max_rec - 1));
-
-       /* If physical DMA is off, work around limitation in ohci1394:
-        * packet size must not exceed PAGE_SIZE */
-       if (lu->ne->host->low_addr_space < (1ULL << 32))
-               while (SBP2_PAYLOAD_TO_BYTES(payload) + 24 > PAGE_SIZE &&
-                      payload)
-                       payload--;
-
-       SBP2_INFO("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
-                 NODE_BUS_ARGS(hi->host, lu->ne->nodeid),
-                 hpsb_speedto_str[lu->speed_code],
-                 SBP2_PAYLOAD_TO_BYTES(payload));
-
-       lu->max_payload_size = payload;
-       return 0;
-}
-
-static int sbp2_agent_reset(struct sbp2_lu *lu, int wait)
-{
-       quadlet_t data;
-       u64 addr;
-       int retval;
-       unsigned long flags;
-
-       /* flush lu->protocol_work */
-       if (wait)
-               flush_scheduled_work();
-
-       data = ntohl(SBP2_AGENT_RESET_DATA);
-       addr = lu->command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
-
-       if (wait)
-               retval = hpsb_node_write(lu->ne, addr, &data, 4);
-       else
-               retval = sbp2util_node_write_no_wait(lu->ne, addr, &data, 4);
-
-       if (retval < 0) {
-               SBP2_ERR("hpsb_node_write failed.\n");
-               return -EIO;
-       }
-
-       /* make sure that the ORB_POINTER is written on next command */
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       lu->last_orb = NULL;
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-       return 0;
-}
-
-static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
-                                   struct sbp2_fwhost_info *hi,
-                                   struct sbp2_command_info *cmd,
-                                   unsigned int sg_count,
-                                   struct scatterlist *sg,
-                                   u32 orb_direction,
-                                   enum dma_data_direction dma_dir)
-{
-       struct device *dmadev = hi->host->device.parent;
-       struct sbp2_unrestricted_page_table *pt;
-       int i, n;
-
-       n = dma_map_sg(dmadev, sg, sg_count, dma_dir);
-       if (n == 0)
-               return -ENOMEM;
-
-       orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
-       orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
-       /* special case if only one element (and less than 64KB in size) */
-       if (n == 1) {
-               orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
-               orb->data_descriptor_lo = sg_dma_address(sg);
-       } else {
-               pt = &cmd->scatter_gather_element[0];
-
-               dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
-                                       sizeof(cmd->scatter_gather_element),
-                                       DMA_TO_DEVICE);
-
-               for_each_sg(sg, sg, n, i) {
-                       pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
-                       pt[i].low = cpu_to_be32(sg_dma_address(sg));
-               }
-
-               orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
-                            ORB_SET_DATA_SIZE(n);
-               orb->data_descriptor_lo = cmd->sge_dma;
-
-               dma_sync_single_for_device(dmadev, cmd->sge_dma,
-                                          sizeof(cmd->scatter_gather_element),
-                                          DMA_TO_DEVICE);
-       }
-       return 0;
-}
-
-static int sbp2_create_command_orb(struct sbp2_lu *lu,
-                                  struct sbp2_command_info *cmd,
-                                  struct scsi_cmnd *SCpnt)
-{
-       struct device *dmadev = lu->hi->host->device.parent;
-       struct sbp2_command_orb *orb = &cmd->command_orb;
-       unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
-       enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
-       u32 orb_direction;
-       int ret;
-
-       dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma,
-                               sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-       /*
-        * Set-up our command ORB.
-        *
-        * NOTE: We're doing unrestricted page tables (s/g), as this is
-        * best performance (at least with the devices I have). This means
-        * that data_size becomes the number of s/g elements, and
-        * page_size should be zero (for unrestricted).
-        */
-       orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
-       orb->next_ORB_lo = 0x0;
-       orb->misc = ORB_SET_MAX_PAYLOAD(lu->max_payload_size);
-       orb->misc |= ORB_SET_SPEED(lu->speed_code);
-       orb->misc |= ORB_SET_NOTIFY(1);
-
-       if (dma_dir == DMA_NONE)
-               orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
-       else if (dma_dir == DMA_TO_DEVICE && scsi_request_bufflen)
-               orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
-       else if (dma_dir == DMA_FROM_DEVICE && scsi_request_bufflen)
-               orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
-       else {
-               SBP2_INFO("Falling back to DMA_NONE");
-               orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
-       }
-
-       /* set up our page table stuff */
-       if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
-               orb->data_descriptor_hi = 0x0;
-               orb->data_descriptor_lo = 0x0;
-               orb->misc |= ORB_SET_DIRECTION(1);
-               ret = 0;
-       } else {
-               ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd,
-                                              scsi_sg_count(SCpnt),
-                                              scsi_sglist(SCpnt),
-                                              orb_direction, dma_dir);
-       }
-       sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
-
-       memset(orb->cdb, 0, sizeof(orb->cdb));
-       memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-       dma_sync_single_for_device(dmadev, cmd->command_orb_dma,
-                       sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-       return ret;
-}
-
-static void sbp2_link_orb_command(struct sbp2_lu *lu,
-                                 struct sbp2_command_info *cmd)
-{
-       struct sbp2_fwhost_info *hi = lu->hi;
-       struct sbp2_command_orb *last_orb;
-       dma_addr_t last_orb_dma;
-       u64 addr = lu->command_block_agent_addr;
-       quadlet_t data[2];
-       size_t length;
-       unsigned long flags;
-
-       /* check to see if there are any previous orbs to use */
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       last_orb = lu->last_orb;
-       last_orb_dma = lu->last_orb_dma;
-       if (!last_orb) {
-               /*
-                * last_orb == NULL means: We know that the target's fetch agent
-                * is not active right now.
-                */
-               addr += SBP2_ORB_POINTER_OFFSET;
-               data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-               data[1] = cmd->command_orb_dma;
-               sbp2util_cpu_to_be32_buffer(data, 8);
-               length = 8;
-       } else {
-               /*
-                * last_orb != NULL means: We know that the target's fetch agent
-                * is (very probably) not dead or in reset state right now.
-                * We have an ORB already sent that we can append a new one to.
-                * The target's fetch agent may or may not have read this
-                * previous ORB yet.
-                */
-               dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma,
-                                       sizeof(struct sbp2_command_orb),
-                                       DMA_TO_DEVICE);
-               last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma);
-               wmb();
-               /* Tells hardware that this pointer is valid */
-               last_orb->next_ORB_hi = 0;
-               dma_sync_single_for_device(hi->host->device.parent,
-                                          last_orb_dma,
-                                          sizeof(struct sbp2_command_orb),
-                                          DMA_TO_DEVICE);
-               addr += SBP2_DOORBELL_OFFSET;
-               data[0] = 0;
-               length = 4;
-       }
-       lu->last_orb = &cmd->command_orb;
-       lu->last_orb_dma = cmd->command_orb_dma;
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-       if (sbp2util_node_write_no_wait(lu->ne, addr, data, length)) {
-               /*
-                * sbp2util_node_write_no_wait failed. We certainly ran out
-                * of transaction labels, perhaps just because there were no
-                * context switches which gave khpsbpkt a chance to collect
-                * free tlabels. Try again in non-atomic context. If necessary,
-                * the workqueue job will sleep to guaranteedly get a tlabel.
-                * We do not accept new commands until the job is over.
-                */
-               scsi_block_requests(lu->shost);
-               PREPARE_WORK(&lu->protocol_work,
-                            last_orb ? sbp2util_write_doorbell:
-                                       sbp2util_write_orb_pointer);
-               schedule_work(&lu->protocol_work);
-       }
-}
-
-static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
-                            void (*done)(struct scsi_cmnd *))
-{
-       struct sbp2_command_info *cmd;
-
-       cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
-       if (!cmd)
-               return -EIO;
-
-       if (sbp2_create_command_orb(lu, cmd, SCpnt))
-               return -ENOMEM;
-
-       sbp2_link_orb_command(lu, cmd);
-       return 0;
-}
-
-/*
- * Translates SBP-2 status into SCSI sense data for check conditions
- */
-static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
-                                             unchar *sense_data)
-{
-       /* OK, it's pretty ugly... ;-) */
-       sense_data[0] = 0x70;
-       sense_data[1] = 0x0;
-       sense_data[2] = sbp2_status[9];
-       sense_data[3] = sbp2_status[12];
-       sense_data[4] = sbp2_status[13];
-       sense_data[5] = sbp2_status[14];
-       sense_data[6] = sbp2_status[15];
-       sense_data[7] = 10;
-       sense_data[8] = sbp2_status[16];
-       sense_data[9] = sbp2_status[17];
-       sense_data[10] = sbp2_status[18];
-       sense_data[11] = sbp2_status[19];
-       sense_data[12] = sbp2_status[10];
-       sense_data[13] = sbp2_status[11];
-       sense_data[14] = sbp2_status[20];
-       sense_data[15] = sbp2_status[21];
-
-       return sbp2_status[8] & 0x3f;
-}
-
-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
-                                   int destid, quadlet_t *data, u64 addr,
-                                   size_t length, u16 fl)
-{
-       struct sbp2_fwhost_info *hi;
-       struct sbp2_lu *lu = NULL, *lu_tmp;
-       struct scsi_cmnd *SCpnt = NULL;
-       struct sbp2_status_block *sb;
-       u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
-       struct sbp2_command_info *cmd;
-       unsigned long flags;
-
-       if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
-               SBP2_ERR("Wrong size of status block");
-               return RCODE_ADDRESS_ERROR;
-       }
-       if (unlikely(!host)) {
-               SBP2_ERR("host is NULL - this is bad!");
-               return RCODE_ADDRESS_ERROR;
-       }
-       hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-       if (unlikely(!hi)) {
-               SBP2_ERR("host info is NULL - this is bad!");
-               return RCODE_ADDRESS_ERROR;
-       }
-
-       /* Find the unit which wrote the status. */
-       read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-       list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
-               if (lu_tmp->ne->nodeid == nodeid &&
-                   lu_tmp->status_fifo_addr == addr) {
-                       lu = lu_tmp;
-                       break;
-               }
-       }
-       read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-       if (unlikely(!lu)) {
-               SBP2_ERR("lu is NULL - device is gone?");
-               return RCODE_ADDRESS_ERROR;
-       }
-
-       /* Put response into lu status fifo buffer. The first two bytes
-        * come in big endian bit order. Often the target writes only a
-        * truncated status block, minimally the first two quadlets. The rest
-        * is implied to be zeros. */
-       sb = &lu->status_block;
-       memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
-       memcpy(sb, data, length);
-       sbp2util_be32_to_cpu_buffer(sb, 8);
-
-       /* Ignore unsolicited status. Handle command ORB status. */
-       if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
-               cmd = NULL;
-       else
-               cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
-       if (cmd) {
-               /* Grab SCSI command pointers and check status. */
-               /*
-                * FIXME: If the src field in the status is 1, the ORB DMA must
-                * not be reused until status for a subsequent ORB is received.
-                */
-               SCpnt = cmd->Current_SCpnt;
-               spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-               sbp2util_mark_command_completed(lu, cmd);
-               spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-               if (SCpnt) {
-                       u32 h = sb->ORB_offset_hi_misc;
-                       u32 r = STATUS_GET_RESP(h);
-
-                       if (r != RESP_STATUS_REQUEST_COMPLETE) {
-                               SBP2_INFO("resp 0x%x, sbp_status 0x%x",
-                                         r, STATUS_GET_SBP_STATUS(h));
-                               scsi_status =
-                                       r == RESP_STATUS_TRANSPORT_FAILURE ?
-                                       SBP2_SCSI_STATUS_BUSY :
-                                       SBP2_SCSI_STATUS_COMMAND_TERMINATED;
-                       }
-
-                       if (STATUS_GET_LEN(h) > 1)
-                               scsi_status = sbp2_status_to_sense_data(
-                                       (unchar *)sb, SCpnt->sense_buffer);
-
-                       if (STATUS_TEST_DEAD(h))
-                                sbp2_agent_reset(lu, 0);
-               }
-
-               /* Check here to see if there are no commands in-use. If there
-                * are none, we know that the fetch agent left the active state
-                * _and_ that we did not reactivate it yet. Therefore clear
-                * last_orb so that next time we write directly to the
-                * ORB_POINTER register. That way the fetch agent does not need
-                * to refetch the next_ORB. */
-               spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-               if (list_empty(&lu->cmd_orb_inuse))
-                       lu->last_orb = NULL;
-               spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-       } else {
-               /* It's probably status after a management request. */
-               if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) ||
-                   (sb->ORB_offset_lo == lu->login_orb_dma) ||
-                   (sb->ORB_offset_lo == lu->query_logins_orb_dma) ||
-                   (sb->ORB_offset_lo == lu->logout_orb_dma)) {
-                       lu->access_complete = 1;
-                       wake_up_interruptible(&sbp2_access_wq);
-               }
-       }
-
-       if (SCpnt)
-               sbp2scsi_complete_command(lu, scsi_status, SCpnt,
-                                         cmd->Current_done);
-       return RCODE_COMPLETE;
-}
-
-/**************************************
- * SCSI interface related section
- **************************************/
-
-static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
-                                void (*done)(struct scsi_cmnd *))
-{
-       struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-       struct sbp2_fwhost_info *hi;
-       int result = DID_NO_CONNECT << 16;
-
-       if (unlikely(!sbp2util_node_is_available(lu)))
-               goto done;
-
-       hi = lu->hi;
-
-       if (unlikely(!hi)) {
-               SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!");
-               goto done;
-       }
-
-       /* Multiple units are currently represented to the SCSI core as separate
-        * targets, not as one target with multiple LUs. Therefore return
-        * selection time-out to any IO directed at non-zero LUNs. */
-       if (unlikely(SCpnt->device->lun))
-               goto done;
-
-       if (unlikely(!hpsb_node_entry_valid(lu->ne))) {
-               SBP2_ERR("Bus reset in progress - rejecting command");
-               result = DID_BUS_BUSY << 16;
-               goto done;
-       }
-
-       /* Bidirectional commands are not yet implemented,
-        * and unknown transfer direction not handled. */
-       if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) {
-               SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
-               result = DID_ERROR << 16;
-               goto done;
-       }
-
-       if (sbp2_send_command(lu, SCpnt, done)) {
-               SBP2_ERR("Error sending SCSI command");
-               sbp2scsi_complete_command(lu,
-                                         SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
-                                         SCpnt, done);
-       }
-       return 0;
-
-done:
-       SCpnt->result = result;
-       done(SCpnt);
-       return 0;
-}
-
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
-{
-       struct list_head *lh;
-       struct sbp2_command_info *cmd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-       while (!list_empty(&lu->cmd_orb_inuse)) {
-               lh = lu->cmd_orb_inuse.next;
-               cmd = list_entry(lh, struct sbp2_command_info, list);
-               sbp2util_mark_command_completed(lu, cmd);
-               if (cmd->Current_SCpnt) {
-                       cmd->Current_SCpnt->result = status << 16;
-                       cmd->Current_done(cmd->Current_SCpnt);
-               }
-       }
-       spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-       return;
-}
-
-/*
- * Complete a regular SCSI command. Can be called in atomic context.
- */
-static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status,
-                                     struct scsi_cmnd *SCpnt,
-                                     void (*done)(struct scsi_cmnd *))
-{
-       if (!SCpnt) {
-               SBP2_ERR("SCpnt is NULL");
-               return;
-       }
-
-       switch (scsi_status) {
-       case SBP2_SCSI_STATUS_GOOD:
-               SCpnt->result = DID_OK << 16;
-               break;
-
-       case SBP2_SCSI_STATUS_BUSY:
-               SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
-               SCpnt->result = DID_BUS_BUSY << 16;
-               break;
-
-       case SBP2_SCSI_STATUS_CHECK_CONDITION:
-               SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16;
-               break;
-
-       case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
-               SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
-               SCpnt->result = DID_NO_CONNECT << 16;
-               scsi_print_command(SCpnt);
-               break;
-
-       case SBP2_SCSI_STATUS_CONDITION_MET:
-       case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
-       case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
-               SBP2_ERR("Bad SCSI status = %x", scsi_status);
-               SCpnt->result = DID_ERROR << 16;
-               scsi_print_command(SCpnt);
-               break;
-
-       default:
-               SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
-               SCpnt->result = DID_ERROR << 16;
-       }
-
-       /* If a bus reset is in progress and there was an error, complete
-        * the command as busy so that it will get retried. */
-       if (!hpsb_node_entry_valid(lu->ne)
-           && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
-               SBP2_ERR("Completing command with busy (bus reset)");
-               SCpnt->result = DID_BUS_BUSY << 16;
-       }
-
-       /* Tell the SCSI stack that we're done with this command. */
-       done(SCpnt);
-}
-
-static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
-{
-       struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
-       if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
-               return -ENODEV;
-
-       lu->sdev = sdev;
-       sdev->allow_restart = 1;
-
-       /* SBP-2 requires quadlet alignment of the data buffers. */
-       blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
-
-       if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
-               sdev->inquiry_len = 36;
-       return 0;
-}
-
-static int sbp2scsi_slave_configure(struct scsi_device *sdev)
-{
-       struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
-       sdev->use_10_for_rw = 1;
-
-       if (sbp2_exclusive_login)
-               sdev->manage_start_stop = 1;
-       if (sdev->type == TYPE_ROM)
-               sdev->use_10_for_ms = 1;
-       if (sdev->type == TYPE_DISK &&
-           lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
-               sdev->skip_ms_page_8 = 1;
-       if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
-               sdev->fix_capacity = 1;
-       if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
-               sdev->start_stop_pwr_cond = 1;
-       if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
-               blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
-
-       blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
-       return 0;
-}
-
-static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
-{
-       ((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL;
-       return;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- * Usually called when a command has timed-out for some reason.
- */
-static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
-{
-       struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-       struct sbp2_command_info *cmd;
-       unsigned long flags;
-
-       SBP2_INFO("aborting sbp2 command");
-       scsi_print_command(SCpnt);
-
-       if (sbp2util_node_is_available(lu)) {
-               sbp2_agent_reset(lu, 1);
-
-               /* Return a matching command structure to the free pool. */
-               spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-               cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
-               if (cmd) {
-                       sbp2util_mark_command_completed(lu, cmd);
-                       if (cmd->Current_SCpnt) {
-                               cmd->Current_SCpnt->result = DID_ABORT << 16;
-                               cmd->Current_done(cmd->Current_SCpnt);
-                       }
-               }
-               spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-               sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-       }
-
-       return SUCCESS;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- */
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
-{
-       struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-
-       SBP2_INFO("reset requested");
-
-       if (sbp2util_node_is_available(lu)) {
-               SBP2_INFO("generating sbp2 fetch agent reset");
-               sbp2_agent_reset(lu, 1);
-       }
-
-       return SUCCESS;
-}
-
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf)
-{
-       struct scsi_device *sdev;
-       struct sbp2_lu *lu;
-
-       if (!(sdev = to_scsi_device(dev)))
-               return 0;
-
-       if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0]))
-               return 0;
-
-       if (sbp2_long_sysfs_ieee1394_id)
-               return sprintf(buf, "%016Lx:%06x:%04x\n",
-                               (unsigned long long)lu->ne->guid,
-                               lu->ud->directory_id, ORB_SET_LUN(lu->lun));
-       else
-               return sprintf(buf, "%016Lx:%d:%d\n",
-                               (unsigned long long)lu->ne->guid,
-                               lu->ud->id, ORB_SET_LUN(lu->lun));
-}
-
-MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-static int sbp2_module_init(void)
-{
-       int ret;
-
-       if (sbp2_serialize_io) {
-               sbp2_shost_template.can_queue = 1;
-               sbp2_shost_template.cmd_per_lun = 1;
-       }
-
-       sbp2_shost_template.max_sectors = sbp2_max_sectors;
-
-       hpsb_register_highlevel(&sbp2_highlevel);
-       ret = hpsb_register_protocol(&sbp2_driver);
-       if (ret) {
-               SBP2_ERR("Failed to register protocol");
-               hpsb_unregister_highlevel(&sbp2_highlevel);
-               return ret;
-       }
-       return 0;
-}
-
-static void __exit sbp2_module_exit(void)
-{
-       hpsb_unregister_protocol(&sbp2_driver);
-       hpsb_unregister_highlevel(&sbp2_highlevel);
-}
-
-module_init(sbp2_module_init);
-module_exit(sbp2_module_exit);
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
deleted file mode 100644 (file)
index 64a3a66..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * sbp2.h - Defines and prototypes for sbp2.c
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef SBP2_H
-#define SBP2_H
-
-#define SBP2_DEVICE_NAME               "sbp2"
-
-/*
- * There is no transport protocol limit to the CDB length,  but we implement
- * a fixed length only.  16 bytes is enough for disks larger than 2 TB.
- */
-#define SBP2_MAX_CDB_SIZE              16
-
-/*
- * SBP-2 specific definitions
- */
-
-#define ORB_DIRECTION_WRITE_TO_MEDIA   0x0
-#define ORB_DIRECTION_READ_FROM_MEDIA  0x1
-#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
-
-#define ORB_SET_NULL_PTR(v)            (((v) & 0x1) << 31)
-#define ORB_SET_NOTIFY(v)              (((v) & 0x1) << 31)
-#define ORB_SET_RQ_FMT(v)              (((v) & 0x3) << 29)
-#define ORB_SET_NODE_ID(v)             (((v) & 0xffff) << 16)
-#define ORB_SET_STATUS_FIFO_HI(v, id)  ((v) >> 32 | ORB_SET_NODE_ID(id))
-#define ORB_SET_STATUS_FIFO_LO(v)      ((v) & 0xffffffff)
-#define ORB_SET_DATA_SIZE(v)           ((v) & 0xffff)
-#define ORB_SET_PAGE_SIZE(v)           (((v) & 0x7) << 16)
-#define ORB_SET_PAGE_TABLE_PRESENT(v)  (((v) & 0x1) << 19)
-#define ORB_SET_MAX_PAYLOAD(v)         (((v) & 0xf) << 20)
-#define ORB_SET_SPEED(v)               (((v) & 0x7) << 24)
-#define ORB_SET_DIRECTION(v)           (((v) & 0x1) << 27)
-
-struct sbp2_command_orb {
-       u32 next_ORB_hi;
-       u32 next_ORB_lo;
-       u32 data_descriptor_hi;
-       u32 data_descriptor_lo;
-       u32 misc;
-       u8 cdb[SBP2_MAX_CDB_SIZE];
-} __attribute__((packed));
-
-#define SBP2_LOGIN_REQUEST             0x0
-#define SBP2_QUERY_LOGINS_REQUEST      0x1
-#define SBP2_RECONNECT_REQUEST         0x3
-#define SBP2_SET_PASSWORD_REQUEST      0x4
-#define SBP2_LOGOUT_REQUEST            0x7
-#define SBP2_ABORT_TASK_REQUEST                0xb
-#define SBP2_ABORT_TASK_SET            0xc
-#define SBP2_LOGICAL_UNIT_RESET                0xe
-#define SBP2_TARGET_RESET_REQUEST      0xf
-
-#define ORB_SET_LUN(v)                 ((v) & 0xffff)
-#define ORB_SET_FUNCTION(v)            (((v) & 0xf) << 16)
-#define ORB_SET_RECONNECT(v)           (((v) & 0xf) << 20)
-#define ORB_SET_EXCLUSIVE(v)           ((v) ? 1 << 28 : 0)
-#define ORB_SET_LOGIN_RESP_LENGTH(v)   ((v) & 0xffff)
-#define ORB_SET_PASSWD_LENGTH(v)       (((v) & 0xffff) << 16)
-
-struct sbp2_login_orb {
-       u32 password_hi;
-       u32 password_lo;
-       u32 login_response_hi;
-       u32 login_response_lo;
-       u32 lun_misc;
-       u32 passwd_resp_lengths;
-       u32 status_fifo_hi;
-       u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_LOGIN_ID(v)       ((v) & 0xffff)
-#define RESPONSE_GET_LENGTH(v)         (((v) >> 16) & 0xffff)
-#define RESPONSE_GET_RECONNECT_HOLD(v) ((v) & 0xffff)
-
-struct sbp2_login_response {
-       u32 length_login_ID;
-       u32 command_block_agent_hi;
-       u32 command_block_agent_lo;
-       u32 reconnect_hold;
-} __attribute__((packed));
-
-#define ORB_SET_LOGIN_ID(v)                 ((v) & 0xffff)
-#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
-
-struct sbp2_query_logins_orb {
-       u32 reserved1;
-       u32 reserved2;
-       u32 query_response_hi;
-       u32 query_response_lo;
-       u32 lun_misc;
-       u32 reserved_resp_length;
-       u32 status_fifo_hi;
-       u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_MAX_LOGINS(v)     ((v) & 0xffff)
-#define RESPONSE_GET_ACTIVE_LOGINS(v)  ((RESPONSE_GET_LENGTH((v)) - 4) / 12)
-
-struct sbp2_query_logins_response {
-       u32 length_max_logins;
-       u32 misc_IDs;
-       u32 initiator_misc_hi;
-       u32 initiator_misc_lo;
-} __attribute__((packed));
-
-struct sbp2_reconnect_orb {
-       u32 reserved1;
-       u32 reserved2;
-       u32 reserved3;
-       u32 reserved4;
-       u32 login_ID_misc;
-       u32 reserved5;
-       u32 status_fifo_hi;
-       u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_logout_orb {
-       u32 reserved1;
-       u32 reserved2;
-       u32 reserved3;
-       u32 reserved4;
-       u32 login_ID_misc;
-       u32 reserved5;
-       u32 status_fifo_hi;
-       u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_unrestricted_page_table {
-       __be32 high;
-       __be32 low;
-};
-
-#define RESP_STATUS_REQUEST_COMPLETE           0x0
-#define RESP_STATUS_TRANSPORT_FAILURE          0x1
-#define RESP_STATUS_ILLEGAL_REQUEST            0x2
-#define RESP_STATUS_VENDOR_DEPENDENT           0x3
-
-#define SBP2_STATUS_NO_ADDITIONAL_INFO         0x0
-#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED     0x1
-#define SBP2_STATUS_SPEED_NOT_SUPPORTED                0x2
-#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED    0x3
-#define SBP2_STATUS_ACCESS_DENIED              0x4
-#define SBP2_STATUS_LU_NOT_SUPPORTED           0x5
-#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL      0x6
-#define SBP2_STATUS_RESOURCES_UNAVAILABLE      0x8
-#define SBP2_STATUS_FUNCTION_REJECTED          0x9
-#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED    0xa
-#define SBP2_STATUS_DUMMY_ORB_COMPLETED                0xb
-#define SBP2_STATUS_REQUEST_ABORTED            0xc
-#define SBP2_STATUS_UNSPECIFIED_ERROR          0xff
-
-#define SFMT_CURRENT_ERROR                     0x0
-#define SFMT_DEFERRED_ERROR                    0x1
-#define SFMT_VENDOR_DEPENDENT_STATUS           0x3
-
-#define STATUS_GET_SRC(v)                      (((v) >> 30) & 0x3)
-#define STATUS_GET_RESP(v)                     (((v) >> 28) & 0x3)
-#define STATUS_GET_LEN(v)                      (((v) >> 24) & 0x7)
-#define STATUS_GET_SBP_STATUS(v)               (((v) >> 16) & 0xff)
-#define STATUS_GET_ORB_OFFSET_HI(v)            ((v) & 0x0000ffff)
-#define STATUS_TEST_DEAD(v)                    ((v) & 0x08000000)
-/* test 'resp' | 'dead' | 'sbp2_status' */
-#define STATUS_TEST_RDS(v)                     ((v) & 0x38ff0000)
-
-struct sbp2_status_block {
-       u32 ORB_offset_hi_misc;
-       u32 ORB_offset_lo;
-       u8 command_set_dependent[24];
-} __attribute__((packed));
-
-
-/*
- * SBP2 related configuration ROM definitions
- */
-
-#define SBP2_UNIT_DIRECTORY_OFFSET_KEY         0xd1
-#define SBP2_CSR_OFFSET_KEY                    0x54
-#define SBP2_UNIT_SPEC_ID_KEY                  0x12
-#define SBP2_UNIT_SW_VERSION_KEY               0x13
-#define SBP2_COMMAND_SET_SPEC_ID_KEY           0x38
-#define SBP2_COMMAND_SET_KEY                   0x39
-#define SBP2_UNIT_CHARACTERISTICS_KEY          0x3a
-#define SBP2_DEVICE_TYPE_AND_LUN_KEY           0x14
-#define SBP2_FIRMWARE_REVISION_KEY             0x3c
-
-#define SBP2_AGENT_STATE_OFFSET                        0x00ULL
-#define SBP2_AGENT_RESET_OFFSET                        0x04ULL
-#define SBP2_ORB_POINTER_OFFSET                        0x08ULL
-#define SBP2_DOORBELL_OFFSET                   0x10ULL
-#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET  0x14ULL
-#define SBP2_UNSOLICITED_STATUS_VALUE          0xf
-
-#define SBP2_BUSY_TIMEOUT_ADDRESS              0xfffff0000210ULL
-/* biggest possible value for Single Phase Retry count is 0xf */
-#define SBP2_BUSY_TIMEOUT_VALUE                        0xf
-
-#define SBP2_AGENT_RESET_DATA                  0xf
-
-#define SBP2_UNIT_SPEC_ID_ENTRY                        0x0000609e
-#define SBP2_SW_VERSION_ENTRY                  0x00010483
-
-/*
- * The default maximum s/g segment size of a FireWire controller is
- * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
- * be quadlet-aligned, we set the length limit to 0xffff & ~3.
- */
-#define SBP2_MAX_SEG_SIZE                      0xfffc
-
-/*
- * There is no real limitation of the queue depth (i.e. length of the linked
- * list of command ORBs) at the target. The chosen depth is merely an
- * implementation detail of the sbp2 driver.
- */
-#define SBP2_MAX_CMDS                          8
-
-#define SBP2_SCSI_STATUS_GOOD                  0x0
-#define SBP2_SCSI_STATUS_CHECK_CONDITION       0x2
-#define SBP2_SCSI_STATUS_CONDITION_MET         0x4
-#define SBP2_SCSI_STATUS_BUSY                  0x8
-#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT  0x18
-#define SBP2_SCSI_STATUS_COMMAND_TERMINATED    0x22
-#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT     0xff
-
-
-/*
- * Representations of commands and devices
- */
-
-/* Per SCSI command */
-struct sbp2_command_info {
-       struct list_head list;
-       struct sbp2_command_orb command_orb;
-       dma_addr_t command_orb_dma;
-       struct scsi_cmnd *Current_SCpnt;
-       void (*Current_done)(struct scsi_cmnd *);
-
-       /* Also need s/g structure for each sbp2 command */
-       struct sbp2_unrestricted_page_table
-               scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
-       dma_addr_t sge_dma;
-};
-
-/* Per FireWire host */
-struct sbp2_fwhost_info {
-       struct hpsb_host *host;
-       struct list_head logical_units;
-};
-
-/* Per logical unit */
-struct sbp2_lu {
-       /* Operation request blocks */
-       struct sbp2_command_orb *last_orb;
-       dma_addr_t last_orb_dma;
-       struct sbp2_login_orb *login_orb;
-       dma_addr_t login_orb_dma;
-       struct sbp2_login_response *login_response;
-       dma_addr_t login_response_dma;
-       struct sbp2_query_logins_orb *query_logins_orb;
-       dma_addr_t query_logins_orb_dma;
-       struct sbp2_query_logins_response *query_logins_response;
-       dma_addr_t query_logins_response_dma;
-       struct sbp2_reconnect_orb *reconnect_orb;
-       dma_addr_t reconnect_orb_dma;
-       struct sbp2_logout_orb *logout_orb;
-       dma_addr_t logout_orb_dma;
-       struct sbp2_status_block status_block;
-
-       /* How to talk to the unit */
-       u64 management_agent_addr;
-       u64 command_block_agent_addr;
-       u32 speed_code;
-       u32 max_payload_size;
-       u16 lun;
-
-       /* Address for the unit to write status blocks to */
-       u64 status_fifo_addr;
-
-       /* Waitqueue flag for logins, reconnects, logouts, query logins */
-       unsigned int access_complete:1;
-
-       /* Pool of command ORBs for this logical unit */
-       spinlock_t cmd_orb_lock;
-       struct list_head cmd_orb_inuse;
-       struct list_head cmd_orb_completed;
-
-       /* Backlink to FireWire host; list of units attached to the host */
-       struct sbp2_fwhost_info *hi;
-       struct list_head lu_list;
-
-       /* IEEE 1394 core's device representations */
-       struct node_entry *ne;
-       struct unit_directory *ud;
-
-       /* SCSI core's device representations */
-       struct scsi_device *sdev;
-       struct Scsi_Host *shost;
-
-       /* Device specific workarounds/brokeness */
-       unsigned workarounds;
-
-       /* Connection state */
-       atomic_t state;
-
-       /* For deferred requests to the fetch agent */
-       struct work_struct protocol_work;
-};
-
-/* For use in sbp2_lu.state */
-enum sbp2lu_state_types {
-       SBP2LU_STATE_RUNNING,           /* all normal */
-       SBP2LU_STATE_IN_RESET,          /* between bus reset and reconnect */
-       SBP2LU_STATE_IN_SHUTDOWN        /* when sbp2_remove was called */
-};
-
-/* For use in sbp2_lu.workarounds and in the corresponding
- * module load parameter */
-#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
-#define SBP2_WORKAROUND_INQUIRY_36     0x2
-#define SBP2_WORKAROUND_MODE_SENSE_8   0x4
-#define SBP2_WORKAROUND_FIX_CAPACITY   0x8
-#define SBP2_WORKAROUND_DELAY_INQUIRY  0x10
-#define SBP2_INQUIRY_DELAY             12
-#define SBP2_WORKAROUND_POWER_CONDITION        0x20
-#define SBP2_WORKAROUND_OVERRIDE       0x100
-
-#endif /* SBP2_H */
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
deleted file mode 100644 (file)
index 5c74f79..0000000
+++ /dev/null
@@ -1,1528 +0,0 @@
-/*
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Peter Schlaile <udbz@rz.uni-karlsruhe.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * NOTES:
- *
- * ioctl return codes:
- * EFAULT is only for invalid address for the argp
- * EINVAL for out of range values
- * EBUSY when trying to use an already used resource
- * ESRCH when trying to free/stop a not used resource
- * EAGAIN for resource allocation failure that could perhaps succeed later
- * ENOTTY for unsupported ioctl request
- *
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/timex.h>
-#include <linux/mm.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dma.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-#include "video1394.h"
-
-#define ISO_CHANNELS 64
-
-struct it_dma_prg {
-       struct dma_cmd begin;
-       quadlet_t data[4];
-       struct dma_cmd end;
-       quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-struct dma_iso_ctx {
-       struct ti_ohci *ohci;
-       int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
-       struct ohci1394_iso_tasklet iso_tasklet;
-       int channel;
-       int ctx;
-       int last_buffer;
-       int * next_buffer;  /* For ISO Transmit of video packets
-                              to write the correct SYT field
-                              into the next block */
-       unsigned int num_desc;
-       unsigned int buf_size;
-       unsigned int frame_size;
-       unsigned int packet_size;
-       unsigned int left_size;
-       unsigned int nb_cmd;
-
-       struct dma_region dma;
-
-       struct dma_prog_region *prg_reg;
-
-        struct dma_cmd **ir_prg;
-       struct it_dma_prg **it_prg;
-
-       unsigned int *buffer_status;
-       unsigned int *buffer_prg_assignment;
-        struct timeval *buffer_time; /* time when the buffer was received */
-       unsigned int *last_used_cmd; /* For ISO Transmit with
-                                       variable sized packets only ! */
-       int ctrlClear;
-       int ctrlSet;
-       int cmdPtr;
-       int ctxMatch;
-       wait_queue_head_t waitq;
-       spinlock_t lock;
-       unsigned int syt_offset;
-       int flags;
-
-       struct list_head link;
-};
-
-
-struct file_ctx {
-       struct ti_ohci *ohci;
-       struct list_head context_list;
-       struct dma_iso_ctx *current_ctx;
-};
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define VIDEO1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef VIDEO1394_DEBUG
-#define DBGMSG(card, fmt, args...) \
-printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
-#else
-#define DBGMSG(card, fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "video1394: " fmt "\n" , ## args)
-
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) \
-printk(level "video1394_%d: " fmt "\n" , card , ## args)
-
-static void wakeup_dma_ir_ctx(unsigned long l);
-static void wakeup_dma_it_ctx(unsigned long l);
-
-static struct hpsb_highlevel video1394_highlevel;
-
-static int free_dma_iso_ctx(struct dma_iso_ctx *d)
-{
-       int i;
-
-       DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx);
-
-       ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
-       if (d->iso_tasklet.link.next != NULL)
-               ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
-
-       dma_region_free(&d->dma);
-
-       if (d->prg_reg) {
-               for (i = 0; i < d->num_desc; i++)
-                       dma_prog_region_free(&d->prg_reg[i]);
-               kfree(d->prg_reg);
-       }
-
-       kfree(d->ir_prg);
-       kfree(d->it_prg);
-       kfree(d->buffer_status);
-       kfree(d->buffer_prg_assignment);
-       kfree(d->buffer_time);
-       kfree(d->last_used_cmd);
-       kfree(d->next_buffer);
-       list_del(&d->link);
-       kfree(d);
-
-       return 0;
-}
-
-static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
-                 int buf_size, int channel, unsigned int packet_size)
-{
-       struct dma_iso_ctx *d;
-       int i;
-
-       d = kzalloc(sizeof(*d), GFP_KERNEL);
-       if (!d) {
-               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx");
-               return NULL;
-       }
-
-       d->ohci = ohci;
-       d->type = type;
-       d->channel = channel;
-       d->num_desc = num_desc;
-       d->frame_size = buf_size;
-       d->buf_size = PAGE_ALIGN(buf_size);
-       d->last_buffer = -1;
-       INIT_LIST_HEAD(&d->link);
-       init_waitqueue_head(&d->waitq);
-
-       /* Init the regions for easy cleanup */
-       dma_region_init(&d->dma);
-
-       if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
-                            PCI_DMA_BIDIRECTIONAL)) {
-               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
-               free_dma_iso_ctx(d);
-               return NULL;
-       }
-
-       if (type == OHCI_ISO_RECEIVE)
-               ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
-                                         wakeup_dma_ir_ctx,
-                                         (unsigned long) d);
-       else
-               ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
-                                         wakeup_dma_it_ctx,
-                                         (unsigned long) d);
-
-       if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
-               PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts",
-                     type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
-               free_dma_iso_ctx(d);
-               return NULL;
-       }
-       d->ctx = d->iso_tasklet.context;
-
-       d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL);
-       if (!d->prg_reg) {
-               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs");
-               free_dma_iso_ctx(d);
-               return NULL;
-       }
-       /* Makes for easier cleanup */
-       for (i = 0; i < d->num_desc; i++)
-               dma_prog_region_init(&d->prg_reg[i]);
-
-       if (type == OHCI_ISO_RECEIVE) {
-               d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
-               d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
-               d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
-               d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
-
-               d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg),
-                                   GFP_KERNEL);
-
-               if (!d->ir_prg) {
-                       PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
-                       free_dma_iso_ctx(d);
-                       return NULL;
-               }
-
-               d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
-               d->left_size = (d->frame_size % PAGE_SIZE) ?
-                       d->frame_size % PAGE_SIZE : PAGE_SIZE;
-
-               for (i = 0;i < d->num_desc; i++) {
-                       if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
-                                                 sizeof(struct dma_cmd), ohci->dev)) {
-                               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
-                               free_dma_iso_ctx(d);
-                               return NULL;
-                       }
-                       d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
-               }
-
-       } else {  /* OHCI_ISO_TRANSMIT */
-               d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
-               d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
-               d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
-
-               d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg),
-                                   GFP_KERNEL);
-
-               if (!d->it_prg) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Failed to allocate dma it prg");
-                       free_dma_iso_ctx(d);
-                       return NULL;
-               }
-
-               d->packet_size = packet_size;
-
-               if (PAGE_SIZE % packet_size || packet_size>4096) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Packet size %d (page_size: %ld) "
-                             "not yet supported\n",
-                             packet_size, PAGE_SIZE);
-                       free_dma_iso_ctx(d);
-                       return NULL;
-               }
-
-               d->nb_cmd = d->frame_size / d->packet_size;
-               if (d->frame_size % d->packet_size) {
-                       d->nb_cmd++;
-                       d->left_size = d->frame_size % d->packet_size;
-               } else
-                       d->left_size = d->packet_size;
-
-               for (i = 0; i < d->num_desc; i++) {
-                       if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
-                                               sizeof(struct it_dma_prg), ohci->dev)) {
-                               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg");
-                               free_dma_iso_ctx(d);
-                               return NULL;
-                       }
-                       d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
-               }
-       }
-
-       d->buffer_status =
-           kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL);
-       d->buffer_prg_assignment =
-           kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL);
-       d->buffer_time =
-           kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL);
-       d->last_used_cmd =
-           kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL);
-       d->next_buffer =
-           kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL);
-
-       if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time ||
-           !d->last_used_cmd || !d->next_buffer) {
-               PRINT(KERN_ERR, ohci->host->id,
-                     "Failed to allocate dma_iso_ctx member");
-               free_dma_iso_ctx(d);
-               return NULL;
-       }
-
-        spin_lock_init(&d->lock);
-
-       DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers "
-             "of size %d allocated for a frame size %d, each with %d prgs",
-             (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
-             d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
-
-       return d;
-}
-
-static void reset_ir_status(struct dma_iso_ctx *d, int n)
-{
-       int i;
-       d->ir_prg[n][0].status = cpu_to_le32(4);
-       d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
-       for (i = 2; i < d->nb_cmd - 1; i++)
-               d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
-       d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
-}
-
-static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
-{
-       struct dma_cmd *ir_prg = d->ir_prg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
-       int i;
-
-       d->buffer_prg_assignment[n] = buffer;
-
-       ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
-                               (unsigned long)d->dma.kvirt));
-       ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                               (buf + 4) - (unsigned long)d->dma.kvirt));
-
-       for (i=2;i<d->nb_cmd-1;i++) {
-               ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                                               (buf+(i-1)*PAGE_SIZE) -
-                                               (unsigned long)d->dma.kvirt));
-       }
-
-       ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-                                 DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
-       ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                                 (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
-}
-
-static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
-{
-       struct dma_cmd *ir_prg = d->ir_prg[n];
-       struct dma_prog_region *ir_reg = &d->prg_reg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt;
-       int i;
-
-       /* the first descriptor will read only 4 bytes */
-       ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-               DMA_CTL_BRANCH | 4);
-
-       /* set the sync flag */
-       if (flags & VIDEO1394_SYNC_FRAMES)
-               ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
-
-       ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
-                               (unsigned long)d->dma.kvirt));
-       ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-                                       1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
-       /* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */
-       if (d->nb_cmd > 2) {
-               /* The second descriptor will read PAGE_SIZE-4 bytes */
-               ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-                                               DMA_CTL_BRANCH | (PAGE_SIZE-4));
-               ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
-                                               (unsigned long)d->dma.kvirt));
-               ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-                                                     2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
-               for (i = 2; i < d->nb_cmd - 1; i++) {
-                       ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-                                                       DMA_CTL_BRANCH | PAGE_SIZE);
-                       ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                                                       (buf+(i-1)*PAGE_SIZE) -
-                                                       (unsigned long)d->dma.kvirt));
-
-                       ir_prg[i].branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-                                           (i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-               }
-
-               /* The last descriptor will generate an interrupt */
-               ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-                                               DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
-               ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                                               (buf+(i-1)*PAGE_SIZE) -
-                                               (unsigned long)d->dma.kvirt));
-       } else {
-               /* Only one DMA page is used. Read d->left_size immediately and */
-               /* generate an interrupt as this is also the last page. */
-               ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-                                               DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4));
-               ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                                               (buf + 4) - (unsigned long)d->dma.kvirt));
-       }
-}
-
-static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
-{
-       struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
-       int i;
-
-       d->flags = flags;
-
-       ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-       for (i=0;i<d->num_desc;i++) {
-               initialize_dma_ir_prg(d, i, flags);
-               reset_ir_status(d, i);
-       }
-
-       /* reset the ctrl register */
-       reg_write(ohci, d->ctrlClear, 0xf0000000);
-
-       /* Set bufferFill */
-       reg_write(ohci, d->ctrlSet, 0x80000000);
-
-       /* Set isoch header */
-       if (flags & VIDEO1394_INCLUDE_ISO_HEADERS)
-               reg_write(ohci, d->ctrlSet, 0x40000000);
-
-       /* Set the context match register to match on all tags,
-          sync for sync tag, and listen to d->channel */
-       reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-
-       /* Set up isoRecvIntMask to generate interrupts */
-       reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-static struct dma_iso_ctx *
-find_ctx(struct list_head *list, int type, int channel)
-{
-       struct dma_iso_ctx *ctx;
-
-       list_for_each_entry(ctx, list, link) {
-               if (ctx->type == type && ctx->channel == channel)
-                       return ctx;
-       }
-
-       return NULL;
-}
-
-static void wakeup_dma_ir_ctx(unsigned long l)
-{
-       struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
-       int i;
-
-       spin_lock(&d->lock);
-
-       for (i = 0; i < d->num_desc; i++) {
-               if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
-                       reset_ir_status(d, i);
-                       d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
-                       do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
-                       dma_region_sync_for_cpu(&d->dma,
-                               d->buffer_prg_assignment[i] * d->buf_size,
-                               d->buf_size);
-               }
-       }
-
-       spin_unlock(&d->lock);
-
-       if (waitqueue_active(&d->waitq))
-               wake_up_interruptible(&d->waitq);
-}
-
-static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
-                                int n)
-{
-       unsigned char* buf = d->dma.kvirt + n * d->buf_size;
-       u32 cycleTimer;
-       u32 timeStamp;
-
-       if (n == -1) {
-         return;
-       }
-
-       cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-
-       timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */
-       timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)
-               + (cycleTimer & 0xf000)) & 0xffff;
-
-       buf[6] = timeStamp >> 8;
-       buf[7] = timeStamp & 0xff;
-
-    /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
-           buf += d->packet_size;
-       buf[6] = timeStamp >> 8;
-           buf[7] = timeStamp & 0xff;
-       }
-
-    /* do the next buffer frame too in case of irq latency */
-       n = d->next_buffer[n];
-       if (n == -1) {
-         return;
-       }
-       buf = d->dma.kvirt + n * d->buf_size;
-
-       timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
-
-       buf[6] = timeStamp >> 8;
-       buf[7] = timeStamp & 0xff;
-
-    /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
-           buf += d->packet_size;
-       buf[6] = timeStamp >> 8;
-           buf[7] = timeStamp & 0xff;
-       }
-
-#if 0
-       printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",
-              curr, n, cycleTimer, timeStamp);
-#endif
-}
-
-static void wakeup_dma_it_ctx(unsigned long l)
-{
-       struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
-       struct ti_ohci *ohci = d->ohci;
-       int i;
-
-       spin_lock(&d->lock);
-
-       for (i = 0; i < d->num_desc; i++) {
-               if (d->it_prg[i][d->last_used_cmd[i]].end.status &
-                   cpu_to_le32(0xFFFF0000)) {
-                       int next = d->next_buffer[i];
-                       put_timestamp(ohci, d, next);
-                       d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
-                       d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
-               }
-       }
-
-       spin_unlock(&d->lock);
-
-       if (waitqueue_active(&d->waitq))
-               wake_up_interruptible(&d->waitq);
-}
-
-static void reprogram_dma_it_prg(struct dma_iso_ctx  *d, int n, int buffer)
-{
-       struct it_dma_prg *it_prg = d->it_prg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
-       int i;
-
-       d->buffer_prg_assignment[n] = buffer;
-       for (i=0;i<d->nb_cmd;i++) {
-         it_prg[i].end.address =
-               cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-                       (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
-       }
-}
-
-static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
-{
-       struct it_dma_prg *it_prg = d->it_prg[n];
-       struct dma_prog_region *it_reg = &d->prg_reg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt;
-       int i;
-       d->last_used_cmd[n] = d->nb_cmd - 1;
-       for (i=0;i<d->nb_cmd;i++) {
-
-               it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-                       DMA_CTL_IMMEDIATE | 8) ;
-               it_prg[i].begin.address = 0;
-
-               it_prg[i].begin.status = 0;
-
-               it_prg[i].data[0] = cpu_to_le32(
-                       (IEEE1394_SPEED_100 << 16)
-                       | (/* tag */ 1 << 14)
-                       | (d->channel << 8)
-                       | (TCODE_ISO_DATA << 4));
-               if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
-               it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
-               it_prg[i].data[2] = 0;
-               it_prg[i].data[3] = 0;
-
-               it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-                                            DMA_CTL_BRANCH);
-               it_prg[i].end.address =
-                       cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
-                                               (unsigned long)d->dma.kvirt));
-
-               if (i<d->nb_cmd-1) {
-                       it_prg[i].end.control |= cpu_to_le32(d->packet_size);
-                       it_prg[i].begin.branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-                                       sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-                       it_prg[i].end.branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-                                       sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-               } else {
-                       /* the last prg generates an interrupt */
-                       it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
-                               DMA_CTL_IRQ | d->left_size);
-                       /* the last prg doesn't branch */
-                       it_prg[i].begin.branchAddress = 0;
-                       it_prg[i].end.branchAddress = 0;
-               }
-               it_prg[i].end.status = 0;
-       }
-}
-
-static void initialize_dma_it_prg_var_packet_queue(
-       struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,
-       struct ti_ohci *ohci)
-{
-       struct it_dma_prg *it_prg = d->it_prg[n];
-       struct dma_prog_region *it_reg = &d->prg_reg[n];
-       int i;
-
-#if 0
-       if (n != -1) {
-               put_timestamp(ohci, d, n);
-       }
-#endif
-       d->last_used_cmd[n] = d->nb_cmd - 1;
-
-       for (i = 0; i < d->nb_cmd; i++) {
-               unsigned int size;
-               if (packet_sizes[i] > d->packet_size) {
-                       size = d->packet_size;
-               } else {
-                       size = packet_sizes[i];
-               }
-               it_prg[i].data[1] = cpu_to_le32(size << 16);
-               it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
-
-               if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
-                       it_prg[i].end.control |= cpu_to_le32(size);
-                       it_prg[i].begin.branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-                                       sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-                       it_prg[i].end.branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-                                       sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-               } else {
-                       /* the last prg generates an interrupt */
-                       it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
-                               DMA_CTL_IRQ | size);
-                       /* the last prg doesn't branch */
-                       it_prg[i].begin.branchAddress = 0;
-                       it_prg[i].end.branchAddress = 0;
-                       d->last_used_cmd[n] = i;
-                       break;
-               }
-       }
-}
-
-static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
-                                 unsigned int syt_offset, int flags)
-{
-       struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
-       int i;
-
-       d->flags = flags;
-       d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);
-
-       ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-       for (i=0;i<d->num_desc;i++)
-               initialize_dma_it_prg(d, i, sync_tag);
-
-       /* Set up isoRecvIntMask to generate interrupts */
-       reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
-}
-
-static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
-                                             unsigned int buffer)
-{
-       unsigned long flags;
-       unsigned int ret;
-       spin_lock_irqsave(&d->lock, flags);
-       ret = d->buffer_status[buffer];
-       spin_unlock_irqrestore(&d->lock, flags);
-       return ret;
-}
-
-static long video1394_ioctl(struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct file_ctx *ctx = file->private_data;
-       struct ti_ohci *ohci = ctx->ohci;
-       unsigned long flags;
-       void __user *argp = (void __user *)arg;
-
-       switch(cmd)
-       {
-       case VIDEO1394_IOC_LISTEN_CHANNEL:
-       case VIDEO1394_IOC_TALK_CHANNEL:
-       {
-               struct video1394_mmap v;
-               u64 mask;
-               struct dma_iso_ctx *d;
-               int i;
-
-               if (copy_from_user(&v, argp, sizeof(v)))
-                       return -EFAULT;
-
-               /* if channel < 0, find lowest available one */
-               if (v.channel < 0) {
-                   mask = (u64)0x1;
-                   for (i=0; ; i++) {
-                       if (i == ISO_CHANNELS) {
-                           PRINT(KERN_ERR, ohci->host->id, 
-                                 "No free channel found");
-                           return -EAGAIN;
-                       }
-                       if (!(ohci->ISO_channel_usage & mask)) {
-                           v.channel = i;
-                           PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
-                           break;
-                       }
-                       mask = mask << 1;
-                   }
-               } else if (v.channel >= ISO_CHANNELS) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Iso channel %d out of bounds", v.channel);
-                       return -EINVAL;
-               } else {
-                       mask = (u64)0x1<<v.channel;
-               }
-               DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
-                       (u32)(mask>>32),(u32)(mask&0xffffffff),
-                       (u32)(ohci->ISO_channel_usage>>32),
-                       (u32)(ohci->ISO_channel_usage&0xffffffff));
-               if (ohci->ISO_channel_usage & mask) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Channel %d is already taken", v.channel);
-                       return -EBUSY;
-               }
-
-               if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Invalid %d length buffer requested",v.buf_size);
-                       return -EINVAL;
-               }
-
-               if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Invalid %d buffers requested",v.nb_buffers);
-                       return -EINVAL;
-               }
-
-               if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "%d buffers of size %d bytes is too big",
-                             v.nb_buffers, v.buf_size);
-                       return -EINVAL;
-               }
-
-               if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
-                       d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
-                                             v.nb_buffers + 1, v.buf_size,
-                                             v.channel, 0);
-
-                       if (d == NULL) {
-                               PRINT(KERN_ERR, ohci->host->id,
-                                     "Couldn't allocate ir context");
-                               return -EAGAIN;
-                       }
-                       initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
-
-                       ctx->current_ctx = d;
-
-                       v.buf_size = d->buf_size;
-                       list_add_tail(&d->link, &ctx->context_list);
-
-                       DBGMSG(ohci->host->id,
-                             "iso context %d listen on channel %d",
-                             d->ctx, v.channel);
-               }
-               else {
-                       d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
-                                             v.nb_buffers + 1, v.buf_size,
-                                             v.channel, v.packet_size);
-
-                       if (d == NULL) {
-                               PRINT(KERN_ERR, ohci->host->id,
-                                     "Couldn't allocate it context");
-                               return -EAGAIN;
-                       }
-                       initialize_dma_it_ctx(d, v.sync_tag,
-                                             v.syt_offset, v.flags);
-
-                       ctx->current_ctx = d;
-
-                       v.buf_size = d->buf_size;
-
-                       list_add_tail(&d->link, &ctx->context_list);
-
-                       DBGMSG(ohci->host->id,
-                             "Iso context %d talk on channel %d", d->ctx,
-                             v.channel);
-               }
-
-               if (copy_to_user(argp, &v, sizeof(v))) {
-                       /* FIXME : free allocated dma resources */
-                       return -EFAULT;
-               }
-               
-               ohci->ISO_channel_usage |= mask;
-
-               return 0;
-       }
-       case VIDEO1394_IOC_UNLISTEN_CHANNEL:
-       case VIDEO1394_IOC_UNTALK_CHANNEL:
-       {
-               int channel;
-               u64 mask;
-               struct dma_iso_ctx *d;
-
-               if (copy_from_user(&channel, argp, sizeof(int)))
-                       return -EFAULT;
-
-               if (channel < 0 || channel >= ISO_CHANNELS) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Iso channel %d out of bound", channel);
-                       return -EINVAL;
-               }
-               mask = (u64)0x1<<channel;
-               if (!(ohci->ISO_channel_usage & mask)) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Channel %d is not being used", channel);
-                       return -ESRCH;
-               }
-
-               /* Mark this channel as unused */
-               ohci->ISO_channel_usage &= ~mask;
-
-               if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL)
-                       d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
-               else
-                       d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
-
-               if (d == NULL) return -ESRCH;
-               DBGMSG(ohci->host->id, "Iso context %d "
-                     "stop talking on channel %d", d->ctx, channel);
-               free_dma_iso_ctx(d);
-
-               return 0;
-       }
-       case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
-       {
-               struct video1394_wait v;
-               struct dma_iso_ctx *d;
-               int next_prg;
-
-               if (unlikely(copy_from_user(&v, argp, sizeof(v))))
-                       return -EFAULT;
-
-               d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
-               if (unlikely(d == NULL))
-                       return -EFAULT;
-
-               if (unlikely(v.buffer >= d->num_desc - 1)) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d out of range",v.buffer);
-                       return -EINVAL;
-               }
-
-               spin_lock_irqsave(&d->lock,flags);
-
-               if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d is already used",v.buffer);
-                       spin_unlock_irqrestore(&d->lock,flags);
-                       return -EBUSY;
-               }
-
-               d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
-               next_prg = (d->last_buffer + 1) % d->num_desc;
-               if (d->last_buffer>=0)
-                       d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
-                                       & 0xfffffff0) | 0x1);
-
-               d->last_buffer = next_prg;
-               reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
-
-               d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
-
-               spin_unlock_irqrestore(&d->lock,flags);
-
-               if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
-               {
-                       DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx);
-
-                       /* Tell the controller where the first program is */
-                       reg_write(ohci, d->cmdPtr,
-                                 dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
-
-                       /* Run IR context */
-                       reg_write(ohci, d->ctrlSet, 0x8000);
-               }
-               else {
-                       /* Wake up dma context if necessary */
-                       if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-                               DBGMSG(ohci->host->id,
-                                     "Waking up iso dma ctx=%d", d->ctx);
-                               reg_write(ohci, d->ctrlSet, 0x1000);
-                       }
-               }
-               return 0;
-
-       }
-       case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
-       case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
-       {
-               struct video1394_wait v;
-               struct dma_iso_ctx *d;
-               int i = 0;
-
-               if (unlikely(copy_from_user(&v, argp, sizeof(v))))
-                       return -EFAULT;
-
-               d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
-               if (unlikely(d == NULL))
-                       return -EFAULT;
-
-               if (unlikely(v.buffer > d->num_desc - 1)) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d out of range",v.buffer);
-                       return -EINVAL;
-               }
-
-               /*
-                * I change the way it works so that it returns
-                * the last received frame.
-                */
-               spin_lock_irqsave(&d->lock, flags);
-               switch(d->buffer_status[v.buffer]) {
-               case VIDEO1394_BUFFER_READY:
-                       d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-                       break;
-               case VIDEO1394_BUFFER_QUEUED:
-                       if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) {
-                           /* for polling, return error code EINTR */
-                           spin_unlock_irqrestore(&d->lock, flags);
-                           return -EINTR;
-                       }
-
-                       spin_unlock_irqrestore(&d->lock, flags);
-                       wait_event_interruptible(d->waitq,
-                                       video1394_buffer_state(d, v.buffer) ==
-                                        VIDEO1394_BUFFER_READY);
-                       if (signal_pending(current))
-                                return -EINTR;
-                       spin_lock_irqsave(&d->lock, flags);
-                       d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-                       break;
-               default:
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d is not queued",v.buffer);
-                       spin_unlock_irqrestore(&d->lock, flags);
-                       return -ESRCH;
-               }
-
-               /* set time of buffer */
-               v.filltime = d->buffer_time[v.buffer];
-
-               /*
-                * Look ahead to see how many more buffers have been received
-                */
-               i=0;
-               while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
-                      VIDEO1394_BUFFER_READY) {
-                       v.buffer=(v.buffer+1)%(d->num_desc - 1);
-                       i++;
-               }
-               spin_unlock_irqrestore(&d->lock, flags);
-
-               v.buffer=i;
-               if (unlikely(copy_to_user(argp, &v, sizeof(v))))
-                       return -EFAULT;
-
-               return 0;
-       }
-       case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
-       {
-               struct video1394_wait v;
-               unsigned int *psizes = NULL;
-               struct dma_iso_ctx *d;
-               int next_prg;
-
-               if (copy_from_user(&v, argp, sizeof(v)))
-                       return -EFAULT;
-
-               d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
-               if (d == NULL) return -EFAULT;
-
-               if (v.buffer >= d->num_desc - 1) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d out of range",v.buffer);
-                       return -EINVAL;
-               }
-
-               if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
-                       int buf_size = d->nb_cmd * sizeof(*psizes);
-                       struct video1394_queue_variable __user *p = argp;
-                       unsigned int __user *qv;
-
-                       if (get_user(qv, &p->packet_sizes))
-                               return -EFAULT;
-
-                       psizes = memdup_user(qv, buf_size);
-                       if (IS_ERR(psizes))
-                               return PTR_ERR(psizes);
-               }
-
-               spin_lock_irqsave(&d->lock,flags);
-
-               /* last_buffer is last_prg */
-               next_prg = (d->last_buffer + 1) % d->num_desc;
-               if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d is already used",v.buffer);
-                       spin_unlock_irqrestore(&d->lock,flags);
-                       kfree(psizes);
-                       return -EBUSY;
-               }
-
-               if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
-                       initialize_dma_it_prg_var_packet_queue(
-                               d, next_prg, psizes, ohci);
-               }
-
-               d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
-               if (d->last_buffer >= 0) {
-                       d->it_prg[d->last_buffer]
-                               [ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
-                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
-                                               0) & 0xfffffff0) | 0x3);
-
-                       d->it_prg[d->last_buffer]
-                               [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
-                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
-                                               0) & 0xfffffff0) | 0x3);
-                       d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
-               }
-               d->last_buffer = next_prg;
-               reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
-               d->next_buffer[d->last_buffer] = -1;
-
-               d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
-
-               spin_unlock_irqrestore(&d->lock,flags);
-
-               if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
-               {
-                       DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
-                              d->ctx);
-                       put_timestamp(ohci, d, d->last_buffer);
-                       dma_region_sync_for_device(&d->dma,
-                               v.buffer * d->buf_size, d->buf_size);
-
-                       /* Tell the controller where the first program is */
-                       reg_write(ohci, d->cmdPtr,
-                               dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
-
-                       /* Run IT context */
-                       reg_write(ohci, d->ctrlSet, 0x8000);
-               }
-               else {
-                       /* Wake up dma context if necessary */
-                       if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-                               DBGMSG(ohci->host->id,
-                                     "Waking up iso transmit dma ctx=%d",
-                                     d->ctx);
-                               put_timestamp(ohci, d, d->last_buffer);
-                               dma_region_sync_for_device(&d->dma,
-                                       v.buffer * d->buf_size, d->buf_size);
-
-                               reg_write(ohci, d->ctrlSet, 0x1000);
-                       }
-               }
-
-               kfree(psizes);
-               return 0;
-
-       }
-       case VIDEO1394_IOC_TALK_WAIT_BUFFER:
-       {
-               struct video1394_wait v;
-               struct dma_iso_ctx *d;
-
-               if (copy_from_user(&v, argp, sizeof(v)))
-                       return -EFAULT;
-
-               d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
-               if (d == NULL) return -EFAULT;
-
-               if (v.buffer >= d->num_desc - 1) {
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d out of range",v.buffer);
-                       return -EINVAL;
-               }
-
-               switch(d->buffer_status[v.buffer]) {
-               case VIDEO1394_BUFFER_READY:
-                       d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-                       return 0;
-               case VIDEO1394_BUFFER_QUEUED:
-                       wait_event_interruptible(d->waitq,
-                                       (d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
-                       if (signal_pending(current))
-                               return -EINTR;
-                       d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-                       return 0;
-               default:
-                       PRINT(KERN_ERR, ohci->host->id,
-                             "Buffer %d is not queued",v.buffer);
-                       return -ESRCH;
-               }
-       }
-       default:
-               return -ENOTTY;
-       }
-}
-
-/*
- *     This maps the vmalloced and reserved buffer to user space.
- *
- *  FIXME:
- *  - PAGE_READONLY should suffice!?
- *  - remap_pfn_range is kind of inefficient for page by page remapping.
- *    But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct file_ctx *ctx = file->private_data;
-
-       if (ctx->current_ctx == NULL) {
-               PRINT(KERN_ERR, ctx->ohci->host->id,
-                               "Current iso context not set");
-               return -EINVAL;
-       }
-
-       return dma_region_mmap(&ctx->current_ctx->dma, file, vma);
-}
-
-static unsigned int video1394_poll(struct file *file, poll_table *pt)
-{
-       struct file_ctx *ctx;
-       unsigned int mask = 0;
-       unsigned long flags;
-       struct dma_iso_ctx *d;
-       int i;
-
-       ctx = file->private_data;
-       d = ctx->current_ctx;
-       if (d == NULL) {
-               PRINT(KERN_ERR, ctx->ohci->host->id,
-                               "Current iso context not set");
-               return POLLERR;
-       }
-
-       poll_wait(file, &d->waitq, pt);
-
-       spin_lock_irqsave(&d->lock, flags);
-       for (i = 0; i < d->num_desc; i++) {
-               if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
-                       mask |= POLLIN | POLLRDNORM;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&d->lock, flags);
-
-       return mask;
-}
-
-static int video1394_open(struct inode *inode, struct file *file)
-{
-       int i = ieee1394_file_to_instance(file);
-       struct ti_ohci *ohci;
-       struct file_ctx *ctx;
-
-       ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i);
-        if (ohci == NULL)
-                return -EIO;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)  {
-               PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx");
-               return -ENOMEM;
-       }
-
-       ctx->ohci = ohci;
-       INIT_LIST_HEAD(&ctx->context_list);
-       ctx->current_ctx = NULL;
-       file->private_data = ctx;
-
-       return nonseekable_open(inode, file);
-}
-
-static int video1394_release(struct inode *inode, struct file *file)
-{
-       struct file_ctx *ctx = file->private_data;
-       struct ti_ohci *ohci = ctx->ohci;
-       struct list_head *lh, *next;
-       u64 mask;
-
-       list_for_each_safe(lh, next, &ctx->context_list) {
-               struct dma_iso_ctx *d;
-               d = list_entry(lh, struct dma_iso_ctx, link);
-               mask = (u64) 1 << d->channel;
-
-               if (!(ohci->ISO_channel_usage & mask))
-                       PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d "
-                             "is not being used", d->channel);
-               else
-                       ohci->ISO_channel_usage &= ~mask;
-               DBGMSG(ohci->host->id, "On release: Iso %s context "
-                     "%d stop listening on channel %d",
-                     d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
-                     d->ctx, d->channel);
-               free_dma_iso_ctx(d);
-       }
-
-       kfree(ctx);
-       file->private_data = NULL;
-
-       return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
-#endif
-
-static struct cdev video1394_cdev;
-static const struct file_operations video1394_fops=
-{
-       .owner =        THIS_MODULE,
-       .unlocked_ioctl = video1394_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = video1394_compat_ioctl,
-#endif
-       .poll =         video1394_poll,
-       .mmap =         video1394_mmap,
-       .open =         video1394_open,
-       .release =      video1394_release,
-       .llseek =       no_llseek,
-};
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id video1394_id_table[] = {
-       {
-               .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-               .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-               .version        = CAMERA_SW_VERSION_ENTRY & 0xffffff
-       },
-        {
-                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-                .version        = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
-        },
-        {
-                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-                .version        = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
-        },
-       { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver video1394_driver = {
-       .name = VIDEO1394_DRIVER_NAME,
-};
-
-
-static void video1394_add_host (struct hpsb_host *host)
-{
-       struct ti_ohci *ohci;
-       int minor;
-
-       /* We only work with the OHCI-1394 driver */
-       if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-               return;
-
-       ohci = (struct ti_ohci *)host->hostdata;
-
-       if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) {
-               PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo");
-               return;
-       }
-
-       hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
-       hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
-
-       minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
-       device_create(hpsb_protocol_class, NULL, MKDEV(IEEE1394_MAJOR, minor),
-                     NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-}
-
-
-static void video1394_remove_host (struct hpsb_host *host)
-{
-       struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
-
-       if (ohci)
-               device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
-                              IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
-       return;
-}
-
-
-static struct hpsb_highlevel video1394_highlevel = {
-       .name =         VIDEO1394_DRIVER_NAME,
-       .add_host =     video1394_add_host,
-       .remove_host =  video1394_remove_host,
-};
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("driver for digital video on OHCI board");
-MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_COMPAT
-
-#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER     \
-       _IOW ('#', 0x12, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER      \
-       _IOWR('#', 0x13, struct video1394_wait32)
-#define VIDEO1394_IOC32_TALK_WAIT_BUFFER        \
-       _IOW ('#', 0x17, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER      \
-       _IOWR('#', 0x18, struct video1394_wait32)
-
-struct video1394_wait32 {
-       u32 channel;
-       u32 buffer;
-       struct compat_timeval filltime;
-};
-
-static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        struct video1394_wait32 __user *argp = (void __user *)arg;
-        struct video1394_wait32 wait32;
-        struct video1394_wait wait;
-        mm_segment_t old_fs;
-        int ret;
-
-        if (copy_from_user(&wait32, argp, sizeof(wait32)))
-                return -EFAULT;
-
-        wait.channel = wait32.channel;
-        wait.buffer = wait32.buffer;
-        wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
-        wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
-               ret = video1394_ioctl(file,
-                                     VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
-                                     (unsigned long) &wait);
-        else
-               ret = video1394_ioctl(file,
-                                     VIDEO1394_IOC_LISTEN_POLL_BUFFER,
-                                     (unsigned long) &wait);
-        set_fs(old_fs);
-
-        if (!ret) {
-                wait32.channel = wait.channel;
-                wait32.buffer = wait.buffer;
-                wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
-                wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
-
-                if (copy_to_user(argp, &wait32, sizeof(wait32)))
-                        ret = -EFAULT;
-        }
-
-        return ret;
-}
-
-static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        struct video1394_wait32 wait32;
-        struct video1394_wait wait;
-        mm_segment_t old_fs;
-        int ret;
-
-        if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32)))
-                return -EFAULT;
-
-        wait.channel = wait32.channel;
-        wait.buffer = wait32.buffer;
-        wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
-        wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
-               ret = video1394_ioctl(file,
-                                     VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
-                                     (unsigned long) &wait);
-        else
-               ret = video1394_ioctl(file,
-                                     VIDEO1394_IOC_TALK_WAIT_BUFFER,
-                                     (unsigned long) &wait);
-        set_fs(old_fs);
-
-        return ret;
-}
-
-static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        return -EFAULT;   /* ??? was there before. */
-
-       return video1394_ioctl(file,
-                               VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
-}
-
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case VIDEO1394_IOC_LISTEN_CHANNEL:
-       case VIDEO1394_IOC_UNLISTEN_CHANNEL:
-       case VIDEO1394_IOC_TALK_CHANNEL:
-       case VIDEO1394_IOC_UNTALK_CHANNEL:
-               return video1394_ioctl(f, cmd, arg);
-
-       case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER:
-               return video1394_w_wait32(f, cmd, arg);
-       case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER:
-               return video1394_wr_wait32(f, cmd, arg);
-       case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
-               return video1394_queue_buf32(f, cmd, arg);
-       case VIDEO1394_IOC32_TALK_WAIT_BUFFER:
-               return video1394_w_wait32(f, cmd, arg);
-       case VIDEO1394_IOC32_LISTEN_POLL_BUFFER:
-               return video1394_wr_wait32(f, cmd, arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-#endif /* CONFIG_COMPAT */
-
-static void __exit video1394_exit_module (void)
-{
-       hpsb_unregister_protocol(&video1394_driver);
-       hpsb_unregister_highlevel(&video1394_highlevel);
-       cdev_del(&video1394_cdev);
-       PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
-}
-
-static int __init video1394_init_module (void)
-{
-       int ret;
-
-       hpsb_init_highlevel(&video1394_highlevel);
-
-       cdev_init(&video1394_cdev, &video1394_fops);
-       video1394_cdev.owner = THIS_MODULE;
-       ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
-       if (ret) {
-               PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
-               return ret;
-        }
-
-       hpsb_register_highlevel(&video1394_highlevel);
-
-       ret = hpsb_register_protocol(&video1394_driver);
-       if (ret) {
-               PRINT_G(KERN_ERR, "video1394: failed to register protocol");
-               hpsb_unregister_highlevel(&video1394_highlevel);
-               cdev_del(&video1394_cdev);
-               return ret;
-       }
-
-       PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
-       return 0;
-}
-
-
-module_init(video1394_init_module);
-module_exit(video1394_exit_module);
diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h
deleted file mode 100644 (file)
index 9a89d9c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Peter Schlaile <udbz@rz.uni-karlsruhe.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _VIDEO_1394_H
-#define _VIDEO_1394_H
-
-#include "ieee1394-ioctl.h"
-
-#define VIDEO1394_DRIVER_NAME "video1394"
-
-#define VIDEO1394_MAX_SIZE 0x4000000
-
-enum {
-       VIDEO1394_BUFFER_FREE = 0,
-       VIDEO1394_BUFFER_QUEUED,
-       VIDEO1394_BUFFER_READY
-};
-
-#define VIDEO1394_SYNC_FRAMES          0x00000001
-#define VIDEO1394_INCLUDE_ISO_HEADERS  0x00000002
-#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
-
-struct video1394_mmap {
-       int channel;                    /* -1 to find an open channel in LISTEN/TALK */
-       unsigned int sync_tag;
-       unsigned int nb_buffers;
-       unsigned int buf_size;
-       unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
-                                    Maximum packet size */
-       unsigned int fps;
-       unsigned int syt_offset;
-       unsigned int flags;
-};
-
-/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
-struct video1394_queue_variable {
-       unsigned int channel;
-       unsigned int buffer;
-       unsigned int __user * packet_sizes; /* Buffer of size:
-                                      buf_size / packet_size  */
-};
-
-struct video1394_wait {
-       unsigned int channel;
-       unsigned int buffer;
-       struct timeval filltime;        /* time of buffer full */
-};
-
-
-#endif
index ae7c2880e6248fff4746613d69330f0f07e55fce..91916a8d5de408b239050f614f86ed09d4717433 100644 (file)
@@ -59,8 +59,8 @@ __ib_get_agent_port(struct ib_device *device, int port_num)
        struct ib_agent_port_private *entry;
 
        list_for_each_entry(entry, &ib_agent_port_list, port_list) {
-               if (entry->agent[0]->device == device &&
-                   entry->agent[0]->port_num == port_num)
+               if (entry->agent[1]->device == device &&
+                   entry->agent[1]->port_num == port_num)
                        return entry;
        }
        return NULL;
@@ -155,14 +155,16 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
                goto error1;
        }
 
-       /* Obtain send only MAD agent for SMI QP */
-       port_priv->agent[0] = ib_register_mad_agent(device, port_num,
-                                                   IB_QPT_SMI, NULL, 0,
-                                                   &agent_send_handler,
-                                                   NULL, NULL);
-       if (IS_ERR(port_priv->agent[0])) {
-               ret = PTR_ERR(port_priv->agent[0]);
-               goto error2;
+       if (rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND) {
+               /* Obtain send only MAD agent for SMI QP */
+               port_priv->agent[0] = ib_register_mad_agent(device, port_num,
+                                                           IB_QPT_SMI, NULL, 0,
+                                                           &agent_send_handler,
+                                                           NULL, NULL);
+               if (IS_ERR(port_priv->agent[0])) {
+                       ret = PTR_ERR(port_priv->agent[0]);
+                       goto error2;
+               }
        }
 
        /* Obtain send only MAD agent for GSI QP */
@@ -182,7 +184,8 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
        return 0;
 
 error3:
-       ib_unregister_mad_agent(port_priv->agent[0]);
+       if (port_priv->agent[0])
+               ib_unregister_mad_agent(port_priv->agent[0]);
 error2:
        kfree(port_priv);
 error1:
@@ -205,7 +208,9 @@ int ib_agent_port_close(struct ib_device *device, int port_num)
        spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
 
        ib_unregister_mad_agent(port_priv->agent[1]);
-       ib_unregister_mad_agent(port_priv->agent[0]);
+       if (port_priv->agent[0])
+               ib_unregister_mad_agent(port_priv->agent[0]);
+
        kfree(port_priv);
        return 0;
 }
index b930b8110a63b22f23822cc812740b0acf120988..6884da24fde1e8338ef572aec075167faf5a73f0 100644 (file)
@@ -59,6 +59,7 @@ MODULE_LICENSE("Dual BSD/GPL");
 #define CMA_CM_RESPONSE_TIMEOUT 20
 #define CMA_MAX_CM_RETRIES 15
 #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
+#define CMA_IBOE_PACKET_LIFETIME 18
 
 static void cma_add_one(struct ib_device *device);
 static void cma_remove_one(struct ib_device *device);
@@ -157,6 +158,7 @@ struct cma_multicast {
        struct list_head        list;
        void                    *context;
        struct sockaddr_storage addr;
+       struct kref             mcref;
 };
 
 struct cma_work {
@@ -173,6 +175,12 @@ struct cma_ndev_work {
        struct rdma_cm_event    event;
 };
 
+struct iboe_mcast_work {
+       struct work_struct       work;
+       struct rdma_id_private  *id;
+       struct cma_multicast    *mc;
+};
+
 union cma_ip_addr {
        struct in6_addr ip6;
        struct {
@@ -281,6 +289,8 @@ static void cma_attach_to_dev(struct rdma_id_private *id_priv,
        atomic_inc(&cma_dev->refcount);
        id_priv->cma_dev = cma_dev;
        id_priv->id.device = cma_dev->device;
+       id_priv->id.route.addr.dev_addr.transport =
+               rdma_node_get_transport(cma_dev->device->node_type);
        list_add_tail(&id_priv->list, &cma_dev->id_list);
 }
 
@@ -290,6 +300,14 @@ static inline void cma_deref_dev(struct cma_device *cma_dev)
                complete(&cma_dev->comp);
 }
 
+static inline void release_mc(struct kref *kref)
+{
+       struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref);
+
+       kfree(mc->multicast.ib);
+       kfree(mc);
+}
+
 static void cma_detach_from_dev(struct rdma_id_private *id_priv)
 {
        list_del(&id_priv->list);
@@ -323,22 +341,63 @@ static int cma_set_qkey(struct rdma_id_private *id_priv)
        return ret;
 }
 
+static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num)
+{
+       int i;
+       int err;
+       struct ib_port_attr props;
+       union ib_gid tmp;
+
+       err = ib_query_port(device, port_num, &props);
+       if (err)
+               return 1;
+
+       for (i = 0; i < props.gid_tbl_len; ++i) {
+               err = ib_query_gid(device, port_num, i, &tmp);
+               if (err)
+                       return 1;
+               if (!memcmp(&tmp, gid, sizeof tmp))
+                       return 0;
+       }
+
+       return -EAGAIN;
+}
+
 static int cma_acquire_dev(struct rdma_id_private *id_priv)
 {
        struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
        struct cma_device *cma_dev;
-       union ib_gid gid;
+       union ib_gid gid, iboe_gid;
        int ret = -ENODEV;
+       u8 port;
+       enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
+               IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
 
-       rdma_addr_get_sgid(dev_addr, &gid);
+       iboe_addr_get_sgid(dev_addr, &iboe_gid);
+       memcpy(&gid, dev_addr->src_dev_addr +
+              rdma_addr_gid_offset(dev_addr), sizeof gid);
        list_for_each_entry(cma_dev, &dev_list, list) {
-               ret = ib_find_cached_gid(cma_dev->device, &gid,
-                                        &id_priv->id.port_num, NULL);
-               if (!ret) {
-                       cma_attach_to_dev(id_priv, cma_dev);
-                       break;
+               for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
+                       if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) {
+                               if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB &&
+                                   rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET)
+                                       ret = find_gid_port(cma_dev->device, &iboe_gid, port);
+                               else
+                                       ret = find_gid_port(cma_dev->device, &gid, port);
+
+                               if (!ret) {
+                                       id_priv->id.port_num = port;
+                                       goto out;
+                               } else if (ret == 1)
+                                       break;
+                       }
                }
        }
+
+out:
+       if (!ret)
+               cma_attach_to_dev(id_priv, cma_dev);
+
        return ret;
 }
 
@@ -556,10 +615,16 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
 {
        struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
        int ret;
+       u16 pkey;
+
+       if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) ==
+           IB_LINK_LAYER_INFINIBAND)
+               pkey = ib_addr_get_pkey(dev_addr);
+       else
+               pkey = 0xffff;
 
        ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
-                                 ib_addr_get_pkey(dev_addr),
-                                 &qp_attr->pkey_index);
+                                 pkey, &qp_attr->pkey_index);
        if (ret)
                return ret;
 
@@ -737,8 +802,8 @@ static inline int cma_user_data_offset(enum rdma_port_space ps)
 
 static void cma_cancel_route(struct rdma_id_private *id_priv)
 {
-       switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
-       case RDMA_TRANSPORT_IB:
+       switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) {
+       case IB_LINK_LAYER_INFINIBAND:
                if (id_priv->query)
                        ib_sa_cancel_query(id_priv->query_id, id_priv->query);
                break;
@@ -816,8 +881,17 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
                mc = container_of(id_priv->mc_list.next,
                                  struct cma_multicast, list);
                list_del(&mc->list);
-               ib_sa_free_multicast(mc->multicast.ib);
-               kfree(mc);
+               switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) {
+               case IB_LINK_LAYER_INFINIBAND:
+                       ib_sa_free_multicast(mc->multicast.ib);
+                       kfree(mc);
+                       break;
+               case IB_LINK_LAYER_ETHERNET:
+                       kref_put(&mc->mcref, release_mc);
+                       break;
+               default:
+                       break;
+               }
        }
 }
 
@@ -833,7 +907,7 @@ void rdma_destroy_id(struct rdma_cm_id *id)
        mutex_lock(&lock);
        if (id_priv->cma_dev) {
                mutex_unlock(&lock);
-               switch (rdma_node_get_transport(id->device->node_type)) {
+               switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
                case RDMA_TRANSPORT_IB:
                        if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
                                ib_destroy_cm_id(id_priv->cm_id.ib);
@@ -1708,6 +1782,81 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
        return 0;
 }
 
+static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
+{
+       struct rdma_route *route = &id_priv->id.route;
+       struct rdma_addr *addr = &route->addr;
+       struct cma_work *work;
+       int ret;
+       struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
+       struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
+       struct net_device *ndev = NULL;
+       u16 vid;
+
+       if (src_addr->sin_family != dst_addr->sin_family)
+               return -EINVAL;
+
+       work = kzalloc(sizeof *work, GFP_KERNEL);
+       if (!work)
+               return -ENOMEM;
+
+       work->id = id_priv;
+       INIT_WORK(&work->work, cma_work_handler);
+
+       route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
+       if (!route->path_rec) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       route->num_paths = 1;
+
+       if (addr->dev_addr.bound_dev_if)
+               ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
+       if (!ndev) {
+               ret = -ENODEV;
+               goto err2;
+       }
+
+       vid = rdma_vlan_dev_vlan_id(ndev);
+
+       iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid);
+       iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid);
+
+       route->path_rec->hop_limit = 1;
+       route->path_rec->reversible = 1;
+       route->path_rec->pkey = cpu_to_be16(0xffff);
+       route->path_rec->mtu_selector = IB_SA_EQ;
+       route->path_rec->sl = id_priv->tos >> 5;
+
+       route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
+       route->path_rec->rate_selector = IB_SA_EQ;
+       route->path_rec->rate = iboe_get_rate(ndev);
+       dev_put(ndev);
+       route->path_rec->packet_life_time_selector = IB_SA_EQ;
+       route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
+       if (!route->path_rec->mtu) {
+               ret = -EINVAL;
+               goto err2;
+       }
+
+       work->old_state = CMA_ROUTE_QUERY;
+       work->new_state = CMA_ROUTE_RESOLVED;
+       work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+       work->event.status = 0;
+
+       queue_work(cma_wq, &work->work);
+
+       return 0;
+
+err2:
+       kfree(route->path_rec);
+       route->path_rec = NULL;
+err1:
+       kfree(work);
+       return ret;
+}
+
 int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
 {
        struct rdma_id_private *id_priv;
@@ -1720,7 +1869,16 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
        atomic_inc(&id_priv->refcount);
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               ret = cma_resolve_ib_route(id_priv, timeout_ms);
+               switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+               case IB_LINK_LAYER_INFINIBAND:
+                       ret = cma_resolve_ib_route(id_priv, timeout_ms);
+                       break;
+               case IB_LINK_LAYER_ETHERNET:
+                       ret = cma_resolve_iboe_route(id_priv);
+                       break;
+               default:
+                       ret = -ENOSYS;
+               }
                break;
        case RDMA_TRANSPORT_IWARP:
                ret = cma_resolve_iw_route(id_priv, timeout_ms);
@@ -1773,7 +1931,7 @@ port_found:
                goto out;
 
        id_priv->id.route.addr.dev_addr.dev_type =
-               (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ?
+               (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ?
                ARPHRD_INFINIBAND : ARPHRD_ETHER;
 
        rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
@@ -2758,6 +2916,102 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
        return 0;
 }
 
+static void iboe_mcast_work_handler(struct work_struct *work)
+{
+       struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
+       struct cma_multicast *mc = mw->mc;
+       struct ib_sa_multicast *m = mc->multicast.ib;
+
+       mc->multicast.ib->context = mc;
+       cma_ib_mc_handler(0, m);
+       kref_put(&mc->mcref, release_mc);
+       kfree(mw);
+}
+
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+       if (cma_any_addr(addr)) {
+               memset(mgid, 0, sizeof *mgid);
+       } else if (addr->sa_family == AF_INET6) {
+               memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+       } else {
+               mgid->raw[0] = 0xff;
+               mgid->raw[1] = 0x0e;
+               mgid->raw[2] = 0;
+               mgid->raw[3] = 0;
+               mgid->raw[4] = 0;
+               mgid->raw[5] = 0;
+               mgid->raw[6] = 0;
+               mgid->raw[7] = 0;
+               mgid->raw[8] = 0;
+               mgid->raw[9] = 0;
+               mgid->raw[10] = 0xff;
+               mgid->raw[11] = 0xff;
+               *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
+       }
+}
+
+static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
+                                  struct cma_multicast *mc)
+{
+       struct iboe_mcast_work *work;
+       struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+       int err;
+       struct sockaddr *addr = (struct sockaddr *)&mc->addr;
+       struct net_device *ndev = NULL;
+
+       if (cma_zero_addr((struct sockaddr *)&mc->addr))
+               return -EINVAL;
+
+       work = kzalloc(sizeof *work, GFP_KERNEL);
+       if (!work)
+               return -ENOMEM;
+
+       mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
+       if (!mc->multicast.ib) {
+               err = -ENOMEM;
+               goto out1;
+       }
+
+       cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid);
+
+       mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
+       if (id_priv->id.ps == RDMA_PS_UDP)
+               mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+
+       if (dev_addr->bound_dev_if)
+               ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+       if (!ndev) {
+               err = -ENODEV;
+               goto out2;
+       }
+       mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
+       mc->multicast.ib->rec.hop_limit = 1;
+       mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
+       dev_put(ndev);
+       if (!mc->multicast.ib->rec.mtu) {
+               err = -EINVAL;
+               goto out2;
+       }
+       iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid);
+       work->id = id_priv;
+       work->mc = mc;
+       INIT_WORK(&work->work, iboe_mcast_work_handler);
+       kref_get(&mc->mcref);
+       queue_work(cma_wq, &work->work);
+
+       return 0;
+
+out2:
+       kfree(mc->multicast.ib);
+out1:
+       kfree(work);
+       return err;
+}
+
 int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
                        void *context)
 {
@@ -2784,7 +3038,17 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
 
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               ret = cma_join_ib_multicast(id_priv, mc);
+               switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+               case IB_LINK_LAYER_INFINIBAND:
+                       ret = cma_join_ib_multicast(id_priv, mc);
+                       break;
+               case IB_LINK_LAYER_ETHERNET:
+                       kref_init(&mc->mcref);
+                       ret = cma_iboe_join_multicast(id_priv, mc);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
                break;
        default:
                ret = -ENOSYS;
@@ -2817,8 +3081,19 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
                                ib_detach_mcast(id->qp,
                                                &mc->multicast.ib->rec.mgid,
                                                mc->multicast.ib->rec.mlid);
-                       ib_sa_free_multicast(mc->multicast.ib);
-                       kfree(mc);
+                       if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) {
+                               switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+                               case IB_LINK_LAYER_INFINIBAND:
+                                       ib_sa_free_multicast(mc->multicast.ib);
+                                       kfree(mc);
+                                       break;
+                               case IB_LINK_LAYER_ETHERNET:
+                                       kref_put(&mc->mcref, release_mc);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
                        return;
                }
        }
index bfead5bc25f6e14efcc09c4e5be51050785acb53..2a1e9ae134b4c330bbffd048d6ce037e75652d45 100644 (file)
@@ -506,6 +506,8 @@ int iw_cm_accept(struct iw_cm_id *cm_id,
        qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
        if (!qp) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+               wake_up_all(&cm_id_priv->connect_wait);
                return -EINVAL;
        }
        cm_id->device->iwcm->add_ref(qp);
@@ -565,6 +567,8 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
        qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
        if (!qp) {
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+               wake_up_all(&cm_id_priv->connect_wait);
                return -EINVAL;
        }
        cm_id->device->iwcm->add_ref(qp);
index ef1304f151dc6fbaf9cf847a79557b1953f3e448..822cfdcd9f785af9fffb9a2b2b9b9f037b328e33 100644 (file)
@@ -2598,6 +2598,9 @@ static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info)
        struct ib_mad_private *recv;
        struct ib_mad_list_head *mad_list;
 
+       if (!qp_info->qp)
+               return;
+
        while (!list_empty(&qp_info->recv_queue.list)) {
 
                mad_list = list_entry(qp_info->recv_queue.list.next,
@@ -2639,6 +2642,9 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
 
        for (i = 0; i < IB_MAD_QPS_CORE; i++) {
                qp = port_priv->qp_info[i].qp;
+               if (!qp)
+                       continue;
+
                /*
                 * PKey index for QP1 is irrelevant but
                 * one is needed for the Reset to Init transition
@@ -2680,6 +2686,9 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
        }
 
        for (i = 0; i < IB_MAD_QPS_CORE; i++) {
+               if (!port_priv->qp_info[i].qp)
+                       continue;
+
                ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL);
                if (ret) {
                        printk(KERN_ERR PFX "Couldn't post receive WRs\n");
@@ -2758,6 +2767,9 @@ error:
 
 static void destroy_mad_qp(struct ib_mad_qp_info *qp_info)
 {
+       if (!qp_info->qp)
+               return;
+
        ib_destroy_qp(qp_info->qp);
        kfree(qp_info->snoop_table);
 }
@@ -2773,6 +2785,7 @@ static int ib_mad_port_open(struct ib_device *device,
        struct ib_mad_port_private *port_priv;
        unsigned long flags;
        char name[sizeof "ib_mad123"];
+       int has_smi;
 
        /* Create new device info */
        port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
@@ -2788,7 +2801,11 @@ static int ib_mad_port_open(struct ib_device *device,
        init_mad_qp(port_priv, &port_priv->qp_info[0]);
        init_mad_qp(port_priv, &port_priv->qp_info[1]);
 
-       cq_size = (mad_sendq_size + mad_recvq_size) * 2;
+       cq_size = mad_sendq_size + mad_recvq_size;
+       has_smi = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND;
+       if (has_smi)
+               cq_size *= 2;
+
        port_priv->cq = ib_create_cq(port_priv->device,
                                     ib_mad_thread_completion_handler,
                                     NULL, port_priv, cq_size, 0);
@@ -2812,9 +2829,11 @@ static int ib_mad_port_open(struct ib_device *device,
                goto error5;
        }
 
-       ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
-       if (ret)
-               goto error6;
+       if (has_smi) {
+               ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
+               if (ret)
+                       goto error6;
+       }
        ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI);
        if (ret)
                goto error7;
index a519801dcfb758f785a885ce49259fa7b1a01f8d..68b4162fd9d2b17ee33a2d565b381bafa94c7ae2 100644 (file)
@@ -774,6 +774,10 @@ static void mcast_event_handler(struct ib_event_handler *handler,
        int index;
 
        dev = container_of(handler, struct mcast_device, event_handler);
+       if (rdma_port_get_link_layer(dev->device, event->element.port_num) !=
+           IB_LINK_LAYER_INFINIBAND)
+               return;
+
        index = event->element.port_num - dev->start_port;
 
        switch (event->event) {
@@ -796,6 +800,7 @@ static void mcast_add_one(struct ib_device *device)
        struct mcast_device *dev;
        struct mcast_port *port;
        int i;
+       int count = 0;
 
        if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
                return;
@@ -813,6 +818,9 @@ static void mcast_add_one(struct ib_device *device)
        }
 
        for (i = 0; i <= dev->end_port - dev->start_port; i++) {
+               if (rdma_port_get_link_layer(device, dev->start_port + i) !=
+                   IB_LINK_LAYER_INFINIBAND)
+                       continue;
                port = &dev->port[i];
                port->dev = dev;
                port->port_num = dev->start_port + i;
@@ -820,6 +828,12 @@ static void mcast_add_one(struct ib_device *device)
                port->table = RB_ROOT;
                init_completion(&port->comp);
                atomic_set(&port->refcount, 1);
+               ++count;
+       }
+
+       if (!count) {
+               kfree(dev);
+               return;
        }
 
        dev->device = device;
@@ -843,9 +857,12 @@ static void mcast_remove_one(struct ib_device *device)
        flush_workqueue(mcast_wq);
 
        for (i = 0; i <= dev->end_port - dev->start_port; i++) {
-               port = &dev->port[i];
-               deref_port(port);
-               wait_for_completion(&port->comp);
+               if (rdma_port_get_link_layer(device, dev->start_port + i) ==
+                   IB_LINK_LAYER_INFINIBAND) {
+                       port = &dev->port[i];
+                       deref_port(port);
+                       wait_for_completion(&port->comp);
+               }
        }
 
        kfree(dev);
index 7e1ffd8ccd5c07084317fecbae15cd3574938991..91a660310b7c03b3c920bb8b70f86a790720414b 100644 (file)
@@ -416,6 +416,9 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
                struct ib_sa_port *port =
                        &sa_dev->port[event->element.port_num - sa_dev->start_port];
 
+               if (rdma_port_get_link_layer(handler->device, port->port_num) != IB_LINK_LAYER_INFINIBAND)
+                       return;
+
                spin_lock_irqsave(&port->ah_lock, flags);
                if (port->sm_ah)
                        kref_put(&port->sm_ah->ref, free_sm_ah);
@@ -493,6 +496,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
 {
        int ret;
        u16 gid_index;
+       int force_grh;
 
        memset(ah_attr, 0, sizeof *ah_attr);
        ah_attr->dlid = be16_to_cpu(rec->dlid);
@@ -502,7 +506,9 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
        ah_attr->port_num = port_num;
        ah_attr->static_rate = rec->rate;
 
-       if (rec->hop_limit > 1) {
+       force_grh = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_ETHERNET;
+
+       if (rec->hop_limit > 1 || force_grh) {
                ah_attr->ah_flags = IB_AH_GRH;
                ah_attr->grh.dgid = rec->dgid;
 
@@ -1007,7 +1013,7 @@ static void ib_sa_add_one(struct ib_device *device)
                e = device->phys_port_cnt;
        }
 
-       sa_dev = kmalloc(sizeof *sa_dev +
+       sa_dev = kzalloc(sizeof *sa_dev +
                         (e - s + 1) * sizeof (struct ib_sa_port),
                         GFP_KERNEL);
        if (!sa_dev)
@@ -1017,9 +1023,12 @@ static void ib_sa_add_one(struct ib_device *device)
        sa_dev->end_port   = e;
 
        for (i = 0; i <= e - s; ++i) {
+               spin_lock_init(&sa_dev->port[i].ah_lock);
+               if (rdma_port_get_link_layer(device, i + 1) != IB_LINK_LAYER_INFINIBAND)
+                       continue;
+
                sa_dev->port[i].sm_ah    = NULL;
                sa_dev->port[i].port_num = i + s;
-               spin_lock_init(&sa_dev->port[i].ah_lock);
 
                sa_dev->port[i].agent =
                        ib_register_mad_agent(device, i + s, IB_QPT_GSI,
@@ -1045,13 +1054,15 @@ static void ib_sa_add_one(struct ib_device *device)
                goto err;
 
        for (i = 0; i <= e - s; ++i)
-               update_sm_ah(&sa_dev->port[i].update_task);
+               if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+                       update_sm_ah(&sa_dev->port[i].update_task);
 
        return;
 
 err:
        while (--i >= 0)
-               ib_unregister_mad_agent(sa_dev->port[i].agent);
+               if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+                       ib_unregister_mad_agent(sa_dev->port[i].agent);
 
        kfree(sa_dev);
 
@@ -1071,9 +1082,12 @@ static void ib_sa_remove_one(struct ib_device *device)
        flush_scheduled_work();
 
        for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
-               ib_unregister_mad_agent(sa_dev->port[i].agent);
-               if (sa_dev->port[i].sm_ah)
-                       kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+               if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) {
+                       ib_unregister_mad_agent(sa_dev->port[i].agent);
+                       if (sa_dev->port[i].sm_ah)
+                               kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+               }
+
        }
 
        kfree(sa_dev);
index 3627300e2a10e1efe8d1435d32313a05b3302507..9ab5df72df7bf3b3c93dfb7ef6dc21b9810592a3 100644 (file)
@@ -222,6 +222,19 @@ static ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused,
        }
 }
 
+static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
+                              char *buf)
+{
+       switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) {
+       case IB_LINK_LAYER_INFINIBAND:
+               return sprintf(buf, "%s\n", "InfiniBand");
+       case IB_LINK_LAYER_ETHERNET:
+               return sprintf(buf, "%s\n", "Ethernet");
+       default:
+               return sprintf(buf, "%s\n", "Unknown");
+       }
+}
+
 static PORT_ATTR_RO(state);
 static PORT_ATTR_RO(lid);
 static PORT_ATTR_RO(lid_mask_count);
@@ -230,6 +243,7 @@ static PORT_ATTR_RO(sm_sl);
 static PORT_ATTR_RO(cap_mask);
 static PORT_ATTR_RO(rate);
 static PORT_ATTR_RO(phys_state);
+static PORT_ATTR_RO(link_layer);
 
 static struct attribute *port_default_attrs[] = {
        &port_attr_state.attr,
@@ -240,6 +254,7 @@ static struct attribute *port_default_attrs[] = {
        &port_attr_cap_mask.attr,
        &port_attr_rate.attr,
        &port_attr_phys_state.attr,
+       &port_attr_link_layer.attr,
        NULL
 };
 
index ac7edc24165cd5902d1557df18a0e130cf7f5458..ca12acf383793615a72ca1a828d544c8e32b0324 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/in6.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 
 #include <rdma/rdma_user_cm.h>
 #include <rdma/ib_marshall.h>
@@ -50,8 +51,24 @@ MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
 MODULE_LICENSE("Dual BSD/GPL");
 
-enum {
-       UCMA_MAX_BACKLOG        = 128
+static unsigned int max_backlog = 1024;
+
+static struct ctl_table_header *ucma_ctl_table_hdr;
+static ctl_table ucma_ctl_table[] = {
+       {
+               .procname       = "max_backlog",
+               .data           = &max_backlog,
+               .maxlen         = sizeof max_backlog,
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       { }
+};
+
+static struct ctl_path ucma_ctl_path[] = {
+       { .procname = "net" },
+       { .procname = "rdma_ucm" },
+       { }
 };
 
 struct ucma_file {
@@ -583,6 +600,42 @@ static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
        }
 }
 
+static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
+                                struct rdma_route *route)
+{
+       struct rdma_dev_addr *dev_addr;
+       struct net_device *dev;
+       u16 vid = 0;
+
+       resp->num_paths = route->num_paths;
+       switch (route->num_paths) {
+       case 0:
+               dev_addr = &route->addr.dev_addr;
+               dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+                       if (dev) {
+                               vid = rdma_vlan_dev_vlan_id(dev);
+                               dev_put(dev);
+                       }
+
+               iboe_mac_vlan_to_ll((union ib_gid *) &resp->ib_route[0].dgid,
+                                   dev_addr->dst_dev_addr, vid);
+               iboe_addr_get_sgid(dev_addr,
+                                  (union ib_gid *) &resp->ib_route[0].sgid);
+               resp->ib_route[0].pkey = cpu_to_be16(0xffff);
+               break;
+       case 2:
+               ib_copy_path_rec_to_user(&resp->ib_route[1],
+                                        &route->path_rec[1]);
+               /* fall through */
+       case 1:
+               ib_copy_path_rec_to_user(&resp->ib_route[0],
+                                        &route->path_rec[0]);
+               break;
+       default:
+               break;
+       }
+}
+
 static ssize_t ucma_query_route(struct ucma_file *file,
                                const char __user *inbuf,
                                int in_len, int out_len)
@@ -617,12 +670,17 @@ static ssize_t ucma_query_route(struct ucma_file *file,
 
        resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
        resp.port_num = ctx->cm_id->port_num;
-       switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
-       case RDMA_TRANSPORT_IB:
-               ucma_copy_ib_route(&resp, &ctx->cm_id->route);
-               break;
-       default:
-               break;
+       if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
+               switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
+               case IB_LINK_LAYER_INFINIBAND:
+                       ucma_copy_ib_route(&resp, &ctx->cm_id->route);
+                       break;
+               case IB_LINK_LAYER_ETHERNET:
+                       ucma_copy_iboe_route(&resp, &ctx->cm_id->route);
+                       break;
+               default:
+                       break;
+               }
        }
 
 out:
@@ -686,8 +744,8 @@ static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ?
-                      cmd.backlog : UCMA_MAX_BACKLOG;
+       ctx->backlog = cmd.backlog > 0 && cmd.backlog < max_backlog ?
+                      cmd.backlog : max_backlog;
        ret = rdma_listen(ctx->cm_id, ctx->backlog);
        ucma_put_ctx(ctx);
        return ret;
@@ -1279,16 +1337,26 @@ static int __init ucma_init(void)
        ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version);
        if (ret) {
                printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n");
-               goto err;
+               goto err1;
+       }
+
+       ucma_ctl_table_hdr = register_sysctl_paths(ucma_ctl_path, ucma_ctl_table);
+       if (!ucma_ctl_table_hdr) {
+               printk(KERN_ERR "rdma_ucm: couldn't register sysctl paths\n");
+               ret = -ENOMEM;
+               goto err2;
        }
        return 0;
-err:
+err2:
+       device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
+err1:
        misc_deregister(&ucma_misc);
        return ret;
 }
 
 static void __exit ucma_cleanup(void)
 {
+       unregister_sysctl_table(ucma_ctl_table_hdr);
        device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
        misc_deregister(&ucma_misc);
        idr_destroy(&ctx_idr);
index 650b501eb142718fb322019a9357e2186c02a71c..bb7e19280821c1074c6efd23a992f243ba33d258 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/if_ether.h>
 
 #include <rdma/ib_pack.h>
 
@@ -80,6 +81,40 @@ static const struct ib_field lrh_table[]  = {
          .size_bits    = 16 }
 };
 
+static const struct ib_field eth_table[]  = {
+       { STRUCT_FIELD(eth, dmac_h),
+         .offset_words = 0,
+         .offset_bits  = 0,
+         .size_bits    = 32 },
+       { STRUCT_FIELD(eth, dmac_l),
+         .offset_words = 1,
+         .offset_bits  = 0,
+         .size_bits    = 16 },
+       { STRUCT_FIELD(eth, smac_h),
+         .offset_words = 1,
+         .offset_bits  = 16,
+         .size_bits    = 16 },
+       { STRUCT_FIELD(eth, smac_l),
+         .offset_words = 2,
+         .offset_bits  = 0,
+         .size_bits    = 32 },
+       { STRUCT_FIELD(eth, type),
+         .offset_words = 3,
+         .offset_bits  = 0,
+         .size_bits    = 16 }
+};
+
+static const struct ib_field vlan_table[]  = {
+       { STRUCT_FIELD(vlan, tag),
+         .offset_words = 0,
+         .offset_bits  = 0,
+         .size_bits    = 16 },
+       { STRUCT_FIELD(vlan, type),
+         .offset_words = 0,
+         .offset_bits  = 16,
+         .size_bits    = 16 }
+};
+
 static const struct ib_field grh_table[]  = {
        { STRUCT_FIELD(grh, ip_version),
          .offset_words = 0,
@@ -180,38 +215,43 @@ static const struct ib_field deth_table[] = {
 /**
  * ib_ud_header_init - Initialize UD header structure
  * @payload_bytes:Length of packet payload
+ * @lrh_present: specify if LRH is present
+ * @eth_present: specify if Eth header is present
+ * @vlan_present: packet is tagged vlan
  * @grh_present:GRH flag (if non-zero, GRH will be included)
- * @immediate_present: specify if immediate data should be used
+ * @immediate_present: specify if immediate data is present
  * @header:Structure to initialize
- *
- * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
- * lrh.packet_length, grh.ip_version, grh.payload_length,
- * grh.next_header, bth.opcode, bth.pad_count and
- * bth.transport_header_version fields of a &struct ib_ud_header given
- * the payload length and whether a GRH will be included.
  */
 void ib_ud_header_init(int                         payload_bytes,
+                      int                  lrh_present,
+                      int                  eth_present,
+                      int                  vlan_present,
                       int                  grh_present,
                       int                  immediate_present,
                       struct ib_ud_header *header)
 {
-       u16 packet_length;
-
        memset(header, 0, sizeof *header);
 
-       header->lrh.link_version     = 0;
-       header->lrh.link_next_header =
-               grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
-       packet_length                = (IB_LRH_BYTES     +
-                                       IB_BTH_BYTES     +
-                                       IB_DETH_BYTES    +
-                                       payload_bytes    +
-                                       4                + /* ICRC     */
-                                       3) / 4;            /* round up */
-
-       header->grh_present          = grh_present;
+       if (lrh_present) {
+               u16 packet_length;
+
+               header->lrh.link_version     = 0;
+               header->lrh.link_next_header =
+                       grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
+               packet_length = (IB_LRH_BYTES   +
+                                IB_BTH_BYTES   +
+                                IB_DETH_BYTES  +
+                                (grh_present ? IB_GRH_BYTES : 0) +
+                                payload_bytes  +
+                                4              + /* ICRC     */
+                                3) / 4;          /* round up */
+               header->lrh.packet_length = cpu_to_be16(packet_length);
+       }
+
+       if (vlan_present)
+               header->eth.type = cpu_to_be16(ETH_P_8021Q);
+
        if (grh_present) {
-               packet_length              += IB_GRH_BYTES / 4;
                header->grh.ip_version      = 6;
                header->grh.payload_length  =
                        cpu_to_be16((IB_BTH_BYTES     +
@@ -222,18 +262,51 @@ void ib_ud_header_init(int                    payload_bytes,
                header->grh.next_header     = 0x1b;
        }
 
-       header->lrh.packet_length = cpu_to_be16(packet_length);
-
-       header->immediate_present            = immediate_present;
        if (immediate_present)
                header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
        else
                header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
        header->bth.pad_count                = (4 - payload_bytes) & 3;
        header->bth.transport_header_version = 0;
+
+       header->lrh_present = lrh_present;
+       header->eth_present = eth_present;
+       header->vlan_present = vlan_present;
+       header->grh_present = grh_present;
+       header->immediate_present = immediate_present;
 }
 EXPORT_SYMBOL(ib_ud_header_init);
 
+/**
+ * ib_lrh_header_pack - Pack LRH header struct into wire format
+ * @lrh:unpacked LRH header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_lrh_header_pack() packs the LRH header structure @lrh into
+ * wire format in the buffer @buf.
+ */
+int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf)
+{
+       ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf);
+       return 0;
+}
+EXPORT_SYMBOL(ib_lrh_header_pack);
+
+/**
+ * ib_lrh_header_unpack - Unpack LRH structure from wire format
+ * @lrh:unpacked LRH header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_lrh_header_unpack() unpacks the LRH header structure from
+ * wire format (in buf) into @lrh.
+ */
+int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh)
+{
+       ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh);
+       return 0;
+}
+EXPORT_SYMBOL(ib_lrh_header_unpack);
+
 /**
  * ib_ud_header_pack - Pack UD header struct into wire format
  * @header:UD header struct
@@ -247,10 +320,21 @@ int ib_ud_header_pack(struct ib_ud_header *header,
 {
        int len = 0;
 
-       ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
-               &header->lrh, buf);
-       len += IB_LRH_BYTES;
-
+       if (header->lrh_present) {
+               ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
+                       &header->lrh, buf + len);
+               len += IB_LRH_BYTES;
+       }
+       if (header->eth_present) {
+               ib_pack(eth_table, ARRAY_SIZE(eth_table),
+                       &header->eth, buf + len);
+               len += IB_ETH_BYTES;
+       }
+       if (header->vlan_present) {
+               ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
+                       &header->vlan, buf + len);
+               len += IB_VLAN_BYTES;
+       }
        if (header->grh_present) {
                ib_pack(grh_table, ARRAY_SIZE(grh_table),
                        &header->grh, buf + len);
index 5fa856909511248c01bb925166bb592e8e94a0e4..cd1996d0ad089950960ba8bb3f4eaa0bff24f7fe 100644 (file)
@@ -1022,7 +1022,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
 
        port->ib_dev   = device;
        port->port_num = port_num;
-       init_MUTEX(&port->sm_sem);
+       sema_init(&port->sm_sem, 1);
        mutex_init(&port->file_mutex);
        INIT_LIST_HEAD(&port->file_list);
 
index 6fcfbeb24a234a419ec9313c956c7c4ba581bcf6..b342248aec059060e19f64ffd69ec28af256682a 100644 (file)
@@ -460,6 +460,8 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
        resp.active_width    = attr.active_width;
        resp.active_speed    = attr.active_speed;
        resp.phys_state      = attr.phys_state;
+       resp.link_layer      = rdma_port_get_link_layer(file->device->ib_dev,
+                                                       cmd.port_num);
 
        if (copy_to_user((void __user *) (unsigned long) cmd.response,
                         &resp, sizeof resp))
index e0fa222387157b3f639bec876297f43ee55ad20a..af7a8b08b2e95abe26704c747ba68bea63e97937 100644 (file)
@@ -94,6 +94,22 @@ rdma_node_get_transport(enum rdma_node_type node_type)
 }
 EXPORT_SYMBOL(rdma_node_get_transport);
 
+enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
+{
+       if (device->get_link_layer)
+               return device->get_link_layer(device, port_num);
+
+       switch (rdma_node_get_transport(device->node_type)) {
+       case RDMA_TRANSPORT_IB:
+               return IB_LINK_LAYER_INFINIBAND;
+       case RDMA_TRANSPORT_IWARP:
+               return IB_LINK_LAYER_ETHERNET;
+       default:
+               return IB_LINK_LAYER_UNSPECIFIED;
+       }
+}
+EXPORT_SYMBOL(rdma_port_get_link_layer);
+
 /* Protection domains */
 
 struct ib_pd *ib_alloc_pd(struct ib_device *device)
index 06964c4af84961864398bb7258c7fae13ffb54f2..950dfabcd89d25f3bd2b33a50f88dc839fce9141 100644 (file)
@@ -1,6 +1,4 @@
-ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_AMSO1100_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
 
index 3b5095470cb3d37955cb24c101f8d07ac609432b..0ebe4e806b86c7a712142aa53fcb117a3d4d8158 100644 (file)
@@ -62,8 +62,8 @@ void c2_rnic_interrupt(struct c2_dev *c2dev)
 static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
 {
        if (c2dev->qptr_array[mq_index] == NULL) {
-               pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
-                       mq_index);
+               pr_debug("handle_mq: stray activity for mq_index=%d\n",
+                        mq_index);
                return;
        }
 
index 7e7b5a66f042ad096b9960cdb6e6ebf66e759d6a..621619c794e5aaed29e56f685e7007e5c57b2e04 100644 (file)
@@ -1,10 +1,8 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb3
+ccflags-y := -Idrivers/net/cxgb3
 
 obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
 
 iw_cxgb3-y :=  iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
               iwch_provider.o iwch.o cxio_hal.o cxio_resource.o
 
-ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_CXGB3_DEBUG) += -DDEBUG
index 005b7b52bc1e5751f8e4eb3f359bd4debcf54202..09dda0b8740eac9ee1a6d50ed536dec3a709a37d 100644 (file)
@@ -160,6 +160,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
        struct rdma_cq_setup setup;
        int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
 
+       size += 1; /* one extra page for storing cq-in-err state */
        cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
        if (!cq->cqid)
                return -ENOMEM;
index e5ddb63e7d234d66ac16aeb6cfb3b33b1cd9dcb2..4bb997aa39d0c69154074d47f40243ff3c314995 100644 (file)
@@ -728,6 +728,22 @@ struct t3_cq {
 #define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \
                                         CQE_GENBIT(*cqe))
 
+struct t3_cq_status_page {
+       u32 cq_err;
+};
+
+static inline int cxio_cq_in_error(struct t3_cq *cq)
+{
+       return ((struct t3_cq_status_page *)
+               &cq->queue[1 << cq->size_log2])->cq_err;
+}
+
+static inline void cxio_set_cq_in_error(struct t3_cq *cq)
+{
+       ((struct t3_cq_status_page *)
+        &cq->queue[1 << cq->size_log2])->cq_err = 1;
+}
+
 static inline void cxio_set_wq_in_error(struct t3_wq *wq)
 {
        wq->queue->wq_in_err.err |= 1;
index 13c88871dc3b90f564a52b4651aa371a4cd15633..d02dcc6e5963bf99f35020525d0c4c2c306c5464 100644 (file)
@@ -1093,8 +1093,8 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        PDBG("%s ep %p credits %u\n", __func__, ep, credits);
 
        if (credits == 0) {
-               PDBG(KERN_ERR "%s 0 credit ack  ep %p state %u\n",
-                       __func__, ep, state_read(&ep->com));
+               PDBG("%s 0 credit ack  ep %p state %u\n",
+                    __func__, ep, state_read(&ep->com));
                return CPL_RET_BUF_DONE;
        }
 
index 6afc89e7572c8d880db196cc34402d3a168e39d8..71e0d845da3d976588542aebd2803e9d4a6ef2e9 100644 (file)
@@ -76,6 +76,14 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
        atomic_inc(&qhp->refcnt);
        spin_unlock(&rnicp->lock);
 
+       if (qhp->attr.state == IWCH_QP_STATE_RTS) {
+               attrs.next_state = IWCH_QP_STATE_TERMINATE;
+               iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
+                              &attrs, 1);
+               if (send_term)
+                       iwch_post_terminate(qhp, rsp_msg);
+       }
+
        event.event = ib_event;
        event.device = chp->ibcq.device;
        if (ib_event == IB_EVENT_CQ_ERR)
@@ -86,13 +94,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
        if (qhp->ibqp.event_handler)
                (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
 
-       if (qhp->attr.state == IWCH_QP_STATE_RTS) {
-               attrs.next_state = IWCH_QP_STATE_TERMINATE;
-               iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
-                              &attrs, 1);
-               if (send_term)
-                       iwch_post_terminate(qhp, rsp_msg);
-       }
+       (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
 
        if (atomic_dec_and_test(&qhp->refcnt))
                wake_up(&qhp->wait);
@@ -179,7 +181,6 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
        case TPT_ERR_BOUND:
        case TPT_ERR_INVALIDATE_SHARED_MR:
        case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
-               (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
                post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1);
                break;
 
index fca0b4b747e4e5aedfb7668a74bb40fafdad9ff2..2e2741307af4be4114df4545a2fb5676f360c8ea 100644 (file)
@@ -154,6 +154,8 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
        struct iwch_create_cq_resp uresp;
        struct iwch_create_cq_req ureq;
        struct iwch_ucontext *ucontext = NULL;
+       static int warned;
+       size_t resplen;
 
        PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
        rhp = to_iwch_dev(ibdev);
@@ -217,15 +219,26 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
                uresp.key = ucontext->key;
                ucontext->key += PAGE_SIZE;
                spin_unlock(&ucontext->mmap_lock);
-               if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+               mm->key = uresp.key;
+               mm->addr = virt_to_phys(chp->cq.queue);
+               if (udata->outlen < sizeof uresp) {
+                       if (!warned++)
+                               printk(KERN_WARNING MOD "Warning - "
+                                      "downlevel libcxgb3 (non-fatal).\n");
+                       mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
+                                            sizeof(struct t3_cqe));
+                       resplen = sizeof(struct iwch_create_cq_resp_v0);
+               } else {
+                       mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
+                                            sizeof(struct t3_cqe));
+                       uresp.memsize = mm->len;
+                       resplen = sizeof uresp;
+               }
+               if (ib_copy_to_udata(udata, &uresp, resplen)) {
                        kfree(mm);
                        iwch_destroy_cq(&chp->ibcq);
                        return ERR_PTR(-EFAULT);
                }
-               mm->key = uresp.key;
-               mm->addr = virt_to_phys(chp->cq.queue);
-               mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
-                                            sizeof (struct t3_cqe));
                insert_mmap(ucontext, mm);
        }
        PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
@@ -1414,6 +1427,7 @@ int iwch_register_device(struct iwch_dev *dev)
        dev->ibdev.post_send = iwch_post_send;
        dev->ibdev.post_recv = iwch_post_receive;
        dev->ibdev.get_protocol_stats = iwch_get_mib;
+       dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
 
        dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
        if (!dev->ibdev.iwcm)
index c64d27bf2c15b20eba43ddf91051ece1212495fb..0993137181d7a893d6084688f003ca05358d3b42 100644 (file)
@@ -802,14 +802,12 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
 /*
  * Assumes qhp lock is held.
  */
-static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
+                               struct iwch_cq *schp, unsigned long *flag)
 {
-       struct iwch_cq *rchp, *schp;
        int count;
        int flushed;
 
-       rchp = get_chp(qhp->rhp, qhp->attr.rcq);
-       schp = get_chp(qhp->rhp, qhp->attr.scq);
 
        PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
        /* take a ref on the qhp since we must release the lock */
@@ -847,10 +845,23 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 
 static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 {
-       if (qhp->ibqp.uobject)
+       struct iwch_cq *rchp, *schp;
+
+       rchp = get_chp(qhp->rhp, qhp->attr.rcq);
+       schp = get_chp(qhp->rhp, qhp->attr.scq);
+
+       if (qhp->ibqp.uobject) {
                cxio_set_wq_in_error(&qhp->wq);
-       else
-               __flush_qp(qhp, flag);
+               cxio_set_cq_in_error(&rchp->cq);
+               (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+               if (schp != rchp) {
+                       cxio_set_cq_in_error(&schp->cq);
+                       (*schp->ibcq.comp_handler)(&schp->ibcq,
+                                                  schp->ibcq.cq_context);
+               }
+               return;
+       }
+       __flush_qp(qhp, rchp, schp, flag);
 }
 
 
index cb7086f558c1e769ad66eee48fee14d1bbe97081..a277c31fcaf7bed35f727c329dabd63b7e10960f 100644 (file)
@@ -45,10 +45,18 @@ struct iwch_create_cq_req {
        __u64 user_rptr_addr;
 };
 
+struct iwch_create_cq_resp_v0 {
+       __u64 key;
+       __u32 cqid;
+       __u32 size_log2;
+};
+
 struct iwch_create_cq_resp {
        __u64 key;
        __u32 cqid;
        __u32 size_log2;
+       __u32 memsize;
+       __u32 reserved;
 };
 
 struct iwch_create_qp_resp {
index e31a499f0172373b274e7c6b4f4321506f7c32dd..cd20b1342aec18e7b017a98678607a9fa26c661d 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb4
+ccflags-y := -Idrivers/net/cxgb4
 
 obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
 
index 32d352a88d50fba3e4526608b6ca345af630ab16..0dc62b1438bee2b52483381db9708d5a1f5c837e 100644 (file)
@@ -117,9 +117,9 @@ static int rcv_win = 256 * 1024;
 module_param(rcv_win, int, 0644);
 MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256KB)");
 
-static int snd_win = 32 * 1024;
+static int snd_win = 128 * 1024;
 module_param(snd_win, int, 0644);
-MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
+MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=128KB)");
 
 static struct workqueue_struct *workq;
 
@@ -172,7 +172,7 @@ static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb,
        error = cxgb4_l2t_send(rdev->lldi.ports[0], skb, l2e);
        if (error < 0)
                kfree_skb(skb);
-       return error;
+       return error < 0 ? error : 0;
 }
 
 int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
@@ -187,7 +187,7 @@ int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
        error = cxgb4_ofld_send(rdev->lldi.ports[0], skb);
        if (error < 0)
                kfree_skb(skb);
-       return error;
+       return error < 0 ? error : 0;
 }
 
 static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
@@ -219,12 +219,11 @@ static void set_emss(struct c4iw_ep *ep, u16 opt)
 
 static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc)
 {
-       unsigned long flags;
        enum c4iw_ep_state state;
 
-       spin_lock_irqsave(&epc->lock, flags);
+       mutex_lock(&epc->mutex);
        state = epc->state;
-       spin_unlock_irqrestore(&epc->lock, flags);
+       mutex_unlock(&epc->mutex);
        return state;
 }
 
@@ -235,12 +234,10 @@ static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
 
 static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&epc->lock, flags);
+       mutex_lock(&epc->mutex);
        PDBG("%s - %s -> %s\n", __func__, states[epc->state], states[new]);
        __state_set(epc, new);
-       spin_unlock_irqrestore(&epc->lock, flags);
+       mutex_unlock(&epc->mutex);
        return;
 }
 
@@ -251,8 +248,8 @@ static void *alloc_ep(int size, gfp_t gfp)
        epc = kzalloc(size, gfp);
        if (epc) {
                kref_init(&epc->kref);
-               spin_lock_init(&epc->lock);
-               init_waitqueue_head(&epc->waitq);
+               mutex_init(&epc->mutex);
+               c4iw_init_wr_wait(&epc->wr_wait);
        }
        PDBG("%s alloc ep %p\n", __func__, epc);
        return epc;
@@ -1131,7 +1128,6 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct c4iw_ep *ep;
        struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
-       unsigned long flags;
        int release = 0;
        unsigned int tid = GET_TID(rpl);
        struct tid_info *t = dev->rdev.lldi.tids;
@@ -1139,7 +1135,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        ep = lookup_tid(t, tid);
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        BUG_ON(!ep);
-       spin_lock_irqsave(&ep->com.lock, flags);
+       mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
        case ABORTING:
                __state_set(&ep->com, DEAD);
@@ -1150,7 +1146,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
                     __func__, ep, ep->com.state);
                break;
        }
-       spin_unlock_irqrestore(&ep->com.lock, flags);
+       mutex_unlock(&ep->com.mutex);
 
        if (release)
                release_ep_resources(ep);
@@ -1213,9 +1209,9 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        }
        PDBG("%s ep %p status %d error %d\n", __func__, ep,
             rpl->status, status2errno(rpl->status));
-       ep->com.rpl_err = status2errno(rpl->status);
-       ep->com.rpl_done = 1;
-       wake_up(&ep->com.waitq);
+       ep->com.wr_wait.ret = status2errno(rpl->status);
+       ep->com.wr_wait.done = 1;
+       wake_up(&ep->com.wr_wait.wait);
 
        return 0;
 }
@@ -1249,9 +1245,9 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_listen_ep *ep = lookup_stid(t, stid);
 
        PDBG("%s ep %p\n", __func__, ep);
-       ep->com.rpl_err = status2errno(rpl->status);
-       ep->com.rpl_done = 1;
-       wake_up(&ep->com.waitq);
+       ep->com.wr_wait.ret = status2errno(rpl->status);
+       ep->com.wr_wait.done = 1;
+       wake_up(&ep->com.wr_wait.wait);
        return 0;
 }
 
@@ -1478,7 +1474,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        struct cpl_peer_close *hdr = cplhdr(skb);
        struct c4iw_ep *ep;
        struct c4iw_qp_attributes attrs;
-       unsigned long flags;
        int disconnect = 1;
        int release = 0;
        int closing = 0;
@@ -1489,7 +1484,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        dst_confirm(ep->dst);
 
-       spin_lock_irqsave(&ep->com.lock, flags);
+       mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
        case MPA_REQ_WAIT:
                __state_set(&ep->com, CLOSING);
@@ -1507,17 +1502,17 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
                 * in rdma connection migration (see c4iw_accept_cr()).
                 */
                __state_set(&ep->com, CLOSING);
-               ep->com.rpl_done = 1;
-               ep->com.rpl_err = -ECONNRESET;
+               ep->com.wr_wait.done = 1;
+               ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-               wake_up(&ep->com.waitq);
+               wake_up(&ep->com.wr_wait.wait);
                break;
        case MPA_REP_SENT:
                __state_set(&ep->com, CLOSING);
-               ep->com.rpl_done = 1;
-               ep->com.rpl_err = -ECONNRESET;
+               ep->com.wr_wait.done = 1;
+               ep->com.wr_wait.ret = -ECONNRESET;
                PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-               wake_up(&ep->com.waitq);
+               wake_up(&ep->com.wr_wait.wait);
                break;
        case FPDU_MODE:
                start_ep_timer(ep);
@@ -1550,7 +1545,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        default:
                BUG_ON(1);
        }
-       spin_unlock_irqrestore(&ep->com.lock, flags);
+       mutex_unlock(&ep->com.mutex);
        if (closing) {
                attrs.next_state = C4IW_QP_STATE_CLOSING;
                c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
@@ -1581,7 +1576,6 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_qp_attributes attrs;
        int ret;
        int release = 0;
-       unsigned long flags;
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int tid = GET_TID(req);
 
@@ -1591,9 +1585,17 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
                     ep->hwtid);
                return 0;
        }
-       spin_lock_irqsave(&ep->com.lock, flags);
        PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
             ep->com.state);
+
+       /*
+        * Wake up any threads in rdma_init() or rdma_fini().
+        */
+       ep->com.wr_wait.done = 1;
+       ep->com.wr_wait.ret = -ECONNRESET;
+       wake_up(&ep->com.wr_wait.wait);
+
+       mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
        case CONNECTING:
                break;
@@ -1605,23 +1607,8 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
                connect_reply_upcall(ep, -ECONNRESET);
                break;
        case MPA_REP_SENT:
-               ep->com.rpl_done = 1;
-               ep->com.rpl_err = -ECONNRESET;
-               PDBG("waking up ep %p\n", ep);
-               wake_up(&ep->com.waitq);
                break;
        case MPA_REQ_RCVD:
-
-               /*
-                * We're gonna mark this puppy DEAD, but keep
-                * the reference on it until the ULP accepts or
-                * rejects the CR. Also wake up anyone waiting
-                * in rdma connection migration (see c4iw_accept_cr()).
-                */
-               ep->com.rpl_done = 1;
-               ep->com.rpl_err = -ECONNRESET;
-               PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-               wake_up(&ep->com.waitq);
                break;
        case MORIBUND:
        case CLOSING:
@@ -1644,7 +1631,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
                break;
        case DEAD:
                PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
-               spin_unlock_irqrestore(&ep->com.lock, flags);
+               mutex_unlock(&ep->com.mutex);
                return 0;
        default:
                BUG_ON(1);
@@ -1655,7 +1642,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
                __state_set(&ep->com, DEAD);
                release = 1;
        }
-       spin_unlock_irqrestore(&ep->com.lock, flags);
+       mutex_unlock(&ep->com.mutex);
 
        rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
        if (!rpl_skb) {
@@ -1681,7 +1668,6 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_ep *ep;
        struct c4iw_qp_attributes attrs;
        struct cpl_close_con_rpl *rpl = cplhdr(skb);
-       unsigned long flags;
        int release = 0;
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int tid = GET_TID(rpl);
@@ -1692,7 +1678,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        BUG_ON(!ep);
 
        /* The cm_id may be null if we failed to connect */
-       spin_lock_irqsave(&ep->com.lock, flags);
+       mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
        case CLOSING:
                __state_set(&ep->com, MORIBUND);
@@ -1717,7 +1703,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
                BUG_ON(1);
                break;
        }
-       spin_unlock_irqrestore(&ep->com.lock, flags);
+       mutex_unlock(&ep->com.mutex);
        if (release)
                release_ep_resources(ep);
        return 0;
@@ -1725,23 +1711,24 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 
 static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
 {
-       struct c4iw_ep *ep;
-       struct cpl_rdma_terminate *term = cplhdr(skb);
+       struct cpl_rdma_terminate *rpl = cplhdr(skb);
        struct tid_info *t = dev->rdev.lldi.tids;
-       unsigned int tid = GET_TID(term);
+       unsigned int tid = GET_TID(rpl);
+       struct c4iw_ep *ep;
+       struct c4iw_qp_attributes attrs;
 
        ep = lookup_tid(t, tid);
+       BUG_ON(!ep);
 
-       if (state_read(&ep->com) != FPDU_MODE)
-               return 0;
+       if (ep->com.qp) {
+               printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
+                      ep->com.qp->wq.sq.qid);
+               attrs.next_state = C4IW_QP_STATE_TERMINATE;
+               c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+                              C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+       } else
+               printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
 
-       PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-       skb_pull(skb, sizeof *term);
-       PDBG("%s saving %d bytes of term msg\n", __func__, skb->len);
-       skb_copy_from_linear_data(skb, ep->com.qp->attr.terminate_buffer,
-                                 skb->len);
-       ep->com.qp->attr.terminate_msg_len = skb->len;
-       ep->com.qp->attr.is_terminate_local = 0;
        return 0;
 }
 
@@ -1762,8 +1749,8 @@ static int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)
        ep = lookup_tid(t, tid);
        PDBG("%s ep %p tid %u credits %u\n", __func__, ep, ep->hwtid, credits);
        if (credits == 0) {
-               PDBG(KERN_ERR "%s 0 credit ack ep %p tid %u state %u\n",
-                       __func__, ep, ep->hwtid, state_read(&ep->com));
+               PDBG("%s 0 credit ack ep %p tid %u state %u\n",
+                    __func__, ep, ep->hwtid, state_read(&ep->com));
                return 0;
        }
 
@@ -2042,6 +2029,7 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
        }
 
        state_set(&ep->com, LISTEN);
+       c4iw_init_wr_wait(&ep->com.wr_wait);
        err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0], ep->stid,
                                  ep->com.local_addr.sin_addr.s_addr,
                                  ep->com.local_addr.sin_port,
@@ -2050,15 +2038,8 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
                goto fail3;
 
        /* wait for pass_open_rpl */
-       wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
-       if (ep->com.rpl_done)
-               err = ep->com.rpl_err;
-       else {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(ep->com.dev->rdev.lldi.pdev));
-               ep->com.dev->rdev.flags = T4_FATAL_ERROR;
-               err = -EIO;
-       }
+       err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+                                 __func__);
        if (!err) {
                cm_id->provider_data = ep;
                goto out;
@@ -2082,20 +2063,12 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id)
 
        might_sleep();
        state_set(&ep->com, DEAD);
-       ep->com.rpl_done = 0;
-       ep->com.rpl_err = 0;
+       c4iw_init_wr_wait(&ep->com.wr_wait);
        err = listen_stop(ep);
        if (err)
                goto done;
-       wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
-       if (ep->com.rpl_done)
-               err = ep->com.rpl_err;
-       else {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(ep->com.dev->rdev.lldi.pdev));
-               ep->com.dev->rdev.flags = T4_FATAL_ERROR;
-               err = -EIO;
-       }
+       err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+                                 __func__);
        cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
 done:
        cm_id->rem_ref(cm_id);
@@ -2106,12 +2079,11 @@ done:
 int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
 {
        int ret = 0;
-       unsigned long flags;
        int close = 0;
        int fatal = 0;
        struct c4iw_rdev *rdev;
 
-       spin_lock_irqsave(&ep->com.lock, flags);
+       mutex_lock(&ep->com.mutex);
 
        PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep,
             states[ep->com.state], abrupt);
@@ -2158,7 +2130,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
                break;
        }
 
-       spin_unlock_irqrestore(&ep->com.lock, flags);
+       mutex_unlock(&ep->com.mutex);
        if (close) {
                if (abrupt)
                        ret = abort_connection(ep, NULL, gfp);
@@ -2172,6 +2144,13 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
        return ret;
 }
 
+static int async_event(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+       struct cpl_fw6_msg *rpl = cplhdr(skb);
+       c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+       return 0;
+}
+
 /*
  * These are the real handlers that are called from a
  * work queue.
@@ -2190,7 +2169,8 @@ static c4iw_handler_func work_handlers[NUM_CPL_CMDS] = {
        [CPL_ABORT_REQ_RSS] = peer_abort,
        [CPL_CLOSE_CON_RPL] = close_con_rpl,
        [CPL_RDMA_TERMINATE] = terminate,
-       [CPL_FW4_ACK] = fw4_ack
+       [CPL_FW4_ACK] = fw4_ack,
+       [CPL_FW6_MSG] = async_event
 };
 
 static void process_timeout(struct c4iw_ep *ep)
@@ -2198,7 +2178,7 @@ static void process_timeout(struct c4iw_ep *ep)
        struct c4iw_qp_attributes attrs;
        int abort = 1;
 
-       spin_lock_irq(&ep->com.lock);
+       mutex_lock(&ep->com.mutex);
        PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
             ep->com.state);
        switch (ep->com.state) {
@@ -2225,7 +2205,7 @@ static void process_timeout(struct c4iw_ep *ep)
                WARN_ON(1);
                abort = 0;
        }
-       spin_unlock_irq(&ep->com.lock);
+       mutex_unlock(&ep->com.mutex);
        if (abort)
                abort_connection(ep, NULL, GFP_KERNEL);
        c4iw_put_ep(&ep->com);
@@ -2309,6 +2289,7 @@ static int set_tcb_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
                printk(KERN_ERR MOD "Unexpected SET_TCB_RPL status %u "
                       "for tid %u\n", rpl->status, GET_TID(rpl));
        }
+       kfree_skb(skb);
        return 0;
 }
 
@@ -2323,20 +2304,25 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
        switch (rpl->type) {
        case 1:
                ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
-               wr_waitp = (__force struct c4iw_wr_wait *)rpl->data[1];
+               wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
                PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
                if (wr_waitp) {
-                       wr_waitp->ret = ret;
+                       if (ret)
+                               wr_waitp->ret = -ret;
+                       else
+                               wr_waitp->ret = 0;
                        wr_waitp->done = 1;
                        wake_up(&wr_waitp->wait);
                }
+               kfree_skb(skb);
                break;
        case 2:
-               c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+               sched(dev, skb);
                break;
        default:
                printk(KERN_ERR MOD "%s unexpected fw6 msg type %u\n", __func__,
                       rpl->type);
+               kfree_skb(skb);
                break;
        }
        return 0;
index b3daf39eed4a0ac52e4d10e18f45cd233d76e969..8d8f8add6fcd93e71fd5b8931616554099bd7b00 100644 (file)
@@ -55,7 +55,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
                        V_FW_RI_RES_WR_NRES(1) |
                        FW_WR_COMPL(1));
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (u64)&wr_wait;
+       res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
        res->u.cq.restype = FW_RI_RES_TYPE_CQ;
        res->u.cq.op = FW_RI_RES_OP_RESET;
@@ -64,14 +64,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
        c4iw_init_wr_wait(&wr_wait);
        ret = c4iw_ofld_send(rdev, skb);
        if (!ret) {
-               wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-               if (!wr_wait.done) {
-                       printk(KERN_ERR MOD "Device %s not responding!\n",
-                              pci_name(rdev->lldi.pdev));
-                       rdev->flags = T4_FATAL_ERROR;
-                       ret = -EIO;
-               } else
-                       ret = wr_wait.ret;
+               ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
        }
 
        kfree(cq->sw_queue);
@@ -132,7 +125,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
                        V_FW_RI_RES_WR_NRES(1) |
                        FW_WR_COMPL(1));
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (u64)&wr_wait;
+       res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
        res->u.cq.restype = FW_RI_RES_TYPE_CQ;
        res->u.cq.op = FW_RI_RES_OP_WRITE;
@@ -157,14 +150,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
        if (ret)
                goto err4;
        PDBG("%s wait_event wr_wait %p\n", __func__, &wr_wait);
-       wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-       if (!wr_wait.done) {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(rdev->lldi.pdev));
-               rdev->flags = T4_FATAL_ERROR;
-               ret = -EIO;
-       } else
-               ret = wr_wait.ret;
+       ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
        if (ret)
                goto err4;
 
@@ -476,6 +462,11 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
                goto proc_cqe;
        }
 
+       if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) {
+               ret = -EAGAIN;
+               goto skip_cqe;
+       }
+
        /*
         * RECV completion.
         */
@@ -696,6 +687,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
                case T4_ERR_MSN_RANGE:
                case T4_ERR_IRD_OVERFLOW:
                case T4_ERR_OPCODE:
+               case T4_ERR_INTERNAL_ERR:
                        wc->status = IB_WC_FATAL_ERR;
                        break;
                case T4_ERR_SWFLUSH:
index 9bbf491d5d9ee087e2081ef024e7ebdd0d2c23aa..54fbc1118abe0eb2e2e4592ab0724e1e72ca0f5a 100644 (file)
@@ -49,29 +49,33 @@ static DEFINE_MUTEX(dev_mutex);
 
 static struct dentry *c4iw_debugfs_root;
 
-struct debugfs_qp_data {
+struct c4iw_debugfs_data {
        struct c4iw_dev *devp;
        char *buf;
        int bufsize;
        int pos;
 };
 
-static int count_qps(int id, void *p, void *data)
+static int count_idrs(int id, void *p, void *data)
 {
-       struct c4iw_qp *qp = p;
        int *countp = data;
 
-       if (id != qp->wq.sq.qid)
-               return 0;
-
        *countp = *countp + 1;
        return 0;
 }
 
-static int dump_qps(int id, void *p, void *data)
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       struct c4iw_debugfs_data *d = file->private_data;
+
+       return simple_read_from_buffer(buf, count, ppos, d->buf, d->pos);
+}
+
+static int dump_qp(int id, void *p, void *data)
 {
        struct c4iw_qp *qp = p;
-       struct debugfs_qp_data *qpd = data;
+       struct c4iw_debugfs_data *qpd = data;
        int space;
        int cc;
 
@@ -101,7 +105,7 @@ static int dump_qps(int id, void *p, void *data)
 
 static int qp_release(struct inode *inode, struct file *file)
 {
-       struct debugfs_qp_data *qpd = file->private_data;
+       struct c4iw_debugfs_data *qpd = file->private_data;
        if (!qpd) {
                printk(KERN_INFO "%s null qpd?\n", __func__);
                return 0;
@@ -113,7 +117,7 @@ static int qp_release(struct inode *inode, struct file *file)
 
 static int qp_open(struct inode *inode, struct file *file)
 {
-       struct debugfs_qp_data *qpd;
+       struct c4iw_debugfs_data *qpd;
        int ret = 0;
        int count = 1;
 
@@ -126,7 +130,7 @@ static int qp_open(struct inode *inode, struct file *file)
        qpd->pos = 0;
 
        spin_lock_irq(&qpd->devp->lock);
-       idr_for_each(&qpd->devp->qpidr, count_qps, &count);
+       idr_for_each(&qpd->devp->qpidr, count_idrs, &count);
        spin_unlock_irq(&qpd->devp->lock);
 
        qpd->bufsize = count * 128;
@@ -137,7 +141,7 @@ static int qp_open(struct inode *inode, struct file *file)
        }
 
        spin_lock_irq(&qpd->devp->lock);
-       idr_for_each(&qpd->devp->qpidr, dump_qps, qpd);
+       idr_for_each(&qpd->devp->qpidr, dump_qp, qpd);
        spin_unlock_irq(&qpd->devp->lock);
 
        qpd->buf[qpd->pos++] = 0;
@@ -149,43 +153,86 @@ out:
        return ret;
 }
 
-static ssize_t qp_read(struct file *file, char __user *buf, size_t count,
-                       loff_t *ppos)
+static const struct file_operations qp_debugfs_fops = {
+       .owner   = THIS_MODULE,
+       .open    = qp_open,
+       .release = qp_release,
+       .read    = debugfs_read,
+       .llseek  = default_llseek,
+};
+
+static int dump_stag(int id, void *p, void *data)
 {
-       struct debugfs_qp_data *qpd = file->private_data;
-       loff_t pos = *ppos;
-       loff_t avail = qpd->pos;
+       struct c4iw_debugfs_data *stagd = data;
+       int space;
+       int cc;
 
-       if (pos < 0)
-               return -EINVAL;
-       if (pos >= avail)
+       space = stagd->bufsize - stagd->pos - 1;
+       if (space == 0)
+               return 1;
+
+       cc = snprintf(stagd->buf + stagd->pos, space, "0x%x\n", id<<8);
+       if (cc < space)
+               stagd->pos += cc;
+       return 0;
+}
+
+static int stag_release(struct inode *inode, struct file *file)
+{
+       struct c4iw_debugfs_data *stagd = file->private_data;
+       if (!stagd) {
+               printk(KERN_INFO "%s null stagd?\n", __func__);
                return 0;
-       if (count > avail - pos)
-               count = avail - pos;
+       }
+       kfree(stagd->buf);
+       kfree(stagd);
+       return 0;
+}
 
-       while (count) {
-               size_t len = 0;
+static int stag_open(struct inode *inode, struct file *file)
+{
+       struct c4iw_debugfs_data *stagd;
+       int ret = 0;
+       int count = 1;
 
-               len = min((int)count, (int)qpd->pos - (int)pos);
-               if (copy_to_user(buf, qpd->buf + pos, len))
-                       return -EFAULT;
-               if (len == 0)
-                       return -EINVAL;
+       stagd = kmalloc(sizeof *stagd, GFP_KERNEL);
+       if (!stagd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       stagd->devp = inode->i_private;
+       stagd->pos = 0;
+
+       spin_lock_irq(&stagd->devp->lock);
+       idr_for_each(&stagd->devp->mmidr, count_idrs, &count);
+       spin_unlock_irq(&stagd->devp->lock);
 
-               buf += len;
-               pos += len;
-               count -= len;
+       stagd->bufsize = count * sizeof("0x12345678\n");
+       stagd->buf = kmalloc(stagd->bufsize, GFP_KERNEL);
+       if (!stagd->buf) {
+               ret = -ENOMEM;
+               goto err1;
        }
-       count = pos - *ppos;
-       *ppos = pos;
-       return count;
+
+       spin_lock_irq(&stagd->devp->lock);
+       idr_for_each(&stagd->devp->mmidr, dump_stag, stagd);
+       spin_unlock_irq(&stagd->devp->lock);
+
+       stagd->buf[stagd->pos++] = 0;
+       file->private_data = stagd;
+       goto out;
+err1:
+       kfree(stagd);
+out:
+       return ret;
 }
 
-static const struct file_operations qp_debugfs_fops = {
+static const struct file_operations stag_debugfs_fops = {
        .owner   = THIS_MODULE,
-       .open    = qp_open,
-       .release = qp_release,
-       .read    = qp_read,
+       .open    = stag_open,
+       .release = stag_release,
+       .read    = debugfs_read,
+       .llseek  = default_llseek,
 };
 
 static int setup_debugfs(struct c4iw_dev *devp)
@@ -199,6 +246,11 @@ static int setup_debugfs(struct c4iw_dev *devp)
                                 (void *)devp, &qp_debugfs_fops);
        if (de && de->d_inode)
                de->d_inode->i_size = 4096;
+
+       de = debugfs_create_file("stags", S_IWUSR, devp->debugfs_root,
+                                (void *)devp, &stag_debugfs_fops);
+       if (de && de->d_inode)
+               de->d_inode->i_size = 4096;
        return 0;
 }
 
@@ -290,7 +342,14 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
                printk(KERN_ERR MOD "error %d initializing rqt pool\n", err);
                goto err3;
        }
+       err = c4iw_ocqp_pool_create(rdev);
+       if (err) {
+               printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
+               goto err4;
+       }
        return 0;
+err4:
+       c4iw_rqtpool_destroy(rdev);
 err3:
        c4iw_pblpool_destroy(rdev);
 err2:
@@ -317,6 +376,7 @@ static void c4iw_remove(struct c4iw_dev *dev)
        idr_destroy(&dev->cqidr);
        idr_destroy(&dev->qpidr);
        idr_destroy(&dev->mmidr);
+       iounmap(dev->rdev.oc_mw_kva);
        ib_dealloc_device(&dev->ibdev);
 }
 
@@ -332,6 +392,17 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        }
        devp->rdev.lldi = *infop;
 
+       devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) +
+               (pci_resource_len(devp->rdev.lldi.pdev, 2) -
+                roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size));
+       devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
+                                              devp->rdev.lldi.vr->ocq.size);
+
+       printk(KERN_INFO MOD "ocq memory: "
+              "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
+              devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
+              devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
+
        mutex_lock(&dev_mutex);
 
        ret = c4iw_rdev_open(&devp->rdev);
@@ -383,46 +454,6 @@ out:
        return dev;
 }
 
-static struct sk_buff *t4_pktgl_to_skb(const struct pkt_gl *gl,
-                                      unsigned int skb_len,
-                                      unsigned int pull_len)
-{
-       struct sk_buff *skb;
-       struct skb_shared_info *ssi;
-
-       if (gl->tot_len <= 512) {
-               skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
-               if (unlikely(!skb))
-                       goto out;
-               __skb_put(skb, gl->tot_len);
-               skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
-       } else {
-               skb = alloc_skb(skb_len, GFP_ATOMIC);
-               if (unlikely(!skb))
-                       goto out;
-               __skb_put(skb, pull_len);
-               skb_copy_to_linear_data(skb, gl->va, pull_len);
-
-               ssi = skb_shinfo(skb);
-               ssi->frags[0].page = gl->frags[0].page;
-               ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
-               ssi->frags[0].size = gl->frags[0].size - pull_len;
-               if (gl->nfrags > 1)
-                       memcpy(&ssi->frags[1], &gl->frags[1],
-                              (gl->nfrags - 1) * sizeof(skb_frag_t));
-               ssi->nr_frags = gl->nfrags;
-
-               skb->len = gl->tot_len;
-               skb->data_len = skb->len - pull_len;
-               skb->truesize += skb->data_len;
-
-               /* Get a reference for the last page, we don't own it */
-               get_page(gl->frags[gl->nfrags - 1].page);
-       }
-out:
-       return skb;
-}
-
 static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
                        const struct pkt_gl *gl)
 {
@@ -447,7 +478,7 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
                c4iw_ev_handler(dev, qid);
                return 0;
        } else {
-               skb = t4_pktgl_to_skb(gl, 128, 128);
+               skb = cxgb4_pktgl_to_skb(gl, 128, 128);
                if (unlikely(!skb))
                        goto nomem;
        }
index 491e76a0327ff7fe52597683aa45c2ea88a164d6..c13041a0aeba90b033b7b338e26ecc80efc42753 100644 (file)
@@ -60,7 +60,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
        if (qhp->attr.state == C4IW_QP_STATE_RTS) {
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
                c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
-                              &attrs, 1);
+                              &attrs, 0);
        }
 
        event.event = ib_event;
index ed459b8f800fb65c0a9ab90b6dfeea6959d28e0c..16032cdb433779656f438b519a582bb710638c98 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/timer.h>
 #include <linux/io.h>
 #include <linux/kfifo.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 
@@ -79,21 +80,6 @@ static inline void *cplhdr(struct sk_buff *skb)
        return skb->data;
 }
 
-#define C4IW_WR_TO (10*HZ)
-
-struct c4iw_wr_wait {
-       wait_queue_head_t wait;
-       int done;
-       int ret;
-};
-
-static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
-{
-       wr_waitp->ret = 0;
-       wr_waitp->done = 0;
-       init_waitqueue_head(&wr_waitp->wait);
-}
-
 struct c4iw_resource {
        struct kfifo tpt_fifo;
        spinlock_t tpt_fifo_lock;
@@ -127,8 +113,11 @@ struct c4iw_rdev {
        struct c4iw_dev_ucontext uctx;
        struct gen_pool *pbl_pool;
        struct gen_pool *rqt_pool;
+       struct gen_pool *ocqp_pool;
        u32 flags;
        struct cxgb4_lld_info lldi;
+       unsigned long oc_mw_pa;
+       void __iomem *oc_mw_kva;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -141,6 +130,44 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
        return min((int)T4_MAX_NUM_STAG, (int)(rdev->lldi.vr->stag.size >> 5));
 }
 
+#define C4IW_WR_TO (10*HZ)
+
+struct c4iw_wr_wait {
+       wait_queue_head_t wait;
+       int done;
+       int ret;
+};
+
+static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
+{
+       wr_waitp->ret = 0;
+       wr_waitp->done = 0;
+       init_waitqueue_head(&wr_waitp->wait);
+}
+
+static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
+                                struct c4iw_wr_wait *wr_waitp,
+                                u32 hwtid, u32 qpid,
+                                const char *func)
+{
+       unsigned to = C4IW_WR_TO;
+       do {
+
+               wait_event_timeout(wr_waitp->wait, wr_waitp->done, to);
+               if (!wr_waitp->done) {
+                       printk(KERN_ERR MOD "%s - Device %s not responding - "
+                              "tid %u qpid %u\n", func,
+                              pci_name(rdev->lldi.pdev), hwtid, qpid);
+                       to = to << 2;
+               }
+       } while (!wr_waitp->done);
+       if (wr_waitp->ret)
+               printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n",
+                      pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
+       return wr_waitp->ret;
+}
+
+
 struct c4iw_dev {
        struct ib_device ibdev;
        struct c4iw_rdev rdev;
@@ -327,6 +354,7 @@ struct c4iw_qp {
        struct c4iw_qp_attributes attr;
        struct t4_wq wq;
        spinlock_t lock;
+       struct mutex mutex;
        atomic_t refcnt;
        wait_queue_head_t wait;
        struct timer_list timer;
@@ -579,12 +607,10 @@ struct c4iw_ep_common {
        struct c4iw_dev *dev;
        enum c4iw_ep_state state;
        struct kref kref;
-       spinlock_t lock;
+       struct mutex mutex;
        struct sockaddr_in local_addr;
        struct sockaddr_in remote_addr;
-       wait_queue_head_t waitq;
-       int rpl_done;
-       int rpl_err;
+       struct c4iw_wr_wait wr_wait;
        unsigned long flags;
 };
 
@@ -654,8 +680,10 @@ int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid);
 int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_pblpool_create(struct c4iw_rdev *rdev);
 int c4iw_rqtpool_create(struct c4iw_rdev *rdev);
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev);
 void c4iw_pblpool_destroy(struct c4iw_rdev *rdev);
 void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev);
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev);
 void c4iw_destroy_resource(struct c4iw_resource *rscp);
 int c4iw_destroy_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_register_device(struct c4iw_dev *dev);
@@ -721,6 +749,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size);
 void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size);
 void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size);
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
 void c4iw_flush_hw_cq(struct t4_cq *cq);
 void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count);
index 269373a62f228edb347bae6750e2680050e8f30e..273ffe49525a5d3d1642a292730af15a388ad9da 100644 (file)
@@ -71,7 +71,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
                if (i == (num_wqe-1)) {
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
                                                    FW_WR_COMPL(1));
-                       req->wr.wr_lo = (__force __be64)&wr_wait;
+                       req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
                } else
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR));
                req->wr.wr_mid = cpu_to_be32(
@@ -103,14 +103,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
                len -= C4IW_MAX_INLINE_SIZE;
        }
 
-       wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-       if (!wr_wait.done) {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(rdev->lldi.pdev));
-               rdev->flags = T4_FATAL_ERROR;
-               ret = -EIO;
-       } else
-               ret = wr_wait.ret;
+       ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
        return ret;
 }
 
index 8f645c83a125c1c9a1e3ad3ff400c3d90a0fec3a..f66dd8bf5128a0fd4f1a0acf686b4e4815813384 100644 (file)
@@ -54,9 +54,9 @@
 
 #include "iw_cxgb4.h"
 
-static int fastreg_support;
+static int fastreg_support = 1;
 module_param(fastreg_support, int, 0644);
-MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=0)");
+MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=1)");
 
 static int c4iw_modify_port(struct ib_device *ibdev,
                            u8 port, int port_modify_mask,
@@ -149,19 +149,28 @@ static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
        addr = mm->addr;
        kfree(mm);
 
-       if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
-           (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
-                      pci_resource_len(rdev->lldi.pdev, 2)))) {
+       if ((addr >= pci_resource_start(rdev->lldi.pdev, 0)) &&
+           (addr < (pci_resource_start(rdev->lldi.pdev, 0) +
+                   pci_resource_len(rdev->lldi.pdev, 0)))) {
 
                /*
-                * Map T4 DB register.
+                * MA_SYNC register...
                 */
-               if (vma->vm_flags & VM_READ)
-                       return -EPERM;
-
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-               vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
-               vma->vm_flags &= ~VM_MAYREAD;
+               ret = io_remap_pfn_range(vma, vma->vm_start,
+                                        addr >> PAGE_SHIFT,
+                                        len, vma->vm_page_prot);
+       } else if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
+                  (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
+                   pci_resource_len(rdev->lldi.pdev, 2)))) {
+
+               /*
+                * Map user DB or OCQP memory...
+                */
+               if (addr >= rdev->oc_mw_pa)
+                       vma->vm_page_prot = t4_pgprot_wc(vma->vm_page_prot);
+               else
+                       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                ret = io_remap_pfn_range(vma, vma->vm_start,
                                         addr >> PAGE_SHIFT,
                                         len, vma->vm_page_prot);
@@ -382,7 +391,17 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
 static int c4iw_get_mib(struct ib_device *ibdev,
                        union rdma_protocol_stats *stats)
 {
-       return -ENOSYS;
+       struct tp_tcp_stats v4, v6;
+       struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev);
+
+       cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
+       memset(stats, 0, sizeof *stats);
+       stats->iw.tcpInSegs = v4.tcpInSegs + v6.tcpInSegs;
+       stats->iw.tcpOutSegs = v4.tcpOutSegs + v6.tcpOutSegs;
+       stats->iw.tcpRetransSegs = v4.tcpRetransSegs + v6.tcpRetransSegs;
+       stats->iw.tcpOutRsts = v4.tcpOutRsts + v6.tcpOutSegs;
+
+       return 0;
 }
 
 static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
@@ -472,6 +491,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
        dev->ibdev.post_send = c4iw_post_send;
        dev->ibdev.post_recv = c4iw_post_receive;
        dev->ibdev.get_protocol_stats = c4iw_get_mib;
+       dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
 
        dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
        if (!dev->ibdev.iwcm)
index 93f6e5bf0ec57ccc53d3ad68a2cde7103eda5931..057cb2505ea12ce00431ba3dd2f86fae59da12ea 100644 (file)
  */
 #include "iw_cxgb4.h"
 
+static int ocqp_support;
+module_param(ocqp_support, int, 0644);
+MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=0)");
+
+static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
+{
+       unsigned long flag;
+       spin_lock_irqsave(&qhp->lock, flag);
+       qhp->attr.state = state;
+       spin_unlock_irqrestore(&qhp->lock, flag);
+}
+
+static void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+       c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize);
+}
+
+static void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+       dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue,
+                         pci_unmap_addr(sq, mapping));
+}
+
+static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+       if (t4_sq_onchip(sq))
+               dealloc_oc_sq(rdev, sq);
+       else
+               dealloc_host_sq(rdev, sq);
+}
+
+static int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+       if (!ocqp_support || !t4_ocqp_supported())
+               return -ENOSYS;
+       sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
+       if (!sq->dma_addr)
+               return -ENOMEM;
+       sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr -
+                       rdev->lldi.vr->ocq.start;
+       sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr -
+                                           rdev->lldi.vr->ocq.start);
+       sq->flags |= T4_SQ_ONCHIP;
+       return 0;
+}
+
+static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+       sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
+                                      &(sq->dma_addr), GFP_KERNEL);
+       if (!sq->queue)
+               return -ENOMEM;
+       sq->phys_addr = virt_to_phys(sq->queue);
+       pci_unmap_addr_set(sq, mapping, sq->dma_addr);
+       return 0;
+}
+
 static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                      struct c4iw_dev_ucontext *uctx)
 {
@@ -41,9 +98,7 @@ static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        dma_free_coherent(&(rdev->lldi.pdev->dev),
                          wq->rq.memsize, wq->rq.queue,
                          dma_unmap_addr(&wq->rq, mapping));
-       dma_free_coherent(&(rdev->lldi.pdev->dev),
-                         wq->sq.memsize, wq->sq.queue,
-                         dma_unmap_addr(&wq->sq, mapping));
+       dealloc_sq(rdev, &wq->sq);
        c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
        kfree(wq->rq.sw_rq);
        kfree(wq->sq.sw_sq);
@@ -93,11 +148,12 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        if (!wq->rq.rqt_hwaddr)
                goto err4;
 
-       wq->sq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
-                                         wq->sq.memsize, &(wq->sq.dma_addr),
-                                         GFP_KERNEL);
-       if (!wq->sq.queue)
-               goto err5;
+       if (user) {
+               if (alloc_oc_sq(rdev, &wq->sq) && alloc_host_sq(rdev, &wq->sq))
+                       goto err5;
+       } else
+               if (alloc_host_sq(rdev, &wq->sq))
+                       goto err5;
        memset(wq->sq.queue, 0, wq->sq.memsize);
        dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
 
@@ -144,7 +200,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                        V_FW_RI_RES_WR_NRES(2) |
                        FW_WR_COMPL(1));
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-       res_wr->cookie = (u64)&wr_wait;
+       res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
        res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
        res->u.sqrq.op = FW_RI_RES_OP_WRITE;
@@ -158,6 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_HOSTFCMODE(0) |  /* no host cidx updates */
                V_FW_RI_RES_WR_CPRIO(0) |       /* don't keep in chip cache */
                V_FW_RI_RES_WR_PCIECHN(0) |     /* set by uP at ri_init time */
+               t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 |
                V_FW_RI_RES_WR_IQID(scq->cqid));
        res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
                V_FW_RI_RES_WR_DCAEN(0) |
@@ -198,14 +255,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        ret = c4iw_ofld_send(rdev, skb);
        if (ret)
                goto err7;
-       wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-       if (!wr_wait.done) {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(rdev->lldi.pdev));
-               rdev->flags = T4_FATAL_ERROR;
-               ret = -EIO;
-       } else
-               ret = wr_wait.ret;
+       ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, wq->sq.qid, __func__);
        if (ret)
                goto err7;
 
@@ -219,9 +269,7 @@ err7:
                          wq->rq.memsize, wq->rq.queue,
                          dma_unmap_addr(&wq->rq, mapping));
 err6:
-       dma_free_coherent(&(rdev->lldi.pdev->dev),
-                         wq->sq.memsize, wq->sq.queue,
-                         dma_unmap_addr(&wq->sq, mapping));
+       dealloc_sq(rdev, &wq->sq);
 err5:
        c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
 err4:
@@ -263,6 +311,9 @@ static int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp,
                        rem -= len;
                }
        }
+       len = roundup(plen + sizeof *immdp, 16) - (plen + sizeof *immdp);
+       if (len)
+               memset(dstp, 0, len);
        immdp->op = FW_RI_DATA_IMMD;
        immdp->r1 = 0;
        immdp->r2 = 0;
@@ -292,6 +343,7 @@ static int build_isgl(__be64 *queue_start, __be64 *queue_end,
                if (++flitp == queue_end)
                        flitp = queue_start;
        }
+       *flitp = (__force __be64)0;
        isglp->op = FW_RI_DATA_ISGL;
        isglp->r1 = 0;
        isglp->nsge = cpu_to_be16(num_sge);
@@ -453,13 +505,15 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
        return 0;
 }
 
-static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
+                        struct ib_send_wr *wr, u8 *len16)
 {
 
        struct fw_ri_immd *imdp;
        __be64 *p;
        int i;
        int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
+       int rem;
 
        if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH)
                return -EINVAL;
@@ -474,32 +528,28 @@ static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
        wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
        wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
                                        0xffffffff);
-       if (pbllen > T4_MAX_FR_IMMD) {
-               struct c4iw_fr_page_list *c4pl =
-                               to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
-               struct fw_ri_dsgl *sglp;
-
-               sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
-               sglp->op = FW_RI_DATA_DSGL;
-               sglp->r1 = 0;
-               sglp->nsge = cpu_to_be16(1);
-               sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
-               sglp->len0 = cpu_to_be32(pbllen);
-
-               *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *sglp, 16);
-       } else {
-               imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
-               imdp->op = FW_RI_DATA_IMMD;
-               imdp->r1 = 0;
-               imdp->r2 = 0;
-               imdp->immdlen = cpu_to_be32(pbllen);
-               p = (__be64 *)(imdp + 1);
-               for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++)
-                       *p = cpu_to_be64(
-                               (u64)wr->wr.fast_reg.page_list->page_list[i]);
-               *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen,
-                                     16);
+       WARN_ON(pbllen > T4_MAX_FR_IMMD);
+       imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+       imdp->op = FW_RI_DATA_IMMD;
+       imdp->r1 = 0;
+       imdp->r2 = 0;
+       imdp->immdlen = cpu_to_be32(pbllen);
+       p = (__be64 *)(imdp + 1);
+       rem = pbllen;
+       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+               *p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);
+               rem -= sizeof *p;
+               if (++p == (__be64 *)&sq->queue[sq->size])
+                       p = (__be64 *)sq->queue;
        }
+       BUG_ON(rem < 0);
+       while (rem) {
+               *p = 0;
+               rem -= sizeof *p;
+               if (++p == (__be64 *)&sq->queue[sq->size])
+                       p = (__be64 *)sq->queue;
+       }
+       *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
        return 0;
 }
 
@@ -587,7 +637,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        fw_opcode = FW_RI_RDMA_READ_WR;
                        swsqe->opcode = FW_RI_READ_REQ;
                        if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)
-                               fw_flags |= FW_RI_RDMA_READ_INVALIDATE;
+                               fw_flags = FW_RI_RDMA_READ_INVALIDATE;
                        else
                                fw_flags = 0;
                        err = build_rdma_read(wqe, wr, &len16);
@@ -600,7 +650,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                case IB_WR_FAST_REG_MR:
                        fw_opcode = FW_RI_FR_NSMR_WR;
                        swsqe->opcode = FW_RI_FAST_REGISTER;
-                       err = build_fastreg(wqe, wr, &len16);
+                       err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16);
                        break;
                case IB_WR_LOCAL_INV:
                        if (wr->send_flags & IB_SEND_FENCE)
@@ -905,46 +955,38 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
  * Assumes qhp lock is held.
  */
 static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
-                      struct c4iw_cq *schp, unsigned long *flag)
+                      struct c4iw_cq *schp)
 {
        int count;
        int flushed;
+       unsigned long flag;
 
        PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
-       /* take a ref on the qhp since we must release the lock */
-       atomic_inc(&qhp->refcnt);
-       spin_unlock_irqrestore(&qhp->lock, *flag);
 
        /* locking hierarchy: cq lock first, then qp lock. */
-       spin_lock_irqsave(&rchp->lock, *flag);
+       spin_lock_irqsave(&rchp->lock, flag);
        spin_lock(&qhp->lock);
        c4iw_flush_hw_cq(&rchp->cq);
        c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
        flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
        spin_unlock(&qhp->lock);
-       spin_unlock_irqrestore(&rchp->lock, *flag);
+       spin_unlock_irqrestore(&rchp->lock, flag);
        if (flushed)
                (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
 
        /* locking hierarchy: cq lock first, then qp lock. */
-       spin_lock_irqsave(&schp->lock, *flag);
+       spin_lock_irqsave(&schp->lock, flag);
        spin_lock(&qhp->lock);
        c4iw_flush_hw_cq(&schp->cq);
        c4iw_count_scqes(&schp->cq, &qhp->wq, &count);
        flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
        spin_unlock(&qhp->lock);
-       spin_unlock_irqrestore(&schp->lock, *flag);
+       spin_unlock_irqrestore(&schp->lock, flag);
        if (flushed)
                (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
-
-       /* deref */
-       if (atomic_dec_and_test(&qhp->refcnt))
-               wake_up(&qhp->wait);
-
-       spin_lock_irqsave(&qhp->lock, *flag);
 }
 
-static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
+static void flush_qp(struct c4iw_qp *qhp)
 {
        struct c4iw_cq *rchp, *schp;
 
@@ -958,7 +1000,7 @@ static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
                        t4_set_cq_in_error(&schp->cq);
                return;
        }
-       __flush_qp(qhp, rchp, schp, flag);
+       __flush_qp(qhp, rchp, schp);
 }
 
 static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
@@ -966,7 +1008,6 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
 {
        struct fw_ri_wr *wqe;
        int ret;
-       struct c4iw_wr_wait wr_wait;
        struct sk_buff *skb;
 
        PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -985,28 +1026,16 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        wqe->flowid_len16 = cpu_to_be32(
                FW_WR_FLOWID(ep->hwtid) |
                FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
-       wqe->cookie = (u64)&wr_wait;
+       wqe->cookie = (unsigned long) &ep->com.wr_wait;
 
        wqe->u.fini.type = FW_RI_TYPE_FINI;
-       c4iw_init_wr_wait(&wr_wait);
+       c4iw_init_wr_wait(&ep->com.wr_wait);
        ret = c4iw_ofld_send(&rhp->rdev, skb);
        if (ret)
                goto out;
 
-       wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-       if (!wr_wait.done) {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(rhp->rdev.lldi.pdev));
-               rhp->rdev.flags = T4_FATAL_ERROR;
-               ret = -EIO;
-       } else {
-               ret = wr_wait.ret;
-               if (ret)
-                       printk(KERN_WARNING MOD
-                              "%s: Abnormal close qpid %d ret %u\n",
-                              pci_name(rhp->rdev.lldi.pdev), qhp->wq.sq.qid,
-                              ret);
-       }
+       ret = c4iw_wait_for_reply(&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid,
+                            qhp->wq.sq.qid, __func__);
 out:
        PDBG("%s ret %d\n", __func__, ret);
        return ret;
@@ -1040,7 +1069,6 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
 {
        struct fw_ri_wr *wqe;
        int ret;
-       struct c4iw_wr_wait wr_wait;
        struct sk_buff *skb;
 
        PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -1060,7 +1088,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
                FW_WR_FLOWID(qhp->ep->hwtid) |
                FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
 
-       wqe->cookie = (u64)&wr_wait;
+       wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
 
        wqe->u.init.type = FW_RI_TYPE_INIT;
        wqe->u.init.mpareqbit_p2ptype =
@@ -1097,19 +1125,13 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
        if (qhp->attr.mpa_attr.initiator)
                build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
 
-       c4iw_init_wr_wait(&wr_wait);
+       c4iw_init_wr_wait(&qhp->ep->com.wr_wait);
        ret = c4iw_ofld_send(&rhp->rdev, skb);
        if (ret)
                goto out;
 
-       wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-       if (!wr_wait.done) {
-               printk(KERN_ERR MOD "Device %s not responding!\n",
-                      pci_name(rhp->rdev.lldi.pdev));
-               rhp->rdev.flags = T4_FATAL_ERROR;
-               ret = -EIO;
-       } else
-               ret = wr_wait.ret;
+       ret = c4iw_wait_for_reply(&rhp->rdev, &qhp->ep->com.wr_wait,
+                                 qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
 out:
        PDBG("%s ret %d\n", __func__, ret);
        return ret;
@@ -1122,7 +1144,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
 {
        int ret = 0;
        struct c4iw_qp_attributes newattr = qhp->attr;
-       unsigned long flag;
        int disconnect = 0;
        int terminate = 0;
        int abort = 0;
@@ -1133,7 +1154,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
             qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
             (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
 
-       spin_lock_irqsave(&qhp->lock, flag);
+       mutex_lock(&qhp->mutex);
 
        /* Process attr changes if in IDLE */
        if (mask & C4IW_QP_ATTR_VALID_MODIFY) {
@@ -1184,7 +1205,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                        qhp->attr.mpa_attr = attrs->mpa_attr;
                        qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
                        qhp->ep = qhp->attr.llp_stream_handle;
-                       qhp->attr.state = C4IW_QP_STATE_RTS;
+                       set_state(qhp, C4IW_QP_STATE_RTS);
 
                        /*
                         * Ref the endpoint here and deref when we
@@ -1193,15 +1214,13 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                         * transition.
                         */
                        c4iw_get_ep(&qhp->ep->com);
-                       spin_unlock_irqrestore(&qhp->lock, flag);
                        ret = rdma_init(rhp, qhp);
-                       spin_lock_irqsave(&qhp->lock, flag);
                        if (ret)
                                goto err;
                        break;
                case C4IW_QP_STATE_ERROR:
-                       qhp->attr.state = C4IW_QP_STATE_ERROR;
-                       flush_qp(qhp, &flag);
+                       set_state(qhp, C4IW_QP_STATE_ERROR);
+                       flush_qp(qhp);
                        break;
                default:
                        ret = -EINVAL;
@@ -1212,38 +1231,38 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                switch (attrs->next_state) {
                case C4IW_QP_STATE_CLOSING:
                        BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
-                       qhp->attr.state = C4IW_QP_STATE_CLOSING;
+                       set_state(qhp, C4IW_QP_STATE_CLOSING);
                        ep = qhp->ep;
                        if (!internal) {
                                abort = 0;
                                disconnect = 1;
-                               c4iw_get_ep(&ep->com);
+                               c4iw_get_ep(&qhp->ep->com);
                        }
-                       spin_unlock_irqrestore(&qhp->lock, flag);
                        ret = rdma_fini(rhp, qhp, ep);
-                       spin_lock_irqsave(&qhp->lock, flag);
                        if (ret) {
-                               c4iw_get_ep(&ep->com);
+                               if (internal)
+                                       c4iw_get_ep(&qhp->ep->com);
                                disconnect = abort = 1;
                                goto err;
                        }
                        break;
                case C4IW_QP_STATE_TERMINATE:
-                       qhp->attr.state = C4IW_QP_STATE_TERMINATE;
+                       set_state(qhp, C4IW_QP_STATE_TERMINATE);
                        if (qhp->ibqp.uobject)
                                t4_set_wq_in_error(&qhp->wq);
                        ep = qhp->ep;
-                       c4iw_get_ep(&ep->com);
-                       terminate = 1;
+                       if (!internal)
+                               terminate = 1;
                        disconnect = 1;
+                       c4iw_get_ep(&qhp->ep->com);
                        break;
                case C4IW_QP_STATE_ERROR:
-                       qhp->attr.state = C4IW_QP_STATE_ERROR;
+                       set_state(qhp, C4IW_QP_STATE_ERROR);
                        if (!internal) {
                                abort = 1;
                                disconnect = 1;
                                ep = qhp->ep;
-                               c4iw_get_ep(&ep->com);
+                               c4iw_get_ep(&qhp->ep->com);
                        }
                        goto err;
                        break;
@@ -1259,8 +1278,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                }
                switch (attrs->next_state) {
                case C4IW_QP_STATE_IDLE:
-                       flush_qp(qhp, &flag);
-                       qhp->attr.state = C4IW_QP_STATE_IDLE;
+                       flush_qp(qhp);
+                       set_state(qhp, C4IW_QP_STATE_IDLE);
                        qhp->attr.llp_stream_handle = NULL;
                        c4iw_put_ep(&qhp->ep->com);
                        qhp->ep = NULL;
@@ -1282,7 +1301,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                        ret = -EINVAL;
                        goto out;
                }
-               qhp->attr.state = C4IW_QP_STATE_IDLE;
+               set_state(qhp, C4IW_QP_STATE_IDLE);
                break;
        case C4IW_QP_STATE_TERMINATE:
                if (!internal) {
@@ -1305,15 +1324,16 @@ err:
 
        /* disassociate the LLP connection */
        qhp->attr.llp_stream_handle = NULL;
-       ep = qhp->ep;
+       if (!ep)
+               ep = qhp->ep;
        qhp->ep = NULL;
-       qhp->attr.state = C4IW_QP_STATE_ERROR;
+       set_state(qhp, C4IW_QP_STATE_ERROR);
        free = 1;
        wake_up(&qhp->wait);
        BUG_ON(!ep);
-       flush_qp(qhp, &flag);
+       flush_qp(qhp);
 out:
-       spin_unlock_irqrestore(&qhp->lock, flag);
+       mutex_unlock(&qhp->mutex);
 
        if (terminate)
                post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL);
@@ -1335,7 +1355,6 @@ out:
         */
        if (free)
                c4iw_put_ep(&ep->com);
-
        PDBG("%s exit state %d\n", __func__, qhp->attr.state);
        return ret;
 }
@@ -1380,7 +1399,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        int sqsize, rqsize;
        struct c4iw_ucontext *ucontext;
        int ret;
-       struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4;
+       struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4, *mm5 = NULL;
 
        PDBG("%s ib_pd %p\n", __func__, pd);
 
@@ -1450,6 +1469,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        qhp->attr.max_ord = 1;
        qhp->attr.max_ird = 1;
        spin_lock_init(&qhp->lock);
+       mutex_init(&qhp->mutex);
        init_waitqueue_head(&qhp->wait);
        atomic_set(&qhp->refcnt, 1);
 
@@ -1478,7 +1498,15 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                        ret = -ENOMEM;
                        goto err6;
                }
-
+               if (t4_sq_onchip(&qhp->wq.sq)) {
+                       mm5 = kmalloc(sizeof *mm5, GFP_KERNEL);
+                       if (!mm5) {
+                               ret = -ENOMEM;
+                               goto err7;
+                       }
+                       uresp.flags = C4IW_QPF_ONCHIP;
+               } else
+                       uresp.flags = 0;
                uresp.qid_mask = rhp->rdev.qpmask;
                uresp.sqid = qhp->wq.sq.qid;
                uresp.sq_size = qhp->wq.sq.size;
@@ -1487,6 +1515,10 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                uresp.rq_size = qhp->wq.rq.size;
                uresp.rq_memsize = qhp->wq.rq.memsize;
                spin_lock(&ucontext->mmap_lock);
+               if (mm5) {
+                       uresp.ma_sync_key = ucontext->key;
+                       ucontext->key += PAGE_SIZE;
+               }
                uresp.sq_key = ucontext->key;
                ucontext->key += PAGE_SIZE;
                uresp.rq_key = ucontext->key;
@@ -1498,9 +1530,9 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                spin_unlock(&ucontext->mmap_lock);
                ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
                if (ret)
-                       goto err7;
+                       goto err8;
                mm1->key = uresp.sq_key;
-               mm1->addr = virt_to_phys(qhp->wq.sq.queue);
+               mm1->addr = qhp->wq.sq.phys_addr;
                mm1->len = PAGE_ALIGN(qhp->wq.sq.memsize);
                insert_mmap(ucontext, mm1);
                mm2->key = uresp.rq_key;
@@ -1515,6 +1547,13 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                mm4->addr = qhp->wq.rq.udb;
                mm4->len = PAGE_SIZE;
                insert_mmap(ucontext, mm4);
+               if (mm5) {
+                       mm5->key = uresp.ma_sync_key;
+                       mm5->addr = (pci_resource_start(rhp->rdev.lldi.pdev, 0)
+                                   + A_PCIE_MA_SYNC) & PAGE_MASK;
+                       mm5->len = PAGE_SIZE;
+                       insert_mmap(ucontext, mm5);
+               }
        }
        qhp->ibqp.qp_num = qhp->wq.sq.qid;
        init_timer(&(qhp->timer));
@@ -1522,6 +1561,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
             __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
             qhp->wq.sq.qid);
        return &qhp->ibqp;
+err8:
+       kfree(mm5);
 err7:
        kfree(mm4);
 err6:
index 83b23dfa250dea9171ef44a9e37fa3fc7efe3698..4fb50d58b4934a18fb298e3ef542a7c2f424dab5 100644 (file)
@@ -311,6 +311,9 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
 {
        unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
        PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+       if (!addr && printk_ratelimit())
+               printk(KERN_WARNING MOD "%s: Out of PBL memory\n",
+                      pci_name(rdev->lldi.pdev));
        return (u32)addr;
 }
 
@@ -370,6 +373,9 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
 {
        unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
        PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
+       if (!addr && printk_ratelimit())
+               printk(KERN_WARNING MOD "%s: Out of RQT memory\n",
+                      pci_name(rdev->lldi.pdev));
        return (u32)addr;
 }
 
@@ -416,3 +422,59 @@ void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
 {
        gen_pool_destroy(rdev->rqt_pool);
 }
+
+/*
+ * On-Chip QP Memory.
+ */
+#define MIN_OCQP_SHIFT 12      /* 4KB == min ocqp size */
+
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
+{
+       unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
+       PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+       return (u32)addr;
+}
+
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+{
+       PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+       gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
+}
+
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev)
+{
+       unsigned start, chunk, top;
+
+       rdev->ocqp_pool = gen_pool_create(MIN_OCQP_SHIFT, -1);
+       if (!rdev->ocqp_pool)
+               return -ENOMEM;
+
+       start = rdev->lldi.vr->ocq.start;
+       chunk = rdev->lldi.vr->ocq.size;
+       top = start + chunk;
+
+       while (start < top) {
+               chunk = min(top - start + 1, chunk);
+               if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
+                       PDBG("%s failed to add OCQP chunk (%x/%x)\n",
+                            __func__, start, chunk);
+                       if (chunk <= 1024 << MIN_OCQP_SHIFT) {
+                               printk(KERN_WARNING MOD
+                                      "Failed to add all OCQP chunks (%x/%x)\n",
+                                      start, top - start);
+                               return 0;
+                       }
+                       chunk >>= 1;
+               } else {
+                       PDBG("%s added OCQP chunk (%x/%x)\n",
+                            __func__, start, chunk);
+                       start += chunk;
+               }
+       }
+       return 0;
+}
+
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev)
+{
+       gen_pool_destroy(rdev->ocqp_pool);
+}
index 24f369046ef3cc772a84ca54082b8b8d945916f8..70004425d695b0d765a3305406dc3ac5c0970d44 100644 (file)
@@ -52,6 +52,7 @@
 #define T4_STAG_UNSET 0xffffffff
 #define T4_FW_MAJ 0
 #define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1)
+#define A_PCIE_MA_SYNC 0x30b4
 
 struct t4_status_page {
        __be32 rsvd1;   /* flit 0 - hw owns */
@@ -65,7 +66,7 @@ struct t4_status_page {
 
 #define T4_EQ_ENTRY_SIZE 64
 
-#define T4_SQ_NUM_SLOTS 4
+#define T4_SQ_NUM_SLOTS 5
 #define T4_SQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_SQ_NUM_SLOTS)
 #define T4_MAX_SEND_SGE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
                        sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
@@ -78,7 +79,7 @@ struct t4_status_page {
                        sizeof(struct fw_ri_rdma_write_wr) - \
                        sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
 #define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
-                       sizeof(struct fw_ri_immd)))
+                       sizeof(struct fw_ri_immd)) & ~31UL)
 #define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
 
 #define T4_RQ_NUM_SLOTS 2
@@ -266,10 +267,36 @@ struct t4_swsqe {
        u16                     idx;
 };
 
+static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
+{
+#if defined(__i386__) || defined(__x86_64__)
+       return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+       return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
+                       ~(pgprot_t)_PAGE_GUARDED);
+#else
+       return pgprot_noncached(prot);
+#endif
+}
+
+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+enum {
+       T4_SQ_ONCHIP = (1<<0),
+};
+
 struct t4_sq {
        union t4_wr *queue;
        dma_addr_t dma_addr;
        DEFINE_DMA_UNMAP_ADDR(mapping);
+       unsigned long phys_addr;
        struct t4_swsqe *sw_sq;
        struct t4_swsqe *oldest_read;
        u64 udb;
@@ -280,6 +307,7 @@ struct t4_sq {
        u16 cidx;
        u16 pidx;
        u16 wq_pidx;
+       u16 flags;
 };
 
 struct t4_swrqe {
@@ -350,6 +378,11 @@ static inline void t4_rq_consume(struct t4_wq *wq)
                wq->rq.cidx = 0;
 }
 
+static inline int t4_sq_onchip(struct t4_sq *sq)
+{
+       return sq->flags & T4_SQ_ONCHIP;
+}
+
 static inline int t4_sq_empty(struct t4_wq *wq)
 {
        return wq->sq.in_use == 0;
@@ -396,30 +429,27 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc)
 
 static inline int t4_wq_in_error(struct t4_wq *wq)
 {
-       return wq->sq.queue[wq->sq.size].status.qp_err;
+       return wq->rq.queue[wq->rq.size].status.qp_err;
 }
 
 static inline void t4_set_wq_in_error(struct t4_wq *wq)
 {
-       wq->sq.queue[wq->sq.size].status.qp_err = 1;
        wq->rq.queue[wq->rq.size].status.qp_err = 1;
 }
 
 static inline void t4_disable_wq_db(struct t4_wq *wq)
 {
-       wq->sq.queue[wq->sq.size].status.db_off = 1;
        wq->rq.queue[wq->rq.size].status.db_off = 1;
 }
 
 static inline void t4_enable_wq_db(struct t4_wq *wq)
 {
-       wq->sq.queue[wq->sq.size].status.db_off = 0;
        wq->rq.queue[wq->rq.size].status.db_off = 0;
 }
 
 static inline int t4_wq_db_enabled(struct t4_wq *wq)
 {
-       return !wq->sq.queue[wq->sq.size].status.db_off;
+       return !wq->rq.queue[wq->rq.size].status.db_off;
 }
 
 struct t4_cq {
index ed6414abde024c322585530bbb71b0b45d44c433..e6669d54770e8ce034541f1c5e7d314d8274070f 100644 (file)
@@ -50,7 +50,13 @@ struct c4iw_create_cq_resp {
        __u32 qid_mask;
 };
 
+
+enum {
+       C4IW_QPF_ONCHIP = (1<<0)
+};
+
 struct c4iw_create_qp_resp {
+       __u64 ma_sync_key;
        __u64 sq_key;
        __u64 rq_key;
        __u64 sq_db_gts_key;
@@ -62,5 +68,6 @@ struct c4iw_create_qp_resp {
        __u32 sq_size;
        __u32 rq_size;
        __u32 qid_mask;
+       __u32 flags;
 };
 #endif
index 53f4cd4fc19a33d26da6e58d8fb0d4d5a41930e8..43cae84005f0a5bb7d80b440eb0e34e1e6a2500e 100644 (file)
@@ -171,7 +171,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
                }
 
                ret = ehca_reg_maxmr(shca, e_maxmr,
-                                    (void *)ehca_map_vaddr((void *)KERNELBASE),
+                                    (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)),
                                     mr_access_flags, e_pd,
                                     &e_maxmr->ib.ib_mr.lkey,
                                     &e_maxmr->ib.ib_mr.rkey);
@@ -1636,7 +1636,7 @@ int ehca_reg_internal_maxmr(
 
        /* register internal max-MR on HCA */
        size_maxmr = ehca_mr_len;
-       iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE);
+       iova_start = (u64 *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START));
        ib_pbuf.addr = 0;
        ib_pbuf.size = size_maxmr;
        num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
@@ -2209,7 +2209,7 @@ int ehca_mr_is_maxmr(u64 size,
 {
        /* a MR is treated as max-MR only if it fits following: */
        if ((size == ehca_mr_len) &&
-           (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) {
+           (iova_start == (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)))) {
                ehca_gen_dbg("this is a max-MR");
                return 1;
        } else
index fa3df82681dfb9b695232bca88434d17948b4027..4496f2820c92d98197e3fcd69b4b938165215163 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \
+ccflags-y := -DIPATH_IDSTR='"QLogic kernel.org driver"' \
        -DIPATH_KERN_TYPE=0
 
 obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
index d13e72685dcfa17388c274a62df80f88f68b558f..12d5bf76302cc0eff403b5538607350f4e554e42 100644 (file)
@@ -57,6 +57,7 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
                goto bail;
        }
 
+       inode->i_ino = get_next_ino();
        inode->i_mode = mode;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        inode->i_private = data;
index 11a236f8d884a4902b6243139eddd6da6c98c76a..4b8f9c49397e2c23cd9471ad854936ce1af8ed46 100644 (file)
  * SOFTWARE.
  */
 
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+
 #include <linux/slab.h>
+#include <linux/inet.h>
+#include <linux/string.h>
 
 #include "mlx4_ib.h"
 
-struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
+                       u8 *mac, int *is_mcast, u8 port)
 {
-       struct mlx4_dev *dev = to_mdev(pd->device)->dev;
-       struct mlx4_ib_ah *ah;
+       struct in6_addr in6;
 
-       ah = kmalloc(sizeof *ah, GFP_ATOMIC);
-       if (!ah)
-               return ERR_PTR(-ENOMEM);
+       *is_mcast = 0;
 
-       memset(&ah->av, 0, sizeof ah->av);
+       memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6);
+       if (rdma_link_local_addr(&in6))
+               rdma_get_ll_mac(&in6, mac);
+       else if (rdma_is_multicast_addr(&in6)) {
+               rdma_get_mcast_mac(&in6, mac);
+               *is_mcast = 1;
+       } else
+               return -EINVAL;
 
-       ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
-       ah->av.g_slid  = ah_attr->src_path_bits;
-       ah->av.dlid    = cpu_to_be16(ah_attr->dlid);
-       if (ah_attr->static_rate) {
-               ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
-               while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
-                      !(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
-                       --ah->av.stat_rate;
-       }
-       ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+       return 0;
+}
+
+static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+                                 struct mlx4_ib_ah *ah)
+{
+       struct mlx4_dev *dev = to_mdev(pd->device)->dev;
+
+       ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+       ah->av.ib.g_slid  = ah_attr->src_path_bits;
        if (ah_attr->ah_flags & IB_AH_GRH) {
-               ah->av.g_slid   |= 0x80;
-               ah->av.gid_index = ah_attr->grh.sgid_index;
-               ah->av.hop_limit = ah_attr->grh.hop_limit;
-               ah->av.sl_tclass_flowlabel |=
+               ah->av.ib.g_slid   |= 0x80;
+               ah->av.ib.gid_index = ah_attr->grh.sgid_index;
+               ah->av.ib.hop_limit = ah_attr->grh.hop_limit;
+               ah->av.ib.sl_tclass_flowlabel |=
                        cpu_to_be32((ah_attr->grh.traffic_class << 20) |
                                    ah_attr->grh.flow_label);
-               memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
+               memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16);
+       }
+
+       ah->av.ib.dlid    = cpu_to_be16(ah_attr->dlid);
+       if (ah_attr->static_rate) {
+               ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+               while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+                      !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support))
+                       --ah->av.ib.stat_rate;
        }
+       ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
 
        return &ah->ibah;
 }
 
+static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+                                   struct mlx4_ib_ah *ah)
+{
+       struct mlx4_ib_dev *ibdev = to_mdev(pd->device);
+       struct mlx4_dev *dev = ibdev->dev;
+       union ib_gid sgid;
+       u8 mac[6];
+       int err;
+       int is_mcast;
+       u16 vlan_tag;
+
+       err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num);
+       if (err)
+               return ERR_PTR(err);
+
+       memcpy(ah->av.eth.mac, mac, 6);
+       err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid);
+       if (err)
+               return ERR_PTR(err);
+       vlan_tag = rdma_get_vlan_id(&sgid);
+       if (vlan_tag < 0x1000)
+               vlan_tag |= (ah_attr->sl & 7) << 13;
+       ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+       ah->av.eth.gid_index = ah_attr->grh.sgid_index;
+       ah->av.eth.vlan = cpu_to_be16(vlan_tag);
+       if (ah_attr->static_rate) {
+               ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+               while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+                      !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
+                       --ah->av.eth.stat_rate;
+       }
+
+       /*
+        * HW requires multicast LID so we just choose one.
+        */
+       if (is_mcast)
+               ah->av.ib.dlid = cpu_to_be16(0xc000);
+
+       memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
+       ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+
+       return &ah->ibah;
+}
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       struct mlx4_ib_ah *ah;
+       struct ib_ah *ret;
+
+       ah = kzalloc(sizeof *ah, GFP_ATOMIC);
+       if (!ah)
+               return ERR_PTR(-ENOMEM);
+
+       if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) {
+               if (!(ah_attr->ah_flags & IB_AH_GRH)) {
+                       ret = ERR_PTR(-EINVAL);
+               } else {
+                       /*
+                        * TBD: need to handle the case when we get
+                        * called in an atomic context and there we
+                        * might sleep.  We don't expect this
+                        * currently since we're working with link
+                        * local addresses which we can translate
+                        * without going to sleep.
+                        */
+                       ret = create_iboe_ah(pd, ah_attr, ah);
+               }
+
+               if (IS_ERR(ret))
+                       kfree(ah);
+
+               return ret;
+       } else
+               return create_ib_ah(pd, ah_attr, ah); /* never fails */
+}
+
 int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
 {
        struct mlx4_ib_ah *ah = to_mah(ibah);
+       enum rdma_link_layer ll;
 
        memset(ah_attr, 0, sizeof *ah_attr);
-       ah_attr->dlid          = be16_to_cpu(ah->av.dlid);
-       ah_attr->sl            = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
-       ah_attr->port_num      = be32_to_cpu(ah->av.port_pd) >> 24;
-       if (ah->av.stat_rate)
-               ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
-       ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
+       ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
+       ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
+       ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num);
+       ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0;
+       if (ah->av.ib.stat_rate)
+               ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET;
+       ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F;
 
        if (mlx4_ib_ah_grh_present(ah)) {
                ah_attr->ah_flags = IB_AH_GRH;
 
                ah_attr->grh.traffic_class =
-                       be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20;
+                       be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20;
                ah_attr->grh.flow_label =
-                       be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
-               ah_attr->grh.hop_limit  = ah->av.hop_limit;
-               ah_attr->grh.sgid_index = ah->av.gid_index;
-               memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
+                       be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff;
+               ah_attr->grh.hop_limit  = ah->av.ib.hop_limit;
+               ah_attr->grh.sgid_index = ah->av.ib.gid_index;
+               memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16);
        }
 
        return 0;
index f38d5b1189273d8fb320374d06c3c3f044d7cec2..c9a8dd63b9e24b757eb5813f18d8fda08a89d988 100644 (file)
@@ -311,19 +311,25 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
        struct ib_mad_agent *agent;
        int p, q;
        int ret;
+       enum rdma_link_layer ll;
 
-       for (p = 0; p < dev->num_ports; ++p)
+       for (p = 0; p < dev->num_ports; ++p) {
+               ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1);
                for (q = 0; q <= 1; ++q) {
-                       agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
-                                                     q ? IB_QPT_GSI : IB_QPT_SMI,
-                                                     NULL, 0, send_handler,
-                                                     NULL, NULL);
-                       if (IS_ERR(agent)) {
-                               ret = PTR_ERR(agent);
-                               goto err;
-                       }
-                       dev->send_agent[p][q] = agent;
+                       if (ll == IB_LINK_LAYER_INFINIBAND) {
+                               agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
+                                                             q ? IB_QPT_GSI : IB_QPT_SMI,
+                                                             NULL, 0, send_handler,
+                                                             NULL, NULL);
+                               if (IS_ERR(agent)) {
+                                       ret = PTR_ERR(agent);
+                                       goto err;
+                               }
+                               dev->send_agent[p][q] = agent;
+                       } else
+                               dev->send_agent[p][q] = NULL;
                }
+       }
 
        return 0;
 
@@ -344,8 +350,10 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
        for (p = 0; p < dev->num_ports; ++p) {
                for (q = 0; q <= 1; ++q) {
                        agent = dev->send_agent[p][q];
-                       dev->send_agent[p][q] = NULL;
-                       ib_unregister_mad_agent(agent);
+                       if (agent) {
+                               dev->send_agent[p][q] = NULL;
+                               ib_unregister_mad_agent(agent);
+                       }
                }
 
                if (dev->sm_ah[p])
index 4e94e360e43b42ed1f31685bdcb8b7387bc1b46e..bf3e20cd029859f2beb23e962fa2640e30faf44c 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
 
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/cmd.h>
@@ -58,6 +63,15 @@ static const char mlx4_ib_version[] =
        DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
+struct update_gid_work {
+       struct work_struct      work;
+       union ib_gid            gids[128];
+       struct mlx4_ib_dev     *dev;
+       int                     port;
+};
+
+static struct workqueue_struct *wq;
+
 static void init_query_mad(struct ib_smp *mad)
 {
        mad->base_version  = 1;
@@ -66,6 +80,8 @@ static void init_query_mad(struct ib_smp *mad)
        mad->method        = IB_MGMT_METHOD_GET;
 }
 
+static union ib_gid zgid;
+
 static int mlx4_ib_query_device(struct ib_device *ibdev,
                                struct ib_device_attr *props)
 {
@@ -135,7 +151,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
        props->max_srq             = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs;
        props->max_srq_wr          = dev->dev->caps.max_srq_wqes - 1;
        props->max_srq_sge         = dev->dev->caps.max_srq_sge;
-       props->max_fast_reg_page_list_len = PAGE_SIZE / sizeof (u64);
+       props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES;
        props->local_ca_ack_delay  = dev->dev->caps.local_ca_ack_delay;
        props->atomic_cap          = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
                IB_ATOMIC_HCA : IB_ATOMIC_NONE;
@@ -154,28 +170,19 @@ out:
        return err;
 }
 
-static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
-                             struct ib_port_attr *props)
+static enum rdma_link_layer
+mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num)
 {
-       struct ib_smp *in_mad  = NULL;
-       struct ib_smp *out_mad = NULL;
-       int err = -ENOMEM;
-
-       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
-       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
-       if (!in_mad || !out_mad)
-               goto out;
-
-       memset(props, 0, sizeof *props);
-
-       init_query_mad(in_mad);
-       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
-       in_mad->attr_mod = cpu_to_be32(port);
+       struct mlx4_dev *dev = to_mdev(device)->dev;
 
-       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
-       if (err)
-               goto out;
+       return dev->caps.port_mask & (1 << (port_num - 1)) ?
+               IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
+}
 
+static int ib_link_query_port(struct ib_device *ibdev, u8 port,
+                             struct ib_port_attr *props,
+                             struct ib_smp *out_mad)
+{
        props->lid              = be16_to_cpup((__be16 *) (out_mad->data + 16));
        props->lmc              = out_mad->data[34] & 0x7;
        props->sm_lid           = be16_to_cpup((__be16 *) (out_mad->data + 18));
@@ -196,6 +203,80 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
        props->max_vl_num       = out_mad->data[37] >> 4;
        props->init_type_reply  = out_mad->data[41] >> 4;
 
+       return 0;
+}
+
+static u8 state_to_phys_state(enum ib_port_state state)
+{
+       return state == IB_PORT_ACTIVE ? 5 : 3;
+}
+
+static int eth_link_query_port(struct ib_device *ibdev, u8 port,
+                              struct ib_port_attr *props,
+                              struct ib_smp *out_mad)
+{
+       struct mlx4_ib_iboe *iboe = &to_mdev(ibdev)->iboe;
+       struct net_device *ndev;
+       enum ib_mtu tmp;
+
+       props->active_width     = IB_WIDTH_4X;
+       props->active_speed     = 4;
+       props->port_cap_flags   = IB_PORT_CM_SUP;
+       props->gid_tbl_len      = to_mdev(ibdev)->dev->caps.gid_table_len[port];
+       props->max_msg_sz       = to_mdev(ibdev)->dev->caps.max_msg_sz;
+       props->pkey_tbl_len     = 1;
+       props->bad_pkey_cntr    = be16_to_cpup((__be16 *) (out_mad->data + 46));
+       props->qkey_viol_cntr   = be16_to_cpup((__be16 *) (out_mad->data + 48));
+       props->max_mtu          = IB_MTU_2048;
+       props->subnet_timeout   = 0;
+       props->max_vl_num       = out_mad->data[37] >> 4;
+       props->init_type_reply  = 0;
+       props->state            = IB_PORT_DOWN;
+       props->phys_state       = state_to_phys_state(props->state);
+       props->active_mtu       = IB_MTU_256;
+       spin_lock(&iboe->lock);
+       ndev = iboe->netdevs[port - 1];
+       if (!ndev)
+               goto out;
+
+       tmp = iboe_get_mtu(ndev->mtu);
+       props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
+
+       props->state            = netif_running(ndev) &&  netif_oper_up(ndev) ?
+                                       IB_PORT_ACTIVE : IB_PORT_DOWN;
+       props->phys_state       = state_to_phys_state(props->state);
+
+out:
+       spin_unlock(&iboe->lock);
+       return 0;
+}
+
+static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
+                             struct ib_port_attr *props)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       memset(props, 0, sizeof *props);
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ?
+               ib_link_query_port(ibdev, port, props, out_mad) :
+               eth_link_query_port(ibdev, port, props, out_mad);
+
 out:
        kfree(in_mad);
        kfree(out_mad);
@@ -203,8 +284,8 @@ out:
        return err;
 }
 
-static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
-                            union ib_gid *gid)
+static int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+                              union ib_gid *gid)
 {
        struct ib_smp *in_mad  = NULL;
        struct ib_smp *out_mad = NULL;
@@ -241,6 +322,25 @@ out:
        return err;
 }
 
+static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index,
+                         union ib_gid *gid)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+
+       *gid = dev->iboe.gid_table[port - 1][index];
+
+       return 0;
+}
+
+static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+                            union ib_gid *gid)
+{
+       if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+               return __mlx4_ib_query_gid(ibdev, port, index, gid);
+       else
+               return iboe_query_gid(ibdev, port, index, gid);
+}
+
 static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
                              u16 *pkey)
 {
@@ -272,14 +372,32 @@ out:
 static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
                                 struct ib_device_modify *props)
 {
+       struct mlx4_cmd_mailbox *mailbox;
+
        if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
                return -EOPNOTSUPP;
 
-       if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
-               spin_lock(&to_mdev(ibdev)->sm_lock);
-               memcpy(ibdev->node_desc, props->node_desc, 64);
-               spin_unlock(&to_mdev(ibdev)->sm_lock);
-       }
+       if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+               return 0;
+
+       spin_lock(&to_mdev(ibdev)->sm_lock);
+       memcpy(ibdev->node_desc, props->node_desc, 64);
+       spin_unlock(&to_mdev(ibdev)->sm_lock);
+
+       /*
+        * If possible, pass node desc to FW, so it can generate
+        * a 144 trap.  If cmd fails, just ignore.
+        */
+       mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev);
+       if (IS_ERR(mailbox))
+               return 0;
+
+       memset(mailbox->buf, 0, 256);
+       memcpy(mailbox->buf, props->node_desc, 64);
+       mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
+                MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A);
+
+       mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox);
 
        return 0;
 }
@@ -289,6 +407,7 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
 {
        struct mlx4_cmd_mailbox *mailbox;
        int err;
+       u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
 
        mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
        if (IS_ERR(mailbox))
@@ -304,7 +423,7 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
                ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
        }
 
-       err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
+       err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
                       MLX4_CMD_TIME_CLASS_B);
 
        mlx4_free_cmd_mailbox(dev->dev, mailbox);
@@ -447,18 +566,132 @@ static int mlx4_ib_dealloc_pd(struct ib_pd *pd)
        return 0;
 }
 
+static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
+{
+       struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+       struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+       struct mlx4_ib_gid_entry *ge;
+
+       ge = kzalloc(sizeof *ge, GFP_KERNEL);
+       if (!ge)
+               return -ENOMEM;
+
+       ge->gid = *gid;
+       if (mlx4_ib_add_mc(mdev, mqp, gid)) {
+               ge->port = mqp->port;
+               ge->added = 1;
+       }
+
+       mutex_lock(&mqp->mutex);
+       list_add_tail(&ge->list, &mqp->gid_list);
+       mutex_unlock(&mqp->mutex);
+
+       return 0;
+}
+
+int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+                  union ib_gid *gid)
+{
+       u8 mac[6];
+       struct net_device *ndev;
+       int ret = 0;
+
+       if (!mqp->port)
+               return 0;
+
+       spin_lock(&mdev->iboe.lock);
+       ndev = mdev->iboe.netdevs[mqp->port - 1];
+       if (ndev)
+               dev_hold(ndev);
+       spin_unlock(&mdev->iboe.lock);
+
+       if (ndev) {
+               rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+               rtnl_lock();
+               dev_mc_add(mdev->iboe.netdevs[mqp->port - 1], mac);
+               ret = 1;
+               rtnl_unlock();
+               dev_put(ndev);
+       }
+
+       return ret;
+}
+
 static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
-       return mlx4_multicast_attach(to_mdev(ibqp->device)->dev,
-                                    &to_mqp(ibqp)->mqp, gid->raw,
-                                    !!(to_mqp(ibqp)->flags &
-                                       MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+       int err;
+       struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+       struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+
+       err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags &
+                                   MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+       if (err)
+               return err;
+
+       err = add_gid_entry(ibqp, gid);
+       if (err)
+               goto err_add;
+
+       return 0;
+
+err_add:
+       mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw);
+       return err;
+}
+
+static struct mlx4_ib_gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw)
+{
+       struct mlx4_ib_gid_entry *ge;
+       struct mlx4_ib_gid_entry *tmp;
+       struct mlx4_ib_gid_entry *ret = NULL;
+
+       list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+               if (!memcmp(raw, ge->gid.raw, 16)) {
+                       ret = ge;
+                       break;
+               }
+       }
+
+       return ret;
 }
 
 static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
-       return mlx4_multicast_detach(to_mdev(ibqp->device)->dev,
-                                    &to_mqp(ibqp)->mqp, gid->raw);
+       int err;
+       struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+       struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+       u8 mac[6];
+       struct net_device *ndev;
+       struct mlx4_ib_gid_entry *ge;
+
+       err = mlx4_multicast_detach(mdev->dev,
+                                   &mqp->mqp, gid->raw);
+       if (err)
+               return err;
+
+       mutex_lock(&mqp->mutex);
+       ge = find_gid_entry(mqp, gid->raw);
+       if (ge) {
+               spin_lock(&mdev->iboe.lock);
+               ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL;
+               if (ndev)
+                       dev_hold(ndev);
+               spin_unlock(&mdev->iboe.lock);
+               rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+               if (ndev) {
+                       rtnl_lock();
+                       dev_mc_del(mdev->iboe.netdevs[ge->port - 1], mac);
+                       rtnl_unlock();
+                       dev_put(ndev);
+               }
+               list_del(&ge->list);
+               kfree(ge);
+       } else
+               printk(KERN_WARNING "could not find mgid entry\n");
+
+       mutex_unlock(&mqp->mutex);
+
+       return 0;
 }
 
 static int init_node_data(struct mlx4_ib_dev *dev)
@@ -543,15 +776,215 @@ static struct device_attribute *mlx4_class_attributes[] = {
        &dev_attr_board_id
 };
 
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev)
+{
+       memcpy(eui, dev->dev_addr, 3);
+       memcpy(eui + 5, dev->dev_addr + 3, 3);
+       if (vlan_id < 0x1000) {
+               eui[3] = vlan_id >> 8;
+               eui[4] = vlan_id & 0xff;
+       } else {
+               eui[3] = 0xff;
+               eui[4] = 0xfe;
+       }
+       eui[0] ^= 2;
+}
+
+static void update_gids_task(struct work_struct *work)
+{
+       struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
+       struct mlx4_cmd_mailbox *mailbox;
+       union ib_gid *gids;
+       int err;
+       struct mlx4_dev *dev = gw->dev->dev;
+       struct ib_event event;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               printk(KERN_WARNING "update gid table failed %ld\n", PTR_ERR(mailbox));
+               return;
+       }
+
+       gids = mailbox->buf;
+       memcpy(gids, gw->gids, sizeof gw->gids);
+
+       err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
+                      1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B);
+       if (err)
+               printk(KERN_WARNING "set port command failed\n");
+       else {
+               memcpy(gw->dev->iboe.gid_table[gw->port - 1], gw->gids, sizeof gw->gids);
+               event.device = &gw->dev->ib_dev;
+               event.element.port_num = gw->port;
+               event.event    = IB_EVENT_LID_CHANGE;
+               ib_dispatch_event(&event);
+       }
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       kfree(gw);
+}
+
+static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear)
+{
+       struct net_device *ndev = dev->iboe.netdevs[port - 1];
+       struct update_gid_work *work;
+       struct net_device *tmp;
+       int i;
+       u8 *hits;
+       int ret;
+       union ib_gid gid;
+       int free;
+       int found;
+       int need_update = 0;
+       u16 vid;
+
+       work = kzalloc(sizeof *work, GFP_ATOMIC);
+       if (!work)
+               return -ENOMEM;
+
+       hits = kzalloc(128, GFP_ATOMIC);
+       if (!hits) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       read_lock(&dev_base_lock);
+       for_each_netdev(&init_net, tmp) {
+               if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
+                       gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+                       vid = rdma_vlan_dev_vlan_id(tmp);
+                       mlx4_addrconf_ifid_eui48(&gid.raw[8], vid, ndev);
+                       found = 0;
+                       free = -1;
+                       for (i = 0; i < 128; ++i) {
+                               if (free < 0 &&
+                                   !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+                                       free = i;
+                               if (!memcmp(&dev->iboe.gid_table[port - 1][i], &gid, sizeof gid)) {
+                                       hits[i] = 1;
+                                       found = 1;
+                                       break;
+                               }
+                       }
+
+                       if (!found) {
+                               if (tmp == ndev &&
+                                   (memcmp(&dev->iboe.gid_table[port - 1][0],
+                                           &gid, sizeof gid) ||
+                                    !memcmp(&dev->iboe.gid_table[port - 1][0],
+                                            &zgid, sizeof gid))) {
+                                       dev->iboe.gid_table[port - 1][0] = gid;
+                                       ++need_update;
+                                       hits[0] = 1;
+                               } else if (free >= 0) {
+                                       dev->iboe.gid_table[port - 1][free] = gid;
+                                       hits[free] = 1;
+                                       ++need_update;
+                               }
+                       }
+               }
+       }
+       read_unlock(&dev_base_lock);
+
+       for (i = 0; i < 128; ++i)
+               if (!hits[i]) {
+                       if (memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+                               ++need_update;
+                       dev->iboe.gid_table[port - 1][i] = zgid;
+               }
+
+       if (need_update) {
+               memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof work->gids);
+               INIT_WORK(&work->work, update_gids_task);
+               work->port = port;
+               work->dev = dev;
+               queue_work(wq, &work->work);
+       } else
+               kfree(work);
+
+       kfree(hits);
+       return 0;
+
+out:
+       kfree(work);
+       return ret;
+}
+
+static void handle_en_event(struct mlx4_ib_dev *dev, int port, unsigned long event)
+{
+       switch (event) {
+       case NETDEV_UP:
+       case NETDEV_CHANGEADDR:
+               update_ipv6_gids(dev, port, 0);
+               break;
+
+       case NETDEV_DOWN:
+               update_ipv6_gids(dev, port, 1);
+               dev->iboe.netdevs[port - 1] = NULL;
+       }
+}
+
+static void netdev_added(struct mlx4_ib_dev *dev, int port)
+{
+       update_ipv6_gids(dev, port, 0);
+}
+
+static void netdev_removed(struct mlx4_ib_dev *dev, int port)
+{
+       update_ipv6_gids(dev, port, 1);
+}
+
+static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event,
+                               void *ptr)
+{
+       struct net_device *dev = ptr;
+       struct mlx4_ib_dev *ibdev;
+       struct net_device *oldnd;
+       struct mlx4_ib_iboe *iboe;
+       int port;
+
+       if (!net_eq(dev_net(dev), &init_net))
+               return NOTIFY_DONE;
+
+       ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
+       iboe = &ibdev->iboe;
+
+       spin_lock(&iboe->lock);
+       mlx4_foreach_ib_transport_port(port, ibdev->dev) {
+               oldnd = iboe->netdevs[port - 1];
+               iboe->netdevs[port - 1] =
+                       mlx4_get_protocol_dev(ibdev->dev, MLX4_PROTOCOL_EN, port);
+               if (oldnd != iboe->netdevs[port - 1]) {
+                       if (iboe->netdevs[port - 1])
+                               netdev_added(ibdev, port);
+                       else
+                               netdev_removed(ibdev, port);
+               }
+       }
+
+       if (dev == iboe->netdevs[0] ||
+           (iboe->netdevs[0] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[0]))
+               handle_en_event(ibdev, 1, event);
+       else if (dev == iboe->netdevs[1]
+                || (iboe->netdevs[1] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[1]))
+               handle_en_event(ibdev, 2, event);
+
+       spin_unlock(&iboe->lock);
+
+       return NOTIFY_DONE;
+}
+
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
        struct mlx4_ib_dev *ibdev;
        int num_ports = 0;
        int i;
+       int err;
+       struct mlx4_ib_iboe *iboe;
 
        printk_once(KERN_INFO "%s", mlx4_ib_version);
 
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+       mlx4_foreach_ib_transport_port(i, dev)
                num_ports++;
 
        /* No point in registering a device with no ports... */
@@ -564,6 +997,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                return NULL;
        }
 
+       iboe = &ibdev->iboe;
+
        if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
                goto err_dealloc;
 
@@ -612,6 +1047,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
 
        ibdev->ib_dev.query_device      = mlx4_ib_query_device;
        ibdev->ib_dev.query_port        = mlx4_ib_query_port;
+       ibdev->ib_dev.get_link_layer    = mlx4_ib_port_link_layer;
        ibdev->ib_dev.query_gid         = mlx4_ib_query_gid;
        ibdev->ib_dev.query_pkey        = mlx4_ib_query_pkey;
        ibdev->ib_dev.modify_device     = mlx4_ib_modify_device;
@@ -656,6 +1092,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        ibdev->ib_dev.unmap_fmr         = mlx4_ib_unmap_fmr;
        ibdev->ib_dev.dealloc_fmr       = mlx4_ib_fmr_dealloc;
 
+       spin_lock_init(&iboe->lock);
+
        if (init_node_data(ibdev))
                goto err_map;
 
@@ -668,16 +1106,28 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        if (mlx4_ib_mad_init(ibdev))
                goto err_reg;
 
+       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE && !iboe->nb.notifier_call) {
+               iboe->nb.notifier_call = mlx4_ib_netdev_event;
+               err = register_netdevice_notifier(&iboe->nb);
+               if (err)
+                       goto err_reg;
+       }
+
        for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
                if (device_create_file(&ibdev->ib_dev.dev,
                                       mlx4_class_attributes[i]))
-                       goto err_reg;
+                       goto err_notif;
        }
 
        ibdev->ib_active = true;
 
        return ibdev;
 
+err_notif:
+       if (unregister_netdevice_notifier(&ibdev->iboe.nb))
+               printk(KERN_WARNING "failure unregistering notifier\n");
+       flush_workqueue(wq);
+
 err_reg:
        ib_unregister_device(&ibdev->ib_dev);
 
@@ -703,11 +1153,16 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
 
        mlx4_ib_mad_cleanup(ibdev);
        ib_unregister_device(&ibdev->ib_dev);
+       if (ibdev->iboe.nb.notifier_call) {
+               if (unregister_netdevice_notifier(&ibdev->iboe.nb))
+                       printk(KERN_WARNING "failure unregistering notifier\n");
+               ibdev->iboe.nb.notifier_call = NULL;
+       }
+       iounmap(ibdev->uar_map);
 
-       for (p = 1; p <= ibdev->num_ports; ++p)
+       mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
                mlx4_CLOSE_PORT(dev, p);
 
-       iounmap(ibdev->uar_map);
        mlx4_uar_free(dev, &ibdev->priv_uar);
        mlx4_pd_free(dev, ibdev->priv_pdn);
        ib_dealloc_device(&ibdev->ib_dev);
@@ -747,19 +1202,33 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
 }
 
 static struct mlx4_interface mlx4_ib_interface = {
-       .add    = mlx4_ib_add,
-       .remove = mlx4_ib_remove,
-       .event  = mlx4_ib_event
+       .add            = mlx4_ib_add,
+       .remove         = mlx4_ib_remove,
+       .event          = mlx4_ib_event,
+       .protocol       = MLX4_PROTOCOL_IB
 };
 
 static int __init mlx4_ib_init(void)
 {
-       return mlx4_register_interface(&mlx4_ib_interface);
+       int err;
+
+       wq = create_singlethread_workqueue("mlx4_ib");
+       if (!wq)
+               return -ENOMEM;
+
+       err = mlx4_register_interface(&mlx4_ib_interface);
+       if (err) {
+               destroy_workqueue(wq);
+               return err;
+       }
+
+       return 0;
 }
 
 static void __exit mlx4_ib_cleanup(void)
 {
        mlx4_unregister_interface(&mlx4_ib_interface);
+       destroy_workqueue(wq);
 }
 
 module_init(mlx4_ib_init);
index 3486d7675e56dfece310b090abf0eec93d140ec6..2a322f21049fad5366a4c9464e998dba4ebe8167 100644 (file)
@@ -112,6 +112,13 @@ enum mlx4_ib_qp_flags {
        MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK     = 1 << 1,
 };
 
+struct mlx4_ib_gid_entry {
+       struct list_head        list;
+       union ib_gid            gid;
+       int                     added;
+       u8                      port;
+};
+
 struct mlx4_ib_qp {
        struct ib_qp            ibqp;
        struct mlx4_qp          mqp;
@@ -138,6 +145,8 @@ struct mlx4_ib_qp {
        u8                      resp_depth;
        u8                      sq_no_prefetch;
        u8                      state;
+       int                     mlx_type;
+       struct list_head        gid_list;
 };
 
 struct mlx4_ib_srq {
@@ -157,7 +166,14 @@ struct mlx4_ib_srq {
 
 struct mlx4_ib_ah {
        struct ib_ah            ibah;
-       struct mlx4_av          av;
+       union mlx4_ext_av       av;
+};
+
+struct mlx4_ib_iboe {
+       spinlock_t              lock;
+       struct net_device      *netdevs[MLX4_MAX_PORTS];
+       struct notifier_block   nb;
+       union ib_gid            gid_table[MLX4_MAX_PORTS][128];
 };
 
 struct mlx4_ib_dev {
@@ -176,6 +192,7 @@ struct mlx4_ib_dev {
 
        struct mutex            cap_mask_mutex;
        bool                    ib_active;
+       struct mlx4_ib_iboe     iboe;
 };
 
 static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev)
@@ -314,9 +331,20 @@ int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
 int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
 int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
 
+int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
+                       u8 *mac, int *is_mcast, u8 port);
+
 static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
 {
-       return !!(ah->av.g_slid & 0x80);
+       u8 port = be32_to_cpu(ah->av.ib.port_pd) >> 24 & 3;
+
+       if (rdma_port_get_link_layer(ah->ibah.device, port) == IB_LINK_LAYER_ETHERNET)
+               return 1;
+
+       return !!(ah->av.ib.g_slid & 0x80);
 }
 
+int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+                  union ib_gid *gid);
+
 #endif /* MLX4_IB_H */
index 1d27b9a8e2d6b6944e002296479116952456d73b..dca55b19a6f198ee9d9fee7b6f003306a55279a9 100644 (file)
@@ -226,7 +226,7 @@ struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device
        struct mlx4_ib_fast_reg_page_list *mfrpl;
        int size = page_list_len * sizeof (u64);
 
-       if (size > PAGE_SIZE)
+       if (page_list_len > MLX4_MAX_FAST_REG_PAGES)
                return ERR_PTR(-EINVAL);
 
        mfrpl = kmalloc(sizeof *mfrpl, GFP_KERNEL);
index 6a60827b2301b1d19581f1de95266f433e9d586d..9a7794ac34c1ead2f08a9da3078db777ee1ef1ec 100644 (file)
 
 #include <linux/log2.h>
 #include <linux/slab.h>
+#include <linux/netdevice.h>
 
 #include <rdma/ib_cache.h>
 #include <rdma/ib_pack.h>
+#include <rdma/ib_addr.h>
 
 #include <linux/mlx4/qp.h>
 
@@ -48,17 +50,26 @@ enum {
 
 enum {
        MLX4_IB_DEFAULT_SCHED_QUEUE     = 0x83,
-       MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f
+       MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f,
+       MLX4_IB_LINK_TYPE_IB            = 0,
+       MLX4_IB_LINK_TYPE_ETH           = 1
 };
 
 enum {
        /*
-        * Largest possible UD header: send with GRH and immediate data.
+        * Largest possible UD header: send with GRH and immediate
+        * data plus 18 bytes for an Ethernet header with VLAN/802.1Q
+        * tag.  (LRH would only use 8 bytes, so Ethernet is the
+        * biggest case)
         */
-       MLX4_IB_UD_HEADER_SIZE          = 72,
+       MLX4_IB_UD_HEADER_SIZE          = 82,
        MLX4_IB_LSO_HEADER_SPARE        = 128,
 };
 
+enum {
+       MLX4_IB_IBOE_ETHERTYPE          = 0x8915
+};
+
 struct mlx4_ib_sqp {
        struct mlx4_ib_qp       qp;
        int                     pkey_index;
@@ -462,6 +473,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        mutex_init(&qp->mutex);
        spin_lock_init(&qp->sq.lock);
        spin_lock_init(&qp->rq.lock);
+       INIT_LIST_HEAD(&qp->gid_list);
 
        qp->state        = IB_QPS_RESET;
        if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
@@ -649,6 +661,16 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re
        }
 }
 
+static void del_gid_entries(struct mlx4_ib_qp *qp)
+{
+       struct mlx4_ib_gid_entry *ge, *tmp;
+
+       list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+               list_del(&ge->list);
+               kfree(ge);
+       }
+}
+
 static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                              int is_user)
 {
@@ -695,6 +717,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                if (!qp->ibqp.srq)
                        mlx4_db_free(dev->dev, &qp->db);
        }
+
+       del_gid_entries(qp);
 }
 
 struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
@@ -852,6 +876,14 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
 static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
                         struct mlx4_qp_path *path, u8 port)
 {
+       int err;
+       int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
+               IB_LINK_LAYER_ETHERNET;
+       u8 mac[6];
+       int is_mcast;
+       u16 vlan_tag;
+       int vidx;
+
        path->grh_mylmc     = ah->src_path_bits & 0x7f;
        path->rlid          = cpu_to_be16(ah->dlid);
        if (ah->static_rate) {
@@ -879,12 +911,49 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
                memcpy(path->rgid, ah->grh.dgid.raw, 16);
        }
 
-       path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
-               ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+       if (is_eth) {
+               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+                       ((port - 1) << 6) | ((ah->sl & 7) << 3) | ((ah->sl & 8) >> 1);
+
+               if (!(ah->ah_flags & IB_AH_GRH))
+                       return -1;
+
+               err = mlx4_ib_resolve_grh(dev, ah, mac, &is_mcast, port);
+               if (err)
+                       return err;
+
+               memcpy(path->dmac, mac, 6);
+               path->ackto = MLX4_IB_LINK_TYPE_ETH;
+               /* use index 0 into MAC table for IBoE */
+               path->grh_mylmc &= 0x80;
+
+               vlan_tag = rdma_get_vlan_id(&dev->iboe.gid_table[port - 1][ah->grh.sgid_index]);
+               if (vlan_tag < 0x1000) {
+                       if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx))
+                               return -ENOENT;
+
+                       path->vlan_index = vidx;
+                       path->fl = 1 << 6;
+               }
+       } else
+               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+                       ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
 
        return 0;
 }
 
+static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
+{
+       struct mlx4_ib_gid_entry *ge, *tmp;
+
+       list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+               if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) {
+                       ge->added = 1;
+                       ge->port = qp->port;
+               }
+       }
+}
+
 static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                               const struct ib_qp_attr *attr, int attr_mask,
                               enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -980,7 +1049,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_TIMEOUT) {
-               context->pri_path.ackto = attr->timeout << 3;
+               context->pri_path.ackto |= attr->timeout << 3;
                optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT;
        }
 
@@ -1118,8 +1187,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                qp->atomic_rd_en = attr->qp_access_flags;
        if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
                qp->resp_depth = attr->max_dest_rd_atomic;
-       if (attr_mask & IB_QP_PORT)
+       if (attr_mask & IB_QP_PORT) {
                qp->port = attr->port_num;
+               update_mcg_macs(dev, qp);
+       }
        if (attr_mask & IB_QP_ALT_PATH)
                qp->alt_port = attr->alt_port_num;
 
@@ -1221,40 +1292,59 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        struct mlx4_wqe_mlx_seg *mlx = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
        struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       union ib_gid sgid;
        u16 pkey;
        int send_size;
        int header_size;
        int spc;
        int i;
+       int is_eth;
+       int is_vlan = 0;
+       int is_grh;
+       u16 vlan;
 
        send_size = 0;
        for (i = 0; i < wr->num_sge; ++i)
                send_size += wr->sg_list[i].length;
 
-       ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header);
+       is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET;
+       is_grh = mlx4_ib_ah_grh_present(ah);
+       if (is_eth) {
+               ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24,
+                                 ah->av.ib.gid_index, &sgid);
+               vlan = rdma_get_vlan_id(&sgid);
+               is_vlan = vlan < 0x1000;
+       }
+       ib_ud_header_init(send_size, !is_eth, is_eth, is_vlan, is_grh, 0, &sqp->ud_header);
+
+       if (!is_eth) {
+               sqp->ud_header.lrh.service_level =
+                       be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
+               sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid;
+               sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f);
+       }
 
-       sqp->ud_header.lrh.service_level   =
-               be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
-       sqp->ud_header.lrh.destination_lid = ah->av.dlid;
-       sqp->ud_header.lrh.source_lid      = cpu_to_be16(ah->av.g_slid & 0x7f);
-       if (mlx4_ib_ah_grh_present(ah)) {
+       if (is_grh) {
                sqp->ud_header.grh.traffic_class =
-                       (be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff;
+                       (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff;
                sqp->ud_header.grh.flow_label    =
-                       ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
-               sqp->ud_header.grh.hop_limit     = ah->av.hop_limit;
-               ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24,
-                                 ah->av.gid_index, &sqp->ud_header.grh.source_gid);
+                       ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
+               sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
+               ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24,
+                                 ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid);
                memcpy(sqp->ud_header.grh.destination_gid.raw,
-                      ah->av.dgid, 16);
+                      ah->av.ib.dgid, 16);
        }
 
        mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
-       mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
-                                 (sqp->ud_header.lrh.destination_lid ==
-                                  IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
-                                 (sqp->ud_header.lrh.service_level << 8));
-       mlx->rlid   = sqp->ud_header.lrh.destination_lid;
+
+       if (!is_eth) {
+               mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
+                                         (sqp->ud_header.lrh.destination_lid ==
+                                          IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
+                                         (sqp->ud_header.lrh.service_level << 8));
+               mlx->rlid = sqp->ud_header.lrh.destination_lid;
+       }
 
        switch (wr->opcode) {
        case IB_WR_SEND:
@@ -1270,9 +1360,29 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                return -EINVAL;
        }
 
-       sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
-       if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
-               sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
+       if (is_eth) {
+               u8 *smac;
+
+               memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
+               /* FIXME: cache smac value? */
+               smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+               memcpy(sqp->ud_header.eth.smac_h, smac, 6);
+               if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
+                       mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
+               if (!is_vlan) {
+                       sqp->ud_header.eth.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
+               } else {
+                       u16 pcp;
+
+                       sqp->ud_header.vlan.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
+                       pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 27 & 3) << 13;
+                       sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp);
+               }
+       } else {
+               sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
+               if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
+                       sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
+       }
        sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
        if (!sqp->qp.ibqp.qp_num)
                ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
@@ -1429,11 +1539,14 @@ static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg,
 }
 
 static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
-                            struct ib_send_wr *wr)
+                            struct ib_send_wr *wr, __be16 *vlan)
 {
        memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
        dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
        dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan;
+       memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6);
+       *vlan = dseg->vlan;
 }
 
 static void set_mlx_icrc_seg(void *dseg)
@@ -1536,6 +1649,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        __be32 uninitialized_var(lso_hdr_sz);
        __be32 blh;
        int i;
+       __be16 vlan = cpu_to_be16(0xffff);
 
        spin_lock_irqsave(&qp->sq.lock, flags);
 
@@ -1639,7 +1753,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case IB_QPT_UD:
-                       set_datagram_seg(wqe, wr);
+                       set_datagram_seg(wqe, wr, &vlan);
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
 
@@ -1717,6 +1831,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
                        (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh;
 
+               if (be16_to_cpu(vlan) < 0x1000) {
+                       ctrl->ins_vlan = 1 << 6;
+                       ctrl->vlan_tag = vlan;
+               }
+
                stamp = ind + qp->sq_spare_wqes;
                ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift);
 
@@ -1866,17 +1985,27 @@ static int to_ib_qp_access_flags(int mlx4_flags)
        return ib_flags;
 }
 
-static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
+static void to_ib_ah_attr(struct mlx4_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr,
                                struct mlx4_qp_path *path)
 {
+       struct mlx4_dev *dev = ibdev->dev;
+       int is_eth;
+
        memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
        ib_ah_attr->port_num      = path->sched_queue & 0x40 ? 2 : 1;
 
        if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
                return;
 
+       is_eth = rdma_port_get_link_layer(&ibdev->ib_dev, ib_ah_attr->port_num) ==
+               IB_LINK_LAYER_ETHERNET;
+       if (is_eth)
+               ib_ah_attr->sl = ((path->sched_queue >> 3) & 0x7) |
+               ((path->sched_queue & 4) << 1);
+       else
+               ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf;
+
        ib_ah_attr->dlid          = be16_to_cpu(path->rlid);
-       ib_ah_attr->sl            = (path->sched_queue >> 2) & 0xf;
        ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f;
        ib_ah_attr->static_rate   = path->static_rate ? path->static_rate - 5 : 0;
        ib_ah_attr->ah_flags      = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
@@ -1929,8 +2058,8 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
                to_ib_qp_access_flags(be32_to_cpu(context.params2));
 
        if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
-               to_ib_ah_attr(dev->dev, &qp_attr->ah_attr, &context.pri_path);
-               to_ib_ah_attr(dev->dev, &qp_attr->alt_ah_attr, &context.alt_path);
+               to_ib_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path);
+               to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context.alt_path);
                qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f;
                qp_attr->alt_port_num   = qp_attr->alt_ah_attr.port_num;
        }
index d2d172e6289c2171d02c07c36515d90dc2d8c7ce..a34c9d38e82250ba50c31aa367afed1fb7f9d0b0 100644 (file)
@@ -1493,7 +1493,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        int err;
        u16 pkey;
 
-       ib_ud_header_init(256, /* assume a MAD */
+       ib_ud_header_init(256, /* assume a MAD */ 1, 0, 0,
                          mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0,
                          &sqp->ud_header);
 
index 6220d9d75b582f468789c9680d1f01399d043792..25ad0f9944c0198782e308e9e606cee1c6aba446 100644 (file)
@@ -1424,7 +1424,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 {
 
        int     reset = 0;      /* whether to send reset in case of err.. */
-       int     passive_state;
        atomic_inc(&cm_resets_recvd);
        nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
                        " refcnt=%d\n", cm_node, cm_node->state,
@@ -1439,7 +1438,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                active_open_err(cm_node, skb, reset);
                break;
        case NES_CM_STATE_MPAREQ_RCVD:
-               passive_state = atomic_add_return(1, &cm_node->passive_state);
+               atomic_inc(&cm_node->passive_state);
                dev_kfree_skb_any(skb);
                break;
        case NES_CM_STATE_ESTABLISHED:
index 10560c796fd6c0ffc591601c610579d3e1b6e8ca..3892e2c0e95a57b38f2bd0258355d43540003e14 100644 (file)
@@ -271,6 +271,7 @@ static int nes_netdev_stop(struct net_device *netdev)
 
        if (netif_msg_ifdown(nesvnic))
                printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
+       netif_carrier_off(netdev);
 
        /* Disable network packets */
        napi_disable(&nesvnic->napi);
index 546fc22405fe315636cdf36a2207e5f14302497b..99933e4e48ff853da4a79f14ce899a1dea5afc67 100644 (file)
@@ -476,9 +476,9 @@ static struct ib_fast_reg_page_list *nes_alloc_fast_reg_page_list(
        }
        nes_debug(NES_DBG_MR, "nes_alloc_fast_reg_pbl: nes_frpl = %p, "
                  "ibfrpl = %p, ibfrpl.page_list = %p, pbl.kva = %p, "
-                 "pbl.paddr= %p\n", pnesfrpl, &pnesfrpl->ibfrpl,
+                 "pbl.paddr = %llx\n", pnesfrpl, &pnesfrpl->ibfrpl,
                  pnesfrpl->ibfrpl.page_list, pnesfrpl->nes_wqe_pbl.kva,
-                 (void *)pnesfrpl->nes_wqe_pbl.paddr);
+                 (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr);
 
        return pifrpl;
 }
@@ -584,7 +584,9 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr
        props->lmc = 0;
        props->sm_lid = 0;
        props->sm_sl = 0;
-       if (nesvnic->linkup)
+       if (netif_queue_stopped(netdev))
+               props->state = IB_PORT_DOWN;
+       else if (nesvnic->linkup)
                props->state = IB_PORT_ACTIVE;
        else
                props->state = IB_PORT_DOWN;
@@ -3483,13 +3485,13 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                        for (i = 0; i < ib_wr->wr.fast_reg.page_list_len; i++)
                                dst_page_list[i] = cpu_to_le64(src_page_list[i]);
 
-                       nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %p, "
-                                 "length: %d, rkey: %0x, pgl_paddr: %p, "
+                       nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %llx, "
+                                 "length: %d, rkey: %0x, pgl_paddr: %llx, "
                                  "page_list_len: %u, wqe_misc: %x\n",
-                                 (void *)ib_wr->wr.fast_reg.iova_start,
+                                 (unsigned long long) ib_wr->wr.fast_reg.iova_start,
                                  ib_wr->wr.fast_reg.length,
                                  ib_wr->wr.fast_reg.rkey,
-                                 (void *)pnesfrpl->nes_wqe_pbl.paddr,
+                                 (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr,
                                  ib_wr->wr.fast_reg.page_list_len,
                                  wqe_misc);
                        break;
index 61de0654820ed8dd6c401816a6c26ec22dae4673..64c9e7d02d4a3e667bebf099fd6ed93160329f22 100644 (file)
@@ -1406,7 +1406,7 @@ extern struct mutex qib_mutex;
  */
 #define qib_early_err(dev, fmt, ...) \
        do { \
-               dev_info(dev, KERN_ERR QIB_DRV_NAME ": " fmt, ##__VA_ARGS__); \
+               dev_err(dev, fmt, ##__VA_ARGS__); \
        } while (0)
 
 #define qib_dev_err(dd, fmt, ...) \
index a0e6613e8be6151d3fdc00efc3005ad8c6f22ebd..7e433d75c775a963fdedb38612ef734a6211ce79 100644 (file)
@@ -58,6 +58,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
                goto bail;
        }
 
+       inode->i_ino = get_next_ino();
        inode->i_mode = mode;
        inode->i_uid = 0;
        inode->i_gid = 0;
index f1d16d3a01f66c72ab004b62dbb6575dde11ba02..f3b50393604307a92fd1ee0b4e1f2e9bd706607c 100644 (file)
@@ -1243,6 +1243,7 @@ static int __devinit qib_init_one(struct pci_dev *pdev,
                qib_early_err(&pdev->dev, "QLogic PCIE device 0x%x cannot "
                      "work if CONFIG_PCI_MSI is not enabled\n",
                      ent->device);
+               dd = ERR_PTR(-ENODEV);
 #endif
                break;
 
index 7fa6e5592630247b7208f22205e980c574c3af83..48b6674cbc49f97b9fd4e8d225325b6304833b5d 100644 (file)
@@ -103,16 +103,20 @@ int qib_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
                ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
        } else
                ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-       if (ret)
+       if (ret) {
                qib_early_err(&pdev->dev,
                              "Unable to set DMA consistent mask: %d\n", ret);
+               goto bail;
+       }
 
        pci_set_master(pdev);
        ret = pci_enable_pcie_error_reporting(pdev);
-       if (ret)
+       if (ret) {
                qib_early_err(&pdev->dev,
                              "Unable to enable pcie error reporting: %d\n",
                              ret);
+               ret = 0;
+       }
        goto done;
 
 bail:
index a0931119bd78c50a7324b6da4350832e66312bac..955fb7157793f4a65582e21998e74a3f7474496d 100644 (file)
@@ -2068,7 +2068,10 @@ send_last:
                        goto nack_op_err;
                if (!ret)
                        goto rnr_nak;
-               goto send_last_imm;
+               wc.ex.imm_data = ohdr->u.rc.imm_data;
+               hdrsize += 4;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               goto send_last;
 
        case OP(RDMA_READ_REQUEST): {
                struct qib_ack_entry *e;
index b9c8b6346c1b3e475a5d945a4ce611b36a5a6e3c..32ccf3c824ca5545bdf5972123016dca5fb110d4 100644 (file)
@@ -457,8 +457,10 @@ rdma_first:
                }
                if (opcode == OP(RDMA_WRITE_ONLY))
                        goto rdma_last;
-               else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+               else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) {
+                       wc.ex.imm_data = ohdr->u.rc.imm_data;
                        goto rdma_last_imm;
+               }
                /* FALLTHROUGH */
        case OP(RDMA_WRITE_MIDDLE):
                /* Check for invalid length PMTU or posted rwqe len. */
@@ -471,8 +473,8 @@ rdma_first:
                break;
 
        case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
-rdma_last_imm:
                wc.ex.imm_data = ohdr->u.imm_data;
+rdma_last_imm:
                hdrsize += 4;
                wc.wc_flags = IB_WC_WITH_IMM;
 
index ec6b4fbe25e4416fb45ef9e76f5703093c26e86a..dfa71903d6e467c59071e3cc01b04fea98c256b3 100644 (file)
@@ -223,6 +223,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
        struct sk_buff *skb;
        u64 mapping[IPOIB_UD_RX_SG];
+       union ib_gid *dgid;
 
        ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
                       wr_id, wc->status);
@@ -271,6 +272,16 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        ipoib_ud_dma_unmap_rx(priv, mapping);
        ipoib_ud_skb_put_frags(priv, skb, wc->byte_len);
 
+       /* First byte of dgid signals multicast when 0xff */
+       dgid = &((struct ib_grh *)skb->data)->dgid;
+
+       if (!(wc->wc_flags & IB_WC_GRH) || dgid->raw[0] != 0xff)
+               skb->pkt_type = PACKET_HOST;
+       else if (memcmp(dgid, dev->broadcast + 4, sizeof(union ib_gid)) == 0)
+               skb->pkt_type = PACKET_BROADCAST;
+       else
+               skb->pkt_type = PACKET_MULTICAST;
+
        skb_pull(skb, IB_GRH_BYTES);
 
        skb->protocol = ((struct ipoib_header *) skb->data)->proto;
@@ -281,9 +292,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        dev->stats.rx_bytes += skb->len;
 
        skb->dev = dev;
-       /* XXX get correct PACKET_ type here */
-       skb->pkt_type = PACKET_HOST;
-
        if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
index b4b22576f12a0a0aba0c99f421fcdf7cd2699016..9ff7bc73ed95e8689bede687e30086acc99fe4fe 100644 (file)
@@ -1240,6 +1240,7 @@ static struct net_device *ipoib_add_port(const char *format,
                goto alloc_mem_failed;
 
        SET_NETDEV_DEV(priv->dev, hca->dma_device);
+       priv->dev->dev_id = port - 1;
 
        if (!ib_query_port(hca, port, &attr))
                priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu);
@@ -1362,6 +1363,8 @@ static void ipoib_add_one(struct ib_device *device)
        }
 
        for (p = s; p <= e; ++p) {
+               if (rdma_port_get_link_layer(device, p) != IB_LINK_LAYER_INFINIBAND)
+                       continue;
                dev = ipoib_add_port("ib%d", device, p);
                if (!IS_ERR(dev)) {
                        priv = netdev_priv(dev);
@@ -1409,8 +1412,7 @@ static int __init ipoib_init_module(void)
 
        ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
        ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
-       ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE,
-                                                    IPOIB_MIN_QUEUE_SIZE));
+       ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE);
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
        ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
 #endif
index 7f8f16bad75339388160db5b0095d8e0d131dd96..cfc1d65c4577bf4ed2ce07bc2ea1924f406bd445 100644 (file)
@@ -291,7 +291,7 @@ static void srp_free_target_ib(struct srp_target_port *target)
 
        for (i = 0; i < SRP_RQ_SIZE; ++i)
                srp_free_iu(target->srp_host, target->rx_ring[i]);
-       for (i = 0; i < SRP_SQ_SIZE + 1; ++i)
+       for (i = 0; i < SRP_SQ_SIZE; ++i)
                srp_free_iu(target->srp_host, target->tx_ring[i]);
 }
 
@@ -811,6 +811,75 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
        return len;
 }
 
+/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head.  Lock cannot be dropped between call here and
+ * call to __srp_post_send().
+ *
+ * Note:
+ * An upper limit for the number of allocated information units for each
+ * request type is:
+ * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
+ *   more than Scsi_Host.can_queue requests.
+ * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
+ * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
+ *   one unanswered SRP request to an initiator.
+ */
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+                                     enum srp_iu_type iu_type)
+{
+       s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
+       struct srp_iu *iu;
+
+       srp_send_completion(target->send_cq, target);
+
+       if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
+               return NULL;
+
+       /* Initiator responses to target requests do not consume credits */
+       if (target->req_lim <= rsv && iu_type != SRP_IU_RSP) {
+               ++target->zero_req_lim;
+               return NULL;
+       }
+
+       iu = target->tx_ring[target->tx_head & SRP_SQ_MASK];
+       iu->type = iu_type;
+       return iu;
+}
+
+/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head.
+ */
+static int __srp_post_send(struct srp_target_port *target,
+                          struct srp_iu *iu, int len)
+{
+       struct ib_sge list;
+       struct ib_send_wr wr, *bad_wr;
+       int ret = 0;
+
+       list.addr   = iu->dma;
+       list.length = len;
+       list.lkey   = target->srp_host->srp_dev->mr->lkey;
+
+       wr.next       = NULL;
+       wr.wr_id      = target->tx_head & SRP_SQ_MASK;
+       wr.sg_list    = &list;
+       wr.num_sge    = 1;
+       wr.opcode     = IB_WR_SEND;
+       wr.send_flags = IB_SEND_SIGNALED;
+
+       ret = ib_post_send(target->qp, &wr, &bad_wr);
+
+       if (!ret) {
+               ++target->tx_head;
+               if (iu->type != SRP_IU_RSP)
+                       --target->req_lim;
+       }
+
+       return ret;
+}
+
 static int srp_post_recv(struct srp_target_port *target)
 {
        unsigned long flags;
@@ -822,7 +891,7 @@ static int srp_post_recv(struct srp_target_port *target)
 
        spin_lock_irqsave(target->scsi_host->host_lock, flags);
 
-       next     = target->rx_head & (SRP_RQ_SIZE - 1);
+       next     = target->rx_head & SRP_RQ_MASK;
        wr.wr_id = next;
        iu       = target->rx_ring[next];
 
@@ -896,6 +965,71 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
        spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
 }
 
+static int srp_response_common(struct srp_target_port *target, s32 req_delta,
+                              void *rsp, int len)
+{
+       struct ib_device *dev;
+       unsigned long flags;
+       struct srp_iu *iu;
+       int err = 1;
+
+       dev = target->srp_host->srp_dev->dev;
+
+       spin_lock_irqsave(target->scsi_host->host_lock, flags);
+       target->req_lim += req_delta;
+
+       iu = __srp_get_tx_iu(target, SRP_IU_RSP);
+       if (!iu) {
+               shost_printk(KERN_ERR, target->scsi_host, PFX
+                            "no IU available to send response\n");
+               goto out;
+       }
+
+       ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE);
+       memcpy(iu->buf, rsp, len);
+       ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
+
+       err = __srp_post_send(target, iu, len);
+       if (err)
+               shost_printk(KERN_ERR, target->scsi_host, PFX
+                            "unable to post response: %d\n", err);
+
+out:
+       spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+       return err;
+}
+
+static void srp_process_cred_req(struct srp_target_port *target,
+                                struct srp_cred_req *req)
+{
+       struct srp_cred_rsp rsp = {
+               .opcode = SRP_CRED_RSP,
+               .tag = req->tag,
+       };
+       s32 delta = be32_to_cpu(req->req_lim_delta);
+
+       if (srp_response_common(target, delta, &rsp, sizeof rsp))
+               shost_printk(KERN_ERR, target->scsi_host, PFX
+                            "problems processing SRP_CRED_REQ\n");
+}
+
+static void srp_process_aer_req(struct srp_target_port *target,
+                               struct srp_aer_req *req)
+{
+       struct srp_aer_rsp rsp = {
+               .opcode = SRP_AER_RSP,
+               .tag = req->tag,
+       };
+       s32 delta = be32_to_cpu(req->req_lim_delta);
+
+       shost_printk(KERN_ERR, target->scsi_host, PFX
+                    "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun));
+
+       if (srp_response_common(target, delta, &rsp, sizeof rsp))
+               shost_printk(KERN_ERR, target->scsi_host, PFX
+                            "problems processing SRP_AER_REQ\n");
+}
+
 static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 {
        struct ib_device *dev;
@@ -923,6 +1057,14 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
                srp_process_rsp(target, iu->buf);
                break;
 
+       case SRP_CRED_REQ:
+               srp_process_cred_req(target, iu->buf);
+               break;
+
+       case SRP_AER_REQ:
+               srp_process_aer_req(target, iu->buf);
+               break;
+
        case SRP_T_LOGOUT:
                /* XXX Handle target logout */
                shost_printk(KERN_WARNING, target->scsi_host,
@@ -981,61 +1123,6 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
        }
 }
 
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.  Lock cannot be dropped between call here and
- * call to __srp_post_send().
- */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
-                                       enum srp_request_type req_type)
-{
-       s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
-
-       srp_send_completion(target->send_cq, target);
-
-       if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
-               return NULL;
-
-       if (target->req_lim < min) {
-               ++target->zero_req_lim;
-               return NULL;
-       }
-
-       return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
-}
-
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.
- */
-static int __srp_post_send(struct srp_target_port *target,
-                          struct srp_iu *iu, int len)
-{
-       struct ib_sge list;
-       struct ib_send_wr wr, *bad_wr;
-       int ret = 0;
-
-       list.addr   = iu->dma;
-       list.length = len;
-       list.lkey   = target->srp_host->srp_dev->mr->lkey;
-
-       wr.next       = NULL;
-       wr.wr_id      = target->tx_head & SRP_SQ_SIZE;
-       wr.sg_list    = &list;
-       wr.num_sge    = 1;
-       wr.opcode     = IB_WR_SEND;
-       wr.send_flags = IB_SEND_SIGNALED;
-
-       ret = ib_post_send(target->qp, &wr, &bad_wr);
-
-       if (!ret) {
-               ++target->tx_head;
-               --target->req_lim;
-       }
-
-       return ret;
-}
-
 static int srp_queuecommand(struct scsi_cmnd *scmnd,
                            void (*done)(struct scsi_cmnd *))
 {
@@ -1056,7 +1143,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                return 0;
        }
 
-       iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
+       iu = __srp_get_tx_iu(target, SRP_IU_CMD);
        if (!iu)
                goto err;
 
@@ -1064,7 +1151,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
        ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
                                   DMA_TO_DEVICE);
 
-       req = list_entry(target->free_reqs.next, struct srp_request, list);
+       req = list_first_entry(&target->free_reqs, struct srp_request, list);
 
        scmnd->scsi_done     = done;
        scmnd->result        = 0;
@@ -1121,7 +1208,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
                        goto err;
        }
 
-       for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+       for (i = 0; i < SRP_SQ_SIZE; ++i) {
                target->tx_ring[i] = srp_alloc_iu(target->srp_host,
                                                  srp_max_iu_len,
                                                  GFP_KERNEL, DMA_TO_DEVICE);
@@ -1137,7 +1224,7 @@ err:
                target->rx_ring[i] = NULL;
        }
 
-       for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+       for (i = 0; i < SRP_SQ_SIZE; ++i) {
                srp_free_iu(target->srp_host, target->tx_ring[i]);
                target->tx_ring[i] = NULL;
        }
@@ -1252,8 +1339,13 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                        target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
                        target->req_lim       = be32_to_cpu(rsp->req_lim_delta);
 
-                       target->scsi_host->can_queue = min(target->req_lim,
-                                                          target->scsi_host->can_queue);
+                       /*
+                        * Reserve credits for task management so we don't
+                        * bounce requests back to the SCSI mid-layer.
+                        */
+                       target->scsi_host->can_queue
+                               = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
+                                     target->scsi_host->can_queue);
                } else {
                        shost_printk(KERN_WARNING, target->scsi_host,
                                    PFX "Unhandled RSP opcode %#x\n", opcode);
@@ -1350,6 +1442,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 static int srp_send_tsk_mgmt(struct srp_target_port *target,
                             struct srp_request *req, u8 func)
 {
+       struct ib_device *dev = target->srp_host->srp_dev->dev;
        struct srp_iu *iu;
        struct srp_tsk_mgmt *tsk_mgmt;
 
@@ -1363,10 +1456,12 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
 
        init_completion(&req->done);
 
-       iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
+       iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT);
        if (!iu)
                goto out;
 
+       ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt,
+                                  DMA_TO_DEVICE);
        tsk_mgmt = iu->buf;
        memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
 
@@ -1376,6 +1471,8 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
        tsk_mgmt->tsk_mgmt_func = func;
        tsk_mgmt->task_tag      = req->index;
 
+       ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
+                                     DMA_TO_DEVICE);
        if (__srp_post_send(target, iu, sizeof *tsk_mgmt))
                goto out;
 
@@ -1626,9 +1723,9 @@ static struct scsi_host_template srp_template = {
        .eh_abort_handler               = srp_abort,
        .eh_device_reset_handler        = srp_reset_device,
        .eh_host_reset_handler          = srp_reset_host,
-       .can_queue                      = SRP_SQ_SIZE,
+       .can_queue                      = SRP_CMD_SQ_SIZE,
        .this_id                        = -1,
-       .cmd_per_lun                    = SRP_SQ_SIZE,
+       .cmd_per_lun                    = SRP_CMD_SQ_SIZE,
        .use_clustering                 = ENABLE_CLUSTERING,
        .shost_attrs                    = srp_host_attrs
 };
@@ -1813,7 +1910,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                                printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p);
                                goto out;
                        }
-                       target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE);
+                       target->scsi_host->cmd_per_lun = min(token, SRP_CMD_SQ_SIZE);
                        break;
 
                case SRP_OPT_IO_CLASS:
@@ -1891,7 +1988,7 @@ static ssize_t srp_create_target(struct device *dev,
 
        INIT_LIST_HEAD(&target->free_reqs);
        INIT_LIST_HEAD(&target->req_queue);
-       for (i = 0; i < SRP_SQ_SIZE; ++i) {
+       for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
                target->req_ring[i].index = i;
                list_add_tail(&target->req_ring[i].list, &target->free_reqs);
        }
@@ -2159,6 +2256,9 @@ static int __init srp_init_module(void)
 {
        int ret;
 
+       BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE);
+       BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE);
+
        if (srp_sg_tablesize > 255) {
                printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n");
                srp_sg_tablesize = 255;
index 5a80eac6fdaaca5339f2efa5a17abc57170874b7..ed0dce9e479fc9ed199d633662094e435944be0d 100644 (file)
@@ -59,7 +59,14 @@ enum {
 
        SRP_RQ_SHIFT            = 6,
        SRP_RQ_SIZE             = 1 << SRP_RQ_SHIFT,
-       SRP_SQ_SIZE             = SRP_RQ_SIZE - 1,
+       SRP_RQ_MASK             = SRP_RQ_SIZE - 1,
+
+       SRP_SQ_SIZE             = SRP_RQ_SIZE,
+       SRP_SQ_MASK             = SRP_SQ_SIZE - 1,
+       SRP_RSP_SQ_SIZE         = 1,
+       SRP_REQ_SQ_SIZE         = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE,
+       SRP_TSK_MGMT_SQ_SIZE    = 1,
+       SRP_CMD_SQ_SIZE         = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE,
 
        SRP_TAG_TSK_MGMT        = 1 << (SRP_RQ_SHIFT + 1),
 
@@ -75,9 +82,10 @@ enum srp_target_state {
        SRP_TARGET_REMOVED
 };
 
-enum srp_request_type {
-       SRP_REQ_NORMAL,
-       SRP_REQ_TASK_MGMT,
+enum srp_iu_type {
+       SRP_IU_CMD,
+       SRP_IU_TSK_MGMT,
+       SRP_IU_RSP,
 };
 
 struct srp_device {
@@ -144,11 +152,11 @@ struct srp_target_port {
 
        unsigned                tx_head;
        unsigned                tx_tail;
-       struct srp_iu          *tx_ring[SRP_SQ_SIZE + 1];
+       struct srp_iu          *tx_ring[SRP_SQ_SIZE];
 
        struct list_head        free_reqs;
        struct list_head        req_queue;
-       struct srp_request      req_ring[SRP_SQ_SIZE];
+       struct srp_request      req_ring[SRP_CMD_SQ_SIZE];
 
        struct work_struct      work;
 
@@ -164,6 +172,7 @@ struct srp_iu {
        void                   *buf;
        size_t                  size;
        enum dma_data_direction direction;
+       enum srp_iu_type        type;
 };
 
 #endif /* IB_SRP_H */
index 535fea4fe67f026bbe6475c5cd70c8a18d0bc4dd..e3f7fc6f95657e2f4846cebc0efae905d309c31d 100644 (file)
@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev,
 }
 #undef OLD_KEY_MAX
 
+static int evdev_handle_get_keycode(struct input_dev *dev,
+                                   void __user *p, size_t size)
+{
+       struct input_keymap_entry ke;
+       int error;
+
+       memset(&ke, 0, sizeof(ke));
+
+       if (size == sizeof(unsigned int[2])) {
+               /* legacy case */
+               int __user *ip = (int __user *)p;
+
+               if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+                       return -EFAULT;
+
+               ke.len = sizeof(unsigned int);
+               ke.flags = 0;
+
+               error = input_get_keycode(dev, &ke);
+               if (error)
+                       return error;
+
+               if (put_user(ke.keycode, ip + 1))
+                       return -EFAULT;
+
+       } else {
+               size = min(size, sizeof(ke));
+
+               if (copy_from_user(&ke, p, size))
+                       return -EFAULT;
+
+               error = input_get_keycode(dev, &ke);
+               if (error)
+                       return error;
+
+               if (copy_to_user(p, &ke, size))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+static int evdev_handle_set_keycode(struct input_dev *dev,
+                                   void __user *p, size_t size)
+{
+       struct input_keymap_entry ke;
+
+       memset(&ke, 0, sizeof(ke));
+
+       if (size == sizeof(unsigned int[2])) {
+               /* legacy case */
+               int __user *ip = (int __user *)p;
+
+               if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+                       return -EFAULT;
+
+               if (get_user(ke.keycode, ip + 1))
+                       return -EFAULT;
+
+               ke.len = sizeof(unsigned int);
+               ke.flags = 0;
+
+       } else {
+               size = min(size, sizeof(ke));
+
+               if (copy_from_user(&ke, p, size))
+                       return -EFAULT;
+
+               if (ke.len > sizeof(ke.scancode))
+                       return -EINVAL;
+       }
+
+       return input_set_keycode(dev, &ke);
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                           void __user *p, int compat_mode)
 {
@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
                return 0;
 
-       case EVIOCGKEYCODE:
-               if (get_user(t, ip))
-                       return -EFAULT;
-
-               error = input_get_keycode(dev, t, &v);
-               if (error)
-                       return error;
-
-               if (put_user(v, ip + 1))
-                       return -EFAULT;
-
-               return 0;
-
-       case EVIOCSKEYCODE:
-               if (get_user(t, ip) || get_user(v, ip + 1))
-                       return -EFAULT;
-
-               return input_set_keycode(dev, t, v);
-
        case EVIOCRMFF:
                return input_ff_erase(dev, (int)(unsigned long) p, file);
 
@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
        /* Now check variable-length commands */
 #define EVIOC_MASK_SIZE(nr)    ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
-
        switch (EVIOC_MASK_SIZE(cmd)) {
 
        case EVIOCGKEY(0):
@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                        return -EFAULT;
 
                return error;
+
+       case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
+               return evdev_handle_get_keycode(dev, p, size);
+
+       case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
+               return evdev_handle_set_keycode(dev, p, size);
        }
 
        /* Multi-number variable-length handlers */
index 7392992da4243c35e127466035e1f35cb377af3a..422aa0a6b77fc62d3d4b46ffd9a42ba85cce3c99 100644 (file)
@@ -59,44 +59,52 @@ MODULE_DEVICE_TABLE(pci, emu_tbl);
 
 static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int ioport, iolen;
        struct emu *emu;
        struct gameport *port;
-
-       if (pci_enable_device(pdev))
-               return -EBUSY;
-
-       ioport = pci_resource_start(pdev, 0);
-       iolen = pci_resource_len(pdev, 0);
-
-       if (!request_region(ioport, iolen, "emu10k1-gp"))
-               return -EBUSY;
+       int error;
 
        emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
        port = gameport_allocate_port();
        if (!emu || !port) {
                printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
-               release_region(ioport, iolen);
-               kfree(emu);
-               gameport_free_port(port);
-               return -ENOMEM;
+               error = -ENOMEM;
+               goto err_out_free;
        }
 
-       emu->io = ioport;
-       emu->size = iolen;
+       error = pci_enable_device(pdev);
+       if (error)
+               goto err_out_free;
+
+       emu->io = pci_resource_start(pdev, 0);
+       emu->size = pci_resource_len(pdev, 0);
+
        emu->dev = pdev;
        emu->gameport = port;
 
        gameport_set_name(port, "EMU10K1");
        gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
        port->dev.parent = &pdev->dev;
-       port->io = ioport;
+       port->io = emu->io;
+
+       if (!request_region(emu->io, emu->size, "emu10k1-gp")) {
+               printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n",
+                       emu->io, emu->io + emu->size - 1);
+               error = -EBUSY;
+               goto err_out_disable_dev;
+       }
 
        pci_set_drvdata(pdev, emu);
 
        gameport_register_port(port);
 
        return 0;
+
+ err_out_disable_dev:
+       pci_disable_device(pdev);
+ err_out_free:
+       gameport_free_port(port);
+       kfree(emu);
+       return error;
 }
 
 static void __devexit emu_remove(struct pci_dev *pdev)
@@ -106,6 +114,8 @@ static void __devexit emu_remove(struct pci_dev *pdev)
        gameport_unregister_port(emu->gameport);
        release_region(emu->io, emu->size);
        kfree(emu);
+
+       pci_disable_device(pdev);
 }
 
 static struct pci_driver emu_driver = {
index 14d3f3e208a2f557a80156dbe51c29f8aa0a0773..a3b70ff21018bce1c7e6e82e83ad429785d36d62 100644 (file)
@@ -133,11 +133,11 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
 {
        struct fm801_gp *gp = pci_get_drvdata(pci);
 
-       if (gp) {
-               gameport_unregister_port(gp->gameport);
-               release_resource(gp->res_port);
-               kfree(gp);
-       }
+       gameport_unregister_port(gp->gameport);
+       release_resource(gp->res_port);
+       kfree(gp);
+
+       pci_disable_device(pci);
 }
 
 static const struct pci_device_id fm801_gp_id_table[] = {
index 7919c25372257e0baa922903565f55fd94effb29..d092ef9291dabe1301006bc94310bc1973037808 100644 (file)
@@ -171,7 +171,7 @@ static int input_handle_abs_event(struct input_dev *dev,
        if (code == ABS_MT_SLOT) {
                /*
                 * "Stage" the event; we'll flush it later, when we
-                * get actiual touch data.
+                * get actual touch data.
                 */
                if (*pval >= 0 && *pval < dev->mtsize)
                        dev->slot = *pval;
@@ -188,7 +188,7 @@ static int input_handle_abs_event(struct input_dev *dev,
                pold = &mtslot->abs[code - ABS_MT_FIRST];
        } else {
                /*
-                * Bypass filtering for multitouch events when
+                * Bypass filtering for multi-touch events when
                 * not employing slots.
                 */
                pold = NULL;
@@ -634,78 +634,141 @@ static void input_disconnect_device(struct input_dev *dev)
        spin_unlock_irq(&dev->event_lock);
 }
 
-static int input_fetch_keycode(struct input_dev *dev, int scancode)
+/**
+ * input_scancode_to_scalar() - converts scancode in &struct input_keymap_entry
+ * @ke: keymap entry containing scancode to be converted.
+ * @scancode: pointer to the location where converted scancode should
+ *     be stored.
+ *
+ * This function is used to convert scancode stored in &struct keymap_entry
+ * into scalar form understood by legacy keymap handling methods. These
+ * methods expect scancodes to be represented as 'unsigned int'.
+ */
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+                            unsigned int *scancode)
+{
+       switch (ke->len) {
+       case 1:
+               *scancode = *((u8 *)ke->scancode);
+               break;
+
+       case 2:
+               *scancode = *((u16 *)ke->scancode);
+               break;
+
+       case 4:
+               *scancode = *((u32 *)ke->scancode);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(input_scancode_to_scalar);
+
+/*
+ * Those routines handle the default case where no [gs]etkeycode() is
+ * defined. In this case, an array indexed by the scancode is used.
+ */
+
+static unsigned int input_fetch_keycode(struct input_dev *dev,
+                                       unsigned int index)
 {
        switch (dev->keycodesize) {
-               case 1:
-                       return ((u8 *)dev->keycode)[scancode];
+       case 1:
+               return ((u8 *)dev->keycode)[index];
 
-               case 2:
-                       return ((u16 *)dev->keycode)[scancode];
+       case 2:
+               return ((u16 *)dev->keycode)[index];
 
-               default:
-                       return ((u32 *)dev->keycode)[scancode];
+       default:
+               return ((u32 *)dev->keycode)[index];
        }
 }
 
 static int input_default_getkeycode(struct input_dev *dev,
-                                   unsigned int scancode,
-                                   unsigned int *keycode)
+                                   struct input_keymap_entry *ke)
 {
+       unsigned int index;
+       int error;
+
        if (!dev->keycodesize)
                return -EINVAL;
 
-       if (scancode >= dev->keycodemax)
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+               index = ke->index;
+       else {
+               error = input_scancode_to_scalar(ke, &index);
+               if (error)
+                       return error;
+       }
+
+       if (index >= dev->keycodemax)
                return -EINVAL;
 
-       *keycode = input_fetch_keycode(dev, scancode);
+       ke->keycode = input_fetch_keycode(dev, index);
+       ke->index = index;
+       ke->len = sizeof(index);
+       memcpy(ke->scancode, &index, sizeof(index));
 
        return 0;
 }
 
 static int input_default_setkeycode(struct input_dev *dev,
-                                   unsigned int scancode,
-                                   unsigned int keycode)
+                                   const struct input_keymap_entry *ke,
+                                   unsigned int *old_keycode)
 {
-       int old_keycode;
+       unsigned int index;
+       int error;
        int i;
 
-       if (scancode >= dev->keycodemax)
+       if (!dev->keycodesize)
                return -EINVAL;
 
-       if (!dev->keycodesize)
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+       } else {
+               error = input_scancode_to_scalar(ke, &index);
+               if (error)
+                       return error;
+       }
+
+       if (index >= dev->keycodemax)
                return -EINVAL;
 
-       if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+       if (dev->keycodesize < sizeof(dev->keycode) &&
+                       (ke->keycode >> (dev->keycodesize * 8)))
                return -EINVAL;
 
        switch (dev->keycodesize) {
                case 1: {
                        u8 *k = (u8 *)dev->keycode;
-                       old_keycode = k[scancode];
-                       k[scancode] = keycode;
+                       *old_keycode = k[index];
+                       k[index] = ke->keycode;
                        break;
                }
                case 2: {
                        u16 *k = (u16 *)dev->keycode;
-                       old_keycode = k[scancode];
-                       k[scancode] = keycode;
+                       *old_keycode = k[index];
+                       k[index] = ke->keycode;
                        break;
                }
                default: {
                        u32 *k = (u32 *)dev->keycode;
-                       old_keycode = k[scancode];
-                       k[scancode] = keycode;
+                       *old_keycode = k[index];
+                       k[index] = ke->keycode;
                        break;
                }
        }
 
-       __clear_bit(old_keycode, dev->keybit);
-       __set_bit(keycode, dev->keybit);
+       __clear_bit(*old_keycode, dev->keybit);
+       __set_bit(ke->keycode, dev->keybit);
 
        for (i = 0; i < dev->keycodemax; i++) {
-               if (input_fetch_keycode(dev, i) == old_keycode) {
-                       __set_bit(old_keycode, dev->keybit);
+               if (input_fetch_keycode(dev, i) == *old_keycode) {
+                       __set_bit(*old_keycode, dev->keybit);
                        break; /* Setting the bit twice is useless, so break */
                }
        }
@@ -716,53 +779,86 @@ static int input_default_setkeycode(struct input_dev *dev,
 /**
  * input_get_keycode - retrieve keycode currently mapped to a given scancode
  * @dev: input device which keymap is being queried
- * @scancode: scancode (or its equivalent for device in question) for which
- *     keycode is needed
- * @keycode: result
+ * @ke: keymap entry
  *
  * This function should be called by anyone interested in retrieving current
- * keymap. Presently keyboard and evdev handlers use it.
+ * keymap. Presently evdev handlers use it.
  */
-int input_get_keycode(struct input_dev *dev,
-                     unsigned int scancode, unsigned int *keycode)
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
 {
        unsigned long flags;
        int retval;
 
        spin_lock_irqsave(&dev->event_lock, flags);
-       retval = dev->getkeycode(dev, scancode, keycode);
-       spin_unlock_irqrestore(&dev->event_lock, flags);
 
+       if (dev->getkeycode) {
+               /*
+                * Support for legacy drivers, that don't implement the new
+                * ioctls
+                */
+               u32 scancode = ke->index;
+
+               memcpy(ke->scancode, &scancode, sizeof(scancode));
+               ke->len = sizeof(scancode);
+               retval = dev->getkeycode(dev, scancode, &ke->keycode);
+       } else {
+               retval = dev->getkeycode_new(dev, ke);
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
        return retval;
 }
 EXPORT_SYMBOL(input_get_keycode);
 
 /**
- * input_get_keycode - assign new keycode to a given scancode
+ * input_set_keycode - attribute a keycode to a given scancode
  * @dev: input device which keymap is being updated
- * @scancode: scancode (or its equivalent for device in question)
- * @keycode: new keycode to be assigned to the scancode
+ * @ke: new keymap entry
  *
  * This function should be called by anyone needing to update current
  * keymap. Presently keyboard and evdev handlers use it.
  */
 int input_set_keycode(struct input_dev *dev,
-                     unsigned int scancode, unsigned int keycode)
+                     const struct input_keymap_entry *ke)
 {
        unsigned long flags;
        unsigned int old_keycode;
        int retval;
 
-       if (keycode > KEY_MAX)
+       if (ke->keycode > KEY_MAX)
                return -EINVAL;
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
-       retval = dev->getkeycode(dev, scancode, &old_keycode);
-       if (retval)
-               goto out;
+       if (dev->setkeycode) {
+               /*
+                * Support for legacy drivers, that don't implement the new
+                * ioctls
+                */
+               unsigned int scancode;
+
+               retval = input_scancode_to_scalar(ke, &scancode);
+               if (retval)
+                       goto out;
+
+               /*
+                * We need to know the old scancode, in order to generate a
+                * keyup effect, if the set operation happens successfully
+                */
+               if (!dev->getkeycode) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+
+               retval = dev->getkeycode(dev, scancode, &old_keycode);
+               if (retval)
+                       goto out;
+
+               retval = dev->setkeycode(dev, scancode, ke->keycode);
+       } else {
+               retval = dev->setkeycode_new(dev, ke, &old_keycode);
+       }
 
-       retval = dev->setkeycode(dev, scancode, keycode);
        if (retval)
                goto out;
 
@@ -1601,7 +1697,7 @@ EXPORT_SYMBOL(input_free_device);
  *
  * This function allocates all necessary memory for MT slot handling in the
  * input device, and adds ABS_MT_SLOT to the device capabilities. All slots
- * are initially marked as unused iby setting ABS_MT_TRACKING_ID to -1.
+ * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
  */
 int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
 {
@@ -1759,11 +1855,11 @@ int input_register_device(struct input_dev *dev)
                dev->rep[REP_PERIOD] = 33;
        }
 
-       if (!dev->getkeycode)
-               dev->getkeycode = input_default_getkeycode;
+       if (!dev->getkeycode && !dev->getkeycode_new)
+               dev->getkeycode_new = input_default_getkeycode;
 
-       if (!dev->setkeycode)
-               dev->setkeycode = input_default_setkeycode;
+       if (!dev->setkeycode && !dev->setkeycode_new)
+               dev->setkeycode_new = input_default_setkeycode;
 
        dev_set_name(&dev->dev, "input%ld",
                     (unsigned long) atomic_inc_return(&input_no) - 1);
index aa037fec2f86122500cbd5d14cfca0c59e614804..b8c51b9781dbfb5e51c9a9d84071f534bf44e1d1 100644 (file)
@@ -327,6 +327,16 @@ config KEYBOARD_NEWTON
          To compile this driver as a module, choose M here: the
          module will be called newtonkbd.
 
+config KEYBOARD_NOMADIK
+       tristate "ST-Ericsson Nomadik SKE keyboard"
+       depends on PLAT_NOMADIK
+       help
+         Say Y here if you want to use a keypad provided on the SKE controller
+         used on the Ux500 and Nomadik platforms
+
+         To compile this driver as a module, choose M here: the
+         module will be called nmk-ske-keypad.
+
 config KEYBOARD_OPENCORES
        tristate "OpenCores Keyboard Controller"
        help
@@ -424,6 +434,24 @@ config KEYBOARD_OMAP
          To compile this driver as a module, choose M here: the
          module will be called omap-keypad.
 
+config KEYBOARD_OMAP4
+       tristate "TI OMAP4 keypad support"
+       depends on ARCH_OMAP4
+       help
+         Say Y here if you want to use the OMAP4 keypad.
+
+         To compile this driver as a module, choose M here: the
+         module will be called omap4-keypad.
+
+config KEYBOARD_TNETV107X
+       tristate "TI TNETV107X keypad support"
+       depends on ARCH_DAVINCI_TNETV107X
+       help
+         Say Y here if you want to use the TNETV107X keypad.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tnetv107x-keypad.
+
 config KEYBOARD_TWL4030
        tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
        depends on TWL4030_CORE
index 504b591be0cdff5d193da2b15180a969075db724..a34452e8ebe2a1cb190f82d5c5f9c037860fcf07 100644 (file)
@@ -28,7 +28,9 @@ obj-$(CONFIG_KEYBOARD_MATRIX)         += matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)         += max7359_keypad.o
 obj-$(CONFIG_KEYBOARD_MCS)             += mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
+obj-$(CONFIG_KEYBOARD_NOMADIK)         += nomadik-ske-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_OMAP4)           += omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)       += opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
@@ -38,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC)               += sh_keysc.o
 obj-$(CONFIG_KEYBOARD_STMPE)           += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
+obj-$(CONFIG_KEYBOARD_TNETV107X)       += tnetv107x-keypad.o
 obj-$(CONFIG_KEYBOARD_TWL4030)         += twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
 obj-$(CONFIG_KEYBOARD_W90P910)         += w90p910_keypad.o
index d6918cb966c0603157265851958fd72e9ce5a7a4..b92d1cd5cba1e4ee83923b7bce43c80a7075f5b8 100644 (file)
@@ -660,7 +660,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
 #endif
 
 static const struct i2c_device_id adp5588_id[] = {
-       { KBUILD_MODNAME, 0 },
+       { "adp5588-keys", 0 },
        { "adp5587-keys", 0 },
        { }
 };
index 19fa94af207a6fa37fbadc7a3d39a65ea2010482..fed31e0947a170f7a39468f97ec4ab10a3ab3181 100644 (file)
@@ -570,6 +570,8 @@ static struct serio_device_id hil_dev_ids[] = {
        { 0 }
 };
 
+MODULE_DEVICE_TABLE(serio, hil_dev_ids);
+
 static struct serio_driver hil_serio_drv = {
        .driver         = {
                .name   = "hil_dev",
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
new file mode 100644 (file)
index 0000000..6e0f230
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * License terms:GNU General Public License (GPL) version 2
+ *
+ * Keypad controller driver for the SKE (Scroll Key Encoder) module used in
+ * the Nomadik 8815 and Ux500 platforms.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <plat/ske.h>
+
+/* SKE_CR bits */
+#define SKE_KPMLT      (0x1 << 6)
+#define SKE_KPCN       (0x7 << 3)
+#define SKE_KPASEN     (0x1 << 2)
+#define SKE_KPASON     (0x1 << 7)
+
+/* SKE_IMSC bits */
+#define SKE_KPIMA      (0x1 << 2)
+
+/* SKE_ICR bits */
+#define SKE_KPICS      (0x1 << 3)
+#define SKE_KPICA      (0x1 << 2)
+
+/* SKE_RIS bits */
+#define SKE_KPRISA     (0x1 << 2)
+
+#define SKE_KEYPAD_ROW_SHIFT   3
+#define SKE_KPD_KEYMAP_SIZE    (8 * 8)
+
+/* keypad auto scan registers */
+#define SKE_ASR0       0x20
+#define SKE_ASR1       0x24
+#define SKE_ASR2       0x28
+#define SKE_ASR3       0x2C
+
+#define SKE_NUM_ASRX_REGISTERS (4)
+
+/**
+ * struct ske_keypad  - data structure used by keypad driver
+ * @irq:       irq no
+ * @reg_base:  ske regsiters base address
+ * @input:     pointer to input device object
+ * @board:     keypad platform device
+ * @keymap:    matrix scan code table for keycodes
+ * @clk:       clock structure pointer
+ */
+struct ske_keypad {
+       int irq;
+       void __iomem *reg_base;
+       struct input_dev *input;
+       const struct ske_keypad_platform_data *board;
+       unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+       struct clk *clk;
+       spinlock_t ske_keypad_lock;
+};
+
+static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
+               u8 mask, u8 data)
+{
+       u32 ret;
+
+       spin_lock(&keypad->ske_keypad_lock);
+
+       ret = readl(keypad->reg_base + addr);
+       ret &= ~mask;
+       ret |= data;
+       writel(ret, keypad->reg_base + addr);
+
+       spin_unlock(&keypad->ske_keypad_lock);
+}
+
+/*
+ * ske_keypad_chip_init: init keypad controller configuration
+ *
+ * Enable Multi key press detection, auto scan mode
+ */
+static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+{
+       u32 value;
+       int timeout = 50;
+
+       /* check SKE_RIS to be 0 */
+       while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
+               cpu_relax();
+
+       if (!timeout)
+               return -EINVAL;
+
+       /*
+        * set debounce value
+        * keypad dbounce is configured in DBCR[15:8]
+        * dbounce value in steps of 32/32.768 ms
+        */
+       spin_lock(&keypad->ske_keypad_lock);
+       value = readl(keypad->reg_base + SKE_DBCR);
+       value = value & 0xff;
+       value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
+       writel(value, keypad->reg_base + SKE_DBCR);
+       spin_unlock(&keypad->ske_keypad_lock);
+
+       /* enable multi key detection */
+       ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
+
+       /*
+        * set up the number of columns
+        * KPCN[5:3] defines no. of keypad columns to be auto scanned
+        */
+       value = (keypad->board->kcol - 1) << 3;
+       ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
+
+       /* clear keypad interrupt for auto(and pending SW) scans */
+       ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
+
+       /* un-mask keypad interrupts */
+       ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+       /* enable automatic scan */
+       ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
+
+       return 0;
+}
+
+static void ske_keypad_read_data(struct ske_keypad *keypad)
+{
+       struct input_dev *input = keypad->input;
+       u16 status;
+       int col = 0, row = 0, code;
+       int ske_asr, ske_ris, key_pressed, i;
+
+       /*
+        * Read the auto scan registers
+        *
+        * Each SKE_ASRx (x=0 to x=3) contains two row values.
+        * lower byte contains row value for column 2*x,
+        * upper byte contains row value for column 2*x + 1
+        */
+       for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
+               ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
+               if (!ske_asr)
+                       continue;
+
+               /* now that ASRx is zero, find out the column x and row y*/
+               if (ske_asr & 0xff) {
+                       col = i * 2;
+                       status = ske_asr & 0xff;
+               } else {
+                       col = (i * 2) + 1;
+                       status = (ske_asr & 0xff00) >> 8;
+               }
+
+               /* find out the row */
+               row = __ffs(status);
+
+               code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
+               ske_ris = readl(keypad->reg_base + SKE_RIS);
+               key_pressed = ske_ris & SKE_KPRISA;
+
+               input_event(input, EV_MSC, MSC_SCAN, code);
+               input_report_key(input, keypad->keymap[code], key_pressed);
+               input_sync(input);
+       }
+}
+
+static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
+{
+       struct ske_keypad *keypad = dev_id;
+       int retries = 20;
+
+       /* disable auto scan interrupt; mask the interrupt generated */
+       ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+       ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
+
+       while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries)
+               msleep(5);
+
+       if (retries) {
+               /* SKEx registers are stable and can be read */
+               ske_keypad_read_data(keypad);
+       }
+
+       /* enable auto scan interrupts */
+       ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit ske_keypad_probe(struct platform_device *pdev)
+{
+       const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
+       struct ske_keypad *keypad;
+       struct input_dev *input;
+       struct resource *res;
+       int irq;
+       int error;
+
+       if (!plat) {
+               dev_err(&pdev->dev, "invalid keypad platform data\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get keypad irq\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "missing platform resources\n");
+               return -EINVAL;
+       }
+
+       keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!keypad || !input) {
+               dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       keypad->irq = irq;
+       keypad->board = plat;
+       keypad->input = input;
+       spin_lock_init(&keypad->ske_keypad_lock);
+
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               error = -EBUSY;
+               goto err_free_mem;
+       }
+
+       keypad->reg_base = ioremap(res->start, resource_size(res));
+       if (!keypad->reg_base) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENXIO;
+               goto err_free_mem_region;
+       }
+
+       keypad->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(keypad->clk)) {
+               dev_err(&pdev->dev, "failed to get clk\n");
+               error = PTR_ERR(keypad->clk);
+               goto err_iounmap;
+       }
+
+       input->id.bustype = BUS_HOST;
+       input->name = "ux500-ske-keypad";
+       input->dev.parent = &pdev->dev;
+
+       input->keycode = keypad->keymap;
+       input->keycodesize = sizeof(keypad->keymap[0]);
+       input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+       input_set_capability(input, EV_MSC, MSC_SCAN);
+
+       __set_bit(EV_KEY, input->evbit);
+       if (!plat->no_autorepeat)
+               __set_bit(EV_REP, input->evbit);
+
+       matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
+                       input->keycode, input->keybit);
+
+       clk_enable(keypad->clk);
+
+       /* go through board initialization helpers */
+       if (keypad->board->init)
+               keypad->board->init();
+
+       error = ske_keypad_chip_init(keypad);
+       if (error) {
+               dev_err(&pdev->dev, "unable to init keypad hardware\n");
+               goto err_clk_disable;
+       }
+
+       error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq,
+                                    IRQF_ONESHOT, "ske-keypad", keypad);
+       if (error) {
+               dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+               goto err_clk_disable;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev,
+                               "unable to register input device: %d\n", error);
+               goto err_free_irq;
+       }
+
+       if (plat->wakeup_enable)
+               device_init_wakeup(&pdev->dev, true);
+
+       platform_set_drvdata(pdev, keypad);
+
+       return 0;
+
+err_free_irq:
+       free_irq(keypad->irq, keypad);
+err_clk_disable:
+       clk_disable(keypad->clk);
+       clk_put(keypad->clk);
+err_iounmap:
+       iounmap(keypad->reg_base);
+err_free_mem_region:
+       release_mem_region(res->start, resource_size(res));
+err_free_mem:
+       input_free_device(input);
+       kfree(keypad);
+       return error;
+}
+
+static int __devexit ske_keypad_remove(struct platform_device *pdev)
+{
+       struct ske_keypad *keypad = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       free_irq(keypad->irq, keypad);
+
+       input_unregister_device(keypad->input);
+
+       clk_disable(keypad->clk);
+       clk_put(keypad->clk);
+
+       if (keypad->board->exit)
+               keypad->board->exit();
+
+       iounmap(keypad->reg_base);
+       release_mem_region(res->start, resource_size(res));
+       kfree(keypad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ske_keypad_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct ske_keypad *keypad = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(irq);
+       else
+               ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+
+       return 0;
+}
+
+static int ske_keypad_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct ske_keypad *keypad = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(irq);
+       else
+               ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+       return 0;
+}
+
+static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
+       .suspend = ske_keypad_suspend,
+       .resume = ske_keypad_resume,
+};
+#endif
+
+struct platform_driver ske_keypad_driver = {
+       .driver = {
+               .name = "nmk-ske-keypad",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &ske_keypad_dev_pm_ops,
+#endif
+       },
+       .probe = ske_keypad_probe,
+       .remove = __devexit_p(ske_keypad_remove),
+};
+
+static int __init ske_keypad_init(void)
+{
+       return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+       platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
+MODULE_ALIAS("platform:nomadik-ske-keypad");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
new file mode 100644 (file)
index 0000000..45bd097
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * OMAP4 Keypad Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author: Abraham Arce <x0066660@ti.com>
+ * Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <plat/omap4-keypad.h>
+
+/* OMAP4 registers */
+#define OMAP4_KBD_REVISION             0x00
+#define OMAP4_KBD_SYSCONFIG            0x10
+#define OMAP4_KBD_SYSSTATUS            0x14
+#define OMAP4_KBD_IRQSTATUS            0x18
+#define OMAP4_KBD_IRQENABLE            0x1C
+#define OMAP4_KBD_WAKEUPENABLE         0x20
+#define OMAP4_KBD_PENDING              0x24
+#define OMAP4_KBD_CTRL                 0x28
+#define OMAP4_KBD_DEBOUNCINGTIME       0x2C
+#define OMAP4_KBD_LONGKEYTIME          0x30
+#define OMAP4_KBD_TIMEOUT              0x34
+#define OMAP4_KBD_STATEMACHINE         0x38
+#define OMAP4_KBD_ROWINPUTS            0x3C
+#define OMAP4_KBD_COLUMNOUTPUTS                0x40
+#define OMAP4_KBD_FULLCODE31_0         0x44
+#define OMAP4_KBD_FULLCODE63_32                0x48
+
+/* OMAP4 bit definitions */
+#define OMAP4_DEF_IRQENABLE_EVENTEN    (1 << 0)
+#define OMAP4_DEF_IRQENABLE_LONGKEY    (1 << 1)
+#define OMAP4_DEF_IRQENABLE_TIMEOUTEN  (1 << 2)
+#define OMAP4_DEF_WUP_EVENT_ENA                (1 << 0)
+#define OMAP4_DEF_WUP_LONG_KEY_ENA     (1 << 1)
+#define OMAP4_DEF_CTRL_NOSOFTMODE      (1 << 1)
+#define OMAP4_DEF_CTRLPTVVALUE         (1 << 2)
+#define OMAP4_DEF_CTRLPTV              (1 << 1)
+
+/* OMAP4 values */
+#define OMAP4_VAL_IRQDISABLE           0x00
+#define OMAP4_VAL_DEBOUNCINGTIME       0x07
+#define OMAP4_VAL_FUNCTIONALCFG                0x1E
+
+#define OMAP4_MASK_IRQSTATUSDISABLE    0xFFFF
+
+struct omap4_keypad {
+       struct input_dev *input;
+
+       void __iomem *base;
+       int irq;
+
+       unsigned int rows;
+       unsigned int cols;
+       unsigned int row_shift;
+       unsigned char key_state[8];
+       unsigned short keymap[];
+};
+
+static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
+{
+       __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
+                       keypad_data->base + OMAP4_KBD_CTRL);
+       __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
+                       keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+                       keypad_data->base + OMAP4_KBD_IRQENABLE);
+       __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
+                       keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+}
+
+/* Interrupt handler */
+static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
+{
+       struct omap4_keypad *keypad_data = dev_id;
+       struct input_dev *input_dev = keypad_data->input;
+       unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
+       unsigned int col, row, code, changed;
+       u32 *new_state = (u32 *) key_state;
+
+       /* Disable interrupts */
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                    keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+       *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
+       *(new_state + 1) = __raw_readl(keypad_data->base
+                                               + OMAP4_KBD_FULLCODE63_32);
+
+       for (row = 0; row < keypad_data->rows; row++) {
+               changed = key_state[row] ^ keypad_data->key_state[row];
+               if (!changed)
+                       continue;
+
+               for (col = 0; col < keypad_data->cols; col++) {
+                       if (changed & (1 << col)) {
+                               code = MATRIX_SCAN_CODE(row, col,
+                                               keypad_data->row_shift);
+                               input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                               input_report_key(input_dev,
+                                                keypad_data->keymap[code],
+                                                key_state[row] & (1 << col));
+                       }
+               }
+       }
+
+       input_sync(input_dev);
+
+       memcpy(keypad_data->key_state, key_state,
+               sizeof(keypad_data->key_state));
+
+       /* clear pending interrupts */
+       __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+
+       /* enable interrupts */
+       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+                       keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit omap4_keypad_probe(struct platform_device *pdev)
+{
+       const struct omap4_keypad_platform_data *pdata;
+       struct omap4_keypad *keypad_data;
+       struct input_dev *input_dev;
+       struct resource *res;
+       resource_size_t size;
+       unsigned int row_shift, max_keys;
+       int irq;
+       int error;
+
+       /* platform data */
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no base address specified\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no keyboard irq assigned\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->keymap_data) {
+               dev_err(&pdev->dev, "no keymap data defined\n");
+               return -EINVAL;
+       }
+
+       row_shift = get_count_order(pdata->cols);
+       max_keys = pdata->rows << row_shift;
+
+       keypad_data = kzalloc(sizeof(struct omap4_keypad) +
+                               max_keys * sizeof(keypad_data->keymap[0]),
+                             GFP_KERNEL);
+       if (!keypad_data) {
+               dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
+               return -ENOMEM;
+       }
+
+       size = resource_size(res);
+
+       res = request_mem_region(res->start, size, pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "can't request mem region\n");
+               error = -EBUSY;
+               goto err_free_keypad;
+       }
+
+       keypad_data->base = ioremap(res->start, resource_size(res));
+       if (!keypad_data->base) {
+               dev_err(&pdev->dev, "can't ioremap mem resource\n");
+               error = -ENOMEM;
+               goto err_release_mem;
+       }
+
+       keypad_data->irq = irq;
+       keypad_data->row_shift = row_shift;
+       keypad_data->rows = pdata->rows;
+       keypad_data->cols = pdata->cols;
+
+       /* input device allocation */
+       keypad_data->input = input_dev = input_allocate_device();
+       if (!input_dev) {
+               error = -ENOMEM;
+               goto err_unmap;
+       }
+
+       input_dev->name = pdev->name;
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor = 0x0001;
+       input_dev->id.product = 0x0001;
+       input_dev->id.version = 0x0001;
+
+       input_dev->keycode      = keypad_data->keymap;
+       input_dev->keycodesize  = sizeof(keypad_data->keymap[0]);
+       input_dev->keycodemax   = max_keys;
+
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(EV_REP, input_dev->evbit);
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       input_set_drvdata(input_dev, keypad_data);
+
+       matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
+                       input_dev->keycode, input_dev->keybit);
+
+       omap4_keypad_config(keypad_data);
+
+       error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
+                            IRQF_TRIGGER_RISING,
+                            "omap4-keypad", keypad_data);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register interrupt\n");
+               goto err_free_input;
+       }
+
+       error = input_register_device(keypad_data->input);
+       if (error < 0) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto err_free_irq;
+       }
+
+
+       platform_set_drvdata(pdev, keypad_data);
+       return 0;
+
+err_free_irq:
+       free_irq(keypad_data->irq, keypad_data);
+err_free_input:
+       input_free_device(input_dev);
+err_unmap:
+       iounmap(keypad_data->base);
+err_release_mem:
+       release_mem_region(res->start, size);
+err_free_keypad:
+       kfree(keypad_data);
+       return error;
+}
+
+static int __devexit omap4_keypad_remove(struct platform_device *pdev)
+{
+       struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       free_irq(keypad_data->irq, keypad_data);
+       input_unregister_device(keypad_data->input);
+
+       iounmap(keypad_data->base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(keypad_data);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver omap4_keypad_driver = {
+       .probe          = omap4_keypad_probe,
+       .remove         = __devexit_p(omap4_keypad_remove),
+       .driver         = {
+               .name   = "omap4-keypad",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap4_keypad_init(void)
+{
+       return platform_driver_register(&omap4_keypad_driver);
+}
+module_init(omap4_keypad_init);
+
+static void __exit omap4_keypad_exit(void)
+{
+       platform_driver_unregister(&omap4_keypad_driver);
+}
+module_exit(omap4_keypad_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP4 Keypad Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap4-keypad");
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
new file mode 100644 (file)
index 0000000..b4a81eb
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Texas Instruments TNETV107X Keypad Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/input/matrix_keypad.h>
+
+#define BITS(x)                        (BIT(x) - 1)
+
+#define KEYPAD_ROWS            9
+#define KEYPAD_COLS            9
+
+#define DEBOUNCE_MIN           0x400ul
+#define DEBOUNCE_MAX           0x3ffffffful
+
+struct keypad_regs {
+       u32     rev;
+       u32     mode;
+       u32     mask;
+       u32     pol;
+       u32     dclock;
+       u32     rclock;
+       u32     stable_cnt;
+       u32     in_en;
+       u32     out;
+       u32     out_en;
+       u32     in;
+       u32     lock;
+       u32     pres[3];
+};
+
+#define keypad_read(kp, reg)           __raw_readl(&(kp)->regs->reg)
+#define keypad_write(kp, reg, val)     __raw_writel(val, &(kp)->regs->reg)
+
+struct keypad_data {
+       struct input_dev                *input_dev;
+       struct resource                 *res;
+       struct keypad_regs __iomem      *regs;
+       struct clk                      *clk;
+       struct device                   *dev;
+       spinlock_t                      lock;
+       u32                             irq_press;
+       u32                             irq_release;
+       int                             rows, cols, row_shift;
+       int                             debounce_ms, active_low;
+       u32                             prev_keys[3];
+       unsigned short                  keycodes[];
+};
+
+static irqreturn_t keypad_irq(int irq, void *data)
+{
+       struct keypad_data *kp = data;
+       int i, bit, val, row, col, code;
+       unsigned long flags;
+       u32 curr_keys[3];
+       u32 change;
+
+       spin_lock_irqsave(&kp->lock, flags);
+
+       memset(curr_keys, 0, sizeof(curr_keys));
+       if (irq == kp->irq_press)
+               for (i = 0; i < 3; i++)
+                       curr_keys[i] = keypad_read(kp, pres[i]);
+
+       for (i = 0; i < 3; i++) {
+               change = curr_keys[i] ^ kp->prev_keys[i];
+
+               while (change) {
+                       bit     = fls(change) - 1;
+                       change ^= BIT(bit);
+                       val     = curr_keys[i] & BIT(bit);
+                       bit    += i * 32;
+                       row     = bit / KEYPAD_COLS;
+                       col     = bit % KEYPAD_COLS;
+
+                       code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
+                       input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(kp->input_dev, kp->keycodes[code],
+                                        val);
+               }
+       }
+       input_sync(kp->input_dev);
+       memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
+
+       if (irq == kp->irq_press)
+               keypad_write(kp, lock, 0); /* Allow hardware updates */
+
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int keypad_start(struct input_dev *dev)
+{
+       struct keypad_data *kp = input_get_drvdata(dev);
+       unsigned long mask, debounce, clk_rate_khz;
+       unsigned long flags;
+
+       clk_enable(kp->clk);
+       clk_rate_khz = clk_get_rate(kp->clk) / 1000;
+
+       spin_lock_irqsave(&kp->lock, flags);
+
+       /* Initialize device registers */
+       keypad_write(kp, mode, 0);
+
+       mask  = BITS(kp->rows) << KEYPAD_COLS;
+       mask |= BITS(kp->cols);
+       keypad_write(kp, mask, ~mask);
+
+       keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
+       keypad_write(kp, stable_cnt, 3);
+
+       debounce = kp->debounce_ms * clk_rate_khz;
+       debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
+       keypad_write(kp, dclock, debounce);
+       keypad_write(kp, rclock, 4 * debounce);
+
+       keypad_write(kp, in_en, 1);
+
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       return 0;
+}
+
+static void keypad_stop(struct input_dev *dev)
+{
+       struct keypad_data *kp = input_get_drvdata(dev);
+
+       synchronize_irq(kp->irq_press);
+       synchronize_irq(kp->irq_release);
+       clk_disable(kp->clk);
+}
+
+static int __devinit keypad_probe(struct platform_device *pdev)
+{
+       const struct matrix_keypad_platform_data *pdata;
+       const struct matrix_keymap_data *keymap_data;
+       struct device *dev = &pdev->dev;
+       struct keypad_data *kp;
+       int error = 0, sz, row_shift;
+       u32 rev = 0;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(dev, "cannot find device data\n");
+               return -EINVAL;
+       }
+
+       keymap_data = pdata->keymap_data;
+       if (!keymap_data) {
+               dev_err(dev, "cannot find keymap data\n");
+               return -EINVAL;
+       }
+
+       row_shift = get_count_order(pdata->num_col_gpios);
+       sz  = offsetof(struct keypad_data, keycodes);
+       sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
+       kp = kzalloc(sz, GFP_KERNEL);
+       if (!kp) {
+               dev_err(dev, "cannot allocate device info\n");
+               return -ENOMEM;
+       }
+
+       kp->dev  = dev;
+       kp->rows = pdata->num_row_gpios;
+       kp->cols = pdata->num_col_gpios;
+       kp->row_shift = row_shift;
+       platform_set_drvdata(pdev, kp);
+       spin_lock_init(&kp->lock);
+
+       kp->irq_press   = platform_get_irq_byname(pdev, "press");
+       kp->irq_release = platform_get_irq_byname(pdev, "release");
+       if (kp->irq_press < 0 || kp->irq_release < 0) {
+               dev_err(dev, "cannot determine device interrupts\n");
+               error = -ENODEV;
+               goto error_res;
+       }
+
+       kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!kp->res) {
+               dev_err(dev, "cannot determine register area\n");
+               error = -ENODEV;
+               goto error_res;
+       }
+
+       if (!request_mem_region(kp->res->start, resource_size(kp->res),
+                               pdev->name)) {
+               dev_err(dev, "cannot claim register memory\n");
+               kp->res = NULL;
+               error = -EINVAL;
+               goto error_res;
+       }
+
+       kp->regs = ioremap(kp->res->start, resource_size(kp->res));
+       if (!kp->regs) {
+               dev_err(dev, "cannot map register memory\n");
+               error = -ENOMEM;
+               goto error_map;
+       }
+
+       kp->clk = clk_get(dev, NULL);
+       if (!kp->clk) {
+               dev_err(dev, "cannot claim device clock\n");
+               error = -EINVAL;
+               goto error_clk;
+       }
+
+       error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0,
+                                    dev_name(dev), kp);
+       if (error < 0) {
+               dev_err(kp->dev, "Could not allocate keypad press key irq\n");
+               goto error_irq_press;
+       }
+
+       error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0,
+                                    dev_name(dev), kp);
+       if (error < 0) {
+               dev_err(kp->dev, "Could not allocate keypad release key irq\n");
+               goto error_irq_release;
+       }
+
+       kp->input_dev = input_allocate_device();
+       if (!kp->input_dev) {
+               dev_err(dev, "cannot allocate input device\n");
+               error = -ENOMEM;
+               goto error_input;
+       }
+       input_set_drvdata(kp->input_dev, kp);
+
+       kp->input_dev->name       = pdev->name;
+       kp->input_dev->dev.parent = &pdev->dev;
+       kp->input_dev->open       = keypad_start;
+       kp->input_dev->close      = keypad_stop;
+       kp->input_dev->evbit[0]   = BIT_MASK(EV_KEY);
+       if (!pdata->no_autorepeat)
+               kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+       clk_enable(kp->clk);
+       rev = keypad_read(kp, rev);
+       kp->input_dev->id.bustype = BUS_HOST;
+       kp->input_dev->id.product = ((rev >>  8) & 0x07);
+       kp->input_dev->id.version = ((rev >> 16) & 0xfff);
+       clk_disable(kp->clk);
+
+       kp->input_dev->keycode     = kp->keycodes;
+       kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
+       kp->input_dev->keycodemax  = kp->rows << kp->row_shift;
+
+       matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
+                                  kp->input_dev->keybit);
+
+       input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
+
+       error = input_register_device(kp->input_dev);
+       if (error < 0) {
+               dev_err(dev, "Could not register input device\n");
+               goto error_reg;
+       }
+
+       return 0;
+
+
+error_reg:
+       input_free_device(kp->input_dev);
+error_input:
+       free_irq(kp->irq_release, kp);
+error_irq_release:
+       free_irq(kp->irq_press, kp);
+error_irq_press:
+       clk_put(kp->clk);
+error_clk:
+       iounmap(kp->regs);
+error_map:
+       release_mem_region(kp->res->start, resource_size(kp->res));
+error_res:
+       platform_set_drvdata(pdev, NULL);
+       kfree(kp);
+       return error;
+}
+
+static int __devexit keypad_remove(struct platform_device *pdev)
+{
+       struct keypad_data *kp = platform_get_drvdata(pdev);
+
+       free_irq(kp->irq_press, kp);
+       free_irq(kp->irq_release, kp);
+       input_unregister_device(kp->input_dev);
+       clk_put(kp->clk);
+       iounmap(kp->regs);
+       release_mem_region(kp->res->start, resource_size(kp->res));
+       platform_set_drvdata(pdev, NULL);
+       kfree(kp);
+
+       return 0;
+}
+
+static struct platform_driver keypad_driver = {
+       .probe          = keypad_probe,
+       .remove         = __devexit_p(keypad_remove),
+       .driver.name    = "tnetv107x-keypad",
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init keypad_init(void)
+{
+       return platform_driver_register(&keypad_driver);
+}
+
+static void __exit keypad_exit(void)
+{
+       platform_driver_unregister(&keypad_driver);
+}
+
+module_init(keypad_init);
+module_exit(keypad_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TNETV107X Keypad Driver");
+MODULE_ALIAS("platform: tnetv107x-keypad");
+MODULE_LICENSE("GPL");
index fb16b5e5ea13fd64a461577778bec1d3e9c04343..09bef79d9da1c6e3aecd6efe40c0d4c4c900ba0b 100644 (file)
@@ -406,23 +406,22 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
        if (error) {
                dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
                        kp->irq);
-               goto err3;
+               goto err2;
        }
 
        /* Enable KP and TO interrupts now. */
        reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
        if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
                error = -EIO;
-               goto err4;
+               goto err3;
        }
 
        platform_set_drvdata(pdev, kp);
        return 0;
 
-err4:
+err3:
        /* mask all events - we don't care about the result */
        (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
-err3:
        free_irq(kp->irq, NULL);
 err2:
        input_unregister_device(input);
index b49e233797235e8169ee999f4b2305fa301e327d..b99b8cbde02f531ba08fbcfa2f8b10f4d52e0c02 100644 (file)
@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
          To compile this driver as a module, choose M here: the module
          will be called 88pm860x_onkey.
 
+config INPUT_AB8500_PONKEY
+       tristate "AB8500 Pon (PowerOn) Key"
+       depends on AB8500_CORE
+       help
+         Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
+         Mix-Sig PMIC.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ab8500-ponkey.
+
 config INPUT_AD714X
        tristate "Analog Devices AD714x Capacitance Touch Sensor"
        help
index 19ccca78fa766d2ea2bb24f78201a6b6d9ec770c..1fe1f6c8b7379afc6b70807be2f2428833122611 100644 (file)
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT_88PM860X_ONKEY)     += 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_AB8500_PONKEY)      += ab8500-ponkey.o
 obj-$(CONFIG_INPUT_AD714X)             += ad714x.o
 obj-$(CONFIG_INPUT_AD714X_I2C)         += ad714x-i2c.o
 obj-$(CONFIG_INPUT_AD714X_SPI)         += ad714x-spi.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
new file mode 100644 (file)
index 0000000..3d3288a
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 Power-On Key handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/slab.h>
+
+/**
+ * struct ab8500_ponkey - ab8500 ponkey information
+ * @input_dev: pointer to input device
+ * @ab8500: ab8500 parent
+ * @irq_dbf: irq number for falling transition
+ * @irq_dbr: irq number for rising transition
+ */
+struct ab8500_ponkey {
+       struct input_dev        *idev;
+       struct ab8500           *ab8500;
+       int                     irq_dbf;
+       int                     irq_dbr;
+};
+
+/* AB8500 gives us an interrupt when ONKEY is held */
+static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
+{
+       struct ab8500_ponkey *ponkey = data;
+
+       if (irq == ponkey->irq_dbf)
+               input_report_key(ponkey->idev, KEY_POWER, true);
+       else if (irq == ponkey->irq_dbr)
+               input_report_key(ponkey->idev, KEY_POWER, false);
+
+       input_sync(ponkey->idev);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+       struct ab8500_ponkey *ponkey;
+       struct input_dev *input;
+       int irq_dbf, irq_dbr;
+       int error;
+
+       irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
+       if (irq_dbf < 0) {
+               dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
+               return irq_dbf;
+       }
+
+       irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
+       if (irq_dbr < 0) {
+               dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
+               return irq_dbr;
+       }
+
+       ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!ponkey || !input) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ponkey->idev = input;
+       ponkey->ab8500 = ab8500;
+       ponkey->irq_dbf = irq_dbf;
+       ponkey->irq_dbr = irq_dbr;
+
+       input->name = "AB8500 POn(PowerOn) Key";
+       input->dev.parent = &pdev->dev;
+
+       input_set_capability(input, EV_KEY, KEY_POWER);
+
+       error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
+                                       0, "ab8500-ponkey-dbf", ponkey);
+       if (error < 0) {
+               dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
+                       ponkey->irq_dbf, error);
+               goto err_free_mem;
+       }
+
+       error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
+                                       0, "ab8500-ponkey-dbr", ponkey);
+       if (error < 0) {
+               dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
+                       ponkey->irq_dbr, error);
+               goto err_free_dbf_irq;
+       }
+
+       error = input_register_device(ponkey->idev);
+       if (error) {
+               dev_err(ab8500->dev, "Can't register input device: %d\n", error);
+               goto err_free_dbr_irq;
+       }
+
+       platform_set_drvdata(pdev, ponkey);
+       return 0;
+
+err_free_dbr_irq:
+       free_irq(ponkey->irq_dbr, ponkey);
+err_free_dbf_irq:
+       free_irq(ponkey->irq_dbf, ponkey);
+err_free_mem:
+       input_free_device(input);
+       kfree(ponkey);
+
+       return error;
+}
+
+static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+{
+       struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
+
+       free_irq(ponkey->irq_dbf, ponkey);
+       free_irq(ponkey->irq_dbr, ponkey);
+       input_unregister_device(ponkey->idev);
+       kfree(ponkey);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_ponkey_driver = {
+       .driver         = {
+               .name   = "ab8500-poweron-key",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ab8500_ponkey_probe,
+       .remove         = __devexit_p(ab8500_ponkey_remove),
+};
+
+static int __init ab8500_ponkey_init(void)
+{
+       return platform_driver_register(&ab8500_ponkey_driver);
+}
+module_init(ab8500_ponkey_init);
+
+static void __exit ab8500_ponkey_exit(void)
+{
+       platform_driver_unregister(&ab8500_ponkey_driver);
+}
+module_exit(ab8500_ponkey_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
index 23257652b8e8b49f8ed85d8e2ca1f259b35f8453..0b0e9be6354215319200a8a305c9db55e8b4c3dd 100644 (file)
@@ -483,51 +483,88 @@ static void ati_remote2_complete_key(struct urb *urb)
 }
 
 static int ati_remote2_getkeycode(struct input_dev *idev,
-                                 unsigned int scancode, unsigned int *keycode)
+                                 struct input_keymap_entry *ke)
 {
        struct ati_remote2 *ar2 = input_get_drvdata(idev);
        unsigned int mode;
-       int index;
+       int offset;
+       unsigned int index;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+               if (index >= ATI_REMOTE2_MODES *
+                               ARRAY_SIZE(ati_remote2_key_table))
+                       return -EINVAL;
+
+               mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+               offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+               scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
+       } else {
+               if (input_scancode_to_scalar(ke, &scancode))
+                       return -EINVAL;
+
+               mode = scancode >> 8;
+               if (mode > ATI_REMOTE2_PC)
+                       return -EINVAL;
+
+               offset = ati_remote2_lookup(scancode & 0xff);
+               if (offset < 0)
+                       return -EINVAL;
+
+               index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
+       }
 
-       mode = scancode >> 8;
-       if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
-               return -EINVAL;
+       ke->keycode = ar2->keycode[mode][offset];
+       ke->len = sizeof(scancode);
+       memcpy(&ke->scancode, &scancode, sizeof(scancode));
+       ke->index = index;
 
-       index = ati_remote2_lookup(scancode & 0xFF);
-       if (index < 0)
-               return -EINVAL;
-
-       *keycode = ar2->keycode[mode][index];
        return 0;
 }
 
 static int ati_remote2_setkeycode(struct input_dev *idev,
-                                 unsigned int scancode, unsigned int keycode)
+                                 const struct input_keymap_entry *ke,
+                                 unsigned int *old_keycode)
 {
        struct ati_remote2 *ar2 = input_get_drvdata(idev);
-       unsigned int mode, old_keycode;
-       int index;
-
-       mode = scancode >> 8;
-       if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
-               return -EINVAL;
-
-       index = ati_remote2_lookup(scancode & 0xFF);
-       if (index < 0)
-               return -EINVAL;
+       unsigned int mode;
+       int offset;
+       unsigned int index;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               if (ke->index >= ATI_REMOTE2_MODES *
+                               ARRAY_SIZE(ati_remote2_key_table))
+                       return -EINVAL;
+
+               mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+               offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+       } else {
+               if (input_scancode_to_scalar(ke, &scancode))
+                       return -EINVAL;
+
+               mode = scancode >> 8;
+               if (mode > ATI_REMOTE2_PC)
+                       return -EINVAL;
+
+               offset = ati_remote2_lookup(scancode & 0xff);
+               if (offset < 0)
+                       return -EINVAL;
+       }
 
-       old_keycode = ar2->keycode[mode][index];
-       ar2->keycode[mode][index] = keycode;
-       __set_bit(keycode, idev->keybit);
+       *old_keycode = ar2->keycode[mode][offset];
+       ar2->keycode[mode][offset] = ke->keycode;
+       __set_bit(ke->keycode, idev->keybit);
 
        for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
                for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
-                       if (ar2->keycode[mode][index] == old_keycode)
+                       if (ar2->keycode[mode][index] == *old_keycode)
                                return 0;
                }
        }
 
-       __clear_bit(old_keycode, idev->keybit);
+       __clear_bit(*old_keycode, idev->keybit);
 
        return 0;
 }
@@ -575,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
        idev->open = ati_remote2_open;
        idev->close = ati_remote2_close;
 
-       idev->getkeycode = ati_remote2_getkeycode;
-       idev->setkeycode = ati_remote2_setkeycode;
+       idev->getkeycode_new = ati_remote2_getkeycode;
+       idev->setkeycode_new = ati_remote2_setkeycode;
 
        idev->name = ar2->name;
        idev->phys = ar2->phys;
index bf170f6b4422676889658959af884834d8e81efb..f45947190e4fcb07668adeec9734ea28418df481 100644 (file)
@@ -280,7 +280,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
 
        pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
        if (!pm->configcr)
-               return -1;
+               return -ENOMEM;
 
        return 0;
 }
index 4f9b2afc24e820d75b819555f7f667f94bd73f69..014dd4ad0d4fecede04221e5348fc78e023d76e2 100644 (file)
@@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
        .probe          = twl4030_vibra_probe,
        .remove         = __devexit_p(twl4030_vibra_remove),
        .driver         = {
-               .name   = "twl4030_codec_vibra",
+               .name   = "twl4030-vibra",
                .owner  = THIS_MODULE,
 #ifdef CONFIG_PM
                .pm     = &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
 }
 module_exit(twl4030_vibra_exit);
 
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
 
 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 MODULE_LICENSE("GPL");
index 48311204ba51a76fbc90f7f3194e6a2f79e5a403..04d9bf320a4f9c090b8d4f46aeca8e848bc4f988 100644 (file)
@@ -699,7 +699,7 @@ int elantech_init(struct psmouse *psmouse)
 
        psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
        if (!etd)
-               return -1;
+               return -ENOMEM;
 
        etd->parity[0] = 1;
        for (i = 1; i < 256; i++)
index 73a7af2542a8c7a32c1815e72df9fb10dac3ee1c..cd9d0c97e429622ca5d7fd21c69e9e0be14156ec 100644 (file)
@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
        if (!new_dev)
                return -ENOMEM;
 
-       while (serio->child) {
+       while (!list_empty(&serio->children)) {
                if (++retry > 3) {
                        printk(KERN_WARNING
-                               "psmouse: failed to destroy child port, "
+                               "psmouse: failed to destroy children ports, "
                                "protocol change aborted.\n");
                        input_free_device(new_dev);
                        return -EIO;
index 96b70a43515f034ff5c1c02b8ec7a35674afb394..2e300a460556573ec20f85ac536f63f6d0bed438 100644 (file)
@@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
        return 0;
 }
 
-static inline int synaptics_is_pt_packet(unsigned char *buf)
+static int synaptics_pt_start(struct serio *serio)
+{
+       struct psmouse *parent = serio_get_drvdata(serio->parent);
+       struct synaptics_data *priv = parent->private;
+
+       serio_pause_rx(parent->ps2dev.serio);
+       priv->pt_port = serio;
+       serio_continue_rx(parent->ps2dev.serio);
+
+       return 0;
+}
+
+static void synaptics_pt_stop(struct serio *serio)
+{
+       struct psmouse *parent = serio_get_drvdata(serio->parent);
+       struct synaptics_data *priv = parent->private;
+
+       serio_pause_rx(parent->ps2dev.serio);
+       priv->pt_port = NULL;
+       serio_continue_rx(parent->ps2dev.serio);
+}
+
+static int synaptics_is_pt_packet(unsigned char *buf)
 {
        return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
@@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-       struct serio *ptport = psmouse->ps2dev.serio->child;
-       struct psmouse *child = serio_get_drvdata(ptport);
        struct synaptics_data *priv = psmouse->private;
+       struct psmouse *child = serio_get_drvdata(priv->pt_port);
 
        /* adjust the touchpad to child's choice of protocol */
        if (child) {
@@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
        strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
        strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
        serio->write = synaptics_pt_write;
+       serio->start = synaptics_pt_start;
+       serio->stop = synaptics_pt_stop;
        serio->parent = psmouse->ps2dev.serio;
 
        psmouse->pt_activate = synaptics_pt_activate;
@@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
                if (unlikely(priv->pkt_type == SYN_NEWABS))
                        priv->pkt_type = synaptics_detect_pkt_type(psmouse);
 
-               if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
-                       if (psmouse->ps2dev.serio->child)
-                               synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
+               if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
+                   synaptics_is_pt_packet(psmouse->packet)) {
+                       if (priv->pt_port)
+                               synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
                } else
                        synaptics_process_packet(psmouse);
 
@@ -731,7 +755,7 @@ int synaptics_init(struct psmouse *psmouse)
 
        psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
        if (!priv)
-               return -1;
+               return -ENOMEM;
 
        psmouse_reset(psmouse);
 
index b6aa7d20d8a35c0c2eb3f313c388bd80b8638f1e..613a3652f98f5f787fa619807f10de67aa8634c5 100644 (file)
@@ -110,6 +110,8 @@ struct synaptics_data {
        unsigned char pkt_type;                 /* packet type - old, new, etc */
        unsigned char mode;                     /* current mode byte */
        int scroll;
+
+       struct serio *pt_port;                  /* Pass-through serio port */
 };
 
 void synaptics_module_init(void);
index 0643e49ca6039ea239e777c0b7f695040fed53bb..54b2fa892e1941b76d3d863013b85a4884595770 100644 (file)
@@ -303,7 +303,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
 
        psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
        if (!psmouse->private)
-               return -1;
+               return -ENOMEM;
 
        psmouse->vendor = "IBM";
        psmouse->name = "TrackPoint";
index 31ec7265aac63806060a665278afc70d6e18946f..2a00ddf4f23a3b469c621be77b08c4d6b943c428 100644 (file)
@@ -867,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
        spin_lock_init(&mousedev->client_lock);
        mutex_init(&mousedev->mutex);
        lockdep_set_subclass(&mousedev->mutex,
-                            minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
+                            minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
        init_waitqueue_head(&mousedev->wait);
 
        if (minor == MOUSEDEV_MIX)
index 3bfe8fafc6adac421577bc17c4da964537a4145f..6256233d2bfb12eef200e310da75f6a4e6468afc 100644 (file)
@@ -226,4 +226,13 @@ config SERIO_AMS_DELTA
          To compile this driver as a module, choose M here;
          the module will be called ams_delta_serio.
 
+config SERIO_PS2MULT
+       tristate "TQC PS/2 multiplexer"
+       help
+         Say Y here if you have the PS/2 line multiplexer like the one
+         present on TQC boads.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ps2mult.
+
 endif
index 84c80bf7185e6b58e992080d952ca2ff6afdc8c4..dbbe37616c92ece327bada8c39cde862aff6e196 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_SERIO_GSCPS2)    += gscps2.o
 obj-$(CONFIG_HP_SDC)           += hp_sdc.o
 obj-$(CONFIG_HIL_MLC)          += hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)     += pcips2.o
+obj-$(CONFIG_SERIO_PS2MULT)    += ps2mult.o
 obj-$(CONFIG_SERIO_MACEPS2)    += maceps2.o
 obj-$(CONFIG_SERIO_LIBPS2)     += libps2.o
 obj-$(CONFIG_SERIO_RAW)                += serio_raw.o
index f585131604806f531f91c48ebb867919339fd80f..18db5a8c747830516ded46abd66bb822edca2ab5 100644 (file)
@@ -1063,7 +1063,7 @@ static long i8042_panic_blink(int state)
 #ifdef CONFIG_X86
 static void i8042_dritek_enable(void)
 {
-       char param = 0x90;
+       unsigned char param = 0x90;
        int error;
 
        error = i8042_command(&param, 0x1059);
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
new file mode 100644 (file)
index 0000000..6bce22e
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * TQC PS/2 Multiplexer driver
+ *
+ * Copyright (C) 2010 Dmitry Eremin-Solenikov
+ *
+ * This program is free software; you can 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/slab.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
+MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
+MODULE_LICENSE("GPL");
+
+#define PS2MULT_KB_SELECTOR            0xA0
+#define PS2MULT_MS_SELECTOR            0xA1
+#define PS2MULT_ESCAPE                 0x7D
+#define PS2MULT_BSYNC                  0x7E
+#define PS2MULT_SESSION_START          0x55
+#define PS2MULT_SESSION_END            0x56
+
+struct ps2mult_port {
+       struct serio *serio;
+       unsigned char sel;
+       bool registered;
+};
+
+#define PS2MULT_NUM_PORTS      2
+#define PS2MULT_KBD_PORT       0
+#define PS2MULT_MOUSE_PORT     1
+
+struct ps2mult {
+       struct serio *mx_serio;
+       struct ps2mult_port ports[PS2MULT_NUM_PORTS];
+
+       spinlock_t lock;
+       struct ps2mult_port *in_port;
+       struct ps2mult_port *out_port;
+       bool escape;
+};
+
+/* First MUST come PS2MULT_NUM_PORTS selectors */
+static const unsigned char ps2mult_controls[] = {
+       PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
+       PS2MULT_ESCAPE, PS2MULT_BSYNC,
+       PS2MULT_SESSION_START, PS2MULT_SESSION_END,
+};
+
+static const struct serio_device_id ps2mult_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_PS2MULT,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
+
+static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
+{
+       struct serio *mx_serio = psm->mx_serio;
+
+       serio_write(mx_serio, port->sel);
+       psm->out_port = port;
+       dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
+}
+
+static int ps2mult_serio_write(struct serio *serio, unsigned char data)
+{
+       struct serio *mx_port = serio->parent;
+       struct ps2mult *psm = serio_get_drvdata(mx_port);
+       struct ps2mult_port *port = serio->port_data;
+       bool need_escape;
+       unsigned long flags;
+
+       spin_lock_irqsave(&psm->lock, flags);
+
+       if (psm->out_port != port)
+               ps2mult_select_port(psm, port);
+
+       need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
+
+       dev_dbg(&serio->dev,
+               "write: %s%02x\n", need_escape ? "ESC " : "", data);
+
+       if (need_escape)
+               serio_write(mx_port, PS2MULT_ESCAPE);
+
+       serio_write(mx_port, data);
+
+       spin_unlock_irqrestore(&psm->lock, flags);
+
+       return 0;
+}
+
+static int ps2mult_serio_start(struct serio *serio)
+{
+       struct ps2mult *psm = serio_get_drvdata(serio->parent);
+       struct ps2mult_port *port = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&psm->lock, flags);
+       port->registered = true;
+       spin_unlock_irqrestore(&psm->lock, flags);
+
+       return 0;
+}
+
+static void ps2mult_serio_stop(struct serio *serio)
+{
+       struct ps2mult *psm = serio_get_drvdata(serio->parent);
+       struct ps2mult_port *port = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&psm->lock, flags);
+       port->registered = false;
+       spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_create_port(struct ps2mult *psm, int i)
+{
+       struct serio *mx_serio = psm->mx_serio;
+       struct serio *serio;
+
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!serio)
+               return -ENOMEM;
+
+       strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
+       snprintf(serio->phys, sizeof(serio->phys),
+                "%s/port%d", mx_serio->phys, i);
+       serio->id.type = SERIO_8042;
+       serio->write = ps2mult_serio_write;
+       serio->start = ps2mult_serio_start;
+       serio->stop = ps2mult_serio_stop;
+       serio->parent = psm->mx_serio;
+       serio->port_data = &psm->ports[i];
+
+       psm->ports[i].serio = serio;
+
+       return 0;
+}
+
+static void ps2mult_reset(struct ps2mult *psm)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&psm->lock, flags);
+
+       serio_write(psm->mx_serio, PS2MULT_SESSION_END);
+       serio_write(psm->mx_serio, PS2MULT_SESSION_START);
+
+       ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
+
+       spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct ps2mult *psm;
+       int i;
+       int error;
+
+       if (!serio->write)
+               return -EINVAL;
+
+       psm = kzalloc(sizeof(*psm), GFP_KERNEL);
+       if (!psm)
+               return -ENOMEM;
+
+       spin_lock_init(&psm->lock);
+       psm->mx_serio = serio;
+
+       for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
+               psm->ports[i].sel = ps2mult_controls[i];
+               error = ps2mult_create_port(psm, i);
+               if (error)
+                       goto err_out;
+       }
+
+       psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
+
+       serio_set_drvdata(serio, psm);
+       error = serio_open(serio, drv);
+       if (error)
+               goto err_out;
+
+       ps2mult_reset(psm);
+
+       for (i = 0; i <  PS2MULT_NUM_PORTS; i++) {
+               struct serio *s = psm->ports[i].serio;
+
+               dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
+               serio_register_port(s);
+       }
+
+       return 0;
+
+err_out:
+       while (--i >= 0)
+               kfree(psm->ports[i].serio);
+       kfree(serio);
+       return error;
+}
+
+static void ps2mult_disconnect(struct serio *serio)
+{
+       struct ps2mult *psm = serio_get_drvdata(serio);
+
+       /* Note that serio core already take care of children ports */
+       serio_write(serio, PS2MULT_SESSION_END);
+       serio_close(serio);
+       kfree(psm);
+
+       serio_set_drvdata(serio, NULL);
+}
+
+static int ps2mult_reconnect(struct serio *serio)
+{
+       struct ps2mult *psm = serio_get_drvdata(serio);
+
+       ps2mult_reset(psm);
+
+       return 0;
+}
+
+static irqreturn_t ps2mult_interrupt(struct serio *serio,
+                                    unsigned char data, unsigned int dfl)
+{
+       struct ps2mult *psm = serio_get_drvdata(serio);
+       struct ps2mult_port *in_port;
+       unsigned long flags;
+
+       dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
+
+       spin_lock_irqsave(&psm->lock, flags);
+
+       if (psm->escape) {
+               psm->escape = false;
+               in_port = psm->in_port;
+               if (in_port->registered)
+                       serio_interrupt(in_port->serio, data, dfl);
+               goto out;
+       }
+
+       switch (data) {
+       case PS2MULT_ESCAPE:
+               dev_dbg(&serio->dev, "ESCAPE\n");
+               psm->escape = true;
+               break;
+
+       case PS2MULT_BSYNC:
+               dev_dbg(&serio->dev, "BSYNC\n");
+               psm->in_port = psm->out_port;
+               break;
+
+       case PS2MULT_SESSION_START:
+               dev_dbg(&serio->dev, "SS\n");
+               break;
+
+       case PS2MULT_SESSION_END:
+               dev_dbg(&serio->dev, "SE\n");
+               break;
+
+       case PS2MULT_KB_SELECTOR:
+               dev_dbg(&serio->dev, "KB\n");
+               psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
+               break;
+
+       case PS2MULT_MS_SELECTOR:
+               dev_dbg(&serio->dev, "MS\n");
+               psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
+               break;
+
+       default:
+               in_port = psm->in_port;
+               if (in_port->registered)
+                       serio_interrupt(in_port->serio, data, dfl);
+               break;
+       }
+
+ out:
+       spin_unlock_irqrestore(&psm->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static struct serio_driver ps2mult_drv = {
+       .driver         = {
+               .name   = "ps2mult",
+       },
+       .description    = "TQC PS/2 Multiplexer driver",
+       .id_table       = ps2mult_serio_ids,
+       .interrupt      = ps2mult_interrupt,
+       .connect        = ps2mult_connect,
+       .disconnect     = ps2mult_disconnect,
+       .reconnect      = ps2mult_reconnect,
+};
+
+static int __init ps2mult_init(void)
+{
+       return serio_register_driver(&ps2mult_drv);
+}
+
+static void __exit ps2mult_exit(void)
+{
+       serio_unregister_driver(&ps2mult_drv);
+}
+
+module_init(ps2mult_init);
+module_exit(ps2mult_exit);
index c3b626e9eae7c075cd7597779ddbef4becb731f6..405bf214527c33f08c40c04d60c5e863826dbcc7 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/slab.h>
 #include <linux/kthread.h>
 #include <linux/mutex.h>
-#include <linux/freezer.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -56,7 +55,7 @@ static struct bus_type serio_bus;
 static void serio_add_port(struct serio *serio);
 static int serio_reconnect_port(struct serio *serio);
 static void serio_disconnect_port(struct serio *serio);
-static void serio_reconnect_chain(struct serio *serio);
+static void serio_reconnect_subtree(struct serio *serio);
 static void serio_attach_driver(struct serio_driver *drv);
 
 static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
@@ -152,7 +151,7 @@ static void serio_find_driver(struct serio *serio)
 enum serio_event_type {
        SERIO_RESCAN_PORT,
        SERIO_RECONNECT_PORT,
-       SERIO_RECONNECT_CHAIN,
+       SERIO_RECONNECT_SUBTREE,
        SERIO_REGISTER_PORT,
        SERIO_ATTACH_DRIVER,
 };
@@ -292,8 +291,8 @@ static void serio_handle_event(void)
                        serio_find_driver(event->object);
                        break;
 
-               case SERIO_RECONNECT_CHAIN:
-                       serio_reconnect_chain(event->object);
+               case SERIO_RECONNECT_SUBTREE:
+                       serio_reconnect_subtree(event->object);
                        break;
 
                case SERIO_ATTACH_DRIVER:
@@ -330,12 +329,10 @@ static void serio_remove_pending_events(void *object)
 }
 
 /*
- * Destroy child serio port (if any) that has not been fully registered yet.
+ * Locate child serio port (if any) that has not been fully registered yet.
  *
- * Note that we rely on the fact that port can have only one child and therefore
- * only one child registration request can be pending. Additionally, children
- * are registered by driver's connect() handler so there can't be a grandchild
- * pending registration together with a child.
+ * Children are registered by driver's connect() handler so there can't be a
+ * grandchild pending registration together with a child.
  */
 static struct serio *serio_get_pending_child(struct serio *parent)
 {
@@ -449,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
        if (!strncmp(buf, "none", count)) {
                serio_disconnect_port(serio);
        } else if (!strncmp(buf, "reconnect", count)) {
-               serio_reconnect_chain(serio);
+               serio_reconnect_subtree(serio);
        } else if (!strncmp(buf, "rescan", count)) {
                serio_disconnect_port(serio);
                serio_find_driver(serio);
@@ -516,6 +513,8 @@ static void serio_init_port(struct serio *serio)
        __module_get(THIS_MODULE);
 
        INIT_LIST_HEAD(&serio->node);
+       INIT_LIST_HEAD(&serio->child_node);
+       INIT_LIST_HEAD(&serio->children);
        spin_lock_init(&serio->lock);
        mutex_init(&serio->drv_mutex);
        device_initialize(&serio->dev);
@@ -538,12 +537,13 @@ static void serio_init_port(struct serio *serio)
  */
 static void serio_add_port(struct serio *serio)
 {
+       struct serio *parent = serio->parent;
        int error;
 
-       if (serio->parent) {
-               serio_pause_rx(serio->parent);
-               serio->parent->child = serio;
-               serio_continue_rx(serio->parent);
+       if (parent) {
+               serio_pause_rx(parent);
+               list_add_tail(&serio->child_node, &parent->children);
+               serio_continue_rx(parent);
        }
 
        list_add_tail(&serio->node, &serio_list);
@@ -559,15 +559,14 @@ static void serio_add_port(struct serio *serio)
 }
 
 /*
- * serio_destroy_port() completes deregistration process and removes
+ * serio_destroy_port() completes unregistration process and removes
  * port from the system
  */
 static void serio_destroy_port(struct serio *serio)
 {
        struct serio *child;
 
-       child = serio_get_pending_child(serio);
-       if (child) {
+       while ((child = serio_get_pending_child(serio)) != NULL) {
                serio_remove_pending_events(child);
                put_device(&child->dev);
        }
@@ -577,7 +576,7 @@ static void serio_destroy_port(struct serio *serio)
 
        if (serio->parent) {
                serio_pause_rx(serio->parent);
-               serio->parent->child = NULL;
+               list_del_init(&serio->child_node);
                serio_continue_rx(serio->parent);
                serio->parent = NULL;
        }
@@ -609,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio)
 }
 
 /*
- * Reconnect serio port and all its children (re-initialize attached devices)
+ * Reconnect serio port and all its children (re-initialize attached
+ * devices).
  */
-static void serio_reconnect_chain(struct serio *serio)
+static void serio_reconnect_subtree(struct serio *root)
 {
+       struct serio *s = root;
+       int error;
+
        do {
-               if (serio_reconnect_port(serio)) {
-                       /* Ok, old children are now gone, we are done */
-                       break;
+               error = serio_reconnect_port(s);
+               if (!error) {
+                       /*
+                        * Reconnect was successful, move on to do the
+                        * first child.
+                        */
+                       if (!list_empty(&s->children)) {
+                               s = list_first_entry(&s->children,
+                                                    struct serio, child_node);
+                               continue;
+                       }
                }
-               serio = serio->child;
-       } while (serio);
+
+               /*
+                * Either it was a leaf node or reconnect failed and it
+                * became a leaf node. Continue reconnecting starting with
+                * the next sibling of the parent node.
+                */
+               while (s != root) {
+                       struct serio *parent = s->parent;
+
+                       if (!list_is_last(&s->child_node, &parent->children)) {
+                               s = list_entry(s->child_node.next,
+                                              struct serio, child_node);
+                               break;
+                       }
+
+                       s = parent;
+               }
+       } while (s != root);
 }
 
 /*
  * serio_disconnect_port() unbinds a port from its driver. As a side effect
- * all child ports are unbound and destroyed.
+ * all children ports are unbound and destroyed.
  */
 static void serio_disconnect_port(struct serio *serio)
 {
-       struct serio *s, *parent;
+       struct serio *s = serio;
+
+       /*
+        * Children ports should be disconnected and destroyed
+        * first; we travel the tree in depth-first order.
+        */
+       while (!list_empty(&serio->children)) {
+
+               /* Locate a leaf */
+               while (!list_empty(&s->children))
+                       s = list_first_entry(&s->children,
+                                            struct serio, child_node);
 
-       if (serio->child) {
                /*
-                * Children ports should be disconnected and destroyed
-                * first, staring with the leaf one, since we don't want
-                * to do recursion
+                * Prune this leaf node unless it is the one we
+                * started with.
                 */
-               for (s = serio; s->child; s = s->child)
-                       /* empty */;
-
-               do {
-                       parent = s->parent;
+               if (s != serio) {
+                       struct serio *parent = s->parent;
 
                        device_release_driver(&s->dev);
                        serio_destroy_port(s);
-               } while ((s = parent) != serio);
+
+                       s = parent;
+               }
        }
 
        /*
-        * Ok, no children left, now disconnect this port
+        * OK, no children left, now disconnect this port.
         */
        device_release_driver(&serio->dev);
 }
@@ -661,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan);
 
 void serio_reconnect(struct serio *serio)
 {
-       serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN);
+       serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE);
 }
 EXPORT_SYMBOL(serio_reconnect);
 
@@ -689,14 +724,16 @@ void serio_unregister_port(struct serio *serio)
 EXPORT_SYMBOL(serio_unregister_port);
 
 /*
- * Safely unregisters child port if one is present.
+ * Safely unregisters children ports if they are present.
  */
 void serio_unregister_child_port(struct serio *serio)
 {
+       struct serio *s, *next;
+
        mutex_lock(&serio_mutex);
-       if (serio->child) {
-               serio_disconnect_port(serio->child);
-               serio_destroy_port(serio->child);
+       list_for_each_entry_safe(s, next, &serio->children, child_node) {
+               serio_disconnect_port(s);
+               serio_destroy_port(s);
        }
        mutex_unlock(&serio_mutex);
 }
index 014248344763775b49285db0a480e794f5c76c2e..a29a7812bd46cea26613b813a3091eed476077aa 100644 (file)
@@ -22,6 +22,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.1");
 
+static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
+                                               const struct key_entry *k)
+{
+       struct key_entry *key;
+       unsigned int idx = 0;
+
+       for (key = dev->keycode; key->type != KE_END; key++) {
+               if (key->type == KE_KEY) {
+                       if (key == k)
+                               break;
+                       idx++;
+               }
+       }
+
+       return idx;
+}
+
+static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
+                                                     unsigned int index)
+{
+       struct key_entry *key;
+       unsigned int key_cnt = 0;
+
+       for (key = dev->keycode; key->type != KE_END; key++)
+               if (key->type == KE_KEY)
+                       if (key_cnt++ == index)
+                               return key;
+
+       return NULL;
+}
+
 /**
  * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
  * @dev: Input device using sparse keymap
@@ -64,16 +95,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
 }
 EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
 
+static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
+                                       const struct input_keymap_entry *ke)
+{
+       struct key_entry *key;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+               key = sparse_keymap_entry_by_index(dev, ke->index);
+       else if (input_scancode_to_scalar(ke, &scancode) == 0)
+               key = sparse_keymap_entry_from_scancode(dev, scancode);
+       else
+               key = NULL;
+
+       return key;
+}
+
 static int sparse_keymap_getkeycode(struct input_dev *dev,
-                                   unsigned int scancode,
-                                   unsigned int *keycode)
+                                   struct input_keymap_entry *ke)
 {
        const struct key_entry *key;
 
        if (dev->keycode) {
-               key = sparse_keymap_entry_from_scancode(dev, scancode);
+               key = sparse_keymap_locate(dev, ke);
                if (key && key->type == KE_KEY) {
-                       *keycode = key->keycode;
+                       ke->keycode = key->keycode;
+                       if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+                               ke->index =
+                                       sparse_keymap_get_key_index(dev, key);
+                       ke->len = sizeof(key->code);
+                       memcpy(ke->scancode, &key->code, sizeof(key->code));
                        return 0;
                }
        }
@@ -82,20 +133,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
 }
 
 static int sparse_keymap_setkeycode(struct input_dev *dev,
-                                   unsigned int scancode,
-                                   unsigned int keycode)
+                                   const struct input_keymap_entry *ke,
+                                   unsigned int *old_keycode)
 {
        struct key_entry *key;
-       int old_keycode;
 
        if (dev->keycode) {
-               key = sparse_keymap_entry_from_scancode(dev, scancode);
+               key = sparse_keymap_locate(dev, ke);
                if (key && key->type == KE_KEY) {
-                       old_keycode = key->keycode;
-                       key->keycode = keycode;
-                       set_bit(keycode, dev->keybit);
-                       if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
-                               clear_bit(old_keycode, dev->keybit);
+                       *old_keycode = key->keycode;
+                       key->keycode = ke->keycode;
+                       set_bit(ke->keycode, dev->keybit);
+                       if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
+                               clear_bit(*old_keycode, dev->keybit);
                        return 0;
                }
        }
@@ -159,15 +209,14 @@ int sparse_keymap_setup(struct input_dev *dev,
 
        dev->keycode = map;
        dev->keycodemax = map_size;
-       dev->getkeycode = sparse_keymap_getkeycode;
-       dev->setkeycode = sparse_keymap_setkeycode;
+       dev->getkeycode_new = sparse_keymap_getkeycode;
+       dev->setkeycode_new = sparse_keymap_setkeycode;
 
        return 0;
 
  err_out:
        kfree(map);
        return error;
-
 }
 EXPORT_SYMBOL(sparse_keymap_setup);
 
index effb49ea24aa4c6ec337e14cfa4336e4fd153345..58a87755b936eee386811396b9ba0ae418a3e0ea 100644 (file)
@@ -49,6 +49,17 @@ config TABLET_USB_GTCO
           To compile this driver as a module, choose M here: the
           module will be called gtco.
 
+config TABLET_USB_HANWANG
+       tristate "Hanwang Art Master III tablet support (USB)"
+       depends on USB_ARCH_HAS_HCD
+       select USB
+       help
+         Say Y here if you want to use the USB version of the Hanwang Art
+         Master III tablet.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hanwang.
+
 config TABLET_USB_KBTAB
        tristate "KB Gear JamStudio tablet support (USB)"
        depends on USB_ARCH_HAS_HCD
index ce8b9a9cfa40b2782cea9946fab26d039883a521..3f6c25220638c179de271d1145f25054a3fb137d 100644 (file)
@@ -8,5 +8,6 @@ wacom-objs      := wacom_wac.o wacom_sys.o
 obj-$(CONFIG_TABLET_USB_ACECAD)        += acecad.o
 obj-$(CONFIG_TABLET_USB_AIPTEK)        += aiptek.o
 obj-$(CONFIG_TABLET_USB_GTCO)  += gtco.o
+obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
 obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
 obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
new file mode 100644 (file)
index 0000000..6504b62
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ *  USB Hanwang tablet support
+ *
+ *  Copyright (c) 2010 Xing Wei <weixing@hanwang.com.cn>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_AUTHOR   "Xing Wei <weixing@hanwang.com.cn>"
+#define DRIVER_DESC     "USB Hanwang tablet driver"
+#define DRIVER_LICENSE  "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_HANWANG          0x0b57
+#define HANWANG_TABLET_INT_CLASS       0x0003
+#define HANWANG_TABLET_INT_SUB_CLASS   0x0001
+#define HANWANG_TABLET_INT_PROTOCOL    0x0002
+
+#define ART_MASTER_PKGLEN_MAX  10
+
+/* device IDs */
+#define STYLUS_DEVICE_ID       0x02
+#define TOUCH_DEVICE_ID                0x03
+#define CURSOR_DEVICE_ID       0x06
+#define ERASER_DEVICE_ID       0x0A
+#define PAD_DEVICE_ID          0x0F
+
+/* match vendor and interface info  */
+#define HANWANG_TABLET_DEVICE(vend, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR \
+               | USB_DEVICE_ID_MATCH_INT_INFO, \
+       .idVendor = (vend), \
+       .bInterfaceClass = (cl), \
+       .bInterfaceSubClass = (sc), \
+       .bInterfaceProtocol = (pr)
+
+enum hanwang_tablet_type {
+       HANWANG_ART_MASTER_III,
+       HANWANG_ART_MASTER_HD,
+};
+
+struct hanwang {
+       unsigned char *data;
+       dma_addr_t data_dma;
+       struct input_dev *dev;
+       struct usb_device *usbdev;
+       struct urb *irq;
+       const struct hanwang_features *features;
+       unsigned int current_tool;
+       unsigned int current_id;
+       char name[64];
+       char phys[32];
+};
+
+struct hanwang_features {
+       unsigned short pid;
+       char *name;
+       enum hanwang_tablet_type type;
+       int pkg_len;
+       int max_x;
+       int max_y;
+       int max_tilt_x;
+       int max_tilt_y;
+       int max_pressure;
+};
+
+static const struct hanwang_features features_array[] = {
+       { 0x8528, "Hanwang Art Master III 0906", HANWANG_ART_MASTER_III,
+         ART_MASTER_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 },
+       { 0x8529, "Hanwang Art Master III 0604", HANWANG_ART_MASTER_III,
+         ART_MASTER_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 },
+       { 0x852a, "Hanwang Art Master III 1308", HANWANG_ART_MASTER_III,
+         ART_MASTER_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 },
+       { 0x8401, "Hanwang Art Master HD 5012", HANWANG_ART_MASTER_HD,
+         ART_MASTER_PKGLEN_MAX, 0x678e, 0x4150, 0x3f, 0x7f, 1024 },
+};
+
+static const int hw_eventtypes[] = {
+       EV_KEY, EV_ABS, EV_MSC,
+};
+
+static const int hw_absevents[] = {
+       ABS_X, ABS_Y, ABS_TILT_X, ABS_TILT_Y, ABS_WHEEL,
+       ABS_RX, ABS_RY, ABS_PRESSURE, ABS_MISC,
+};
+
+static const int hw_btnevents[] = {
+       BTN_STYLUS, BTN_STYLUS2, BTN_TOOL_PEN, BTN_TOOL_RUBBER,
+       BTN_TOOL_MOUSE, BTN_TOOL_FINGER,
+       BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8,
+};
+
+static const int hw_mscevents[] = {
+       MSC_SERIAL,
+};
+
+static void hanwang_parse_packet(struct hanwang *hanwang)
+{
+       unsigned char *data = hanwang->data;
+       struct input_dev *input_dev = hanwang->dev;
+       struct usb_device *dev = hanwang->usbdev;
+       enum hanwang_tablet_type type = hanwang->features->type;
+       int i;
+       u16 x, y, p;
+
+       switch (data[0]) {
+       case 0x02:      /* data packet */
+               switch (data[1]) {
+               case 0x80:      /* tool prox out */
+                       hanwang->current_id = 0;
+                       input_report_key(input_dev, hanwang->current_tool, 0);
+                       break;
+
+               case 0xc2:      /* first time tool prox in */
+                       switch (data[3] & 0xf0) {
+                       case 0x20:      /* art_master III */
+                       case 0x30:      /* art_master_HD */
+                               hanwang->current_id = STYLUS_DEVICE_ID;
+                               hanwang->current_tool = BTN_TOOL_PEN;
+                               input_report_key(input_dev, BTN_TOOL_PEN, 1);
+                               break;
+                       case 0xa0:      /* art_master III */
+                       case 0xb0:      /* art_master_HD */
+                               hanwang->current_id = ERASER_DEVICE_ID;
+                               hanwang->current_tool = BTN_TOOL_RUBBER;
+                               input_report_key(input_dev, BTN_TOOL_RUBBER, 1);
+                               break;
+                       default:
+                               hanwang->current_id = 0;
+                               dev_dbg(&dev->dev,
+                                       "unknown tablet tool %02x ", data[0]);
+                               break;
+                       }
+                       break;
+
+               default:        /* tool data packet */
+                       x = (data[2] << 8) | data[3];
+                       y = (data[4] << 8) | data[5];
+
+                       switch (type) {
+                       case HANWANG_ART_MASTER_III:
+                               p = (data[6] << 3) |
+                                   ((data[7] & 0xc0) >> 5) |
+                                   (data[1] & 0x01);
+                               break;
+
+                       case HANWANG_ART_MASTER_HD:
+                               p = (data[7] >> 6) | (data[6] << 2);
+                               break;
+
+                       default:
+                               p = 0;
+                               break;
+                       }
+
+                       input_report_abs(input_dev, ABS_X,
+                                               le16_to_cpup((__le16 *)&x));
+                       input_report_abs(input_dev, ABS_Y,
+                                               le16_to_cpup((__le16 *)&y));
+                       input_report_abs(input_dev, ABS_PRESSURE,
+                                               le16_to_cpup((__le16 *)&p));
+                       input_report_abs(input_dev, ABS_TILT_X, data[7] & 0x3f);
+                       input_report_abs(input_dev, ABS_TILT_Y, data[8] & 0x7f);
+                       input_report_key(input_dev, BTN_STYLUS, data[1] & 0x02);
+                       input_report_key(input_dev, BTN_STYLUS2, data[1] & 0x04);
+                       break;
+               }
+               input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+               input_event(input_dev, EV_MSC, MSC_SERIAL,
+                               hanwang->features->pid);
+               break;
+
+       case 0x0c:
+               /* roll wheel */
+               hanwang->current_id = PAD_DEVICE_ID;
+
+               switch (type) {
+               case HANWANG_ART_MASTER_III:
+                       input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+                                                       data[2] || data[3]);
+                       input_report_abs(input_dev, ABS_WHEEL, data[1]);
+                       input_report_key(input_dev, BTN_0, data[2]);
+                       for (i = 0; i < 8; i++)
+                               input_report_key(input_dev,
+                                        BTN_1 + i, data[3] & (1 << i));
+                       break;
+
+               case HANWANG_ART_MASTER_HD:
+                       input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+                                       data[2] || data[3] || data[4] ||
+                                       data[5] || data[6]);
+                       input_report_abs(input_dev, ABS_RX,
+                                       ((data[1] & 0x1f) << 8) | data[2]);
+                       input_report_abs(input_dev, ABS_RY,
+                                       ((data[3] & 0x1f) << 8) | data[4]);
+                       input_report_key(input_dev, BTN_0, data[5] & 0x01);
+                       for (i = 0; i < 4; i++) {
+                               input_report_key(input_dev,
+                                        BTN_1 + i, data[5] & (1 << i));
+                               input_report_key(input_dev,
+                                        BTN_5 + i, data[6] & (1 << i));
+                       }
+                       break;
+               }
+
+               input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+               input_event(input_dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+               break;
+
+       default:
+               dev_dbg(&dev->dev, "error packet  %02x ", data[0]);
+               break;
+       }
+
+       input_sync(input_dev);
+}
+
+static void hanwang_irq(struct urb *urb)
+{
+       struct hanwang *hanwang = urb->context;
+       struct usb_device *dev = hanwang->usbdev;
+       int retval;
+
+       switch (urb->status) {
+       case 0:
+               /* success */;
+               hanwang_parse_packet(hanwang);
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dev_err(&dev->dev, "%s - urb shutting down with status: %d",
+                       __func__, urb->status);
+               return;
+       default:
+               dev_err(&dev->dev, "%s - nonzero urb status received: %d",
+                       __func__, urb->status);
+               break;
+       }
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d",
+                       __func__, retval);
+}
+
+static int hanwang_open(struct input_dev *dev)
+{
+       struct hanwang *hanwang = input_get_drvdata(dev);
+
+       hanwang->irq->dev = hanwang->usbdev;
+       if (usb_submit_urb(hanwang->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void hanwang_close(struct input_dev *dev)
+{
+       struct hanwang *hanwang = input_get_drvdata(dev);
+
+       usb_kill_urb(hanwang->irq);
+}
+
+static bool get_features(struct usb_device *dev, struct hanwang *hanwang)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(features_array); i++) {
+               if (le16_to_cpu(dev->descriptor.idProduct) ==
+                               features_array[i].pid) {
+                       hanwang->features = &features_array[i];
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
+static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *endpoint;
+       struct hanwang *hanwang;
+       struct input_dev *input_dev;
+       int error;
+       int i;
+
+       hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!hanwang || !input_dev) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       if (!get_features(dev, hanwang)) {
+               error = -ENXIO;
+               goto fail1;
+       }
+
+       hanwang->data = usb_alloc_coherent(dev, hanwang->features->pkg_len,
+                                       GFP_KERNEL, &hanwang->data_dma);
+       if (!hanwang->data) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       hanwang->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!hanwang->irq) {
+               error = -ENOMEM;
+               goto fail2;
+       }
+
+       hanwang->usbdev = dev;
+       hanwang->dev = input_dev;
+
+       usb_make_path(dev, hanwang->phys, sizeof(hanwang->phys));
+       strlcat(hanwang->phys, "/input0", sizeof(hanwang->phys));
+
+       strlcpy(hanwang->name, hanwang->features->name, sizeof(hanwang->name));
+       input_dev->name = hanwang->name;
+       input_dev->phys = hanwang->phys;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, hanwang);
+
+       input_dev->open = hanwang_open;
+       input_dev->close = hanwang_close;
+
+       for (i = 0; i < ARRAY_SIZE(hw_eventtypes); ++i)
+               __set_bit(hw_eventtypes[i], input_dev->evbit);
+
+       for (i = 0; i < ARRAY_SIZE(hw_absevents); ++i)
+               __set_bit(hw_absevents[i], input_dev->absbit);
+
+       for (i = 0; i < ARRAY_SIZE(hw_btnevents); ++i)
+               __set_bit(hw_btnevents[i], input_dev->keybit);
+
+       for (i = 0; i < ARRAY_SIZE(hw_mscevents); ++i)
+               __set_bit(hw_mscevents[i], input_dev->mscbit);
+
+       input_set_abs_params(input_dev, ABS_X,
+                            0, hanwang->features->max_x, 4, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                            0, hanwang->features->max_y, 4, 0);
+       input_set_abs_params(input_dev, ABS_TILT_X,
+                            0, hanwang->features->max_tilt_x, 0, 0);
+       input_set_abs_params(input_dev, ABS_TILT_Y,
+                            0, hanwang->features->max_tilt_y, 0, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE,
+                            0, hanwang->features->max_pressure, 0, 0);
+
+       endpoint = &intf->cur_altsetting->endpoint[0].desc;
+       usb_fill_int_urb(hanwang->irq, dev,
+                       usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+                       hanwang->data, hanwang->features->pkg_len,
+                       hanwang_irq, hanwang, endpoint->bInterval);
+       hanwang->irq->transfer_dma = hanwang->data_dma;
+       hanwang->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       error = input_register_device(hanwang->dev);
+       if (error)
+               goto fail3;
+
+       usb_set_intfdata(intf, hanwang);
+
+       return 0;
+
+ fail3:        usb_free_urb(hanwang->irq);
+ fail2:        usb_free_coherent(dev, hanwang->features->pkg_len,
+                       hanwang->data, hanwang->data_dma);
+ fail1:        input_free_device(input_dev);
+       kfree(hanwang);
+       return error;
+
+}
+
+static void hanwang_disconnect(struct usb_interface *intf)
+{
+       struct hanwang *hanwang = usb_get_intfdata(intf);
+
+       input_unregister_device(hanwang->dev);
+       usb_free_urb(hanwang->irq);
+       usb_free_coherent(interface_to_usbdev(intf),
+                       hanwang->features->pkg_len, hanwang->data,
+                       hanwang->data_dma);
+       kfree(hanwang);
+       usb_set_intfdata(intf, NULL);
+}
+
+static const struct usb_device_id hanwang_ids[] = {
+       { HANWANG_TABLET_DEVICE(USB_VENDOR_ID_HANWANG, HANWANG_TABLET_INT_CLASS,
+               HANWANG_TABLET_INT_SUB_CLASS, HANWANG_TABLET_INT_PROTOCOL) },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, hanwang_ids);
+
+static struct usb_driver hanwang_driver = {
+       .name           = "hanwang",
+       .probe          = hanwang_probe,
+       .disconnect     = hanwang_disconnect,
+       .id_table       = hanwang_ids,
+};
+
+static int __init hanwang_init(void)
+{
+       return usb_register(&hanwang_driver);
+}
+
+static void __exit hanwang_exit(void)
+{
+       usb_deregister(&hanwang_driver);
+}
+
+module_init(hanwang_init);
+module_exit(hanwang_exit);
index 284dfaab6b8cc67d375ca2c1de8aa639bbc6aaae..de5adb109030640d4ccde73787582ccef97d323a 100644 (file)
@@ -118,6 +118,7 @@ struct wacom {
 extern const struct usb_device_id wacom_ids[];
 
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
+void wacom_setup_device_quirks(struct wacom_features *features);
 void wacom_setup_input_capabilities(struct input_dev *input_dev,
                                    struct wacom_wac *wacom_wac);
 #endif
index b35876ee6908c7328f29e2505fd29a94a61b2d61..fc381498b79879551b697e05d24050020b7f220e 100644 (file)
@@ -120,14 +120,16 @@ static int wacom_open(struct input_dev *dev)
 
 out:
        mutex_unlock(&wacom->lock);
-       if (retval)
-               usb_autopm_put_interface(wacom->intf);
+       usb_autopm_put_interface(wacom->intf);
        return retval;
 }
 
 static void wacom_close(struct input_dev *dev)
 {
        struct wacom *wacom = input_get_drvdata(dev);
+       int autopm_error;
+
+       autopm_error = usb_autopm_get_interface(wacom->intf);
 
        mutex_lock(&wacom->lock);
        usb_kill_urb(wacom->irq);
@@ -135,7 +137,8 @@ static void wacom_close(struct input_dev *dev)
        wacom->intf->needs_remote_wakeup = 0;
        mutex_unlock(&wacom->lock);
 
-       usb_autopm_put_interface(wacom->intf);
+       if (!autopm_error)
+               usb_autopm_put_interface(wacom->intf);
 }
 
 static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
@@ -196,17 +199,30 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
                                                        features->device_type = BTN_TOOL_TRIPLETAP;
                                                }
-                                               features->x_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->x_phy =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               features->unit = report[i + 9];
-                                               features->unitExpo = report[i + 11];
-                                               i += 12;
+                                               if (features->type == BAMBOO_PT) {
+                                                       /* need to reset back */
+                                                       features->pktlen = WACOM_PKGLEN_BBTOUCH;
+                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->x_phy =
+                                                               get_unaligned_le16(&report[i + 5]);
+                                                       features->x_max =
+                                                               get_unaligned_le16(&report[i + 8]);
+                                                       i += 15;
+                                               } else {
+                                                       features->x_max =
+                                                               get_unaligned_le16(&report[i + 3]);
+                                                       features->x_phy =
+                                                               get_unaligned_le16(&report[i + 6]);
+                                                       features->unit = report[i + 9];
+                                                       features->unitExpo = report[i + 11];
+                                                       i += 12;
+                                               }
                                        } else if (pen) {
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+                                               if (features->type == BAMBOO_PT)
+                                                       features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->x_max =
                                                        get_unaligned_le16(&report[i + 3]);
@@ -235,6 +251,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 6]);
                                                        i += 7;
+                                               } else if (features->type == BAMBOO_PT) {
+                                                       /* need to reset back */
+                                                       features->pktlen = WACOM_PKGLEN_BBTOUCH;
+                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->y_phy =
+                                                               get_unaligned_le16(&report[i + 3]);
+                                                       features->y_max =
+                                                               get_unaligned_le16(&report[i + 6]);
+                                                       i += 12;
                                                } else {
                                                        features->y_max =
                                                                features->x_max;
@@ -246,6 +271,8 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+                                               if (features->type == BAMBOO_PT)
+                                                       features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->y_max =
                                                        get_unaligned_le16(&report[i + 3]);
@@ -296,8 +323,9 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
        if (!rep_data)
                return error;
 
-       /* ask to report tablet data if it is 2FGT or not a Tablet PC */
-       if (features->device_type == BTN_TOOL_TRIPLETAP) {
+       /* ask to report tablet data if it is 2FGT Tablet PC or
+        * not a Tablet PC */
+       if (features->type == TABLETPC2FG) {
                do {
                        rep_data[0] = 3;
                        rep_data[1] = 4;
@@ -309,7 +337,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
                                        WAC_HID_FEATURE_REPORT, report_id,
                                        rep_data, 3);
                } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
-       } else if (features->type != TABLETPC && features->type != TABLETPC2FG) {
+       } else if (features->type != TABLETPC) {
                do {
                        rep_data[0] = 2;
                        rep_data[1] = 2;
@@ -334,11 +362,16 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
        struct usb_host_interface *interface = intf->cur_altsetting;
        struct hid_descriptor *hid_desc;
 
-       /* default device to penabled */
+       /* default features */
        features->device_type = BTN_TOOL_PEN;
-
-       /* only Tablet PCs need to retrieve the info */
-       if ((features->type != TABLETPC) && (features->type != TABLETPC2FG))
+       features->x_fuzz = 4;
+       features->y_fuzz = 4;
+       features->pressure_fuzz = 0;
+       features->distance_fuzz = 0;
+
+       /* only Tablet PCs and Bamboo P&T need to retrieve the info */
+       if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
+           (features->type != BAMBOO_PT))
                goto out;
 
        if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
@@ -353,12 +386,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
        if (error)
                goto out;
 
-       /* touch device found but size is not defined. use default */
-       if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
-               features->x_max = 1023;
-               features->y_max = 1023;
-       }
-
  out:
        return error;
 }
@@ -494,9 +521,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (error)
                goto fail2;
 
+       wacom_setup_device_quirks(features);
+
        strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
 
-       if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+       if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
                /* Append the device type to the name */
                strlcat(wacom_wac->name,
                        features->device_type == BTN_TOOL_PEN ?
index 47fd7a041c52e1898a8727c5386569fb3caed45c..b3252ef1e2797e6b7f640322bb8cbf4a6ecc61bd 100644 (file)
@@ -857,6 +857,134 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
        return retval;
 }
 
+static int wacom_bpt_touch(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int sp = 0, sx = 0, sy = 0, count = 0;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               int p = data[9 * i + 2];
+               input_mt_slot(input, i);
+               /*
+                * Touch events need to be disabled while stylus is
+                * in proximity because user's hand is resting on touchpad
+                * and sending unwanted events.  User expects tablet buttons
+                * to continue working though.
+                */
+               if (p && !wacom->shared->stylus_in_proximity) {
+                       int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
+                       int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
+                       if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
+                               x <<= 5;
+                               y <<= 5;
+                       }
+                       input_report_abs(input, ABS_MT_PRESSURE, p);
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       if (wacom->id[i] < 0)
+                               wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
+                       if (!count++)
+                               sp = p, sx = x, sy = y;
+               } else {
+                       wacom->id[i] = -1;
+               }
+               input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
+       }
+
+       input_report_key(input, BTN_TOUCH, count > 0);
+       input_report_key(input, BTN_TOOL_FINGER, count == 1);
+       input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
+
+       input_report_abs(input, ABS_PRESSURE, sp);
+       input_report_abs(input, ABS_X, sx);
+       input_report_abs(input, ABS_Y, sy);
+
+       input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
+       input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
+       input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
+       input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
+
+       input_sync(input);
+
+       return 0;
+}
+
+static int wacom_bpt_pen(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
+
+       /*
+        * Similar to Graphire protocol, data[1] & 0x20 is proximity and
+        * data[1] & 0x18 is tool ID.  0x30 is safety check to ignore
+        * 2 unused tool ID's.
+        */
+       prox = (data[1] & 0x30) == 0x30;
+
+       /*
+        * All reports shared between PEN and RUBBER tool must be
+        * forced to a known starting value (zero) when transitioning to
+        * out-of-prox.
+        *
+        * If not reset then, to userspace, it will look like lost events
+        * if new tool comes in-prox with same values as previous tool sent.
+        *
+        * Hardware does report zero in most out-of-prox cases but not all.
+        */
+       if (prox) {
+               if (!wacom->shared->stylus_in_proximity) {
+                       if (data[1] & 0x08) {
+                               wacom->tool[0] = BTN_TOOL_RUBBER;
+                               wacom->id[0] = ERASER_DEVICE_ID;
+                       } else {
+                               wacom->tool[0] = BTN_TOOL_PEN;
+                               wacom->id[0] = STYLUS_DEVICE_ID;
+                       }
+                       wacom->shared->stylus_in_proximity = true;
+               }
+               x = le16_to_cpup((__le16 *)&data[2]);
+               y = le16_to_cpup((__le16 *)&data[4]);
+               p = le16_to_cpup((__le16 *)&data[6]);
+               d = data[8];
+               pen = data[1] & 0x01;
+               btn1 = data[1] & 0x02;
+               btn2 = data[1] & 0x04;
+       }
+
+       input_report_key(input, BTN_TOUCH, pen);
+       input_report_key(input, BTN_STYLUS, btn1);
+       input_report_key(input, BTN_STYLUS2, btn2);
+
+       input_report_abs(input, ABS_X, x);
+       input_report_abs(input, ABS_Y, y);
+       input_report_abs(input, ABS_PRESSURE, p);
+       input_report_abs(input, ABS_DISTANCE, d);
+
+       if (!prox) {
+               wacom->id[0] = 0;
+               wacom->shared->stylus_in_proximity = false;
+       }
+
+       input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
+       input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
+
+       return 1;
+}
+
+static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
+{
+       if (len == WACOM_PKGLEN_BBTOUCH)
+               return wacom_bpt_touch(wacom);
+       else if (len == WACOM_PKGLEN_BBFUN)
+               return wacom_bpt_pen(wacom);
+
+       return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        bool sync;
@@ -902,6 +1030,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                sync = wacom_tpc_irq(wacom_wac, len);
                break;
 
+       case BAMBOO_PT:
+               sync = wacom_bpt_irq(wacom_wac, len);
+               break;
+
        default:
                sync = false;
                break;
@@ -911,26 +1043,17 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                input_sync(wacom_wac->input);
 }
 
-static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
 {
        struct input_dev *input_dev = wacom_wac->input;
 
        input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
-       input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
-       __set_bit(BTN_LEFT, input_dev->keybit);
-       __set_bit(BTN_RIGHT, input_dev->keybit);
-       __set_bit(BTN_MIDDLE, input_dev->keybit);
-       __set_bit(BTN_SIDE, input_dev->keybit);
-       __set_bit(BTN_EXTRA, input_dev->keybit);
 
        __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
        __set_bit(BTN_TOOL_PEN, input_dev->keybit);
-       __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
        __set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
        __set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
        __set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
-       __set_bit(BTN_TOOL_LENS, input_dev->keybit);
        __set_bit(BTN_STYLUS, input_dev->keybit);
        __set_bit(BTN_STYLUS2, input_dev->keybit);
 
@@ -939,10 +1062,55 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
        input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
        input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
        input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+}
+
+static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+{
+       struct input_dev *input_dev = wacom_wac->input;
+
+       input_set_capability(input_dev, EV_REL, REL_WHEEL);
+
+       wacom_setup_cintiq(wacom_wac);
+
+       __set_bit(BTN_LEFT, input_dev->keybit);
+       __set_bit(BTN_RIGHT, input_dev->keybit);
+       __set_bit(BTN_MIDDLE, input_dev->keybit);
+       __set_bit(BTN_SIDE, input_dev->keybit);
+       __set_bit(BTN_EXTRA, input_dev->keybit);
+       __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
+       __set_bit(BTN_TOOL_LENS, input_dev->keybit);
+
        input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
        input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
 }
 
+void wacom_setup_device_quirks(struct wacom_features *features)
+{
+
+       /* touch device found but size is not defined. use default */
+       if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+               features->x_max = 1023;
+               features->y_max = 1023;
+       }
+
+       /* these device have multiple inputs */
+       if (features->type == TABLETPC || features->type == TABLETPC2FG ||
+           features->type == BAMBOO_PT)
+               features->quirks |= WACOM_QUIRK_MULTI_INPUT;
+
+       /* quirks for bamboo touch */
+       if (features->type == BAMBOO_PT &&
+           features->device_type == BTN_TOOL_TRIPLETAP) {
+               features->x_max <<= 5;
+               features->y_max <<= 5;
+               features->x_fuzz <<= 5;
+               features->y_fuzz <<= 5;
+               features->pressure_max = 256;
+               features->pressure_fuzz = 16;
+               features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
+       }
+}
+
 void wacom_setup_input_capabilities(struct input_dev *input_dev,
                                    struct wacom_wac *wacom_wac)
 {
@@ -953,9 +1121,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 
        __set_bit(BTN_TOUCH, input_dev->keybit);
 
-       input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
+                            features->x_fuzz, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
+                            features->y_fuzz, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
+                            features->pressure_fuzz, 0);
 
        __set_bit(ABS_MISC, input_dev->absbit);
 
@@ -1005,9 +1176,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                __set_bit(BTN_9, input_dev->keybit);
                /* fall through */
 
+       case CINTIQ:
+               for (i = 0; i < 8; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+               __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+               input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+               wacom_setup_cintiq(wacom_wac);
+               break;
+
        case INTUOS3:
        case INTUOS3L:
-       case CINTIQ:
                __set_bit(BTN_4, input_dev->keybit);
                __set_bit(BTN_5, input_dev->keybit);
                __set_bit(BTN_6, input_dev->keybit);
@@ -1078,6 +1259,38 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case PENPARTNER:
                __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                break;
+
+       case BAMBOO_PT:
+               __clear_bit(ABS_MISC, input_dev->absbit);
+
+               if (features->device_type == BTN_TOOL_TRIPLETAP) {
+                       __set_bit(BTN_LEFT, input_dev->keybit);
+                       __set_bit(BTN_FORWARD, input_dev->keybit);
+                       __set_bit(BTN_BACK, input_dev->keybit);
+                       __set_bit(BTN_RIGHT, input_dev->keybit);
+
+                       __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+                       __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+
+                       input_mt_create_slots(input_dev, 2);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                            0, features->x_max,
+                                            features->x_fuzz, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                            0, features->y_max,
+                                            features->y_fuzz, 0);
+                       input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+                                            0, features->pressure_max,
+                                            features->pressure_fuzz, 0);
+                       input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
+                                            MAX_TRACKING_ID, 0, 0);
+               } else if (features->device_type == BTN_TOOL_PEN) {
+                       __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+                       __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+                       __set_bit(BTN_STYLUS, input_dev->keybit);
+                       __set_bit(BTN_STYLUS2, input_dev->keybit);
+               }
+               break;
        }
 }
 
@@ -1215,6 +1428,14 @@ static const struct wacom_features wacom_features_0xE3 =
        { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG };
 static const struct wacom_features wacom_features_0x47 =
        { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+static struct wacom_features wacom_features_0xD0 =
+       { "Wacom Bamboo 2FG",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD1 =
+       { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN,     14720,  9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD2 =
+       { "Wacom Bamboo Craft",   WACOM_PKGLEN_BBFUN,     14720,  9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD3 =
+       { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13530, 1023, 63, BAMBOO_PT };
 
 #define USB_DEVICE_WACOM(prod)                                 \
        USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
@@ -1279,6 +1500,10 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xC6) },
        { USB_DEVICE_WACOM(0xC7) },
        { USB_DEVICE_WACOM(0xCE) },
+       { USB_DEVICE_WACOM(0xD0) },
+       { USB_DEVICE_WACOM(0xD1) },
+       { USB_DEVICE_WACOM(0xD2) },
+       { USB_DEVICE_WACOM(0xD3) },
        { USB_DEVICE_WACOM(0xF0) },
        { USB_DEVICE_WACOM(0xCC) },
        { USB_DEVICE_WACOM(0x90) },
index 99e1a54cd305fa3dce303670f44973dd82d273f9..00ca01541d89e86e210c34efc184e3b385dee096 100644 (file)
@@ -21,6 +21,7 @@
 #define WACOM_PKGLEN_INTUOS    10
 #define WACOM_PKGLEN_TPC1FG     5
 #define WACOM_PKGLEN_TPC2FG    14
+#define WACOM_PKGLEN_BBTOUCH   20
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
 #define WACOM_REPORT_TPC1FG            6
 #define WACOM_REPORT_TPC2FG            13
 
+/* device quirks */
+#define WACOM_QUIRK_MULTI_INPUT                0x0001
+#define WACOM_QUIRK_BBTOUCH_LOWRES     0x0002
+
+/* largest reported tracking id */
+#define MAX_TRACKING_ID                        0xfff
+
 enum {
        PENPARTNER = 0,
        GRAPHIRE,
@@ -44,6 +52,7 @@ enum {
        PTU,
        PL,
        DTU,
+       BAMBOO_PT,
        INTUOS,
        INTUOS3S,
        INTUOS3,
@@ -73,6 +82,11 @@ struct wacom_features {
        int y_phy;
        unsigned char unit;
        unsigned char unitExpo;
+       int x_fuzz;
+       int y_fuzz;
+       int pressure_fuzz;
+       int distance_fuzz;
+       unsigned quirks;
 };
 
 struct wacom_shared {
@@ -86,6 +100,7 @@ struct wacom_wac {
        int id[3];
        __u32 serial[2];
        int last_finger;
+       int trk_id;
        struct wacom_features features;
        struct wacom_shared *shared;
        struct input_dev *input;
index 0069d9703fda82c94409bae95e64e6be2faac4ac..06ea8da95c62b074d9f2320805c3faf93cb8f0c0 100644 (file)
@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY
          To compile this driver as a module, choose M here: the
          module will be called h3600_ts_input.
 
+config TOUCHSCREEN_BU21013
+       tristate "BU21013 based touch panel controllers"
+       depends on I2C
+       help
+         Say Y here if you have a bu21013 touchscreen connected to
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bu21013_ts.
+
 config TOUCHSCREEN_CY8CTMG110
        tristate "cy8ctmg110 touchscreen"
        depends on I2C
@@ -214,6 +226,16 @@ config TOUCHSCREEN_WACOM_W8001
          To compile this driver as a module, choose M here: the
          module will be called wacom_w8001.
 
+config TOUCHSCREEN_LPC32XX
+       tristate "LPC32XX touchscreen controller"
+       depends on ARCH_LPC32XX
+       help
+         Say Y here if you have a LPC32XX device and want
+         to support the built-in touchscreen.
+
+         To compile this driver as a module, choose M here: the
+         module will be called lpc32xx_ts.
+
 config TOUCHSCREEN_MCS5000
        tristate "MELFAS MCS-5000 touchscreen"
        depends on I2C
@@ -250,6 +272,18 @@ config TOUCHSCREEN_INEXIO
          To compile this driver as a module, choose M here: the
          module will be called inexio.
 
+config TOUCHSCREEN_INTEL_MID
+       tristate "Intel MID platform resistive touchscreen"
+       depends on INTEL_SCU_IPC
+       help
+         Say Y here if you have a Intel MID based touchscreen in
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called intel_mid_touch.
+
 config TOUCHSCREEN_MK712
        tristate "ICS MicroClock MK712 touchscreen"
        help
@@ -328,6 +362,15 @@ config TOUCHSCREEN_MIGOR
          To compile this driver as a module, choose M here: the
          module will be called migor_ts.
 
+config TOUCHSCREEN_TNETV107X
+       tristate "TI TNETV107X touchscreen support"
+       depends on ARCH_DAVINCI_TNETV107X
+       help
+         Say Y here if you want to use the TNETV107X touchscreen.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tnetv107x-ts.
+
 config TOUCHSCREEN_TOUCHRIGHT
        tristate "Touchright serial touchscreen"
        select SERIO
index 28217e1dcafd9687e8e46fa4ab41e6c374f8706b..7cc1b4f4b677db6631f0f68f6f0f34ad5299b8ab 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)  += ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)      += ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)                += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)   += cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)       += da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)      += dynapro.o
@@ -23,6 +24,8 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)                += eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)       += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)    += intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_LPC32XX)      += lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)      += mc13783_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MCS5000)      += mcs5000_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)                += migor_ts.o
@@ -37,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)    += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_QT602240)     += qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TNETV107X)    += tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
index 5f0221cffef9bf12821ed9fd38d63bac0df720dc..a1952fcc083e14a68694b5f69c64359588818b2c 100644 (file)
@@ -191,13 +191,12 @@ struct ad7877 {
        struct spi_message      msg;
 
        struct mutex            mutex;
-       unsigned                disabled:1;     /* P: mutex */
-       unsigned                gpio3:1;        /* P: mutex */
-       unsigned                gpio4:1;        /* P: mutex */
+       bool                    disabled;       /* P: mutex */
+       bool                    gpio3;          /* P: mutex */
+       bool                    gpio4;          /* P: mutex */
 
        spinlock_t              lock;
        struct timer_list       timer;          /* P: lock */
-       unsigned                pending:1;      /* P: lock */
 
        /*
         * DMA (thus cache coherency maintenance) requires the
@@ -206,8 +205,8 @@ struct ad7877 {
        u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
 };
 
-static int gpio3;
-module_param(gpio3, int, 0);
+static bool gpio3;
+module_param(gpio3, bool, 0);
 MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
 
 /*
@@ -230,6 +229,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg)
                        AD7877_READADD(reg));
        req->xfer[0].tx_buf = &req->command;
        req->xfer[0].len = 2;
+       req->xfer[0].cs_change = 1;
 
        req->xfer[1].rx_buf = &req->sample;
        req->xfer[1].len = 2;
@@ -295,20 +295,25 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
 
        req->xfer[0].tx_buf = &req->reset;
        req->xfer[0].len = 2;
+       req->xfer[0].cs_change = 1;
 
        req->xfer[1].tx_buf = &req->ref_on;
        req->xfer[1].len = 2;
        req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+       req->xfer[1].cs_change = 1;
 
        req->xfer[2].tx_buf = &req->command;
        req->xfer[2].len = 2;
        req->xfer[2].delay_usecs = ts->vref_delay_usecs;
+       req->xfer[2].cs_change = 1;
 
        req->xfer[3].rx_buf = &req->sample;
        req->xfer[3].len = 2;
+       req->xfer[3].cs_change = 1;
 
        req->xfer[4].tx_buf = &ts->cmd_crtl2;   /*REF OFF*/
        req->xfer[4].len = 2;
+       req->xfer[4].cs_change = 1;
 
        req->xfer[5].tx_buf = &ts->cmd_crtl1;   /*DEFAULT*/
        req->xfer[5].len = 2;
@@ -327,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
        return status ? : sample;
 }
 
-static void ad7877_rx(struct ad7877 *ts)
+static int ad7877_process_data(struct ad7877 *ts)
 {
        struct input_dev *input_dev = ts->input;
        unsigned Rt;
@@ -354,11 +359,25 @@ static void ad7877_rx(struct ad7877 *ts)
                Rt /= z1;
                Rt = (Rt + 2047) >> 12;
 
+               /*
+                * Sample found inconsistent, pressure is beyond
+                * the maximum. Don't report it to user space.
+                */
+               if (Rt > ts->pressure_max)
+                       return -EINVAL;
+
+               if (!timer_pending(&ts->timer))
+                       input_report_key(input_dev, BTN_TOUCH, 1);
+
                input_report_abs(input_dev, ABS_X, x);
                input_report_abs(input_dev, ABS_Y, y);
                input_report_abs(input_dev, ABS_PRESSURE, Rt);
                input_sync(input_dev);
+
+               return 0;
        }
+
+       return -EINVAL;
 }
 
 static inline void ad7877_ts_event_release(struct ad7877 *ts)
@@ -366,72 +385,56 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
        struct input_dev *input_dev = ts->input;
 
        input_report_abs(input_dev, ABS_PRESSURE, 0);
+       input_report_key(input_dev, BTN_TOUCH, 0);
        input_sync(input_dev);
 }
 
 static void ad7877_timer(unsigned long handle)
 {
        struct ad7877 *ts = (void *)handle;
+       unsigned long flags;
 
+       spin_lock_irqsave(&ts->lock, flags);
        ad7877_ts_event_release(ts);
+       spin_unlock_irqrestore(&ts->lock, flags);
 }
 
 static irqreturn_t ad7877_irq(int irq, void *handle)
 {
        struct ad7877 *ts = handle;
        unsigned long flags;
-       int status;
+       int error;
 
-       /*
-        * The repeated conversion sequencer controlled by TMR kicked off
-        * too fast. We ignore the last and process the sample sequence
-        * currently in the queue. It can't be older than 9.4ms, and we
-        * need to avoid that ts->msg doesn't get issued twice while in work.
-        */
+       error = spi_sync(ts->spi, &ts->msg);
+       if (error) {
+               dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+               goto out;
+       }
 
        spin_lock_irqsave(&ts->lock, flags);
-       if (!ts->pending) {
-               ts->pending = 1;
-
-               status = spi_async(ts->spi, &ts->msg);
-               if (status)
-                       dev_err(&ts->spi->dev, "spi_sync --> %d\n", status);
-       }
+       error = ad7877_process_data(ts);
+       if (!error)
+               mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
        spin_unlock_irqrestore(&ts->lock, flags);
 
+out:
        return IRQ_HANDLED;
 }
 
-static void ad7877_callback(void *_ts)
-{
-       struct ad7877 *ts = _ts;
-
-       spin_lock_irq(&ts->lock);
-
-       ad7877_rx(ts);
-       ts->pending = 0;
-       mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
-
-       spin_unlock_irq(&ts->lock);
-}
-
 static void ad7877_disable(struct ad7877 *ts)
 {
        mutex_lock(&ts->mutex);
 
        if (!ts->disabled) {
-               ts->disabled = 1;
+               ts->disabled = true;
                disable_irq(ts->spi->irq);
 
-               /* Wait for spi_async callback */
-               while (ts->pending)
-                       msleep(1);
-
                if (del_timer_sync(&ts->timer))
                        ad7877_ts_event_release(ts);
        }
 
-       /* we know the chip's in lowpower mode since we always
+       /*
+        * We know the chip's in lowpower mode since we always
         * leave it that way after every request
         */
 
@@ -443,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts)
        mutex_lock(&ts->mutex);
 
        if (ts->disabled) {
-               ts->disabled = 0;
+               ts->disabled = false;
                enable_irq(ts->spi->irq);
        }
 
@@ -453,7 +456,7 @@ static void ad7877_enable(struct ad7877 *ts)
 #define SHOW(name) static ssize_t \
 name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
-       struct ad7877   *ts = dev_get_drvdata(dev); \
+       struct ad7877 *ts = dev_get_drvdata(dev); \
        ssize_t v = ad7877_read_adc(ts->spi, \
                        AD7877_READ_CHAN(name)); \
        if (v < 0) \
@@ -473,7 +476,7 @@ SHOW(temp2)
 static ssize_t ad7877_disable_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct ad7877   *ts = dev_get_drvdata(dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        return sprintf(buf, "%u\n", ts->disabled);
 }
@@ -503,7 +506,7 @@ static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store);
 static ssize_t ad7877_dac_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct ad7877   *ts = dev_get_drvdata(dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        return sprintf(buf, "%u\n", ts->dac);
 }
@@ -533,7 +536,7 @@ static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store);
 static ssize_t ad7877_gpio3_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct ad7877   *ts = dev_get_drvdata(dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        return sprintf(buf, "%u\n", ts->gpio3);
 }
@@ -564,7 +567,7 @@ static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store);
 static ssize_t ad7877_gpio4_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct ad7877   *ts = dev_get_drvdata(dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        return sprintf(buf, "%u\n", ts->gpio4);
 }
@@ -597,16 +600,35 @@ static struct attribute *ad7877_attributes[] = {
        &dev_attr_temp2.attr,
        &dev_attr_aux1.attr,
        &dev_attr_aux2.attr,
+       &dev_attr_aux3.attr,
        &dev_attr_bat1.attr,
        &dev_attr_bat2.attr,
        &dev_attr_disable.attr,
        &dev_attr_dac.attr,
+       &dev_attr_gpio3.attr,
        &dev_attr_gpio4.attr,
        NULL
 };
 
+static mode_t ad7877_attr_is_visible(struct kobject *kobj,
+                                    struct attribute *attr, int n)
+{
+       mode_t mode = attr->mode;
+
+       if (attr == &dev_attr_aux3.attr) {
+               if (gpio3)
+                       mode = 0;
+       } else if (attr == &dev_attr_gpio3.attr) {
+               if (!gpio3)
+                       mode = 0;
+       }
+
+       return mode;
+}
+
 static const struct attribute_group ad7877_attr_group = {
-       .attrs = ad7877_attributes,
+       .is_visible     = ad7877_attr_is_visible,
+       .attrs          = ad7877_attributes,
 };
 
 static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
@@ -635,22 +657,25 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
 
        spi_message_init(m);
 
-       m->complete = ad7877_callback;
        m->context = ts;
 
        ts->xfer[0].tx_buf = &ts->cmd_crtl1;
        ts->xfer[0].len = 2;
+       ts->xfer[0].cs_change = 1;
 
        spi_message_add_tail(&ts->xfer[0], m);
 
        ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
        ts->xfer[1].len = 2;
+       ts->xfer[1].cs_change = 1;
 
        spi_message_add_tail(&ts->xfer[1], m);
 
-       for (i = 0; i < 11; i++) {
+       for (i = 0; i < AD7877_NR_SENSE; i++) {
                ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
                ts->xfer[i + 2].len = 2;
+               if (i < (AD7877_NR_SENSE - 1))
+                       ts->xfer[i + 2].cs_change = 1;
                spi_message_add_tail(&ts->xfer[i + 2], m);
        }
 }
@@ -718,6 +743,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
        input_dev->phys = ts->phys;
        input_dev->dev.parent = &spi->dev;
 
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(ABS_X, input_dev->absbit);
        __set_bit(ABS_Y, input_dev->absbit);
@@ -752,8 +779,9 @@ static int __devinit ad7877_probe(struct spi_device *spi)
 
        /* Request AD7877 /DAV GPIO interrupt */
 
-       err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING,
-                       spi->dev.driver->name, ts);
+       err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  spi->dev.driver->name, ts);
        if (err) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                goto err_free_mem;
@@ -763,20 +791,12 @@ static int __devinit ad7877_probe(struct spi_device *spi)
        if (err)
                goto err_free_irq;
 
-       err = device_create_file(&spi->dev,
-                                gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
-       if (err)
-               goto err_remove_attr_group;
-
        err = input_register_device(input_dev);
        if (err)
-               goto err_remove_attr;
+               goto err_remove_attr_group;
 
        return 0;
 
-err_remove_attr:
-       device_remove_file(&spi->dev,
-                          gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
 err_remove_attr_group:
        sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
 err_free_irq:
@@ -790,11 +810,9 @@ err_free_mem:
 
 static int __devexit ad7877_remove(struct spi_device *spi)
 {
-       struct ad7877           *ts = dev_get_drvdata(&spi->dev);
+       struct ad7877 *ts = dev_get_drvdata(&spi->dev);
 
        sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
-       device_remove_file(&spi->dev,
-                          gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
 
        ad7877_disable(ts);
        free_irq(ts->spi->irq, ts);
index 16031933a8f621266a555b09ff63979c0359ca0b..14ea54b78e4648b0ac8a3403440f6f5d120dfdd9 100644 (file)
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/types.h>
 #include <linux/hwmon.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
  * files.
  */
 
-#define TS_POLL_DELAY  (1 * 1000000)   /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000000)   /* ns delay between samples */
+#define TS_POLL_DELAY  1       /* ms delay before the first sample */
+#define TS_POLL_PERIOD 5       /* ms delay between samples */
 
 /* this driver doesn't aim at the peak continuous sample rate */
 #define        SAMPLE_BITS     (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
 
 struct ts_event {
-       /* For portability, we can't read 12 bit values using SPI (which
-        * would make the controller deliver them as native byteorder u16
+       /*
+        * For portability, we can't read 12 bit values using SPI (which
+        * would make the controller deliver them as native byte order u16
         * with msbs zeroed).  Instead, we read them as two 8-bit values,
         * *** WHICH NEED BYTESWAPPING *** and range adjustment.
         */
        u16     x;
        u16     y;
        u16     z1, z2;
-       int     ignore;
+       bool    ignore;
        u8      x_buf[3];
        u8      y_buf[3];
 };
@@ -110,8 +113,11 @@ struct ads7846 {
 
        struct spi_transfer     xfer[18];
        struct spi_message      msg[5];
-       struct spi_message      *last_msg;
-       int                     msg_idx;
+       int                     msg_count;
+       wait_queue_head_t       wait;
+
+       bool                    pendown;
+
        int                     read_cnt;
        int                     read_rep;
        int                     last_read;
@@ -122,14 +128,10 @@ struct ads7846 {
 
        u16                     penirq_recheck_delay_usecs;
 
-       spinlock_t              lock;
-       struct hrtimer          timer;
-       unsigned                pendown:1;      /* P: lock */
-       unsigned                pending:1;      /* P: lock */
-// FIXME remove "irq_disabled"
-       unsigned                irq_disabled:1; /* P: lock */
-       unsigned                disabled:1;
-       unsigned                is_suspended:1;
+       struct mutex            lock;
+       bool                    stopped;        /* P: lock */
+       bool                    disabled;       /* P: lock */
+       bool                    suspended;      /* P: lock */
 
        int                     (*filter)(void *data, int data_idx, int *val);
        void                    *filter_data;
@@ -165,7 +167,7 @@ struct ads7846 {
 #define        ADS_12_BIT              (0 << 3)
 #define        ADS_SER                 (1 << 2)        /* non-differential */
 #define        ADS_DFR                 (0 << 2)        /* differential */
-#define        ADS_PD10_PDOWN          (0 << 0)        /* lowpower mode + penirq */
+#define        ADS_PD10_PDOWN          (0 << 0)        /* low power mode + penirq */
 #define        ADS_PD10_ADC_ON         (1 << 0)        /* ADC on */
 #define        ADS_PD10_REF_ON         (2 << 0)        /* vREF on + penirq */
 #define        ADS_PD10_ALL_ON         (3 << 0)        /* ADC + vREF on */
@@ -193,6 +195,78 @@ struct ads7846 {
 #define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
 #define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
+/* Must be called with ts->lock held */
+static void ads7846_stop(struct ads7846 *ts)
+{
+       if (!ts->disabled && !ts->suspended) {
+               /* Signal IRQ thread to stop polling and disable the handler. */
+               ts->stopped = true;
+               mb();
+               wake_up(&ts->wait);
+               disable_irq(ts->spi->irq);
+       }
+}
+
+/* Must be called with ts->lock held */
+static void ads7846_restart(struct ads7846 *ts)
+{
+       if (!ts->disabled && !ts->suspended) {
+               /* Tell IRQ thread that it may poll the device. */
+               ts->stopped = false;
+               mb();
+               enable_irq(ts->spi->irq);
+       }
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_disable(struct ads7846 *ts)
+{
+       ads7846_stop(ts);
+       regulator_disable(ts->reg);
+
+       /*
+        * We know the chip's in low power mode since we always
+        * leave it that way after every request
+        */
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_enable(struct ads7846 *ts)
+{
+       regulator_enable(ts->reg);
+       ads7846_restart(ts);
+}
+
+static void ads7846_disable(struct ads7846 *ts)
+{
+       mutex_lock(&ts->lock);
+
+       if (!ts->disabled) {
+
+               if  (!ts->suspended)
+                       __ads7846_disable(ts);
+
+               ts->disabled = true;
+       }
+
+       mutex_unlock(&ts->lock);
+}
+
+static void ads7846_enable(struct ads7846 *ts)
+{
+       mutex_lock(&ts->lock);
+
+       if (ts->disabled) {
+
+               ts->disabled = false;
+
+               if (!ts->suspended)
+                       __ads7846_enable(ts);
+       }
+
+       mutex_unlock(&ts->lock);
+}
+
 /*--------------------------------------------------------------------------*/
 
 /*
@@ -219,23 +293,15 @@ struct ads7845_ser_req {
        struct spi_transfer     xfer[2];
 };
 
-static void ads7846_enable(struct ads7846 *ts);
-static void ads7846_disable(struct ads7846 *ts);
-
-static int device_suspended(struct device *dev)
-{
-       struct ads7846 *ts = dev_get_drvdata(dev);
-       return ts->is_suspended || ts->disabled;
-}
-
 static int ads7846_read12_ser(struct device *dev, unsigned command)
 {
-       struct spi_device       *spi = to_spi_device(dev);
-       struct ads7846          *ts = dev_get_drvdata(dev);
-       struct ser_req          *req = kzalloc(sizeof *req, GFP_KERNEL);
-       int                     status;
-       int                     use_internal;
+       struct spi_device *spi = to_spi_device(dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
+       struct ser_req *req;
+       int status;
+       int use_internal;
 
+       req = kzalloc(sizeof *req, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
 
@@ -282,11 +348,11 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        CS_CHANGE(req->xfer[5]);
        spi_message_add_tail(&req->xfer[5], &req->msg);
 
-       ts->irq_disabled = 1;
-       disable_irq(spi->irq);
+       mutex_lock(&ts->lock);
+       ads7846_stop(ts);
        status = spi_sync(spi, &req->msg);
-       ts->irq_disabled = 0;
-       enable_irq(spi->irq);
+       ads7846_restart(ts);
+       mutex_unlock(&ts->lock);
 
        if (status == 0) {
                /* on-wire is a must-ignore bit, a BE12 value, then padding */
@@ -301,11 +367,12 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
 
 static int ads7845_read12_ser(struct device *dev, unsigned command)
 {
-       struct spi_device       *spi = to_spi_device(dev);
-       struct ads7846          *ts = dev_get_drvdata(dev);
-       struct ads7845_ser_req  *req = kzalloc(sizeof *req, GFP_KERNEL);
-       int                     status;
+       struct spi_device *spi = to_spi_device(dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
+       struct ads7845_ser_req *req;
+       int status;
 
+       req = kzalloc(sizeof *req, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
 
@@ -317,11 +384,11 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
        req->xfer[0].len = 3;
        spi_message_add_tail(&req->xfer[0], &req->msg);
 
-       ts->irq_disabled = 1;
-       disable_irq(spi->irq);
+       mutex_lock(&ts->lock);
+       ads7846_stop(ts);
        status = spi_sync(spi, &req->msg);
-       ts->irq_disabled = 0;
-       enable_irq(spi->irq);
+       ads7846_restart(ts);
+       mutex_unlock(&ts->lock);
 
        if (status == 0) {
                /* BE12 value, then padding */
@@ -374,6 +441,7 @@ static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
        /* external resistors may scale vAUX into 0..vREF */
        retval *= ts->vref_mv;
        retval = retval >> 12;
+
        return retval;
 }
 
@@ -384,13 +452,13 @@ static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
        /* ads7846 has a resistor ladder to scale this signal down */
        if (ts->model == 7846)
                retval *= 4;
+
        return retval;
 }
 
 SHOW(in0_input, vaux, vaux_adjust)
 SHOW(in1_input, vbatt, vbatt_adjust)
 
-
 static struct attribute *ads7846_attributes[] = {
        &dev_attr_temp0.attr,
        &dev_attr_temp1.attr,
@@ -498,17 +566,12 @@ static inline void ads784x_hwmon_unregister(struct spi_device *spi,
 }
 #endif
 
-static int is_pen_down(struct device *dev)
-{
-       struct ads7846  *ts = dev_get_drvdata(dev);
-
-       return ts->pendown;
-}
-
 static ssize_t ads7846_pen_down_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%u\n", is_pen_down(dev));
+       struct ads7846 *ts = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", ts->pendown);
 }
 
 static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
@@ -516,7 +579,7 @@ static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
 static ssize_t ads7846_disable_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct ads7846  *ts = dev_get_drvdata(dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
 
        return sprintf(buf, "%u\n", ts->disabled);
 }
@@ -531,15 +594,11 @@ static ssize_t ads7846_disable_store(struct device *dev,
        if (strict_strtoul(buf, 10, &i))
                return -EINVAL;
 
-       spin_lock_irq(&ts->lock);
-
        if (i)
                ads7846_disable(ts);
        else
                ads7846_enable(ts);
 
-       spin_unlock_irq(&ts->lock);
-
        return count;
 }
 
@@ -569,23 +628,141 @@ static void null_wait_for_sync(void)
 {
 }
 
-/*
- * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
- * to retrieve touchscreen status.
- *
- * The SPI transfer completion callback does the real work.  It reports
- * touchscreen events and reactivates the timer (or IRQ) as appropriate.
- */
+static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
+{
+       struct ads7846 *ts = ads;
+
+       if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+               /* Start over collecting consistent readings. */
+               ts->read_rep = 0;
+               /*
+                * Repeat it, if this was the first read or the read
+                * wasn't consistent enough.
+                */
+               if (ts->read_cnt < ts->debounce_max) {
+                       ts->last_read = *val;
+                       ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
+               } else {
+                       /*
+                        * Maximum number of debouncing reached and still
+                        * not enough number of consistent readings. Abort
+                        * the whole sample, repeat it in the next sampling
+                        * period.
+                        */
+                       ts->read_cnt = 0;
+                       return ADS7846_FILTER_IGNORE;
+               }
+       } else {
+               if (++ts->read_rep > ts->debounce_rep) {
+                       /*
+                        * Got a good reading for this coordinate,
+                        * go for the next one.
+                        */
+                       ts->read_cnt = 0;
+                       ts->read_rep = 0;
+                       return ADS7846_FILTER_OK;
+               } else {
+                       /* Read more values that are consistent. */
+                       ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
+               }
+       }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+       return ADS7846_FILTER_OK;
+}
+
+static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+{
+       struct spi_transfer *t =
+               list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+       if (ts->model == 7845) {
+               return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+       } else {
+               /*
+                * adjust:  on-wire is a must-ignore bit, a BE12 value, then
+                * padding; built from two 8 bit values written msb-first.
+                */
+               return be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+       }
+}
+
+static void ads7846_update_value(struct spi_message *m, int val)
+{
+       struct spi_transfer *t =
+               list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+       *(u16 *)t->rx_buf = val;
+}
+
+static void ads7846_read_state(struct ads7846 *ts)
+{
+       struct ads7846_packet *packet = ts->packet;
+       struct spi_message *m;
+       int msg_idx = 0;
+       int val;
+       int action;
+       int error;
+
+       while (msg_idx < ts->msg_count) {
+
+               ts->wait_for_sync();
+
+               m = &ts->msg[msg_idx];
+               error = spi_sync(ts->spi, m);
+               if (error) {
+                       dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+                       packet->tc.ignore = true;
+                       return;
+               }
+
+               /*
+                * Last message is power down request, no need to convert
+                * or filter the value.
+                */
+               if (msg_idx < ts->msg_count - 1) {
 
-static void ads7846_rx(void *ads)
+                       val = ads7846_get_value(ts, m);
+
+                       action = ts->filter(ts->filter_data, msg_idx, &val);
+                       switch (action) {
+                       case ADS7846_FILTER_REPEAT:
+                               continue;
+
+                       case ADS7846_FILTER_IGNORE:
+                               packet->tc.ignore = true;
+                               msg_idx = ts->msg_count - 1;
+                               continue;
+
+                       case ADS7846_FILTER_OK:
+                               ads7846_update_value(m, val);
+                               packet->tc.ignore = false;
+                               msg_idx++;
+                               break;
+
+                       default:
+                               BUG();
+                       }
+               } else {
+                       msg_idx++;
+               }
+       }
+}
+
+static void ads7846_report_state(struct ads7846 *ts)
 {
-       struct ads7846          *ts = ads;
-       struct ads7846_packet   *packet = ts->packet;
-       unsigned                Rt;
-       u16                     x, y, z1, z2;
+       struct ads7846_packet *packet = ts->packet;
+       unsigned int Rt;
+       u16 x, y, z1, z2;
 
-       /* ads7846_rx_val() did in-place conversion (including byteswap) from
-        * on-the-wire format as part of debouncing to get stable readings.
+       /*
+        * ads7846_get_value() does in-place conversion (including byte swap)
+        * from on-the-wire format as part of debouncing to get stable
+        * readings.
         */
        if (ts->model == 7845) {
                x = *(u16 *)packet->tc.x_buf;
@@ -623,19 +800,19 @@ static void ads7846_rx(void *ads)
                Rt = 0;
        }
 
-       /* Sample found inconsistent by debouncing or pressure is beyond
+       /*
+        * Sample found inconsistent by debouncing or pressure is beyond
         * the maximum. Don't report it to user space, repeat at least
         * once more the measurement
         */
        if (packet->tc.ignore || Rt > ts->pressure_max) {
                dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
                         packet->tc.ignore, Rt);
-               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
-                             HRTIMER_MODE_REL);
                return;
        }
 
-       /* Maybe check the pendown state before reporting. This discards
+       /*
+        * Maybe check the pendown state before reporting. This discards
         * false readings when the pen is lifted.
         */
        if (ts->penirq_recheck_delay_usecs) {
@@ -644,8 +821,9 @@ static void ads7846_rx(void *ads)
                        Rt = 0;
        }
 
-       /* NOTE: We can't rely on the pressure to determine the pen down
-        * state, even this controller has a pressure sensor.  The pressure
+       /*
+        * NOTE: We can't rely on the pressure to determine the pen down
+        * state, even this controller has a pressure sensor. The pressure
         * value can fluctuate for quite a while after lifting the pen and
         * in some cases may not even settle at the expected value.
         *
@@ -655,15 +833,15 @@ static void ads7846_rx(void *ads)
        if (Rt) {
                struct input_dev *input = ts->input;
 
+               if (ts->swap_xy)
+                       swap(x, y);
+
                if (!ts->pendown) {
                        input_report_key(input, BTN_TOUCH, 1);
-                       ts->pendown = 1;
+                       ts->pendown = true;
                        dev_vdbg(&ts->spi->dev, "DOWN\n");
                }
 
-               if (ts->swap_xy)
-                       swap(x, y);
-
                input_report_abs(input, ABS_X, x);
                input_report_abs(input, ABS_Y, y);
                input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
@@ -671,246 +849,94 @@ static void ads7846_rx(void *ads)
                input_sync(input);
                dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
        }
-
-       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
-                       HRTIMER_MODE_REL);
-}
-
-static int ads7846_debounce(void *ads, int data_idx, int *val)
-{
-       struct ads7846          *ts = ads;
-
-       if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
-               /* Start over collecting consistent readings. */
-               ts->read_rep = 0;
-               /* Repeat it, if this was the first read or the read
-                * wasn't consistent enough. */
-               if (ts->read_cnt < ts->debounce_max) {
-                       ts->last_read = *val;
-                       ts->read_cnt++;
-                       return ADS7846_FILTER_REPEAT;
-               } else {
-                       /* Maximum number of debouncing reached and still
-                        * not enough number of consistent readings. Abort
-                        * the whole sample, repeat it in the next sampling
-                        * period.
-                        */
-                       ts->read_cnt = 0;
-                       return ADS7846_FILTER_IGNORE;
-               }
-       } else {
-               if (++ts->read_rep > ts->debounce_rep) {
-                       /* Got a good reading for this coordinate,
-                        * go for the next one. */
-                       ts->read_cnt = 0;
-                       ts->read_rep = 0;
-                       return ADS7846_FILTER_OK;
-               } else {
-                       /* Read more values that are consistent. */
-                       ts->read_cnt++;
-                       return ADS7846_FILTER_REPEAT;
-               }
-       }
 }
 
-static int ads7846_no_filter(void *ads, int data_idx, int *val)
+static irqreturn_t ads7846_hard_irq(int irq, void *handle)
 {
-       return ADS7846_FILTER_OK;
-}
-
-static void ads7846_rx_val(void *ads)
-{
-       struct ads7846 *ts = ads;
-       struct ads7846_packet *packet = ts->packet;
-       struct spi_message *m;
-       struct spi_transfer *t;
-       int val;
-       int action;
-       int status;
-
-       m = &ts->msg[ts->msg_idx];
-       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-
-       if (ts->model == 7845) {
-               val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
-       } else {
-               /* adjust:  on-wire is a must-ignore bit, a BE12 value, then
-                * padding; built from two 8 bit values written msb-first.
-                */
-               val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
-       }
+       struct ads7846 *ts = handle;
 
-       action = ts->filter(ts->filter_data, ts->msg_idx, &val);
-       switch (action) {
-       case ADS7846_FILTER_REPEAT:
-               break;
-       case ADS7846_FILTER_IGNORE:
-               packet->tc.ignore = 1;
-               /* Last message will contain ads7846_rx() as the
-                * completion function.
-                */
-               m = ts->last_msg;
-               break;
-       case ADS7846_FILTER_OK:
-               *(u16 *)t->rx_buf = val;
-               packet->tc.ignore = 0;
-               m = &ts->msg[++ts->msg_idx];
-               break;
-       default:
-               BUG();
-       }
-       ts->wait_for_sync();
-       status = spi_async(ts->spi, m);
-       if (status)
-               dev_err(&ts->spi->dev, "spi_async --> %d\n",
-                               status);
+       return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
 }
 
-static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
-{
-       struct ads7846  *ts = container_of(handle, struct ads7846, timer);
-       int             status = 0;
-
-       spin_lock(&ts->lock);
-
-       if (unlikely(!get_pendown_state(ts) ||
-                    device_suspended(&ts->spi->dev))) {
-               if (ts->pendown) {
-                       struct input_dev *input = ts->input;
-
-                       input_report_key(input, BTN_TOUCH, 0);
-                       input_report_abs(input, ABS_PRESSURE, 0);
-                       input_sync(input);
-
-                       ts->pendown = 0;
-                       dev_vdbg(&ts->spi->dev, "UP\n");
-               }
-
-               /* measurement cycle ended */
-               if (!device_suspended(&ts->spi->dev)) {
-                       ts->irq_disabled = 0;
-                       enable_irq(ts->spi->irq);
-               }
-               ts->pending = 0;
-       } else {
-               /* pen is still down, continue with the measurement */
-               ts->msg_idx = 0;
-               ts->wait_for_sync();
-               status = spi_async(ts->spi, &ts->msg[0]);
-               if (status)
-                       dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
-       }
-
-       spin_unlock(&ts->lock);
-       return HRTIMER_NORESTART;
-}
 
 static irqreturn_t ads7846_irq(int irq, void *handle)
 {
        struct ads7846 *ts = handle;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ts->lock, flags);
-       if (likely(get_pendown_state(ts))) {
-               if (!ts->irq_disabled) {
-                       /* The ARM do_simple_IRQ() dispatcher doesn't act
-                        * like the other dispatchers:  it will report IRQs
-                        * even after they've been disabled.  We work around
-                        * that here.  (The "generic irq" framework may help...)
-                        */
-                       ts->irq_disabled = 1;
-                       disable_irq_nosync(ts->spi->irq);
-                       ts->pending = 1;
-                       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
-                                       HRTIMER_MODE_REL);
-               }
-       }
-       spin_unlock_irqrestore(&ts->lock, flags);
 
-       return IRQ_HANDLED;
-}
+       /* Start with a small delay before checking pendown state */
+       msleep(TS_POLL_DELAY);
 
-/*--------------------------------------------------------------------------*/
+       while (!ts->stopped && get_pendown_state(ts)) {
 
-/* Must be called with ts->lock held */
-static void ads7846_disable(struct ads7846 *ts)
-{
-       if (ts->disabled)
-               return;
+               /* pen is down, continue with the measurement */
+               ads7846_read_state(ts);
 
-       ts->disabled = 1;
+               if (!ts->stopped)
+                       ads7846_report_state(ts);
 
-       /* are we waiting for IRQ, or polling? */
-       if (!ts->pending) {
-               ts->irq_disabled = 1;
-               disable_irq(ts->spi->irq);
-       } else {
-               /* the timer will run at least once more, and
-                * leave everything in a clean state, IRQ disabled
-                */
-               while (ts->pending) {
-                       spin_unlock_irq(&ts->lock);
-                       msleep(1);
-                       spin_lock_irq(&ts->lock);
-               }
+               wait_event_timeout(ts->wait, ts->stopped,
+                                  msecs_to_jiffies(TS_POLL_PERIOD));
        }
 
-       regulator_disable(ts->reg);
-
-       /* we know the chip's in lowpower mode since we always
-        * leave it that way after every request
-        */
-}
+       if (ts->pendown) {
+               struct input_dev *input = ts->input;
 
-/* Must be called with ts->lock held */
-static void ads7846_enable(struct ads7846 *ts)
-{
-       if (!ts->disabled)
-               return;
+               input_report_key(input, BTN_TOUCH, 0);
+               input_report_abs(input, ABS_PRESSURE, 0);
+               input_sync(input);
 
-       regulator_enable(ts->reg);
+               ts->pendown = false;
+               dev_vdbg(&ts->spi->dev, "UP\n");
+       }
 
-       ts->disabled = 0;
-       ts->irq_disabled = 0;
-       enable_irq(ts->spi->irq);
+       return IRQ_HANDLED;
 }
 
 static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
 {
        struct ads7846 *ts = dev_get_drvdata(&spi->dev);
 
-       spin_lock_irq(&ts->lock);
+       mutex_lock(&ts->lock);
 
-       ts->is_suspended = 1;
-       ads7846_disable(ts);
+       if (!ts->suspended) {
 
-       spin_unlock_irq(&ts->lock);
+               if (!ts->disabled)
+                       __ads7846_disable(ts);
 
-       if (device_may_wakeup(&ts->spi->dev))
-               enable_irq_wake(ts->spi->irq);
+               if (device_may_wakeup(&ts->spi->dev))
+                       enable_irq_wake(ts->spi->irq);
 
-       return 0;
+               ts->suspended = true;
+       }
+
+       mutex_unlock(&ts->lock);
 
+       return 0;
 }
 
 static int ads7846_resume(struct spi_device *spi)
 {
        struct ads7846 *ts = dev_get_drvdata(&spi->dev);
 
-       if (device_may_wakeup(&ts->spi->dev))
-               disable_irq_wake(ts->spi->irq);
+       mutex_lock(&ts->lock);
+
+       if (ts->suspended) {
 
-       spin_lock_irq(&ts->lock);
+               ts->suspended = false;
 
-       ts->is_suspended = 0;
-       ads7846_enable(ts);
+               if (device_may_wakeup(&ts->spi->dev))
+                       disable_irq_wake(ts->spi->irq);
 
-       spin_unlock_irq(&ts->lock);
+               if (!ts->disabled)
+                       __ads7846_enable(ts);
+       }
+
+       mutex_unlock(&ts->lock);
 
        return 0;
 }
 
-static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
 {
        struct ads7846_platform_data *pdata = spi->dev.platform_data;
        int err;
@@ -932,146 +958,40 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
        err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
        if (err) {
                dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
-                               pdata->gpio_pendown);
+                       pdata->gpio_pendown);
                return err;
        }
 
        ts->gpio_pendown = pdata->gpio_pendown;
+
        return 0;
 }
 
-static int __devinit ads7846_probe(struct spi_device *spi)
+/*
+ * Set up the transfers to read touchscreen state; this assumes we
+ * use formula #2 for pressure, not #3.
+ */
+static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
+                               const struct ads7846_platform_data *pdata)
 {
-       struct ads7846 *ts;
-       struct ads7846_packet *packet;
-       struct input_dev *input_dev;
-       const struct ads7846_platform_data *pdata = spi->dev.platform_data;
-       struct spi_message *m;
-       struct spi_transfer *x;
-       unsigned long irq_flags;
-       int vref;
-       int err;
-
-       if (!spi->irq) {
-               dev_dbg(&spi->dev, "no IRQ?\n");
-               return -ENODEV;
-       }
-
-       if (!pdata) {
-               dev_dbg(&spi->dev, "no platform data?\n");
-               return -ENODEV;
-       }
-
-       /* don't exceed max specified sample rate */
-       if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
-               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
-                               (spi->max_speed_hz/SAMPLE_BITS)/1000);
-               return -EINVAL;
-       }
-
-       /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
-        * that even if the hardware can do that, the SPI controller driver
-        * may not.  So we stick to very-portable 8 bit words, both RX and TX.
-        */
-       spi->bits_per_word = 8;
-       spi->mode = SPI_MODE_0;
-       err = spi_setup(spi);
-       if (err < 0)
-               return err;
-
-       ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
-       packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ts || !packet || !input_dev) {
-               err = -ENOMEM;
-               goto err_free_mem;
-       }
-
-       dev_set_drvdata(&spi->dev, ts);
-
-       ts->packet = packet;
-       ts->spi = spi;
-       ts->input = input_dev;
-       ts->vref_mv = pdata->vref_mv;
-       ts->swap_xy = pdata->swap_xy;
-
-       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       ts->timer.function = ads7846_timer;
-
-       spin_lock_init(&ts->lock);
-
-       ts->model = pdata->model ? : 7846;
-       ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
-       ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
-       ts->pressure_max = pdata->pressure_max ? : ~0;
-
-       if (pdata->filter != NULL) {
-               if (pdata->filter_init != NULL) {
-                       err = pdata->filter_init(pdata, &ts->filter_data);
-                       if (err < 0)
-                               goto err_free_mem;
-               }
-               ts->filter = pdata->filter;
-               ts->filter_cleanup = pdata->filter_cleanup;
-       } else if (pdata->debounce_max) {
-               ts->debounce_max = pdata->debounce_max;
-               if (ts->debounce_max < 2)
-                       ts->debounce_max = 2;
-               ts->debounce_tol = pdata->debounce_tol;
-               ts->debounce_rep = pdata->debounce_rep;
-               ts->filter = ads7846_debounce;
-               ts->filter_data = ts;
-       } else
-               ts->filter = ads7846_no_filter;
-
-       err = setup_pendown(spi, ts);
-       if (err)
-               goto err_cleanup_filter;
-
-       if (pdata->penirq_recheck_delay_usecs)
-               ts->penirq_recheck_delay_usecs =
-                               pdata->penirq_recheck_delay_usecs;
-
-       ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
-
-       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
-       snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
-
-       input_dev->name = ts->name;
-       input_dev->phys = ts->phys;
-       input_dev->dev.parent = &spi->dev;
-
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-       input_set_abs_params(input_dev, ABS_X,
-                       pdata->x_min ? : 0,
-                       pdata->x_max ? : MAX_12BIT,
-                       0, 0);
-       input_set_abs_params(input_dev, ABS_Y,
-                       pdata->y_min ? : 0,
-                       pdata->y_max ? : MAX_12BIT,
-                       0, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE,
-                       pdata->pressure_min, pdata->pressure_max, 0, 0);
-
-       vref = pdata->keep_vref_on;
+       struct spi_message *m = &ts->msg[0];
+       struct spi_transfer *x = ts->xfer;
+       struct ads7846_packet *packet = ts->packet;
+       int vref = pdata->keep_vref_on;
 
        if (ts->model == 7873) {
-               /* The AD7873 is almost identical to the ADS7846
+               /*
+                * The AD7873 is almost identical to the ADS7846
                 * keep VREF off during differential/ratiometric
-                * conversion modes
+                * conversion modes.
                 */
                ts->model = 7846;
                vref = 0;
        }
 
-       /* set up the transfers to read touchscreen state; this assumes we
-        * use formula #2 for pressure, not #3.
-        */
-       m = &ts->msg[0];
-       x = ts->xfer;
-
+       ts->msg_count = 1;
        spi_message_init(m);
+       m->context = ts;
 
        if (ts->model == 7845) {
                packet->read_y_cmd[0] = READ_Y(vref);
@@ -1094,7 +1014,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_add_tail(x, m);
        }
 
-       /* the first sample after switching drivers can be low quality;
+       /*
+        * The first sample after switching drivers can be low quality;
         * optionally discard it, using a second one after the signals
         * have had enough time to stabilize.
         */
@@ -1112,11 +1033,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_add_tail(x, m);
        }
 
-       m->complete = ads7846_rx_val;
-       m->context = ts;
-
+       ts->msg_count++;
        m++;
        spi_message_init(m);
+       m->context = ts;
 
        if (ts->model == 7845) {
                x++;
@@ -1156,13 +1076,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_add_tail(x, m);
        }
 
-       m->complete = ads7846_rx_val;
-       m->context = ts;
-
        /* turn y+ off, x- on; we'll use formula #2 */
        if (ts->model == 7846) {
+               ts->msg_count++;
                m++;
                spi_message_init(m);
+               m->context = ts;
 
                x++;
                packet->read_z1 = READ_Z1(vref);
@@ -1190,11 +1109,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                        spi_message_add_tail(x, m);
                }
 
-               m->complete = ads7846_rx_val;
-               m->context = ts;
-
+               ts->msg_count++;
                m++;
                spi_message_init(m);
+               m->context = ts;
 
                x++;
                packet->read_z2 = READ_Z2(vref);
@@ -1221,14 +1139,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                        x->len = 2;
                        spi_message_add_tail(x, m);
                }
-
-               m->complete = ads7846_rx_val;
-               m->context = ts;
        }
 
        /* power down */
+       ts->msg_count++;
        m++;
        spi_message_init(m);
+       m->context = ts;
 
        if (ts->model == 7845) {
                x++;
@@ -1251,11 +1168,119 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        CS_CHANGE(*x);
        spi_message_add_tail(x, m);
+}
 
-       m->complete = ads7846_rx;
-       m->context = ts;
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+       struct ads7846 *ts;
+       struct ads7846_packet *packet;
+       struct input_dev *input_dev;
+       struct ads7846_platform_data *pdata = spi->dev.platform_data;
+       unsigned long irq_flags;
+       int err;
+
+       if (!spi->irq) {
+               dev_dbg(&spi->dev, "no IRQ?\n");
+               return -ENODEV;
+       }
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       /* don't exceed max specified sample rate */
+       if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
+               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+                               (spi->max_speed_hz/SAMPLE_BITS)/1000);
+               return -EINVAL;
+       }
+
+       /* We'd set TX word size 8 bits and RX word size to 13 bits ... except
+        * that even if the hardware can do that, the SPI controller driver
+        * may not.  So we stick to very-portable 8 bit words, both RX and TX.
+        */
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       err = spi_setup(spi);
+       if (err < 0)
+               return err;
 
-       ts->last_msg = m;
+       ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
+       packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !packet || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       dev_set_drvdata(&spi->dev, ts);
+
+       ts->packet = packet;
+       ts->spi = spi;
+       ts->input = input_dev;
+       ts->vref_mv = pdata->vref_mv;
+       ts->swap_xy = pdata->swap_xy;
+
+       mutex_init(&ts->lock);
+       init_waitqueue_head(&ts->wait);
+
+       ts->model = pdata->model ? : 7846;
+       ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+       ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+       ts->pressure_max = pdata->pressure_max ? : ~0;
+
+       if (pdata->filter != NULL) {
+               if (pdata->filter_init != NULL) {
+                       err = pdata->filter_init(pdata, &ts->filter_data);
+                       if (err < 0)
+                               goto err_free_mem;
+               }
+               ts->filter = pdata->filter;
+               ts->filter_cleanup = pdata->filter_cleanup;
+       } else if (pdata->debounce_max) {
+               ts->debounce_max = pdata->debounce_max;
+               if (ts->debounce_max < 2)
+                       ts->debounce_max = 2;
+               ts->debounce_tol = pdata->debounce_tol;
+               ts->debounce_rep = pdata->debounce_rep;
+               ts->filter = ads7846_debounce_filter;
+               ts->filter_data = ts;
+       } else {
+               ts->filter = ads7846_no_filter;
+       }
+
+       err = ads7846_setup_pendown(spi, ts);
+       if (err)
+               goto err_cleanup_filter;
+
+       if (pdata->penirq_recheck_delay_usecs)
+               ts->penirq_recheck_delay_usecs =
+                               pdata->penirq_recheck_delay_usecs;
+
+       ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+       snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
+
+       input_dev->name = ts->name;
+       input_dev->phys = ts->phys;
+       input_dev->dev.parent = &spi->dev;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(input_dev, ABS_X,
+                       pdata->x_min ? : 0,
+                       pdata->x_max ? : MAX_12BIT,
+                       0, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                       pdata->y_min ? : 0,
+                       pdata->y_max ? : MAX_12BIT,
+                       0, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE,
+                       pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+       ads7846_setup_spi_msg(ts, pdata);
 
        ts->reg = regulator_get(&spi->dev, "vcc");
        if (IS_ERR(ts->reg)) {
@@ -1271,16 +1296,17 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        }
 
        irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+       irq_flags |= IRQF_ONESHOT;
 
-       err = request_irq(spi->irq, ads7846_irq, irq_flags,
-                         spi->dev.driver->name, ts);
-
+       err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
+                                  irq_flags, spi->dev.driver->name, ts);
        if (err && !pdata->irq_flags) {
                dev_info(&spi->dev,
                        "trying pin change workaround on irq %d\n", spi->irq);
-               err = request_irq(spi->irq, ads7846_irq,
-                                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                                 spi->dev.driver->name, ts);
+               irq_flags |= IRQF_TRIGGER_RISING;
+               err = request_threaded_irq(spi->irq,
+                                 ads7846_hard_irq, ads7846_irq,
+                                 irq_flags, spi->dev.driver->name, ts);
        }
 
        if (err) {
@@ -1294,7 +1320,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
 
-       /* take a first sample, leaving nPENIRQ active and vREF off; avoid
+       /*
+        * Take a first sample, leaving nPENIRQ active and vREF off; avoid
         * the touchscreen, in case it's not connected.
         */
        if (ts->model == 7845)
@@ -1340,20 +1367,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
 static int __devexit ads7846_remove(struct spi_device *spi)
 {
-       struct ads7846          *ts = dev_get_drvdata(&spi->dev);
+       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
 
        device_init_wakeup(&spi->dev, false);
 
-       ads784x_hwmon_unregister(spi, ts);
-       input_unregister_device(ts->input);
-
-       ads7846_suspend(spi, PMSG_SUSPEND);
-
        sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
 
+       ads7846_disable(ts);
        free_irq(ts->spi->irq, ts);
-       /* suspend left the IRQ disabled */
-       enable_irq(ts->spi->irq);
+
+       input_unregister_device(ts->input);
+
+       ads784x_hwmon_unregister(spi, ts);
 
        regulator_disable(ts->reg);
        regulator_put(ts->reg);
@@ -1368,6 +1393,7 @@ static int __devexit ads7846_remove(struct spi_device *spi)
        kfree(ts);
 
        dev_dbg(&spi->dev, "unregistered touchscreen\n");
+
        return 0;
 }
 
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644 (file)
index 0000000..ccde586
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/input/bu21013.h>
+#include <linux/slab.h>
+
+#define PEN_DOWN_INTR  0
+#define MAX_FINGERS    2
+#define RESET_DELAY    30
+#define PENUP_TIMEOUT  (10)
+#define DELTA_MIN      16
+#define MASK_BITS      0x03
+#define SHIFT_8                8
+#define SHIFT_2                2
+#define LENGTH_OF_BUFFER       11
+#define I2C_RETRY_COUNT        5
+
+#define BU21013_SENSORS_BTN_0_7_REG    0x70
+#define BU21013_SENSORS_BTN_8_15_REG   0x71
+#define BU21013_SENSORS_BTN_16_23_REG  0x72
+#define BU21013_X1_POS_MSB_REG         0x73
+#define BU21013_X1_POS_LSB_REG         0x74
+#define BU21013_Y1_POS_MSB_REG         0x75
+#define BU21013_Y1_POS_LSB_REG         0x76
+#define BU21013_X2_POS_MSB_REG         0x77
+#define BU21013_X2_POS_LSB_REG         0x78
+#define BU21013_Y2_POS_MSB_REG         0x79
+#define BU21013_Y2_POS_LSB_REG         0x7A
+#define BU21013_INT_CLR_REG            0xE8
+#define BU21013_INT_MODE_REG           0xE9
+#define BU21013_GAIN_REG               0xEA
+#define BU21013_OFFSET_MODE_REG                0xEB
+#define BU21013_XY_EDGE_REG            0xEC
+#define BU21013_RESET_REG              0xED
+#define BU21013_CALIB_REG              0xEE
+#define BU21013_DONE_REG               0xEF
+#define BU21013_SENSOR_0_7_REG         0xF0
+#define BU21013_SENSOR_8_15_REG                0xF1
+#define BU21013_SENSOR_16_23_REG       0xF2
+#define BU21013_POS_MODE1_REG          0xF3
+#define BU21013_POS_MODE2_REG          0xF4
+#define BU21013_CLK_MODE_REG           0xF5
+#define BU21013_IDLE_REG               0xFA
+#define BU21013_FILTER_REG             0xFB
+#define BU21013_TH_ON_REG              0xFC
+#define BU21013_TH_OFF_REG             0xFD
+
+
+#define BU21013_RESET_ENABLE           0x01
+
+#define BU21013_SENSORS_EN_0_7         0x3F
+#define BU21013_SENSORS_EN_8_15                0xFC
+#define BU21013_SENSORS_EN_16_23       0x1F
+
+#define BU21013_POS_MODE1_0            0x02
+#define BU21013_POS_MODE1_1            0x04
+#define BU21013_POS_MODE1_2            0x08
+
+#define BU21013_POS_MODE2_ZERO         0x01
+#define BU21013_POS_MODE2_AVG1         0x02
+#define BU21013_POS_MODE2_AVG2         0x04
+#define BU21013_POS_MODE2_EN_XY                0x08
+#define BU21013_POS_MODE2_EN_RAW       0x10
+#define BU21013_POS_MODE2_MULTI                0x80
+
+#define BU21013_CLK_MODE_DIV           0x01
+#define BU21013_CLK_MODE_EXT           0x02
+#define BU21013_CLK_MODE_CALIB         0x80
+
+#define BU21013_IDLET_0                        0x01
+#define BU21013_IDLET_1                        0x02
+#define BU21013_IDLET_2                        0x04
+#define BU21013_IDLET_3                        0x08
+#define BU21013_IDLE_INTERMIT_EN       0x10
+
+#define BU21013_DELTA_0_6      0x7F
+#define BU21013_FILTER_EN      0x80
+
+#define BU21013_INT_MODE_LEVEL 0x00
+#define BU21013_INT_MODE_EDGE  0x01
+
+#define BU21013_GAIN_0         0x01
+#define BU21013_GAIN_1         0x02
+#define BU21013_GAIN_2         0x04
+
+#define BU21013_OFFSET_MODE_DEFAULT    0x00
+#define BU21013_OFFSET_MODE_MOVE       0x01
+#define BU21013_OFFSET_MODE_DISABLE    0x02
+
+#define BU21013_TH_ON_0                0x01
+#define BU21013_TH_ON_1                0x02
+#define BU21013_TH_ON_2                0x04
+#define BU21013_TH_ON_3                0x08
+#define BU21013_TH_ON_4                0x10
+#define BU21013_TH_ON_5                0x20
+#define BU21013_TH_ON_6                0x40
+#define BU21013_TH_ON_7                0x80
+#define BU21013_TH_ON_MAX      0xFF
+
+#define BU21013_TH_OFF_0       0x01
+#define BU21013_TH_OFF_1       0x02
+#define BU21013_TH_OFF_2       0x04
+#define BU21013_TH_OFF_3       0x08
+#define BU21013_TH_OFF_4       0x10
+#define BU21013_TH_OFF_5       0x20
+#define BU21013_TH_OFF_6       0x40
+#define BU21013_TH_OFF_7       0x80
+#define BU21013_TH_OFF_MAX     0xFF
+
+#define BU21013_X_EDGE_0       0x01
+#define BU21013_X_EDGE_1       0x02
+#define BU21013_X_EDGE_2       0x04
+#define BU21013_X_EDGE_3       0x08
+#define BU21013_Y_EDGE_0       0x10
+#define BU21013_Y_EDGE_1       0x20
+#define BU21013_Y_EDGE_2       0x40
+#define BU21013_Y_EDGE_3       0x80
+
+#define BU21013_DONE   0x01
+#define BU21013_NUMBER_OF_X_SENSORS    (6)
+#define BU21013_NUMBER_OF_Y_SENSORS    (11)
+
+#define DRIVER_TP      "bu21013_tp"
+
+/**
+ * struct bu21013_ts_data - touch panel data structure
+ * @client: pointer to the i2c client
+ * @wait: variable to wait_queue_head_t structure
+ * @touch_stopped: touch stop flag
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @intr_pin: interrupt pin value
+ *
+ * Touch panel device data structure
+ */
+struct bu21013_ts_data {
+       struct i2c_client *client;
+       wait_queue_head_t wait;
+       bool touch_stopped;
+       const struct bu21013_platform_device *chip;
+       struct input_dev *in_dev;
+       unsigned int intr_pin;
+};
+
+/**
+ * bu21013_read_block_data(): read the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ * @buf: byte pointer
+ *
+ * Read the touch co-ordinates using i2c read block into buffer
+ * and returns integer.
+ */
+static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+{
+       int ret, i;
+
+       for (i = 0; i < I2C_RETRY_COUNT; i++) {
+               ret = i2c_smbus_read_i2c_block_data
+                       (data->client, BU21013_SENSORS_BTN_0_7_REG,
+                               LENGTH_OF_BUFFER, buf);
+               if (ret == LENGTH_OF_BUFFER)
+                       return 0;
+       }
+       return -EINVAL;
+}
+
+/**
+ * bu21013_do_touch_report(): Get the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ *
+ * Get the touch co-ordinates from touch sensor registers and writes
+ * into device structure and returns integer.
+ */
+static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+{
+       u8      buf[LENGTH_OF_BUFFER];
+       unsigned int pos_x[2], pos_y[2];
+       bool    has_x_sensors, has_y_sensors;
+       int     finger_down_count = 0;
+       int     i;
+
+       if (data == NULL)
+               return -EINVAL;
+
+       if (bu21013_read_block_data(data, buf) < 0)
+               return -EINVAL;
+
+       has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
+       has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
+               ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
+       if (!has_x_sensors || !has_y_sensors)
+               return 0;
+
+       for (i = 0; i < MAX_FINGERS; i++) {
+               const u8 *p = &buf[4 * i + 3];
+               unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
+               unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
+               if (x == 0 || y == 0)
+                       continue;
+               pos_x[finger_down_count] = x;
+               pos_y[finger_down_count] = y;
+               finger_down_count++;
+       }
+
+       if (finger_down_count) {
+               if (finger_down_count == 2 &&
+                   (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
+                    abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
+                       return 0;
+               }
+
+               for (i = 0; i < finger_down_count; i++) {
+                       if (data->chip->x_flip)
+                               pos_x[i] = data->chip->touch_x_max - pos_x[i];
+                       if (data->chip->y_flip)
+                               pos_y[i] = data->chip->touch_y_max - pos_y[i];
+
+                       input_report_abs(data->in_dev,
+                                        ABS_MT_POSITION_X, pos_x[i]);
+                       input_report_abs(data->in_dev,
+                                        ABS_MT_POSITION_Y, pos_y[i]);
+                       input_mt_sync(data->in_dev);
+               }
+       } else
+               input_mt_sync(data->in_dev);
+
+       input_sync(data->in_dev);
+
+       return 0;
+}
+/**
+ * bu21013_gpio_irq() - gpio thread function for touch interrupt
+ * @irq: irq value
+ * @device_data: void pointer
+ *
+ * This gpio thread function for touch interrupt
+ * and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+       struct bu21013_ts_data *data = device_data;
+       struct i2c_client *i2c = data->client;
+       int retval;
+
+       do {
+               retval = bu21013_do_touch_report(data);
+               if (retval < 0) {
+                       dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
+                       return IRQ_NONE;
+               }
+
+               data->intr_pin = data->chip->irq_read_val();
+               if (data->intr_pin == PEN_DOWN_INTR)
+                       wait_event_timeout(data->wait, data->touch_stopped,
+                                          msecs_to_jiffies(2));
+       } while (!data->intr_pin && !data->touch_stopped);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * bu21013_init_chip() - power on sequence for the bu21013 controller
+ * @data: device structure pointer
+ *
+ * This function is used to power on
+ * the bu21013 controller and returns integer.
+ */
+static int bu21013_init_chip(struct bu21013_ts_data *data)
+{
+       int retval;
+       struct i2c_client *i2c = data->client;
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
+                                       BU21013_RESET_ENABLE);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
+               return retval;
+       }
+       msleep(RESET_DELAY);
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
+                                       BU21013_SENSORS_EN_0_7);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
+                                               BU21013_SENSORS_EN_8_15);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
+                                               BU21013_SENSORS_EN_16_23);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
+                               (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
+                       (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
+                       BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
+                       BU21013_POS_MODE2_MULTI));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
+               return retval;
+       }
+
+       if (data->chip->ext_clk)
+               retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+                       (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
+       else
+               retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+                       (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
+                               (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
+                                               BU21013_INT_MODE_LEVEL);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
+                                               (BU21013_DELTA_0_6 |
+                                                       BU21013_FILTER_EN));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
+                                       BU21013_TH_ON_5);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
+                               BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
+                                       (BU21013_GAIN_0 | BU21013_GAIN_1));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
+                                       BU21013_OFFSET_MODE_DEFAULT);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
+                               (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+                               BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
+               return retval;
+       }
+
+       retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
+                                                       BU21013_DONE);
+       if (retval < 0) {
+               dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
+               return retval;
+       }
+
+       return 0;
+}
+
+/**
+ * bu21013_free_irq() - frees IRQ registered for touchscreen
+ * @bu21013_data: device structure pointer
+ *
+ * This function signals interrupt thread to stop processing and
+ * frees interrupt.
+ */
+static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+{
+       bu21013_data->touch_stopped = true;
+       wake_up(&bu21013_data->wait);
+       free_irq(bu21013_data->chip->irq, bu21013_data);
+}
+
+/**
+ * bu21013_probe() - initializes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ * @id: i2c device id pointer
+ *
+ * This function used to initializes the i2c-client touchscreen
+ * driver and returns integer.
+ */
+static int __devinit bu21013_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct bu21013_ts_data *bu21013_data;
+       struct input_dev *in_dev;
+       const struct bu21013_platform_device *pdata =
+                                       client->dev.platform_data;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "i2c smbus byte data not supported\n");
+               return -EIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "platform data not defined\n");
+               return -EINVAL;
+       }
+
+       bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
+       in_dev = input_allocate_device();
+       if (!bu21013_data || !in_dev) {
+               dev_err(&client->dev, "device memory alloc failed\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       bu21013_data->in_dev = in_dev;
+       bu21013_data->chip = pdata;
+       bu21013_data->client = client;
+       bu21013_data->touch_stopped = false;
+       init_waitqueue_head(&bu21013_data->wait);
+
+       /* configure the gpio pins */
+       if (pdata->cs_en) {
+               error = pdata->cs_en(pdata->cs_pin);
+               if (error < 0) {
+                       dev_err(&client->dev, "chip init failed\n");
+                       goto err_free_mem;
+               }
+       }
+
+       /* configure the touch panel controller */
+       error = bu21013_init_chip(bu21013_data);
+       if (error) {
+               dev_err(&client->dev, "error in bu21013 config\n");
+               goto err_cs_disable;
+       }
+
+       /* register the device to input subsystem */
+       in_dev->name = DRIVER_TP;
+       in_dev->id.bustype = BUS_I2C;
+       in_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_SYN, in_dev->evbit);
+       __set_bit(EV_KEY, in_dev->evbit);
+       __set_bit(EV_ABS, in_dev->evbit);
+
+       input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
+                                               pdata->x_max_res, 0, 0);
+       input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
+                                               pdata->y_max_res, 0, 0);
+       input_set_drvdata(in_dev, bu21013_data);
+
+       error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
+                                    IRQF_TRIGGER_FALLING | IRQF_SHARED,
+                                    DRIVER_TP, bu21013_data);
+       if (error) {
+               dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
+               goto err_cs_disable;
+       }
+
+       error = input_register_device(in_dev);
+       if (error) {
+               dev_err(&client->dev, "failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       device_init_wakeup(&client->dev, pdata->wakeup);
+       i2c_set_clientdata(client, bu21013_data);
+
+       return 0;
+
+err_free_irq:
+       bu21013_free_irq(bu21013_data);
+err_cs_disable:
+       pdata->cs_dis(pdata->cs_pin);
+err_free_mem:
+       input_free_device(bu21013_data->in_dev);
+       kfree(bu21013_data);
+
+       return error;
+}
+/**
+ * bu21013_remove() - removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit bu21013_remove(struct i2c_client *client)
+{
+       struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+       bu21013_free_irq(bu21013_data);
+
+       bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
+
+       input_unregister_device(bu21013_data->in_dev);
+       kfree(bu21013_data);
+
+       device_init_wakeup(&client->dev, false);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int bu21013_suspend(struct device *dev)
+{
+       struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+       struct i2c_client *client = bu21013_data->client;
+
+       bu21013_data->touch_stopped = true;
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(bu21013_data->chip->irq);
+       else
+               disable_irq(bu21013_data->chip->irq);
+
+       return 0;
+}
+
+/**
+ * bu21013_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int bu21013_resume(struct device *dev)
+{
+       struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+       struct i2c_client *client = bu21013_data->client;
+       int retval;
+
+       retval = bu21013_init_chip(bu21013_data);
+       if (retval < 0) {
+               dev_err(&client->dev, "bu21013 controller config failed\n");
+               return retval;
+       }
+
+       bu21013_data->touch_stopped = false;
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(bu21013_data->chip->irq);
+       else
+               enable_irq(bu21013_data->chip->irq);
+
+       return 0;
+}
+
+static const struct dev_pm_ops bu21013_dev_pm_ops = {
+       .suspend = bu21013_suspend,
+       .resume  = bu21013_resume,
+};
+#endif
+
+static const struct i2c_device_id bu21013_id[] = {
+       { DRIVER_TP, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bu21013_id);
+
+static struct i2c_driver bu21013_driver = {
+       .driver = {
+               .name   =       DRIVER_TP,
+               .owner  =       THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     =       &bu21013_dev_pm_ops,
+#endif
+       },
+       .probe          =       bu21013_probe,
+       .remove         =       __devexit_p(bu21013_remove),
+       .id_table       =       bu21013_id,
+};
+
+/**
+ * bu21013_init() - initializes the bu21013 touchscreen driver
+ *
+ * This function used to initializes the bu21013
+ * touchscreen driver and returns integer.
+ */
+static int __init bu21013_init(void)
+{
+       return i2c_add_driver(&bu21013_driver);
+}
+
+/**
+ * bu21013_exit() - de-initializes the bu21013 touchscreen driver
+ *
+ * This function uses to de-initializes the bu21013
+ * touchscreen driver and returns none.
+ */
+static void __exit bu21013_exit(void)
+{
+       i2c_del_driver(&bu21013_driver);
+}
+
+module_init(bu21013_init);
+module_exit(bu21013_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
+MODULE_DESCRIPTION("bu21013 touch screen controller driver");
index 5ec0946938fe71e105dc519191debb8cc5c607c1..d0c3a7229adf3f9f1ee575d853a90fb3df54facf 100644 (file)
@@ -206,9 +206,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
        input_set_abs_params(input_dev, ABS_X,
-                       CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+                       CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
        input_set_abs_params(input_dev, ABS_Y,
-                       CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+                       CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
 
        if (ts->reset_pin) {
                err = gpio_request(ts->reset_pin, NULL);
index a89700e7ace42138e10a6a47e085a4b90a6f9c15..498bd62af09a284a8b8c8eb3bdc703af3a07e014 100644 (file)
@@ -107,8 +107,7 @@ static int __init hp680_ts_init(void)
        return 0;
 
  fail2:        free_irq(HP680_TS_IRQ, NULL);
-       cancel_delayed_work(&work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&work);
  fail1:        input_free_device(hp680_ts_dev);
        return err;
 }
@@ -116,8 +115,7 @@ static int __init hp680_ts_init(void)
 static void __exit hp680_ts_exit(void)
 {
        free_irq(HP680_TS_IRQ, NULL);
-       cancel_delayed_work(&work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&work);
        input_unregister_device(hp680_ts_dev);
 }
 
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c
new file mode 100644 (file)
index 0000000..c0307b2
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * Intel MID Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
+ * General Public License for more details.
+ *
+ * You 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.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ *                         Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO:
+ *     review conversion of r/m/w sequences
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/intel_scu_ipc.h>
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1           0x00 /* PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT           0x04 /* PMIC interrupt register */
+#define PMIC_REG_MINT          0x05 /* PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT                0x5F /* ADC interrupt register */
+#define PMIC_REG_MADCINT       0x60 /* ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1      0x61 /* ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0              0xA4
+#define END_OF_CHANNEL         0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H      0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10         0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11         0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12         0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13         0xD /* Touch screen Y- connection */
+
+/* Touch screen channel BIAS constants */
+#define MRST_XBIAS             0x20
+#define MRST_YBIAS             0x40
+#define MRST_ZBIAS             0x80
+
+/* Touch screen coordinates */
+#define MRST_X_MIN             10
+#define MRST_X_MAX             1024
+#define MRST_X_FUZZ            5
+#define MRST_Y_MIN             10
+#define MRST_Y_MAX             1024
+#define MRST_Y_FUZZ            5
+#define MRST_PRESSURE_MIN      0
+#define MRST_PRESSURE_NOMINAL  50
+#define MRST_PRESSURE_MAX      100
+
+#define WAIT_ADC_COMPLETION    10 /* msec */
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0                0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1                0x1 /* 4.5  ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS         0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM      1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC                2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS  32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+       struct device *dev; /* device associated with touch screen */
+       struct input_dev *input;
+       char phys[32];
+       u16 asr;                /* Address selection register */
+       int irq;
+       unsigned int vendor;    /* PMIC vendor */
+       unsigned int rev;       /* PMIC revision */
+
+       int (*read_prepare)(struct mrstouch_dev *tsdev);
+       int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
+       int (*read_finish)(struct mrstouch_dev *tsdev);
+};
+
+
+/*************************** NEC and Maxim Interface ************************/
+
+static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+       return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0, 0x20);
+}
+
+/*
+ * Enables PENDET interrupt.
+ */
+static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+       int err;
+
+       err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x20, 0x20);
+       if (!err)
+               err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, 0, 0x05);
+
+       return err;
+}
+
+/*
+ * Reads PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits and
+ * converts the two readings into a single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+       int err;
+       u16 result;
+       u32 res;
+
+       result = PMIC_REG_ADCSNS0H + offset;
+
+       if (chan == MRST_TS_CHAN12)
+               result += 4;
+
+       err = intel_scu_ipc_ioread32(result, &res);
+       if (err)
+               return err;
+
+       /* Mash the bits up */
+
+       *vp = (res & 0xFF) << 3;        /* Highest 7 bits */
+       *vp |= (res >> 8) & 0x07;       /* Lower 3 bits */
+       *vp &= 0x3FF;
+
+       res >>= 16;
+
+       *vm = (res & 0xFF) << 3;        /* Highest 7 bits */
+       *vm |= (res >> 8) & 0x07;       /* Lower 3 bits */
+       *vm &= 0x3FF;
+
+       return 0;
+}
+
+/*
+ * Enables X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+       int count;
+       u16 chan, start;
+       u16 reg[4];
+       u8 data[4];
+
+       chan = PMICADDR0 + offset;
+       start = MRST_TS_CHAN10;
+
+       for (count = 0; count <= 3; count++) {
+               reg[count] = chan++;
+               data[count] = bias | (start + count);
+       }
+
+       return intel_scu_ipc_writev(reg, data, 4);
+}
+
+/* To read touch screen channel values */
+static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
+                                u16 *x, u16 *y, u16 *z)
+{
+       int err;
+       u16 xm, ym, zm;
+
+       /* configure Y bias for X channels */
+       err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       /* read x+ and x- channels */
+       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
+       if (err)
+               goto ipc_error;
+
+       /* configure x bias for y channels */
+       err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       /* read y+ and y- channels */
+       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
+       if (err)
+               goto ipc_error;
+
+       /* configure z bias for x and y channels */
+       err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       /* read z+ and z- channels */
+       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
+       if (err)
+               goto ipc_error;
+
+       return 0;
+
+ipc_error:
+       dev_err(tsdev->dev, "ipc error during adc read\n");
+       return err;
+}
+
+
+/*************************** Freescale Interface ************************/
+
+static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+       int err, count;
+       u16 chan;
+       u16 reg[5];
+       u8 data[5];
+
+       /* Stop the ADC */
+       err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
+       if (err)
+               goto ipc_error;
+
+       chan = PMICADDR0 + tsdev->asr;
+
+       /* Set X BIAS */
+       for (count = 0; count <= 3; count++) {
+               reg[count] = chan++;
+               data[count] = 0x2A;
+       }
+       reg[count] =  chan++; /* Dummy */
+       data[count] = 0;
+
+       err = intel_scu_ipc_writev(reg, data, 5);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       /* Set Y BIAS */
+       for (count = 0; count <= 3; count++) {
+               reg[count] = chan++;
+               data[count] = 0x4A;
+       }
+       reg[count] = chan++; /* Dummy */
+       data[count] = 0;
+
+       err = intel_scu_ipc_writev(reg, data, 5);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       /* Set Z BIAS */
+       err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
+       if (err)
+               goto ipc_error;
+
+       msleep(WAIT_ADC_COMPLETION);
+
+       return 0;
+
+ipc_error:
+       dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+       return err;
+}
+
+static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
+                               u16 *x, u16 *y, u16 *z)
+{
+       int err;
+       u16 result;
+       u16 reg[4];
+       u8 data[4];
+
+       result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+       reg[0] = result + 4;
+       reg[1] = result + 5;
+       reg[2] = result + 16;
+       reg[3] = result + 17;
+
+       err = intel_scu_ipc_readv(reg, data, 4);
+       if (err)
+               goto ipc_error;
+
+       *x = data[0] << 3; /* Higher 7 bits */
+       *x |= data[1] & 0x7; /* Lower 3 bits */
+       *x &= 0x3FF;
+
+       *y = data[2] << 3; /* Higher 7 bits */
+       *y |= data[3] & 0x7; /* Lower 3 bits */
+       *y &= 0x3FF;
+
+       /* Read Z value */
+       reg[0] = result + 28;
+       reg[1] = result + 29;
+
+       err = intel_scu_ipc_readv(reg, data, 4);
+       if (err)
+               goto ipc_error;
+
+       *z = data[0] << 3; /* Higher 7 bits */
+       *z |= data[1] & 0x7; /* Lower 3 bits */
+       *z &= 0x3FF;
+
+       return 0;
+
+ipc_error:
+       dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+       return err;
+}
+
+static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+       int err, count;
+       u16 chan;
+       u16 reg[5];
+       u8 data[5];
+
+       /* Clear all TS channels */
+       chan = PMICADDR0 + tsdev->asr;
+       for (count = 0; count <= 4; count++) {
+               reg[count] = chan++;
+               data[count] = 0;
+       }
+       err = intel_scu_ipc_writev(reg, data, 5);
+       if (err)
+               goto ipc_error;
+
+       for (count = 0; count <= 4; count++) {
+               reg[count] = chan++;
+               data[count] = 0;
+       }
+       err = intel_scu_ipc_writev(reg, data, 5);
+       if (err)
+               goto ipc_error;
+
+       err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
+       if (err)
+               goto ipc_error;
+
+       /* Start ADC */
+       err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
+       if (err)
+               goto ipc_error;
+
+       return 0;
+
+ipc_error:
+       dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+       return err;
+}
+
+static void mrstouch_report_event(struct input_dev *input,
+                       unsigned int x, unsigned int y, unsigned int z)
+{
+       if (z > MRST_PRESSURE_NOMINAL) {
+               /* Pen touched, report button touch and coordinates */
+               input_report_key(input, BTN_TOUCH, 1);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+       } else {
+               input_report_key(input, BTN_TOUCH, 0);
+       }
+
+       input_report_abs(input, ABS_PRESSURE, z);
+       input_sync(input);
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
+{
+       struct mrstouch_dev *tsdev = dev_id;
+       u16 x, y, z;
+
+       /*
+        * Should we lower thread priority? Probably not, since we are
+        * not spinning but sleeping...
+        */
+
+       if (tsdev->read_prepare(tsdev))
+               goto out;
+
+       do {
+               if (tsdev->read(tsdev, &x, &y, &z))
+                       break;
+
+               mrstouch_report_event(tsdev->input, x, y, z);
+       } while (z > MRST_PRESSURE_NOMINAL);
+
+       tsdev->read_finish(tsdev);
+
+out:
+       return IRQ_HANDLED;
+}
+
+/* Utility to read PMIC ID */
+static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
+{
+       int err;
+       u8 r;
+
+       err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
+       if (err)
+               return err;
+
+       *vendor = r & 0x7;
+       *rev = (r >> 3) & 0x7;
+
+       return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+{
+       int err, i, found;
+       u8 r8;
+
+       found = -1;
+
+       for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+               if (found >= 0)
+                       break;
+
+               err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
+               if (err)
+                       return err;
+
+               if (r8 == END_OF_CHANNEL) {
+                       found = i;
+                       break;
+               }
+       }
+       if (found < 0)
+               return 0;
+
+       if (tsdev->vendor == PMIC_VENDOR_FS) {
+               if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+                       return -ENOSPC;
+       } else {
+               if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+                       return -ENOSPC;
+       }
+       return found;
+}
+
+
+/*
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int __devinit mrstouch_ts_chan_set(uint offset)
+{
+       u16 chan;
+
+       int ret, count;
+
+       chan = PMICADDR0 + offset;
+       for (count = 0; count <= 3; count++) {
+               ret = intel_scu_ipc_iowrite8(chan++, MRST_TS_CHAN10 + count);
+               if (ret)
+                       return ret;
+       }
+       return intel_scu_ipc_iowrite8(chan++, END_OF_CHANNEL);
+}
+
+/* Initialize ADC */
+static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+       int err, start;
+       u8 ra, rm;
+
+       err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
+       if (err) {
+               dev_err(tsdev->dev, "Unable to read PMIC id\n");
+               return err;
+       }
+
+       switch (tsdev->vendor) {
+       case PMIC_VENDOR_NEC:
+       case PMIC_VENDOR_MAXIM:
+               tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
+               tsdev->read = mrstouch_nec_adc_read;
+               tsdev->read_finish = mrstouch_nec_adc_read_finish;
+               break;
+
+       case PMIC_VENDOR_FS:
+               tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
+               tsdev->read = mrstouch_fs_adc_read;
+               tsdev->read_finish = mrstouch_fs_adc_read_finish;
+               break;
+
+       default:
+               dev_err(tsdev->dev,
+                       "Unsupported touchscreen: %d\n", tsdev->vendor);
+               return -ENXIO;
+       }
+
+       start = mrstouch_chan_parse(tsdev);
+       if (start < 0) {
+               dev_err(tsdev->dev, "Unable to parse channels\n");
+               return start;
+       }
+
+       tsdev->asr = start;
+
+       /*
+        * ADC power on, start, enable PENDET and set loop delay
+        * ADC loop delay is set to 4.5 ms approximately
+        * Loop delay more than this results in jitter in adc readings
+        * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
+        * interrupt generation sometimes.
+        */
+
+       if (tsdev->vendor == PMIC_VENDOR_FS) {
+               ra = 0xE0 | ADC_LOOP_DELAY0;
+               rm = 0x5;
+       } else {
+               /* NEC and MAXIm not consistent with loop delay 0 */
+               ra = 0xE0 | ADC_LOOP_DELAY1;
+               rm = 0x0;
+
+               /* configure touch screen channels */
+               err = mrstouch_ts_chan_set(tsdev->asr);
+               if (err)
+                       return err;
+       }
+
+       err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
+       if (err)
+               return err;
+
+       err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct platform_device *pdev)
+{
+       struct mrstouch_dev *tsdev;
+       struct input_dev *input;
+       int err;
+       int irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no interrupt assigned\n");
+               return -EINVAL;
+       }
+
+       tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!tsdev || !input) {
+               dev_err(&pdev->dev, "unable to allocate memory\n");
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       tsdev->dev = &pdev->dev;
+       tsdev->input = input;
+       tsdev->irq = irq;
+
+       snprintf(tsdev->phys, sizeof(tsdev->phys),
+                "%s/input0", dev_name(tsdev->dev));
+
+       err = mrstouch_adc_init(tsdev);
+       if (err) {
+               dev_err(&pdev->dev, "ADC initialization failed\n");
+               goto err_free_mem;
+       }
+
+       input->name = "mrst_touchscreen";
+       input->phys = tsdev->phys;
+       input->dev.parent = tsdev->dev;
+
+       input->id.vendor = tsdev->vendor;
+       input->id.version = tsdev->rev;
+
+       input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+       input_set_abs_params(tsdev->input, ABS_X,
+                            MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
+       input_set_abs_params(tsdev->input, ABS_Y,
+                            MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
+       input_set_abs_params(tsdev->input, ABS_PRESSURE,
+                            MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
+
+       err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
+                                  0, "mrstouch", tsdev);
+       if (err) {
+               dev_err(tsdev->dev, "unable to allocate irq\n");
+               goto err_free_mem;
+       }
+
+       err = input_register_device(tsdev->input);
+       if (err) {
+               dev_err(tsdev->dev, "unable to register input device\n");
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, tsdev);
+       return 0;
+
+err_free_irq:
+       free_irq(tsdev->irq, tsdev);
+err_free_mem:
+       input_free_device(input);
+       kfree(tsdev);
+       return err;
+}
+
+static int __devexit mrstouch_remove(struct platform_device *pdev)
+{
+       struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
+
+       free_irq(tsdev->irq, tsdev);
+       input_unregister_device(tsdev->input);
+       kfree(tsdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver mrstouch_driver = {
+       .driver = {
+               .name   = "pmic_touch",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mrstouch_probe,
+       .remove         = __devexit_p(mrstouch_remove),
+};
+
+static int __init mrstouch_init(void)
+{
+       return platform_driver_register(&mrstouch_driver);
+}
+module_init(mrstouch_init);
+
+static void __exit mrstouch_exit(void)
+{
+       platform_driver_unregister(&mrstouch_driver);
+}
+module_exit(mrstouch_exit);
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
new file mode 100644 (file)
index 0000000..dcf803f
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * LPC32xx built-in touchscreen driver
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * Touchscreen controller register offsets
+ */
+#define LPC32XX_TSC_STAT                       0x00
+#define LPC32XX_TSC_SEL                                0x04
+#define LPC32XX_TSC_CON                                0x08
+#define LPC32XX_TSC_FIFO                       0x0C
+#define LPC32XX_TSC_DTR                                0x10
+#define LPC32XX_TSC_RTR                                0x14
+#define LPC32XX_TSC_UTR                                0x18
+#define LPC32XX_TSC_TTR                                0x1C
+#define LPC32XX_TSC_DXP                                0x20
+#define LPC32XX_TSC_MIN_X                      0x24
+#define LPC32XX_TSC_MAX_X                      0x28
+#define LPC32XX_TSC_MIN_Y                      0x2C
+#define LPC32XX_TSC_MAX_Y                      0x30
+#define LPC32XX_TSC_AUX_UTR                    0x34
+#define LPC32XX_TSC_AUX_MIN                    0x38
+#define LPC32XX_TSC_AUX_MAX                    0x3C
+
+#define LPC32XX_TSC_STAT_FIFO_OVRRN            (1 << 8)
+#define LPC32XX_TSC_STAT_FIFO_EMPTY            (1 << 7)
+
+#define LPC32XX_TSC_SEL_DEFVAL                 0x0284
+
+#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4       (0x1 << 11)
+#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s)    ((10 - (s)) << 7)
+#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s)    ((10 - (s)) << 4)
+#define LPC32XX_TSC_ADCCON_POWER_UP            (1 << 2)
+#define LPC32XX_TSC_ADCCON_AUTO_EN             (1 << 0)
+
+#define LPC32XX_TSC_FIFO_TS_P_LEVEL            (1 << 31)
+#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x)    (((x) & 0x03FF0000) >> 16)
+#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y)    ((y) & 0x000003FF)
+
+#define LPC32XX_TSC_ADCDAT_VALUE_MASK          0x000003FF
+
+#define LPC32XX_TSC_MIN_XY_VAL                 0x0
+#define LPC32XX_TSC_MAX_XY_VAL                 0x3FF
+
+#define MOD_NAME "ts-lpc32xx"
+
+#define tsc_readl(dev, reg) \
+       __raw_readl((dev)->tsc_base + (reg))
+#define tsc_writel(dev, reg, val) \
+       __raw_writel((val), (dev)->tsc_base + (reg))
+
+struct lpc32xx_tsc {
+       struct input_dev *dev;
+       void __iomem *tsc_base;
+       int irq;
+       struct clk *clk;
+};
+
+static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
+{
+       while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+                       LPC32XX_TSC_STAT_FIFO_EMPTY))
+               tsc_readl(tsc, LPC32XX_TSC_FIFO);
+}
+
+static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
+{
+       u32 tmp, rv[4], xs[4], ys[4];
+       int idx;
+       struct lpc32xx_tsc *tsc = dev_id;
+       struct input_dev *input = tsc->dev;
+
+       tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
+
+       if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
+               /* FIFO overflow - throw away samples */
+               lpc32xx_fifo_clear(tsc);
+               return IRQ_HANDLED;
+       }
+
+       /*
+        * Gather and normalize 4 samples. Pen-up events may have less
+        * than 4 samples, but its ok to pop 4 and let the last sample
+        * pen status check drop the samples.
+        */
+       idx = 0;
+       while (idx < 4 &&
+              !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+                       LPC32XX_TSC_STAT_FIFO_EMPTY)) {
+               tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
+               xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+                       LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
+               ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+                       LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
+               rv[idx] = tmp;
+               idx++;
+       }
+
+       /* Data is only valid if pen is still down in last sample */
+       if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
+               /* Use average of 2nd and 3rd sample for position */
+               input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
+               input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
+               input_report_key(input, BTN_TOUCH, 1);
+       } else {
+               input_report_key(input, BTN_TOUCH, 0);
+       }
+
+       input_sync(input);
+
+       return IRQ_HANDLED;
+}
+
+static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
+{
+       /* Disable auto mode */
+       tsc_writel(tsc, LPC32XX_TSC_CON,
+                  tsc_readl(tsc, LPC32XX_TSC_CON) &
+                            ~LPC32XX_TSC_ADCCON_AUTO_EN);
+
+       clk_disable(tsc->clk);
+}
+
+static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
+{
+       u32 tmp;
+
+       clk_enable(tsc->clk);
+
+       tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
+
+       /* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
+       tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
+             LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
+             LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
+       tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
+
+       /* These values are all preset */
+       tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
+       tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
+       tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
+       tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
+       tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
+
+       /* Aux support is not used */
+       tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
+       tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
+       tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
+
+       /*
+        * Set sample rate to about 240Hz per X/Y pair. A single measurement
+        * consists of 4 pairs which gives about a 60Hz sample rate based on
+        * a stable 32768Hz clock source. Values are in clocks.
+        * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
+        */
+       tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
+       tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
+       tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
+       tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
+       tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
+
+       lpc32xx_fifo_clear(tsc);
+
+       /* Enable automatic ts event capture */
+       tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
+}
+
+static int lpc32xx_ts_open(struct input_dev *dev)
+{
+       struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+       lpc32xx_setup_tsc(tsc);
+
+       return 0;
+}
+
+static void lpc32xx_ts_close(struct input_dev *dev)
+{
+       struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+       lpc32xx_stop_tsc(tsc);
+}
+
+static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
+{
+       struct lpc32xx_tsc *tsc;
+       struct input_dev *input;
+       struct resource *res;
+       resource_size_t size;
+       int irq;
+       int error;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Can't get memory resource\n");
+               return -ENOENT;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Can't get interrupt resource\n");
+               return irq;
+       }
+
+       tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!tsc || !input) {
+               dev_err(&pdev->dev, "failed allocating memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       tsc->dev = input;
+       tsc->irq = irq;
+
+       size = resource_size(res);
+
+       if (!request_mem_region(res->start, size, pdev->name)) {
+               dev_err(&pdev->dev, "TSC registers are not free\n");
+               error = -EBUSY;
+               goto err_free_mem;
+       }
+
+       tsc->tsc_base = ioremap(res->start, size);
+       if (!tsc->tsc_base) {
+               dev_err(&pdev->dev, "Can't map memory\n");
+               error = -ENOMEM;
+               goto err_release_mem;
+       }
+
+       tsc->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(tsc->clk)) {
+               dev_err(&pdev->dev, "failed getting clock\n");
+               error = PTR_ERR(tsc->clk);
+               goto err_unmap;
+       }
+
+       input->name = MOD_NAME;
+       input->phys = "lpc32xx/input0";
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0002;
+       input->id.version = 0x0100;
+       input->dev.parent = &pdev->dev;
+       input->open = lpc32xx_ts_open;
+       input->close = lpc32xx_ts_close;
+
+       input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
+                            LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+       input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
+                            LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+
+       input_set_drvdata(input, tsc);
+
+       error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
+                           IRQF_DISABLED, pdev->name, tsc);
+       if (error) {
+               dev_err(&pdev->dev, "failed requesting interrupt\n");
+               goto err_put_clock;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev, "failed registering input device\n");
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, tsc);
+       device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+
+err_free_irq:
+       free_irq(tsc->irq, tsc);
+err_put_clock:
+       clk_put(tsc->clk);
+err_unmap:
+       iounmap(tsc->tsc_base);
+err_release_mem:
+       release_mem_region(res->start, size);
+err_free_mem:
+       input_free_device(input);
+       kfree(tsc);
+
+       return error;
+}
+
+static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)
+{
+       struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       device_init_wakeup(&pdev->dev, 0);
+       free_irq(tsc->irq, tsc);
+
+       input_unregister_device(tsc->dev);
+
+       clk_put(tsc->clk);
+
+       iounmap(tsc->tsc_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(tsc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_ts_suspend(struct device *dev)
+{
+       struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+       struct input_dev *input = tsc->dev;
+
+       /*
+        * Suspend and resume can be called when the device hasn't been
+        * enabled. If there are no users that have the device open, then
+        * avoid calling the TSC stop and start functions as the TSC
+        * isn't yet clocked.
+        */
+       mutex_lock(&input->mutex);
+
+       if (input->users) {
+               if (device_may_wakeup(dev))
+                       enable_irq_wake(tsc->irq);
+               else
+                       lpc32xx_stop_tsc(tsc);
+       }
+
+       mutex_unlock(&input->mutex);
+
+       return 0;
+}
+
+static int lpc32xx_ts_resume(struct device *dev)
+{
+       struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+       struct input_dev *input = tsc->dev;
+
+       mutex_lock(&input->mutex);
+
+       if (input->users) {
+               if (device_may_wakeup(dev))
+                       disable_irq_wake(tsc->irq);
+               else
+                       lpc32xx_setup_tsc(tsc);
+       }
+
+       mutex_unlock(&input->mutex);
+
+       return 0;
+}
+
+static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
+       .suspend        = lpc32xx_ts_suspend,
+       .resume         = lpc32xx_ts_resume,
+};
+#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
+#else
+#define LPC32XX_TS_PM_OPS NULL
+#endif
+
+static struct platform_driver lpc32xx_ts_driver = {
+       .probe          = lpc32xx_ts_probe,
+       .remove         = __devexit_p(lpc32xx_ts_remove),
+       .driver         = {
+               .name   = MOD_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = LPC32XX_TS_PM_OPS,
+       },
+};
+
+static int __init lpc32xx_ts_init(void)
+{
+       return platform_driver_register(&lpc32xx_ts_driver);
+}
+module_init(lpc32xx_ts_init);
+
+static void __exit lpc32xx_ts_exit(void)
+{
+       platform_driver_unregister(&lpc32xx_ts_driver);
+}
+module_exit(lpc32xx_ts_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
+MODULE_DESCRIPTION("LPC32XX TSC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_ts");
index 6085d12fd56196e0e47873bade9b4880ab5ca356..8feb7f3c8be17d19f40108d9ad3eddf4450ad309 100644 (file)
@@ -350,7 +350,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
  err_tcirq:
        free_irq(ts.irq_tc, ts.input);
  err_inputdev:
-       input_unregister_device(ts.input);
+       input_free_device(ts.input);
  err_iomap:
        iounmap(ts.io);
  err_clk:
index 656148ec00277d32ee2c7b2d24e6dba673375efb..ae88e13c99ff5194f88bb48f0096daf820c9bf47 100644 (file)
@@ -268,7 +268,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
        struct stmpe_touch *ts;
        struct input_dev *idev;
        struct stmpe_ts_platform_data *ts_pdata = NULL;
-       int ret = 0;
+       int ret;
        int ts_irq;
 
        ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
@@ -276,12 +276,16 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
                return ts_irq;
 
        ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-       if (!ts)
+       if (!ts) {
+               ret = -ENOMEM;
                goto err_out;
+       }
 
        idev = input_allocate_device();
-       if (!idev)
+       if (!idev) {
+               ret = -ENOMEM;
                goto err_free_ts;
+       }
 
        platform_set_drvdata(pdev, ts);
        ts->stmpe = stmpe;
@@ -361,7 +365,6 @@ static int __devexit stmpe_ts_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        input_unregister_device(ts->idev);
-       input_free_device(ts->idev);
 
        kfree(ts);
 
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
new file mode 100644 (file)
index 0000000..cf1dba2
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Texas Instruments TNETV107X Touchscreen Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/tnetv107x.h>
+
+#define TSC_PENUP_POLL         (HZ / 5)
+#define IDLE_TIMEOUT           100 /* msec */
+
+/*
+ * The first and last samples of a touch interval are usually garbage and need
+ * to be filtered out with these devices.  The following definitions control
+ * the number of samples skipped.
+ */
+#define TSC_HEAD_SKIP          1
+#define TSC_TAIL_SKIP          1
+#define TSC_SKIP               (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
+#define TSC_SAMPLES            (TSC_SKIP + 1)
+
+/* Register Offsets */
+struct tsc_regs {
+       u32     rev;
+       u32     tscm;
+       u32     bwcm;
+       u32     swc;
+       u32     adcchnl;
+       u32     adcdata;
+       u32     chval[4];
+};
+
+/* TSC Mode Configuration Register (tscm) bits */
+#define WMODE          BIT(0)
+#define TSKIND         BIT(1)
+#define ZMEASURE_EN    BIT(2)
+#define IDLE           BIT(3)
+#define TSC_EN         BIT(4)
+#define STOP           BIT(5)
+#define ONE_SHOT       BIT(6)
+#define SINGLE         BIT(7)
+#define AVG            BIT(8)
+#define AVGNUM(x)      (((x) & 0x03) <<  9)
+#define PVSTC(x)       (((x) & 0x07) << 11)
+#define PON            BIT(14)
+#define PONBG          BIT(15)
+#define AFERST         BIT(16)
+
+/* ADC DATA Capture Register bits */
+#define DATA_VALID     BIT(16)
+
+/* Register Access Macros */
+#define tsc_read(ts, reg)              __raw_readl(&(ts)->regs->reg)
+#define tsc_write(ts, reg, val)                __raw_writel(val, &(ts)->regs->reg);
+#define tsc_set_bits(ts, reg, val)     \
+       tsc_write(ts, reg, tsc_read(ts, reg) | (val))
+#define tsc_clr_bits(ts, reg, val)     \
+       tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
+
+struct sample {
+       int x, y, p;
+};
+
+struct tsc_data {
+       struct input_dev                *input_dev;
+       struct resource                 *res;
+       struct tsc_regs __iomem         *regs;
+       struct timer_list               timer;
+       spinlock_t                      lock;
+       struct clk                      *clk;
+       struct device                   *dev;
+       int                             sample_count;
+       struct sample                   samples[TSC_SAMPLES];
+       int                             tsc_irq;
+};
+
+static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
+{
+       int     x, y, z1, z2, t, p = 0;
+       u32     val;
+
+       val = tsc_read(ts, chval[0]);
+       if (val & DATA_VALID)
+               x = val & 0xffff;
+       else
+               return -EINVAL;
+
+       y  = tsc_read(ts, chval[1]) & 0xffff;
+       z1 = tsc_read(ts, chval[2]) & 0xffff;
+       z2 = tsc_read(ts, chval[3]) & 0xffff;
+
+       if (z1) {
+               t = ((600 * x) * (z2 - z1));
+               p = t / (u32) (z1 << 12);
+               if (p < 0)
+                       p = 0;
+       }
+
+       sample->x  = x;
+       sample->y  = y;
+       sample->p  = p;
+
+       return 0;
+}
+
+static void tsc_poll(unsigned long data)
+{
+       struct tsc_data *ts = (struct tsc_data *)data;
+       unsigned long flags;
+       int i, val, x, y, p;
+
+       spin_lock_irqsave(&ts->lock, flags);
+
+       if (ts->sample_count >= TSC_SKIP) {
+               input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
+               input_report_key(ts->input_dev, BTN_TOUCH, 0);
+               input_sync(ts->input_dev);
+       } else if (ts->sample_count > 0) {
+               /*
+                * A touch event lasted less than our skip count.  Salvage and
+                * report anyway.
+                */
+               for (i = 0, val = 0; i < ts->sample_count; i++)
+                       val += ts->samples[i].x;
+               x = val / ts->sample_count;
+
+               for (i = 0, val = 0; i < ts->sample_count; i++)
+                       val += ts->samples[i].y;
+               y = val / ts->sample_count;
+
+               for (i = 0, val = 0; i < ts->sample_count; i++)
+                       val += ts->samples[i].p;
+               p = val / ts->sample_count;
+
+               input_report_abs(ts->input_dev, ABS_X, x);
+               input_report_abs(ts->input_dev, ABS_Y, y);
+               input_report_abs(ts->input_dev, ABS_PRESSURE, p);
+               input_report_key(ts->input_dev, BTN_TOUCH, 1);
+               input_sync(ts->input_dev);
+       }
+
+       ts->sample_count = 0;
+
+       spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t tsc_irq(int irq, void *dev_id)
+{
+       struct tsc_data *ts = (struct tsc_data *)dev_id;
+       struct sample *sample;
+       int index;
+
+       spin_lock(&ts->lock);
+
+       index = ts->sample_count % TSC_SAMPLES;
+       sample = &ts->samples[index];
+       if (tsc_read_sample(ts, sample) < 0)
+               goto out;
+
+       if (++ts->sample_count >= TSC_SKIP) {
+               index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
+               sample = &ts->samples[index];
+
+               input_report_abs(ts->input_dev, ABS_X, sample->x);
+               input_report_abs(ts->input_dev, ABS_Y, sample->y);
+               input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
+               if (ts->sample_count == TSC_SKIP)
+                       input_report_key(ts->input_dev, BTN_TOUCH, 1);
+               input_sync(ts->input_dev);
+       }
+       mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
+out:
+       spin_unlock(&ts->lock);
+       return IRQ_HANDLED;
+}
+
+static int tsc_start(struct input_dev *dev)
+{
+       struct tsc_data *ts = input_get_drvdata(dev);
+       unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
+       u32 val;
+
+       clk_enable(ts->clk);
+
+       /* Go to idle mode, before any initialization */
+       while (time_after(timeout, jiffies)) {
+               if (tsc_read(ts, tscm) & IDLE)
+                       break;
+       }
+
+       if (time_before(timeout, jiffies)) {
+               dev_warn(ts->dev, "timeout waiting for idle\n");
+               clk_disable(ts->clk);
+               return -EIO;
+       }
+
+       /* Configure TSC Control register*/
+       val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
+       tsc_write(ts, tscm, val);
+
+       /* Bring TSC out of reset: Clear AFE reset bit */
+       val &= ~(AFERST);
+       tsc_write(ts, tscm, val);
+
+       /* Configure all pins for hardware control*/
+       tsc_write(ts, bwcm, 0);
+
+       /* Finally enable the TSC */
+       tsc_set_bits(ts, tscm, TSC_EN);
+
+       return 0;
+}
+
+static void tsc_stop(struct input_dev *dev)
+{
+       struct tsc_data *ts = input_get_drvdata(dev);
+
+       tsc_clr_bits(ts, tscm, TSC_EN);
+       synchronize_irq(ts->tsc_irq);
+       del_timer_sync(&ts->timer);
+       clk_disable(ts->clk);
+}
+
+static int __devinit tsc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tsc_data *ts;
+       int error = 0;
+       u32 rev = 0;
+
+       ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
+       if (!ts) {
+               dev_err(dev, "cannot allocate device info\n");
+               return -ENOMEM;
+       }
+
+       ts->dev = dev;
+       spin_lock_init(&ts->lock);
+       setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
+       platform_set_drvdata(pdev, ts);
+
+       ts->tsc_irq = platform_get_irq(pdev, 0);
+       if (ts->tsc_irq < 0) {
+               dev_err(dev, "cannot determine device interrupt\n");
+               error = -ENODEV;
+               goto error_res;
+       }
+
+       ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!ts->res) {
+               dev_err(dev, "cannot determine register area\n");
+               error = -ENODEV;
+               goto error_res;
+       }
+
+       if (!request_mem_region(ts->res->start, resource_size(ts->res),
+                               pdev->name)) {
+               dev_err(dev, "cannot claim register memory\n");
+               ts->res = NULL;
+               error = -EINVAL;
+               goto error_res;
+       }
+
+       ts->regs = ioremap(ts->res->start, resource_size(ts->res));
+       if (!ts->regs) {
+               dev_err(dev, "cannot map register memory\n");
+               error = -ENOMEM;
+               goto error_map;
+       }
+
+       ts->clk = clk_get(dev, NULL);
+       if (!ts->clk) {
+               dev_err(dev, "cannot claim device clock\n");
+               error = -EINVAL;
+               goto error_clk;
+       }
+
+       error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
+                                    dev_name(dev), ts);
+       if (error < 0) {
+               dev_err(ts->dev, "Could not allocate ts irq\n");
+               goto error_irq;
+       }
+
+       ts->input_dev = input_allocate_device();
+       if (!ts->input_dev) {
+               dev_err(dev, "cannot allocate input device\n");
+               error = -ENOMEM;
+               goto error_input;
+       }
+       input_set_drvdata(ts->input_dev, ts);
+
+       ts->input_dev->name       = pdev->name;
+       ts->input_dev->id.bustype = BUS_HOST;
+       ts->input_dev->dev.parent = &pdev->dev;
+       ts->input_dev->open       = tsc_start;
+       ts->input_dev->close      = tsc_stop;
+
+       clk_enable(ts->clk);
+       rev = tsc_read(ts, rev);
+       ts->input_dev->id.product = ((rev >>  8) & 0x07);
+       ts->input_dev->id.version = ((rev >> 16) & 0xfff);
+       clk_disable(ts->clk);
+
+       __set_bit(EV_KEY,    ts->input_dev->evbit);
+       __set_bit(EV_ABS,    ts->input_dev->evbit);
+       __set_bit(BTN_TOUCH, ts->input_dev->keybit);
+
+       input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
+       input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
+       input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
+
+       error = input_register_device(ts->input_dev);
+       if (error < 0) {
+               dev_err(dev, "failed input device registration\n");
+               goto error_reg;
+       }
+
+       return 0;
+
+error_reg:
+       input_free_device(ts->input_dev);
+error_input:
+       free_irq(ts->tsc_irq, ts);
+error_irq:
+       clk_put(ts->clk);
+error_clk:
+       iounmap(ts->regs);
+error_map:
+       release_mem_region(ts->res->start, resource_size(ts->res));
+error_res:
+       platform_set_drvdata(pdev, NULL);
+       kfree(ts);
+
+       return error;
+}
+
+static int __devexit tsc_remove(struct platform_device *pdev)
+{
+       struct tsc_data *ts = platform_get_drvdata(pdev);
+
+       input_unregister_device(ts->input_dev);
+       free_irq(ts->tsc_irq, ts);
+       clk_put(ts->clk);
+       iounmap(ts->regs);
+       release_mem_region(ts->res->start, resource_size(ts->res));
+       platform_set_drvdata(pdev, NULL);
+       kfree(ts);
+
+       return 0;
+}
+
+static struct platform_driver tsc_driver = {
+       .probe          = tsc_probe,
+       .remove         = __devexit_p(tsc_remove),
+       .driver.name    = "tnetv107x-ts",
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init tsc_init(void)
+{
+       return platform_driver_register(&tsc_driver);
+}
+
+static void __exit tsc_exit(void)
+{
+       platform_driver_unregister(&tsc_driver);
+}
+
+module_init(tsc_init);
+module_exit(tsc_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
+MODULE_ALIAS("platform: tnetv107x-ts");
+MODULE_LICENSE("GPL");
index a644d18c04dce09862663004217864698948fef0..c8c136cf7bbc2e5429a102974616a0b6dad369c7 100644 (file)
@@ -335,6 +335,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
                dev_err(tsc->dev, "schedule failed");
                goto err2;
         }
+       platform_set_drvdata(pdev, tps6507x_dev);
 
        return 0;
 
@@ -358,7 +359,7 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
        cancel_delayed_work_sync(&tsc->work);
        destroy_workqueue(tsc->wq);
 
-       input_free_device(input_dev);
+       input_unregister_device(input_dev);
 
        tps6507x_dev->ts = NULL;
        kfree(tsc);
index be23780e8a3e3b81be9df7b7cd0f8aab86d87e61..80467f262331e2c94ae9686f21e473b4d203f3f5 100644 (file)
@@ -265,7 +265,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct tsc2007 *ts;
-       struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
+       struct tsc2007_platform_data *pdata = client->dev.platform_data;
        struct input_dev *input_dev;
        int err;
 
index 56dc35c94bb12eb00102a0110044945574edbcf6..9ae4c7b16ba7e36a6a56a4261e9c2373095e4ea9 100644 (file)
@@ -2,6 +2,7 @@
  * Wacom W8001 penabled serial touchscreen driver
  *
  * Copyright (c) 2008 Jaya Kumar
+ * Copyright (c) 2010 Red Hat, Inc.
  *
  * 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
@@ -30,11 +31,24 @@ MODULE_LICENSE("GPL");
 #define W8001_LEAD_BYTE                0x80
 #define W8001_TAB_MASK         0x40
 #define W8001_TAB_BYTE         0x40
+/* set in first byte of touch data packets */
+#define W8001_TOUCH_MASK       (0x10 | W8001_LEAD_MASK)
+#define W8001_TOUCH_BYTE       (0x10 | W8001_LEAD_BYTE)
 
 #define W8001_QUERY_PACKET     0x20
 
 #define W8001_CMD_START                '1'
 #define W8001_CMD_QUERY                '*'
+#define W8001_CMD_TOUCHQUERY   '%'
+
+/* length of data packets in bytes, depends on device. */
+#define W8001_PKTLEN_TOUCH93   5
+#define W8001_PKTLEN_TOUCH9A   7
+#define W8001_PKTLEN_TPCPEN    9
+#define W8001_PKTLEN_TPCCTL    11      /* control packet */
+#define W8001_PKTLEN_TOUCH2FG  13
+
+#define MAX_TRACKING_ID                0xFF    /* arbitrarily chosen */
 
 struct w8001_coord {
        u8 rdy;
@@ -48,6 +62,15 @@ struct w8001_coord {
        u8 tilt_y;
 };
 
+/* touch query reply packet */
+struct w8001_touch_query {
+       u8 panel_res;
+       u8 capacity_res;
+       u8 sensor_id;
+       u16 x;
+       u16 y;
+};
+
 /*
  * Per-touchscreen data.
  */
@@ -62,6 +85,9 @@ struct w8001 {
        unsigned char response[W8001_MAX_LENGTH];
        unsigned char data[W8001_MAX_LENGTH];
        char phys[32];
+       int type;
+       unsigned int pktlen;
+       int trkid[2];
 };
 
 static void parse_data(u8 *data, struct w8001_coord *coord)
@@ -88,11 +114,98 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
        coord->tilt_y = data[8] & 0x7F;
 }
 
+static void parse_touch(struct w8001 *w8001)
+{
+       static int trkid;
+       struct input_dev *dev = w8001->dev;
+       unsigned char *data = w8001->data;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               input_mt_slot(dev, i);
+
+               if (data[0] & (1 << i)) {
+                       int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
+                       int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
+                       /* data[5,6] and [11,12] is finger capacity */
+
+                       input_report_abs(dev, ABS_MT_POSITION_X, x);
+                       input_report_abs(dev, ABS_MT_POSITION_Y, y);
+                       input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+                       if (w8001->trkid[i] < 0)
+                               w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
+               } else {
+                       w8001->trkid[i] = -1;
+               }
+               input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
+       }
+
+       input_sync(dev);
+}
+
+static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
+{
+       memset(query, 0, sizeof(*query));
+
+       query->panel_res = data[1];
+       query->sensor_id = data[2] & 0x7;
+       query->capacity_res = data[7];
+
+       query->x = data[3] << 9;
+       query->x |= data[4] << 2;
+       query->x |= (data[2] >> 5) & 0x3;
+
+       query->y = data[5] << 9;
+       query->y |= data[6] << 2;
+       query->y |= (data[2] >> 3) & 0x3;
+}
+
+static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
+{
+       struct input_dev *dev = w8001->dev;
+
+       /*
+        * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
+        * side2/eraser. If rdy && f2 are set, this can be either pen + side2,
+        * or eraser. assume
+        * - if dev is already in proximity and f2 is toggled → pen + side2
+        * - if dev comes into proximity with f2 set → eraser
+        * If f2 disappears after assuming eraser, fake proximity out for
+        * eraser and in for pen.
+        */
+
+       if (!w8001->type) {
+               w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+       } else if (w8001->type == BTN_TOOL_RUBBER) {
+               if (!coord->f2) {
+                       input_report_abs(dev, ABS_PRESSURE, 0);
+                       input_report_key(dev, BTN_TOUCH, 0);
+                       input_report_key(dev, BTN_STYLUS, 0);
+                       input_report_key(dev, BTN_STYLUS2, 0);
+                       input_report_key(dev, BTN_TOOL_RUBBER, 0);
+                       input_sync(dev);
+                       w8001->type = BTN_TOOL_PEN;
+               }
+       } else {
+               input_report_key(dev, BTN_STYLUS2, coord->f2);
+       }
+
+       input_report_abs(dev, ABS_X, coord->x);
+       input_report_abs(dev, ABS_Y, coord->y);
+       input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure);
+       input_report_key(dev, BTN_TOUCH, coord->tsw);
+       input_report_key(dev, BTN_STYLUS, coord->f1);
+       input_report_key(dev, w8001->type, coord->rdy);
+       input_sync(dev);
+
+       if (!coord->rdy)
+               w8001->type = 0;
+}
+
 static irqreturn_t w8001_interrupt(struct serio *serio,
                                   unsigned char data, unsigned int flags)
 {
        struct w8001 *w8001 = serio_get_drvdata(serio);
-       struct input_dev *dev = w8001->dev;
        struct w8001_coord coord;
        unsigned char tmp;
 
@@ -105,26 +218,45 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
                }
                break;
 
-       case 8:
+       case W8001_PKTLEN_TOUCH93 - 1:
+       case W8001_PKTLEN_TOUCH9A - 1:
+               /* ignore one-finger touch packet. */
+               if (w8001->pktlen == w8001->idx)
+                       w8001->idx = 0;
+               break;
+
+       /* Pen coordinates packet */
+       case W8001_PKTLEN_TPCPEN - 1:
                tmp = w8001->data[0] & W8001_TAB_MASK;
                if (unlikely(tmp == W8001_TAB_BYTE))
                        break;
 
+               tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
+               if (tmp == W8001_TOUCH_BYTE)
+                       break;
+
                w8001->idx = 0;
                parse_data(w8001->data, &coord);
-               input_report_abs(dev, ABS_X, coord.x);
-               input_report_abs(dev, ABS_Y, coord.y);
-               input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure);
-               input_report_key(dev, BTN_TOUCH, coord.tsw);
-               input_sync(dev);
+               report_pen_events(w8001, &coord);
                break;
 
-       case 10:
+       /* control packet */
+       case W8001_PKTLEN_TPCCTL - 1:
+               tmp = (w8001->data[0] & W8001_TOUCH_MASK);
+               if (tmp == W8001_TOUCH_BYTE)
+                       break;
+
                w8001->idx = 0;
                memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
                w8001->response_type = W8001_QUERY_PACKET;
                complete(&w8001->cmd_done);
                break;
+
+       /* 2 finger touch packet */
+       case W8001_PKTLEN_TOUCH2FG - 1:
+               w8001->idx = 0;
+               parse_touch(w8001);
+               break;
        }
 
        return IRQ_HANDLED;
@@ -167,6 +299,38 @@ static int w8001_setup(struct w8001 *w8001)
        input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
        input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
 
+       error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+       if (!error) {
+               struct w8001_touch_query touch;
+
+               parse_touchquery(w8001->response, &touch);
+
+               switch (touch.sensor_id) {
+               case 0:
+               case 2:
+                       w8001->pktlen = W8001_PKTLEN_TOUCH93;
+                       break;
+               case 1:
+               case 3:
+               case 4:
+                       w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+                       break;
+               case 5:
+                       w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+                       input_mt_create_slots(dev, 2);
+                       input_set_abs_params(dev, ABS_MT_TRACKING_ID,
+                                               0, MAX_TRACKING_ID, 0, 0);
+                       input_set_abs_params(dev, ABS_MT_POSITION_X,
+                                               0, touch.x, 0, 0);
+                       input_set_abs_params(dev, ABS_MT_POSITION_Y,
+                                               0, touch.y, 0, 0);
+                       input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
+                                               0, 0, 0, 0);
+                       break;
+               }
+       }
+
        return w8001_command(w8001, W8001_CMD_START, false);
 }
 
@@ -208,6 +372,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
        w8001->serio = serio;
        w8001->id = serio->id.id;
        w8001->dev = input_dev;
+       w8001->trkid[0] = w8001->trkid[1] = -1;
        init_completion(&w8001->cmd_done);
        snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
 
@@ -221,6 +386,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN);
+       input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER);
+       input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS);
+       input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2);
 
        serio_set_drvdata(serio, w8001);
        err = serio_open(serio, drv);
index cbfef1ea7e30b55945c82314a9da5bf9a42a2457..6b75c9f660ae213294ac656e91e4b961fbb8f083 100644 (file)
@@ -125,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
 {
        int power_adc = 0, auxval;
        u16 power = 0;
+       int rc = 0;
+       int timeout = 0;
 
        /* get codec */
        mutex_lock(&wm->codec_mutex);
@@ -143,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
 
        /* Turn polling mode on to read AUX ADC */
        wm->pen_probably_down = 1;
-       wm->codec->poll_sample(wm, adcsel, &auxval);
+
+       while (rc != RC_VALID && timeout++ < 5)
+               rc = wm->codec->poll_sample(wm, adcsel, &auxval);
 
        if (power_adc)
                wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
@@ -152,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
 
        wm->pen_probably_down = 0;
 
+       if (timeout >= 5) {
+               dev_err(wm->dev,
+                       "timeout reading auxadc %d, disabling digitiser\n",
+                       adcsel);
+               wm->codec->dig_enable(wm, false);
+       }
+
        mutex_unlock(&wm->codec_mutex);
-       return auxval & 0xfff;
+       return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
 }
 EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
 
@@ -684,8 +695,7 @@ static int wm97xx_probe(struct device *dev)
  touch_reg_err:
        platform_device_put(wm->touch_dev);
  touch_err:
-       platform_device_unregister(wm->battery_dev);
-       wm->battery_dev = NULL;
+       platform_device_del(wm->battery_dev);
  batt_reg_err:
        platform_device_put(wm->battery_dev);
  batt_err:
index 947d4afa25ca9abfe199ffea35f2233e944c9498..30e6195e19d4ddca5c25f6d26534e7a5e6c55785 100644 (file)
@@ -482,7 +482,7 @@ static s32 pm121_correct(s32 new_setpoint,
        new_min += correction->offset;
        new_min = (new_min >> 16) + min;
 
-       return max(new_setpoint, max(new_min, 0));
+       return max3(new_setpoint, new_min, 0);
 }
 
 static s32 pm121_connect(unsigned int control_id, s32 setpoint)
index 0b61792a278041bc6bedc9c04800457f93db1f6d..2129cdb115dc0e72caced734068deee43f10aa1e 100644 (file)
@@ -254,7 +254,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
         * Issue the synchronous I/O from a different thread
         * to avoid generic_make_request recursion.
         */
-       INIT_WORK_ON_STACK(&req.work, do_metadata);
+       INIT_WORK_ONSTACK(&req.work, do_metadata);
        queue_work(ps->metadata_wq, &req.work);
        flush_workqueue(ps->metadata_wq);
 
index 7961d59f5cace91b18fc6a67fef4caea09f08265..c06b4d50a3dca84e28021b8cd02b05886ea87f81 100644 (file)
 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
 #define IR_KEYPRESS_TIMEOUT 250
 
+/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_tab:    the ir_scancode_table to initialize
+ * @name:      name to assign to the table
+ * @ir_type:   ir type to assign to the new table
+ * @size:      initial size of the table
+ * @return:    zero on success or a negative error code
+ *
+ * This routine will initialize the ir_scancode_table and will allocate
+ * memory to hold at least the specified number elements.
+ */
+static int ir_create_table(struct ir_scancode_table *rc_tab,
+                          const char *name, u64 ir_type, size_t size)
+{
+       rc_tab->name = name;
+       rc_tab->ir_type = ir_type;
+       rc_tab->alloc = roundup_pow_of_two(size * sizeof(struct ir_scancode));
+       rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
+       rc_tab->scan = kmalloc(rc_tab->alloc, GFP_KERNEL);
+       if (!rc_tab->scan)
+               return -ENOMEM;
+
+       IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+                  rc_tab->size, rc_tab->alloc);
+       return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_tab:    the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct ir_scancode_table *rc_tab)
+{
+       rc_tab->size = 0;
+       kfree(rc_tab->scan);
+       rc_tab->scan = NULL;
+}
+
 /**
  * ir_resize_table() - resizes a scancode table if necessary
  * @rc_tab:    the ir_scancode_table to resize
+ * @gfp_flags: gfp flags to use when allocating memory
  * @return:    zero on success or a negative error code
  *
  * This routine will shrink the ir_scancode_table if it has lots of
  * unused entries and grow it if it is full.
  */
-static int ir_resize_table(struct ir_scancode_table *rc_tab)
+static int ir_resize_table(struct ir_scancode_table *rc_tab, gfp_t gfp_flags)
 {
        unsigned int oldalloc = rc_tab->alloc;
        unsigned int newalloc = oldalloc;
@@ -57,7 +99,7 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
        if (newalloc == oldalloc)
                return 0;
 
-       newscan = kmalloc(newalloc, GFP_ATOMIC);
+       newscan = kmalloc(newalloc, gfp_flags);
        if (!newscan) {
                IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
                return -ENOMEM;
@@ -72,26 +114,78 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
 }
 
 /**
- * ir_do_setkeycode() - internal function to set a keycode in the
- *                     scancode->keycode table
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
  * @dev:       the struct input_dev device descriptor
- * @rc_tab:    the struct ir_scancode_table to set the keycode in
- * @scancode:  the scancode for the ir command
- * @keycode:   the keycode for the ir command
- * @resize:    whether the keytable may be shrunk
- * @return:    -EINVAL if the keycode could not be inserted, otherwise zero.
+ * @rc_tab:    scancode table to be adjusted
+ * @index:     index of the mapping that needs to be updated
+ * @keycode:   the desired keycode
+ * @return:    previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycopde mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct input_dev *dev,
+                                     struct ir_scancode_table *rc_tab,
+                                     unsigned int index,
+                                     unsigned int new_keycode)
+{
+       int old_keycode = rc_tab->scan[index].keycode;
+       int i;
+
+       /* Did the user wish to remove the mapping? */
+       if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+               IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+                          index, rc_tab->scan[index].scancode);
+               rc_tab->len--;
+               memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1],
+                       (rc_tab->len - index) * sizeof(struct ir_scancode));
+       } else {
+               IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+                          index,
+                          old_keycode == KEY_RESERVED ? "New" : "Replacing",
+                          rc_tab->scan[index].scancode, new_keycode);
+               rc_tab->scan[index].keycode = new_keycode;
+               __set_bit(new_keycode, dev->keybit);
+       }
+
+       if (old_keycode != KEY_RESERVED) {
+               /* A previous mapping was updated... */
+               __clear_bit(old_keycode, dev->keybit);
+               /* ... but another scancode might use the same keycode */
+               for (i = 0; i < rc_tab->len; i++) {
+                       if (rc_tab->scan[i].keycode == old_keycode) {
+                               __set_bit(old_keycode, dev->keybit);
+                               break;
+                       }
+               }
+
+               /* Possibly shrink the keytable, failure is not a problem */
+               ir_resize_table(rc_tab, GFP_ATOMIC);
+       }
+
+       return old_keycode;
+}
+
+/**
+ * ir_locate_scancode() - set a keycode in the scancode->keycode table
+ * @ir_dev:    the struct ir_input_dev device descriptor
+ * @rc_tab:    scancode table to be searched
+ * @scancode:  the desired scancode
+ * @resize:    controls whether we allowed to resize the table to
+ *             accomodate not yet present scancodes
+ * @return:    index of the mapping containing scancode in question
+ *             or -1U in case of failure.
  *
- * This routine is used internally to manipulate the scancode->keycode table.
- * The caller has to hold @rc_tab->lock.
+ * This routine is used to locate given scancode in ir_scancode_table.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
  */
-static int ir_do_setkeycode(struct input_dev *dev,
-                           struct ir_scancode_table *rc_tab,
-                           unsigned scancode, unsigned keycode,
-                           bool resize)
+static unsigned int ir_establish_scancode(struct ir_input_dev *ir_dev,
+                                         struct ir_scancode_table *rc_tab,
+                                         unsigned int scancode,
+                                         bool resize)
 {
        unsigned int i;
-       int old_keycode = KEY_RESERVED;
-       struct ir_input_dev *ir_dev = input_get_drvdata(dev);
 
        /*
         * Unfortunately, some hardware-based IR decoders don't provide
@@ -100,65 +194,34 @@ static int ir_do_setkeycode(struct input_dev *dev,
         * the provided IR with another one, it is needed to allow loading
         * IR tables from other remotes. So,
         */
-       if (ir_dev->props && ir_dev->props->scanmask) {
+       if (ir_dev->props && ir_dev->props->scanmask)
                scancode &= ir_dev->props->scanmask;
-       }
 
        /* First check if we already have a mapping for this ir command */
        for (i = 0; i < rc_tab->len; i++) {
+               if (rc_tab->scan[i].scancode == scancode)
+                       return i;
+
                /* Keytable is sorted from lowest to highest scancode */
-               if (rc_tab->scan[i].scancode > scancode)
+               if (rc_tab->scan[i].scancode >= scancode)
                        break;
-               else if (rc_tab->scan[i].scancode < scancode)
-                       continue;
-
-               old_keycode = rc_tab->scan[i].keycode;
-               rc_tab->scan[i].keycode = keycode;
-
-               /* Did the user wish to remove the mapping? */
-               if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
-                       IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
-                                  i, scancode);
-                       rc_tab->len--;
-                       memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
-                               (rc_tab->len - i) * sizeof(struct ir_scancode));
-               }
-
-               /* Possibly shrink the keytable, failure is not a problem */
-               ir_resize_table(rc_tab);
-               break;
        }
 
-       if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) {
-               /* No previous mapping found, we might need to grow the table */
-               if (resize && ir_resize_table(rc_tab))
-                       return -ENOMEM;
-
-               IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
-                          i, scancode, keycode);
+       /* No previous mapping found, we might need to grow the table */
+       if (rc_tab->size == rc_tab->len) {
+               if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC))
+                       return -1U;
+       }
 
-               /* i is the proper index to insert our new keycode */
+       /* i is the proper index to insert our new keycode */
+       if (i < rc_tab->len)
                memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
                        (rc_tab->len - i) * sizeof(struct ir_scancode));
-               rc_tab->scan[i].scancode = scancode;
-               rc_tab->scan[i].keycode = keycode;
-               rc_tab->len++;
-               set_bit(keycode, dev->keybit);
-       } else {
-               IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
-                          i, scancode, keycode);
-               /* A previous mapping was updated... */
-               clear_bit(old_keycode, dev->keybit);
-               /* ...but another scancode might use the same keycode */
-               for (i = 0; i < rc_tab->len; i++) {
-                       if (rc_tab->scan[i].keycode == old_keycode) {
-                               set_bit(old_keycode, dev->keybit);
-                               break;
-                       }
-               }
-       }
+       rc_tab->scan[i].scancode = scancode;
+       rc_tab->scan[i].keycode = KEY_RESERVED;
+       rc_tab->len++;
 
-       return 0;
+       return i;
 }
 
 /**
@@ -171,17 +234,41 @@ static int ir_do_setkeycode(struct input_dev *dev,
  * This routine is used to handle evdev EVIOCSKEY ioctl.
  */
 static int ir_setkeycode(struct input_dev *dev,
-                        unsigned int scancode, unsigned int keycode)
+                        const struct input_keymap_entry *ke,
+                        unsigned int *old_keycode)
 {
-       int rc;
-       unsigned long flags;
        struct ir_input_dev *ir_dev = input_get_drvdata(dev);
        struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+       unsigned int index;
+       unsigned int scancode;
+       int retval;
+       unsigned long flags;
 
        spin_lock_irqsave(&rc_tab->lock, flags);
-       rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode, true);
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+               if (index >= rc_tab->len) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+       } else {
+               retval = input_scancode_to_scalar(ke, &scancode);
+               if (retval)
+                       goto out;
+
+               index = ir_establish_scancode(ir_dev, rc_tab, scancode, true);
+               if (index >= rc_tab->len) {
+                       retval = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       *old_keycode = ir_update_mapping(dev, rc_tab, index, ke->keycode);
+
+out:
        spin_unlock_irqrestore(&rc_tab->lock, flags);
-       return rc;
+       return retval;
 }
 
 /**
@@ -189,31 +276,72 @@ static int ir_setkeycode(struct input_dev *dev,
  * @dev:       the struct input_dev device descriptor
  * @to:                the struct ir_scancode_table to copy entries to
  * @from:      the struct ir_scancode_table to copy entries from
- * @return:    -EINVAL if all keycodes could not be inserted, otherwise zero.
+ * @return:    -ENOMEM if all keycodes could not be inserted, otherwise zero.
  *
  * This routine is used to handle table initialization.
  */
-static int ir_setkeytable(struct input_dev *dev,
-                         struct ir_scancode_table *to,
+static int ir_setkeytable(struct ir_input_dev *ir_dev,
                          const struct ir_scancode_table *from)
 {
-       struct ir_input_dev *ir_dev = input_get_drvdata(dev);
        struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
-       unsigned long flags;
-       unsigned int i;
-       int rc = 0;
+       unsigned int i, index;
+       int rc;
+
+       rc = ir_create_table(&ir_dev->rc_tab,
+                            from->name, from->ir_type, from->size);
+       if (rc)
+               return rc;
+
+       IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+                  rc_tab->size, rc_tab->alloc);
 
-       spin_lock_irqsave(&rc_tab->lock, flags);
        for (i = 0; i < from->size; i++) {
-               rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
-                                     from->scan[i].keycode, false);
-               if (rc)
+               index = ir_establish_scancode(ir_dev, rc_tab,
+                                             from->scan[i].scancode, false);
+               if (index >= rc_tab->len) {
+                       rc = -ENOMEM;
                        break;
+               }
+
+               ir_update_mapping(ir_dev->input_dev, rc_tab, index,
+                                 from->scan[i].keycode);
        }
-       spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+       if (rc)
+               ir_free_table(rc_tab);
+
        return rc;
 }
 
+/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_tab:    the &struct ir_scancode_table to search
+ * @scancode:  scancode to look for in the table
+ * @return:    index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct ir_scancode_table *rc_tab,
+                                         unsigned int scancode)
+{
+       unsigned int start = 0;
+       unsigned int end = rc_tab->len - 1;
+       unsigned int mid;
+
+       while (start <= end) {
+               mid = (start + end) / 2;
+               if (rc_tab->scan[mid].scancode < scancode)
+                       start = mid + 1;
+               else if (rc_tab->scan[mid].scancode > scancode)
+                       end = mid - 1;
+               else
+                       return mid;
+       }
+
+       return -1U;
+}
+
 /**
  * ir_getkeycode() - get a keycode from the scancode->keycode table
  * @dev:       the struct input_dev device descriptor
@@ -224,36 +352,46 @@ static int ir_setkeytable(struct input_dev *dev,
  * This routine is used to handle evdev EVIOCGKEY ioctl.
  */
 static int ir_getkeycode(struct input_dev *dev,
-                        unsigned int scancode, unsigned int *keycode)
+                        struct input_keymap_entry *ke)
 {
-       int start, end, mid;
-       unsigned long flags;
-       int key = KEY_RESERVED;
        struct ir_input_dev *ir_dev = input_get_drvdata(dev);
        struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+       struct ir_scancode *entry;
+       unsigned long flags;
+       unsigned int index;
+       unsigned int scancode;
+       int retval;
 
        spin_lock_irqsave(&rc_tab->lock, flags);
-       start = 0;
-       end = rc_tab->len - 1;
-       while (start <= end) {
-               mid = (start + end) / 2;
-               if (rc_tab->scan[mid].scancode < scancode)
-                       start = mid + 1;
-               else if (rc_tab->scan[mid].scancode > scancode)
-                       end = mid - 1;
-               else {
-                       key = rc_tab->scan[mid].keycode;
-                       break;
-               }
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+       } else {
+               retval = input_scancode_to_scalar(ke, &scancode);
+               if (retval)
+                       goto out;
+
+               index = ir_lookup_by_scancode(rc_tab, scancode);
+       }
+
+       if (index >= rc_tab->len) {
+               if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+                       IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+                                  scancode);
+               retval = -EINVAL;
+               goto out;
        }
-       spin_unlock_irqrestore(&rc_tab->lock, flags);
 
-       if (key == KEY_RESERVED)
-               IR_dprintk(1, "unknown key for scancode 0x%04x\n",
-                          scancode);
+       entry = &rc_tab->scan[index];
 
-       *keycode = key;
-       return 0;
+       ke->index = index;
+       ke->keycode = entry->keycode;
+       ke->len = sizeof(entry->scancode);
+       memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+out:
+       spin_unlock_irqrestore(&rc_tab->lock, flags);
+       return retval;
 }
 
 /**
@@ -268,12 +406,24 @@ static int ir_getkeycode(struct input_dev *dev,
  */
 u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
 {
-       int keycode;
+       struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+       struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+       unsigned int keycode;
+       unsigned int index;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc_tab->lock, flags);
+
+       index = ir_lookup_by_scancode(rc_tab, scancode);
+       keycode = index < rc_tab->len ?
+                       rc_tab->scan[index].keycode : KEY_RESERVED;
+
+       spin_unlock_irqrestore(&rc_tab->lock, flags);
 
-       ir_getkeycode(dev, scancode, &keycode);
        if (keycode != KEY_RESERVED)
                IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
                           dev->name, scancode, keycode);
+
        return keycode;
 }
 EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
@@ -453,8 +603,8 @@ int __ir_input_register(struct input_dev *input_dev,
                goto out_dev;
        }
 
-       input_dev->getkeycode = ir_getkeycode;
-       input_dev->setkeycode = ir_setkeycode;
+       input_dev->getkeycode_new = ir_getkeycode;
+       input_dev->setkeycode_new = ir_setkeycode;
        input_set_drvdata(input_dev, ir_dev);
        ir_dev->input_dev = input_dev;
 
@@ -462,12 +612,6 @@ int __ir_input_register(struct input_dev *input_dev,
        spin_lock_init(&ir_dev->keylock);
        setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
 
-       ir_dev->rc_tab.name = rc_tab->name;
-       ir_dev->rc_tab.ir_type = rc_tab->ir_type;
-       ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
-                                                 sizeof(struct ir_scancode));
-       ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
-       ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);
        if (props) {
                ir_dev->props = props;
                if (props->open)
@@ -476,23 +620,14 @@ int __ir_input_register(struct input_dev *input_dev,
                        input_dev->close = ir_close;
        }
 
-       if (!ir_dev->rc_tab.scan) {
-               rc = -ENOMEM;
-               goto out_name;
-       }
-
-       IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-                  ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
-
        set_bit(EV_KEY, input_dev->evbit);
        set_bit(EV_REP, input_dev->evbit);
        set_bit(EV_MSC, input_dev->evbit);
        set_bit(MSC_SCAN, input_dev->mscbit);
 
-       if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
-               rc = -ENOMEM;
-               goto out_table;
-       }
+       rc = ir_setkeytable(ir_dev, rc_tab);
+       if (rc)
+               goto out_name;
 
        rc = ir_register_class(input_dev);
        if (rc < 0)
@@ -522,7 +657,7 @@ int __ir_input_register(struct input_dev *input_dev,
 out_event:
        ir_unregister_class(input_dev);
 out_table:
-       kfree(ir_dev->rc_tab.scan);
+       ir_free_table(&ir_dev->rc_tab);
 out_name:
        kfree(ir_dev->driver_name);
 out_dev:
@@ -540,7 +675,6 @@ EXPORT_SYMBOL_GPL(__ir_input_register);
 void ir_input_unregister(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct ir_scancode_table *rc_tab;
 
        if (!ir_dev)
                return;
@@ -552,10 +686,7 @@ void ir_input_unregister(struct input_dev *input_dev)
                if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
                        ir_raw_event_unregister(input_dev);
 
-       rc_tab = &ir_dev->rc_tab;
-       rc_tab->size = 0;
-       kfree(rc_tab->scan);
-       rc_tab->scan = NULL;
+       ir_free_table(&ir_dev->rc_tab);
 
        ir_unregister_class(input_dev);
 
index defa786dee343a80c6ae5e27ecdb09ca5ec4d058..b8c4b80e4c4355736b11d81f2237414963a0071c 100644 (file)
@@ -338,6 +338,21 @@ static struct resource ab8500_rtc_resources[] = {
        },
 };
 
+static struct resource ab8500_poweronkey_db_resources[] = {
+       {
+               .name   = "ONKEY_DBF",
+               .start  = AB8500_INT_PON_KEY1DB_F,
+               .end    = AB8500_INT_PON_KEY1DB_F,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "ONKEY_DBR",
+               .start  = AB8500_INT_PON_KEY1DB_R,
+               .end    = AB8500_INT_PON_KEY1DB_R,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static struct mfd_cell ab8500_devs[] = {
        {
                .name = "ab8500-gpadc",
@@ -354,6 +369,11 @@ static struct mfd_cell ab8500_devs[] = {
        { .name = "ab8500-usb", },
        { .name = "ab8500-pwm", },
        { .name = "ab8500-regulator", },
+       {
+               .name = "ab8500-poweron-key",
+               .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+               .resources = ab8500_poweronkey_db_resources,
+       },
 };
 
 int __devinit ab8500_init(struct ab8500 *ab8500)
index cd164595f08a0cedfc7335a3033fe7a0980ca025..49b4d069cbf912070b16e3d740fceaa17ef662af 100644 (file)
@@ -65,7 +65,7 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
                p->set_pwr(pdev, state);
 }
 
-static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
        struct sh_mobile_sdhi *priv;
        struct tmio_mmc_data *mmc_data;
index 720e099e506df1297a5e71a2047fe9fae52fe98a..5d0fb60a4c147138833506588d6329b1e716e1ae 100644 (file)
@@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl4030_codec",
+               child = add_child(sub_chip_id, "twl4030-audio",
                                pdata->codec, sizeof(*pdata->codec),
                                false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
-       /* Phoenix*/
+       /* Phoenix codec driver is probed directly atm */
        if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl6040_codec",
+               child = add_child(sub_chip_id, "twl6040-codec",
                                pdata->codec, sizeof(*pdata->codec),
                                false, 0, 0);
                if (IS_ERR(child))
index add6f67d80323a42824709337958fe90df55e443..9a4b196d6deb64751d8e4981bb81de8074f5e231 100644 (file)
@@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 
        if (pdata->audio) {
                cell = &codec->cells[childs];
-               cell->name = "twl4030_codec_audio";
+               cell->name = "twl4030-codec";
                cell->platform_data = pdata->audio;
                cell->data_size = sizeof(*pdata->audio);
                childs++;
        }
        if (pdata->vibra) {
                cell = &codec->cells[childs];
-               cell->name = "twl4030_codec_vibra";
+               cell->name = "twl4030-vibra";
                cell->platform_data = pdata->vibra;
                cell->data_size = sizeof(*pdata->vibra);
                childs++;
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
        return 0;
 }
 
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
 
 static struct platform_driver twl4030_codec_driver = {
        .probe          = twl4030_codec_probe,
        .remove         = __devexit_p(twl4030_codec_remove),
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = "twl4030_codec",
+               .name   = "twl4030-audio",
        },
 };
 
index 1f69743b12ec036239fa6fe05540cec600c5b4b9..5a74db75f66f364daaf8b850893858731ed7e7da 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig MISC_DEVICES
        bool "Misc devices"
-       default y
        ---help---
          Say Y here to get to see options for device drivers from various
          different categories. This option alone does not add any kernel code.
@@ -24,7 +23,8 @@ config AD525X_DPOT
          AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
          AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
          AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282,
-         ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173
+         ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173, AD5270,
+         AD5271, AD5272, AD5274
          digital potentiometer chips.
 
          See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -284,6 +284,16 @@ config SGI_GRU_DEBUG
        This option enables addition debugging code for the SGI GRU driver. If
        you are unsure, say N.
 
+config APDS9802ALS
+       tristate "Medfield Avago APDS9802 ALS Sensor module"
+       depends on I2C
+       help
+         If you say yes here you get support for the ALS APDS9802 ambient
+         light sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called apds9802als.
+
 config ISL29003
        tristate "Intersil ISL29003 ambient light sensor"
        depends on I2C && SYSFS
@@ -294,6 +304,16 @@ config ISL29003
          This driver can also be built as a module.  If so, the module
          will be called isl29003.
 
+config ISL29020
+       tristate "Intersil ISL29020 ambient light sensor"
+       depends on I2C
+       help
+         If you say yes here you get support for the Intersil ISL29020
+         ambient light sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called isl29020.
+
 config SENSORS_TSL2550
        tristate "Taos TSL2550 ambient light sensor"
        depends on I2C && SYSFS
@@ -314,6 +334,27 @@ config SENSORS_BH1780
          This driver can also be built as a module.  If so, the module
          will be called bh1780gli.
 
+config SENSORS_BH1770
+         tristate "BH1770GLC / SFH7770 combined ALS - Proximity sensor"
+         depends on I2C
+         ---help---
+           Say Y here if you want to build a driver for BH1770GLC (ROHM) or
+          SFH7770 (Osram) combined ambient light and proximity sensor chip.
+
+           To compile this driver as a module, choose M here: the
+           module will be called bh1770glc. If unsure, say N here.
+
+config SENSORS_APDS990X
+        tristate "APDS990X combined als and proximity sensors"
+        depends on I2C
+        default n
+        ---help---
+          Say Y here if you want to build a driver for Avago APDS990x
+          combined ambient light and proximity sensor chip.
+
+          To compile this driver as a module, choose M here: the
+          module will be called apds990x. If unsure, say N here.
+
 config HMC6352
        tristate "Honeywell HMC6352 compass"
        depends on I2C
index 9f2986b4da2fd7031c071ec3ac0a2ce636ffe4b4..4be5c6fc5ef4a47ae8a16c213492beba700321bb 100644 (file)
@@ -16,6 +16,8 @@ obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
 obj-$(CONFIG_PHANTOM)          += phantom.o
 obj-$(CONFIG_SENSORS_BH1780)   += bh1780gli.o
+obj-$(CONFIG_SENSORS_BH1770)   += bh1770glc.o
+obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
 obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
 obj-$(CONFIG_KGDB_TESTS)       += kgdbts.o
@@ -23,7 +25,9 @@ obj-$(CONFIG_SGI_XP)          += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
 obj-$(CONFIG_CS5535_MFGPT)     += cs5535-mfgpt.o
 obj-$(CONFIG_HP_ILO)           += hpilo.o
+obj-$(CONFIG_APDS9802ALS)      += apds9802als.o
 obj-$(CONFIG_ISL29003)         += isl29003.o
+obj-$(CONFIG_ISL29020)         += isl29020.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
 obj-$(CONFIG_EP93XX_PWM)       += ep93xx_pwm.o
 obj-$(CONFIG_DS1682)           += ds1682.o
index 374352af79791f8fed39281789169519ce764ceb..4ff73c215746688357ca5406e332b3ed320a5985 100644 (file)
@@ -102,6 +102,8 @@ static const struct i2c_device_id ad_dpot_id[] = {
        {"ad5170", AD5170_ID},
        {"ad5172", AD5172_ID},
        {"ad5173", AD5173_ID},
+       {"ad5272", AD5272_ID},
+       {"ad5274", AD5274_ID},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
index b8c6df9c8437213603cd997c7138f41fe76b94c6..7f9a55afe05d77b224c88f87ac38d367788d643f 100644 (file)
@@ -38,6 +38,8 @@ static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
        {.name = "ad8402", .devid = AD8402_ID},
        {.name = "ad8403", .devid = AD8403_ID},
        {.name = "adn2850", .devid = ADN2850_ID},
+       {.name = "ad5270", .devid = AD5270_ID},
+       {.name = "ad5271", .devid = AD5271_ID},
        {}
 };
 
@@ -53,13 +55,13 @@ static int write8(void *client, u8 val)
 static int write16(void *client, u8 reg, u8 val)
 {
        u8 data[2] = {reg, val};
-       return spi_write(client, data, 1);
+       return spi_write(client, data, 2);
 }
 
 static int write24(void *client, u8 reg, u16 val)
 {
        u8 data[3] = {reg, val >> 8, val};
-       return spi_write(client, data, 1);
+       return spi_write(client, data, 3);
 }
 
 static int read8(void *client)
index 5e6fa8449e8b7bba11c2aca88fce59f34b80277e..7cb911028d094ca4416382806191a5e3e4b68e82 100644 (file)
@@ -29,9 +29,9 @@
  * AD5262              2               256             20, 50, 200
  * AD5263              4               256             20, 50, 200
  * AD5290              1               256             10, 50, 100
- * AD5291              1               256             20
- * AD5292              1               1024            20
- * AD5293              1               1024            20
+ * AD5291              1               256             20, 50, 100  (20-TP)
+ * AD5292              1               1024            20, 50, 100  (20-TP)
+ * AD5293              1               1024            20, 50, 100
  * AD7376              1               128             10, 50, 100, 1M
  * AD8400              1               256             1, 10, 50, 100
  * AD8402              2               256             1, 10, 50, 100
  * AD5170              1               256             2.5, 10, 50, 100 (OTP)
  * AD5172              2               256             2.5, 10, 50, 100 (OTP)
  * AD5173              2               256             2.5, 10, 50, 100 (OTP)
+ * AD5270              1               1024            20, 50, 100 (50-TP)
+ * AD5271              1               256             20, 50, 100 (50-TP)
+ * AD5272              1               1024            20, 50, 100 (50-TP)
+ * AD5274              1               256             20, 50, 100 (50-TP)
  *
  * See Documentation/misc-devices/ad525x_dpot.txt for more info.
  *
@@ -126,18 +130,38 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
 static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
 {
        unsigned ctrl = 0;
+       int value;
 
        if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
 
                if (dpot->feat & F_RDACS_WONLY)
                        return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
-
                if (dpot->uid == DPOT_UID(AD5291_ID) ||
                        dpot->uid == DPOT_UID(AD5292_ID) ||
-                       dpot->uid == DPOT_UID(AD5293_ID))
-                       return dpot_read_r8d8(dpot,
+                       dpot->uid == DPOT_UID(AD5293_ID)) {
+
+                       value = dpot_read_r8d8(dpot,
                                DPOT_AD5291_READ_RDAC << 2);
 
+                       if (dpot->uid == DPOT_UID(AD5291_ID))
+                               value = value >> 2;
+
+                       return value;
+               } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+                       dpot->uid == DPOT_UID(AD5271_ID)) {
+
+                       value = dpot_read_r8d8(dpot,
+                               DPOT_AD5270_1_2_4_READ_RDAC << 2);
+
+                       if (value < 0)
+                               return value;
+
+                       if (dpot->uid == DPOT_UID(AD5271_ID))
+                               value = value >> 2;
+
+                       return value;
+               }
+
                ctrl = DPOT_SPI_READ_RDAC;
        } else if (reg & DPOT_ADDR_EEPROM) {
                ctrl = DPOT_SPI_READ_EEPROM;
@@ -153,6 +177,7 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
 
 static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
 {
+       int value;
        unsigned ctrl = 0;
        switch (dpot->uid) {
        case DPOT_UID(AD5246_ID):
@@ -166,7 +191,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
        case DPOT_UID(AD5280_ID):
        case DPOT_UID(AD5282_ID):
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
-                       0 : DPOT_AD5291_RDAC_AB;
+                       0 : DPOT_AD5282_RDAC_AB;
                return dpot_read_r8d8(dpot, ctrl);
        case DPOT_UID(AD5170_ID):
        case DPOT_UID(AD5171_ID):
@@ -175,8 +200,27 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
        case DPOT_UID(AD5172_ID):
        case DPOT_UID(AD5173_ID):
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
-                       0 : DPOT_AD5272_3_A0;
+                       0 : DPOT_AD5172_3_A0;
                return dpot_read_r8d8(dpot, ctrl);
+       case DPOT_UID(AD5272_ID):
+       case DPOT_UID(AD5274_ID):
+                       dpot_write_r8d8(dpot,
+                               (DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);
+
+                       value = dpot_read_r8d16(dpot,
+                               DPOT_AD5270_1_2_4_RDAC << 2);
+
+                       if (value < 0)
+                               return value;
+                       /*
+                        * AD5272/AD5274 returns high byte first, however
+                        * underling smbus expects low byte first.
+                        */
+                       value = swab16(value);
+
+                       if (dpot->uid == DPOT_UID(AD5271_ID))
+                               value = value >> 2;
+               return value;
        default:
                if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
                        return dpot_read_r8d16(dpot, (reg & 0xF8) |
@@ -198,7 +242,7 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
 {
        unsigned val = 0;
 
-       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {
                if (dpot->feat & F_RDACS_WONLY)
                        dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
 
@@ -219,11 +263,30 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
                } else {
                        if (dpot->uid == DPOT_UID(AD5291_ID) ||
                                dpot->uid == DPOT_UID(AD5292_ID) ||
-                               dpot->uid == DPOT_UID(AD5293_ID))
+                               dpot->uid == DPOT_UID(AD5293_ID)) {
+
+                               dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,
+                                               DPOT_AD5291_UNLOCK_CMD);
+
+                               if (dpot->uid == DPOT_UID(AD5291_ID))
+                                       value = value << 2;
+
                                return dpot_write_r8d8(dpot,
                                        (DPOT_AD5291_RDAC << 2) |
                                        (value >> 8), value & 0xFF);
+                       } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+                               dpot->uid == DPOT_UID(AD5271_ID)) {
+                               dpot_write_r8d8(dpot,
+                                               DPOT_AD5270_1_2_4_CTRLREG << 2,
+                                               DPOT_AD5270_1_2_4_UNLOCK_CMD);
+
+                               if (dpot->uid == DPOT_UID(AD5271_ID))
+                                       value = value << 2;
 
+                               return dpot_write_r8d8(dpot,
+                                       (DPOT_AD5270_1_2_4_RDAC << 2) |
+                                       (value >> 8), value & 0xFF);
+                       }
                        val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
                }
        } else if (reg & DPOT_ADDR_EEPROM) {
@@ -243,6 +306,16 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
                        val = DPOT_SPI_INC_ALL;
                        break;
                }
+       } else if (reg & DPOT_ADDR_OTP) {
+               if (dpot->uid == DPOT_UID(AD5291_ID) ||
+                       dpot->uid == DPOT_UID(AD5292_ID)) {
+                       return dpot_write_r8d8(dpot,
+                               DPOT_AD5291_STORE_XTPM << 2, 0);
+               } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+                       dpot->uid == DPOT_UID(AD5271_ID)) {
+                       return dpot_write_r8d8(dpot,
+                               DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
+               }
        } else
                BUG();
 
@@ -273,7 +346,7 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
        case DPOT_UID(AD5280_ID):
        case DPOT_UID(AD5282_ID):
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
-                       0 : DPOT_AD5291_RDAC_AB;
+                       0 : DPOT_AD5282_RDAC_AB;
                return dpot_write_r8d8(dpot, ctrl, value);
                break;
        case DPOT_UID(AD5171_ID):
@@ -289,12 +362,12 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
        case DPOT_UID(AD5172_ID):
        case DPOT_UID(AD5173_ID):
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
-                       0 : DPOT_AD5272_3_A0;
+                       0 : DPOT_AD5172_3_A0;
                if (reg & DPOT_ADDR_OTP) {
                        tmp = dpot_read_r8d16(dpot, ctrl);
                        if (tmp >> 14) /* Ready to Program? */
                                return -EFAULT;
-                       ctrl |= DPOT_AD5270_2_3_FUSE;
+                       ctrl |= DPOT_AD5170_2_3_FUSE;
                }
                return dpot_write_r8d8(dpot, ctrl, value);
                break;
@@ -303,10 +376,25 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
                        tmp = dpot_read_r8d16(dpot, tmp);
                        if (tmp >> 14) /* Ready to Program? */
                                return -EFAULT;
-                       ctrl = DPOT_AD5270_2_3_FUSE;
+                       ctrl = DPOT_AD5170_2_3_FUSE;
                }
                return dpot_write_r8d8(dpot, ctrl, value);
                break;
+       case DPOT_UID(AD5272_ID):
+       case DPOT_UID(AD5274_ID):
+               dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
+                               DPOT_AD5270_1_2_4_UNLOCK_CMD);
+
+               if (reg & DPOT_ADDR_OTP)
+                       return dpot_write_r8d8(dpot,
+                                       DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
+
+               if (dpot->uid == DPOT_UID(AD5274_ID))
+                       value = value << 2;
+
+               return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
+                                      (value >> 8), value & 0xFF);
+               break;
        default:
                if (reg & DPOT_ADDR_CMD)
                        return dpot_write_d8(dpot, reg);
@@ -320,7 +408,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
        }
 }
 
-
 static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
 {
        if (dpot->feat & F_SPI)
index 78b89fd2e2fd48d20a22e2bf40292e947b388a24..a662f5987b6892591008291e3b5b05506918ed9e 100644 (file)
@@ -47,9 +47,9 @@ enum dpot_devid {
        AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */
        AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1),
        AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
-                       BRDAC0 | BRDAC3, 6, 2),
+                       BRDAC1 | BRDAC3, 6, 2),
        AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
-                       BRDAC0 | BRDAC3, 8, 3),
+                       BRDAC1 | BRDAC3, 8, 3),
        AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
                        BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4),
        AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
@@ -93,8 +93,10 @@ enum dpot_devid {
                        BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
        AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
                        BRDAC0, 8, 24),
-       AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
-       AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
+       AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
+                       BRDAC0, 8, 25),
+       AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
+                       BRDAC0, 10, 26),
        AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
        AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
                        BRDAC0, 7, 28),
@@ -122,6 +124,12 @@ enum dpot_devid {
        AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45),
        AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46),
        AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47),
+       AD5270_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
+                       BRDAC0, 10, 48),
+       AD5271_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
+                       BRDAC0, 8, 49),
+       AD5272_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 10, 50),
+       AD5274_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 51),
 };
 
 #define DPOT_RDAC0             0
@@ -165,15 +173,24 @@ enum dpot_devid {
 /* AD5291/2/3 use special commands */
 #define DPOT_AD5291_RDAC       0x01
 #define DPOT_AD5291_READ_RDAC  0x02
+#define DPOT_AD5291_STORE_XTPM 0x03
+#define DPOT_AD5291_CTRLREG    0x06
+#define DPOT_AD5291_UNLOCK_CMD 0x03
 
-/* AD524x use special commands */
-#define DPOT_AD5291_RDAC_AB    0x80
+/* AD5270/1/2/4 use special commands */
+#define DPOT_AD5270_1_2_4_RDAC         0x01
+#define DPOT_AD5270_1_2_4_READ_RDAC    0x02
+#define DPOT_AD5270_1_2_4_STORE_XTPM   0x03
+#define DPOT_AD5270_1_2_4_CTRLREG      0x07
+#define DPOT_AD5270_1_2_4_UNLOCK_CMD   0x03
+
+#define DPOT_AD5282_RDAC_AB    0x80
 
 #define DPOT_AD5273_FUSE       0x80
-#define DPOT_AD5270_2_3_FUSE   0x20
-#define DPOT_AD5270_2_3_OW     0x08
-#define DPOT_AD5272_3_A0       0x08
-#define DPOT_AD5270_2FUSE      0x80
+#define DPOT_AD5170_2_3_FUSE   0x20
+#define DPOT_AD5170_2_3_OW     0x08
+#define DPOT_AD5172_3_A0       0x08
+#define DPOT_AD5170_2FUSE      0x80
 
 struct dpot_data;
 
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
new file mode 100644 (file)
index 0000000..f9b91ba
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * apds9802als.c - apds9802  ALS Driver
+ *
+ * Copyright (C) 2009 Intel Corp
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+
+#define ALS_MIN_RANGE_VAL 1
+#define ALS_MAX_RANGE_VAL 2
+#define POWER_STA_ENABLE 1
+#define POWER_STA_DISABLE 0
+
+#define DRIVER_NAME "apds9802als"
+
+struct als_data {
+       struct mutex mutex;
+};
+
+static ssize_t als_sensing_range_show(struct device *dev,
+                       struct device_attribute *attr,  char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int  val;
+
+       val = i2c_smbus_read_byte_data(client, 0x81);
+       if (val < 0)
+               return val;
+       if (val & 1)
+               return sprintf(buf, "4095\n");
+       else
+               return sprintf(buf, "65535\n");
+}
+
+static int als_wait_for_data_ready(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret;
+       int retry = 10;
+
+       do {
+               msleep(30);
+               ret = i2c_smbus_read_byte_data(client, 0x86);
+       } while (!(ret & 0x80) && retry--);
+
+       if (!retry) {
+               dev_warn(dev, "timeout waiting for data ready\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static ssize_t als_lux0_input_data_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct als_data *data = i2c_get_clientdata(client);
+       int ret_val;
+       int temp;
+
+       /* Protect against parallel reads */
+       pm_runtime_get_sync(dev);
+       mutex_lock(&data->mutex);
+
+       /* clear EOC interrupt status */
+       i2c_smbus_write_byte(client, 0x40);
+       /* start measurement */
+       temp = i2c_smbus_read_byte_data(client, 0x81);
+       i2c_smbus_write_byte_data(client, 0x81, temp | 0x08);
+
+       ret_val = als_wait_for_data_ready(dev);
+       if (ret_val < 0)
+               goto failed;
+
+       temp = i2c_smbus_read_byte_data(client, 0x8C); /* LSB data */
+       if (temp < 0) {
+               ret_val = temp;
+               goto failed;
+       }
+       ret_val = i2c_smbus_read_byte_data(client, 0x8D); /* MSB data */
+       if (ret_val < 0)
+               goto failed;
+
+       mutex_unlock(&data->mutex);
+       pm_runtime_put_sync(dev);
+
+       temp = (ret_val << 8) | temp;
+       return sprintf(buf, "%d\n", temp);
+failed:
+       mutex_unlock(&data->mutex);
+       pm_runtime_put_sync(dev);
+       return ret_val;
+}
+
+static ssize_t als_sensing_range_store(struct device *dev,
+               struct device_attribute *attr, const  char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct als_data *data = i2c_get_clientdata(client);
+       unsigned int ret_val;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       if (val < 4096)
+               val = 1;
+       else if (val < 65536)
+               val = 2;
+       else
+               return -ERANGE;
+
+       pm_runtime_get_sync(dev);
+
+       /* Make sure nobody else reads/modifies/writes 0x81 while we
+          are active */
+       mutex_lock(&data->mutex);
+
+       ret_val = i2c_smbus_read_byte_data(client, 0x81);
+       if (ret_val < 0)
+               goto fail;
+
+       /* Reset the bits before setting them */
+       ret_val = ret_val & 0xFA;
+
+       if (val == 1) /* Setting detection range up to 4k LUX */
+               ret_val = (ret_val | 0x01);
+       else /* Setting detection range up to 64k LUX*/
+               ret_val = (ret_val | 0x00);
+
+       ret_val = i2c_smbus_write_byte_data(client, 0x81, ret_val);
+
+       if (ret_val >= 0) {
+               /* All OK */
+               mutex_unlock(&data->mutex);
+               pm_runtime_put_sync(dev);
+               return count;
+       }
+fail:
+       mutex_unlock(&data->mutex);
+       pm_runtime_put_sync(dev);
+       return ret_val;
+}
+
+static int als_set_power_state(struct i2c_client *client, bool on_off)
+{
+       int ret_val;
+       struct als_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->mutex);
+       ret_val = i2c_smbus_read_byte_data(client, 0x80);
+       if (ret_val < 0)
+               goto fail;
+       if (on_off)
+               ret_val = ret_val | 0x01;
+       else
+               ret_val = ret_val & 0xFE;
+       ret_val = i2c_smbus_write_byte_data(client, 0x80, ret_val);
+fail:
+       mutex_unlock(&data->mutex);
+       return ret_val;
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,
+       als_sensing_range_show, als_sensing_range_store);
+static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux0_input_data_show, NULL);
+
+static struct attribute *mid_att_als[] = {
+       &dev_attr_lux0_sensor_range.attr,
+       &dev_attr_lux0_input.attr,
+       NULL
+};
+
+static struct attribute_group m_als_gr = {
+       .name = "apds9802als",
+       .attrs = mid_att_als
+};
+
+static int als_set_default_config(struct i2c_client *client)
+{
+       int ret_val;
+       /* Write the command and then switch on */
+       ret_val = i2c_smbus_write_byte_data(client, 0x80, 0x01);
+       if (ret_val < 0) {
+               dev_err(&client->dev, "failed default switch on write\n");
+               return ret_val;
+       }
+       /* detection range: 1~64K Lux, maunal measurement */
+       ret_val = i2c_smbus_write_byte_data(client, 0x81, 0x08);
+       if (ret_val < 0)
+               dev_err(&client->dev, "failed default LUX on write\n");
+
+       /*  We always get 0 for the 1st measurement after system power on,
+        *  so make sure it is finished before user asks for data.
+        */
+       als_wait_for_data_ready(&client->dev);
+
+       return ret_val;
+}
+
+static int apds9802als_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       int res;
+       struct als_data *data;
+
+       data = kzalloc(sizeof(struct als_data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&client->dev, "Memory allocation failed\n");
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, data);
+       res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
+       if (res) {
+               dev_err(&client->dev, "device create file failed\n");
+               goto als_error1;
+       }
+       dev_info(&client->dev, "ALS chip found\n");
+       als_set_default_config(client);
+       mutex_init(&data->mutex);
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_get(&client->dev);
+       pm_runtime_put(&client->dev);
+
+       return res;
+als_error1:
+       i2c_set_clientdata(client, NULL);
+       kfree(data);
+       return res;
+}
+
+static int apds9802als_remove(struct i2c_client *client)
+{
+       struct als_data *data = i2c_get_clientdata(client);
+
+       als_set_power_state(client, false);
+       sysfs_remove_group(&client->dev.kobj, &m_als_gr);
+       kfree(data);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       als_set_power_state(client, false);
+       return 0;
+}
+
+static int apds9802als_resume(struct i2c_client *client)
+{
+       als_set_default_config(client);
+
+       pm_runtime_get(&client->dev);
+       pm_runtime_put(&client->dev);
+       return 0;
+}
+
+static int apds9802als_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       als_set_power_state(client, false);
+       return 0;
+}
+
+static int apds9802als_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       als_set_power_state(client, true);
+       return 0;
+}
+
+static const struct dev_pm_ops apds9802als_pm_ops = {
+       .runtime_suspend = apds9802als_runtime_suspend,
+       .runtime_resume = apds9802als_runtime_resume,
+};
+
+#define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
+
+#else  /* CONFIG_PM */
+#define apds9802als_suspend NULL
+#define apds9802als_resume NULL
+#define APDS9802ALS_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id apds9802als_id[] = {
+       { DRIVER_NAME, 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, apds9802als_id);
+
+static struct i2c_driver apds9802als_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .pm = APDS9802ALS_PM_OPS,
+       },
+       .probe = apds9802als_probe,
+       .remove = apds9802als_remove,
+       .suspend = apds9802als_suspend,
+       .resume = apds9802als_resume,
+       .id_table = apds9802als_id,
+};
+
+static int __init sensor_apds9802als_init(void)
+{
+       return i2c_add_driver(&apds9802als_driver);
+}
+
+static void  __exit sensor_apds9802als_exit(void)
+{
+       i2c_del_driver(&apds9802als_driver);
+}
+module_init(sensor_apds9802als_init);
+module_exit(sensor_apds9802als_exit);
+
+MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com");
+MODULE_DESCRIPTION("Avago apds9802als ALS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
new file mode 100644 (file)
index 0000000..200311f
--- /dev/null
@@ -0,0 +1,1295 @@
+/*
+ * This file is part of the APDS990x sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/i2c/apds990x.h>
+
+/* Register map */
+#define APDS990X_ENABLE         0x00 /* Enable of states and interrupts */
+#define APDS990X_ATIME  0x01 /* ALS ADC time  */
+#define APDS990X_PTIME  0x02 /* Proximity ADC time  */
+#define APDS990X_WTIME  0x03 /* Wait time  */
+#define APDS990X_AILTL  0x04 /* ALS interrupt low threshold low byte */
+#define APDS990X_AILTH  0x05 /* ALS interrupt low threshold hi byte */
+#define APDS990X_AIHTL  0x06 /* ALS interrupt hi threshold low byte */
+#define APDS990X_AIHTH  0x07 /* ALS interrupt hi threshold hi byte */
+#define APDS990X_PILTL  0x08 /* Proximity interrupt low threshold low byte */
+#define APDS990X_PILTH  0x09 /* Proximity interrupt low threshold hi byte */
+#define APDS990X_PIHTL  0x0a /* Proximity interrupt hi threshold low byte */
+#define APDS990X_PIHTH  0x0b /* Proximity interrupt hi threshold hi byte */
+#define APDS990X_PERS   0x0c /* Interrupt persistence filters */
+#define APDS990X_CONFIG         0x0d /* Configuration */
+#define APDS990X_PPCOUNT 0x0e /* Proximity pulse count */
+#define APDS990X_CONTROL 0x0f /* Gain control register */
+#define APDS990X_REV    0x11 /* Revision Number */
+#define APDS990X_ID     0x12 /* Device ID */
+#define APDS990X_STATUS         0x13 /* Device status */
+#define APDS990X_CDATAL         0x14 /* Clear ADC low data register */
+#define APDS990X_CDATAH         0x15 /* Clear ADC high data register */
+#define APDS990X_IRDATAL 0x16 /* IR ADC low data register */
+#define APDS990X_IRDATAH 0x17 /* IR ADC high data register */
+#define APDS990X_PDATAL         0x18 /* Proximity ADC low data register */
+#define APDS990X_PDATAH         0x19 /* Proximity ADC high data register */
+
+/* Control */
+#define APDS990X_MAX_AGAIN     3
+
+/* Enable register */
+#define APDS990X_EN_PIEN       (0x1 << 5)
+#define APDS990X_EN_AIEN       (0x1 << 4)
+#define APDS990X_EN_WEN                (0x1 << 3)
+#define APDS990X_EN_PEN                (0x1 << 2)
+#define APDS990X_EN_AEN                (0x1 << 1)
+#define APDS990X_EN_PON                (0x1 << 0)
+#define APDS990X_EN_DISABLE_ALL 0
+
+/* Status register */
+#define APDS990X_ST_PINT       (0x1 << 5)
+#define APDS990X_ST_AINT       (0x1 << 4)
+
+/* I2C access types */
+#define APDS990x_CMD_TYPE_MASK (0x03 << 5)
+#define APDS990x_CMD_TYPE_RB   (0x00 << 5) /* Repeated byte */
+#define APDS990x_CMD_TYPE_INC  (0x01 << 5) /* Auto increment */
+#define APDS990x_CMD_TYPE_SPE  (0x03 << 5) /* Special function */
+
+#define APDS990x_ADDR_SHIFT    0
+#define APDS990x_CMD           0x80
+
+/* Interrupt ack commands */
+#define APDS990X_INT_ACK_ALS   0x6
+#define APDS990X_INT_ACK_PS    0x5
+#define APDS990X_INT_ACK_BOTH  0x7
+
+/* ptime */
+#define APDS990X_PTIME_DEFAULT 0xff /* Recommended conversion time 2.7ms*/
+
+/* wtime */
+#define APDS990X_WTIME_DEFAULT 0xee /* ~50ms wait time */
+
+#define APDS990X_TIME_TO_ADC   1024 /* One timetick as ADC count value */
+
+/* Persistence */
+#define APDS990X_APERS_SHIFT   0
+#define APDS990X_PPERS_SHIFT   4
+
+/* Supported ID:s */
+#define APDS990X_ID_0          0x0
+#define APDS990X_ID_4          0x4
+#define APDS990X_ID_29         0x29
+
+/* pgain and pdiode settings */
+#define APDS_PGAIN_1X         0x0
+#define APDS_PDIODE_IR        0x2
+
+#define APDS990X_LUX_OUTPUT_SCALE 10
+
+/* Reverse chip factors for threshold calculation */
+struct reverse_factors {
+       u32 afactor;
+       int cf1;
+       int irf1;
+       int cf2;
+       int irf2;
+};
+
+struct apds990x_chip {
+       struct apds990x_platform_data   *pdata;
+       struct i2c_client               *client;
+       struct mutex                    mutex; /* avoid parallel access */
+       struct regulator_bulk_data      regs[2];
+       wait_queue_head_t               wait;
+
+       int     prox_en;
+       bool    prox_continuous_mode;
+       bool    lux_wait_fresh_res;
+
+       /* Chip parameters */
+       struct  apds990x_chip_factors   cf;
+       struct  reverse_factors         rcf;
+       u16     atime;          /* als integration time */
+       u16     arate;          /* als reporting rate */
+       u16     a_max_result;   /* Max possible ADC value with current atime */
+       u8      again_meas;     /* Gain used in last measurement */
+       u8      again_next;     /* Next calculated gain */
+       u8      pgain;
+       u8      pdiode;
+       u8      pdrive;
+       u8      lux_persistence;
+       u8      prox_persistence;
+
+       u32     lux_raw;
+       u32     lux;
+       u16     lux_clear;
+       u16     lux_ir;
+       u16     lux_calib;
+       u32     lux_thres_hi;
+       u32     lux_thres_lo;
+
+       u32     prox_thres;
+       u16     prox_data;
+       u16     prox_calib;
+
+       char    chipname[10];
+       u8      revision;
+};
+
+#define APDS_CALIB_SCALER              8192
+#define APDS_LUX_NEUTRAL_CALIB_VALUE   (1 * APDS_CALIB_SCALER)
+#define APDS_PROX_NEUTRAL_CALIB_VALUE  (1 * APDS_CALIB_SCALER)
+
+#define APDS_PROX_DEF_THRES            600
+#define APDS_PROX_HYSTERESIS           50
+#define APDS_LUX_DEF_THRES_HI          101
+#define APDS_LUX_DEF_THRES_LO          100
+#define APDS_DEFAULT_PROX_PERS         1
+
+#define APDS_TIMEOUT                   2000
+#define APDS_STARTUP_DELAY             25000 /* us */
+#define APDS_RANGE                     65535
+#define APDS_PROX_RANGE                        1023
+#define APDS_LUX_GAIN_LO_LIMIT         100
+#define APDS_LUX_GAIN_LO_LIMIT_STRICT  25
+
+#define TIMESTEP                       87 /* 2.7ms is about 87 / 32 */
+#define TIME_STEP_SCALER               32
+
+#define APDS_LUX_AVERAGING_TIME                50 /* tolerates 50/60Hz ripple */
+#define APDS_LUX_DEFAULT_RATE          200
+
+static const u8 again[]        = {1, 8, 16, 120}; /* ALS gain steps */
+static const u8 ir_currents[]  = {100, 50, 25, 12}; /* IRled currents in mA */
+
+/* Following two tables must match i.e 10Hz rate means 1 as persistence value */
+static const u16 arates_hz[] = {10, 5, 2, 1};
+static const u8 apersis[] = {1, 2, 4, 5};
+
+/* Regulators */
+static const char reg_vcc[] = "Vdd";
+static const char reg_vled[] = "Vled";
+
+static int apds990x_read_byte(struct apds990x_chip *chip, u8 reg, u8 *data)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+
+       reg &= ~APDS990x_CMD_TYPE_MASK;
+       reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       *data = ret;
+       return (int)ret;
+}
+
+static int apds990x_read_word(struct apds990x_chip *chip, u8 reg, u16 *data)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+
+       reg &= ~APDS990x_CMD_TYPE_MASK;
+       reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       *data = ret;
+       return (int)ret;
+}
+
+static int apds990x_write_byte(struct apds990x_chip *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+
+       reg &= ~APDS990x_CMD_TYPE_MASK;
+       reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB;
+
+       ret = i2c_smbus_write_byte_data(client, reg, data);
+       return (int)ret;
+}
+
+static int apds990x_write_word(struct apds990x_chip *chip, u8 reg, u16 data)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+
+       reg &= ~APDS990x_CMD_TYPE_MASK;
+       reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC;
+
+       ret = i2c_smbus_write_word_data(client, reg, data);
+       return (int)ret;
+}
+
+static int apds990x_mode_on(struct apds990x_chip *chip)
+{
+       /* ALS is mandatory, proximity optional */
+       u8 reg = APDS990X_EN_AIEN | APDS990X_EN_PON | APDS990X_EN_AEN |
+               APDS990X_EN_WEN;
+
+       if (chip->prox_en)
+               reg |= APDS990X_EN_PIEN | APDS990X_EN_PEN;
+
+       return apds990x_write_byte(chip, APDS990X_ENABLE, reg);
+}
+
+static u16 apds990x_lux_to_threshold(struct apds990x_chip *chip, u32 lux)
+{
+       u32 thres;
+       u32 cpl;
+       u32 ir;
+
+       if (lux == 0)
+               return 0;
+       else if (lux == APDS_RANGE)
+               return APDS_RANGE;
+
+       /*
+        * Reported LUX value is a combination of the IR and CLEAR channel
+        * values. However, interrupt threshold is only for clear channel.
+        * This function approximates needed HW threshold value for a given
+        * LUX value in the current lightning type.
+        * IR level compared to visible light varies heavily depending on the
+        * source of the light
+        *
+        * Calculate threshold value for the next measurement period.
+        * Math: threshold = lux * cpl where
+        * cpl = atime * again / (glass_attenuation * device_factor)
+        * (count-per-lux)
+        *
+        * First remove calibration. Division by four is to avoid overflow
+        */
+       lux = lux * (APDS_CALIB_SCALER / 4) / (chip->lux_calib / 4);
+
+       /* Multiplication by 64 is to increase accuracy */
+       cpl = ((u32)chip->atime * (u32)again[chip->again_next] *
+               APDS_PARAM_SCALE * 64) / (chip->cf.ga * chip->cf.df);
+
+       thres = lux * cpl / 64;
+       /*
+        * Convert IR light from the latest result to match with
+        * new gain step. This helps to adapt with the current
+        * source of light.
+        */
+       ir = (u32)chip->lux_ir * (u32)again[chip->again_next] /
+               (u32)again[chip->again_meas];
+
+       /*
+        * Compensate count with IR light impact
+        * IAC1 > IAC2 (see apds990x_get_lux for formulas)
+        */
+       if (chip->lux_clear * APDS_PARAM_SCALE >=
+               chip->rcf.afactor * chip->lux_ir)
+               thres = (chip->rcf.cf1 * thres + chip->rcf.irf1 * ir) /
+                       APDS_PARAM_SCALE;
+       else
+               thres = (chip->rcf.cf2 * thres + chip->rcf.irf2 * ir) /
+                       APDS_PARAM_SCALE;
+
+       if (thres >= chip->a_max_result)
+               thres = chip->a_max_result - 1;
+       return thres;
+}
+
+static inline int apds990x_set_atime(struct apds990x_chip *chip, u32 time_ms)
+{
+       u8 reg_value;
+
+       chip->atime = time_ms;
+       /* Formula is specified in the data sheet */
+       reg_value = 256 - ((time_ms * TIME_STEP_SCALER) / TIMESTEP);
+       /* Calculate max ADC value for given integration time */
+       chip->a_max_result = (u16)(256 - reg_value) * APDS990X_TIME_TO_ADC;
+       return apds990x_write_byte(chip, APDS990X_ATIME, reg_value);
+}
+
+/* Called always with mutex locked */
+static int apds990x_refresh_pthres(struct apds990x_chip *chip, int data)
+{
+       int ret, lo, hi;
+
+       /* If the chip is not in use, don't try to access it */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       if (data < chip->prox_thres) {
+               lo = 0;
+               hi = chip->prox_thres;
+       } else {
+               lo = chip->prox_thres - APDS_PROX_HYSTERESIS;
+               if (chip->prox_continuous_mode)
+                       hi = chip->prox_thres;
+               else
+                       hi = APDS_RANGE;
+       }
+
+       ret = apds990x_write_word(chip, APDS990X_PILTL, lo);
+       ret |= apds990x_write_word(chip, APDS990X_PIHTL, hi);
+       return ret;
+}
+
+/* Called always with mutex locked */
+static int apds990x_refresh_athres(struct apds990x_chip *chip)
+{
+       int ret;
+       /* If the chip is not in use, don't try to access it */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       ret = apds990x_write_word(chip, APDS990X_AILTL,
+                       apds990x_lux_to_threshold(chip, chip->lux_thres_lo));
+       ret |= apds990x_write_word(chip, APDS990X_AIHTL,
+                       apds990x_lux_to_threshold(chip, chip->lux_thres_hi));
+
+       return ret;
+}
+
+/* Called always with mutex locked */
+static void apds990x_force_a_refresh(struct apds990x_chip *chip)
+{
+       /* This will force ALS interrupt after the next measurement. */
+       apds990x_write_word(chip, APDS990X_AILTL, APDS_LUX_DEF_THRES_LO);
+       apds990x_write_word(chip, APDS990X_AIHTL, APDS_LUX_DEF_THRES_HI);
+}
+
+/* Called always with mutex locked */
+static void apds990x_force_p_refresh(struct apds990x_chip *chip)
+{
+       /* This will force proximity interrupt after the next measurement. */
+       apds990x_write_word(chip, APDS990X_PILTL, APDS_PROX_DEF_THRES - 1);
+       apds990x_write_word(chip, APDS990X_PIHTL, APDS_PROX_DEF_THRES);
+}
+
+/* Called always with mutex locked */
+static int apds990x_calc_again(struct apds990x_chip *chip)
+{
+       int curr_again = chip->again_meas;
+       int next_again = chip->again_meas;
+       int ret = 0;
+
+       /* Calculate suitable als gain */
+       if (chip->lux_clear == chip->a_max_result)
+               next_again -= 2; /* ALS saturated. Decrease gain by 2 steps */
+       else if (chip->lux_clear > chip->a_max_result / 2)
+               next_again--;
+       else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT)
+               next_again += 2; /* Too dark. Increase gain by 2 steps */
+       else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT)
+               next_again++;
+
+       /* Limit gain to available range */
+       if (next_again < 0)
+               next_again = 0;
+       else if (next_again > APDS990X_MAX_AGAIN)
+               next_again = APDS990X_MAX_AGAIN;
+
+       /* Let's check can we trust the measured result */
+       if (chip->lux_clear == chip->a_max_result)
+               /* Result can be totally garbage due to saturation */
+               ret = -ERANGE;
+       else if (next_again != curr_again &&
+               chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT)
+               /*
+                * Gain is changed and measurement result is very small.
+                * Result can be totally garbage due to underflow
+                */
+               ret = -ERANGE;
+
+       chip->again_next = next_again;
+       apds990x_write_byte(chip, APDS990X_CONTROL,
+                       (chip->pdrive << 6) |
+                       (chip->pdiode << 4) |
+                       (chip->pgain << 2) |
+                       (chip->again_next << 0));
+
+       /*
+        * Error means bad result -> re-measurement is needed. The forced
+        * refresh uses fastest possible persistence setting to get result
+        * as soon as possible.
+        */
+       if (ret < 0)
+               apds990x_force_a_refresh(chip);
+       else
+               apds990x_refresh_athres(chip);
+
+       return ret;
+}
+
+/* Called always with mutex locked */
+static int apds990x_get_lux(struct apds990x_chip *chip, int clear, int ir)
+{
+       int iac, iac1, iac2; /* IR adjusted counts */
+       u32 lpc; /* Lux per count */
+
+       /* Formulas:
+        * iac1 = CF1 * CLEAR_CH - IRF1 * IR_CH
+        * iac2 = CF2 * CLEAR_CH - IRF2 * IR_CH
+        */
+       iac1 = (chip->cf.cf1 * clear - chip->cf.irf1 * ir) / APDS_PARAM_SCALE;
+       iac2 = (chip->cf.cf2 * clear - chip->cf.irf2 * ir) / APDS_PARAM_SCALE;
+
+       iac = max(iac1, iac2);
+       iac = max(iac, 0);
+
+       lpc = APDS990X_LUX_OUTPUT_SCALE * (chip->cf.df * chip->cf.ga) /
+               (u32)(again[chip->again_meas] * (u32)chip->atime);
+
+       return (iac * lpc) / APDS_PARAM_SCALE;
+}
+
+static int apds990x_ack_int(struct apds990x_chip *chip, u8 mode)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+       u8 reg = APDS990x_CMD | APDS990x_CMD_TYPE_SPE;
+
+       switch (mode & (APDS990X_ST_AINT | APDS990X_ST_PINT)) {
+       case APDS990X_ST_AINT:
+               reg |= APDS990X_INT_ACK_ALS;
+               break;
+       case APDS990X_ST_PINT:
+               reg |= APDS990X_INT_ACK_PS;
+               break;
+       default:
+               reg |= APDS990X_INT_ACK_BOTH;
+               break;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       return (int)ret;
+}
+
+static irqreturn_t apds990x_irq(int irq, void *data)
+{
+       struct apds990x_chip *chip = data;
+       u8 status;
+
+       apds990x_read_byte(chip, APDS990X_STATUS, &status);
+       apds990x_ack_int(chip, status);
+
+       mutex_lock(&chip->mutex);
+       if (!pm_runtime_suspended(&chip->client->dev)) {
+               if (status & APDS990X_ST_AINT) {
+                       apds990x_read_word(chip, APDS990X_CDATAL,
+                                       &chip->lux_clear);
+                       apds990x_read_word(chip, APDS990X_IRDATAL,
+                                       &chip->lux_ir);
+                       /* Store used gain for calculations */
+                       chip->again_meas = chip->again_next;
+
+                       chip->lux_raw = apds990x_get_lux(chip,
+                                                       chip->lux_clear,
+                                                       chip->lux_ir);
+
+                       if (apds990x_calc_again(chip) == 0) {
+                               /* Result is valid */
+                               chip->lux = chip->lux_raw;
+                               chip->lux_wait_fresh_res = false;
+                               wake_up(&chip->wait);
+                               sysfs_notify(&chip->client->dev.kobj,
+                                       NULL, "lux0_input");
+                       }
+               }
+
+               if ((status & APDS990X_ST_PINT) && chip->prox_en) {
+                       u16 clr_ch;
+
+                       apds990x_read_word(chip, APDS990X_CDATAL, &clr_ch);
+                       /*
+                        * If ALS channel is saturated at min gain,
+                        * proximity gives false posivite values.
+                        * Just ignore them.
+                        */
+                       if (chip->again_meas == 0 &&
+                               clr_ch == chip->a_max_result)
+                               chip->prox_data = 0;
+                       else
+                               apds990x_read_word(chip,
+                                               APDS990X_PDATAL,
+                                               &chip->prox_data);
+
+                       apds990x_refresh_pthres(chip, chip->prox_data);
+                       if (chip->prox_data < chip->prox_thres)
+                               chip->prox_data = 0;
+                       else if (!chip->prox_continuous_mode)
+                               chip->prox_data = APDS_PROX_RANGE;
+                       sysfs_notify(&chip->client->dev.kobj,
+                               NULL, "prox0_raw");
+               }
+       }
+       mutex_unlock(&chip->mutex);
+       return IRQ_HANDLED;
+}
+
+static int apds990x_configure(struct apds990x_chip *chip)
+{
+       /* It is recommended to use disabled mode during these operations */
+       apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL);
+
+       /* conversion and wait times for different state machince states */
+       apds990x_write_byte(chip, APDS990X_PTIME, APDS990X_PTIME_DEFAULT);
+       apds990x_write_byte(chip, APDS990X_WTIME, APDS990X_WTIME_DEFAULT);
+       apds990x_set_atime(chip, APDS_LUX_AVERAGING_TIME);
+
+       apds990x_write_byte(chip, APDS990X_CONFIG, 0);
+
+       /* Persistence levels */
+       apds990x_write_byte(chip, APDS990X_PERS,
+                       (chip->lux_persistence << APDS990X_APERS_SHIFT) |
+                       (chip->prox_persistence << APDS990X_PPERS_SHIFT));
+
+       apds990x_write_byte(chip, APDS990X_PPCOUNT, chip->pdata->ppcount);
+
+       /* Start with relatively small gain */
+       chip->again_meas = 1;
+       chip->again_next = 1;
+       apds990x_write_byte(chip, APDS990X_CONTROL,
+                       (chip->pdrive << 6) |
+                       (chip->pdiode << 4) |
+                       (chip->pgain << 2) |
+                       (chip->again_next << 0));
+       return 0;
+}
+
+static int apds990x_detect(struct apds990x_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 id;
+
+       ret = apds990x_read_byte(chip, APDS990X_ID, &id);
+       if (ret < 0) {
+               dev_err(&client->dev, "ID read failed\n");
+               return ret;
+       }
+
+       ret = apds990x_read_byte(chip, APDS990X_REV, &chip->revision);
+       if (ret < 0) {
+               dev_err(&client->dev, "REV read failed\n");
+               return ret;
+       }
+
+       switch (id) {
+       case APDS990X_ID_0:
+       case APDS990X_ID_4:
+       case APDS990X_ID_29:
+               snprintf(chip->chipname, sizeof(chip->chipname), "APDS-990x");
+               break;
+       default:
+               ret = -ENODEV;
+               break;
+       }
+       return ret;
+}
+
+static int apds990x_chip_on(struct apds990x_chip *chip)
+{
+       int err  = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+                                       chip->regs);
+       if (err < 0)
+               return err;
+
+       usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY);
+
+       /* Refresh all configs in case of regulators were off */
+       chip->prox_data = 0;
+       apds990x_configure(chip);
+       apds990x_mode_on(chip);
+       return 0;
+}
+
+static int apds990x_chip_off(struct apds990x_chip *chip)
+{
+       apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL);
+       regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+       return 0;
+}
+
+static ssize_t apds990x_lux_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip = dev_get_drvdata(dev);
+       ssize_t ret;
+       u32 result;
+       long timeout;
+
+       if (pm_runtime_suspended(dev))
+               return -EIO;
+
+       timeout = wait_event_interruptible_timeout(chip->wait,
+                                               !chip->lux_wait_fresh_res,
+                                               msecs_to_jiffies(APDS_TIMEOUT));
+       if (!timeout)
+               return -EIO;
+
+       mutex_lock(&chip->mutex);
+       result = (chip->lux * chip->lux_calib) / APDS_CALIB_SCALER;
+       if (result > (APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE))
+               result = APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE;
+
+       ret = sprintf(buf, "%d.%d\n",
+               result / APDS990X_LUX_OUTPUT_SCALE,
+               result % APDS990X_LUX_OUTPUT_SCALE);
+       mutex_unlock(&chip->mutex);
+       return ret;
+}
+
+static DEVICE_ATTR(lux0_input, S_IRUGO, apds990x_lux_show, NULL);
+
+static ssize_t apds990x_lux_range_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", APDS_RANGE);
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, apds990x_lux_range_show, NULL);
+
+static ssize_t apds990x_lux_calib_format_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", APDS_CALIB_SCALER);
+}
+
+static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
+               apds990x_lux_calib_format_show, NULL);
+
+static ssize_t apds990x_lux_calib_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", chip->lux_calib);
+}
+
+static ssize_t apds990x_lux_calib_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip = dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if (chip->lux_calib > APDS_RANGE)
+               return -EINVAL;
+
+       chip->lux_calib = value;
+
+       return len;
+}
+
+static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, apds990x_lux_calib_show,
+               apds990x_lux_calib_store);
+
+static ssize_t apds990x_rate_avail(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int i;
+       int pos = 0;
+       for (i = 0; i < ARRAY_SIZE(arates_hz); i++)
+               pos += sprintf(buf + pos, "%d ", arates_hz[i]);
+       sprintf(buf + pos - 1, "\n");
+       return pos;
+}
+
+static ssize_t apds990x_rate_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->arate);
+}
+
+static int apds990x_set_arate(struct apds990x_chip *chip, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arates_hz); i++)
+               if (rate >= arates_hz[i])
+                       break;
+
+       if (i == ARRAY_SIZE(arates_hz))
+               return -EINVAL;
+
+       /* Pick up corresponding persistence value */
+       chip->lux_persistence = apersis[i];
+       chip->arate = arates_hz[i];
+
+       /* If the chip is not in use, don't try to access it */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       /* Persistence levels */
+       return apds990x_write_byte(chip, APDS990X_PERS,
+                       (chip->lux_persistence << APDS990X_APERS_SHIFT) |
+                       (chip->prox_persistence << APDS990X_PPERS_SHIFT));
+}
+
+static ssize_t apds990x_rate_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+       int ret;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       ret = apds990x_set_arate(chip, value);
+       mutex_unlock(&chip->mutex);
+
+       if (ret < 0)
+               return ret;
+       return len;
+}
+
+static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, apds990x_rate_avail, NULL);
+
+static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, apds990x_rate_show,
+                                                apds990x_rate_store);
+
+static ssize_t apds990x_prox_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       ssize_t ret;
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       if (pm_runtime_suspended(dev) || !chip->prox_en)
+               return -EIO;
+
+       mutex_lock(&chip->mutex);
+       ret = sprintf(buf, "%d\n", chip->prox_data);
+       mutex_unlock(&chip->mutex);
+       return ret;
+}
+
+static DEVICE_ATTR(prox0_raw, S_IRUGO, apds990x_prox_show, NULL);
+
+static ssize_t apds990x_prox_range_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", APDS_PROX_RANGE);
+}
+
+static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, apds990x_prox_range_show, NULL);
+
+static ssize_t apds990x_prox_enable_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->prox_en);
+}
+
+static ssize_t apds990x_prox_enable_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+
+       if (!chip->prox_en)
+               chip->prox_data = 0;
+
+       if (value)
+               chip->prox_en++;
+       else if (chip->prox_en > 0)
+               chip->prox_en--;
+
+       if (!pm_runtime_suspended(dev))
+               apds990x_mode_on(chip);
+       mutex_unlock(&chip->mutex);
+       return len;
+}
+
+static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, apds990x_prox_enable_show,
+                                                  apds990x_prox_enable_store);
+
+static const char reporting_modes[][9] = {"trigger", "periodic"};
+
+static ssize_t apds990x_prox_reporting_mode_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n",
+               reporting_modes[!!chip->prox_continuous_mode]);
+}
+
+static ssize_t apds990x_prox_reporting_mode_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+
+       if (sysfs_streq(buf, reporting_modes[0]))
+               chip->prox_continuous_mode = 0;
+       else if (sysfs_streq(buf, reporting_modes[1]))
+               chip->prox_continuous_mode = 1;
+       else
+               return -EINVAL;
+       return len;
+}
+
+static DEVICE_ATTR(prox0_reporting_mode, S_IRUGO | S_IWUSR,
+               apds990x_prox_reporting_mode_show,
+               apds990x_prox_reporting_mode_store);
+
+static ssize_t apds990x_prox_reporting_avail_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s %s\n", reporting_modes[0], reporting_modes[1]);
+}
+
+static DEVICE_ATTR(prox0_reporting_mode_avail, S_IRUGO | S_IWUSR,
+               apds990x_prox_reporting_avail_show, NULL);
+
+
+static ssize_t apds990x_lux_thresh_above_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->lux_thres_hi);
+}
+
+static ssize_t apds990x_lux_thresh_below_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->lux_thres_lo);
+}
+
+static ssize_t apds990x_set_lux_thresh(struct apds990x_chip *chip, u32 *target,
+                               const char *buf)
+{
+       int ret = 0;
+       unsigned long thresh;
+
+       if (strict_strtoul(buf, 0, &thresh))
+               return -EINVAL;
+
+       if (thresh > APDS_RANGE)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       *target = thresh;
+       /*
+        * Don't update values in HW if we are still waiting for
+        * first interrupt to come after device handle open call.
+        */
+       if (!chip->lux_wait_fresh_res)
+               apds990x_refresh_athres(chip);
+       mutex_unlock(&chip->mutex);
+       return ret;
+
+}
+
+static ssize_t apds990x_lux_thresh_above_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_hi, buf);
+       if (ret < 0)
+               return ret;
+       return len;
+}
+
+static ssize_t apds990x_lux_thresh_below_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_lo, buf);
+       if (ret < 0)
+               return ret;
+       return len;
+}
+
+static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
+               apds990x_lux_thresh_above_show,
+               apds990x_lux_thresh_above_store);
+
+static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
+               apds990x_lux_thresh_below_show,
+               apds990x_lux_thresh_below_store);
+
+static ssize_t apds990x_prox_threshold_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->prox_thres);
+}
+
+static ssize_t apds990x_prox_threshold_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if ((value > APDS_RANGE) || (value == 0) ||
+               (value < APDS_PROX_HYSTERESIS))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       chip->prox_thres = value;
+
+       apds990x_force_p_refresh(chip);
+       mutex_unlock(&chip->mutex);
+       return len;
+}
+
+static DEVICE_ATTR(prox0_thresh_above_value, S_IRUGO | S_IWUSR,
+               apds990x_prox_threshold_show,
+               apds990x_prox_threshold_store);
+
+static ssize_t apds990x_power_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
+       return 0;
+}
+
+static ssize_t apds990x_power_state_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+       if (value) {
+               pm_runtime_get_sync(dev);
+               mutex_lock(&chip->mutex);
+               chip->lux_wait_fresh_res = true;
+               apds990x_force_a_refresh(chip);
+               apds990x_force_p_refresh(chip);
+               mutex_unlock(&chip->mutex);
+       } else {
+               if (!pm_runtime_suspended(dev))
+                       pm_runtime_put(dev);
+       }
+       return len;
+}
+
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
+               apds990x_power_state_show,
+               apds990x_power_state_store);
+
+static ssize_t apds990x_chip_id_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct apds990x_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%s %d\n", chip->chipname, chip->revision);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, apds990x_chip_id_show, NULL);
+
+static struct attribute *sysfs_attrs_ctrl[] = {
+       &dev_attr_lux0_calibscale.attr,
+       &dev_attr_lux0_calibscale_default.attr,
+       &dev_attr_lux0_input.attr,
+       &dev_attr_lux0_sensor_range.attr,
+       &dev_attr_lux0_rate.attr,
+       &dev_attr_lux0_rate_avail.attr,
+       &dev_attr_lux0_thresh_above_value.attr,
+       &dev_attr_lux0_thresh_below_value.attr,
+       &dev_attr_prox0_raw_en.attr,
+       &dev_attr_prox0_raw.attr,
+       &dev_attr_prox0_sensor_range.attr,
+       &dev_attr_prox0_thresh_above_value.attr,
+       &dev_attr_prox0_reporting_mode.attr,
+       &dev_attr_prox0_reporting_mode_avail.attr,
+       &dev_attr_chip_id.attr,
+       &dev_attr_power_state.attr,
+       NULL
+};
+
+static struct attribute_group apds990x_attribute_group[] = {
+       {.attrs = sysfs_attrs_ctrl },
+};
+
+static int __devinit apds990x_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct apds990x_chip *chip;
+       int err;
+
+       chip = kzalloc(sizeof *chip, GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client  = client;
+
+       init_waitqueue_head(&chip->wait);
+       mutex_init(&chip->mutex);
+       chip->pdata     = client->dev.platform_data;
+
+       if (chip->pdata == NULL) {
+               dev_err(&client->dev, "platform data is mandatory\n");
+               err = -EINVAL;
+               goto fail1;
+       }
+
+       if (chip->pdata->cf.ga == 0) {
+               /* set uncovered sensor default parameters */
+               chip->cf.ga = 1966; /* 0.48 * APDS_PARAM_SCALE */
+               chip->cf.cf1 = 4096; /* 1.00 * APDS_PARAM_SCALE */
+               chip->cf.irf1 = 9134; /* 2.23 * APDS_PARAM_SCALE */
+               chip->cf.cf2 = 2867; /* 0.70 * APDS_PARAM_SCALE */
+               chip->cf.irf2 = 5816; /* 1.42 * APDS_PARAM_SCALE */
+               chip->cf.df = 52;
+       } else {
+               chip->cf = chip->pdata->cf;
+       }
+
+       /* precalculate inverse chip factors for threshold control */
+       chip->rcf.afactor =
+               (chip->cf.irf1 - chip->cf.irf2) * APDS_PARAM_SCALE /
+               (chip->cf.cf1 - chip->cf.cf2);
+       chip->rcf.cf1 = APDS_PARAM_SCALE * APDS_PARAM_SCALE /
+               chip->cf.cf1;
+       chip->rcf.irf1 = chip->cf.irf1 * APDS_PARAM_SCALE /
+               chip->cf.cf1;
+       chip->rcf.cf2 = APDS_PARAM_SCALE * APDS_PARAM_SCALE /
+               chip->cf.cf2;
+       chip->rcf.irf2 = chip->cf.irf2 * APDS_PARAM_SCALE /
+               chip->cf.cf2;
+
+       /* Set something to start with */
+       chip->lux_thres_hi = APDS_LUX_DEF_THRES_HI;
+       chip->lux_thres_lo = APDS_LUX_DEF_THRES_LO;
+       chip->lux_calib = APDS_LUX_NEUTRAL_CALIB_VALUE;
+
+       chip->prox_thres = APDS_PROX_DEF_THRES;
+       chip->pdrive = chip->pdata->pdrive;
+       chip->pdiode = APDS_PDIODE_IR;
+       chip->pgain = APDS_PGAIN_1X;
+       chip->prox_calib = APDS_PROX_NEUTRAL_CALIB_VALUE;
+       chip->prox_persistence = APDS_DEFAULT_PROX_PERS;
+       chip->prox_continuous_mode = false;
+
+       chip->regs[0].supply = reg_vcc;
+       chip->regs[1].supply = reg_vled;
+
+       err = regulator_bulk_get(&client->dev,
+                                ARRAY_SIZE(chip->regs), chip->regs);
+       if (err < 0) {
+               dev_err(&client->dev, "Cannot get regulators\n");
+               goto fail1;
+       }
+
+       err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), chip->regs);
+       if (err < 0) {
+               dev_err(&client->dev, "Cannot enable regulators\n");
+               goto fail2;
+       }
+
+       usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY);
+
+       err = apds990x_detect(chip);
+       if (err < 0) {
+               dev_err(&client->dev, "APDS990X not found\n");
+               goto fail3;
+       }
+
+       pm_runtime_set_active(&client->dev);
+
+       apds990x_configure(chip);
+       apds990x_set_arate(chip, APDS_LUX_DEFAULT_RATE);
+       apds990x_mode_on(chip);
+
+       pm_runtime_enable(&client->dev);
+
+       if (chip->pdata->setup_resources) {
+               err = chip->pdata->setup_resources();
+               if (err) {
+                       err = -EINVAL;
+                       goto fail3;
+               }
+       }
+
+       err = sysfs_create_group(&chip->client->dev.kobj,
+                               apds990x_attribute_group);
+       if (err < 0) {
+               dev_err(&chip->client->dev, "Sysfs registration failed\n");
+               goto fail4;
+       }
+
+       err = request_threaded_irq(client->irq, NULL,
+                               apds990x_irq,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW |
+                               IRQF_ONESHOT,
+                               "apds990x", chip);
+       if (err) {
+               dev_err(&client->dev, "could not get IRQ %d\n",
+                       client->irq);
+               goto fail5;
+       }
+       return err;
+fail5:
+       sysfs_remove_group(&chip->client->dev.kobj,
+                       &apds990x_attribute_group[0]);
+fail4:
+       if (chip->pdata && chip->pdata->release_resources)
+               chip->pdata->release_resources();
+fail3:
+       regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+fail2:
+       regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+fail1:
+       kfree(chip);
+       return err;
+}
+
+static int __devexit apds990x_remove(struct i2c_client *client)
+{
+       struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+       free_irq(client->irq, chip);
+       sysfs_remove_group(&chip->client->dev.kobj,
+                       apds990x_attribute_group);
+
+       if (chip->pdata && chip->pdata->release_resources)
+               chip->pdata->release_resources();
+
+       if (!pm_runtime_suspended(&client->dev))
+               apds990x_chip_off(chip);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+
+       kfree(chip);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds990x_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+       apds990x_chip_off(chip);
+       return 0;
+}
+
+static int apds990x_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+       /*
+        * If we were enabled at suspend time, it is expected
+        * everything works nice and smoothly. Chip_on is enough
+        */
+       apds990x_chip_on(chip);
+
+       return 0;
+}
+#else
+#define apds990x_suspend  NULL
+#define apds990x_resume          NULL
+#define apds990x_shutdown NULL
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int apds990x_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+       apds990x_chip_off(chip);
+       return 0;
+}
+
+static int apds990x_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+       apds990x_chip_on(chip);
+       return 0;
+}
+
+#endif
+
+static const struct i2c_device_id apds990x_id[] = {
+       {"apds990x", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, apds990x_id);
+
+static const struct dev_pm_ops apds990x_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(apds990x_suspend, apds990x_resume)
+       SET_RUNTIME_PM_OPS(apds990x_runtime_suspend,
+                       apds990x_runtime_resume,
+                       NULL)
+};
+
+static struct i2c_driver apds990x_driver = {
+       .driver  = {
+               .name   = "apds990x",
+               .owner  = THIS_MODULE,
+               .pm     = &apds990x_pm_ops,
+       },
+       .probe    = apds990x_probe,
+       .remove   = __devexit_p(apds990x_remove),
+       .id_table = apds990x_id,
+};
+
+static int __init apds990x_init(void)
+{
+       return i2c_add_driver(&apds990x_driver);
+}
+
+static void __exit apds990x_exit(void)
+{
+       i2c_del_driver(&apds990x_driver);
+}
+
+MODULE_DESCRIPTION("APDS990X combined ALS and proximity sensor");
+MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
+MODULE_LICENSE("GPL v2");
+
+module_init(apds990x_init);
+module_exit(apds990x_exit);
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
new file mode 100644 (file)
index 0000000..cee632e
--- /dev/null
@@ -0,0 +1,1413 @@
+/*
+ * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/i2c/bh1770glc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#define BH1770_ALS_CONTROL     0x80 /* ALS operation mode control */
+#define BH1770_PS_CONTROL      0x81 /* PS operation mode control */
+#define BH1770_I_LED           0x82 /* active LED and LED1, LED2 current */
+#define BH1770_I_LED3          0x83 /* LED3 current setting */
+#define BH1770_ALS_PS_MEAS     0x84 /* Forced mode trigger */
+#define BH1770_PS_MEAS_RATE    0x85 /* PS meas. rate at stand alone mode */
+#define BH1770_ALS_MEAS_RATE   0x86 /* ALS meas. rate at stand alone mode */
+#define BH1770_PART_ID         0x8a /* Part number and revision ID */
+#define BH1770_MANUFACT_ID     0x8b /* Manufacturerer ID */
+#define BH1770_ALS_DATA_0      0x8c /* ALS DATA low byte */
+#define BH1770_ALS_DATA_1      0x8d /* ALS DATA high byte */
+#define BH1770_ALS_PS_STATUS   0x8e /* Measurement data and int status */
+#define BH1770_PS_DATA_LED1    0x8f /* PS data from LED1 */
+#define BH1770_PS_DATA_LED2    0x90 /* PS data from LED2 */
+#define BH1770_PS_DATA_LED3    0x91 /* PS data from LED3 */
+#define BH1770_INTERRUPT       0x92 /* Interrupt setting */
+#define BH1770_PS_TH_LED1      0x93 /* PS interrupt threshold for LED1 */
+#define BH1770_PS_TH_LED2      0x94 /* PS interrupt threshold for LED2 */
+#define BH1770_PS_TH_LED3      0x95 /* PS interrupt threshold for LED3 */
+#define BH1770_ALS_TH_UP_0     0x96 /* ALS upper threshold low byte */
+#define BH1770_ALS_TH_UP_1     0x97 /* ALS upper threshold high byte */
+#define BH1770_ALS_TH_LOW_0    0x98 /* ALS lower threshold low byte */
+#define BH1770_ALS_TH_LOW_1    0x99 /* ALS lower threshold high byte */
+
+/* MANUFACT_ID */
+#define BH1770_MANUFACT_ROHM   0x01
+#define BH1770_MANUFACT_OSRAM  0x03
+
+/* PART_ID */
+#define BH1770_PART            0x90
+#define BH1770_PART_MASK       0xf0
+#define BH1770_REV_MASK                0x0f
+#define BH1770_REV_SHIFT       0
+#define BH1770_REV_0           0x00
+#define BH1770_REV_1           0x01
+
+/* Operating modes for both */
+#define BH1770_STANDBY         0x00
+#define BH1770_FORCED          0x02
+#define BH1770_STANDALONE      0x03
+#define BH1770_SWRESET         (0x01 << 2)
+
+#define BH1770_PS_TRIG_MEAS    (1 << 0)
+#define BH1770_ALS_TRIG_MEAS   (1 << 1)
+
+/* Interrupt control */
+#define BH1770_INT_OUTPUT_MODE (1 << 3) /* 0 = latched */
+#define BH1770_INT_POLARITY    (1 << 2) /* 1 = active high */
+#define BH1770_INT_ALS_ENA     (1 << 1)
+#define BH1770_INT_PS_ENA      (1 << 0)
+
+/* Interrupt status */
+#define BH1770_INT_LED1_DATA   (1 << 0)
+#define BH1770_INT_LED1_INT    (1 << 1)
+#define BH1770_INT_LED2_DATA   (1 << 2)
+#define BH1770_INT_LED2_INT    (1 << 3)
+#define BH1770_INT_LED3_DATA   (1 << 4)
+#define BH1770_INT_LED3_INT    (1 << 5)
+#define BH1770_INT_LEDS_INT    ((1 << 1) | (1 << 3) | (1 << 5))
+#define BH1770_INT_ALS_DATA    (1 << 6)
+#define BH1770_INT_ALS_INT     (1 << 7)
+
+/* Led channels */
+#define BH1770_LED1            0x00
+
+#define BH1770_DISABLE         0
+#define BH1770_ENABLE          1
+#define BH1770_PROX_CHANNELS   1
+
+#define BH1770_LUX_DEFAULT_RATE        1 /* Index to lux rate table */
+#define BH1770_PROX_DEFAULT_RATE 1 /* Direct HW value =~ 50Hz */
+#define BH1770_PROX_DEF_RATE_THRESH 6 /* Direct HW value =~ 5 Hz */
+#define BH1770_STARTUP_DELAY   50
+#define BH1770_RESET_TIME      10
+#define BH1770_TIMEOUT         2100 /* Timeout in 2.1 seconds */
+
+#define BH1770_LUX_RANGE       65535
+#define BH1770_PROX_RANGE      255
+#define BH1770_COEF_SCALER     1024
+#define BH1770_CALIB_SCALER    8192
+#define BH1770_LUX_NEUTRAL_CALIB_VALUE (1 * BH1770_CALIB_SCALER)
+#define BH1770_LUX_DEF_THRES   1000
+#define BH1770_PROX_DEF_THRES  70
+#define BH1770_PROX_DEF_ABS_THRES   100
+#define BH1770_DEFAULT_PERSISTENCE  10
+#define BH1770_PROX_MAX_PERSISTENCE 50
+#define BH1770_LUX_GA_SCALE    16384
+#define BH1770_LUX_CF_SCALE    2048 /* CF ChipFactor */
+#define BH1770_NEUTRAL_CF      BH1770_LUX_CF_SCALE
+#define BH1770_LUX_CORR_SCALE  4096
+
+#define PROX_ABOVE_THRESHOLD   1
+#define PROX_BELOW_THRESHOLD   0
+
+#define PROX_IGNORE_LUX_LIMIT  500
+
+struct bh1770_chip {
+       struct bh1770_platform_data     *pdata;
+       char                            chipname[10];
+       u8                              revision;
+       struct i2c_client               *client;
+       struct regulator_bulk_data      regs[2];
+       struct mutex                    mutex; /* avoid parallel access */
+       wait_queue_head_t               wait;
+
+       bool                    int_mode_prox;
+       bool                    int_mode_lux;
+       struct delayed_work     prox_work;
+       u32     lux_cf; /* Chip specific factor */
+       u32     lux_ga;
+       u32     lux_calib;
+       int     lux_rate_index;
+       u32     lux_corr;
+       u16     lux_data_raw;
+       u16     lux_threshold_hi;
+       u16     lux_threshold_lo;
+       u16     lux_thres_hi_onchip;
+       u16     lux_thres_lo_onchip;
+       bool    lux_wait_result;
+
+       int     prox_enable_count;
+       u16     prox_coef;
+       u16     prox_const;
+       int     prox_rate;
+       int     prox_rate_threshold;
+       u8      prox_persistence;
+       u8      prox_persistence_counter;
+       u8      prox_data;
+       u8      prox_threshold;
+       u8      prox_threshold_hw;
+       bool    prox_force_update;
+       u8      prox_abs_thres;
+       u8      prox_led;
+};
+
+static const char reg_vcc[] = "Vcc";
+static const char reg_vleds[] = "Vleds";
+
+/*
+ * Supported stand alone rates in ms from chip data sheet
+ * {10, 20, 30, 40, 70, 100, 200, 500, 1000, 2000};
+ */
+static const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2};
+static const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500};
+
+/* Supported IR-led currents in mA */
+static const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200};
+
+/*
+ * Supported stand alone rates in ms from chip data sheet
+ * {100, 200, 500, 1000, 2000};
+ */
+static const s16 lux_rates_hz[] = {10, 5, 2, 1, 0};
+
+/*
+ * interrupt control functions are called while keeping chip->mutex
+ * excluding module probe / remove
+ */
+static inline int bh1770_lux_interrupt_control(struct bh1770_chip *chip,
+                                       int lux)
+{
+       chip->int_mode_lux = lux;
+       /* Set interrupt modes, interrupt active low, latched */
+       return i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_INTERRUPT,
+                                       (lux << 1) | chip->int_mode_prox);
+}
+
+static inline int bh1770_prox_interrupt_control(struct bh1770_chip *chip,
+                                       int ps)
+{
+       chip->int_mode_prox = ps;
+       return i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_INTERRUPT,
+                                       (chip->int_mode_lux << 1) | (ps << 0));
+}
+
+/* chip->mutex is always kept here */
+static int bh1770_lux_rate(struct bh1770_chip *chip, int rate_index)
+{
+       /* sysfs may call this when the chip is powered off */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       /* Proper proximity response needs fastest lux rate (100ms) */
+       if (chip->prox_enable_count)
+               rate_index = 0;
+
+       return i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_ALS_MEAS_RATE,
+                                       rate_index);
+}
+
+static int bh1770_prox_rate(struct bh1770_chip *chip, int mode)
+{
+       int rate;
+
+       rate = (mode == PROX_ABOVE_THRESHOLD) ?
+               chip->prox_rate_threshold : chip->prox_rate;
+
+       return i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_PS_MEAS_RATE,
+                                       rate);
+}
+
+/* InfraredLED is controlled by the chip during proximity scanning */
+static inline int bh1770_led_cfg(struct bh1770_chip *chip)
+{
+       /* LED cfg, current for leds 1 and 2 */
+       return i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_I_LED,
+                                       (BH1770_LED1 << 6) |
+                                       (BH1770_LED_5mA << 3) |
+                                       chip->prox_led);
+}
+
+/*
+ * Following two functions converts raw ps values from HW to normalized
+ * values. Purpose is to compensate differences between different sensor
+ * versions and variants so that result means about the same between
+ * versions.
+ */
+static inline u8 bh1770_psraw_to_adjusted(struct bh1770_chip *chip, u8 psraw)
+{
+       u16 adjusted;
+       adjusted = (u16)(((u32)(psraw + chip->prox_const) * chip->prox_coef) /
+               BH1770_COEF_SCALER);
+       if (adjusted > BH1770_PROX_RANGE)
+               adjusted = BH1770_PROX_RANGE;
+       return adjusted;
+}
+
+static inline u8 bh1770_psadjusted_to_raw(struct bh1770_chip *chip, u8 ps)
+{
+       u16 raw;
+
+       raw = (((u32)ps * BH1770_COEF_SCALER) / chip->prox_coef);
+       if (raw > chip->prox_const)
+               raw = raw - chip->prox_const;
+       else
+               raw = 0;
+       return raw;
+}
+
+/*
+ * Following two functions converts raw lux values from HW to normalized
+ * values. Purpose is to compensate differences between different sensor
+ * versions and variants so that result means about the same between
+ * versions. Chip->mutex is kept when this is called.
+ */
+static int bh1770_prox_set_threshold(struct bh1770_chip *chip)
+{
+       u8 tmp = 0;
+
+       /* sysfs may call this when the chip is powered off */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       tmp = bh1770_psadjusted_to_raw(chip, chip->prox_threshold);
+       chip->prox_threshold_hw = tmp;
+
+       return  i2c_smbus_write_byte_data(chip->client, BH1770_PS_TH_LED1,
+                                       tmp);
+}
+
+static inline u16 bh1770_lux_raw_to_adjusted(struct bh1770_chip *chip, u16 raw)
+{
+       u32 lux;
+       lux = ((u32)raw * chip->lux_corr) / BH1770_LUX_CORR_SCALE;
+       return min(lux, (u32)BH1770_LUX_RANGE);
+}
+
+static inline u16 bh1770_lux_adjusted_to_raw(struct bh1770_chip *chip,
+                                       u16 adjusted)
+{
+       return (u32)adjusted * BH1770_LUX_CORR_SCALE / chip->lux_corr;
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_lux_update_thresholds(struct bh1770_chip *chip,
+                                       u16 threshold_hi, u16 threshold_lo)
+{
+       u8 data[4];
+       int ret;
+
+       /* sysfs may call this when the chip is powered off */
+       if (pm_runtime_suspended(&chip->client->dev))
+               return 0;
+
+       /*
+        * Compensate threshold values with the correction factors if not
+        * set to minimum or maximum.
+        * Min & max values disables interrupts.
+        */
+       if (threshold_hi != BH1770_LUX_RANGE && threshold_hi != 0)
+               threshold_hi = bh1770_lux_adjusted_to_raw(chip, threshold_hi);
+
+       if (threshold_lo != BH1770_LUX_RANGE && threshold_lo != 0)
+               threshold_lo = bh1770_lux_adjusted_to_raw(chip, threshold_lo);
+
+       if (chip->lux_thres_hi_onchip == threshold_hi &&
+           chip->lux_thres_lo_onchip == threshold_lo)
+               return 0;
+
+       chip->lux_thres_hi_onchip = threshold_hi;
+       chip->lux_thres_lo_onchip = threshold_lo;
+
+       data[0] = threshold_hi;
+       data[1] = threshold_hi >> 8;
+       data[2] = threshold_lo;
+       data[3] = threshold_lo >> 8;
+
+       ret = i2c_smbus_write_i2c_block_data(chip->client,
+                                       BH1770_ALS_TH_UP_0,
+                                       ARRAY_SIZE(data),
+                                       data);
+       return ret;
+}
+
+static int bh1770_lux_get_result(struct bh1770_chip *chip)
+{
+       u16 data;
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_0);
+       if (ret < 0)
+               return ret;
+
+       data = ret & 0xff;
+       ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_1);
+       if (ret < 0)
+               return ret;
+
+       chip->lux_data_raw = data | ((ret & 0xff) << 8);
+
+       return 0;
+}
+
+/* Calculate correction value which contains chip and device specific parts */
+static u32 bh1770_get_corr_value(struct bh1770_chip *chip)
+{
+       u32 tmp;
+       /* Impact of glass attenuation correction */
+       tmp = (BH1770_LUX_CORR_SCALE * chip->lux_ga) / BH1770_LUX_GA_SCALE;
+       /* Impact of chip factor correction */
+       tmp = (tmp * chip->lux_cf) / BH1770_LUX_CF_SCALE;
+       /* Impact of Device specific calibration correction */
+       tmp = (tmp * chip->lux_calib) / BH1770_CALIB_SCALER;
+       return tmp;
+}
+
+static int bh1770_lux_read_result(struct bh1770_chip *chip)
+{
+       bh1770_lux_get_result(chip);
+       return bh1770_lux_raw_to_adjusted(chip, chip->lux_data_raw);
+}
+
+/*
+ * Chip on / off functions are called while keeping mutex except probe
+ * or remove phase
+ */
+static int bh1770_chip_on(struct bh1770_chip *chip)
+{
+       int ret = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+                                       chip->regs);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
+
+       /* Reset the chip */
+       i2c_smbus_write_byte_data(chip->client, BH1770_ALS_CONTROL,
+                               BH1770_SWRESET);
+       usleep_range(BH1770_RESET_TIME, BH1770_RESET_TIME * 2);
+
+       /*
+        * ALS is started always since proximity needs als results
+        * for realibility estimation.
+        * Let's assume dark until the first ALS measurement is ready.
+        */
+       chip->lux_data_raw = 0;
+       chip->prox_data = 0;
+       ret = i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_ALS_CONTROL, BH1770_STANDALONE);
+
+       /* Assume reset defaults */
+       chip->lux_thres_hi_onchip = BH1770_LUX_RANGE;
+       chip->lux_thres_lo_onchip = 0;
+
+       return ret;
+}
+
+static void bh1770_chip_off(struct bh1770_chip *chip)
+{
+       i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_INTERRUPT, BH1770_DISABLE);
+       i2c_smbus_write_byte_data(chip->client,
+                               BH1770_ALS_CONTROL, BH1770_STANDBY);
+       i2c_smbus_write_byte_data(chip->client,
+                               BH1770_PS_CONTROL, BH1770_STANDBY);
+       regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_prox_mode_control(struct bh1770_chip *chip)
+{
+       if (chip->prox_enable_count) {
+               chip->prox_force_update = true; /* Force immediate update */
+
+               bh1770_lux_rate(chip, chip->lux_rate_index);
+               bh1770_prox_set_threshold(chip);
+               bh1770_led_cfg(chip);
+               bh1770_prox_rate(chip, PROX_BELOW_THRESHOLD);
+               bh1770_prox_interrupt_control(chip, BH1770_ENABLE);
+               i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_PS_CONTROL, BH1770_STANDALONE);
+       } else {
+               chip->prox_data = 0;
+               bh1770_lux_rate(chip, chip->lux_rate_index);
+               bh1770_prox_interrupt_control(chip, BH1770_DISABLE);
+               i2c_smbus_write_byte_data(chip->client,
+                                       BH1770_PS_CONTROL, BH1770_STANDBY);
+       }
+       return 0;
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_prox_read_result(struct bh1770_chip *chip)
+{
+       int ret;
+       bool above;
+       u8 mode;
+
+       ret = i2c_smbus_read_byte_data(chip->client, BH1770_PS_DATA_LED1);
+       if (ret < 0)
+               goto out;
+
+       if (ret > chip->prox_threshold_hw)
+               above = true;
+       else
+               above = false;
+
+       /*
+        * when ALS levels goes above limit, proximity result may be
+        * false proximity. Thus ignore the result. With real proximity
+        * there is a shadow causing low als levels.
+        */
+       if (chip->lux_data_raw > PROX_IGNORE_LUX_LIMIT)
+               ret = 0;
+
+       chip->prox_data = bh1770_psraw_to_adjusted(chip, ret);
+
+       /* Strong proximity level or force mode requires immediate response */
+       if (chip->prox_data >= chip->prox_abs_thres ||
+           chip->prox_force_update)
+               chip->prox_persistence_counter = chip->prox_persistence;
+
+       chip->prox_force_update = false;
+
+       /* Persistence filttering to reduce false proximity events */
+       if (likely(above)) {
+               if (chip->prox_persistence_counter < chip->prox_persistence) {
+                       chip->prox_persistence_counter++;
+                       ret = -ENODATA;
+               } else {
+                       mode = PROX_ABOVE_THRESHOLD;
+                       ret = 0;
+               }
+       } else {
+               chip->prox_persistence_counter = 0;
+               mode = PROX_BELOW_THRESHOLD;
+               chip->prox_data = 0;
+               ret = 0;
+       }
+
+       /* Set proximity detection rate based on above or below value */
+       if (ret == 0) {
+               bh1770_prox_rate(chip, mode);
+               sysfs_notify(&chip->client->dev.kobj, NULL, "prox0_raw");
+       }
+out:
+       return ret;
+}
+
+static int bh1770_detect(struct bh1770_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       s32 ret;
+       u8 manu, part;
+
+       ret = i2c_smbus_read_byte_data(client, BH1770_MANUFACT_ID);
+       if (ret < 0)
+               goto error;
+       manu = (u8)ret;
+
+       ret = i2c_smbus_read_byte_data(client, BH1770_PART_ID);
+       if (ret < 0)
+               goto error;
+       part = (u8)ret;
+
+       chip->revision = (part & BH1770_REV_MASK) >> BH1770_REV_SHIFT;
+       chip->prox_coef = BH1770_COEF_SCALER;
+       chip->prox_const = 0;
+       chip->lux_cf = BH1770_NEUTRAL_CF;
+
+       if ((manu == BH1770_MANUFACT_ROHM) &&
+           ((part & BH1770_PART_MASK) == BH1770_PART)) {
+               snprintf(chip->chipname, sizeof(chip->chipname), "BH1770GLC");
+               return 0;
+       }
+
+       if ((manu == BH1770_MANUFACT_OSRAM) &&
+           ((part & BH1770_PART_MASK) == BH1770_PART)) {
+               snprintf(chip->chipname, sizeof(chip->chipname), "SFH7770");
+               /* Values selected by comparing different versions */
+               chip->prox_coef = 819; /* 0.8 * BH1770_COEF_SCALER */
+               chip->prox_const = 40;
+               return 0;
+       }
+
+       ret = -ENODEV;
+error:
+       dev_dbg(&client->dev, "BH1770 or SFH7770 not found\n");
+
+       return ret;
+}
+
+/*
+ * This work is re-scheduled at every proximity interrupt.
+ * If this work is running, it means that there hasn't been any
+ * proximity interrupt in time. Situation is handled as no-proximity.
+ * It would be nice to have low-threshold interrupt or interrupt
+ * when measurement and hi-threshold are both 0. But neither of those exists.
+ * This is a workaroud for missing HW feature.
+ */
+
+static void bh1770_prox_work(struct work_struct *work)
+{
+       struct bh1770_chip *chip =
+               container_of(work, struct bh1770_chip, prox_work.work);
+
+       mutex_lock(&chip->mutex);
+       bh1770_prox_read_result(chip);
+       mutex_unlock(&chip->mutex);
+}
+
+/* This is threaded irq handler */
+static irqreturn_t bh1770_irq(int irq, void *data)
+{
+       struct bh1770_chip *chip = data;
+       int status;
+       int rate = 0;
+
+       mutex_lock(&chip->mutex);
+       status = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_PS_STATUS);
+
+       /* Acknowledge interrupt by reading this register */
+       i2c_smbus_read_byte_data(chip->client, BH1770_INTERRUPT);
+
+       /*
+        * Check if there is fresh data available for als.
+        * If this is the very first data, update thresholds after that.
+        */
+       if (status & BH1770_INT_ALS_DATA) {
+               bh1770_lux_get_result(chip);
+               if (unlikely(chip->lux_wait_result)) {
+                       chip->lux_wait_result = false;
+                       wake_up(&chip->wait);
+                       bh1770_lux_update_thresholds(chip,
+                                               chip->lux_threshold_hi,
+                                               chip->lux_threshold_lo);
+               }
+       }
+
+       /* Disable interrupt logic to guarantee acknowledgement */
+       i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
+                                 (0 << 1) | (0 << 0));
+
+       if ((status & BH1770_INT_ALS_INT))
+               sysfs_notify(&chip->client->dev.kobj, NULL, "lux0_input");
+
+       if (chip->int_mode_prox && (status & BH1770_INT_LEDS_INT)) {
+               rate = prox_rates_ms[chip->prox_rate_threshold];
+               bh1770_prox_read_result(chip);
+       }
+
+       /* Re-enable interrupt logic */
+       i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
+                                 (chip->int_mode_lux << 1) |
+                                 (chip->int_mode_prox << 0));
+       mutex_unlock(&chip->mutex);
+
+       /*
+        * Can't cancel work while keeping mutex since the work uses the
+        * same mutex.
+        */
+       if (rate) {
+               /*
+                * Simulate missing no-proximity interrupt 50ms after the
+                * next expected interrupt time.
+                */
+               cancel_delayed_work_sync(&chip->prox_work);
+               schedule_delayed_work(&chip->prox_work,
+                               msecs_to_jiffies(rate + 50));
+       }
+       return IRQ_HANDLED;
+}
+
+static ssize_t bh1770_power_state_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+       size_t ret;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       if (value) {
+               pm_runtime_get_sync(dev);
+
+               ret = bh1770_lux_rate(chip, chip->lux_rate_index);
+               ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+
+               if (ret < 0) {
+                       pm_runtime_put(dev);
+                       goto leave;
+               }
+
+               /* This causes interrupt after the next measurement cycle */
+               bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
+                                       BH1770_LUX_DEF_THRES);
+               /* Inform that we are waiting for a result from ALS */
+               chip->lux_wait_result = true;
+               bh1770_prox_mode_control(chip);
+       } else if (!pm_runtime_suspended(dev)) {
+               pm_runtime_put(dev);
+       }
+       ret = count;
+leave:
+       mutex_unlock(&chip->mutex);
+       return ret;
+}
+
+static ssize_t bh1770_power_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
+}
+
+static ssize_t bh1770_lux_result_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       ssize_t ret;
+       long timeout;
+
+       if (pm_runtime_suspended(dev))
+               return -EIO; /* Chip is not enabled at all */
+
+       timeout = wait_event_interruptible_timeout(chip->wait,
+                                       !chip->lux_wait_result,
+                                       msecs_to_jiffies(BH1770_TIMEOUT));
+       if (!timeout)
+               return -EIO;
+
+       mutex_lock(&chip->mutex);
+       ret = sprintf(buf, "%d\n", bh1770_lux_read_result(chip));
+       mutex_unlock(&chip->mutex);
+
+       return ret;
+}
+
+static ssize_t bh1770_lux_range_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", BH1770_LUX_RANGE);
+}
+
+static ssize_t bh1770_prox_enable_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       /* Assume no proximity. Sensor will tell real state soon */
+       if (!chip->prox_enable_count)
+               chip->prox_data = 0;
+
+       if (value)
+               chip->prox_enable_count++;
+       else if (chip->prox_enable_count > 0)
+               chip->prox_enable_count--;
+       else
+               goto leave;
+
+       /* Run control only when chip is powered on */
+       if (!pm_runtime_suspended(dev))
+               bh1770_prox_mode_control(chip);
+leave:
+       mutex_unlock(&chip->mutex);
+       return count;
+}
+
+static ssize_t bh1770_prox_enable_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       ssize_t len;
+
+       mutex_lock(&chip->mutex);
+       len = sprintf(buf, "%d\n", chip->prox_enable_count);
+       mutex_unlock(&chip->mutex);
+       return len;
+}
+
+static ssize_t bh1770_prox_result_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       ssize_t ret;
+
+       mutex_lock(&chip->mutex);
+       if (chip->prox_enable_count && !pm_runtime_suspended(dev))
+               ret = sprintf(buf, "%d\n", chip->prox_data);
+       else
+               ret = -EIO;
+       mutex_unlock(&chip->mutex);
+       return ret;
+}
+
+static ssize_t bh1770_prox_range_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", BH1770_PROX_RANGE);
+}
+
+static ssize_t bh1770_get_prox_rate_avail(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int i;
+       int pos = 0;
+       for (i = 0; i < ARRAY_SIZE(prox_rates_hz); i++)
+               pos += sprintf(buf + pos, "%d ", prox_rates_hz[i]);
+       sprintf(buf + pos - 1, "\n");
+       return pos;
+}
+
+static ssize_t bh1770_get_prox_rate_above(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate_threshold]);
+}
+
+static ssize_t bh1770_get_prox_rate_below(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate]);
+}
+
+static int bh1770_prox_rate_validate(int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(prox_rates_hz) - 1; i++)
+               if (rate >= prox_rates_hz[i])
+                       break;
+       return i;
+}
+
+static ssize_t bh1770_set_prox_rate_above(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       chip->prox_rate_threshold = bh1770_prox_rate_validate(value);
+       mutex_unlock(&chip->mutex);
+       return count;
+}
+
+static ssize_t bh1770_set_prox_rate_below(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       chip->prox_rate = bh1770_prox_rate_validate(value);
+       mutex_unlock(&chip->mutex);
+       return count;
+}
+
+static ssize_t bh1770_get_prox_thres(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->prox_threshold);
+}
+
+static ssize_t bh1770_set_prox_thres(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long value;
+       int ret;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+       if (value > BH1770_PROX_RANGE)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       chip->prox_threshold = value;
+       ret = bh1770_prox_set_threshold(chip);
+       mutex_unlock(&chip->mutex);
+       if (ret < 0)
+               return ret;
+       return count;
+}
+
+static ssize_t bh1770_prox_persistence_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", chip->prox_persistence);
+}
+
+static ssize_t bh1770_prox_persistence_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if (value > BH1770_PROX_MAX_PERSISTENCE)
+               return -EINVAL;
+
+       chip->prox_persistence = value;
+
+       return len;
+}
+
+static ssize_t bh1770_prox_abs_thres_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", chip->prox_abs_thres);
+}
+
+static ssize_t bh1770_prox_abs_thres_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+       unsigned long value;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if (value > BH1770_PROX_RANGE)
+               return -EINVAL;
+
+       chip->prox_abs_thres = value;
+
+       return len;
+}
+
+static ssize_t bh1770_chip_id_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%s rev %d\n", chip->chipname, chip->revision);
+}
+
+static ssize_t bh1770_lux_calib_default_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", BH1770_CALIB_SCALER);
+}
+
+static ssize_t bh1770_lux_calib_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+       ssize_t len;
+
+       mutex_lock(&chip->mutex);
+       len = sprintf(buf, "%u\n", chip->lux_calib);
+       mutex_unlock(&chip->mutex);
+       return len;
+}
+
+static ssize_t bh1770_lux_calib_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct bh1770_chip *chip = dev_get_drvdata(dev);
+       unsigned long value;
+       u32 old_calib;
+       u32 new_corr;
+
+       if (strict_strtoul(buf, 0, &value))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       old_calib = chip->lux_calib;
+       chip->lux_calib = value;
+       new_corr = bh1770_get_corr_value(chip);
+       if (new_corr == 0) {
+               chip->lux_calib = old_calib;
+               mutex_unlock(&chip->mutex);
+               return -EINVAL;
+       }
+       chip->lux_corr = new_corr;
+       /* Refresh thresholds on HW after changing correction value */
+       bh1770_lux_update_thresholds(chip, chip->lux_threshold_hi,
+                               chip->lux_threshold_lo);
+
+       mutex_unlock(&chip->mutex);
+
+       return len;
+}
+
+static ssize_t bh1770_get_lux_rate_avail(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int i;
+       int pos = 0;
+       for (i = 0; i < ARRAY_SIZE(lux_rates_hz); i++)
+               pos += sprintf(buf + pos, "%d ", lux_rates_hz[i]);
+       sprintf(buf + pos - 1, "\n");
+       return pos;
+}
+
+static ssize_t bh1770_get_lux_rate(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", lux_rates_hz[chip->lux_rate_index]);
+}
+
+static ssize_t bh1770_set_lux_rate(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       unsigned long rate_hz;
+       int ret, i;
+
+       if (strict_strtoul(buf, 0, &rate_hz))
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(lux_rates_hz) - 1; i++)
+               if (rate_hz >= lux_rates_hz[i])
+                       break;
+
+       mutex_lock(&chip->mutex);
+       chip->lux_rate_index = i;
+       ret = bh1770_lux_rate(chip, i);
+       mutex_unlock(&chip->mutex);
+
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t bh1770_get_lux_thresh_above(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->lux_threshold_hi);
+}
+
+static ssize_t bh1770_get_lux_thresh_below(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", chip->lux_threshold_lo);
+}
+
+static ssize_t bh1770_set_lux_thresh(struct bh1770_chip *chip, u16 *target,
+                               const char *buf)
+{
+       int ret = 0;
+       unsigned long thresh;
+
+       if (strict_strtoul(buf, 0, &thresh))
+               return -EINVAL;
+
+       if (thresh > BH1770_LUX_RANGE)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       *target = thresh;
+       /*
+        * Don't update values in HW if we are still waiting for
+        * first interrupt to come after device handle open call.
+        */
+       if (!chip->lux_wait_result)
+               ret = bh1770_lux_update_thresholds(chip,
+                                               chip->lux_threshold_hi,
+                                               chip->lux_threshold_lo);
+       mutex_unlock(&chip->mutex);
+       return ret;
+
+}
+
+static ssize_t bh1770_set_lux_thresh_above(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_hi, buf);
+       if (ret < 0)
+               return ret;
+       return len;
+}
+
+static ssize_t bh1770_set_lux_thresh_below(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct bh1770_chip *chip =  dev_get_drvdata(dev);
+       int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_lo, buf);
+       if (ret < 0)
+               return ret;
+       return len;
+}
+
+static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, bh1770_prox_enable_show,
+                                               bh1770_prox_enable_store);
+static DEVICE_ATTR(prox0_thresh_above1_value, S_IRUGO | S_IWUSR,
+                                               bh1770_prox_abs_thres_show,
+                                               bh1770_prox_abs_thres_store);
+static DEVICE_ATTR(prox0_thresh_above0_value, S_IRUGO | S_IWUSR,
+                                               bh1770_get_prox_thres,
+                                               bh1770_set_prox_thres);
+static DEVICE_ATTR(prox0_raw, S_IRUGO, bh1770_prox_result_show, NULL);
+static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, bh1770_prox_range_show, NULL);
+static DEVICE_ATTR(prox0_thresh_above_count, S_IRUGO | S_IWUSR,
+                                               bh1770_prox_persistence_show,
+                                               bh1770_prox_persistence_store);
+static DEVICE_ATTR(prox0_rate_above, S_IRUGO | S_IWUSR,
+                                               bh1770_get_prox_rate_above,
+                                               bh1770_set_prox_rate_above);
+static DEVICE_ATTR(prox0_rate_below, S_IRUGO | S_IWUSR,
+                                               bh1770_get_prox_rate_below,
+                                               bh1770_set_prox_rate_below);
+static DEVICE_ATTR(prox0_rate_avail, S_IRUGO, bh1770_get_prox_rate_avail, NULL);
+
+static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, bh1770_lux_calib_show,
+                                               bh1770_lux_calib_store);
+static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
+                                               bh1770_lux_calib_default_show,
+                                               NULL);
+static DEVICE_ATTR(lux0_input, S_IRUGO, bh1770_lux_result_show, NULL);
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, bh1770_lux_range_show, NULL);
+static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, bh1770_get_lux_rate,
+                                               bh1770_set_lux_rate);
+static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, bh1770_get_lux_rate_avail, NULL);
+static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
+                                               bh1770_get_lux_thresh_above,
+                                               bh1770_set_lux_thresh_above);
+static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
+                                               bh1770_get_lux_thresh_below,
+                                               bh1770_set_lux_thresh_below);
+static DEVICE_ATTR(chip_id, S_IRUGO, bh1770_chip_id_show, NULL);
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, bh1770_power_state_show,
+                                                bh1770_power_state_store);
+
+
+static struct attribute *sysfs_attrs[] = {
+       &dev_attr_lux0_calibscale.attr,
+       &dev_attr_lux0_calibscale_default.attr,
+       &dev_attr_lux0_input.attr,
+       &dev_attr_lux0_sensor_range.attr,
+       &dev_attr_lux0_rate.attr,
+       &dev_attr_lux0_rate_avail.attr,
+       &dev_attr_lux0_thresh_above_value.attr,
+       &dev_attr_lux0_thresh_below_value.attr,
+       &dev_attr_prox0_raw.attr,
+       &dev_attr_prox0_sensor_range.attr,
+       &dev_attr_prox0_raw_en.attr,
+       &dev_attr_prox0_thresh_above_count.attr,
+       &dev_attr_prox0_rate_above.attr,
+       &dev_attr_prox0_rate_below.attr,
+       &dev_attr_prox0_rate_avail.attr,
+       &dev_attr_prox0_thresh_above0_value.attr,
+       &dev_attr_prox0_thresh_above1_value.attr,
+       &dev_attr_chip_id.attr,
+       &dev_attr_power_state.attr,
+       NULL
+};
+
+static struct attribute_group bh1770_attribute_group = {
+       .attrs = sysfs_attrs
+};
+
+static int __devinit bh1770_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct bh1770_chip *chip;
+       int err;
+
+       chip = kzalloc(sizeof *chip, GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client  = client;
+
+       mutex_init(&chip->mutex);
+       init_waitqueue_head(&chip->wait);
+       INIT_DELAYED_WORK(&chip->prox_work, bh1770_prox_work);
+
+       if (client->dev.platform_data == NULL) {
+               dev_err(&client->dev, "platform data is mandatory\n");
+               err = -EINVAL;
+               goto fail1;
+       }
+
+       chip->pdata             = client->dev.platform_data;
+       chip->lux_calib         = BH1770_LUX_NEUTRAL_CALIB_VALUE;
+       chip->lux_rate_index    = BH1770_LUX_DEFAULT_RATE;
+       chip->lux_threshold_lo  = BH1770_LUX_DEF_THRES;
+       chip->lux_threshold_hi  = BH1770_LUX_DEF_THRES;
+
+       if (chip->pdata->glass_attenuation == 0)
+               chip->lux_ga = BH1770_NEUTRAL_GA;
+       else
+               chip->lux_ga = chip->pdata->glass_attenuation;
+
+       chip->prox_threshold    = BH1770_PROX_DEF_THRES;
+       chip->prox_led          = chip->pdata->led_def_curr;
+       chip->prox_abs_thres    = BH1770_PROX_DEF_ABS_THRES;
+       chip->prox_persistence  = BH1770_DEFAULT_PERSISTENCE;
+       chip->prox_rate_threshold = BH1770_PROX_DEF_RATE_THRESH;
+       chip->prox_rate         = BH1770_PROX_DEFAULT_RATE;
+       chip->prox_data         = 0;
+
+       chip->regs[0].supply = reg_vcc;
+       chip->regs[1].supply = reg_vleds;
+
+       err = regulator_bulk_get(&client->dev,
+                                ARRAY_SIZE(chip->regs), chip->regs);
+       if (err < 0) {
+               dev_err(&client->dev, "Cannot get regulators\n");
+               goto fail1;
+       }
+
+       err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+                               chip->regs);
+       if (err < 0) {
+               dev_err(&client->dev, "Cannot enable regulators\n");
+               goto fail2;
+       }
+
+       usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
+       err = bh1770_detect(chip);
+       if (err < 0)
+               goto fail3;
+
+       /* Start chip */
+       bh1770_chip_on(chip);
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_enable(&client->dev);
+
+       chip->lux_corr = bh1770_get_corr_value(chip);
+       if (chip->lux_corr == 0) {
+               dev_err(&client->dev, "Improper correction values\n");
+               err = -EINVAL;
+               goto fail3;
+       }
+
+       if (chip->pdata->setup_resources) {
+               err = chip->pdata->setup_resources();
+               if (err) {
+                       err = -EINVAL;
+                       goto fail3;
+               }
+       }
+
+       err = sysfs_create_group(&chip->client->dev.kobj,
+                               &bh1770_attribute_group);
+       if (err < 0) {
+               dev_err(&chip->client->dev, "Sysfs registration failed\n");
+               goto fail4;
+       }
+
+       /*
+        * Chip needs level triggered interrupt to work. However,
+        * level triggering doesn't work always correctly with power
+        * management. Select both
+        */
+       err = request_threaded_irq(client->irq, NULL,
+                               bh1770_irq,
+                               IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+                               IRQF_TRIGGER_LOW,
+                               "bh1770", chip);
+       if (err) {
+               dev_err(&client->dev, "could not get IRQ %d\n",
+                       client->irq);
+               goto fail5;
+       }
+       regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+       return err;
+fail5:
+       sysfs_remove_group(&chip->client->dev.kobj,
+                       &bh1770_attribute_group);
+fail4:
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+fail3:
+       regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+fail2:
+       regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+fail1:
+       kfree(chip);
+       return err;
+}
+
+static int __devexit bh1770_remove(struct i2c_client *client)
+{
+       struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+       free_irq(client->irq, chip);
+
+       sysfs_remove_group(&chip->client->dev.kobj,
+                       &bh1770_attribute_group);
+
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+
+       cancel_delayed_work_sync(&chip->prox_work);
+
+       if (!pm_runtime_suspended(&client->dev))
+               bh1770_chip_off(chip);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+       kfree(chip);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bh1770_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+       bh1770_chip_off(chip);
+
+       return 0;
+}
+
+static int bh1770_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct bh1770_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+
+       bh1770_chip_on(chip);
+
+       if (!pm_runtime_suspended(dev)) {
+               /*
+                * If we were enabled at suspend time, it is expected
+                * everything works nice and smoothly
+                */
+               ret = bh1770_lux_rate(chip, chip->lux_rate_index);
+               ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+
+               /* This causes interrupt after the next measurement cycle */
+               bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
+                                       BH1770_LUX_DEF_THRES);
+               /* Inform that we are waiting for a result from ALS */
+               chip->lux_wait_result = true;
+               bh1770_prox_mode_control(chip);
+       }
+       return ret;
+}
+
+#else
+#define bh1770_suspend NULL
+#define bh1770_shutdown NULL
+#define bh1770_resume  NULL
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int bh1770_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+       bh1770_chip_off(chip);
+
+       return 0;
+}
+
+static int bh1770_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+       bh1770_chip_on(chip);
+
+       return 0;
+}
+#endif
+
+static const struct i2c_device_id bh1770_id[] = {
+       {"bh1770glc", 0 },
+       {"sfh7770", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bh1770_id);
+
+static const struct dev_pm_ops bh1770_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(bh1770_suspend, bh1770_resume)
+       SET_RUNTIME_PM_OPS(bh1770_runtime_suspend, bh1770_runtime_resume, NULL)
+};
+
+static struct i2c_driver bh1770_driver = {
+       .driver  = {
+               .name   = "bh1770glc",
+               .owner  = THIS_MODULE,
+               .pm     = &bh1770_pm_ops,
+       },
+       .probe    = bh1770_probe,
+       .remove   = __devexit_p(bh1770_remove),
+       .id_table = bh1770_id,
+};
+
+static int __init bh1770_init(void)
+{
+       return i2c_add_driver(&bh1770_driver);
+}
+
+static void __exit bh1770_exit(void)
+{
+       i2c_del_driver(&bh1770_driver);
+}
+
+MODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor");
+MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
+MODULE_LICENSE("GPL v2");
+
+module_init(bh1770_init);
+module_exit(bh1770_exit);
index af2497ae5fe32be990aabdb6732c44eaaf0591fb..0a53500636c9d3f4c4d1f886d386f1b1b675f95d 100644 (file)
@@ -146,6 +146,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
        struct inode *ret = new_inode(sb);
 
        if (ret) {
+               ret->i_ino = get_next_ino();
                ret->i_mode = mode;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
        }
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
new file mode 100644 (file)
index 0000000..34fe835
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * isl29020.c - Intersil  ALS Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+
+static DEFINE_MUTEX(mutex);
+
+static ssize_t als_sensing_range_show(struct device *dev,
+                       struct device_attribute *attr,  char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int  val;
+
+       val = i2c_smbus_read_byte_data(client, 0x00);
+
+       if (val < 0)
+               return val;
+       return sprintf(buf, "%d000\n", 1 << (2 * (val & 3)));
+
+}
+
+static ssize_t als_lux_input_data_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret_val, val;
+       unsigned long int lux;
+       int temp;
+
+       pm_runtime_get_sync(dev);
+       msleep(100);
+
+       mutex_lock(&mutex);
+       temp = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */
+       if (temp < 0) {
+               pm_runtime_put_sync(dev);
+               mutex_unlock(&mutex);
+               return temp;
+       }
+
+       ret_val = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */
+       mutex_unlock(&mutex);
+
+       if (ret_val < 0) {
+               pm_runtime_put_sync(dev);
+               return ret_val;
+       }
+
+       ret_val |= temp << 8;
+       val = i2c_smbus_read_byte_data(client, 0x00);
+       pm_runtime_put_sync(dev);
+       if (val < 0)
+               return val;
+       lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536;
+       return sprintf(buf, "%ld\n", lux);
+}
+
+static ssize_t als_sensing_range_store(struct device *dev,
+               struct device_attribute *attr, const  char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned int ret_val;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+       if (val < 1 || val > 64000)
+               return -EINVAL;
+
+       /* Pick the smallest sensor range that will meet our requirements */
+       if (val <= 1000)
+               val = 1;
+       else if (val <= 4000)
+               val = 2;
+       else if (val <= 16000)
+               val = 3;
+       else
+               val = 4;
+
+       ret_val = i2c_smbus_read_byte_data(client, 0x00);
+
+       ret_val &= 0xFC; /*reset the bit before setting them */
+       ret_val |= val - 1;
+       ret_val = i2c_smbus_write_byte_data(client, 0x00, ret_val);
+
+       if (ret_val < 0)
+               return ret_val;
+       return count;
+}
+
+static void als_set_power_state(struct i2c_client *client, int enable)
+{
+       int ret_val;
+
+       ret_val = i2c_smbus_read_byte_data(client, 0x00);
+       if (ret_val < 0)
+               return;
+
+       if (enable)
+               ret_val |= 0x80;
+       else
+               ret_val &= 0x7F;
+
+       i2c_smbus_write_byte_data(client, 0x00, ret_val);
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,
+       als_sensing_range_show, als_sensing_range_store);
+static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux_input_data_show, NULL);
+
+static struct attribute *mid_att_als[] = {
+       &dev_attr_lux0_sensor_range.attr,
+       &dev_attr_lux0_input.attr,
+       NULL
+};
+
+static struct attribute_group m_als_gr = {
+       .name = "isl29020",
+       .attrs = mid_att_als
+};
+
+static int als_set_default_config(struct i2c_client *client)
+{
+       int retval;
+
+       retval = i2c_smbus_write_byte_data(client, 0x00, 0xc0);
+       if (retval < 0) {
+               dev_err(&client->dev, "default write failed.");
+               return retval;
+       }
+       return 0;;
+}
+
+static int  isl29020_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       int res;
+
+       res = als_set_default_config(client);
+       if (res <  0)
+               return res;
+
+       res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
+       if (res) {
+               dev_err(&client->dev, "isl29020: device create file failed\n");
+               return res;
+       }
+       dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name);
+       als_set_power_state(client, 0);
+       pm_runtime_enable(&client->dev);
+       return res;
+}
+
+static int isl29020_remove(struct i2c_client *client)
+{
+       struct als_data *data = i2c_get_clientdata(client);
+       sysfs_remove_group(&client->dev.kobj, &m_als_gr);
+       kfree(data);
+       return 0;
+}
+
+static struct i2c_device_id isl29020_id[] = {
+       { "isl29020", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, isl29020_id);
+
+#ifdef CONFIG_PM
+
+static int isl29020_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       als_set_power_state(client, 0);
+       return 0;
+}
+
+static int isl29020_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       als_set_power_state(client, 1);
+       return 0;
+}
+
+static const struct dev_pm_ops isl29020_pm_ops = {
+       .runtime_suspend = isl29020_runtime_suspend,
+       .runtime_resume = isl29020_runtime_resume,
+};
+
+#define ISL29020_PM_OPS (&isl29020_pm_ops)
+#else  /* CONFIG_PM */
+#define ISL29020_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver isl29020_driver = {
+       .driver = {
+               .name = "isl29020",
+               .pm = ISL29020_PM_OPS,
+       },
+       .probe = isl29020_probe,
+       .remove = isl29020_remove,
+       .id_table = isl29020_id,
+};
+
+static int __init sensor_isl29020_init(void)
+{
+       return i2c_add_driver(&isl29020_driver);
+}
+
+static void  __exit sensor_isl29020_exit(void)
+{
+       i2c_del_driver(&isl29020_driver);
+}
+
+module_init(sensor_isl29020_init);
+module_exit(sensor_isl29020_exit);
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
+MODULE_LICENSE("GPL v2");
index 343b5d8ea6971fc07ddbb443b91ddfee6439e31c..81d7fa4ec0db0a284891a31ab280720a19bd32d9 100644 (file)
 #define REC_NUM_DEFAULT 10
 
 enum cname {
-       INVALID,
-       INT_HARDWARE_ENTRY,
-       INT_HW_IRQ_EN,
-       INT_TASKLET_ENTRY,
-       FS_DEVRW,
-       MEM_SWAPOUT,
-       TIMERADD,
-       SCSI_DISPATCH_CMD,
-       IDE_CORE_CP,
-       DIRECT,
+       CN_INVALID,
+       CN_INT_HARDWARE_ENTRY,
+       CN_INT_HW_IRQ_EN,
+       CN_INT_TASKLET_ENTRY,
+       CN_FS_DEVRW,
+       CN_MEM_SWAPOUT,
+       CN_TIMERADD,
+       CN_SCSI_DISPATCH_CMD,
+       CN_IDE_CORE_CP,
+       CN_DIRECT,
 };
 
 enum ctype {
-       NONE,
-       PANIC,
-       BUG,
-       EXCEPTION,
-       LOOP,
-       OVERFLOW,
-       CORRUPT_STACK,
-       UNALIGNED_LOAD_STORE_WRITE,
-       OVERWRITE_ALLOCATION,
-       WRITE_AFTER_FREE,
-       SOFTLOCKUP,
-       HARDLOCKUP,
-       HUNG_TASK,
+       CT_NONE,
+       CT_PANIC,
+       CT_BUG,
+       CT_EXCEPTION,
+       CT_LOOP,
+       CT_OVERFLOW,
+       CT_CORRUPT_STACK,
+       CT_UNALIGNED_LOAD_STORE_WRITE,
+       CT_OVERWRITE_ALLOCATION,
+       CT_WRITE_AFTER_FREE,
+       CT_SOFTLOCKUP,
+       CT_HARDLOCKUP,
+       CT_HUNG_TASK,
 };
 
 static char* cp_name[] = {
@@ -117,8 +117,8 @@ static char* cpoint_type;
 static int cpoint_count = DEFAULT_COUNT;
 static int recur_count = REC_NUM_DEFAULT;
 
-static enum cname cpoint = INVALID;
-static enum ctype cptype = NONE;
+static enum cname cpoint = CN_INVALID;
+static enum ctype cptype = CT_NONE;
 static int count = DEFAULT_COUNT;
 
 module_param(recur_count, int, 0644);
@@ -207,12 +207,12 @@ static enum ctype parse_cp_type(const char *what, size_t count)
                        return i + 1;
        }
 
-       return NONE;
+       return CT_NONE;
 }
 
 static const char *cp_type_to_str(enum ctype type)
 {
-       if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type))
+       if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type))
                return "None";
 
        return cp_type[type - 1];
@@ -220,7 +220,7 @@ static const char *cp_type_to_str(enum ctype type)
 
 static const char *cp_name_to_str(enum cname name)
 {
-       if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
+       if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
                return "INVALID";
 
        return cp_name[name - 1];
@@ -245,7 +245,7 @@ static int lkdtm_parse_commandline(void)
                return -EINVAL;
 
        cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
-       if (cptype == NONE)
+       if (cptype == CT_NONE)
                return -EINVAL;
 
        for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
@@ -274,30 +274,30 @@ static int recursive_loop(int a)
 static void lkdtm_do_action(enum ctype which)
 {
        switch (which) {
-       case PANIC:
+       case CT_PANIC:
                panic("dumptest");
                break;
-       case BUG:
+       case CT_BUG:
                BUG();
                break;
-       case EXCEPTION:
+       case CT_EXCEPTION:
                *((int *) 0) = 0;
                break;
-       case LOOP:
+       case CT_LOOP:
                for (;;)
                        ;
                break;
-       case OVERFLOW:
+       case CT_OVERFLOW:
                (void) recursive_loop(0);
                break;
-       case CORRUPT_STACK: {
+       case CT_CORRUPT_STACK: {
                volatile u32 data[8];
                volatile u32 *p = data;
 
                p[12] = 0x12345678;
                break;
        }
-       case UNALIGNED_LOAD_STORE_WRITE: {
+       case CT_UNALIGNED_LOAD_STORE_WRITE: {
                static u8 data[5] __attribute__((aligned(4))) = {1, 2,
                                3, 4, 5};
                u32 *p;
@@ -309,7 +309,7 @@ static void lkdtm_do_action(enum ctype which)
                *p = val;
                 break;
        }
-       case OVERWRITE_ALLOCATION: {
+       case CT_OVERWRITE_ALLOCATION: {
                size_t len = 1020;
                u32 *data = kmalloc(len, GFP_KERNEL);
 
@@ -317,7 +317,7 @@ static void lkdtm_do_action(enum ctype which)
                kfree(data);
                break;
        }
-       case WRITE_AFTER_FREE: {
+       case CT_WRITE_AFTER_FREE: {
                size_t len = 1024;
                u32 *data = kmalloc(len, GFP_KERNEL);
 
@@ -326,21 +326,21 @@ static void lkdtm_do_action(enum ctype which)
                memset(data, 0x78, len);
                break;
        }
-       case SOFTLOCKUP:
+       case CT_SOFTLOCKUP:
                preempt_disable();
                for (;;)
                        cpu_relax();
                break;
-       case HARDLOCKUP:
+       case CT_HARDLOCKUP:
                local_irq_disable();
                for (;;)
                        cpu_relax();
                break;
-       case HUNG_TASK:
+       case CT_HUNG_TASK:
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule();
                break;
-       case NONE:
+       case CT_NONE:
        default:
                break;
        }
@@ -363,43 +363,43 @@ static int lkdtm_register_cpoint(enum cname which)
 {
        int ret;
 
-       cpoint = INVALID;
+       cpoint = CN_INVALID;
        if (lkdtm.entry != NULL)
                unregister_jprobe(&lkdtm);
 
        switch (which) {
-       case DIRECT:
+       case CN_DIRECT:
                lkdtm_do_action(cptype);
                return 0;
-       case INT_HARDWARE_ENTRY:
+       case CN_INT_HARDWARE_ENTRY:
                lkdtm.kp.symbol_name = "do_IRQ";
                lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
                break;
-       case INT_HW_IRQ_EN:
+       case CN_INT_HW_IRQ_EN:
                lkdtm.kp.symbol_name = "handle_IRQ_event";
                lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
                break;
-       case INT_TASKLET_ENTRY:
+       case CN_INT_TASKLET_ENTRY:
                lkdtm.kp.symbol_name = "tasklet_action";
                lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
                break;
-       case FS_DEVRW:
+       case CN_FS_DEVRW:
                lkdtm.kp.symbol_name = "ll_rw_block";
                lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
                break;
-       case MEM_SWAPOUT:
+       case CN_MEM_SWAPOUT:
                lkdtm.kp.symbol_name = "shrink_inactive_list";
                lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
                break;
-       case TIMERADD:
+       case CN_TIMERADD:
                lkdtm.kp.symbol_name = "hrtimer_start";
                lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
                break;
-       case SCSI_DISPATCH_CMD:
+       case CN_SCSI_DISPATCH_CMD:
                lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
                lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
                break;
-       case IDE_CORE_CP:
+       case CN_IDE_CORE_CP:
 #ifdef CONFIG_IDE
                lkdtm.kp.symbol_name = "generic_ide_ioctl";
                lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
@@ -416,7 +416,7 @@ static int lkdtm_register_cpoint(enum cname which)
        cpoint = which;
        if ((ret = register_jprobe(&lkdtm)) < 0) {
                printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
-               cpoint = INVALID;
+               cpoint = CN_INVALID;
        }
 
        return ret;
@@ -445,7 +445,7 @@ static ssize_t do_register_entry(enum cname which, struct file *f,
        cptype = parse_cp_type(buf, count);
        free_page((unsigned long) buf);
 
-       if (cptype == NONE)
+       if (cptype == CT_NONE)
                return -EINVAL;
 
        err = lkdtm_register_cpoint(which);
@@ -487,49 +487,49 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
 static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off);
+       return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off);
 }
 
 static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off);
+       return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off);
 }
 
 static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off);
+       return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off);
 }
 
 static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(FS_DEVRW, f, buf, count, off);
+       return do_register_entry(CN_FS_DEVRW, f, buf, count, off);
 }
 
 static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(MEM_SWAPOUT, f, buf, count, off);
+       return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off);
 }
 
 static ssize_t timeradd_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(TIMERADD, f, buf, count, off);
+       return do_register_entry(CN_TIMERADD, f, buf, count, off);
 }
 
 static ssize_t scsi_dispatch_cmd_entry(struct file *f,
                const char __user *buf, size_t count, loff_t *off)
 {
-       return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off);
+       return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off);
 }
 
 static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(IDE_CORE_CP, f, buf, count, off);
+       return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off);
 }
 
 /* Special entry to just crash directly. Available without KPROBEs */
@@ -557,7 +557,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
 
        type = parse_cp_type(buf, count);
        free_page((unsigned long) buf);
-       if (type == NONE)
+       if (type == CT_NONE)
                return -EINVAL;
 
        printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
@@ -649,7 +649,7 @@ static int __init lkdtm_module_init(void)
                goto out_err;
        }
 
-       if (cpoint != INVALID && cptype != NONE) {
+       if (cpoint != CN_INVALID && cptype != CT_NONE) {
                ret = lkdtm_register_cpoint(cpoint);
                if (ret < 0) {
                        printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
index 4197a3cb26ba42d674ef7d0935207adee0d70be1..b05db55c8c8e757c312184c797321942d814ec55 100644 (file)
@@ -343,8 +343,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
        int retval;
 
        retval = pci_enable_device(pdev);
-       if (retval)
+       if (retval) {
+               dev_err(&pdev->dev, "pci_enable_device failed!\n");
                goto err;
+       }
 
        minor = phantom_get_free();
        if (minor == PHANTOM_MAX_MINORS) {
@@ -356,8 +358,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
        phantom_devices[minor] = 1;
 
        retval = pci_request_regions(pdev, "phantom");
-       if (retval)
+       if (retval) {
+               dev_err(&pdev->dev, "pci_request_regions failed!\n");
                goto err_null;
+       }
 
        retval = -ENOMEM;
        pht = kzalloc(sizeof(*pht), GFP_KERNEL);
index 1f59ee2226ca4220e470842326ec64fba62377a2..17bbacb1b4b131b119b0076b339f44012fcc51f7 100644 (file)
@@ -417,6 +417,7 @@ xpc_process_activate_IRQ_rcvd_uv(void)
 static void
 xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
                              struct xpc_activate_mq_msghdr_uv *msg_hdr,
+                             int part_setup,
                              int *wakeup_hb_checker)
 {
        unsigned long irq_flags;
@@ -481,6 +482,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
        case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
                struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;
 
+               if (!part_setup)
+                       break;
+
                msg = container_of(msg_hdr, struct
                                   xpc_activate_mq_msg_chctl_closerequest_uv,
                                   hdr);
@@ -497,6 +501,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
        case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
                struct xpc_activate_mq_msg_chctl_closereply_uv *msg;
 
+               if (!part_setup)
+                       break;
+
                msg = container_of(msg_hdr, struct
                                   xpc_activate_mq_msg_chctl_closereply_uv,
                                   hdr);
@@ -511,6 +518,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
        case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
                struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;
 
+               if (!part_setup)
+                       break;
+
                msg = container_of(msg_hdr, struct
                                   xpc_activate_mq_msg_chctl_openrequest_uv,
                                   hdr);
@@ -528,6 +538,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
        case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
                struct xpc_activate_mq_msg_chctl_openreply_uv *msg;
 
+               if (!part_setup)
+                       break;
+
                msg = container_of(msg_hdr, struct
                                   xpc_activate_mq_msg_chctl_openreply_uv, hdr);
                args = &part->remote_openclose_args[msg->ch_number];
@@ -545,6 +558,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
        case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: {
                struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg;
 
+               if (!part_setup)
+                       break;
+
                msg = container_of(msg_hdr, struct
                                xpc_activate_mq_msg_chctl_opencomplete_uv, hdr);
                spin_lock_irqsave(&part->chctl_lock, irq_flags);
@@ -621,6 +637,7 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
 
                        part_referenced = xpc_part_ref(part);
                        xpc_handle_activate_mq_msg_uv(part, msg_hdr,
+                                                     part_referenced,
                                                      &wakeup_hb_checker);
                        if (part_referenced)
                                xpc_part_deref(part);
index 68d12794cfd9b16af4ca4a1f98f57649cdcdc1e3..1a0261160e5600dafdf42127029523bc303e5922 100644 (file)
@@ -237,7 +237,7 @@ endchoice
 
 config MMC_ATMELMCI_DMA
        bool "Atmel MCI DMA support (EXPERIMENTAL)"
-       depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
+       depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE && EXPERIMENTAL
        help
          Say Y here to have the Atmel MCI driver use a DMA engine to
          do data transfers and thus increase the throughput and
index 4526d2791f2990229acbe9ef0f5c88286819807f..4693e62145a6797f2a67415495c9c7e953ec8e66 100644 (file)
@@ -364,6 +364,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 {
        struct regulator *reg;
        int ret = 0;
+       int ocr_value = 0;
 
        switch (host->id) {
        case OMAP_MMC1_DEVID:
@@ -396,6 +397,17 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
                }
        } else {
                host->vcc = reg;
+               ocr_value = mmc_regulator_get_ocrmask(reg);
+               if (!mmc_slot(host).ocr_mask) {
+                       mmc_slot(host).ocr_mask = ocr_value;
+               } else {
+                       if (!(mmc_slot(host).ocr_mask & ocr_value)) {
+                               pr_err("MMC%d ocrmask %x is not supported\n",
+                                       host->id, mmc_slot(host).ocr_mask);
+                               mmc_slot(host).ocr_mask = 0;
+                               return -EINVAL;
+                       }
+               }
                mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg);
 
                /* Allow an aux regulator */
@@ -982,6 +994,17 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
        OMAP_HSMMC_WRITE(host->base, SYSCTL,
                         OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
 
+       /*
+        * OMAP4 ES2 and greater has an updated reset logic.
+        * Monitor a 0->1 transition first
+        */
+       if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
+               while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit))
+                                       && (i++ < limit))
+                       cpu_relax();
+       }
+       i = 0;
+
        while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
                (i++ < limit))
                cpu_relax();
@@ -2003,6 +2026,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        if (res == NULL || irq < 0)
                return -ENXIO;
 
+       res->start += pdata->reg_offset;
+       res->end += pdata->reg_offset;
        res = request_mem_region(res->start, res->end - res->start + 1,
                                                        pdev->name);
        if (res == NULL)
@@ -2116,23 +2141,9 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
                     MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
 
-       switch (mmc_slot(host).wires) {
-       case 8:
-               mmc->caps |= MMC_CAP_8_BIT_DATA;
-               /* Fall through */
-       case 4:
+       mmc->caps |= mmc_slot(host).caps;
+       if (mmc->caps & MMC_CAP_8_BIT_DATA)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
-               break;
-       case 1:
-               /* Nothing to crib here */
-       case 0:
-               /* Assuming nothing was given by board, Core use's 1-Bit */
-               break;
-       default:
-               /* Completely unexpected.. Core goes with 1-Bit Width */
-               dev_crit(mmc_dev(host->mmc), "Invalid width %d\n used!"
-                       "using 1 instead\n", mmc_slot(host).wires);
-       }
 
        if (mmc_slot(host).nonremovable)
                mmc->caps |= MMC_CAP_NONREMOVABLE;
index 6f512b5c117b54ef0dddbe647cdfd53a52100541..ea22520c0406ed6a7c7a3537ee7ce64adf558481 100644 (file)
@@ -924,6 +924,13 @@ static int __devinit m25p_probe(struct spi_device *spi)
                        nr_parts = data->nr_parts;
                }
 
+#ifdef CONFIG_OF
+               if (nr_parts <= 0 && spi->dev.of_node) {
+                       nr_parts = of_mtd_parse_partitions(&spi->dev,
+                                       spi->dev.of_node, &parts);
+               }
+#endif
+
                if (nr_parts > 0) {
                        for (i = 0; i < nr_parts; i++) {
                                DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
index fe63f6bd663c1f7a5ac8db57a0014c1c4a019da0..ec3edf6e68b46175cd10ccff2e6d3dd3f72b8fd8 100644 (file)
@@ -294,7 +294,7 @@ static int __devinit of_flash_probe(struct platform_device *dev,
                info->list[i].map.name = dev_name(&dev->dev);
                info->list[i].map.phys = res.start;
                info->list[i].map.size = res_size;
-               info->list[i].map.bankwidth = *width;
+               info->list[i].map.bankwidth = be32_to_cpup(width);
 
                err = -ENOMEM;
                info->list[i].map.virt = ioremap(info->list[i].map.phys,
index 2ac7367afe77c26c2a209469218c928db3f6140c..8beb0d0233b52bef86ed7f28060e051f5afed039 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 
 #include <mach/nand.h>
+#include <mach/aemif.h>
 
 #include <asm/mach-types.h>
 
@@ -74,6 +75,8 @@ struct davinci_nand_info {
        uint32_t                mask_cle;
 
        uint32_t                core_chipsel;
+
+       struct davinci_aemif_timing     *timing;
 };
 
 static DEFINE_SPINLOCK(davinci_nand_lock);
@@ -478,36 +481,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
        return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
 }
 
-static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info)
-{
-       uint32_t regval, a1cr;
-
-       /*
-        * NAND FLASH timings @ PLL1 == 459 MHz
-        *  - AEMIF.CLK freq   = PLL1/6 = 459/6 = 76.5 MHz
-        *  - AEMIF.CLK period = 1/76.5 MHz = 13.1 ns
-        */
-       regval = 0
-               | (0 << 31)           /* selectStrobe */
-               | (0 << 30)           /* extWait (never with NAND) */
-               | (1 << 26)           /* writeSetup      10 ns */
-               | (3 << 20)           /* writeStrobe     40 ns */
-               | (1 << 17)           /* writeHold       10 ns */
-               | (0 << 13)           /* readSetup       10 ns */
-               | (3 << 7)            /* readStrobe      60 ns */
-               | (0 << 4)            /* readHold        10 ns */
-               | (3 << 2)            /* turnAround      ?? ns */
-               | (0 << 0)            /* asyncSize       8-bit bus */
-               ;
-       a1cr = davinci_nand_readl(info, A1CR_OFFSET);
-       if (a1cr != regval) {
-               dev_dbg(info->dev, "Warning: NAND config: Set A1CR " \
-                      "reg to 0x%08x, was 0x%08x, should be done by " \
-                      "bootloader.\n", regval, a1cr);
-               davinci_nand_writel(info, A1CR_OFFSET, regval);
-       }
-}
-
 /*----------------------------------------------------------------------*/
 
 /* An ECC layout for using 4-bit ECC with small-page flash, storing
@@ -611,6 +584,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        info->chip.options      = pdata->options;
        info->chip.bbt_td       = pdata->bbt_td;
        info->chip.bbt_md       = pdata->bbt_md;
+       info->timing            = pdata->timing;
 
        info->ioaddr            = (uint32_t __force) vaddr;
 
@@ -688,15 +662,25 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                goto err_clk_enable;
        }
 
-       /* EMIF timings should normally be set by the boot loader,
-        * especially after boot-from-NAND.  The *only* reason to
-        * have this special casing for the DM6446 EVM is to work
-        * with boot-from-NOR ... with CS0 manually re-jumpered
-        * (after startup) so it addresses the NAND flash, not NOR.
-        * Even for dev boards, that's unusually rude...
+       /*
+        * Setup Async configuration register in case we did not boot from
+        * NAND and so bootloader did not bother to set it up.
         */
-       if (machine_is_davinci_evm())
-               nand_dm6446evm_flash_init(info);
+       val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4);
+
+       /* Extended Wait is not valid and Select Strobe mode is not used */
+       val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK);
+       if (info->chip.options & NAND_BUSWIDTH_16)
+               val |= 0x1;
+
+       davinci_nand_writel(info, A1CR_OFFSET + info->core_chipsel * 4, val);
+
+       ret = davinci_aemif_setup_timing(info->timing, info->base,
+                                                       info->core_chipsel);
+       if (ret < 0) {
+               dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
+               goto err_timing;
+       }
 
        spin_lock_irq(&davinci_nand_lock);
 
@@ -809,6 +793,7 @@ syndrome_done:
        return 0;
 
 err_scan:
+err_timing:
        clk_disable(info->clk);
 
 err_clk_enable:
index 8bf7dc6d1ce6a452d9ad62185a6b77beab654db9..7bd171eefd216071cc06a2ba4d844013003dd53d 100644 (file)
@@ -53,8 +53,8 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
                        continue;
                }
 
-               (*pparts)[i].offset = reg[0];
-               (*pparts)[i].size = reg[1];
+               (*pparts)[i].offset = be32_to_cpu(reg[0]);
+               (*pparts)[i].size = be32_to_cpu(reg[1]);
 
                partname = of_get_property(pp, "label", &len);
                if (!partname)
index 77c1fab7d774d67e13f4befb797288967cb1699b..86fe67fd49ba0c1dd8d794de61839766c2efacb5 100644 (file)
@@ -883,14 +883,6 @@ config BFIN_RX_DESC_NUM
        help
          Set the number of buffer packets used in driver.
 
-config BFIN_MAC_RMII
-       bool "RMII PHY Interface"
-       depends on BFIN_MAC
-       default y if BFIN527_EZKIT
-       default n if BFIN537_STAMP
-       help
-         Use Reduced PHY MII Interface
-
 config BFIN_MAC_USE_HWSTAMP
        bool "Use IEEE 1588 hwstamp"
        depends on BFIN_MAC && BF518
@@ -954,6 +946,8 @@ config NET_NETX
 config TI_DAVINCI_EMAC
        tristate "TI DaVinci EMAC Support"
        depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+       select TI_DAVINCI_MDIO
+       select TI_DAVINCI_CPDMA
        select PHYLIB
        help
          This driver supports TI's DaVinci Ethernet .
@@ -961,6 +955,25 @@ config TI_DAVINCI_EMAC
          To compile this driver as a module, choose M here: the module
          will be called davinci_emac_driver.  This is recommended.
 
+config TI_DAVINCI_MDIO
+       tristate "TI DaVinci MDIO Support"
+       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+       select PHYLIB
+       help
+         This driver supports TI's DaVinci MDIO module.
+
+         To compile this driver as a module, choose M here: the module
+         will be called davinci_mdio.  This is recommended.
+
+config TI_DAVINCI_CPDMA
+       tristate "TI DaVinci CPDMA Support"
+       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+       help
+         This driver supports TI's DaVinci CPDMA dma engine.
+
+         To compile this driver as a module, choose M here: the module
+         will be called davinci_cpdma.  This is recommended.
+
 config DM9000
        tristate "DM9000 support"
        depends on ARM || BLACKFIN || MIPS
index b8bf93d4a132d2f28b2487f6986530b14edbfa9d..652fc6b98039431832aaceda6f1b4a637720c126 100644 (file)
@@ -7,6 +7,8 @@ obj-$(CONFIG_MDIO) += mdio.o
 obj-$(CONFIG_PHYLIB) += phy/
 
 obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
+obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
+obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
 
 obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_E1000E) += e1000e/
index f7233191162b93297ceaaad8525a893c8010aab7..ce1e5e9d06f6d83a8bfd0ad5239c3eedb626be8c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip MAC Driver
  *
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -23,7 +23,6 @@
 #include <linux/device.h>
 #include <linux/spinlock.h>
 #include <linux/mii.h>
-#include <linux/phy.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -76,12 +75,6 @@ static struct net_dma_desc_tx *current_tx_ptr;
 static struct net_dma_desc_tx *tx_desc;
 static struct net_dma_desc_rx *rx_desc;
 
-#if defined(CONFIG_BFIN_MAC_RMII)
-static u16 pin_req[] = P_RMII0;
-#else
-static u16 pin_req[] = P_MII0;
-#endif
-
 static void desc_list_free(void)
 {
        struct net_dma_desc_rx *r;
@@ -347,23 +340,23 @@ static void bfin_mac_adjust_link(struct net_device *dev)
                }
 
                if (phydev->speed != lp->old_speed) {
-#if defined(CONFIG_BFIN_MAC_RMII)
-                       u32 opmode = bfin_read_EMAC_OPMODE();
-                       switch (phydev->speed) {
-                       case 10:
-                               opmode |= RMII_10;
-                               break;
-                       case 100:
-                               opmode &= ~(RMII_10);
-                               break;
-                       default:
-                               printk(KERN_WARNING
-                                       "%s: Ack!  Speed (%d) is not 10/100!\n",
-                                       DRV_NAME, phydev->speed);
-                               break;
+                       if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+                               u32 opmode = bfin_read_EMAC_OPMODE();
+                               switch (phydev->speed) {
+                               case 10:
+                                       opmode |= RMII_10;
+                                       break;
+                               case 100:
+                                       opmode &= ~RMII_10;
+                                       break;
+                               default:
+                                       printk(KERN_WARNING
+                                               "%s: Ack!  Speed (%d) is not 10/100!\n",
+                                               DRV_NAME, phydev->speed);
+                                       break;
+                               }
+                               bfin_write_EMAC_OPMODE(opmode);
                        }
-                       bfin_write_EMAC_OPMODE(opmode);
-#endif
 
                        new_state = 1;
                        lp->old_speed = phydev->speed;
@@ -392,7 +385,7 @@ static void bfin_mac_adjust_link(struct net_device *dev)
 /* MDC  = 2.5 MHz */
 #define MDC_CLK 2500000
 
-static int mii_probe(struct net_device *dev)
+static int mii_probe(struct net_device *dev, int phy_mode)
 {
        struct bfin_mac_local *lp = netdev_priv(dev);
        struct phy_device *phydev = NULL;
@@ -411,8 +404,8 @@ static int mii_probe(struct net_device *dev)
        sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div);
        bfin_write_EMAC_SYSCTL(sysctl);
 
-       /* search for connect PHY device */
-       for (i = 0; i < PHY_MAX_ADDR; i++) {
+       /* search for connected PHY device */
+       for (i = 0; i < PHY_MAX_ADDR; ++i) {
                struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
 
                if (!tmp_phydev)
@@ -429,13 +422,14 @@ static int mii_probe(struct net_device *dev)
                return -ENODEV;
        }
 
-#if defined(CONFIG_BFIN_MAC_RMII)
-       phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
-                       0, PHY_INTERFACE_MODE_RMII);
-#else
+       if (phy_mode != PHY_INTERFACE_MODE_RMII &&
+               phy_mode != PHY_INTERFACE_MODE_MII) {
+               printk(KERN_INFO "%s: Invalid phy interface mode\n", dev->name);
+               return -EINVAL;
+       }
+
        phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
-                       0, PHY_INTERFACE_MODE_MII);
-#endif
+                       0, phy_mode);
 
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
@@ -570,6 +564,8 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
 /**************************************************************************/
 void setup_system_regs(struct net_device *dev)
 {
+       struct bfin_mac_local *lp = netdev_priv(dev);
+       int i;
        unsigned short sysctl;
 
        /*
@@ -577,6 +573,15 @@ void setup_system_regs(struct net_device *dev)
         * Configure checksum support and rcve frame word alignment
         */
        sysctl = bfin_read_EMAC_SYSCTL();
+       /*
+        * check if interrupt is requested for any PHY,
+        * enable PHY interrupt only if needed
+        */
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               if (lp->mii_bus->irq[i] != PHY_POLL)
+                       break;
+       if (i < PHY_MAX_ADDR)
+               sysctl |= PHYIE;
        sysctl |= RXDWA;
 #if defined(BFIN_MAC_CSUM_OFFLOAD)
        sysctl |= RXCKS;
@@ -1203,7 +1208,7 @@ static void bfin_mac_disable(void)
 /*
  * Enable Interrupts, Receive, and Transmit
  */
-static int bfin_mac_enable(void)
+static int bfin_mac_enable(struct phy_device *phydev)
 {
        int ret;
        u32 opmode;
@@ -1233,12 +1238,13 @@ static int bfin_mac_enable(void)
                opmode |= DRO | DC | PSF;
        opmode |= RE;
 
-#if defined(CONFIG_BFIN_MAC_RMII)
-       opmode |= RMII; /* For Now only 100MBit are supported */
+       if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+               opmode |= RMII; /* For Now only 100MBit are supported */
 #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2
-       opmode |= TE;
-#endif
+               opmode |= TE;
 #endif
+       }
+
        /* Turn on the EMAC rx */
        bfin_write_EMAC_OPMODE(opmode);
 
@@ -1270,7 +1276,7 @@ static void bfin_mac_timeout(struct net_device *dev)
        if (netif_queue_stopped(lp->ndev))
                netif_wake_queue(lp->ndev);
 
-       bfin_mac_enable();
+       bfin_mac_enable(lp->phydev);
 
        /* We can accept TX packets again */
        dev->trans_start = jiffies; /* prevent tx timeout */
@@ -1342,11 +1348,19 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
 
 static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
+       struct bfin_mac_local *lp = netdev_priv(netdev);
+
+       if (!netif_running(netdev))
+               return -EINVAL;
+
        switch (cmd) {
        case SIOCSHWTSTAMP:
                return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd);
        default:
-               return -EOPNOTSUPP;
+               if (lp->phydev)
+                       return phy_mii_ioctl(lp->phydev, ifr, cmd);
+               else
+                       return -EOPNOTSUPP;
        }
 }
 
@@ -1394,7 +1408,7 @@ static int bfin_mac_open(struct net_device *dev)
        setup_mac_addr(dev->dev_addr);
 
        bfin_mac_disable();
-       ret = bfin_mac_enable();
+       ret = bfin_mac_enable(lp->phydev);
        if (ret)
                return ret;
        pr_debug("hardware init finished\n");
@@ -1450,6 +1464,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct bfin_mac_local *lp;
        struct platform_device *pd;
+       struct bfin_mii_bus_platform_data *mii_bus_data;
        int rc;
 
        ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
@@ -1501,11 +1516,12 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
        if (!lp->mii_bus) {
                dev_err(&pdev->dev, "Cannot get mii_bus!\n");
                rc = -ENODEV;
-               goto out_err_mii_bus_probe;
+               goto out_err_probe_mac;
        }
        lp->mii_bus->priv = ndev;
+       mii_bus_data = pd->dev.platform_data;
 
-       rc = mii_probe(ndev);
+       rc = mii_probe(ndev, mii_bus_data->phy_mode);
        if (rc) {
                dev_err(&pdev->dev, "MII Probe failed!\n");
                goto out_err_mii_probe;
@@ -1552,8 +1568,6 @@ out_err_request_irq:
 out_err_mii_probe:
        mdiobus_unregister(lp->mii_bus);
        mdiobus_free(lp->mii_bus);
-out_err_mii_bus_probe:
-       peripheral_free_list(pin_req);
 out_err_probe_mac:
        platform_set_drvdata(pdev, NULL);
        free_netdev(ndev);
@@ -1576,8 +1590,6 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
 
        free_netdev(ndev);
 
-       peripheral_free_list(pin_req);
-
        return 0;
 }
 
@@ -1623,12 +1635,21 @@ static int bfin_mac_resume(struct platform_device *pdev)
 static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
 {
        struct mii_bus *miibus;
+       struct bfin_mii_bus_platform_data *mii_bus_pd;
+       const unsigned short *pin_req;
        int rc, i;
 
+       mii_bus_pd = dev_get_platdata(&pdev->dev);
+       if (!mii_bus_pd) {
+               dev_err(&pdev->dev, "No peripherals in platform data!\n");
+               return -EINVAL;
+       }
+
        /*
         * We are setting up a network card,
         * so set the GPIO pins to Ethernet mode
         */
+       pin_req = mii_bus_pd->mac_peripherals;
        rc = peripheral_request_list(pin_req, DRV_NAME);
        if (rc) {
                dev_err(&pdev->dev, "Requesting peripherals failed!\n");
@@ -1645,13 +1666,30 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
 
        miibus->parent = &pdev->dev;
        miibus->name = "bfin_mii_bus";
+       miibus->phy_mask = mii_bus_pd->phy_mask;
+
        snprintf(miibus->id, MII_BUS_ID_SIZE, "0");
        miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-       if (miibus->irq == NULL)
-               goto out_err_alloc;
-       for (i = 0; i < PHY_MAX_ADDR; ++i)
+       if (!miibus->irq)
+               goto out_err_irq_alloc;
+
+       for (i = rc; i < PHY_MAX_ADDR; ++i)
                miibus->irq[i] = PHY_POLL;
 
+       rc = clamp(mii_bus_pd->phydev_number, 0, PHY_MAX_ADDR);
+       if (rc != mii_bus_pd->phydev_number)
+               dev_err(&pdev->dev, "Invalid number (%i) of phydevs\n",
+                       mii_bus_pd->phydev_number);
+       for (i = 0; i < rc; ++i) {
+               unsigned short phyaddr = mii_bus_pd->phydev_data[i].addr;
+               if (phyaddr < PHY_MAX_ADDR)
+                       miibus->irq[phyaddr] = mii_bus_pd->phydev_data[i].irq;
+               else
+                       dev_err(&pdev->dev,
+                               "Invalid PHY address %i for phydev %i\n",
+                               phyaddr, i);
+       }
+
        rc = mdiobus_register(miibus);
        if (rc) {
                dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
@@ -1663,6 +1701,7 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
 
 out_err_mdiobus_register:
        kfree(miibus->irq);
+out_err_irq_alloc:
        mdiobus_free(miibus);
 out_err_alloc:
        peripheral_free_list(pin_req);
@@ -1673,11 +1712,15 @@ out_err_alloc:
 static int __devexit bfin_mii_bus_remove(struct platform_device *pdev)
 {
        struct mii_bus *miibus = platform_get_drvdata(pdev);
+       struct bfin_mii_bus_platform_data *mii_bus_pd =
+               dev_get_platdata(&pdev->dev);
+
        platform_set_drvdata(pdev, NULL);
        mdiobus_unregister(miibus);
        kfree(miibus->irq);
        mdiobus_free(miibus);
-       peripheral_free_list(pin_req);
+       peripheral_free_list(mii_bus_pd->mac_peripherals);
+
        return 0;
 }
 
index 04e4050df18b91fca21cf39880b654422f848b12..aed68bed2365827aad8e38235fec216d57775db2 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/clocksource.h>
 #include <linux/timecompare.h>
 #include <linux/timer.h>
+#include <linux/etherdevice.h>
+#include <linux/bfin_mac.h>
 
 #define BFIN_MAC_CSUM_OFFLOAD
 
diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/davinci_cpdma.c
new file mode 100644 (file)
index 0000000..e92b2b6
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ * Texas Instruments CPDMA Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include "davinci_cpdma.h"
+
+/* DMA Registers */
+#define CPDMA_TXIDVER          0x00
+#define CPDMA_TXCONTROL                0x04
+#define CPDMA_TXTEARDOWN       0x08
+#define CPDMA_RXIDVER          0x10
+#define CPDMA_RXCONTROL                0x14
+#define CPDMA_SOFTRESET                0x1c
+#define CPDMA_RXTEARDOWN       0x18
+#define CPDMA_TXINTSTATRAW     0x80
+#define CPDMA_TXINTSTATMASKED  0x84
+#define CPDMA_TXINTMASKSET     0x88
+#define CPDMA_TXINTMASKCLEAR   0x8c
+#define CPDMA_MACINVECTOR      0x90
+#define CPDMA_MACEOIVECTOR     0x94
+#define CPDMA_RXINTSTATRAW     0xa0
+#define CPDMA_RXINTSTATMASKED  0xa4
+#define CPDMA_RXINTMASKSET     0xa8
+#define CPDMA_RXINTMASKCLEAR   0xac
+#define CPDMA_DMAINTSTATRAW    0xb0
+#define CPDMA_DMAINTSTATMASKED 0xb4
+#define CPDMA_DMAINTMASKSET    0xb8
+#define CPDMA_DMAINTMASKCLEAR  0xbc
+#define CPDMA_DMAINT_HOSTERR   BIT(1)
+
+/* the following exist only if has_ext_regs is set */
+#define CPDMA_DMACONTROL       0x20
+#define CPDMA_DMASTATUS                0x24
+#define CPDMA_RXBUFFOFS                0x28
+#define CPDMA_EM_CONTROL       0x2c
+
+/* Descriptor mode bits */
+#define CPDMA_DESC_SOP         BIT(31)
+#define CPDMA_DESC_EOP         BIT(30)
+#define CPDMA_DESC_OWNER       BIT(29)
+#define CPDMA_DESC_EOQ         BIT(28)
+#define CPDMA_DESC_TD_COMPLETE BIT(27)
+#define CPDMA_DESC_PASS_CRC    BIT(26)
+
+#define CPDMA_TEARDOWN_VALUE   0xfffffffc
+
+struct cpdma_desc {
+       /* hardware fields */
+       u32                     hw_next;
+       u32                     hw_buffer;
+       u32                     hw_len;
+       u32                     hw_mode;
+       /* software fields */
+       void                    *sw_token;
+       u32                     sw_buffer;
+       u32                     sw_len;
+};
+
+struct cpdma_desc_pool {
+       u32                     phys;
+       void __iomem            *iomap;         /* ioremap map */
+       void                    *cpumap;        /* dma_alloc map */
+       int                     desc_size, mem_size;
+       int                     num_desc, used_desc;
+       unsigned long           *bitmap;
+       struct device           *dev;
+       spinlock_t              lock;
+};
+
+enum cpdma_state {
+       CPDMA_STATE_IDLE,
+       CPDMA_STATE_ACTIVE,
+       CPDMA_STATE_TEARDOWN,
+};
+
+const char *cpdma_state_str[] = { "idle", "active", "teardown" };
+
+struct cpdma_ctlr {
+       enum cpdma_state        state;
+       struct cpdma_params     params;
+       struct device           *dev;
+       struct cpdma_desc_pool  *pool;
+       spinlock_t              lock;
+       struct cpdma_chan       *channels[2 * CPDMA_MAX_CHANNELS];
+};
+
+struct cpdma_chan {
+       enum cpdma_state                state;
+       struct cpdma_ctlr               *ctlr;
+       int                             chan_num;
+       spinlock_t                      lock;
+       struct cpdma_desc __iomem       *head, *tail;
+       int                             count;
+       void __iomem                    *hdp, *cp, *rxfree;
+       u32                             mask;
+       cpdma_handler_fn                handler;
+       enum dma_data_direction         dir;
+       struct cpdma_chan_stats         stats;
+       /* offsets into dmaregs */
+       int     int_set, int_clear, td;
+};
+
+/* The following make access to common cpdma_ctlr params more readable */
+#define dmaregs                params.dmaregs
+#define num_chan       params.num_chan
+
+/* various accessors */
+#define dma_reg_read(ctlr, ofs)                __raw_readl((ctlr)->dmaregs + (ofs))
+#define chan_read(chan, fld)           __raw_readl((chan)->fld)
+#define desc_read(desc, fld)           __raw_readl(&(desc)->fld)
+#define dma_reg_write(ctlr, ofs, v)    __raw_writel(v, (ctlr)->dmaregs + (ofs))
+#define chan_write(chan, fld, v)       __raw_writel(v, (chan)->fld)
+#define desc_write(desc, fld, v)       __raw_writel((u32)(v), &(desc)->fld)
+
+/*
+ * Utility constructs for a cpdma descriptor pool.  Some devices (e.g. davinci
+ * emac) have dedicated on-chip memory for these descriptors.  Some other
+ * devices (e.g. cpsw switches) use plain old memory.  Descriptor pools
+ * abstract out these details
+ */
+static struct cpdma_desc_pool *
+cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align)
+{
+       int bitmap_size;
+       struct cpdma_desc_pool *pool;
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool)
+               return NULL;
+
+       spin_lock_init(&pool->lock);
+
+       pool->dev       = dev;
+       pool->mem_size  = size;
+       pool->desc_size = ALIGN(sizeof(struct cpdma_desc), align);
+       pool->num_desc  = size / pool->desc_size;
+
+       bitmap_size  = (pool->num_desc / BITS_PER_LONG) * sizeof(long);
+       pool->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!pool->bitmap)
+               goto fail;
+
+       if (phys) {
+               pool->phys  = phys;
+               pool->iomap = ioremap(phys, size);
+       } else {
+               pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys,
+                                                 GFP_KERNEL);
+               pool->iomap = (void __force __iomem *)pool->cpumap;
+       }
+
+       if (pool->iomap)
+               return pool;
+
+fail:
+       kfree(pool->bitmap);
+       kfree(pool);
+       return NULL;
+}
+
+static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)
+{
+       unsigned long flags;
+
+       if (!pool)
+               return;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       WARN_ON(pool->used_desc);
+       kfree(pool->bitmap);
+       if (pool->cpumap) {
+               dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap,
+                                 pool->phys);
+       } else {
+               iounmap(pool->iomap);
+       }
+       spin_unlock_irqrestore(&pool->lock, flags);
+       kfree(pool);
+}
+
+static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool,
+                 struct cpdma_desc __iomem *desc)
+{
+       if (!desc)
+               return 0;
+       return pool->phys + (__force dma_addr_t)desc -
+                           (__force dma_addr_t)pool->iomap;
+}
+
+static inline struct cpdma_desc __iomem *
+desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
+{
+       return dma ? pool->iomap + dma - pool->phys : NULL;
+}
+
+static struct cpdma_desc __iomem *
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
+{
+       unsigned long flags;
+       int index;
+       struct cpdma_desc __iomem *desc = NULL;
+
+       spin_lock_irqsave(&pool->lock, flags);
+
+       index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
+                                          num_desc, 0);
+       if (index < pool->num_desc) {
+               bitmap_set(pool->bitmap, index, num_desc);
+               desc = pool->iomap + pool->desc_size * index;
+               pool->used_desc++;
+       }
+
+       spin_unlock_irqrestore(&pool->lock, flags);
+       return desc;
+}
+
+static void cpdma_desc_free(struct cpdma_desc_pool *pool,
+                           struct cpdma_desc __iomem *desc, int num_desc)
+{
+       unsigned long flags, index;
+
+       index = ((unsigned long)desc - (unsigned long)pool->iomap) /
+               pool->desc_size;
+       spin_lock_irqsave(&pool->lock, flags);
+       bitmap_clear(pool->bitmap, index, num_desc);
+       pool->used_desc--;
+       spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
+{
+       struct cpdma_ctlr *ctlr;
+
+       ctlr = kzalloc(sizeof(*ctlr), GFP_KERNEL);
+       if (!ctlr)
+               return NULL;
+
+       ctlr->state = CPDMA_STATE_IDLE;
+       ctlr->params = *params;
+       ctlr->dev = params->dev;
+       spin_lock_init(&ctlr->lock);
+
+       ctlr->pool = cpdma_desc_pool_create(ctlr->dev,
+                                           ctlr->params.desc_mem_phys,
+                                           ctlr->params.desc_mem_size,
+                                           ctlr->params.desc_align);
+       if (!ctlr->pool) {
+               kfree(ctlr);
+               return NULL;
+       }
+
+       if (WARN_ON(ctlr->num_chan > CPDMA_MAX_CHANNELS))
+               ctlr->num_chan = CPDMA_MAX_CHANNELS;
+       return ctlr;
+}
+
+int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       if (ctlr->state != CPDMA_STATE_IDLE) {
+               spin_unlock_irqrestore(&ctlr->lock, flags);
+               return -EBUSY;
+       }
+
+       if (ctlr->params.has_soft_reset) {
+               unsigned long timeout = jiffies + HZ/10;
+
+               dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
+               while (time_before(jiffies, timeout)) {
+                       if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
+                               break;
+               }
+               WARN_ON(!time_before(jiffies, timeout));
+       }
+
+       for (i = 0; i < ctlr->num_chan; i++) {
+               __raw_writel(0, ctlr->params.txhdp + 4 * i);
+               __raw_writel(0, ctlr->params.rxhdp + 4 * i);
+               __raw_writel(0, ctlr->params.txcp + 4 * i);
+               __raw_writel(0, ctlr->params.rxcp + 4 * i);
+       }
+
+       dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
+       dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
+
+       dma_reg_write(ctlr, CPDMA_TXCONTROL, 1);
+       dma_reg_write(ctlr, CPDMA_RXCONTROL, 1);
+
+       ctlr->state = CPDMA_STATE_ACTIVE;
+
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+               if (ctlr->channels[i])
+                       cpdma_chan_start(ctlr->channels[i]);
+       }
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return 0;
+}
+
+int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&ctlr->lock, flags);
+               return -EINVAL;
+       }
+
+       ctlr->state = CPDMA_STATE_TEARDOWN;
+
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+               if (ctlr->channels[i])
+                       cpdma_chan_stop(ctlr->channels[i]);
+       }
+
+       dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
+       dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
+
+       dma_reg_write(ctlr, CPDMA_TXCONTROL, 0);
+       dma_reg_write(ctlr, CPDMA_RXCONTROL, 0);
+
+       ctlr->state = CPDMA_STATE_IDLE;
+
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return 0;
+}
+
+int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr)
+{
+       struct device *dev = ctlr->dev;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+
+       dev_info(dev, "CPDMA: state: %s", cpdma_state_str[ctlr->state]);
+
+       dev_info(dev, "CPDMA: txidver: %x",
+                dma_reg_read(ctlr, CPDMA_TXIDVER));
+       dev_info(dev, "CPDMA: txcontrol: %x",
+                dma_reg_read(ctlr, CPDMA_TXCONTROL));
+       dev_info(dev, "CPDMA: txteardown: %x",
+                dma_reg_read(ctlr, CPDMA_TXTEARDOWN));
+       dev_info(dev, "CPDMA: rxidver: %x",
+                dma_reg_read(ctlr, CPDMA_RXIDVER));
+       dev_info(dev, "CPDMA: rxcontrol: %x",
+                dma_reg_read(ctlr, CPDMA_RXCONTROL));
+       dev_info(dev, "CPDMA: softreset: %x",
+                dma_reg_read(ctlr, CPDMA_SOFTRESET));
+       dev_info(dev, "CPDMA: rxteardown: %x",
+                dma_reg_read(ctlr, CPDMA_RXTEARDOWN));
+       dev_info(dev, "CPDMA: txintstatraw: %x",
+                dma_reg_read(ctlr, CPDMA_TXINTSTATRAW));
+       dev_info(dev, "CPDMA: txintstatmasked: %x",
+                dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED));
+       dev_info(dev, "CPDMA: txintmaskset: %x",
+                dma_reg_read(ctlr, CPDMA_TXINTMASKSET));
+       dev_info(dev, "CPDMA: txintmaskclear: %x",
+                dma_reg_read(ctlr, CPDMA_TXINTMASKCLEAR));
+       dev_info(dev, "CPDMA: macinvector: %x",
+                dma_reg_read(ctlr, CPDMA_MACINVECTOR));
+       dev_info(dev, "CPDMA: maceoivector: %x",
+                dma_reg_read(ctlr, CPDMA_MACEOIVECTOR));
+       dev_info(dev, "CPDMA: rxintstatraw: %x",
+                dma_reg_read(ctlr, CPDMA_RXINTSTATRAW));
+       dev_info(dev, "CPDMA: rxintstatmasked: %x",
+                dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED));
+       dev_info(dev, "CPDMA: rxintmaskset: %x",
+                dma_reg_read(ctlr, CPDMA_RXINTMASKSET));
+       dev_info(dev, "CPDMA: rxintmaskclear: %x",
+                dma_reg_read(ctlr, CPDMA_RXINTMASKCLEAR));
+       dev_info(dev, "CPDMA: dmaintstatraw: %x",
+                dma_reg_read(ctlr, CPDMA_DMAINTSTATRAW));
+       dev_info(dev, "CPDMA: dmaintstatmasked: %x",
+                dma_reg_read(ctlr, CPDMA_DMAINTSTATMASKED));
+       dev_info(dev, "CPDMA: dmaintmaskset: %x",
+                dma_reg_read(ctlr, CPDMA_DMAINTMASKSET));
+       dev_info(dev, "CPDMA: dmaintmaskclear: %x",
+                dma_reg_read(ctlr, CPDMA_DMAINTMASKCLEAR));
+
+       if (!ctlr->params.has_ext_regs) {
+               dev_info(dev, "CPDMA: dmacontrol: %x",
+                        dma_reg_read(ctlr, CPDMA_DMACONTROL));
+               dev_info(dev, "CPDMA: dmastatus: %x",
+                        dma_reg_read(ctlr, CPDMA_DMASTATUS));
+               dev_info(dev, "CPDMA: rxbuffofs: %x",
+                        dma_reg_read(ctlr, CPDMA_RXBUFFOFS));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
+               if (ctlr->channels[i])
+                       cpdma_chan_dump(ctlr->channels[i]);
+
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return 0;
+}
+
+int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
+{
+       unsigned long flags;
+       int ret = 0, i;
+
+       if (!ctlr)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       if (ctlr->state != CPDMA_STATE_IDLE)
+               cpdma_ctlr_stop(ctlr);
+
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+               if (ctlr->channels[i])
+                       cpdma_chan_destroy(ctlr->channels[i]);
+       }
+
+       cpdma_desc_pool_destroy(ctlr->pool);
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       kfree(ctlr);
+       return ret;
+}
+
+int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
+{
+       unsigned long flags;
+       int i, reg;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&ctlr->lock, flags);
+               return -EINVAL;
+       }
+
+       reg = enable ? CPDMA_DMAINTMASKSET : CPDMA_DMAINTMASKCLEAR;
+       dma_reg_write(ctlr, reg, CPDMA_DMAINT_HOSTERR);
+
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+               if (ctlr->channels[i])
+                       cpdma_chan_int_ctrl(ctlr->channels[i], enable);
+       }
+
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return 0;
+}
+
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+{
+       dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+}
+
+struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
+                                    cpdma_handler_fn handler)
+{
+       struct cpdma_chan *chan;
+       int ret, offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;
+       unsigned long flags;
+
+       if (__chan_linear(chan_num) >= ctlr->num_chan)
+               return NULL;
+
+       ret = -ENOMEM;
+       chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               goto err_chan_alloc;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       ret = -EBUSY;
+       if (ctlr->channels[chan_num])
+               goto err_chan_busy;
+
+       chan->ctlr      = ctlr;
+       chan->state     = CPDMA_STATE_IDLE;
+       chan->chan_num  = chan_num;
+       chan->handler   = handler;
+
+       if (is_rx_chan(chan)) {
+               chan->hdp       = ctlr->params.rxhdp + offset;
+               chan->cp        = ctlr->params.rxcp + offset;
+               chan->rxfree    = ctlr->params.rxfree + offset;
+               chan->int_set   = CPDMA_RXINTMASKSET;
+               chan->int_clear = CPDMA_RXINTMASKCLEAR;
+               chan->td        = CPDMA_RXTEARDOWN;
+               chan->dir       = DMA_FROM_DEVICE;
+       } else {
+               chan->hdp       = ctlr->params.txhdp + offset;
+               chan->cp        = ctlr->params.txcp + offset;
+               chan->int_set   = CPDMA_TXINTMASKSET;
+               chan->int_clear = CPDMA_TXINTMASKCLEAR;
+               chan->td        = CPDMA_TXTEARDOWN;
+               chan->dir       = DMA_TO_DEVICE;
+       }
+       chan->mask = BIT(chan_linear(chan));
+
+       spin_lock_init(&chan->lock);
+
+       ctlr->channels[chan_num] = chan;
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return chan;
+
+err_chan_busy:
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       kfree(chan);
+err_chan_alloc:
+       return ERR_PTR(ret);
+}
+
+int cpdma_chan_destroy(struct cpdma_chan *chan)
+{
+       struct cpdma_ctlr *ctlr = chan->ctlr;
+       unsigned long flags;
+
+       if (!chan)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+       if (chan->state != CPDMA_STATE_IDLE)
+               cpdma_chan_stop(chan);
+       ctlr->channels[chan->chan_num] = NULL;
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       kfree(chan);
+       return 0;
+}
+
+int cpdma_chan_get_stats(struct cpdma_chan *chan,
+                        struct cpdma_chan_stats *stats)
+{
+       unsigned long flags;
+       if (!chan)
+               return -EINVAL;
+       spin_lock_irqsave(&chan->lock, flags);
+       memcpy(stats, &chan->stats, sizeof(*stats));
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return 0;
+}
+
+int cpdma_chan_dump(struct cpdma_chan *chan)
+{
+       unsigned long flags;
+       struct device *dev = chan->ctlr->dev;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       dev_info(dev, "channel %d (%s %d) state %s",
+                chan->chan_num, is_rx_chan(chan) ? "rx" : "tx",
+                chan_linear(chan), cpdma_state_str[chan->state]);
+       dev_info(dev, "\thdp: %x\n", chan_read(chan, hdp));
+       dev_info(dev, "\tcp: %x\n", chan_read(chan, cp));
+       if (chan->rxfree) {
+               dev_info(dev, "\trxfree: %x\n",
+                        chan_read(chan, rxfree));
+       }
+
+       dev_info(dev, "\tstats head_enqueue: %d\n",
+                chan->stats.head_enqueue);
+       dev_info(dev, "\tstats tail_enqueue: %d\n",
+                chan->stats.tail_enqueue);
+       dev_info(dev, "\tstats pad_enqueue: %d\n",
+                chan->stats.pad_enqueue);
+       dev_info(dev, "\tstats misqueued: %d\n",
+                chan->stats.misqueued);
+       dev_info(dev, "\tstats desc_alloc_fail: %d\n",
+                chan->stats.desc_alloc_fail);
+       dev_info(dev, "\tstats pad_alloc_fail: %d\n",
+                chan->stats.pad_alloc_fail);
+       dev_info(dev, "\tstats runt_receive_buff: %d\n",
+                chan->stats.runt_receive_buff);
+       dev_info(dev, "\tstats runt_transmit_buff: %d\n",
+                chan->stats.runt_transmit_buff);
+       dev_info(dev, "\tstats empty_dequeue: %d\n",
+                chan->stats.empty_dequeue);
+       dev_info(dev, "\tstats busy_dequeue: %d\n",
+                chan->stats.busy_dequeue);
+       dev_info(dev, "\tstats good_dequeue: %d\n",
+                chan->stats.good_dequeue);
+       dev_info(dev, "\tstats requeue: %d\n",
+                chan->stats.requeue);
+       dev_info(dev, "\tstats teardown_dequeue: %d\n",
+                chan->stats.teardown_dequeue);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return 0;
+}
+
+static void __cpdma_chan_submit(struct cpdma_chan *chan,
+                               struct cpdma_desc __iomem *desc)
+{
+       struct cpdma_ctlr               *ctlr = chan->ctlr;
+       struct cpdma_desc __iomem       *prev = chan->tail;
+       struct cpdma_desc_pool          *pool = ctlr->pool;
+       dma_addr_t                      desc_dma;
+       u32                             mode;
+
+       desc_dma = desc_phys(pool, desc);
+
+       /* simple case - idle channel */
+       if (!chan->head) {
+               chan->stats.head_enqueue++;
+               chan->head = desc;
+               chan->tail = desc;
+               if (chan->state == CPDMA_STATE_ACTIVE)
+                       chan_write(chan, hdp, desc_dma);
+               return;
+       }
+
+       /* first chain the descriptor at the tail of the list */
+       desc_write(prev, hw_next, desc_dma);
+       chan->tail = desc;
+       chan->stats.tail_enqueue++;
+
+       /* next check if EOQ has been triggered already */
+       mode = desc_read(prev, hw_mode);
+       if (((mode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ) &&
+           (chan->state == CPDMA_STATE_ACTIVE)) {
+               desc_write(prev, hw_mode, mode & ~CPDMA_DESC_EOQ);
+               chan_write(chan, hdp, desc_dma);
+               chan->stats.misqueued++;
+       }
+}
+
+int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
+                     int len, gfp_t gfp_mask)
+{
+       struct cpdma_ctlr               *ctlr = chan->ctlr;
+       struct cpdma_desc __iomem       *desc;
+       dma_addr_t                      buffer;
+       unsigned long                   flags;
+       u32                             mode;
+       int                             ret = 0;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       if (chan->state == CPDMA_STATE_TEARDOWN) {
+               ret = -EINVAL;
+               goto unlock_ret;
+       }
+
+       desc = cpdma_desc_alloc(ctlr->pool, 1);
+       if (!desc) {
+               chan->stats.desc_alloc_fail++;
+               ret = -ENOMEM;
+               goto unlock_ret;
+       }
+
+       if (len < ctlr->params.min_packet_size) {
+               len = ctlr->params.min_packet_size;
+               chan->stats.runt_transmit_buff++;
+       }
+
+       buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
+       mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+
+       desc_write(desc, hw_next,   0);
+       desc_write(desc, hw_buffer, buffer);
+       desc_write(desc, hw_len,    len);
+       desc_write(desc, hw_mode,   mode | len);
+       desc_write(desc, sw_token,  token);
+       desc_write(desc, sw_buffer, buffer);
+       desc_write(desc, sw_len,    len);
+
+       __cpdma_chan_submit(chan, desc);
+
+       if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree)
+               chan_write(chan, rxfree, 1);
+
+       chan->count++;
+
+unlock_ret:
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return ret;
+}
+
+static void __cpdma_chan_free(struct cpdma_chan *chan,
+                             struct cpdma_desc __iomem *desc,
+                             int outlen, int status)
+{
+       struct cpdma_ctlr               *ctlr = chan->ctlr;
+       struct cpdma_desc_pool          *pool = ctlr->pool;
+       dma_addr_t                      buff_dma;
+       int                             origlen;
+       void                            *token;
+
+       token      = (void *)desc_read(desc, sw_token);
+       buff_dma   = desc_read(desc, sw_buffer);
+       origlen    = desc_read(desc, sw_len);
+
+       dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+       cpdma_desc_free(pool, desc, 1);
+       (*chan->handler)(token, outlen, status);
+}
+
+static int __cpdma_chan_process(struct cpdma_chan *chan)
+{
+       struct cpdma_ctlr               *ctlr = chan->ctlr;
+       struct cpdma_desc __iomem       *desc;
+       int                             status, outlen;
+       struct cpdma_desc_pool          *pool = ctlr->pool;
+       dma_addr_t                      desc_dma;
+       unsigned long                   flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       desc = chan->head;
+       if (!desc) {
+               chan->stats.empty_dequeue++;
+               status = -ENOENT;
+               goto unlock_ret;
+       }
+       desc_dma = desc_phys(pool, desc);
+
+       status  = __raw_readl(&desc->hw_mode);
+       outlen  = status & 0x7ff;
+       if (status & CPDMA_DESC_OWNER) {
+               chan->stats.busy_dequeue++;
+               status = -EBUSY;
+               goto unlock_ret;
+       }
+       status  = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
+
+       chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
+       chan_write(chan, cp, desc_dma);
+       chan->count--;
+       chan->stats.good_dequeue++;
+
+       if (status & CPDMA_DESC_EOQ) {
+               chan->stats.requeue++;
+               chan_write(chan, hdp, desc_phys(pool, chan->head));
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       __cpdma_chan_free(chan, desc, outlen, status);
+       return status;
+
+unlock_ret:
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return status;
+}
+
+int cpdma_chan_process(struct cpdma_chan *chan, int quota)
+{
+       int used = 0, ret = 0;
+
+       if (chan->state != CPDMA_STATE_ACTIVE)
+               return -EINVAL;
+
+       while (used < quota) {
+               ret = __cpdma_chan_process(chan);
+               if (ret < 0)
+                       break;
+               used++;
+       }
+       return used;
+}
+
+int cpdma_chan_start(struct cpdma_chan *chan)
+{
+       struct cpdma_ctlr       *ctlr = chan->ctlr;
+       struct cpdma_desc_pool  *pool = ctlr->pool;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->state != CPDMA_STATE_IDLE) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EBUSY;
+       }
+       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EINVAL;
+       }
+       dma_reg_write(ctlr, chan->int_set, chan->mask);
+       chan->state = CPDMA_STATE_ACTIVE;
+       if (chan->head) {
+               chan_write(chan, hdp, desc_phys(pool, chan->head));
+               if (chan->rxfree)
+                       chan_write(chan, rxfree, chan->count);
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return 0;
+}
+
+int cpdma_chan_stop(struct cpdma_chan *chan)
+{
+       struct cpdma_ctlr       *ctlr = chan->ctlr;
+       struct cpdma_desc_pool  *pool = ctlr->pool;
+       unsigned long           flags;
+       int                     ret;
+       unsigned long           timeout;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EINVAL;
+       }
+
+       chan->state = CPDMA_STATE_TEARDOWN;
+       dma_reg_write(ctlr, chan->int_clear, chan->mask);
+
+       /* trigger teardown */
+       dma_reg_write(ctlr, chan->td, chan->chan_num);
+
+       /* wait for teardown complete */
+       timeout = jiffies + HZ/10;      /* 100 msec */
+       while (time_before(jiffies, timeout)) {
+               u32 cp = chan_read(chan, cp);
+               if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE)
+                       break;
+               cpu_relax();
+       }
+       WARN_ON(!time_before(jiffies, timeout));
+       chan_write(chan, cp, CPDMA_TEARDOWN_VALUE);
+
+       /* handle completed packets */
+       do {
+               ret = __cpdma_chan_process(chan);
+               if (ret < 0)
+                       break;
+       } while ((ret & CPDMA_DESC_TD_COMPLETE) == 0);
+
+       /* remaining packets haven't been tx/rx'ed, clean them up */
+       while (chan->head) {
+               struct cpdma_desc __iomem *desc = chan->head;
+               dma_addr_t next_dma;
+
+               next_dma = desc_read(desc, hw_next);
+               chan->head = desc_from_phys(pool, next_dma);
+               chan->stats.teardown_dequeue++;
+
+               /* issue callback without locks held */
+               spin_unlock_irqrestore(&chan->lock, flags);
+               __cpdma_chan_free(chan, desc, 0, -ENOSYS);
+               spin_lock_irqsave(&chan->lock, flags);
+       }
+
+       chan->state = CPDMA_STATE_IDLE;
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return 0;
+}
+
+int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EINVAL;
+       }
+
+       dma_reg_write(chan->ctlr, enable ? chan->int_set : chan->int_clear,
+                     chan->mask);
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return 0;
+}
+
+struct cpdma_control_info {
+       u32             reg;
+       u32             shift, mask;
+       int             access;
+#define ACCESS_RO      BIT(0)
+#define ACCESS_WO      BIT(1)
+#define ACCESS_RW      (ACCESS_RO | ACCESS_WO)
+};
+
+struct cpdma_control_info controls[] = {
+       [CPDMA_CMD_IDLE]          = {CPDMA_DMACONTROL,  3,  1,      ACCESS_WO},
+       [CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL,  4,  1,      ACCESS_RW},
+       [CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL,  2,  1,      ACCESS_RW},
+       [CPDMA_RX_OWNERSHIP_FLIP] = {CPDMA_DMACONTROL,  1,  1,      ACCESS_RW},
+       [CPDMA_TX_PRIO_FIXED]     = {CPDMA_DMACONTROL,  0,  1,      ACCESS_RW},
+       [CPDMA_STAT_IDLE]         = {CPDMA_DMASTATUS,   31, 1,      ACCESS_RO},
+       [CPDMA_STAT_TX_ERR_CODE]  = {CPDMA_DMASTATUS,   20, 0xf,    ACCESS_RW},
+       [CPDMA_STAT_TX_ERR_CHAN]  = {CPDMA_DMASTATUS,   16, 0x7,    ACCESS_RW},
+       [CPDMA_STAT_RX_ERR_CODE]  = {CPDMA_DMASTATUS,   12, 0xf,    ACCESS_RW},
+       [CPDMA_STAT_RX_ERR_CHAN]  = {CPDMA_DMASTATUS,   8,  0x7,    ACCESS_RW},
+       [CPDMA_RX_BUFFER_OFFSET]  = {CPDMA_RXBUFFOFS,   0,  0xffff, ACCESS_RW},
+};
+
+int cpdma_control_get(struct cpdma_ctlr *ctlr, int control)
+{
+       unsigned long flags;
+       struct cpdma_control_info *info = &controls[control];
+       int ret;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+
+       ret = -ENOTSUPP;
+       if (!ctlr->params.has_ext_regs)
+               goto unlock_ret;
+
+       ret = -EINVAL;
+       if (ctlr->state != CPDMA_STATE_ACTIVE)
+               goto unlock_ret;
+
+       ret = -ENOENT;
+       if (control < 0 || control >= ARRAY_SIZE(controls))
+               goto unlock_ret;
+
+       ret = -EPERM;
+       if ((info->access & ACCESS_RO) != ACCESS_RO)
+               goto unlock_ret;
+
+       ret = (dma_reg_read(ctlr, info->reg) >> info->shift) & info->mask;
+
+unlock_ret:
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return ret;
+}
+
+int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value)
+{
+       unsigned long flags;
+       struct cpdma_control_info *info = &controls[control];
+       int ret;
+       u32 val;
+
+       spin_lock_irqsave(&ctlr->lock, flags);
+
+       ret = -ENOTSUPP;
+       if (!ctlr->params.has_ext_regs)
+               goto unlock_ret;
+
+       ret = -EINVAL;
+       if (ctlr->state != CPDMA_STATE_ACTIVE)
+               goto unlock_ret;
+
+       ret = -ENOENT;
+       if (control < 0 || control >= ARRAY_SIZE(controls))
+               goto unlock_ret;
+
+       ret = -EPERM;
+       if ((info->access & ACCESS_WO) != ACCESS_WO)
+               goto unlock_ret;
+
+       val  = dma_reg_read(ctlr, info->reg);
+       val &= ~(info->mask << info->shift);
+       val |= (value & info->mask) << info->shift;
+       dma_reg_write(ctlr, info->reg, val);
+       ret = 0;
+
+unlock_ret:
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+       return ret;
+}
diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/davinci_cpdma.h
new file mode 100644 (file)
index 0000000..868e50e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Texas Instruments CPDMA Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DAVINCI_CPDMA_H__
+#define __DAVINCI_CPDMA_H__
+
+#define CPDMA_MAX_CHANNELS     BITS_PER_LONG
+
+#define tx_chan_num(chan)      (chan)
+#define rx_chan_num(chan)      ((chan) + CPDMA_MAX_CHANNELS)
+#define is_rx_chan(chan)       ((chan)->chan_num >= CPDMA_MAX_CHANNELS)
+#define is_tx_chan(chan)       (!is_rx_chan(chan))
+#define __chan_linear(chan_num)        ((chan_num) & (CPDMA_MAX_CHANNELS - 1))
+#define chan_linear(chan)      __chan_linear((chan)->chan_num)
+
+struct cpdma_params {
+       struct device           *dev;
+       void __iomem            *dmaregs;
+       void __iomem            *txhdp, *rxhdp, *txcp, *rxcp;
+       void __iomem            *rxthresh, *rxfree;
+       int                     num_chan;
+       bool                    has_soft_reset;
+       int                     min_packet_size;
+       u32                     desc_mem_phys;
+       int                     desc_mem_size;
+       int                     desc_align;
+
+       /*
+        * Some instances of embedded cpdma controllers have extra control and
+        * status registers.  The following flag enables access to these
+        * "extended" registers.
+        */
+       bool                    has_ext_regs;
+};
+
+struct cpdma_chan_stats {
+       u32                     head_enqueue;
+       u32                     tail_enqueue;
+       u32                     pad_enqueue;
+       u32                     misqueued;
+       u32                     desc_alloc_fail;
+       u32                     pad_alloc_fail;
+       u32                     runt_receive_buff;
+       u32                     runt_transmit_buff;
+       u32                     empty_dequeue;
+       u32                     busy_dequeue;
+       u32                     good_dequeue;
+       u32                     requeue;
+       u32                     teardown_dequeue;
+};
+
+struct cpdma_ctlr;
+struct cpdma_chan;
+
+typedef void (*cpdma_handler_fn)(void *token, int len, int status);
+
+struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params);
+int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_start(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr);
+
+struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
+                                    cpdma_handler_fn handler);
+int cpdma_chan_destroy(struct cpdma_chan *chan);
+int cpdma_chan_start(struct cpdma_chan *chan);
+int cpdma_chan_stop(struct cpdma_chan *chan);
+int cpdma_chan_dump(struct cpdma_chan *chan);
+
+int cpdma_chan_get_stats(struct cpdma_chan *chan,
+                        struct cpdma_chan_stats *stats);
+int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
+                     int len, gfp_t gfp_mask);
+int cpdma_chan_process(struct cpdma_chan *chan, int quota);
+
+int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
+int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
+
+enum cpdma_control {
+       CPDMA_CMD_IDLE,                 /* write-only */
+       CPDMA_COPY_ERROR_FRAMES,        /* read-write */
+       CPDMA_RX_OFF_LEN_UPDATE,        /* read-write */
+       CPDMA_RX_OWNERSHIP_FLIP,        /* read-write */
+       CPDMA_TX_PRIO_FIXED,            /* read-write */
+       CPDMA_STAT_IDLE,                /* read-only */
+       CPDMA_STAT_TX_ERR_CHAN,         /* read-only */
+       CPDMA_STAT_TX_ERR_CODE,         /* read-only */
+       CPDMA_STAT_RX_ERR_CHAN,         /* read-only */
+       CPDMA_STAT_RX_ERR_CODE,         /* read-only */
+       CPDMA_RX_BUFFER_OFFSET,         /* read-write */
+};
+
+int cpdma_control_get(struct cpdma_ctlr *ctlr, int control);
+int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value);
+
+#endif
index 7fbd052ddb0a2b20e33bad64820fa9cc41dbbeb5..2a628d17d178f14a0167780c01c48b351c41550f 100644 (file)
@@ -63,6 +63,8 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 
+#include "davinci_cpdma.h"
+
 static int debug_level;
 module_param(debug_level, int, 0);
 MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)");
@@ -113,7 +115,7 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 #define EMAC_DEF_MAX_FRAME_SIZE                (1500 + 14 + 4 + 4)
 #define EMAC_DEF_TX_CH                 (0) /* Default 0th channel */
 #define EMAC_DEF_RX_CH                 (0) /* Default 0th channel */
-#define EMAC_DEF_MDIO_TICK_MS          (10) /* typically 1 tick=1 ms) */
+#define EMAC_DEF_RX_NUM_DESC           (128)
 #define EMAC_DEF_MAX_TX_CH             (1) /* Max TX channels configured */
 #define EMAC_DEF_MAX_RX_CH             (1) /* Max RX channels configured */
 #define EMAC_POLL_WEIGHT               (64) /* Default NAPI poll weight */
@@ -125,7 +127,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 /* EMAC register related defines */
 #define EMAC_ALL_MULTI_REG_VALUE       (0xFFFFFFFF)
 #define EMAC_NUM_MULTICAST_BITS                (64)
-#define EMAC_TEARDOWN_VALUE            (0xFFFFFFFC)
 #define EMAC_TX_CONTROL_TX_ENABLE_VAL  (0x1)
 #define EMAC_RX_CONTROL_RX_ENABLE_VAL  (0x1)
 #define EMAC_MAC_HOST_ERR_INTMASK_VAL  (0x2)
@@ -212,24 +213,10 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 #define EMAC_DEF_MAX_MULTICAST_ADDRESSES (64) /* Max mcast addr's */
 
 /* EMAC Peripheral Device Register Memory Layout structure */
-#define EMAC_TXIDVER           0x0
-#define EMAC_TXCONTROL         0x4
-#define EMAC_TXTEARDOWN                0x8
-#define EMAC_RXIDVER           0x10
-#define EMAC_RXCONTROL         0x14
-#define EMAC_RXTEARDOWN                0x18
-#define EMAC_TXINTSTATRAW      0x80
-#define EMAC_TXINTSTATMASKED   0x84
-#define EMAC_TXINTMASKSET      0x88
-#define EMAC_TXINTMASKCLEAR    0x8C
 #define EMAC_MACINVECTOR       0x90
 
 #define EMAC_DM646X_MACEOIVECTOR       0x94
 
-#define EMAC_RXINTSTATRAW      0xA0
-#define EMAC_RXINTSTATMASKED   0xA4
-#define EMAC_RXINTMASKSET      0xA8
-#define EMAC_RXINTMASKCLEAR    0xAC
 #define EMAC_MACINTSTATRAW     0xB0
 #define EMAC_MACINTSTATMASKED  0xB4
 #define EMAC_MACINTMASKSET     0xB8
@@ -256,12 +243,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 #define EMAC_MACADDRHI         0x504
 #define EMAC_MACINDEX          0x508
 
-/* EMAC HDP and Completion registors */
-#define EMAC_TXHDP(ch)         (0x600 + (ch * 4))
-#define EMAC_RXHDP(ch)         (0x620 + (ch * 4))
-#define EMAC_TXCP(ch)          (0x640 + (ch * 4))
-#define EMAC_RXCP(ch)          (0x660 + (ch * 4))
-
 /* EMAC statistics registers */
 #define EMAC_RXGOODFRAMES      0x200
 #define EMAC_RXBCASTFRAMES     0x204
@@ -303,25 +284,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 #define EMAC_DM644X_INTMIN_INTVL       0x1
 #define EMAC_DM644X_INTMAX_INTVL       (EMAC_DM644X_EWINTCNT_MASK)
 
-/* EMAC MDIO related */
-/* Mask & Control defines */
-#define MDIO_CONTROL_CLKDIV    (0xFF)
-#define MDIO_CONTROL_ENABLE    BIT(30)
-#define MDIO_USERACCESS_GO     BIT(31)
-#define MDIO_USERACCESS_WRITE  BIT(30)
-#define MDIO_USERACCESS_READ   (0)
-#define MDIO_USERACCESS_REGADR (0x1F << 21)
-#define MDIO_USERACCESS_PHYADR (0x1F << 16)
-#define MDIO_USERACCESS_DATA   (0xFFFF)
-#define MDIO_USERPHYSEL_LINKSEL        BIT(7)
-#define MDIO_VER_MODID         (0xFFFF << 16)
-#define MDIO_VER_REVMAJ                (0xFF   << 8)
-#define MDIO_VER_REVMIN                (0xFF)
-
-#define MDIO_USERACCESS(inst)  (0x80 + (inst * 8))
-#define MDIO_USERPHYSEL(inst)  (0x84 + (inst * 8))
-#define MDIO_CONTROL           (0x04)
-
 /* EMAC DM646X control module registers */
 #define EMAC_DM646X_CMINTCTRL  0x0C
 #define EMAC_DM646X_CMRXINTEN  0x14
@@ -345,120 +307,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 /* EMAC Stats Clear Mask */
 #define EMAC_STATS_CLR_MASK    (0xFFFFFFFF)
 
-/** net_buf_obj: EMAC network bufferdata structure
- *
- * EMAC network buffer data structure
- */
-struct emac_netbufobj {
-       void *buf_token;
-       char *data_ptr;
-       int length;
-};
-
-/** net_pkt_obj: EMAC network packet data structure
- *
- * EMAC network packet data structure - supports buffer list (for future)
- */
-struct emac_netpktobj {
-       void *pkt_token; /* data token may hold tx/rx chan id */
-       struct emac_netbufobj *buf_list; /* array of network buffer objects */
-       int num_bufs;
-       int pkt_length;
-};
-
-/** emac_tx_bd: EMAC TX Buffer descriptor data structure
- *
- * EMAC TX Buffer descriptor data structure
- */
-struct emac_tx_bd {
-       int h_next;
-       int buff_ptr;
-       int off_b_len;
-       int mode; /* SOP, EOP, ownership, EOQ, teardown,Qstarv, length */
-       struct emac_tx_bd __iomem *next;
-       void *buf_token;
-};
-
-/** emac_txch: EMAC TX Channel data structure
- *
- * EMAC TX Channel data structure
- */
-struct emac_txch {
-       /* Config related */
-       u32 num_bd;
-       u32 service_max;
-
-       /* CPPI specific */
-       u32 alloc_size;
-       void __iomem *bd_mem;
-       struct emac_tx_bd __iomem *bd_pool_head;
-       struct emac_tx_bd __iomem *active_queue_head;
-       struct emac_tx_bd __iomem *active_queue_tail;
-       struct emac_tx_bd __iomem *last_hw_bdprocessed;
-       u32 queue_active;
-       u32 teardown_pending;
-       u32 *tx_complete;
-
-       /** statistics */
-       u32 proc_count;     /* TX: # of times emac_tx_bdproc is called */
-       u32 mis_queued_packets;
-       u32 queue_reinit;
-       u32 end_of_queue_add;
-       u32 out_of_tx_bd;
-       u32 no_active_pkts; /* IRQ when there were no packets to process */
-       u32 active_queue_count;
-};
-
-/** emac_rx_bd: EMAC RX Buffer descriptor data structure
- *
- * EMAC RX Buffer descriptor data structure
- */
-struct emac_rx_bd {
-       int h_next;
-       int buff_ptr;
-       int off_b_len;
-       int mode;
-       struct emac_rx_bd __iomem *next;
-       void *data_ptr;
-       void *buf_token;
-};
-
-/** emac_rxch: EMAC RX Channel data structure
- *
- * EMAC RX Channel data structure
- */
-struct emac_rxch {
-       /* configuration info */
-       u32 num_bd;
-       u32 service_max;
-       u32 buf_size;
-       char mac_addr[6];
-
-       /** CPPI specific */
-       u32 alloc_size;
-       void __iomem *bd_mem;
-       struct emac_rx_bd __iomem *bd_pool_head;
-       struct emac_rx_bd __iomem *active_queue_head;
-       struct emac_rx_bd __iomem *active_queue_tail;
-       u32 queue_active;
-       u32 teardown_pending;
-
-       /* packet and buffer objects */
-       struct emac_netpktobj pkt_queue;
-       struct emac_netbufobj buf_queue;
-
-       /** statistics */
-       u32 proc_count; /* number of times emac_rx_bdproc is called */
-       u32 processed_bd;
-       u32 recycled_bd;
-       u32 out_of_rx_bd;
-       u32 out_of_rx_buffers;
-       u32 queue_reinit;
-       u32 end_of_queue_add;
-       u32 end_of_queue;
-       u32 mis_queued_packets;
-};
-
 /* emac_priv: EMAC private data structure
  *
  * EMAC adapter private data structure
@@ -469,17 +317,13 @@ struct emac_priv {
        struct platform_device *pdev;
        struct napi_struct napi;
        char mac_addr[6];
-       spinlock_t tx_lock;
-       spinlock_t rx_lock;
        void __iomem *remap_addr;
        u32 emac_base_phys;
        void __iomem *emac_base;
        void __iomem *ctrl_base;
-       void __iomem *emac_ctrl_ram;
-       u32 ctrl_ram_size;
-       u32 hw_ram_addr;
-       struct emac_txch *txch[EMAC_DEF_MAX_TX_CH];
-       struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH];
+       struct cpdma_ctlr *dma;
+       struct cpdma_chan *txchan;
+       struct cpdma_chan *rxchan;
        u32 link; /* 1=link on, 0=link off */
        u32 speed; /* 0=Auto Neg, 1=No PHY, 10,100, 1000 - mbps */
        u32 duplex; /* Link duplex: 0=Half, 1=Full */
@@ -493,13 +337,7 @@ struct emac_priv {
        u32 mac_hash2;
        u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
        u32 rx_addr_type;
-       /* periodic timer required for MDIO polling */
-       struct timer_list periodic_timer;
-       u32 periodic_ticks;
-       u32 timer_active;
-       u32 phy_mask;
-       /* mii_bus,phy members */
-       struct mii_bus *mii_bus;
+       const char *phy_id;
        struct phy_device *phydev;
        spinlock_t lock;
        /*platform specific members*/
@@ -510,19 +348,6 @@ struct emac_priv {
 /* clock frequency for EMAC */
 static struct clk *emac_clk;
 static unsigned long emac_bus_frequency;
-static unsigned long mdio_max_freq;
-
-#define emac_virt_to_phys(addr, priv) \
-       (((u32 __force)(addr) - (u32 __force)(priv->emac_ctrl_ram)) \
-       + priv->hw_ram_addr)
-
-/* Cache macros - Packet buffers would be from skb pool which is cached */
-#define EMAC_VIRT_NOCACHE(addr) (addr)
-
-/* DM644x does not have BD's in cached memory - so no cache functions */
-#define BD_CACHE_INVALIDATE(addr, size)
-#define BD_CACHE_WRITEBACK(addr, size)
-#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size)
 
 /* EMAC TX Host Error description strings */
 static char *emac_txhost_errcodes[16] = {
@@ -548,9 +373,6 @@ static char *emac_rxhost_errcodes[16] = {
 #define emac_ctrl_read(reg)      ioread32((priv->ctrl_base + (reg)))
 #define emac_ctrl_write(reg, val) iowrite32(val, (priv->ctrl_base + (reg)))
 
-#define emac_mdio_read(reg)      ioread32(bus->priv + (reg))
-#define emac_mdio_write(reg, val) iowrite32(val, (bus->priv + (reg)))
-
 /**
  * emac_dump_regs: Dump important EMAC registers to debug terminal
  * @priv: The DaVinci EMAC private adapter structure
@@ -569,20 +391,6 @@ static void emac_dump_regs(struct emac_priv *priv)
                        emac_ctrl_read(EMAC_CTRL_EWCTL),
                        emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
        }
-       dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n",
-               emac_read(EMAC_TXIDVER),
-               ((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"),
-               emac_read(EMAC_RXIDVER),
-               ((emac_read(EMAC_RXCONTROL)) ? "enabled" : "disabled"));
-       dev_info(emac_dev, "EMAC: TXIntRaw:%08X, TxIntMasked: %08X, "\
-               "TxIntMasSet: %08X\n", emac_read(EMAC_TXINTSTATRAW),
-               emac_read(EMAC_TXINTSTATMASKED), emac_read(EMAC_TXINTMASKSET));
-       dev_info(emac_dev, "EMAC: RXIntRaw:%08X, RxIntMasked: %08X, "\
-               "RxIntMasSet: %08X\n", emac_read(EMAC_RXINTSTATRAW),
-               emac_read(EMAC_RXINTSTATMASKED), emac_read(EMAC_RXINTMASKSET));
-       dev_info(emac_dev, "EMAC: MacIntRaw:%08X, MacIntMasked: %08X, "\
-               "MacInVector=%08X\n", emac_read(EMAC_MACINTSTATRAW),
-               emac_read(EMAC_MACINTSTATMASKED), emac_read(EMAC_MACINVECTOR));
        dev_info(emac_dev, "EMAC: EmuControl:%08X, FifoControl: %08X\n",
                emac_read(EMAC_EMCONTROL), emac_read(EMAC_FIFOCONTROL));
        dev_info(emac_dev, "EMAC: MBPEnable:%08X, RXUnicastSet: %08X, "\
@@ -591,8 +399,6 @@ static void emac_dump_regs(struct emac_priv *priv)
        dev_info(emac_dev, "EMAC: MacControl:%08X, MacStatus: %08X, "\
                "MacConfig=%08X\n", emac_read(EMAC_MACCONTROL),
                emac_read(EMAC_MACSTATUS), emac_read(EMAC_MACCONFIG));
-       dev_info(emac_dev, "EMAC: TXHDP[0]:%08X, RXHDP[0]: %08X\n",
-               emac_read(EMAC_TXHDP(0)), emac_read(EMAC_RXHDP(0)));
        dev_info(emac_dev, "EMAC Statistics\n");
        dev_info(emac_dev, "EMAC: rx_good_frames:%d\n",
                emac_read(EMAC_RXGOODFRAMES));
@@ -654,11 +460,10 @@ static void emac_dump_regs(struct emac_priv *priv)
                emac_read(EMAC_RXMOFOVERRUNS));
        dev_info(emac_dev, "EMAC: rx_dma_overruns:%d\n",
                emac_read(EMAC_RXDMAOVERRUNS));
+
+       cpdma_ctlr_dump(priv->dma);
 }
 
-/*************************************************************************
- *  EMAC MDIO/Phy Functionality
- *************************************************************************/
 /**
  * emac_get_drvinfo: Get EMAC driver information
  * @ndev: The DaVinci EMAC network adapter
@@ -686,7 +491,7 @@ static int emac_get_settings(struct net_device *ndev,
                             struct ethtool_cmd *ecmd)
 {
        struct emac_priv *priv = netdev_priv(ndev);
-       if (priv->phy_mask)
+       if (priv->phydev)
                return phy_ethtool_gset(priv->phydev, ecmd);
        else
                return -EOPNOTSUPP;
@@ -704,7 +509,7 @@ static int emac_get_settings(struct net_device *ndev,
 static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
 {
        struct emac_priv *priv = netdev_priv(ndev);
-       if (priv->phy_mask)
+       if (priv->phydev)
                return phy_ethtool_sset(priv->phydev, ecmd);
        else
                return -EOPNOTSUPP;
@@ -841,7 +646,7 @@ static void emac_update_phystatus(struct emac_priv *priv)
        mac_control = emac_read(EMAC_MACCONTROL);
        cur_duplex = (mac_control & EMAC_MACCONTROL_FULLDUPLEXEN) ?
                        DUPLEX_FULL : DUPLEX_HALF;
-       if (priv->phy_mask)
+       if (priv->phydev)
                new_duplex = priv->phydev->duplex;
        else
                new_duplex = DUPLEX_FULL;
@@ -1184,371 +989,68 @@ static irqreturn_t emac_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/** EMAC on-chip buffer descriptor memory
- *
- * WARNING: Please note that the on chip memory is used for both TX and RX
- * buffer descriptor queues and is equally divided between TX and RX desc's
- * If the number of TX or RX descriptors change this memory pointers need
- * to be adjusted. If external memory is allocated then these pointers can
- * pointer to the memory
- *
- */
-#define EMAC_TX_BD_MEM(priv)   ((priv)->emac_ctrl_ram)
-#define EMAC_RX_BD_MEM(priv)   ((priv)->emac_ctrl_ram + \
-                               (((priv)->ctrl_ram_size) >> 1))
-
-/**
- * emac_init_txch: TX channel initialization
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device init to setup a TX channel (allocate buffer desc
- * create free pool and keep ready for transmission
- *
- * Returns success(0) or mem alloc failures error code
- */
-static int emac_init_txch(struct emac_priv *priv, u32 ch)
-{
-       struct device *emac_dev = &priv->ndev->dev;
-       u32 cnt, bd_size;
-       void __iomem *mem;
-       struct emac_tx_bd __iomem *curr_bd;
-       struct emac_txch *txch = NULL;
-
-       txch = kzalloc(sizeof(struct emac_txch), GFP_KERNEL);
-       if (NULL == txch) {
-               dev_err(emac_dev, "DaVinci EMAC: TX Ch mem alloc failed");
-               return -ENOMEM;
-       }
-       priv->txch[ch] = txch;
-       txch->service_max = EMAC_DEF_TX_MAX_SERVICE;
-       txch->active_queue_head = NULL;
-       txch->active_queue_tail = NULL;
-       txch->queue_active = 0;
-       txch->teardown_pending = 0;
-
-       /* allocate memory for TX CPPI channel on a 4 byte boundry */
-       txch->tx_complete = kzalloc(txch->service_max * sizeof(u32),
-                                   GFP_KERNEL);
-       if (NULL == txch->tx_complete) {
-               dev_err(emac_dev, "DaVinci EMAC: Tx service mem alloc failed");
-               kfree(txch);
-               return -ENOMEM;
-       }
-
-       /* allocate buffer descriptor pool align every BD on four word
-        * boundry for future requirements */
-       bd_size = (sizeof(struct emac_tx_bd) + 0xF) & ~0xF;
-       txch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size;
-       txch->alloc_size = (((bd_size * txch->num_bd) + 0xF) & ~0xF);
-
-       /* alloc TX BD memory */
-       txch->bd_mem = EMAC_TX_BD_MEM(priv);
-       __memzero((void __force *)txch->bd_mem, txch->alloc_size);
-
-       /* initialize the BD linked list */
-       mem = (void __force __iomem *)
-                       (((u32 __force) txch->bd_mem + 0xF) & ~0xF);
-       txch->bd_pool_head = NULL;
-       for (cnt = 0; cnt < txch->num_bd; cnt++) {
-               curr_bd = mem + (cnt * bd_size);
-               curr_bd->next = txch->bd_pool_head;
-               txch->bd_pool_head = curr_bd;
-       }
-
-       /* reset statistics counters */
-       txch->out_of_tx_bd = 0;
-       txch->no_active_pkts = 0;
-       txch->active_queue_count = 0;
-
-       return 0;
-}
-
-/**
- * emac_cleanup_txch: Book-keep function to clean TX channel resources
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to clean up TX channel resources
- *
- */
-static void emac_cleanup_txch(struct emac_priv *priv, u32 ch)
+static struct sk_buff *emac_rx_alloc(struct emac_priv *priv)
 {
-       struct emac_txch *txch = priv->txch[ch];
-
-       if (txch) {
-               if (txch->bd_mem)
-                       txch->bd_mem = NULL;
-               kfree(txch->tx_complete);
-               kfree(txch);
-               priv->txch[ch] = NULL;
-       }
+       struct sk_buff *skb = dev_alloc_skb(priv->rx_buf_size);
+       if (WARN_ON(!skb))
+               return NULL;
+       skb->dev = priv->ndev;
+       skb_reserve(skb, NET_IP_ALIGN);
+       return skb;
 }
 
-/**
- * emac_net_tx_complete: TX packet completion function
- * @priv: The DaVinci EMAC private adapter structure
- * @net_data_tokens: packet token - skb pointer
- * @num_tokens: number of skb's to free
- * @ch: TX channel number
- *
- * Frees the skb once packet is transmitted
- *
- */
-static int emac_net_tx_complete(struct emac_priv *priv,
-                               void **net_data_tokens,
-                               int num_tokens, u32 ch)
+static void emac_rx_handler(void *token, int len, int status)
 {
-       struct net_device *ndev = priv->ndev;
-       u32 cnt;
-
-       if (unlikely(num_tokens && netif_queue_stopped(ndev)))
-               netif_start_queue(ndev);
-       for (cnt = 0; cnt < num_tokens; cnt++) {
-               struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
-               if (skb == NULL)
-                       continue;
-               ndev->stats.tx_packets++;
-               ndev->stats.tx_bytes += skb->len;
+       struct sk_buff          *skb = token;
+       struct net_device       *ndev = skb->dev;
+       struct emac_priv        *priv = netdev_priv(ndev);
+       struct device           *emac_dev = &ndev->dev;
+       int                     ret;
+
+       /* free and bail if we are shutting down */
+       if (unlikely(!netif_running(ndev))) {
                dev_kfree_skb_any(skb);
+               return;
        }
-       return 0;
-}
-
-/**
- * emac_txch_teardown: TX channel teardown
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to teardown TX channel
- *
- */
-static void emac_txch_teardown(struct emac_priv *priv, u32 ch)
-{
-       struct device *emac_dev = &priv->ndev->dev;
-       u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */
-       struct emac_txch *txch = priv->txch[ch];
-       struct emac_tx_bd __iomem *curr_bd;
-
-       while ((emac_read(EMAC_TXCP(ch)) & EMAC_TEARDOWN_VALUE) !=
-              EMAC_TEARDOWN_VALUE) {
-               /* wait till tx teardown complete */
-               cpu_relax(); /* TODO: check if this helps ... */
-               --teardown_cnt;
-               if (0 == teardown_cnt) {
-                       dev_err(emac_dev, "EMAC: TX teardown aborted\n");
-                       break;
-               }
-       }
-       emac_write(EMAC_TXCP(ch), EMAC_TEARDOWN_VALUE);
-
-       /* process sent packets and return skb's to upper layer */
-       if (1 == txch->queue_active) {
-               curr_bd = txch->active_queue_head;
-               while (curr_bd != NULL) {
-                       dma_unmap_single(emac_dev, curr_bd->buff_ptr,
-                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
-                               DMA_TO_DEVICE);
-
-                       emac_net_tx_complete(priv, (void __force *)
-                                       &curr_bd->buf_token, 1, ch);
-                       if (curr_bd != txch->active_queue_tail)
-                               curr_bd = curr_bd->next;
-                       else
-                               break;
-               }
-               txch->bd_pool_head = txch->active_queue_head;
-               txch->active_queue_head =
-               txch->active_queue_tail = NULL;
-       }
-}
 
-/**
- * emac_stop_txch: Stop TX channel operation
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to stop TX channel operation
- *
- */
-static void emac_stop_txch(struct emac_priv *priv, u32 ch)
-{
-       struct emac_txch *txch = priv->txch[ch];
-
-       if (txch) {
-               txch->teardown_pending = 1;
-               emac_write(EMAC_TXTEARDOWN, 0);
-               emac_txch_teardown(priv, ch);
-               txch->teardown_pending = 0;
-               emac_write(EMAC_TXINTMASKCLEAR, BIT(ch));
+       /* recycle on recieve error */
+       if (status < 0) {
+               ndev->stats.rx_errors++;
+               goto recycle;
        }
-}
 
-/**
- * emac_tx_bdproc: TX buffer descriptor (packet) processing
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number to process buffer descriptors for
- * @budget: number of packets allowed to process
- * @pending: indication to caller that packets are pending to process
- *
- * Processes TX buffer descriptors after packets are transmitted - checks
- * ownership bit on the TX * descriptor and requeues it to free pool & frees
- * the SKB buffer. Only "budget" number of packets are processed and
- * indication of pending packets provided to the caller
- *
- * Returns number of packets processed
- */
-static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
-{
-       struct device *emac_dev = &priv->ndev->dev;
-       unsigned long flags;
-       u32 frame_status;
-       u32 pkts_processed = 0;
-       u32 tx_complete_cnt = 0;
-       struct emac_tx_bd __iomem *curr_bd;
-       struct emac_txch *txch = priv->txch[ch];
-       u32 *tx_complete_ptr = txch->tx_complete;
-
-       if (unlikely(1 == txch->teardown_pending)) {
-               if (netif_msg_tx_err(priv) && net_ratelimit()) {
-                       dev_err(emac_dev, "DaVinci EMAC:emac_tx_bdproc: "\
-                               "teardown pending\n");
-               }
-               return 0;  /* dont handle any pkt completions */
-       }
+       /* feed received packet up the stack */
+       skb_put(skb, len);
+       skb->protocol = eth_type_trans(skb, ndev);
+       netif_receive_skb(skb);
+       ndev->stats.rx_bytes += len;
+       ndev->stats.rx_packets++;
 
-       ++txch->proc_count;
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       curr_bd = txch->active_queue_head;
-       if (NULL == curr_bd) {
-               emac_write(EMAC_TXCP(ch),
-                          emac_virt_to_phys(txch->last_hw_bdprocessed, priv));
-               txch->no_active_pkts++;
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
-               return 0;
+       /* alloc a new packet for receive */
+       skb = emac_rx_alloc(priv);
+       if (!skb) {
+               if (netif_msg_rx_err(priv) && net_ratelimit())
+                       dev_err(emac_dev, "failed rx buffer alloc\n");
+               return;
        }
-       BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-       frame_status = curr_bd->mode;
-       while ((curr_bd) &&
-             ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
-             (pkts_processed < budget)) {
-               emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd, priv));
-               txch->active_queue_head = curr_bd->next;
-               if (frame_status & EMAC_CPPI_EOQ_BIT) {
-                       if (curr_bd->next) {    /* misqueued packet */
-                               emac_write(EMAC_TXHDP(ch), curr_bd->h_next);
-                               ++txch->mis_queued_packets;
-                       } else {
-                               txch->queue_active = 0; /* end of queue */
-                       }
-               }
 
-               dma_unmap_single(emac_dev, curr_bd->buff_ptr,
-                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
-                               DMA_TO_DEVICE);
-
-               *tx_complete_ptr = (u32) curr_bd->buf_token;
-               ++tx_complete_ptr;
-               ++tx_complete_cnt;
-               curr_bd->next = txch->bd_pool_head;
-               txch->bd_pool_head = curr_bd;
-               --txch->active_queue_count;
-               pkts_processed++;
-               txch->last_hw_bdprocessed = curr_bd;
-               curr_bd = txch->active_queue_head;
-               if (curr_bd) {
-                       BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-                       frame_status = curr_bd->mode;
-               }
-       } /* end of pkt processing loop */
-
-       emac_net_tx_complete(priv,
-                            (void *)&txch->tx_complete[0],
-                            tx_complete_cnt, ch);
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-       return pkts_processed;
+recycle:
+       ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
+                       skb_tailroom(skb), GFP_KERNEL);
+       if (WARN_ON(ret < 0))
+               dev_kfree_skb_any(skb);
 }
 
-#define EMAC_ERR_TX_OUT_OF_BD -1
-
-/**
- * emac_send: EMAC Transmit function (internal)
- * @priv: The DaVinci EMAC private adapter structure
- * @pkt: packet pointer (contains skb ptr)
- * @ch: TX channel number
- *
- * Called by the transmit function to queue the packet in EMAC hardware queue
- *
- * Returns success(0) or error code (typically out of desc's)
- */
-static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
+static void emac_tx_handler(void *token, int len, int status)
 {
-       unsigned long flags;
-       struct emac_tx_bd __iomem *curr_bd;
-       struct emac_txch *txch;
-       struct emac_netbufobj *buf_list;
-
-       txch = priv->txch[ch];
-       buf_list = pkt->buf_list;   /* get handle to the buffer array */
-
-       /* check packet size and pad if short */
-       if (pkt->pkt_length < EMAC_DEF_MIN_ETHPKTSIZE) {
-               buf_list->length += (EMAC_DEF_MIN_ETHPKTSIZE - pkt->pkt_length);
-               pkt->pkt_length = EMAC_DEF_MIN_ETHPKTSIZE;
-       }
+       struct sk_buff          *skb = token;
+       struct net_device       *ndev = skb->dev;
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       curr_bd = txch->bd_pool_head;
-       if (curr_bd == NULL) {
-               txch->out_of_tx_bd++;
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
-               return EMAC_ERR_TX_OUT_OF_BD;
-       }
-
-       txch->bd_pool_head = curr_bd->next;
-       curr_bd->buf_token = buf_list->buf_token;
-       curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buf_list->data_ptr,
-                       buf_list->length, DMA_TO_DEVICE);
-       curr_bd->off_b_len = buf_list->length;
-       curr_bd->h_next = 0;
-       curr_bd->next = NULL;
-       curr_bd->mode = (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT |
-                        EMAC_CPPI_EOP_BIT | pkt->pkt_length);
-
-       /* flush the packet from cache if write back cache is present */
-       BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-
-       /* send the packet */
-       if (txch->active_queue_head == NULL) {
-               txch->active_queue_head = curr_bd;
-               txch->active_queue_tail = curr_bd;
-               if (1 != txch->queue_active) {
-                       emac_write(EMAC_TXHDP(ch),
-                                       emac_virt_to_phys(curr_bd, priv));
-                       txch->queue_active = 1;
-               }
-               ++txch->queue_reinit;
-       } else {
-               register struct emac_tx_bd __iomem *tail_bd;
-               register u32 frame_status;
-
-               tail_bd = txch->active_queue_tail;
-               tail_bd->next = curr_bd;
-               txch->active_queue_tail = curr_bd;
-               tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
-               tail_bd->h_next = (int)emac_virt_to_phys(curr_bd, priv);
-               frame_status = tail_bd->mode;
-               if (frame_status & EMAC_CPPI_EOQ_BIT) {
-                       emac_write(EMAC_TXHDP(ch),
-                               emac_virt_to_phys(curr_bd, priv));
-                       frame_status &= ~(EMAC_CPPI_EOQ_BIT);
-                       tail_bd->mode = frame_status;
-                       ++txch->end_of_queue_add;
-               }
-       }
-       txch->active_queue_count++;
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-       return 0;
+       if (unlikely(netif_queue_stopped(ndev)))
+               netif_start_queue(ndev);
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += len;
+       dev_kfree_skb_any(skb);
 }
 
 /**
@@ -1565,42 +1067,36 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct device *emac_dev = &ndev->dev;
        int ret_code;
-       struct emac_netbufobj tx_buf; /* buffer obj-only single frame support */
-       struct emac_netpktobj tx_packet;  /* packet object */
        struct emac_priv *priv = netdev_priv(ndev);
 
        /* If no link, return */
        if (unlikely(!priv->link)) {
                if (netif_msg_tx_err(priv) && net_ratelimit())
                        dev_err(emac_dev, "DaVinci EMAC: No link to transmit");
-               return NETDEV_TX_BUSY;
+               goto fail_tx;
+       }
+
+       ret_code = skb_padto(skb, EMAC_DEF_MIN_ETHPKTSIZE);
+       if (unlikely(ret_code < 0)) {
+               if (netif_msg_tx_err(priv) && net_ratelimit())
+                       dev_err(emac_dev, "DaVinci EMAC: packet pad failed");
+               goto fail_tx;
        }
 
-       /* Build the buffer and packet objects - Since only single fragment is
-        * supported, need not set length and token in both packet & object.
-        * Doing so for completeness sake & to show that this needs to be done
-        * in multifragment case
-        */
-       tx_packet.buf_list = &tx_buf;
-       tx_packet.num_bufs = 1; /* only single fragment supported */
-       tx_packet.pkt_length = skb->len;
-       tx_packet.pkt_token = (void *)skb;
-       tx_buf.length = skb->len;
-       tx_buf.buf_token = (void *)skb;
-       tx_buf.data_ptr = skb->data;
-       ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH);
+       ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
+                                    GFP_KERNEL);
        if (unlikely(ret_code != 0)) {
-               if (ret_code == EMAC_ERR_TX_OUT_OF_BD) {
-                       if (netif_msg_tx_err(priv) && net_ratelimit())
-                               dev_err(emac_dev, "DaVinci EMAC: xmit() fatal"\
-                                       " err. Out of TX BD's");
-                       netif_stop_queue(priv->ndev);
-               }
-               ndev->stats.tx_dropped++;
-               return NETDEV_TX_BUSY;
+               if (netif_msg_tx_err(priv) && net_ratelimit())
+                       dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
+               goto fail_tx;
        }
 
        return NETDEV_TX_OK;
+
+fail_tx:
+       ndev->stats.tx_dropped++;
+       netif_stop_queue(ndev);
+       return NETDEV_TX_BUSY;
 }
 
 /**
@@ -1621,217 +1117,15 @@ static void emac_dev_tx_timeout(struct net_device *ndev)
        if (netif_msg_tx_err(priv))
                dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX");
 
+       emac_dump_regs(priv);
+
        ndev->stats.tx_errors++;
        emac_int_disable(priv);
-       emac_stop_txch(priv, EMAC_DEF_TX_CH);
-       emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
-       emac_init_txch(priv, EMAC_DEF_TX_CH);
-       emac_write(EMAC_TXHDP(0), 0);
-       emac_write(EMAC_TXINTMASKSET, BIT(EMAC_DEF_TX_CH));
+       cpdma_chan_stop(priv->txchan);
+       cpdma_chan_start(priv->txchan);
        emac_int_enable(priv);
 }
 
-/**
- * emac_net_alloc_rx_buf: Allocate a skb for RX
- * @priv: The DaVinci EMAC private adapter structure
- * @buf_size: size of SKB data buffer to allocate
- * @data_token: data token returned (skb handle for storing in buffer desc)
- * @ch: RX channel number
- *
- * Called during RX channel setup - allocates skb buffer of required size
- * and provides the skb handle and allocated buffer data pointer to caller
- *
- * Returns skb data pointer or 0 on failure to alloc skb
- */
-static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size,
-               void **data_token, u32 ch)
-{
-       struct net_device *ndev = priv->ndev;
-       struct device *emac_dev = &ndev->dev;
-       struct sk_buff *p_skb;
-
-       p_skb = dev_alloc_skb(buf_size);
-       if (unlikely(NULL == p_skb)) {
-               if (netif_msg_rx_err(priv) && net_ratelimit())
-                       dev_err(emac_dev, "DaVinci EMAC: failed to alloc skb");
-               return NULL;
-       }
-
-       /* set device pointer in skb and reserve space for extra bytes */
-       p_skb->dev = ndev;
-       skb_reserve(p_skb, NET_IP_ALIGN);
-       *data_token = (void *) p_skb;
-       return p_skb->data;
-}
-
-/**
- * emac_init_rxch: RX channel initialization
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- * @param: mac address for RX channel
- *
- * Called during device init to setup a RX channel (allocate buffers and
- * buffer descriptors, create queue and keep ready for reception
- *
- * Returns success(0) or mem alloc failures error code
- */
-static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)
-{
-       struct device *emac_dev = &priv->ndev->dev;
-       u32 cnt, bd_size;
-       void __iomem *mem;
-       struct emac_rx_bd __iomem *curr_bd;
-       struct emac_rxch *rxch = NULL;
-
-       rxch = kzalloc(sizeof(struct emac_rxch), GFP_KERNEL);
-       if (NULL == rxch) {
-               dev_err(emac_dev, "DaVinci EMAC: RX Ch mem alloc failed");
-               return -ENOMEM;
-       }
-       priv->rxch[ch] = rxch;
-       rxch->buf_size = priv->rx_buf_size;
-       rxch->service_max = EMAC_DEF_RX_MAX_SERVICE;
-       rxch->queue_active = 0;
-       rxch->teardown_pending = 0;
-
-       /* save mac address */
-       for (cnt = 0; cnt < 6; cnt++)
-               rxch->mac_addr[cnt] = param[cnt];
-
-       /* allocate buffer descriptor pool align every BD on four word
-        * boundry for future requirements */
-       bd_size = (sizeof(struct emac_rx_bd) + 0xF) & ~0xF;
-       rxch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size;
-       rxch->alloc_size = (((bd_size * rxch->num_bd) + 0xF) & ~0xF);
-       rxch->bd_mem = EMAC_RX_BD_MEM(priv);
-       __memzero((void __force *)rxch->bd_mem, rxch->alloc_size);
-       rxch->pkt_queue.buf_list = &rxch->buf_queue;
-
-       /* allocate RX buffer and initialize the BD linked list */
-       mem = (void __force __iomem *)
-                       (((u32 __force) rxch->bd_mem + 0xF) & ~0xF);
-       rxch->active_queue_head = NULL;
-       rxch->active_queue_tail = mem;
-       for (cnt = 0; cnt < rxch->num_bd; cnt++) {
-               curr_bd = mem + (cnt * bd_size);
-               /* for future use the last parameter contains the BD ptr */
-               curr_bd->data_ptr = emac_net_alloc_rx_buf(priv,
-                                   rxch->buf_size,
-                                   (void __force **)&curr_bd->buf_token,
-                                   EMAC_DEF_RX_CH);
-               if (curr_bd->data_ptr == NULL) {
-                       dev_err(emac_dev, "DaVinci EMAC: RX buf mem alloc " \
-                               "failed for ch %d\n", ch);
-                       kfree(rxch);
-                       return -ENOMEM;
-               }
-
-               /* populate the hardware descriptor */
-               curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,
-                               priv);
-               curr_bd->buff_ptr = dma_map_single(emac_dev, curr_bd->data_ptr,
-                               rxch->buf_size, DMA_FROM_DEVICE);
-               curr_bd->off_b_len = rxch->buf_size;
-               curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
-
-               /* write back to hardware memory */
-               BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd,
-                                             EMAC_BD_LENGTH_FOR_CACHE);
-               curr_bd->next = rxch->active_queue_head;
-               rxch->active_queue_head = curr_bd;
-       }
-
-       /* At this point rxCppi->activeQueueHead points to the first
-          RX BD ready to be given to RX HDP and rxch->active_queue_tail
-          points to the last RX BD
-        */
-       return 0;
-}
-
-/**
- * emac_rxch_teardown: RX channel teardown
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to teardown RX channel
- *
- */
-static void emac_rxch_teardown(struct emac_priv *priv, u32 ch)
-{
-       struct device *emac_dev = &priv->ndev->dev;
-       u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */
-
-       while ((emac_read(EMAC_RXCP(ch)) & EMAC_TEARDOWN_VALUE) !=
-              EMAC_TEARDOWN_VALUE) {
-               /* wait till tx teardown complete */
-               cpu_relax(); /* TODO: check if this helps ... */
-               --teardown_cnt;
-               if (0 == teardown_cnt) {
-                       dev_err(emac_dev, "EMAC: RX teardown aborted\n");
-                       break;
-               }
-       }
-       emac_write(EMAC_RXCP(ch), EMAC_TEARDOWN_VALUE);
-}
-
-/**
- * emac_stop_rxch: Stop RX channel operation
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to stop RX channel operation
- *
- */
-static void emac_stop_rxch(struct emac_priv *priv, u32 ch)
-{
-       struct emac_rxch *rxch = priv->rxch[ch];
-
-       if (rxch) {
-               rxch->teardown_pending = 1;
-               emac_write(EMAC_RXTEARDOWN, ch);
-               /* wait for teardown complete */
-               emac_rxch_teardown(priv, ch);
-               rxch->teardown_pending = 0;
-               emac_write(EMAC_RXINTMASKCLEAR, BIT(ch));
-       }
-}
-
-/**
- * emac_cleanup_rxch: Book-keep function to clean RX channel resources
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to clean up RX channel resources
- *
- */
-static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch)
-{
-       struct emac_rxch *rxch = priv->rxch[ch];
-       struct emac_rx_bd __iomem *curr_bd;
-
-       if (rxch) {
-               /* free the receive buffers previously allocated */
-               curr_bd = rxch->active_queue_head;
-               while (curr_bd) {
-                       if (curr_bd->buf_token) {
-                               dma_unmap_single(&priv->ndev->dev,
-                                       curr_bd->buff_ptr,
-                                       curr_bd->off_b_len
-                                               & EMAC_RX_BD_BUF_SIZE,
-                                       DMA_FROM_DEVICE);
-
-                               dev_kfree_skb_any((struct sk_buff *)\
-                                                 curr_bd->buf_token);
-                       }
-                       curr_bd = curr_bd->next;
-               }
-               if (rxch->bd_mem)
-                       rxch->bd_mem = NULL;
-               kfree(rxch);
-               priv->rxch[ch] = NULL;
-       }
-}
-
 /**
  * emac_set_type0addr: Set EMAC Type0 mac address
  * @priv: The DaVinci EMAC private adapter structure
@@ -1948,7 +1242,6 @@ static void emac_setmac(struct emac_priv *priv, u32 ch, char *mac_addr)
 static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
 {
        struct emac_priv *priv = netdev_priv(ndev);
-       struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH];
        struct device *emac_dev = &priv->ndev->dev;
        struct sockaddr *sa = addr;
 
@@ -1959,11 +1252,10 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
        memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
 
-       /* If the interface is down - rxch is NULL. */
        /* MAC address is configured only after the interface is enabled. */
        if (netif_running(ndev)) {
-               memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
-               emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+               memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
+               emac_setmac(priv, EMAC_DEF_RX_CH, priv->mac_addr);
        }
 
        if (netif_msg_drv(priv))
@@ -1973,194 +1265,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        return 0;
 }
 
-/**
- * emac_addbd_to_rx_queue: Recycle RX buffer descriptor
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number to process buffer descriptors for
- * @curr_bd: current buffer descriptor
- * @buffer: buffer pointer for descriptor
- * @buf_token: buffer token (stores skb information)
- *
- * Prepares the recycled buffer descriptor and addes it to hardware
- * receive queue - if queue empty this descriptor becomes the head
- * else addes the descriptor to end of queue
- *
- */
-static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
-               struct emac_rx_bd __iomem *curr_bd,
-               char *buffer, void *buf_token)
-{
-       struct emac_rxch *rxch = priv->rxch[ch];
-
-       /* populate the hardware descriptor */
-       curr_bd->h_next = 0;
-       curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buffer,
-                               rxch->buf_size, DMA_FROM_DEVICE);
-       curr_bd->off_b_len = rxch->buf_size;
-       curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
-       curr_bd->next = NULL;
-       curr_bd->data_ptr = buffer;
-       curr_bd->buf_token = buf_token;
-
-       /* write back  */
-       BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-       if (rxch->active_queue_head == NULL) {
-               rxch->active_queue_head = curr_bd;
-               rxch->active_queue_tail = curr_bd;
-               if (0 != rxch->queue_active) {
-                       emac_write(EMAC_RXHDP(ch),
-                          emac_virt_to_phys(rxch->active_queue_head, priv));
-                       rxch->queue_active = 1;
-               }
-       } else {
-               struct emac_rx_bd __iomem *tail_bd;
-               u32 frame_status;
-
-               tail_bd = rxch->active_queue_tail;
-               rxch->active_queue_tail = curr_bd;
-               tail_bd->next = curr_bd;
-               tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
-               tail_bd->h_next = emac_virt_to_phys(curr_bd, priv);
-               frame_status = tail_bd->mode;
-               if (frame_status & EMAC_CPPI_EOQ_BIT) {
-                       emac_write(EMAC_RXHDP(ch),
-                                       emac_virt_to_phys(curr_bd, priv));
-                       frame_status &= ~(EMAC_CPPI_EOQ_BIT);
-                       tail_bd->mode = frame_status;
-                       ++rxch->end_of_queue_add;
-               }
-       }
-       ++rxch->recycled_bd;
-}
-
-/**
- * emac_net_rx_cb: Prepares packet and sends to upper layer
- * @priv: The DaVinci EMAC private adapter structure
- * @net_pkt_list: Network packet list (received packets)
- *
- * Invalidates packet buffer memory and sends the received packet to upper
- * layer
- *
- * Returns success or appropriate error code (none as of now)
- */
-static int emac_net_rx_cb(struct emac_priv *priv,
-                         struct emac_netpktobj *net_pkt_list)
-{
-       struct net_device *ndev = priv->ndev;
-       struct sk_buff *p_skb = net_pkt_list->pkt_token;
-       /* set length of packet */
-       skb_put(p_skb, net_pkt_list->pkt_length);
-       p_skb->protocol = eth_type_trans(p_skb, priv->ndev);
-       netif_receive_skb(p_skb);
-       ndev->stats.rx_bytes += net_pkt_list->pkt_length;
-       ndev->stats.rx_packets++;
-       return 0;
-}
-
-/**
- * emac_rx_bdproc: RX buffer descriptor (packet) processing
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number to process buffer descriptors for
- * @budget: number of packets allowed to process
- * @pending: indication to caller that packets are pending to process
- *
- * Processes RX buffer descriptors - checks ownership bit on the RX buffer
- * descriptor, sends the receive packet to upper layer, allocates a new SKB
- * and recycles the buffer descriptor (requeues it in hardware RX queue).
- * Only "budget" number of packets are processed and indication of pending
- * packets provided to the caller.
- *
- * Returns number of packets processed (and indication of pending packets)
- */
-static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
-{
-       unsigned long flags;
-       u32 frame_status;
-       u32 pkts_processed = 0;
-       char *new_buffer;
-       struct emac_rx_bd __iomem *curr_bd;
-       struct emac_rx_bd __iomem *last_bd;
-       struct emac_netpktobj *curr_pkt, pkt_obj;
-       struct emac_netbufobj buf_obj;
-       struct emac_netbufobj *rx_buf_obj;
-       void *new_buf_token;
-       struct emac_rxch *rxch = priv->rxch[ch];
-
-       if (unlikely(1 == rxch->teardown_pending))
-               return 0;
-       ++rxch->proc_count;
-       spin_lock_irqsave(&priv->rx_lock, flags);
-       pkt_obj.buf_list = &buf_obj;
-       curr_pkt = &pkt_obj;
-       curr_bd = rxch->active_queue_head;
-       BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-       frame_status = curr_bd->mode;
-
-       while ((curr_bd) &&
-              ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
-              (pkts_processed < budget)) {
-
-               new_buffer = emac_net_alloc_rx_buf(priv, rxch->buf_size,
-                                       &new_buf_token, EMAC_DEF_RX_CH);
-               if (unlikely(NULL == new_buffer)) {
-                       ++rxch->out_of_rx_buffers;
-                       goto end_emac_rx_bdproc;
-               }
-
-               /* populate received packet data structure */
-               rx_buf_obj = &curr_pkt->buf_list[0];
-               rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;
-               rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;
-               rx_buf_obj->buf_token = curr_bd->buf_token;
-
-               dma_unmap_single(&priv->ndev->dev, curr_bd->buff_ptr,
-                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
-                               DMA_FROM_DEVICE);
-
-               curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;
-               curr_pkt->num_bufs = 1;
-               curr_pkt->pkt_length =
-                       (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK);
-               emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd, priv));
-               ++rxch->processed_bd;
-               last_bd = curr_bd;
-               curr_bd = last_bd->next;
-               rxch->active_queue_head = curr_bd;
-
-               /* check if end of RX queue ? */
-               if (frame_status & EMAC_CPPI_EOQ_BIT) {
-                       if (curr_bd) {
-                               ++rxch->mis_queued_packets;
-                               emac_write(EMAC_RXHDP(ch),
-                                          emac_virt_to_phys(curr_bd, priv));
-                       } else {
-                               ++rxch->end_of_queue;
-                               rxch->queue_active = 0;
-                       }
-               }
-
-               /* recycle BD */
-               emac_addbd_to_rx_queue(priv, ch, last_bd, new_buffer,
-                                      new_buf_token);
-
-               /* return the packet to the user - BD ptr passed in
-                * last parameter for potential *future* use */
-               spin_unlock_irqrestore(&priv->rx_lock, flags);
-               emac_net_rx_cb(priv, curr_pkt);
-               spin_lock_irqsave(&priv->rx_lock, flags);
-               curr_bd = rxch->active_queue_head;
-               if (curr_bd) {
-                       BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-                       frame_status = curr_bd->mode;
-               }
-               ++pkts_processed;
-       }
-
-end_emac_rx_bdproc:
-       spin_unlock_irqrestore(&priv->rx_lock, flags);
-       return pkts_processed;
-}
-
 /**
  * emac_hw_enable: Enable EMAC hardware for packet transmission/reception
  * @priv: The DaVinci EMAC private adapter structure
@@ -2172,7 +1276,7 @@ end_emac_rx_bdproc:
  */
 static int emac_hw_enable(struct emac_priv *priv)
 {
-       u32 ch, val, mbp_enable, mac_control;
+       u32 val, mbp_enable, mac_control;
 
        /* Soft reset */
        emac_write(EMAC_SOFTRESET, 1);
@@ -2215,26 +1319,9 @@ static int emac_hw_enable(struct emac_priv *priv)
        emac_write(EMAC_RXUNICASTCLEAR, EMAC_RX_UNICAST_CLEAR_ALL);
        priv->rx_addr_type = (emac_read(EMAC_MACCONFIG) >> 8) & 0xFF;
 
-       val = emac_read(EMAC_TXCONTROL);
-       val |= EMAC_TX_CONTROL_TX_ENABLE_VAL;
-       emac_write(EMAC_TXCONTROL, val);
-       val = emac_read(EMAC_RXCONTROL);
-       val |= EMAC_RX_CONTROL_RX_ENABLE_VAL;
-       emac_write(EMAC_RXCONTROL, val);
        emac_write(EMAC_MACINTMASKSET, EMAC_MAC_HOST_ERR_INTMASK_VAL);
 
-       for (ch = 0; ch < EMAC_DEF_MAX_TX_CH; ch++) {
-               emac_write(EMAC_TXHDP(ch), 0);
-               emac_write(EMAC_TXINTMASKSET, BIT(ch));
-       }
-       for (ch = 0; ch < EMAC_DEF_MAX_RX_CH; ch++) {
-               struct emac_rxch *rxch = priv->rxch[ch];
-               emac_setmac(priv, ch, rxch->mac_addr);
-               emac_write(EMAC_RXINTMASKSET, BIT(ch));
-               rxch->queue_active = 1;
-               emac_write(EMAC_RXHDP(ch),
-                          emac_virt_to_phys(rxch->active_queue_head, priv));
-       }
+       emac_setmac(priv, EMAC_DEF_RX_CH, priv->mac_addr);
 
        /* Enable MII */
        val = emac_read(EMAC_MACCONTROL);
@@ -2279,8 +1366,8 @@ static int emac_poll(struct napi_struct *napi, int budget)
                mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
 
        if (status & mask) {
-               num_tx_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
-                                         EMAC_DEF_TX_MAX_SERVICE);
+               num_tx_pkts = cpdma_chan_process(priv->txchan,
+                                             EMAC_DEF_TX_MAX_SERVICE);
        } /* TX processing */
 
        mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
@@ -2289,7 +1376,7 @@ static int emac_poll(struct napi_struct *napi, int budget)
                mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC;
 
        if (status & mask) {
-               num_rx_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
+               num_rx_pkts = cpdma_chan_process(priv->rxchan, budget);
        } /* RX processing */
 
        mask = EMAC_DM644X_MAC_IN_VECTOR_HOST_INT;
@@ -2348,79 +1435,6 @@ void emac_poll_controller(struct net_device *ndev)
 }
 #endif
 
-/* PHY/MII bus related */
-
-/* Wait until mdio is ready for next command */
-#define MDIO_WAIT_FOR_USER_ACCESS\
-               while ((emac_mdio_read((MDIO_USERACCESS(0))) &\
-                       MDIO_USERACCESS_GO) != 0)
-
-static int emac_mii_read(struct mii_bus *bus, int phy_id, int phy_reg)
-{
-       unsigned int phy_data = 0;
-       unsigned int phy_control;
-
-       /* Wait until mdio is ready for next command */
-       MDIO_WAIT_FOR_USER_ACCESS;
-
-       phy_control = (MDIO_USERACCESS_GO |
-                      MDIO_USERACCESS_READ |
-                      ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
-                      ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
-                      (phy_data & MDIO_USERACCESS_DATA));
-       emac_mdio_write(MDIO_USERACCESS(0), phy_control);
-
-       /* Wait until mdio is ready for next command */
-       MDIO_WAIT_FOR_USER_ACCESS;
-
-       return emac_mdio_read(MDIO_USERACCESS(0)) & MDIO_USERACCESS_DATA;
-
-}
-
-static int emac_mii_write(struct mii_bus *bus, int phy_id,
-                         int phy_reg, u16 phy_data)
-{
-
-       unsigned int control;
-
-       /*  until mdio is ready for next command */
-       MDIO_WAIT_FOR_USER_ACCESS;
-
-       control = (MDIO_USERACCESS_GO |
-                  MDIO_USERACCESS_WRITE |
-                  ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
-                  ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
-                  (phy_data & MDIO_USERACCESS_DATA));
-       emac_mdio_write(MDIO_USERACCESS(0), control);
-
-       return 0;
-}
-
-static int emac_mii_reset(struct mii_bus *bus)
-{
-       unsigned int clk_div;
-       int mdio_bus_freq = emac_bus_frequency;
-
-       if (mdio_max_freq && mdio_bus_freq)
-               clk_div = ((mdio_bus_freq / mdio_max_freq) - 1);
-       else
-               clk_div = 0xFF;
-
-       clk_div &= MDIO_CONTROL_CLKDIV;
-
-       /* Set enable and clock divider in MDIOControl */
-       emac_mdio_write(MDIO_CONTROL, (clk_div | MDIO_CONTROL_ENABLE));
-
-       return 0;
-
-}
-
-static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, PHY_POLL };
-
-/* emac_driver: EMAC MII bus structure */
-
-static struct mii_bus *emac_mii;
-
 static void emac_adjust_link(struct net_device *ndev)
 {
        struct emac_priv *priv = netdev_priv(ndev);
@@ -2485,6 +1499,11 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
        return -EOPNOTSUPP;
 }
 
+static int match_first_device(struct device *dev, void *data)
+{
+       return 1;
+}
+
 /**
  * emac_dev_open: EMAC device open
  * @ndev: The DaVinci EMAC network adapter
@@ -2498,10 +1517,9 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
 static int emac_dev_open(struct net_device *ndev)
 {
        struct device *emac_dev = &ndev->dev;
-       u32 rc, cnt, ch;
-       int phy_addr;
+       u32 cnt;
        struct resource *res;
-       int q, m;
+       int q, m, ret;
        int i = 0;
        int k = 0;
        struct emac_priv *priv = netdev_priv(ndev);
@@ -2513,29 +1531,21 @@ static int emac_dev_open(struct net_device *ndev)
        /* Configuration items */
        priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + NET_IP_ALIGN;
 
-       /* Clear basic hardware */
-       for (ch = 0; ch < EMAC_MAX_TXRX_CHANNELS; ch++) {
-               emac_write(EMAC_TXHDP(ch), 0);
-               emac_write(EMAC_RXHDP(ch), 0);
-               emac_write(EMAC_RXHDP(ch), 0);
-               emac_write(EMAC_RXINTMASKCLEAR, EMAC_INT_MASK_CLEAR);
-               emac_write(EMAC_TXINTMASKCLEAR, EMAC_INT_MASK_CLEAR);
-       }
        priv->mac_hash1 = 0;
        priv->mac_hash2 = 0;
        emac_write(EMAC_MACHASH1, 0);
        emac_write(EMAC_MACHASH2, 0);
 
-       /* multi ch not supported - open 1 TX, 1RX ch by default */
-       rc = emac_init_txch(priv, EMAC_DEF_TX_CH);
-       if (0 != rc) {
-               dev_err(emac_dev, "DaVinci EMAC: emac_init_txch() failed");
-               return rc;
-       }
-       rc = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr);
-       if (0 != rc) {
-               dev_err(emac_dev, "DaVinci EMAC: emac_init_rxch() failed");
-               return rc;
+       for (i = 0; i < EMAC_DEF_RX_NUM_DESC; i++) {
+               struct sk_buff *skb = emac_rx_alloc(priv);
+
+               if (!skb)
+                       break;
+
+               ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
+                                       skb_tailroom(skb), GFP_KERNEL);
+               if (WARN_ON(ret < 0))
+                       break;
        }
 
        /* Request IRQ */
@@ -2560,28 +1570,28 @@ static int emac_dev_open(struct net_device *ndev)
                emac_set_coalesce(ndev, &coal);
        }
 
-       /* find the first phy */
+       cpdma_ctlr_start(priv->dma);
+
        priv->phydev = NULL;
-       if (priv->phy_mask) {
-               emac_mii_reset(priv->mii_bus);
-               for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-                       if (priv->mii_bus->phy_map[phy_addr]) {
-                               priv->phydev = priv->mii_bus->phy_map[phy_addr];
-                               break;
-                       }
-               }
+       /* use the first phy on the bus if pdata did not give us a phy id */
+       if (!priv->phy_id) {
+               struct device *phy;
 
-               if (!priv->phydev) {
-                       printk(KERN_ERR "%s: no PHY found\n", ndev->name);
-                       return -1;
-               }
+               phy = bus_find_device(&mdio_bus_type, NULL, NULL,
+                                     match_first_device);
+               if (phy)
+                       priv->phy_id = dev_name(phy);
+       }
 
-               priv->phydev = phy_connect(ndev, dev_name(&priv->phydev->dev),
-                               &emac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+       if (priv->phy_id && *priv->phy_id) {
+               priv->phydev = phy_connect(ndev, priv->phy_id,
+                                          &emac_adjust_link, 0,
+                                          PHY_INTERFACE_MODE_MII);
 
                if (IS_ERR(priv->phydev)) {
-                       printk(KERN_ERR "%s: Could not attach to PHY\n",
-                                                               ndev->name);
+                       dev_err(emac_dev, "could not connect to phy %s\n",
+                               priv->phy_id);
+                       priv->phydev = NULL;
                        return PTR_ERR(priv->phydev);
                }
 
@@ -2589,12 +1599,13 @@ static int emac_dev_open(struct net_device *ndev)
                priv->speed = 0;
                priv->duplex = ~0;
 
-               printk(KERN_INFO "%s: attached PHY driver [%s] "
-                       "(mii_bus:phy_addr=%s, id=%x)\n", ndev->name,
+               dev_info(emac_dev, "attached PHY driver [%s] "
+                       "(mii_bus:phy_addr=%s, id=%x)\n",
                        priv->phydev->drv->name, dev_name(&priv->phydev->dev),
                        priv->phydev->phy_id);
-       } else{
+       } else {
                /* No PHY , fix the link, speed and duplex settings */
+               dev_notice(emac_dev, "no phy, defaulting to 100/full\n");
                priv->link = 1;
                priv->speed = SPEED_100;
                priv->duplex = DUPLEX_FULL;
@@ -2607,7 +1618,7 @@ static int emac_dev_open(struct net_device *ndev)
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: Opened %s\n", ndev->name);
 
-       if (priv->phy_mask)
+       if (priv->phydev)
                phy_start(priv->phydev);
 
        return 0;
@@ -2648,10 +1659,7 @@ static int emac_dev_stop(struct net_device *ndev)
 
        netif_carrier_off(ndev);
        emac_int_disable(priv);
-       emac_stop_txch(priv, EMAC_DEF_TX_CH);
-       emac_stop_rxch(priv, EMAC_DEF_RX_CH);
-       emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
-       emac_cleanup_rxch(priv, EMAC_DEF_RX_CH);
+       cpdma_ctlr_stop(priv->dma);
        emac_write(EMAC_SOFTRESET, 1);
 
        if (priv->phydev)
@@ -2756,9 +1764,10 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        struct resource *res;
        struct net_device *ndev;
        struct emac_priv *priv;
-       unsigned long size;
+       unsigned long size, hw_ram_addr;
        struct emac_platform_data *pdata;
        struct device *emac_dev;
+       struct cpdma_params dma_params;
 
        /* obtain emac clock from kernel */
        emac_clk = clk_get(&pdev->dev, NULL);
@@ -2782,8 +1791,6 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        priv->ndev = ndev;
        priv->msg_enable = netif_msg_init(debug_level, DAVINCI_EMAC_DEBUG);
 
-       spin_lock_init(&priv->tx_lock);
-       spin_lock_init(&priv->rx_lock);
        spin_lock_init(&priv->lock);
 
        pdata = pdev->dev.platform_data;
@@ -2794,7 +1801,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
 
        /* MAC addr and PHY mask , RMII enable info from platform_data */
        memcpy(priv->mac_addr, pdata->mac_addr, 6);
-       priv->phy_mask = pdata->phy_mask;
+       priv->phy_id = pdata->phy_id;
        priv->rmii_en = pdata->rmii_en;
        priv->version = pdata->version;
        priv->int_enable = pdata->interrupt_enable;
@@ -2831,14 +1838,41 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        ndev->base_addr = (unsigned long)priv->remap_addr;
 
        priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset;
-       priv->ctrl_ram_size = pdata->ctrl_ram_size;
-       priv->emac_ctrl_ram = priv->remap_addr + pdata->ctrl_ram_offset;
 
-       if (pdata->hw_ram_addr)
-               priv->hw_ram_addr = pdata->hw_ram_addr;
-       else
-               priv->hw_ram_addr = (u32 __force)res->start +
-                                       pdata->ctrl_ram_offset;
+       hw_ram_addr = pdata->hw_ram_addr;
+       if (!hw_ram_addr)
+               hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset;
+
+       memset(&dma_params, 0, sizeof(dma_params));
+       dma_params.dev                  = emac_dev;
+       dma_params.dmaregs              = priv->emac_base;
+       dma_params.rxthresh             = priv->emac_base + 0x120;
+       dma_params.rxfree               = priv->emac_base + 0x140;
+       dma_params.txhdp                = priv->emac_base + 0x600;
+       dma_params.rxhdp                = priv->emac_base + 0x620;
+       dma_params.txcp                 = priv->emac_base + 0x640;
+       dma_params.rxcp                 = priv->emac_base + 0x660;
+       dma_params.num_chan             = EMAC_MAX_TXRX_CHANNELS;
+       dma_params.min_packet_size      = EMAC_DEF_MIN_ETHPKTSIZE;
+       dma_params.desc_mem_phys        = hw_ram_addr;
+       dma_params.desc_mem_size        = pdata->ctrl_ram_size;
+       dma_params.desc_align           = 16;
+
+       priv->dma = cpdma_ctlr_create(&dma_params);
+       if (!priv->dma) {
+               dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n");
+               rc = -ENOMEM;
+               goto no_dma;
+       }
+
+       priv->txchan = cpdma_chan_create(priv->dma, tx_chan_num(EMAC_DEF_TX_CH),
+                                      emac_tx_handler);
+       priv->rxchan = cpdma_chan_create(priv->dma, rx_chan_num(EMAC_DEF_RX_CH),
+                                      emac_rx_handler);
+       if (WARN_ON(!priv->txchan || !priv->rxchan)) {
+               rc = -ENOMEM;
+               goto no_irq_res;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -2871,32 +1905,6 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        }
 
 
-       /* MII/Phy intialisation, mdio bus registration */
-       emac_mii = mdiobus_alloc();
-       if (emac_mii == NULL) {
-               dev_err(emac_dev, "DaVinci EMAC: Error allocating mii_bus\n");
-               rc = -ENOMEM;
-               goto mdio_alloc_err;
-       }
-
-       priv->mii_bus = emac_mii;
-       emac_mii->name  = "emac-mii",
-       emac_mii->read  = emac_mii_read,
-       emac_mii->write = emac_mii_write,
-       emac_mii->reset = emac_mii_reset,
-       emac_mii->irq   = mii_irqs,
-       emac_mii->phy_mask = ~(priv->phy_mask);
-       emac_mii->parent = &pdev->dev;
-       emac_mii->priv = priv->remap_addr + pdata->mdio_reg_offset;
-       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", priv->pdev->id);
-       mdio_max_freq = pdata->mdio_max_freq;
-       emac_mii->reset(emac_mii);
-
-       /* Register the MII bus */
-       rc = mdiobus_register(emac_mii);
-       if (rc)
-               goto mdiobus_quit;
-
        if (netif_msg_probe(priv)) {
                dev_notice(emac_dev, "DaVinci EMAC Probe found device "\
                           "(regs: %p, irq: %d)\n",
@@ -2904,13 +1912,15 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        }
        return 0;
 
-mdiobus_quit:
-       mdiobus_free(emac_mii);
-
 netdev_reg_err:
-mdio_alloc_err:
        clk_disable(emac_clk);
 no_irq_res:
+       if (priv->txchan)
+               cpdma_chan_destroy(priv->txchan);
+       if (priv->rxchan)
+               cpdma_chan_destroy(priv->rxchan);
+       cpdma_ctlr_destroy(priv->dma);
+no_dma:
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, res->end - res->start + 1);
        iounmap(priv->remap_addr);
@@ -2938,8 +1948,12 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mdiobus_unregister(priv->mii_bus);
-       mdiobus_free(priv->mii_bus);
+
+       if (priv->txchan)
+               cpdma_chan_destroy(priv->txchan);
+       if (priv->rxchan)
+               cpdma_chan_destroy(priv->rxchan);
+       cpdma_ctlr_destroy(priv->dma);
 
        release_mem_region(res->start, res->end - res->start + 1);
 
diff --git a/drivers/net/davinci_mdio.c b/drivers/net/davinci_mdio.c
new file mode 100644 (file)
index 0000000..7615040
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * DaVinci MDIO Module driver
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Shamelessly ripped out of davinci_emac.c, original copyrights follow:
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/davinci_emac.h>
+
+/*
+ * This timeout definition is a worst-case ultra defensive measure against
+ * unexpected controller lock ups.  Ideally, we should never ever hit this
+ * scenario in practice.
+ */
+#define MDIO_TIMEOUT           100 /* msecs */
+
+#define PHY_REG_MASK           0x1f
+#define PHY_ID_MASK            0x1f
+
+#define DEF_OUT_FREQ           2200000         /* 2.2 MHz */
+
+struct davinci_mdio_regs {
+       u32     version;
+       u32     control;
+#define CONTROL_IDLE           BIT(31)
+#define CONTROL_ENABLE         BIT(30)
+#define CONTROL_MAX_DIV                (0xff)
+
+       u32     alive;
+       u32     link;
+       u32     linkintraw;
+       u32     linkintmasked;
+       u32     __reserved_0[2];
+       u32     userintraw;
+       u32     userintmasked;
+       u32     userintmaskset;
+       u32     userintmaskclr;
+       u32     __reserved_1[20];
+
+       struct {
+               u32     access;
+#define USERACCESS_GO          BIT(31)
+#define USERACCESS_WRITE       BIT(30)
+#define USERACCESS_ACK         BIT(29)
+#define USERACCESS_READ                (0)
+#define USERACCESS_DATA                (0xffff)
+
+               u32     physel;
+       }       user[0];
+};
+
+struct mdio_platform_data default_pdata = {
+       .bus_freq = DEF_OUT_FREQ,
+};
+
+struct davinci_mdio_data {
+       struct mdio_platform_data pdata;
+       struct davinci_mdio_regs __iomem *regs;
+       spinlock_t      lock;
+       struct clk      *clk;
+       struct device   *dev;
+       struct mii_bus  *bus;
+       bool            suspended;
+       unsigned long   access_time; /* jiffies */
+};
+
+static void __davinci_mdio_reset(struct davinci_mdio_data *data)
+{
+       u32 mdio_in, div, mdio_out_khz, access_time;
+
+       mdio_in = clk_get_rate(data->clk);
+       div = (mdio_in / data->pdata.bus_freq) - 1;
+       if (div > CONTROL_MAX_DIV)
+               div = CONTROL_MAX_DIV;
+
+       /* set enable and clock divider */
+       __raw_writel(div | CONTROL_ENABLE, &data->regs->control);
+
+       /*
+        * One mdio transaction consists of:
+        *      32 bits of preamble
+        *      32 bits of transferred data
+        *      24 bits of bus yield (not needed unless shared?)
+        */
+       mdio_out_khz = mdio_in / (1000 * (div + 1));
+       access_time  = (88 * 1000) / mdio_out_khz;
+
+       /*
+        * In the worst case, we could be kicking off a user-access immediately
+        * after the mdio bus scan state-machine triggered its own read.  If
+        * so, our request could get deferred by one access cycle.  We
+        * defensively allow for 4 access cycles.
+        */
+       data->access_time = usecs_to_jiffies(access_time * 4);
+       if (!data->access_time)
+               data->access_time = 1;
+}
+
+static int davinci_mdio_reset(struct mii_bus *bus)
+{
+       struct davinci_mdio_data *data = bus->priv;
+       u32 phy_mask, ver;
+
+       __davinci_mdio_reset(data);
+
+       /* wait for scan logic to settle */
+       msleep(PHY_MAX_ADDR * data->access_time);
+
+       /* dump hardware version info */
+       ver = __raw_readl(&data->regs->version);
+       dev_info(data->dev, "davinci mdio revision %d.%d\n",
+                (ver >> 8) & 0xff, ver & 0xff);
+
+       /* get phy mask from the alive register */
+       phy_mask = __raw_readl(&data->regs->alive);
+       if (phy_mask) {
+               /* restrict mdio bus to live phys only */
+               dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
+               phy_mask = ~phy_mask;
+       } else {
+               /* desperately scan all phys */
+               dev_warn(data->dev, "no live phy, scanning all\n");
+               phy_mask = 0;
+       }
+       data->bus->phy_mask = phy_mask;
+
+       return 0;
+}
+
+/* wait until hardware is ready for another user access */
+static inline int wait_for_user_access(struct davinci_mdio_data *data)
+{
+       struct davinci_mdio_regs __iomem *regs = data->regs;
+       unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
+       u32 reg;
+
+       while (time_after(timeout, jiffies)) {
+               reg = __raw_readl(&regs->user[0].access);
+               if ((reg & USERACCESS_GO) == 0)
+                       return 0;
+
+               reg = __raw_readl(&regs->control);
+               if ((reg & CONTROL_IDLE) == 0)
+                       continue;
+
+               /*
+                * An emac soft_reset may have clobbered the mdio controller's
+                * state machine.  We need to reset and retry the current
+                * operation
+                */
+               dev_warn(data->dev, "resetting idled controller\n");
+               __davinci_mdio_reset(data);
+               return -EAGAIN;
+       }
+       dev_err(data->dev, "timed out waiting for user access\n");
+       return -ETIMEDOUT;
+}
+
+/* wait until hardware state machine is idle */
+static inline int wait_for_idle(struct davinci_mdio_data *data)
+{
+       struct davinci_mdio_regs __iomem *regs = data->regs;
+       unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
+
+       while (time_after(timeout, jiffies)) {
+               if (__raw_readl(&regs->control) & CONTROL_IDLE)
+                       return 0;
+       }
+       dev_err(data->dev, "timed out waiting for idle\n");
+       return -ETIMEDOUT;
+}
+
+static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+       struct davinci_mdio_data *data = bus->priv;
+       u32 reg;
+       int ret;
+
+       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+               return -EINVAL;
+
+       spin_lock(&data->lock);
+
+       if (data->suspended) {
+               spin_unlock(&data->lock);
+               return -ENODEV;
+       }
+
+       reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
+              (phy_id << 16));
+
+       while (1) {
+               ret = wait_for_user_access(data);
+               if (ret == -EAGAIN)
+                       continue;
+               if (ret < 0)
+                       break;
+
+               __raw_writel(reg, &data->regs->user[0].access);
+
+               ret = wait_for_user_access(data);
+               if (ret == -EAGAIN)
+                       continue;
+               if (ret < 0)
+                       break;
+
+               reg = __raw_readl(&data->regs->user[0].access);
+               ret = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
+               break;
+       }
+
+       spin_unlock(&data->lock);
+
+       return ret;
+}
+
+static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
+                             int phy_reg, u16 phy_data)
+{
+       struct davinci_mdio_data *data = bus->priv;
+       u32 reg;
+       int ret;
+
+       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+               return -EINVAL;
+
+       spin_lock(&data->lock);
+
+       if (data->suspended) {
+               spin_unlock(&data->lock);
+               return -ENODEV;
+       }
+
+       reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
+                  (phy_id << 16) | (phy_data & USERACCESS_DATA));
+
+       while (1) {
+               ret = wait_for_user_access(data);
+               if (ret == -EAGAIN)
+                       continue;
+               if (ret < 0)
+                       break;
+
+               __raw_writel(reg, &data->regs->user[0].access);
+
+               ret = wait_for_user_access(data);
+               if (ret == -EAGAIN)
+                       continue;
+               break;
+       }
+
+       spin_unlock(&data->lock);
+
+       return 0;
+}
+
+static int __devinit davinci_mdio_probe(struct platform_device *pdev)
+{
+       struct mdio_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct davinci_mdio_data *data;
+       struct resource *res;
+       struct phy_device *phy;
+       int ret, addr;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "failed to alloc device data\n");
+               return -ENOMEM;
+       }
+
+       data->pdata = pdata ? (*pdata) : default_pdata;
+
+       data->bus = mdiobus_alloc();
+       if (!data->bus) {
+               dev_err(dev, "failed to alloc mii bus\n");
+               ret = -ENOMEM;
+               goto bail_out;
+       }
+
+       data->bus->name         = dev_name(dev);
+       data->bus->read         = davinci_mdio_read,
+       data->bus->write        = davinci_mdio_write,
+       data->bus->reset        = davinci_mdio_reset,
+       data->bus->parent       = dev;
+       data->bus->priv         = data;
+       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+
+       data->clk = clk_get(dev, NULL);
+       if (IS_ERR(data->clk)) {
+               data->clk = NULL;
+               dev_err(dev, "failed to get device clock\n");
+               ret = PTR_ERR(data->clk);
+               goto bail_out;
+       }
+
+       clk_enable(data->clk);
+
+       dev_set_drvdata(dev, data);
+       data->dev = dev;
+       spin_lock_init(&data->lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "could not find register map resource\n");
+               ret = -ENOENT;
+               goto bail_out;
+       }
+
+       res = devm_request_mem_region(dev, res->start, resource_size(res),
+                                           dev_name(dev));
+       if (!res) {
+               dev_err(dev, "could not allocate register map resource\n");
+               ret = -ENXIO;
+               goto bail_out;
+       }
+
+       data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
+       if (!data->regs) {
+               dev_err(dev, "could not map mdio registers\n");
+               ret = -ENOMEM;
+               goto bail_out;
+       }
+
+       /* register the mii bus */
+       ret = mdiobus_register(data->bus);
+       if (ret)
+               goto bail_out;
+
+       /* scan and dump the bus */
+       for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+               phy = data->bus->phy_map[addr];
+               if (phy) {
+                       dev_info(dev, "phy[%d]: device %s, driver %s\n",
+                                phy->addr, dev_name(&phy->dev),
+                                phy->drv ? phy->drv->name : "unknown");
+               }
+       }
+
+       return 0;
+
+bail_out:
+       if (data->bus)
+               mdiobus_free(data->bus);
+
+       if (data->clk) {
+               clk_disable(data->clk);
+               clk_put(data->clk);
+       }
+
+       kfree(data);
+
+       return ret;
+}
+
+static int __devexit davinci_mdio_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct davinci_mdio_data *data = dev_get_drvdata(dev);
+
+       if (data->bus)
+               mdiobus_free(data->bus);
+
+       if (data->clk) {
+               clk_disable(data->clk);
+               clk_put(data->clk);
+       }
+
+       dev_set_drvdata(dev, NULL);
+
+       kfree(data);
+
+       return 0;
+}
+
+static int davinci_mdio_suspend(struct device *dev)
+{
+       struct davinci_mdio_data *data = dev_get_drvdata(dev);
+       u32 ctrl;
+
+       spin_lock(&data->lock);
+
+       /* shutdown the scan state machine */
+       ctrl = __raw_readl(&data->regs->control);
+       ctrl &= ~CONTROL_ENABLE;
+       __raw_writel(ctrl, &data->regs->control);
+       wait_for_idle(data);
+
+       if (data->clk)
+               clk_disable(data->clk);
+
+       data->suspended = true;
+       spin_unlock(&data->lock);
+
+       return 0;
+}
+
+static int davinci_mdio_resume(struct device *dev)
+{
+       struct davinci_mdio_data *data = dev_get_drvdata(dev);
+       u32 ctrl;
+
+       spin_lock(&data->lock);
+       if (data->clk)
+               clk_enable(data->clk);
+
+       /* restart the scan state machine */
+       ctrl = __raw_readl(&data->regs->control);
+       ctrl |= CONTROL_ENABLE;
+       __raw_writel(ctrl, &data->regs->control);
+
+       data->suspended = false;
+       spin_unlock(&data->lock);
+
+       return 0;
+}
+
+static const struct dev_pm_ops davinci_mdio_pm_ops = {
+       .suspend        = davinci_mdio_suspend,
+       .resume         = davinci_mdio_resume,
+};
+
+static struct platform_driver davinci_mdio_driver = {
+       .driver = {
+               .name    = "davinci_mdio",
+               .owner   = THIS_MODULE,
+               .pm      = &davinci_mdio_pm_ops,
+       },
+       .probe = davinci_mdio_probe,
+       .remove = __devexit_p(davinci_mdio_remove),
+};
+
+static int __init davinci_mdio_init(void)
+{
+       return platform_driver_register(&davinci_mdio_driver);
+}
+device_initcall(davinci_mdio_init);
+
+static void __exit davinci_mdio_exit(void)
+{
+       platform_driver_unregister(&davinci_mdio_driver);
+}
+module_exit(davinci_mdio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DaVinci MDIO driver");
index 14390641704881ffb71ded6fd2d19118be07a4d6..f6e0d40cd876407ddf998ff846cf095cfaeddd4f 100644 (file)
@@ -124,6 +124,13 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
        return 0;
 }
 
+static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
+{
+       struct mlx4_en_dev *endev = ctx;
+
+       return endev->pndev[port];
+}
+
 static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
                          enum mlx4_dev_event event, int port)
 {
@@ -282,9 +289,11 @@ err_free_res:
 }
 
 static struct mlx4_interface mlx4_en_interface = {
-       .add    = mlx4_en_add,
-       .remove = mlx4_en_remove,
-       .event  = mlx4_en_event,
+       .add            = mlx4_en_add,
+       .remove         = mlx4_en_remove,
+       .event          = mlx4_en_event,
+       .get_dev        = mlx4_en_get_netdev,
+       .protocol       = MLX4_PROTOCOL_EN,
 };
 
 static int __init mlx4_en_init(void)
index 79478bd4211a958b369f9c8882351e3bcbb89424..6d6806b361e3145e31e654db0acef6152fec7b4b 100644 (file)
@@ -69,6 +69,7 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
        int err;
+       int idx;
 
        if (!priv->vlgrp)
                return;
@@ -83,7 +84,10 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
                if (err)
                        en_err(priv, "Failed configuring VLAN filter\n");
        }
+       if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx))
+               en_err(priv, "failed adding vlan %d\n", vid);
        mutex_unlock(&mdev->state_lock);
+
 }
 
 static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
@@ -91,6 +95,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
        int err;
+       int idx;
 
        if (!priv->vlgrp)
                return;
@@ -101,6 +106,11 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 
        /* Remove VID from port VLAN filter */
        mutex_lock(&mdev->state_lock);
+       if (!mlx4_find_cached_vlan(mdev->dev, priv->port, vid, &idx))
+               mlx4_unregister_vlan(mdev->dev, priv->port, idx);
+       else
+               en_err(priv, "could not find vid %d in cache\n", vid);
+
        if (mdev->device_up && priv->port_up) {
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
                if (err)
index aa3ef2aee5bf8435575a6f75a8e65502ebc09456..7f5a3221e0c1dc8c8c9071808e18e9f552c11eca 100644 (file)
@@ -127,8 +127,8 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
        memset(context, 0, sizeof *context);
 
        context->base_qpn = cpu_to_be32(base_qpn);
-       context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn);
-       context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_SHIFT | base_qpn);
+       context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn);
+       context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_MODE_SHIFT | base_qpn);
        context->intra_no_vlan = 0;
        context->no_vlan = MLX4_NO_VLAN_IDX;
        context->intra_vlan_miss = 0;
index f6511aa2b7dfba0a8fca919f606189be9b3a2a5b..092e814b19813bbff8fbef391b69b8acaf0cc291 100644 (file)
@@ -36,7 +36,8 @@
 
 
 #define SET_PORT_GEN_ALL_VALID 0x7
-#define SET_PORT_PROMISC_SHIFT 31
+#define SET_PORT_PROMISC_EN_SHIFT      31
+#define SET_PORT_PROMISC_MODE_SHIFT    30
 
 enum {
        MLX4_CMD_SET_VLAN_FLTR  = 0x47,
index b716e1a1b2982bae0f25b1ed57793c3ccc31aaa7..b68eee2414c208765849d0136dfb7cb0065f52ba 100644 (file)
@@ -98,7 +98,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
                [20] = "Address vector port checking support",
                [21] = "UD multicast support",
                [24] = "Demand paging support",
-               [25] = "Router support"
+               [25] = "Router support",
+               [30] = "IBoE support"
        };
        int i;
 
index 5550678027513fa6f7b443bffe63e72198f4ec1c..73c94fcdfddf0096318e4db7649a4c5a858e9f20 100644 (file)
@@ -161,3 +161,24 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
 
        mutex_unlock(&intf_mutex);
 }
+
+void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_device_context *dev_ctx;
+       unsigned long flags;
+       void *result = NULL;
+
+       spin_lock_irqsave(&priv->ctx_lock, flags);
+
+       list_for_each_entry(dev_ctx, &priv->ctx_list, list)
+               if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
+                       result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
+                       break;
+               }
+
+       spin_unlock_irqrestore(&priv->ctx_lock, flags);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
index 569fa3df381f8131bb6b91454a577bde8314500b..782f11d8fa71d52e2ae8549c41970c52cdb2cbb8 100644 (file)
@@ -103,7 +103,7 @@ MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
 
 static int log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG);
 module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
-MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");
+MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-7)");
 
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
@@ -1310,7 +1310,7 @@ static int __init mlx4_verify_params(void)
                return -1;
        }
 
-       if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
+       if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 7)) {
                pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
                return -1;
        }
index 1fc16ab7ad2f0ebc0d6b7b6d604e593ceb223e69..dfed6a07c2d77d34e9a6a8775afacfac76f07c6c 100644 (file)
@@ -475,6 +475,7 @@ struct mlx4_en_priv {
        char *mc_addrs;
        int mc_addrs_cnt;
        struct mlx4_en_stat_out_mbox hw_stats;
+       int vids[128];
 };
 
 
index 8674ad5764c4a7660a9b98ab4f2a11a7e9acb684..451339559bdc16bd64e07e124850f5280ef02b3d 100644 (file)
@@ -188,6 +188,25 @@ static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
        return err;
 }
 
+int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
+{
+       struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
+       int i;
+
+       for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
+               if (table->refs[i] &&
+                   (vid == (MLX4_VLAN_MASK &
+                             be32_to_cpu(table->entries[i])))) {
+                       /* VLAN already registered, increase reference count */
+                       *idx = i;
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
+
 int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
 {
        struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
index f3f8be5a35fac0a47a40a40f14ee6d40bb055549..14f0955eca68b37ed8f776fd83390339cacf1351 100644 (file)
@@ -430,8 +430,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
        }
 
        /* Get the protocol type of the ethernet frame that arrived */
-       proto_type = ((in_be32(addr + XEL_HEADER_OFFSET +
-                       XEL_RXBUFF_OFFSET) >> XEL_HEADER_SHIFT) &
+       proto_type = ((ntohl(in_be32(addr + XEL_HEADER_OFFSET +
+                       XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) &
                        XEL_RPLR_LENGTH_MASK);
 
        /* Check if received ethernet frame is a raw ethernet frame
@@ -439,9 +439,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
        if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
 
                if (proto_type == ETH_P_IP) {
-                       length = ((in_be32(addr +
+                       length = ((ntohl(in_be32(addr +
                                        XEL_HEADER_IP_LENGTH_OFFSET +
-                                       XEL_RXBUFF_OFFSET) >>
+                                       XEL_RXBUFF_OFFSET)) >>
                                        XEL_HEADER_SHIFT) &
                                        XEL_RPLR_LENGTH_MASK);
                        length += ETH_HLEN + ETH_FCS_LEN;
index 6acbff389ab66c54e12f80a1831fedc41475de87..aa675ebd8eb3cd9636de7b69add0cfe73a134995 100644 (file)
@@ -4,7 +4,7 @@ config DTC
 config OF
        bool
 
-menu "Flattened Device Tree and Open Firmware support"
+menu "Device Tree and Open Firmware support"
        depends on OF
 
 config PROC_DEVICETREE
@@ -19,6 +19,9 @@ config OF_FLATTREE
        bool
        select DTC
 
+config OF_PROMTREE
+       bool
+
 config OF_DYNAMIC
        def_bool y
        depends on PPC_OF
index 0052c405463acfe1d692aaf4dadf22dc455fc771..7888155bea08dacb3317c0d25cc66a34a0d952ed 100644 (file)
@@ -1,5 +1,6 @@
 obj-y = base.o
 obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_PROMTREE) += pdt.o
 obj-$(CONFIG_OF_ADDRESS)  += address.o
 obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
index fcadb726d4f9cdbed41ecf370544b358644a65b5..3a1c7e70b192a014088649fb6a275154fb1f9b9c 100644 (file)
@@ -163,7 +163,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
 const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
                        unsigned int *flags)
 {
-       const u32 *prop;
+       const __be32 *prop;
        unsigned int psize;
        struct device_node *parent;
        struct of_bus *bus;
index aa805250de765e5e1c9531e0b9cbfbb6143683f2..710b53bfac6d9478b86aed67e537bc06ee1cbc6d 100644 (file)
@@ -33,7 +33,7 @@ DEFINE_RWLOCK(devtree_lock);
 
 int of_n_addr_cells(struct device_node *np)
 {
-       const int *ip;
+       const __be32 *ip;
 
        do {
                if (np->parent)
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
 
 int of_n_size_cells(struct device_node *np)
 {
-       const int *ip;
+       const __be32 *ip;
 
        do {
                if (np->parent)
index 92de0eb74aea9ebfb5825129d8dcd38b2e3bb232..45d86530799fce60e1f117dd7b55d9223f29748d 100644 (file)
@@ -81,29 +81,10 @@ struct device_attribute of_platform_device_attrs[] = {
        __ATTR_NULL
 };
 
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct platform_device *ofdev;
-
-       ofdev = to_platform_device(dev);
-       of_node_put(ofdev->dev.of_node);
-       kfree(ofdev);
-}
-EXPORT_SYMBOL(of_release_dev);
-
-int of_device_register(struct platform_device *ofdev)
+int of_device_add(struct platform_device *ofdev)
 {
        BUG_ON(ofdev->dev.of_node == NULL);
 
-       device_initialize(&ofdev->dev);
-
        /* name and id have to be set so that the platform bus doesn't get
         * confused on matching */
        ofdev->name = dev_name(&ofdev->dev);
@@ -117,6 +98,12 @@ int of_device_register(struct platform_device *ofdev)
 
        return device_add(&ofdev->dev);
 }
+
+int of_device_register(struct platform_device *pdev)
+{
+       device_initialize(&pdev->dev);
+       return of_device_add(pdev);
+}
 EXPORT_SYMBOL(of_device_register);
 
 void of_device_unregister(struct platform_device *ofdev)
index 65da5aec7552c70162b6646ded99a32c72797b9d..c1360e02f9212de87d1ce7680153d0058720a11b 100644 (file)
@@ -533,8 +533,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
                strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
 #endif /* CONFIG_CMDLINE */
 
-       early_init_dt_scan_chosen_arch(node);
-
        pr_debug("Command line is: %s\n", cmd_line);
 
        /* break now */
index 6e595e5a39770b912e05feccb4c4f9a85c0742a4..75b0d3cb7676d39458ad2f402c0bb255a779f6b5 100644 (file)
 #include <linux/of_irq.h>
 #include <linux/string.h>
 
+/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
 /**
  * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
  * @device: Device node of the device whose interrupt is to be mapped
@@ -347,3 +352,37 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
        return irq;
 }
 EXPORT_SYMBOL_GPL(of_irq_to_resource);
+
+/**
+ * of_irq_count - Count the number of IRQs a node uses
+ * @dev: pointer to device tree node
+ */
+int of_irq_count(struct device_node *dev)
+{
+       int nr = 0;
+
+       while (of_irq_to_resource(dev, nr, NULL) != NO_IRQ)
+               nr++;
+
+       return nr;
+}
+
+/**
+ * of_irq_to_resource_table - Fill in resource table with node's IRQ info
+ * @dev: pointer to device tree node
+ * @res: array of resources to fill in
+ * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
+ *
+ * Returns the size of the filled in table (up to @nr_irqs).
+ */
+int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
+               int nr_irqs)
+{
+       int i;
+
+       for (i = 0; i < nr_irqs; i++, res++)
+               if (of_irq_to_resource(dev, i, res) == NO_IRQ)
+                       break;
+
+       return i;
+}
index 0a694debd226b8dbc066789f198b2de0017c30d8..c85d3c7421fc94796c6814d0c453b33f831a9279 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/i2c.h>
+#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_i2c.h>
 #include <linux/of_irq.h>
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
new file mode 100644 (file)
index 0000000..28295d0
--- /dev/null
@@ -0,0 +1,276 @@
+/* pdt.c: OF PROM device tree support 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
+ *  Adapted for multiple architectures by Andres Salomon <dilinger@queued.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 <linux/of_pdt.h>
+#include <asm/prom.h>
+
+static struct of_pdt_ops *of_pdt_prom_ops __initdata;
+
+void __initdata (*of_pdt_build_more)(struct device_node *dp,
+               struct device_node ***nextp);
+
+#if defined(CONFIG_SPARC)
+unsigned int of_pdt_unique_id __initdata;
+
+#define of_pdt_incr_unique_id(p) do { \
+       (p)->unique_id = of_pdt_unique_id++; \
+} while (0)
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+       return dp->path_component_name;
+}
+
+#else
+
+static inline void of_pdt_incr_unique_id(void *p) { }
+static inline void irq_trans_init(struct device_node *dp) { }
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+       return dp->name;
+}
+
+#endif /* !CONFIG_SPARC */
+
+static struct property * __init of_pdt_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 err;
+
+       if (tmp) {
+               p = tmp;
+               memset(p, 0, sizeof(*p) + 32);
+               tmp = NULL;
+       } else {
+               p = prom_early_alloc(sizeof(struct property) + 32);
+               of_pdt_incr_unique_id(p);
+       }
+
+       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 {
+               err = of_pdt_prom_ops->nextprop(node, prev, p->name);
+               if (err) {
+                       tmp = p;
+                       return NULL;
+               }
+               p->length = of_pdt_prom_ops->getproplen(node, p->name);
+               if (p->length <= 0) {
+                       p->length = 0;
+               } else {
+                       int len;
+
+                       p->value = prom_early_alloc(p->length + 1);
+                       len = of_pdt_prom_ops->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 of_pdt_build_prop_list(phandle node)
+{
+       struct property *head, *tail;
+
+       head = tail = of_pdt_build_one_prop(node, NULL,
+                                    ".node", &node, sizeof(node));
+
+       tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
+       tail = tail->next;
+       while(tail) {
+               tail->next = of_pdt_build_one_prop(node, tail->name,
+                                           NULL, NULL, 0);
+               tail = tail->next;
+       }
+
+       return head;
+}
+
+static char * __init of_pdt_get_one_property(phandle node, const char *name)
+{
+       char *buf = "<NULL>";
+       int len;
+
+       len = of_pdt_prom_ops->getproplen(node, name);
+       if (len > 0) {
+               buf = prom_early_alloc(len);
+               len = of_pdt_prom_ops->getproperty(node, name, buf, len);
+       }
+
+       return buf;
+}
+
+static char * __init of_pdt_try_pkg2path(phandle node)
+{
+       char *res, *buf = NULL;
+       int len;
+
+       if (!of_pdt_prom_ops->pkg2path)
+               return NULL;
+
+       if (of_pdt_prom_ops->pkg2path(node, buf, 0, &len))
+               return NULL;
+       buf = prom_early_alloc(len + 1);
+       if (of_pdt_prom_ops->pkg2path(node, buf, len, &len)) {
+               pr_err("%s: package-to-path failed\n", __func__);
+               return NULL;
+       }
+
+       res = strrchr(buf, '/');
+       if (!res) {
+               pr_err("%s: couldn't find / in %s\n", __func__, buf);
+               return NULL;
+       }
+       return res+1;
+}
+
+/*
+ * When fetching the node's name, first try using package-to-path; if
+ * that fails (either because the arch hasn't supplied a PROM callback,
+ * or some other random failure), fall back to just looking at the node's
+ * 'name' property.
+ */
+static char * __init of_pdt_build_name(phandle node)
+{
+       char *buf;
+
+       buf = of_pdt_try_pkg2path(node);
+       if (!buf)
+               buf = of_pdt_get_one_property(node, "name");
+
+       return buf;
+}
+
+static struct device_node * __init of_pdt_create_node(phandle node,
+                                                   struct device_node *parent)
+{
+       struct device_node *dp;
+
+       if (!node)
+               return NULL;
+
+       dp = prom_early_alloc(sizeof(*dp));
+       of_pdt_incr_unique_id(dp);
+       dp->parent = parent;
+
+       kref_init(&dp->kref);
+
+       dp->name = of_pdt_build_name(node);
+       dp->type = of_pdt_get_one_property(node, "device_type");
+       dp->phandle = node;
+
+       dp->properties = of_pdt_build_prop_list(node);
+
+       irq_trans_init(dp);
+
+       return dp;
+}
+
+static char * __init of_pdt_build_full_name(struct device_node *dp)
+{
+       int len, ourlen, plen;
+       char *n;
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(of_pdt_node_name(dp));
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!of_node_is_root(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, of_pdt_node_name(dp));
+
+       return n;
+}
+
+static struct device_node * __init of_pdt_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 = of_pdt_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;
+
+#if defined(CONFIG_SPARC)
+               dp->path_component_name = build_path_component(dp);
+#endif
+               dp->full_name = of_pdt_build_full_name(dp);
+
+               dp->child = of_pdt_build_tree(dp,
+                               of_pdt_prom_ops->getchild(node), nextp);
+
+               if (of_pdt_build_more)
+                       of_pdt_build_more(dp, nextp);
+
+               node = of_pdt_prom_ops->getsibling(node);
+       }
+
+       return ret;
+}
+
+void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
+{
+       struct device_node **nextp;
+
+       BUG_ON(!ops);
+       of_pdt_prom_ops = ops;
+
+       allnodes = of_pdt_create_node(root_node, NULL);
+#if defined(CONFIG_SPARC)
+       allnodes->path_component_name = "";
+#endif
+       allnodes->full_name = "/";
+
+       nextp = &allnodes->allnext;
+       allnodes->child = of_pdt_build_tree(allnodes,
+                       of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
+}
index bb72223c22ae233592b31549bd9417a1d3eb3c65..5b4a07f1220ed38d326e87591eef924b15d9e353 100644 (file)
@@ -584,34 +584,33 @@ struct platform_device *of_device_alloc(struct device_node *np,
                                  struct device *parent)
 {
        struct platform_device *dev;
-       int rc, i, num_reg = 0, num_irq = 0;
+       int rc, i, num_reg = 0, num_irq;
        struct resource *res, temp_res;
 
-       /* First count how many resources are needed */
-       while (of_address_to_resource(np, num_reg, &temp_res) == 0)
-               num_reg++;
-       while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ)
-               num_irq++;
-
-       /* Allocate memory for both the struct device and the resource table */
-       dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)),
-                     GFP_KERNEL);
+       dev = platform_device_alloc("", -1);
        if (!dev)
                return NULL;
-       res = (struct resource *) &dev[1];
+
+       /* count the io and irq resources */
+       while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+               num_reg++;
+       num_irq = of_irq_count(np);
 
        /* Populate the resource table */
        if (num_irq || num_reg) {
+               res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+               if (!res) {
+                       platform_device_put(dev);
+                       return NULL;
+               }
+
                dev->num_resources = num_reg + num_irq;
                dev->resource = res;
                for (i = 0; i < num_reg; i++, res++) {
                        rc = of_address_to_resource(np, i, res);
                        WARN_ON(rc);
                }
-               for (i = 0; i < num_irq; i++, res++) {
-                       rc = of_irq_to_resource(np, i, res);
-                       WARN_ON(rc == NO_IRQ);
-               }
+               WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
        }
 
        dev->dev.of_node = of_node_get(np);
@@ -619,7 +618,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
        dev->dev.dma_mask = &dev->archdata.dma_mask;
 #endif
        dev->dev.parent = parent;
-       dev->dev.release = of_release_dev;
 
        if (bus_id)
                dev_set_name(&dev->dev, "%s", bus_id);
@@ -657,8 +655,8 @@ struct platform_device *of_platform_device_create(struct device_node *np,
         * to do such, possibly using a device notifier
         */
 
-       if (of_device_register(dev) != 0) {
-               of_device_free(dev);
+       if (of_device_add(dev) != 0) {
+               platform_device_put(dev);
                return NULL;
        }
 
index 95f711b251adf33a80dd69eab2a6b792a11313ac..449de59bf35bb8a255d73b1a77eff0d040f953be 100644 (file)
@@ -28,6 +28,7 @@ static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
        struct inode *inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        }
index cff7cc2c1f025295746416e86e88a07859e29154..faec777b1ed433de38514c479fc17dc2ebf96c00 100644 (file)
@@ -92,6 +92,7 @@ config DELL_WMI
        tristate "Dell WMI extras"
        depends on ACPI_WMI
        depends on INPUT
+       select INPUT_SPARSEKMAP
        ---help---
          Say Y here if you want to support WMI-based hotkeys on Dell laptops.
 
@@ -140,6 +141,7 @@ config HP_WMI
        depends on ACPI_WMI
        depends on INPUT
        depends on RFKILL || RFKILL = n
+       select INPUT_SPARSEKMAP
        help
         Say Y here if you want to support WMI-based hotkeys on HP laptops and
         to read data from WMI such as docking or ambient light sensor state.
@@ -171,6 +173,7 @@ config PANASONIC_LAPTOP
        tristate "Panasonic Laptop Extras"
        depends on INPUT && ACPI
        depends on BACKLIGHT_CLASS_DEVICE
+       select INPUT_SPARSEKMAP
        ---help---
          This driver adds support for access to backlight control and hotkeys
          on Panasonic Let's Note laptops.
@@ -219,8 +222,8 @@ config SONYPI_COMPAT
          ---help---
          Build the sonypi driver compatibility code into the sony-laptop driver.
 
-config IDEAPAD_ACPI
-       tristate "Lenovo IdeaPad ACPI Laptop Extras"
+config IDEAPAD_LAPTOP
+       tristate "Lenovo IdeaPad Laptop Extras"
        depends on ACPI
        depends on RFKILL
        help
@@ -365,6 +368,26 @@ config THINKPAD_ACPI_HOTKEY_POLL
          If you are not sure, say Y here.  The driver enables polling only if
          it is strictly necessary to do so.
 
+config SENSORS_HDAPS
+       tristate "Thinkpad Hard Drive Active Protection System (hdaps)"
+       depends on INPUT && X86
+       select INPUT_POLLDEV
+       default n
+       help
+         This driver provides support for the IBM Hard Drive Active Protection
+         System (hdaps), which provides an accelerometer and other misc. data.
+         ThinkPads starting with the R50, T41, and X40 are supported.  The
+         accelerometer data is readable via sysfs.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         If your ThinkPad is not recognized by the driver, please update to latest
+         BIOS. This is especially the case for some R52 ThinkPads.
+
+         Say Y here if you have an applicable laptop and want to experience
+         the awesome power of hdaps.
+
 config INTEL_MENLOW
        tristate "Thermal Management driver for Intel menlow platform"
        depends on ACPI_THERMAL
@@ -478,6 +501,7 @@ config TOPSTAR_LAPTOP
        tristate "Topstar Laptop Extras"
        depends on ACPI
        depends on INPUT
+       select INPUT_SPARSEKMAP
        ---help---
          This driver adds support for hotkeys found on Topstar laptops.
 
@@ -492,6 +516,7 @@ config ACPI_TOSHIBA
        depends on INPUT
        depends on RFKILL || RFKILL = n
        select INPUT_POLLDEV
+       select INPUT_SPARSEKMAP
        ---help---
          This driver adds support for access to certain system settings
          on "legacy free" Toshiba laptops.  These laptops can be recognized by
@@ -590,4 +615,28 @@ config INTEL_IPS
          functionality.  If in doubt, say Y here; it will only load on
          supported platforms.
 
+config IBM_RTL
+       tristate "Device driver to enable PRTL support"
+       depends on X86 && PCI
+       ---help---
+        Enable support for IBM Premium Real Time Mode (PRTM).
+        This module will allow you the enter and exit PRTM in the BIOS via
+        sysfs on platforms that support this feature.  System in PRTM will
+        not receive CPU-generated SMIs for recoverable errors.  Use of this
+        feature without proper support may void your hardware warranty.
+
+        If the proper BIOS support is found the driver will load and create
+        /sys/devices/system/ibm_rtl/.  The "state" variable will indicate
+        whether or not the BIOS is in PRTM.
+        state = 0 (BIOS SMIs on)
+        state = 1 (BIOS SMIs off)
+
+config XO1_RFKILL
+       tristate "OLPC XO-1 software RF kill switch"
+       depends on OLPC
+       depends on RFKILL
+       ---help---
+         Support for enabling/disabling the WLAN interface on the OLPC XO-1
+         laptop.
+
 endif # X86_PLATFORM_DEVICES
index 85fb2b84f57ebef5d1edb6991ffa8d5532199367..9950ccc940b5b926ad86a50c07a9651432dbea4c 100644 (file)
@@ -15,8 +15,9 @@ obj-$(CONFIG_ACERHDF)         += acerhdf.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
 obj-$(CONFIG_SONY_LAPTOP)      += sony-laptop.o
-obj-$(CONFIG_IDEAPAD_ACPI)     += ideapad_acpi.o
+obj-$(CONFIG_IDEAPAD_LAPTOP)   += ideapad-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)    += thinkpad_acpi.o
+obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
 obj-$(CONFIG_FUJITSU_LAPTOP)   += fujitsu-laptop.o
 obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
@@ -30,4 +31,5 @@ obj-$(CONFIG_INTEL_SCU_IPC)   += intel_scu_ipc.o
 obj-$(CONFIG_RAR_REGISTER)     += intel_rar_register.o
 obj-$(CONFIG_INTEL_IPS)                += intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)  += intel_pmic_gpio.o
-
+obj-$(CONFIG_XO1_RFKILL)       += xo1-rfkill.o
+obj-$(CONFIG_IBM_RTL)          += ibm_rtl.o
index 2badee2fdeed4238adf3c77844c4fbdacdaef70a..c8c65375bfe2cf61e83276c97ad3eed86453a0a0 100644 (file)
@@ -1314,7 +1314,7 @@ static int __init acer_wmi_init(void)
                AMW0_find_mailled();
 
        if (!interface) {
-               printk(ACER_ERR "No or unsupported WMI interface, unable to "
+               printk(ACER_INFO "No or unsupported WMI interface, unable to "
                                "load\n");
                return -ENODEV;
        }
index b756e07d41b4d9c551fe6234889d23d97a4ffcd8..60a5a5c6b50ac7d6dfb4767163d30446ef03f80f 100644 (file)
@@ -236,7 +236,6 @@ struct asus_laptop {
        u8 light_level;         /* light sensor level */
        u8 light_switch;        /* light sensor switch value */
        u16 event_count[128];   /* count for each event TODO make this better */
-       u16 *keycode_map;
 };
 
 static const struct key_entry asus_keymap[] = {
@@ -278,6 +277,7 @@ static const struct key_entry asus_keymap[] = {
        {KE_KEY, 0x99, { KEY_PHONE } },
        {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
        {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
+       {KE_KEY, 0xb5, { KEY_CALC } },
        {KE_END, 0},
 };
 
@@ -639,29 +639,29 @@ static int asus_backlight_notify(struct asus_laptop *asus)
 static int asus_backlight_init(struct asus_laptop *asus)
 {
        struct backlight_device *bd;
-       struct device *dev = &asus->platform_device->dev;
        struct backlight_properties props;
 
-       if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
-           !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
-           lcd_switch_handle) {
-               memset(&props, 0, sizeof(struct backlight_properties));
-               props.max_brightness = 15;
-
-               bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
-                                              asus, &asusbl_ops, &props);
-               if (IS_ERR(bd)) {
-                       pr_err("Could not register asus backlight device\n");
-                       asus->backlight_device = NULL;
-                       return PTR_ERR(bd);
-               }
+       if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
+           acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) ||
+           !lcd_switch_handle)
+               return 0;
 
-               asus->backlight_device = bd;
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 15;
 
-               bd->props.power = FB_BLANK_UNBLANK;
-               bd->props.brightness = asus_read_brightness(bd);
-               backlight_update_status(bd);
+       bd = backlight_device_register(ASUS_LAPTOP_FILE,
+                                      &asus->platform_device->dev, asus,
+                                      &asusbl_ops, &props);
+       if (IS_ERR(bd)) {
+               pr_err("Could not register asus backlight device\n");
+               asus->backlight_device = NULL;
+               return PTR_ERR(bd);
        }
+
+       asus->backlight_device = bd;
+       bd->props.brightness = asus_read_brightness(bd);
+       bd->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(bd);
        return 0;
 }
 
@@ -1065,9 +1065,9 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
  */
 static int asus_gps_rfkill_set(void *data, bool blocked)
 {
-       acpi_handle handle = data;
+       struct asus_laptop *asus = data;
 
-       return asus_gps_switch(handle, !blocked);
+       return asus_gps_switch(asus, !blocked);
 }
 
 static const struct rfkill_ops asus_gps_rfkill_ops = {
@@ -1094,7 +1094,7 @@ static int asus_rfkill_init(struct asus_laptop *asus)
 
        asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
                                        RFKILL_TYPE_GPS,
-                                       &asus_gps_rfkill_ops, NULL);
+                                       &asus_gps_rfkill_ops, asus);
        if (!asus->gps_rfkill)
                return -EINVAL;
 
@@ -1130,7 +1130,6 @@ static int asus_input_init(struct asus_laptop *asus)
        input->phys = ASUS_LAPTOP_FILE "/input0";
        input->id.bustype = BUS_HOST;
        input->dev.parent = &asus->platform_device->dev;
-       input_set_drvdata(input, asus);
 
        error = sparse_keymap_setup(input, asus_keymap, NULL);
        if (error) {
@@ -1159,6 +1158,7 @@ static void asus_input_exit(struct asus_laptop *asus)
                sparse_keymap_free(asus->inputdev);
                input_unregister_device(asus->inputdev);
        }
+       asus->inputdev = NULL;
 }
 
 /*
@@ -1200,111 +1200,100 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
 
 static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
 static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
-static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth,
-                  store_bluetooth);
+static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
+                  show_bluetooth, store_bluetooth);
 static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
 static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
 static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
 static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
 static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
 
-static void asus_sysfs_exit(struct asus_laptop *asus)
-{
-       struct platform_device *device = asus->platform_device;
-
-       device_remove_file(&device->dev, &dev_attr_infos);
-       device_remove_file(&device->dev, &dev_attr_wlan);
-       device_remove_file(&device->dev, &dev_attr_bluetooth);
-       device_remove_file(&device->dev, &dev_attr_display);
-       device_remove_file(&device->dev, &dev_attr_ledd);
-       device_remove_file(&device->dev, &dev_attr_ls_switch);
-       device_remove_file(&device->dev, &dev_attr_ls_level);
-       device_remove_file(&device->dev, &dev_attr_gps);
-}
+static struct attribute *asus_attributes[] = {
+       &dev_attr_infos.attr,
+       &dev_attr_wlan.attr,
+       &dev_attr_bluetooth.attr,
+       &dev_attr_display.attr,
+       &dev_attr_ledd.attr,
+       &dev_attr_ls_level.attr,
+       &dev_attr_ls_switch.attr,
+       &dev_attr_gps.attr,
+       NULL
+};
 
-static int asus_sysfs_init(struct asus_laptop *asus)
+static mode_t asus_sysfs_is_visible(struct kobject *kobj,
+                                   struct attribute *attr,
+                                   int idx)
 {
-       struct platform_device *device = asus->platform_device;
-       int err;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct asus_laptop *asus = platform_get_drvdata(pdev);
+       acpi_handle handle = asus->handle;
+       bool supported;
 
-       err = device_create_file(&device->dev, &dev_attr_infos);
-       if (err)
-               return err;
+       if (attr == &dev_attr_wlan.attr) {
+               supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
 
-       if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_wlan);
-               if (err)
-                       return err;
-       }
+       } else if (attr == &dev_attr_bluetooth.attr) {
+               supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
 
-       if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_bluetooth);
-               if (err)
-                       return err;
-       }
+       } else if (attr == &dev_attr_display.attr) {
+               supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
 
-       if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_display);
-               if (err)
-                       return err;
-       }
+       } else if (attr == &dev_attr_ledd.attr) {
+               supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
 
-       if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_ledd);
-               if (err)
-                       return err;
-       }
-
-       if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
-           !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_ls_switch);
-               if (err)
-                       return err;
-               err = device_create_file(&device->dev, &dev_attr_ls_level);
-               if (err)
-                       return err;
-       }
+       } else if (attr == &dev_attr_ls_switch.attr ||
+                  attr == &dev_attr_ls_level.attr) {
+               supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
+                           !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
 
-       if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
-           !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
-           !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) {
-               err = device_create_file(&device->dev, &dev_attr_gps);
-               if (err)
-                       return err;
+       } else if (attr == &dev_attr_gps.attr) {
+               supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
+                           !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
+                           !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
+       } else {
+               supported = true;
        }
 
-       return err;
+       return supported ? attr->mode : 0;
 }
 
+
+static const struct attribute_group asus_attr_group = {
+       .is_visible     = asus_sysfs_is_visible,
+       .attrs          = asus_attributes,
+};
+
 static int asus_platform_init(struct asus_laptop *asus)
 {
-       int err;
+       int result;
 
        asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
        if (!asus->platform_device)
                return -ENOMEM;
        platform_set_drvdata(asus->platform_device, asus);
 
-       err = platform_device_add(asus->platform_device);
-       if (err)
+       result = platform_device_add(asus->platform_device);
+       if (result)
                goto fail_platform_device;
 
-       err = asus_sysfs_init(asus);
-       if (err)
+       result = sysfs_create_group(&asus->platform_device->dev.kobj,
+                                   &asus_attr_group);
+       if (result)
                goto fail_sysfs;
+
        return 0;
 
 fail_sysfs:
-       asus_sysfs_exit(asus);
        platform_device_del(asus->platform_device);
 fail_platform_device:
        platform_device_put(asus->platform_device);
-       return err;
+       return result;
 }
 
 static void asus_platform_exit(struct asus_laptop *asus)
 {
-       asus_sysfs_exit(asus);
+       sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
        platform_device_unregister(asus->platform_device);
 }
 
@@ -1428,8 +1417,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
        return AE_OK;
 }
 
-static bool asus_device_present;
-
 static int __devinit asus_acpi_init(struct asus_laptop *asus)
 {
        int result = 0;
@@ -1474,6 +1461,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
        return result;
 }
 
+static bool asus_device_present;
+
 static int __devinit asus_acpi_add(struct acpi_device *device)
 {
        struct asus_laptop *asus;
index 4413975912e036d71961a3430aa00be964de4b39..cf8a89a0d8f519bf5160eef46f2eaaffff7d74f4 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/mm.h>
 #include <linux/i8042.h>
 #include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include "../../firmware/dcdbas.h"
 
 #define BRIGHTNESS_TOKEN 0x7d
@@ -325,6 +327,75 @@ static const struct rfkill_ops dell_rfkill_ops = {
        .query = dell_rfkill_query,
 };
 
+static struct dentry *dell_laptop_dir;
+
+static int dell_debugfs_show(struct seq_file *s, void *data)
+{
+       int status;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+       status = buffer->output[1];
+       release_buffer();
+
+       seq_printf(s, "status:\t0x%X\n", status);
+       seq_printf(s, "Bit 0 : Hardware switch supported:   %lu\n",
+                  status & BIT(0));
+       seq_printf(s, "Bit 1 : Wifi locator supported:      %lu\n",
+                 (status & BIT(1)) >> 1);
+       seq_printf(s, "Bit 2 : Wifi is supported:           %lu\n",
+                 (status & BIT(2)) >> 2);
+       seq_printf(s, "Bit 3 : Bluetooth is supported:      %lu\n",
+                 (status & BIT(3)) >> 3);
+       seq_printf(s, "Bit 4 : WWAN is supported:           %lu\n",
+                 (status & BIT(4)) >> 4);
+       seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n",
+                 (status & BIT(5)) >> 5);
+       seq_printf(s, "Bit 8 : Wifi is installed:           %lu\n",
+                 (status & BIT(8)) >> 8);
+       seq_printf(s, "Bit 9 : Bluetooth is installed:      %lu\n",
+                 (status & BIT(9)) >> 9);
+       seq_printf(s, "Bit 10: WWAN is installed:           %lu\n",
+                 (status & BIT(10)) >> 10);
+       seq_printf(s, "Bit 16: Hardware switch is on:       %lu\n",
+                 (status & BIT(16)) >> 16);
+       seq_printf(s, "Bit 17: Wifi is blocked:             %lu\n",
+                 (status & BIT(17)) >> 17);
+       seq_printf(s, "Bit 18: Bluetooth is blocked:        %lu\n",
+                 (status & BIT(18)) >> 18);
+       seq_printf(s, "Bit 19: WWAN is blocked:             %lu\n",
+                 (status & BIT(19)) >> 19);
+
+       seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
+       seq_printf(s, "Bit 0 : Wifi controlled by switch:      %lu\n",
+                  hwswitch_state & BIT(0));
+       seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
+                  (hwswitch_state & BIT(1)) >> 1);
+       seq_printf(s, "Bit 2 : WWAN controlled by switch:      %lu\n",
+                  (hwswitch_state & BIT(2)) >> 2);
+       seq_printf(s, "Bit 7 : Wireless switch config locked:  %lu\n",
+                  (hwswitch_state & BIT(7)) >> 7);
+       seq_printf(s, "Bit 8 : Wifi locator enabled:           %lu\n",
+                  (hwswitch_state & BIT(8)) >> 8);
+       seq_printf(s, "Bit 15: Wifi locator setting locked:    %lu\n",
+                  (hwswitch_state & BIT(15)) >> 15);
+
+       return 0;
+}
+
+static int dell_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dell_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dell_debugfs_fops = {
+       .owner = THIS_MODULE,
+       .open = dell_debugfs_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static void dell_update_rfkill(struct work_struct *ignored)
 {
        if (wifi_rfkill)
@@ -556,6 +627,11 @@ static int __init dell_init(void)
                goto fail_filter;
        }
 
+       dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
+       if (dell_laptop_dir != NULL)
+               debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
+                                   &dell_debugfs_fops);
+
 #ifdef CONFIG_ACPI
        /* In the event of an ACPI backlight being available, don't
         * register the platform controller.
@@ -615,6 +691,7 @@ fail_platform_driver:
 
 static void __exit dell_exit(void)
 {
+       debugfs_remove_recursive(dell_laptop_dir);
        i8042_remove_filter(dell_laptop_i8042_filter);
        cancel_delayed_work_sync(&dell_rfkill_work);
        backlight_device_unregister(dell_backlight_device);
index 08fb70f6d9bfd3d0039693f6b436f5245264a84a..77f1d55414c670b126f41cce7356dbbd14b1cd13 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/acpi.h>
 #include <linux/string.h>
@@ -44,78 +45,70 @@ static int acpi_video;
 
 MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
 
-struct key_entry {
-       char type;              /* See KE_* below */
-       u16 code;
-       u16 keycode;
-};
-
-enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
-
 /*
  * Certain keys are flagged as KE_IGNORE. All of these are either
  * notifications (rather than requests for change) or are also sent
  * via the keyboard controller so should not be sent again.
  */
 
-static struct key_entry dell_legacy_wmi_keymap[] = {
-       {KE_KEY, 0xe045, KEY_PROG1},
-       {KE_KEY, 0xe009, KEY_EJECTCD},
+static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
+       { KE_KEY, 0xe045, { KEY_PROG1 } },
+       { KE_KEY, 0xe009, { KEY_EJECTCD } },
 
        /* These also contain the brightness level at offset 6 */
-       {KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
-       {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
+       { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
 
        /* Battery health status button */
-       {KE_KEY, 0xe007, KEY_BATTERY},
+       { KE_KEY, 0xe007, { KEY_BATTERY } },
 
        /* This is actually for all radios. Although physically a
         * switch, the notification does not provide an indication of
         * state and so it should be reported as a key */
-       {KE_KEY, 0xe008, KEY_WLAN},
+       { KE_KEY, 0xe008, { KEY_WLAN } },
 
        /* The next device is at offset 6, the active devices are at
           offset 8 and the attached devices at offset 10 */
-       {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
+       { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
 
-       {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
+       { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
 
        /* BIOS error detected */
-       {KE_IGNORE, 0xe00d, KEY_RESERVED},
+       { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
 
        /* Wifi Catcher */
-       {KE_KEY, 0xe011, KEY_PROG2},
+       { KE_KEY, 0xe011, {KEY_PROG2 } },
 
        /* Ambient light sensor toggle */
-       {KE_IGNORE, 0xe013, KEY_RESERVED},
-
-       {KE_IGNORE, 0xe020, KEY_MUTE},
-       {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
-       {KE_IGNORE, 0xe030, KEY_VOLUMEUP},
-       {KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
-       {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
-       {KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
-       {KE_IGNORE, 0xe045, KEY_NUMLOCK},
-       {KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
-       {KE_END, 0}
+       { KE_IGNORE, 0xe013, { KEY_RESERVED } },
+
+       { KE_IGNORE, 0xe020, { KEY_MUTE } },
+       { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
+       { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
+       { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
+       { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
+       { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
+       { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
+       { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
+       { KE_END, 0 }
 };
 
 static bool dell_new_hk_type;
 
-struct dell_new_keymap_entry {
+struct dell_bios_keymap_entry {
        u16 scancode;
        u16 keycode;
 };
 
-struct dell_hotkey_table {
+struct dell_bios_hotkey_table {
        struct dmi_header header;
-       struct dell_new_keymap_entry keymap[];
+       struct dell_bios_keymap_entry keymap[];
 
 };
 
-static struct key_entry *dell_new_wmi_keymap;
+static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
 
-static u16 bios_to_linux_keycode[256] = {
+static const u16 bios_to_linux_keycode[256] __initconst = {
 
        KEY_MEDIA,      KEY_NEXTSONG,   KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
        KEY_STOPCD,     KEY_UNKNOWN,    KEY_UNKNOWN,    KEY_UNKNOWN,
@@ -138,68 +131,11 @@ static u16 bios_to_linux_keycode[256] = {
        KEY_PROG3
 };
 
-
-static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
-
 static struct input_dev *dell_wmi_input_dev;
 
-static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
-{
-       struct key_entry *key;
-
-       for (key = dell_wmi_keymap; key->type != KE_END; key++)
-               if (code == key->code)
-                       return key;
-
-       return NULL;
-}
-
-static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
-{
-       struct key_entry *key;
-
-       for (key = dell_wmi_keymap; key->type != KE_END; key++)
-               if (key->type == KE_KEY && keycode == key->keycode)
-                       return key;
-
-       return NULL;
-}
-
-static int dell_wmi_getkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int *keycode)
-{
-       struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
-
-       if (key && key->type == KE_KEY) {
-               *keycode = key->keycode;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int dell_wmi_setkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int keycode)
-{
-       struct key_entry *key;
-       unsigned int old_keycode;
-
-       key = dell_wmi_get_entry_by_scancode(scancode);
-       if (key && key->type == KE_KEY) {
-               old_keycode = key->keycode;
-               key->keycode = keycode;
-               set_bit(keycode, dev->keybit);
-               if (!dell_wmi_get_entry_by_keycode(old_keycode))
-                       clear_bit(old_keycode, dev->keybit);
-               return 0;
-       }
-       return -EINVAL;
-}
-
 static void dell_wmi_notify(u32 value, void *context)
 {
        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
-       static struct key_entry *key;
        union acpi_object *obj;
        acpi_status status;
 
@@ -212,8 +148,10 @@ static void dell_wmi_notify(u32 value, void *context)
        obj = (union acpi_object *)response.pointer;
 
        if (obj && obj->type == ACPI_TYPE_BUFFER) {
+               const struct key_entry *key;
                int reported_key;
                u16 *buffer_entry = (u16 *)obj->buffer.pointer;
+
                if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
                        printk(KERN_INFO "dell-wmi: Received unknown WMI event"
                                         " (0x%x)\n", buffer_entry[1]);
@@ -226,8 +164,8 @@ static void dell_wmi_notify(u32 value, void *context)
                else
                        reported_key = (int)buffer_entry[1] & 0xffff;
 
-               key = dell_wmi_get_entry_by_scancode(reported_key);
-
+               key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
+                                                       reported_key);
                if (!key) {
                        printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
                                reported_key);
@@ -237,92 +175,98 @@ static void dell_wmi_notify(u32 value, void *context)
                         * come via ACPI */
                        ;
                } else {
-                       input_report_key(dell_wmi_input_dev, key->keycode, 1);
-                       input_sync(dell_wmi_input_dev);
-                       input_report_key(dell_wmi_input_dev, key->keycode, 0);
-                       input_sync(dell_wmi_input_dev);
+                       sparse_keymap_report_entry(dell_wmi_input_dev, key,
+                                                  1, true);
                }
        }
        kfree(obj);
 }
 
-
-static void setup_new_hk_map(const struct dmi_header *dm)
+static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
 {
-
+       int hotkey_num = (dell_bios_hotkey_table->header.length - 4) /
+                               sizeof(struct dell_bios_keymap_entry);
+       struct key_entry *keymap;
        int i;
-       int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
-       struct dell_hotkey_table *table =
-               container_of(dm, struct dell_hotkey_table, header);
 
-       dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
-                                     sizeof(struct key_entry), GFP_KERNEL);
+       keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
+       if (!keymap)
+               return NULL;
 
        for (i = 0; i < hotkey_num; i++) {
-               dell_new_wmi_keymap[i].type = KE_KEY;
-               dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
-               dell_new_wmi_keymap[i].keycode =
-                       (table->keymap[i].keycode > 255) ? 0 :
-                       bios_to_linux_keycode[table->keymap[i].keycode];
+               const struct dell_bios_keymap_entry *bios_entry =
+                                       &dell_bios_hotkey_table->keymap[i];
+               keymap[i].type = KE_KEY;
+               keymap[i].code = bios_entry->scancode;
+               keymap[i].keycode = bios_entry->keycode < 256 ?
+                                   bios_to_linux_keycode[bios_entry->keycode] :
+                                   KEY_RESERVED;
        }
 
-       dell_new_wmi_keymap[i].type = KE_END;
-       dell_new_wmi_keymap[i].code = 0;
-       dell_new_wmi_keymap[i].keycode = 0;
-
-       dell_wmi_keymap = dell_new_wmi_keymap;
+       keymap[hotkey_num].type = KE_END;
 
+       return keymap;
 }
 
-
-static void find_hk_type(const struct dmi_header *dm, void *dummy)
-{
-
-       if ((dm->type == 0xb2) && (dm->length > 6)) {
-               dell_new_hk_type = true;
-               setup_new_hk_map(dm);
-       }
-
-}
-
-
 static int __init dell_wmi_input_setup(void)
 {
-       struct key_entry *key;
        int err;
 
        dell_wmi_input_dev = input_allocate_device();
-
        if (!dell_wmi_input_dev)
                return -ENOMEM;
 
        dell_wmi_input_dev->name = "Dell WMI hotkeys";
        dell_wmi_input_dev->phys = "wmi/input0";
        dell_wmi_input_dev->id.bustype = BUS_HOST;
-       dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode;
-       dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode;
-
-       for (key = dell_wmi_keymap; key->type != KE_END; key++) {
-               switch (key->type) {
-               case KE_KEY:
-                       set_bit(EV_KEY, dell_wmi_input_dev->evbit);
-                       set_bit(key->keycode, dell_wmi_input_dev->keybit);
-                       break;
-               case KE_SW:
-                       set_bit(EV_SW, dell_wmi_input_dev->evbit);
-                       set_bit(key->keycode, dell_wmi_input_dev->swbit);
-                       break;
+
+       if (dell_new_hk_type) {
+               const struct key_entry *keymap = dell_wmi_prepare_new_keymap();
+               if (!keymap) {
+                       err = -ENOMEM;
+                       goto err_free_dev;
                }
-       }
 
-       err = input_register_device(dell_wmi_input_dev);
+               err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
 
-       if (err) {
-               input_free_device(dell_wmi_input_dev);
-               return err;
+               /*
+                * Sparse keymap library makes a copy of keymap so we
+                * don't need the original one that was allocated.
+                */
+               kfree(keymap);
+       } else {
+               err = sparse_keymap_setup(dell_wmi_input_dev,
+                                         dell_wmi_legacy_keymap, NULL);
        }
+       if (err)
+               goto err_free_dev;
+
+       err = input_register_device(dell_wmi_input_dev);
+       if (err)
+               goto err_free_keymap;
 
        return 0;
+
+ err_free_keymap:
+       sparse_keymap_free(dell_wmi_input_dev);
+ err_free_dev:
+       input_free_device(dell_wmi_input_dev);
+       return err;
+}
+
+static void dell_wmi_input_destroy(void)
+{
+       sparse_keymap_free(dell_wmi_input_dev);
+       input_unregister_device(dell_wmi_input_dev);
+}
+
+static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
+{
+       if (dm->type == 0xb2 && dm->length > 6) {
+               dell_new_hk_type = true;
+               dell_bios_hotkey_table =
+                       container_of(dm, struct dell_bios_hotkey_table, header);
+       }
 }
 
 static int __init dell_wmi_init(void)
@@ -339,18 +283,13 @@ static int __init dell_wmi_init(void)
        acpi_video = acpi_video_backlight_support();
 
        err = dell_wmi_input_setup();
-       if (err) {
-               if (dell_new_hk_type)
-                       kfree(dell_wmi_keymap);
+       if (err)
                return err;
-       }
 
        status = wmi_install_notify_handler(DELL_EVENT_GUID,
                                         dell_wmi_notify, NULL);
        if (ACPI_FAILURE(status)) {
-               input_unregister_device(dell_wmi_input_dev);
-               if (dell_new_hk_type)
-                       kfree(dell_wmi_keymap);
+               dell_wmi_input_destroy();
                printk(KERN_ERR
                        "dell-wmi: Unable to register notify handler - %d\n",
                        status);
@@ -359,14 +298,11 @@ static int __init dell_wmi_init(void)
 
        return 0;
 }
+module_init(dell_wmi_init);
 
 static void __exit dell_wmi_exit(void)
 {
        wmi_remove_notify_handler(DELL_EVENT_GUID);
-       input_unregister_device(dell_wmi_input_dev);
-       if (dell_new_hk_type)
-               kfree(dell_wmi_keymap);
+       dell_wmi_input_destroy();
 }
-
-module_init(dell_wmi_init);
 module_exit(dell_wmi_exit);
index 6b8e06206c465043ac11baf9b6fbe3493751f7e2..b2edfdcdcb84fd09d6eee096c56ef146351393be 100644 (file)
@@ -165,6 +165,7 @@ struct eeepc_laptop {
        u16 event_count[128];           /* count for each event */
 
        struct platform_device *platform_device;
+       struct acpi_device *device;             /* the device we are in */
        struct device *hwmon_device;
        struct backlight_device *backlight_device;
 
@@ -1193,9 +1194,9 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc)
        eeepc->inputdev = input;
        return 0;
 
- err_free_keymap:
+err_free_keymap:
        sparse_keymap_free(input);
- err_free_dev:
+err_free_dev:
        input_free_device(input);
        return error;
 }
@@ -1206,6 +1207,7 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
                sparse_keymap_free(eeepc->inputdev);
                input_unregister_device(eeepc->inputdev);
        }
+       eeepc->inputdev = NULL;
 }
 
 /*
@@ -1326,16 +1328,15 @@ static void cmsg_quirks(struct eeepc_laptop *eeepc)
        cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
 }
 
-static int eeepc_acpi_init(struct eeepc_laptop *eeepc,
-                          struct acpi_device *device)
+static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc)
 {
        unsigned int init_flags;
        int result;
 
-       result = acpi_bus_get_status(device);
+       result = acpi_bus_get_status(eeepc->device);
        if (result)
                return result;
-       if (!device->status.present) {
+       if (!eeepc->device->status.present) {
                pr_err("Hotkey device not present, aborting\n");
                return -ENODEV;
        }
@@ -1384,12 +1385,13 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
        strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
        strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
        device->driver_data = eeepc;
+       eeepc->device = device;
 
        eeepc->hotplug_disabled = hotplug_disabled;
 
        eeepc_dmi_check(eeepc);
 
-       result = eeepc_acpi_init(eeepc, device);
+       result = eeepc_acpi_init(eeepc);
        if (result)
                goto fail_platform;
        eeepc_enable_camera(eeepc);
index 9dc50fbf3d0bc787989fe0621dd24e413e55aea6..462ceab93f87b84d59796a58ac90703a2ffaddee 100644 (file)
@@ -57,6 +57,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
 
 #define EEEPC_WMI_METHODID_DEVS        0x53564544
 #define EEEPC_WMI_METHODID_DSTS        0x53544344
+#define EEEPC_WMI_METHODID_CFVS        0x53564643
 
 #define EEEPC_WMI_DEVID_BACKLIGHT      0x00050012
 
@@ -69,6 +70,11 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
        { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
        { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
+       { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
+       { KE_KEY, 0xe1, { KEY_F14 } },
+       { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
+       { KE_KEY, 0xe0, { KEY_PROG1 } },
+       { KE_KEY, 0x5c, { KEY_F15 } },
        { KE_END, 0},
 };
 
@@ -292,6 +298,49 @@ static void eeepc_wmi_notify(u32 value, void *context)
        kfree(obj);
 }
 
+static int store_cpufv(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       int value;
+       struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
+       acpi_status status;
+
+       if (!count || sscanf(buf, "%i", &value) != 1)
+               return -EINVAL;
+       if (value < 0 || value > 2)
+               return -EINVAL;
+
+       status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
+                                    1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
+
+       if (ACPI_FAILURE(status))
+               return -EIO;
+       else
+               return count;
+}
+
+static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
+
+static void eeepc_wmi_sysfs_exit(struct platform_device *device)
+{
+       device_remove_file(&device->dev, &dev_attr_cpufv);
+}
+
+static int eeepc_wmi_sysfs_init(struct platform_device *device)
+{
+       int retval = -ENOMEM;
+
+       retval = device_create_file(&device->dev, &dev_attr_cpufv);
+       if (retval)
+               goto error_sysfs;
+
+       return 0;
+
+error_sysfs:
+       eeepc_wmi_sysfs_exit(platform_device);
+       return retval;
+}
+
 static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
 {
        struct eeepc_wmi *eeepc;
@@ -387,8 +436,14 @@ static int __init eeepc_wmi_init(void)
                goto del_dev;
        }
 
+       err = eeepc_wmi_sysfs_init(platform_device);
+       if (err)
+               goto del_sysfs;
+
        return 0;
 
+del_sysfs:
+       eeepc_wmi_sysfs_exit(platform_device);
 del_dev:
        platform_device_del(platform_device);
 put_dev:
@@ -403,6 +458,7 @@ static void __exit eeepc_wmi_exit(void)
 {
        struct eeepc_wmi *eeepc;
 
+       eeepc_wmi_sysfs_exit(platform_device);
        eeepc = platform_get_drvdata(platform_device);
        platform_driver_unregister(&platform_driver);
        platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
new file mode 100644 (file)
index 0000000..067bf36
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * hdaps.c - driver for IBM's Hard Drive Active Protection System
+ *
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ *
+ * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
+ * starting with the R40, T41, and X40.  It provides a basic two-axis
+ * accelerometer and other data, such as the device's temperature.
+ *
+ * This driver is based on the document by Mark A. Smith available at
+ * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
+ * and error.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 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
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+
+#define HDAPS_LOW_PORT         0x1600  /* first port used by hdaps */
+#define HDAPS_NR_PORTS         0x30    /* number of ports: 0x1600 - 0x162f */
+
+#define HDAPS_PORT_STATE       0x1611  /* device state */
+#define HDAPS_PORT_YPOS                0x1612  /* y-axis position */
+#define        HDAPS_PORT_XPOS         0x1614  /* x-axis position */
+#define HDAPS_PORT_TEMP1       0x1616  /* device temperature, in Celsius */
+#define HDAPS_PORT_YVAR                0x1617  /* y-axis variance (what is this?) */
+#define HDAPS_PORT_XVAR                0x1619  /* x-axis variance (what is this?) */
+#define HDAPS_PORT_TEMP2       0x161b  /* device temperature (again?) */
+#define HDAPS_PORT_UNKNOWN     0x161c  /* what is this? */
+#define HDAPS_PORT_KMACT       0x161d  /* keyboard or mouse activity */
+
+#define STATE_FRESH            0x50    /* accelerometer data is fresh */
+
+#define KEYBD_MASK             0x20    /* set if keyboard activity */
+#define MOUSE_MASK             0x40    /* set if mouse activity */
+#define KEYBD_ISSET(n)         (!! (n & KEYBD_MASK))   /* keyboard used? */
+#define MOUSE_ISSET(n)         (!! (n & MOUSE_MASK))   /* mouse used? */
+
+#define INIT_TIMEOUT_MSECS     4000    /* wait up to 4s for device init ... */
+#define INIT_WAIT_MSECS                200     /* ... in 200ms increments */
+
+#define HDAPS_POLL_INTERVAL    50      /* poll for input every 1/20s (50 ms)*/
+#define HDAPS_INPUT_FUZZ       4       /* input event threshold */
+#define HDAPS_INPUT_FLAT       4
+
+#define HDAPS_X_AXIS           (1 << 0)
+#define HDAPS_Y_AXIS           (1 << 1)
+#define HDAPS_BOTH_AXES                (HDAPS_X_AXIS | HDAPS_Y_AXIS)
+
+static struct platform_device *pdev;
+static struct input_polled_dev *hdaps_idev;
+static unsigned int hdaps_invert;
+static u8 km_activity;
+static int rest_x;
+static int rest_y;
+
+static DEFINE_MUTEX(hdaps_mtx);
+
+/*
+ * __get_latch - Get the value from a given port.  Callers must hold hdaps_mtx.
+ */
+static inline u8 __get_latch(u16 port)
+{
+       return inb(port) & 0xff;
+}
+
+/*
+ * __check_latch - Check a port latch for a given value.  Returns zero if the
+ * port contains the given value.  Callers must hold hdaps_mtx.
+ */
+static inline int __check_latch(u16 port, u8 val)
+{
+       if (__get_latch(port) == val)
+               return 0;
+       return -EINVAL;
+}
+
+/*
+ * __wait_latch - Wait up to 100us for a port latch to get a certain value,
+ * returning zero if the value is obtained.  Callers must hold hdaps_mtx.
+ */
+static int __wait_latch(u16 port, u8 val)
+{
+       unsigned int i;
+
+       for (i = 0; i < 20; i++) {
+               if (!__check_latch(port, val))
+                       return 0;
+               udelay(5);
+       }
+
+       return -EIO;
+}
+
+/*
+ * __device_refresh - request a refresh from the accelerometer.  Does not wait
+ * for refresh to complete.  Callers must hold hdaps_mtx.
+ */
+static void __device_refresh(void)
+{
+       udelay(200);
+       if (inb(0x1604) != STATE_FRESH) {
+               outb(0x11, 0x1610);
+               outb(0x01, 0x161f);
+       }
+}
+
+/*
+ * __device_refresh_sync - request a synchronous refresh from the
+ * accelerometer.  We wait for the refresh to complete.  Returns zero if
+ * successful and nonzero on error.  Callers must hold hdaps_mtx.
+ */
+static int __device_refresh_sync(void)
+{
+       __device_refresh();
+       return __wait_latch(0x1604, STATE_FRESH);
+}
+
+/*
+ * __device_complete - indicate to the accelerometer that we are done reading
+ * data, and then initiate an async refresh.  Callers must hold hdaps_mtx.
+ */
+static inline void __device_complete(void)
+{
+       inb(0x161f);
+       inb(0x1604);
+       __device_refresh();
+}
+
+/*
+ * hdaps_readb_one - reads a byte from a single I/O port, placing the value in
+ * the given pointer.  Returns zero on success or a negative error on failure.
+ * Can sleep.
+ */
+static int hdaps_readb_one(unsigned int port, u8 *val)
+{
+       int ret;
+
+       mutex_lock(&hdaps_mtx);
+
+       /* do a sync refresh -- we need to be sure that we read fresh data */
+       ret = __device_refresh_sync();
+       if (ret)
+               goto out;
+
+       *val = inb(port);
+       __device_complete();
+
+out:
+       mutex_unlock(&hdaps_mtx);
+       return ret;
+}
+
+/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */
+static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
+                            int *x, int *y)
+{
+       /* do a sync refresh -- we need to be sure that we read fresh data */
+       if (__device_refresh_sync())
+               return -EIO;
+
+       *y = inw(port2);
+       *x = inw(port1);
+       km_activity = inb(HDAPS_PORT_KMACT);
+       __device_complete();
+
+       /* hdaps_invert is a bitvector to negate the axes */
+       if (hdaps_invert & HDAPS_X_AXIS)
+               *x = -*x;
+       if (hdaps_invert & HDAPS_Y_AXIS)
+               *y = -*y;
+
+       return 0;
+}
+
+/*
+ * hdaps_read_pair - reads the values from a pair of ports, placing the values
+ * in the given pointers.  Returns zero on success.  Can sleep.
+ */
+static int hdaps_read_pair(unsigned int port1, unsigned int port2,
+                          int *val1, int *val2)
+{
+       int ret;
+
+       mutex_lock(&hdaps_mtx);
+       ret = __hdaps_read_pair(port1, port2, val1, val2);
+       mutex_unlock(&hdaps_mtx);
+
+       return ret;
+}
+
+/*
+ * hdaps_device_init - initialize the accelerometer.  Returns zero on success
+ * and negative error code on failure.  Can sleep.
+ */
+static int hdaps_device_init(void)
+{
+       int total, ret = -ENXIO;
+
+       mutex_lock(&hdaps_mtx);
+
+       outb(0x13, 0x1610);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+
+       /*
+        * Most ThinkPads return 0x01.
+        *
+        * Others--namely the R50p, T41p, and T42p--return 0x03.  These laptops
+        * have "inverted" axises.
+        *
+        * The 0x02 value occurs when the chip has been previously initialized.
+        */
+       if (__check_latch(0x1611, 0x03) &&
+                    __check_latch(0x1611, 0x02) &&
+                    __check_latch(0x1611, 0x01))
+               goto out;
+
+       printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
+              __get_latch(0x1611));
+
+       outb(0x17, 0x1610);
+       outb(0x81, 0x1611);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       if (__wait_latch(0x1611, 0x00))
+               goto out;
+       if (__wait_latch(0x1612, 0x60))
+               goto out;
+       if (__wait_latch(0x1613, 0x00))
+               goto out;
+       outb(0x14, 0x1610);
+       outb(0x01, 0x1611);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       outb(0x10, 0x1610);
+       outb(0xc8, 0x1611);
+       outb(0x00, 0x1612);
+       outb(0x02, 0x1613);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       if (__device_refresh_sync())
+               goto out;
+       if (__wait_latch(0x1611, 0x00))
+               goto out;
+
+       /* we have done our dance, now let's wait for the applause */
+       for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+               int x, y;
+
+               /* a read of the device helps push it into action */
+               __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
+               if (!__wait_latch(0x1611, 0x02)) {
+                       ret = 0;
+                       break;
+               }
+
+               msleep(INIT_WAIT_MSECS);
+       }
+
+out:
+       mutex_unlock(&hdaps_mtx);
+       return ret;
+}
+
+
+/* Device model stuff */
+
+static int hdaps_probe(struct platform_device *dev)
+{
+       int ret;
+
+       ret = hdaps_device_init();
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "hdaps: device successfully initialized.\n");
+       return 0;
+}
+
+static int hdaps_resume(struct platform_device *dev)
+{
+       return hdaps_device_init();
+}
+
+static struct platform_driver hdaps_driver = {
+       .probe = hdaps_probe,
+       .resume = hdaps_resume,
+       .driver = {
+               .name = "hdaps",
+               .owner = THIS_MODULE,
+       },
+};
+
+/*
+ * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_mtx.
+ */
+static void hdaps_calibrate(void)
+{
+       __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
+}
+
+static void hdaps_mousedev_poll(struct input_polled_dev *dev)
+{
+       struct input_dev *input_dev = dev->input;
+       int x, y;
+
+       mutex_lock(&hdaps_mtx);
+
+       if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
+               goto out;
+
+       input_report_abs(input_dev, ABS_X, x - rest_x);
+       input_report_abs(input_dev, ABS_Y, y - rest_y);
+       input_sync(input_dev);
+
+out:
+       mutex_unlock(&hdaps_mtx);
+}
+
+
+/* Sysfs Files */
+
+static ssize_t hdaps_position_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int ret, x, y;
+
+       ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_variance_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int ret, x, y;
+
+       ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_temp1_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u8 temp;
+       int ret;
+
+       ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_temp2_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u8 temp;
+       int ret;
+
+       ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_keyboard_activity_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));
+}
+
+static ssize_t hdaps_mouse_activity_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));
+}
+
+static ssize_t hdaps_calibrate_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t hdaps_calibrate_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       mutex_lock(&hdaps_mtx);
+       hdaps_calibrate();
+       mutex_unlock(&hdaps_mtx);
+
+       return count;
+}
+
+static ssize_t hdaps_invert_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", hdaps_invert);
+}
+
+static ssize_t hdaps_invert_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int invert;
+
+       if (sscanf(buf, "%d", &invert) != 1 ||
+           invert < 0 || invert > HDAPS_BOTH_AXES)
+               return -EINVAL;
+
+       hdaps_invert = invert;
+       hdaps_calibrate();
+
+       return count;
+}
+
+static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
+static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);
+static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
+static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);
+static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
+static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
+static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
+static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
+
+static struct attribute *hdaps_attributes[] = {
+       &dev_attr_position.attr,
+       &dev_attr_variance.attr,
+       &dev_attr_temp1.attr,
+       &dev_attr_temp2.attr,
+       &dev_attr_keyboard_activity.attr,
+       &dev_attr_mouse_activity.attr,
+       &dev_attr_calibrate.attr,
+       &dev_attr_invert.attr,
+       NULL,
+};
+
+static struct attribute_group hdaps_attribute_group = {
+       .attrs = hdaps_attributes,
+};
+
+
+/* Module stuff */
+
+/* hdaps_dmi_match - found a match.  return one, short-circuiting the hunt. */
+static int __init hdaps_dmi_match(const struct dmi_system_id *id)
+{
+       printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
+       return 1;
+}
+
+/* hdaps_dmi_match_invert - found an inverted match. */
+static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
+{
+       hdaps_invert = (unsigned long)id->driver_data;
+       printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
+              hdaps_invert);
+       return hdaps_dmi_match(id);
+}
+
+#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) {  \
+       .ident = vendor " " model,                      \
+       .callback = hdaps_dmi_match_invert,             \
+       .driver_data = (void *)axes,                    \
+       .matches = {                                    \
+               DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
+               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
+       }                                               \
+}
+
+#define HDAPS_DMI_MATCH_NORMAL(vendor, model)          \
+       HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
+
+/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
+   "ThinkPad T42p", so the order of the entries matters.
+   If your ThinkPad is not recognized, please update to latest
+   BIOS. This is especially the case for some R52 ThinkPads. */
+static struct dmi_system_id __initdata hdaps_whitelist[] = {
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
+       HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
+       HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
+       { .ident = NULL }
+};
+
+static int __init hdaps_init(void)
+{
+       struct input_dev *idev;
+       int ret;
+
+       if (!dmi_check_system(hdaps_whitelist)) {
+               printk(KERN_WARNING "hdaps: supported laptop not found!\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       ret = platform_driver_register(&hdaps_driver);
+       if (ret)
+               goto out_region;
+
+       pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               goto out_driver;
+       }
+
+       ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
+       if (ret)
+               goto out_device;
+
+       hdaps_idev = input_allocate_polled_device();
+       if (!hdaps_idev) {
+               ret = -ENOMEM;
+               goto out_group;
+       }
+
+       hdaps_idev->poll = hdaps_mousedev_poll;
+       hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
+
+       /* initial calibrate for the input device */
+       hdaps_calibrate();
+
+       /* initialize the input class */
+       idev = hdaps_idev->input;
+       idev->name = "hdaps";
+       idev->phys = "isa1600/input0";
+       idev->id.bustype = BUS_ISA;
+       idev->dev.parent = &pdev->dev;
+       idev->evbit[0] = BIT_MASK(EV_ABS);
+       input_set_abs_params(idev, ABS_X,
+                       -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
+       input_set_abs_params(idev, ABS_Y,
+                       -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
+
+       ret = input_register_polled_device(hdaps_idev);
+       if (ret)
+               goto out_idev;
+
+       printk(KERN_INFO "hdaps: driver successfully loaded.\n");
+       return 0;
+
+out_idev:
+       input_free_polled_device(hdaps_idev);
+out_group:
+       sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
+out_device:
+       platform_device_unregister(pdev);
+out_driver:
+       platform_driver_unregister(&hdaps_driver);
+out_region:
+       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+out:
+       printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
+       return ret;
+}
+
+static void __exit hdaps_exit(void)
+{
+       input_unregister_polled_device(hdaps_idev);
+       input_free_polled_device(hdaps_idev);
+       sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&hdaps_driver);
+       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+
+       printk(KERN_INFO "hdaps: driver unloaded.\n");
+}
+
+module_init(hdaps_init);
+module_exit(hdaps_exit);
+
+module_param_named(invert, hdaps_invert, int, 0);
+MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
+                "2 invert y-axis, 3 invert both axes.");
+
+MODULE_AUTHOR("Robert Love");
+MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
+MODULE_LICENSE("GPL v2");
index c1741142a4cb64c3cf1c705bbd1385c03d89778c..1dac659b5e0c84e7bc3ccefea144d6a3dc88993c 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/rfkill.h>
@@ -88,24 +89,16 @@ struct bios_return {
        u32 value;
 };
 
-struct key_entry {
-       char type;              /* See KE_* below */
-       u16 code;
-       u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry hp_wmi_keymap[] = {
-       {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
-       {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
-       {KE_KEY, 0x20e6, KEY_PROG1},
-       {KE_KEY, 0x20e8, KEY_MEDIA},
-       {KE_KEY, 0x2142, KEY_MEDIA},
-       {KE_KEY, 0x213b, KEY_INFO},
-       {KE_KEY, 0x2169, KEY_DIRECTION},
-       {KE_KEY, 0x231b, KEY_HELP},
-       {KE_END, 0}
+static const struct key_entry hp_wmi_keymap[] = {
+       { KE_KEY, 0x02,   { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0x03,   { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY, 0x20e6, { KEY_PROG1 } },
+       { KE_KEY, 0x20e8, { KEY_MEDIA } },
+       { KE_KEY, 0x2142, { KEY_MEDIA } },
+       { KE_KEY, 0x213b, { KEY_INFO } },
+       { KE_KEY, 0x2169, { KEY_DIRECTION } },
+       { KE_KEY, 0x231b, { KEY_HELP } },
+       { KE_END, 0 }
 };
 
 static struct input_dev *hp_wmi_input_dev;
@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
 
-static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
-{
-       struct key_entry *key;
-
-       for (key = hp_wmi_keymap; key->type != KE_END; key++)
-               if (code == key->code)
-                       return key;
-
-       return NULL;
-}
-
-static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
-{
-       struct key_entry *key;
-
-       for (key = hp_wmi_keymap; key->type != KE_END; key++)
-               if (key->type == KE_KEY && keycode == key->keycode)
-                       return key;
-
-       return NULL;
-}
-
-static int hp_wmi_getkeycode(struct input_dev *dev,
-                            unsigned int scancode, unsigned int *keycode)
-{
-       struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
-
-       if (key && key->type == KE_KEY) {
-               *keycode = key->keycode;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int hp_wmi_setkeycode(struct input_dev *dev,
-                            unsigned int scancode, unsigned int keycode)
-{
-       struct key_entry *key;
-       unsigned int old_keycode;
-
-       key = hp_wmi_get_entry_by_scancode(scancode);
-       if (key && key->type == KE_KEY) {
-               old_keycode = key->keycode;
-               key->keycode = keycode;
-               set_bit(keycode, dev->keybit);
-               if (!hp_wmi_get_entry_by_keycode(old_keycode))
-                       clear_bit(old_keycode, dev->keybit);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
 static void hp_wmi_notify(u32 value, void *context)
 {
        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
-       static struct key_entry *key;
        union acpi_object *obj;
        u32 event_id, event_data;
        int key_code = 0, ret;
@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
                                           sizeof(key_code));
                if (ret)
                        break;
-               key = hp_wmi_get_entry_by_scancode(key_code);
-               if (key) {
-                       switch (key->type) {
-                       case KE_KEY:
-                               input_report_key(hp_wmi_input_dev,
-                                                key->keycode, 1);
-                               input_sync(hp_wmi_input_dev);
-                               input_report_key(hp_wmi_input_dev,
-                                                key->keycode, 0);
-                               input_sync(hp_wmi_input_dev);
-                               break;
-                       }
-               } else
+
+               if (!sparse_keymap_report_event(hp_wmi_input_dev,
+                                               key_code, 1, true))
                        printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
                               key_code);
                break;
@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
 
 static int __init hp_wmi_input_setup(void)
 {
-       struct key_entry *key;
+       acpi_status status;
        int err;
 
        hp_wmi_input_dev = input_allocate_device();
@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
        hp_wmi_input_dev->name = "HP WMI hotkeys";
        hp_wmi_input_dev->phys = "wmi/input0";
        hp_wmi_input_dev->id.bustype = BUS_HOST;
-       hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
-       hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
-
-       for (key = hp_wmi_keymap; key->type != KE_END; key++) {
-               switch (key->type) {
-               case KE_KEY:
-                       set_bit(EV_KEY, hp_wmi_input_dev->evbit);
-                       set_bit(key->keycode, hp_wmi_input_dev->keybit);
-                       break;
-               }
-       }
 
-       set_bit(EV_SW, hp_wmi_input_dev->evbit);
-       set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
-       set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+       __set_bit(EV_SW, hp_wmi_input_dev->evbit);
+       __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+       __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+       err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
+       if (err)
+               goto err_free_dev;
 
        /* Set initial hardware state */
        input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
                            hp_wmi_tablet_state());
        input_sync(hp_wmi_input_dev);
 
-       err = input_register_device(hp_wmi_input_dev);
-
-       if (err) {
-               input_free_device(hp_wmi_input_dev);
-               return err;
+       status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
+       if (ACPI_FAILURE(status)) {
+               err = -EIO;
+               goto err_free_keymap;
        }
 
+       err = input_register_device(hp_wmi_input_dev);
+       if (err)
+               goto err_uninstall_notifier;
+
        return 0;
+
+ err_uninstall_notifier:
+       wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ err_free_keymap:
+       sparse_keymap_free(hp_wmi_input_dev);
+ err_free_dev:
+       input_free_device(hp_wmi_input_dev);
+       return err;
+}
+
+static void hp_wmi_input_destroy(void)
+{
+       wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+       sparse_keymap_free(hp_wmi_input_dev);
+       input_unregister_device(hp_wmi_input_dev);
 }
 
 static void cleanup_sysfs(struct platform_device *device)
@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
        int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
 
        if (event_capable) {
-               err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
-                                                hp_wmi_notify, NULL);
-               if (ACPI_FAILURE(err))
-                       return -EINVAL;
                err = hp_wmi_input_setup();
-               if (err) {
-                       wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+               if (err)
                        return err;
-               }
        }
 
        if (bios_capable) {
@@ -739,20 +672,17 @@ err_device_add:
 err_device_alloc:
        platform_driver_unregister(&hp_wmi_driver);
 err_driver_reg:
-       if (wmi_has_guid(HPWMI_EVENT_GUID)) {
-               input_unregister_device(hp_wmi_input_dev);
-               wmi_remove_notify_handler(HPWMI_EVENT_GUID);
-       }
+       if (event_capable)
+               hp_wmi_input_destroy();
 
        return err;
 }
 
 static void __exit hp_wmi_exit(void)
 {
-       if (wmi_has_guid(HPWMI_EVENT_GUID)) {
-               wmi_remove_notify_handler(HPWMI_EVENT_GUID);
-               input_unregister_device(hp_wmi_input_dev);
-       }
+       if (wmi_has_guid(HPWMI_EVENT_GUID))
+               hp_wmi_input_destroy();
+
        if (hp_wmi_platform_dev) {
                platform_device_unregister(hp_wmi_platform_dev);
                platform_driver_unregister(&hp_wmi_driver);
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644 (file)
index 0000000..3c2c6b9
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ *         Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO    1
+#define RTL_ADDR_TYPE_MMIO  2
+
+#define RTL_CMD_ENTER_PRTM  1
+#define RTL_CMD_EXIT_PRTM   2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+       char signature[5]; /* signature should be "_RTL_" */
+       u8 version;
+       u8 rt_status;
+       u8 command;
+       u8 command_status;
+       u8 cmd_address_type;
+       u8 cmd_granularity;
+       u8 cmd_offset;
+       u16 reserve1;
+       u32 cmd_port_address; /* platform dependent address */
+       u32 cmd_port_value;   /* platform dependent value */
+} __attribute__((packed));
+
+/* to locate "_RTL_" signature do a masked 5-byte integer compare */
+#define RTL_SIGNATURE 0x0000005f4c54525fULL
+#define RTL_MASK      0x000000ffffffffffULL
+
+#define RTL_DEBUG(A, ...) do { \
+       if (debug) \
+               pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+       if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+               return ioremap(addr, len);
+       return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+       if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+               iounmap(addr);
+       else
+               ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+       int ret = 0, count = 0;
+       static u32 cmd_port_val;
+
+       RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+       value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+       mutex_lock(&rtl_lock);
+
+       if (ioread8(&rtl_table->rt_status) != value) {
+               iowrite8(value, &rtl_table->command);
+
+               switch (rtl_cmd_width) {
+               case 8:
+                       cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+                       RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+                       iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+                       break;
+               case 16:
+                       cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+                       RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+                       iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+                       break;
+               case 32:
+                       cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+                       RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+                       iowrite32(cmd_port_val, rtl_cmd_addr);
+                       break;
+               }
+
+               while (ioread8(&rtl_table->command)) {
+                       msleep(10);
+                       if (count++ > 500) {
+                               pr_err("ibm-rtl: Hardware not responding to "
+                                       "mode switch request\n");
+                               ret = -EIO;
+                               break;
+                       }
+
+               }
+
+               if (ioread8(&rtl_table->command_status)) {
+                       RTL_DEBUG("command_status reports failed command\n");
+                       ret = -EIO;
+               }
+       }
+
+       mutex_unlock(&rtl_lock);
+       return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+                                struct sysdev_class_attribute *attr,
+                                char *buf)
+{
+       return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+                              struct sysdev_class_attribute *attr,
+                              char *buf)
+{
+       return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+                             struct sysdev_class_attribute *attr,
+                             const char *buf,
+                             size_t count)
+{
+       ssize_t ret;
+
+       if (count < 1 || count > 2)
+               return -EINVAL;
+
+       switch (buf[0]) {
+       case '0':
+               ret = ibm_rtl_write(0);
+               break;
+       case '1':
+               ret = ibm_rtl_write(1);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       if (ret >= 0)
+               ret = count;
+
+       return ret;
+}
+
+static struct sysdev_class class_rtl = {
+       .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+       &attr_version,
+       &attr_state,
+       NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+       int ret, i;
+       ret = sysdev_class_register(&class_rtl);
+
+       if (!ret) {
+               for (i = 0; rtl_attributes[i]; i ++)
+                       sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+       }
+       return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+       int i;
+       for (i = 0; rtl_attributes[i]; i ++)
+               sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+       sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+       RTL_DEBUG("found IBM server '%s'\n", id->ident);
+       return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE)                  \
+{                                                  \
+       .ident = NAME,                             \
+       .matches = {                               \
+               DMI_MATCH(DMI_SYS_VENDOR, "IBM"),  \
+               DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+       },                                         \
+       .callback = dmi_check_cb                   \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+       ibm_dmi_entry("BladeCenter LS21", "7971"),
+       ibm_dmi_entry("BladeCenter LS22", "7901"),
+       ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+       ibm_dmi_entry("BladeCenter HS22", "7870"),
+       ibm_dmi_entry("BladeCenter HS22V", "7871"),
+       ibm_dmi_entry("System x3550 M2", "7946"),
+       ibm_dmi_entry("System x3650 M2", "7947"),
+       ibm_dmi_entry("System x3550 M3", "7944"),
+       ibm_dmi_entry("System x3650 M3", "7945"),
+       { }
+};
+
+static int __init ibm_rtl_init(void) {
+       unsigned long ebda_addr, ebda_size;
+       unsigned int ebda_kb;
+       int ret = -ENODEV, i;
+
+       if (force)
+               pr_warning("ibm-rtl: module loaded by force\n");
+       /* first ensure that we are running on IBM HW */
+       else if (!dmi_check_system(ibm_rtl_dmi_table))
+               return -ENODEV;
+
+       /* Get the address for the Extended BIOS Data Area */
+       ebda_addr = get_bios_ebda();
+       if (!ebda_addr) {
+               RTL_DEBUG("no BIOS EBDA found\n");
+               return -ENODEV;
+       }
+
+       ebda_map = ioremap(ebda_addr, 4);
+       if (!ebda_map)
+               return -ENOMEM;
+
+       /* First word in the EDBA is the Size in KB */
+       ebda_kb = ioread16(ebda_map);
+       RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+       if (ebda_kb == 0)
+               goto out;
+
+       iounmap(ebda_map);
+       ebda_size = ebda_kb*1024;
+
+       /* Remap the whole table */
+       ebda_map = ioremap(ebda_addr, ebda_size);
+       if (!ebda_map)
+               return -ENOMEM;
+
+       /* search for the _RTL_ signature at the start of the table */
+       for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+               struct ibm_rtl_table __iomem * tmp;
+               tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+               if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
+                       phys_addr_t addr;
+                       unsigned int plen;
+                       RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+                       rtl_table = tmp;
+                       /* The address, value, width and offset are platform
+                        * dependent and found in the ibm_rtl_table */
+                       rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+                       rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+                       RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+                             rtl_cmd_width, rtl_cmd_type);
+                       addr = ioread32(&rtl_table->cmd_port_address);
+                       RTL_DEBUG("addr = %#llx\n", addr);
+                       plen = rtl_cmd_width/sizeof(char);
+                       rtl_cmd_addr = rtl_port_map(addr, plen);
+                       RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+                       if (!rtl_cmd_addr) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       ret = rtl_setup_sysfs();
+                       break;
+               }
+       }
+
+out:
+       if (ret) {
+               iounmap(ebda_map);
+               rtl_port_unmap(rtl_cmd_addr);
+       }
+
+       return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+       if (rtl_table) {
+               RTL_DEBUG("cleaning up");
+               /* do not leave the machine in SMI-free mode */
+               ibm_rtl_write(0);
+               /* unmap, unlink and remove all traces */
+               rtl_teardown_sysfs();
+               iounmap(ebda_map);
+               rtl_port_unmap(rtl_cmd_addr);
+       }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
new file mode 100644 (file)
index 0000000..5ff1220
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ *  ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
+ *
+ *  Copyright © 2010 Intel Corporation
+ *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/rfkill.h>
+
+#define IDEAPAD_DEV_CAMERA     0
+#define IDEAPAD_DEV_WLAN       1
+#define IDEAPAD_DEV_BLUETOOTH  2
+#define IDEAPAD_DEV_3G         3
+#define IDEAPAD_DEV_KILLSW     4
+
+struct ideapad_private {
+       acpi_handle handle;
+       struct rfkill *rfk[5];
+} *ideapad_priv;
+
+static struct {
+       char *name;
+       int cfgbit;
+       int opcode;
+       int type;
+} ideapad_rfk_data[] = {
+       { "ideapad_camera",     19, 0x1E, NUM_RFKILL_TYPES },
+       { "ideapad_wlan",       18, 0x15, RFKILL_TYPE_WLAN },
+       { "ideapad_bluetooth",  16, 0x17, RFKILL_TYPE_BLUETOOTH },
+       { "ideapad_3g",         17, 0x20, RFKILL_TYPE_WWAN },
+       { "ideapad_killsw",     0,  0,    RFKILL_TYPE_WLAN }
+};
+
+static bool no_bt_rfkill;
+module_param(no_bt_rfkill, bool, 0444);
+MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
+
+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (100) /* in ms */
+
+static int read_method_int(acpi_handle handle, const char *method, int *val)
+{
+       acpi_status status;
+       unsigned long long result;
+
+       status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+       if (ACPI_FAILURE(status)) {
+               *val = -1;
+               return -1;
+       } else {
+               *val = result;
+               return 0;
+       }
+}
+
+static int method_vpcr(acpi_handle handle, int cmd, int *ret)
+{
+       acpi_status status;
+       unsigned long long result;
+       struct acpi_object_list params;
+       union acpi_object in_obj;
+
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_INTEGER;
+       in_obj.integer.value = cmd;
+
+       status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
+
+       if (ACPI_FAILURE(status)) {
+               *ret = -1;
+               return -1;
+       } else {
+               *ret = result;
+               return 0;
+       }
+}
+
+static int method_vpcw(acpi_handle handle, int cmd, int data)
+{
+       struct acpi_object_list params;
+       union acpi_object in_obj[2];
+       acpi_status status;
+
+       params.count = 2;
+       params.pointer = in_obj;
+       in_obj[0].type = ACPI_TYPE_INTEGER;
+       in_obj[0].integer.value = cmd;
+       in_obj[1].type = ACPI_TYPE_INTEGER;
+       in_obj[1].integer.value = data;
+
+       status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+       if (status != AE_OK)
+               return -1;
+       return 0;
+}
+
+static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
+{
+       int val;
+       unsigned long int end_jiffies;
+
+       if (method_vpcw(handle, 1, cmd))
+               return -1;
+
+       for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+            time_before(jiffies, end_jiffies);) {
+               schedule();
+               if (method_vpcr(handle, 1, &val))
+                       return -1;
+               if (val == 0) {
+                       if (method_vpcr(handle, 0, &val))
+                               return -1;
+                       *data = val;
+                       return 0;
+               }
+       }
+       pr_err("timeout in read_ec_cmd\n");
+       return -1;
+}
+
+static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
+{
+       int val;
+       unsigned long int end_jiffies;
+
+       if (method_vpcw(handle, 0, data))
+               return -1;
+       if (method_vpcw(handle, 1, cmd))
+               return -1;
+
+       for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+            time_before(jiffies, end_jiffies);) {
+               schedule();
+               if (method_vpcr(handle, 1, &val))
+                       return -1;
+               if (val == 0)
+                       return 0;
+       }
+       pr_err("timeout in write_ec_cmd\n");
+       return -1;
+}
+/* the above is ACPI helpers */
+
+static ssize_t show_ideapad_cam(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+       acpi_handle handle = priv->handle;
+       unsigned long result;
+
+       if (read_ec_data(handle, 0x1D, &result))
+               return sprintf(buf, "-1\n");
+       return sprintf(buf, "%lu\n", result);
+}
+
+static ssize_t store_ideapad_cam(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+       acpi_handle handle = priv->handle;
+       int ret, state;
+
+       if (!count)
+               return 0;
+       if (sscanf(buf, "%i", &state) != 1)
+               return -EINVAL;
+       ret = write_ec_cmd(handle, 0x1E, state);
+       if (ret < 0)
+               return ret;
+       return count;
+}
+
+static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
+
+static int ideapad_rfk_set(void *data, bool blocked)
+{
+       int device = (unsigned long)data;
+
+       if (device == IDEAPAD_DEV_KILLSW)
+               return -EINVAL;
+
+       return write_ec_cmd(ideapad_priv->handle,
+                           ideapad_rfk_data[device].opcode,
+                           !blocked);
+}
+
+static struct rfkill_ops ideapad_rfk_ops = {
+       .set_block = ideapad_rfk_set,
+};
+
+static void ideapad_sync_rfk_state(struct acpi_device *adevice)
+{
+       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+       acpi_handle handle = priv->handle;
+       unsigned long hw_blocked;
+       int i;
+
+       if (read_ec_data(handle, 0x23, &hw_blocked))
+               return;
+       hw_blocked = !hw_blocked;
+
+       for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+               if (priv->rfk[i])
+                       rfkill_set_hw_state(priv->rfk[i], hw_blocked);
+}
+
+static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
+{
+       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+       int ret;
+       unsigned long sw_blocked;
+
+       if (no_bt_rfkill &&
+           (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
+               /* Force to enable bluetooth when no_bt_rfkill=1 */
+               write_ec_cmd(ideapad_priv->handle,
+                            ideapad_rfk_data[dev].opcode, 1);
+               return 0;
+       }
+
+       priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
+                                     ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
+                                     (void *)(long)dev);
+       if (!priv->rfk[dev])
+               return -ENOMEM;
+
+       if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+                        &sw_blocked)) {
+               rfkill_init_sw_state(priv->rfk[dev], 0);
+       } else {
+               sw_blocked = !sw_blocked;
+               rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
+       }
+
+       ret = rfkill_register(priv->rfk[dev]);
+       if (ret) {
+               rfkill_destroy(priv->rfk[dev]);
+               return ret;
+       }
+       return 0;
+}
+
+static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
+{
+       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+
+       if (!priv->rfk[dev])
+               return;
+
+       rfkill_unregister(priv->rfk[dev]);
+       rfkill_destroy(priv->rfk[dev]);
+}
+
+static const struct acpi_device_id ideapad_device_ids[] = {
+       { "VPC2004", 0},
+       { "", 0},
+};
+MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
+
+static int ideapad_acpi_add(struct acpi_device *adevice)
+{
+       int i, cfg;
+       int devs_present[5];
+       struct ideapad_private *priv;
+
+       if (read_method_int(adevice->handle, "_CFG", &cfg))
+               return -ENODEV;
+
+       for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
+               if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+                       devs_present[i] = 1;
+               else
+                       devs_present[i] = 0;
+       }
+
+       /* The hardware switch is always present */
+       devs_present[IDEAPAD_DEV_KILLSW] = 1;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       if (devs_present[IDEAPAD_DEV_CAMERA]) {
+               int ret = device_create_file(&adevice->dev, &dev_attr_camera_power);
+               if (ret) {
+                       kfree(priv);
+                       return ret;
+               }
+       }
+
+       priv->handle = adevice->handle;
+       dev_set_drvdata(&adevice->dev, priv);
+       ideapad_priv = priv;
+       for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
+               if (!devs_present[i])
+                       continue;
+
+               ideapad_register_rfkill(adevice, i);
+       }
+       ideapad_sync_rfk_state(adevice);
+       return 0;
+}
+
+static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
+{
+       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+       int i;
+
+       device_remove_file(&adevice->dev, &dev_attr_camera_power);
+
+       for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+               ideapad_unregister_rfkill(adevice, i);
+
+       dev_set_drvdata(&adevice->dev, NULL);
+       kfree(priv);
+       return 0;
+}
+
+static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
+{
+       acpi_handle handle = adevice->handle;
+       unsigned long vpc1, vpc2, vpc_bit;
+
+       if (read_ec_data(handle, 0x10, &vpc1))
+               return;
+       if (read_ec_data(handle, 0x1A, &vpc2))
+               return;
+
+       vpc1 = (vpc2 << 8) | vpc1;
+       for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
+               if (test_bit(vpc_bit, &vpc1)) {
+                       if (vpc_bit == 9)
+                               ideapad_sync_rfk_state(adevice);
+               }
+       }
+}
+
+static struct acpi_driver ideapad_acpi_driver = {
+       .name = "ideapad_acpi",
+       .class = "IdeaPad",
+       .ids = ideapad_device_ids,
+       .ops.add = ideapad_acpi_add,
+       .ops.remove = ideapad_acpi_remove,
+       .ops.notify = ideapad_acpi_notify,
+       .owner = THIS_MODULE,
+};
+
+
+static int __init ideapad_acpi_module_init(void)
+{
+       acpi_bus_register_driver(&ideapad_acpi_driver);
+
+       return 0;
+}
+
+
+static void __exit ideapad_acpi_module_exit(void)
+{
+       acpi_bus_unregister_driver(&ideapad_acpi_driver);
+
+}
+
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("IdeaPad ACPI Extras");
+MODULE_LICENSE("GPL");
+
+module_init(ideapad_acpi_module_init);
+module_exit(ideapad_acpi_module_exit);
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
deleted file mode 100644 (file)
index 7984963..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- *  ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
- *
- *  Copyright © 2010 Intel Corporation
- *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the 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/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-#include <linux/rfkill.h>
-
-#define IDEAPAD_DEV_CAMERA     0
-#define IDEAPAD_DEV_WLAN       1
-#define IDEAPAD_DEV_BLUETOOTH  2
-#define IDEAPAD_DEV_3G         3
-#define IDEAPAD_DEV_KILLSW     4
-
-struct ideapad_private {
-       struct rfkill *rfk[5];
-};
-
-static struct {
-       char *name;
-       int type;
-} ideapad_rfk_data[] = {
-       /* camera has no rfkill */
-       { "ideapad_wlan",       RFKILL_TYPE_WLAN },
-       { "ideapad_bluetooth",  RFKILL_TYPE_BLUETOOTH },
-       { "ideapad_3g",         RFKILL_TYPE_WWAN },
-       { "ideapad_killsw",     RFKILL_TYPE_WLAN }
-};
-
-static int ideapad_dev_exists(int device)
-{
-       acpi_status status;
-       union acpi_object in_param;
-       struct acpi_object_list input = { 1, &in_param };
-       struct acpi_buffer output;
-       union acpi_object out_obj;
-
-       output.length = sizeof(out_obj);
-       output.pointer = &out_obj;
-
-       in_param.type = ACPI_TYPE_INTEGER;
-       in_param.integer.value = device + 1;
-
-       status = acpi_evaluate_object(NULL, "\\_SB_.DECN", &input, &output);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method failed %d. Is this an IdeaPAD?\n", status);
-               return -ENODEV;
-       }
-       if (out_obj.type != ACPI_TYPE_INTEGER) {
-               printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method returned unexpected type\n");
-               return -ENODEV;
-       }
-       return out_obj.integer.value;
-}
-
-static int ideapad_dev_get_state(int device)
-{
-       acpi_status status;
-       union acpi_object in_param;
-       struct acpi_object_list input = { 1, &in_param };
-       struct acpi_buffer output;
-       union acpi_object out_obj;
-
-       output.length = sizeof(out_obj);
-       output.pointer = &out_obj;
-
-       in_param.type = ACPI_TYPE_INTEGER;
-       in_param.integer.value = device + 1;
-
-       status = acpi_evaluate_object(NULL, "\\_SB_.GECN", &input, &output);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method failed %d\n", status);
-               return -ENODEV;
-       }
-       if (out_obj.type != ACPI_TYPE_INTEGER) {
-               printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method returned unexpected type\n");
-               return -ENODEV;
-       }
-       return out_obj.integer.value;
-}
-
-static int ideapad_dev_set_state(int device, int state)
-{
-       acpi_status status;
-       union acpi_object in_params[2];
-       struct acpi_object_list input = { 2, in_params };
-
-       in_params[0].type = ACPI_TYPE_INTEGER;
-       in_params[0].integer.value = device + 1;
-       in_params[1].type = ACPI_TYPE_INTEGER;
-       in_params[1].integer.value = state;
-
-       status = acpi_evaluate_object(NULL, "\\_SB_.SECN", &input, NULL);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_WARNING "IdeaPAD \\_SB_.SECN method failed %d\n", status);
-               return -ENODEV;
-       }
-       return 0;
-}
-static ssize_t show_ideapad_cam(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       int state = ideapad_dev_get_state(IDEAPAD_DEV_CAMERA);
-       if (state < 0)
-               return state;
-
-       return sprintf(buf, "%d\n", state);
-}
-
-static ssize_t store_ideapad_cam(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       int ret, state;
-
-       if (!count)
-               return 0;
-       if (sscanf(buf, "%i", &state) != 1)
-               return -EINVAL;
-       ret = ideapad_dev_set_state(IDEAPAD_DEV_CAMERA, !!state);
-       if (ret < 0)
-               return ret;
-       return count;
-}
-
-static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
-
-static int ideapad_rfk_set(void *data, bool blocked)
-{
-       int device = (unsigned long)data;
-
-       if (device == IDEAPAD_DEV_KILLSW)
-               return -EINVAL;
-       return ideapad_dev_set_state(device, !blocked);
-}
-
-static struct rfkill_ops ideapad_rfk_ops = {
-       .set_block = ideapad_rfk_set,
-};
-
-static void ideapad_sync_rfk_state(struct acpi_device *adevice)
-{
-       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
-       int hw_blocked = !ideapad_dev_get_state(IDEAPAD_DEV_KILLSW);
-       int i;
-
-       rfkill_set_hw_state(priv->rfk[IDEAPAD_DEV_KILLSW], hw_blocked);
-       for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
-               if (priv->rfk[i])
-                       rfkill_set_hw_state(priv->rfk[i], hw_blocked);
-       if (hw_blocked)
-               return;
-
-       for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
-               if (priv->rfk[i])
-                       rfkill_set_sw_state(priv->rfk[i], !ideapad_dev_get_state(i));
-}
-
-static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
-{
-       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
-       int ret;
-
-       priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev-1].name, &adevice->dev,
-                                     ideapad_rfk_data[dev-1].type, &ideapad_rfk_ops,
-                                     (void *)(long)dev);
-       if (!priv->rfk[dev])
-               return -ENOMEM;
-
-       ret = rfkill_register(priv->rfk[dev]);
-       if (ret) {
-               rfkill_destroy(priv->rfk[dev]);
-               return ret;
-       }
-       return 0;
-}
-
-static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
-{
-       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
-
-       if (!priv->rfk[dev])
-               return;
-
-       rfkill_unregister(priv->rfk[dev]);
-       rfkill_destroy(priv->rfk[dev]);
-}
-
-static const struct acpi_device_id ideapad_device_ids[] = {
-       { "VPC2004", 0},
-       { "", 0},
-};
-MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
-
-static int ideapad_acpi_add(struct acpi_device *adevice)
-{
-       int i;
-       int devs_present[5];
-       struct ideapad_private *priv;
-
-       for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
-               devs_present[i] = ideapad_dev_exists(i);
-               if (devs_present[i] < 0)
-                       return devs_present[i];
-       }
-
-       /* The hardware switch is always present */
-       devs_present[IDEAPAD_DEV_KILLSW] = 1;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       if (devs_present[IDEAPAD_DEV_CAMERA]) {
-               int ret = device_create_file(&adevice->dev, &dev_attr_camera_power);
-               if (ret) {
-                       kfree(priv);
-                       return ret;
-               }
-       }
-
-       dev_set_drvdata(&adevice->dev, priv);
-       for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
-               if (!devs_present[i])
-                       continue;
-
-               ideapad_register_rfkill(adevice, i);
-       }
-       ideapad_sync_rfk_state(adevice);
-       return 0;
-}
-
-static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
-{
-       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
-       int i;
-
-       device_remove_file(&adevice->dev, &dev_attr_camera_power);
-
-       for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
-               ideapad_unregister_rfkill(adevice, i);
-
-       dev_set_drvdata(&adevice->dev, NULL);
-       kfree(priv);
-       return 0;
-}
-
-static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
-{
-       ideapad_sync_rfk_state(adevice);
-}
-
-static struct acpi_driver ideapad_acpi_driver = {
-       .name = "ideapad_acpi",
-       .class = "IdeaPad",
-       .ids = ideapad_device_ids,
-       .ops.add = ideapad_acpi_add,
-       .ops.remove = ideapad_acpi_remove,
-       .ops.notify = ideapad_acpi_notify,
-       .owner = THIS_MODULE,
-};
-
-
-static int __init ideapad_acpi_module_init(void)
-{
-       acpi_bus_register_driver(&ideapad_acpi_driver);
-
-       return 0;
-}
-
-
-static void __exit ideapad_acpi_module_exit(void)
-{
-       acpi_bus_unregister_driver(&ideapad_acpi_driver);
-
-}
-
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("IdeaPad ACPI Extras");
-MODULE_LICENSE("GPL");
-
-module_init(ideapad_acpi_module_init);
-module_exit(ideapad_acpi_module_exit);
index 5cdcff65391872702cb63c34b9a3ea7488ff25bf..f540ff96c53f8b732dcd4667a9afeccb64fc13dd 100644 (file)
@@ -142,16 +142,16 @@ static int pmic_gpio_direction_output(struct gpio_chip *chip,
 
        if (offset < 8)/* it is GPIO */
                rc = intel_scu_ipc_update_register(GPIO0 + offset,
-                               GPIO_DRV | GPIO_DOU | GPIO_DIR,
-                               GPIO_DRV | (value ? GPIO_DOU : 0));
+                               GPIO_DRV | (value ? GPIO_DOU : 0),
+                               GPIO_DRV | GPIO_DOU | GPIO_DIR);
        else if (offset < 16)/* it is GPOSW */
                rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
-                               GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
-                               GPOSW_DRV | (value ? GPOSW_DOU : 0));
+                               GPOSW_DRV | (value ? GPOSW_DOU : 0),
+                               GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
        else if (offset > 15 && offset < 24)/* it is GPO */
                rc = intel_scu_ipc_update_register(GPO,
-                               1 << (offset - 16),
-                               value ? 1 << (offset - 16) : 0);
+                               value ? 1 << (offset - 16) : 0,
+                               1 << (offset - 16));
        else {
                printk(KERN_ERR
                        "%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
@@ -179,16 +179,16 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        if (offset < 8)/* it is GPIO */
                intel_scu_ipc_update_register(GPIO0 + offset,
-                       GPIO_DRV | GPIO_DOU,
-                       GPIO_DRV | (value ? GPIO_DOU : 0));
+                       GPIO_DRV | (value ? GPIO_DOU : 0),
+                       GPIO_DRV | GPIO_DOU);
        else if (offset < 16)/* it is GPOSW */
                intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
-                       GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
-                       GPOSW_DRV | (value ? GPOSW_DOU : 0));
+                       GPOSW_DRV | (value ? GPOSW_DOU : 0),
+                       GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
        else if (offset > 15 && offset < 24) /* it is GPO */
                intel_scu_ipc_update_register(GPO,
-                       1 << (offset - 16),
-                       value ? 1 << (offset - 16) : 0);
+                       value ? 1 << (offset - 16) : 0,
+                       1 << (offset - 16));
 }
 
 static int pmic_irq_type(unsigned irq, unsigned type)
@@ -197,7 +197,7 @@ static int pmic_irq_type(unsigned irq, unsigned type)
        u32 gpio = irq - pg->irq_base;
        unsigned long flags;
 
-       if (gpio > pg->chip.ngpio)
+       if (gpio >= pg->chip.ngpio)
                return -EINVAL;
 
        spin_lock_irqsave(&pg->irqtypes.lock, flags);
index 6abe18e638e976f325ba92c9892bd2cc1501f4a8..41a9e34899ac5f81da6dde61f6aa2a1d34e2e134 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/sfi.h>
 #include <asm/mrst.h>
 #include <asm/intel_scu_ipc.h>
 
index ec01c3d8fc5a99a0f56eaed762ddf52df569ad8f..cc1e0ba104d749603957d0017d6f1a364b38cc0b 100644 (file)
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 
 #ifndef ACPI_HOTKEY_COMPONENT
@@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = {
                        },
 };
 
-#define KEYMAP_SIZE            11
-static const unsigned int initial_keymap[KEYMAP_SIZE] = {
-       /*  0 */ KEY_RESERVED,
-       /*  1 */ KEY_BRIGHTNESSDOWN,
-       /*  2 */ KEY_BRIGHTNESSUP,
-       /*  3 */ KEY_DISPLAYTOGGLE,
-       /*  4 */ KEY_MUTE,
-       /*  5 */ KEY_VOLUMEDOWN,
-       /*  6 */ KEY_VOLUMEUP,
-       /*  7 */ KEY_SLEEP,
-       /*  8 */ KEY_PROG1, /* Change CPU boost */
-       /*  9 */ KEY_BATTERY,
-       /* 10 */ KEY_SUSPEND,
+static const struct key_entry panasonic_keymap[] = {
+       { KE_KEY, 0, { KEY_RESERVED } },
+       { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
+       { KE_KEY, 4, { KEY_MUTE } },
+       { KE_KEY, 5, { KEY_VOLUMEDOWN } },
+       { KE_KEY, 6, { KEY_VOLUMEUP } },
+       { KE_KEY, 7, { KEY_SLEEP } },
+       { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
+       { KE_KEY, 9, { KEY_BATTERY } },
+       { KE_KEY, 10, { KEY_SUSPEND } },
+       { KE_END, 0 }
 };
 
 struct pcc_acpi {
        acpi_handle             handle;
        unsigned long           num_sifr;
        int                     sticky_mode;
-       u32                     *sinf;
+       u32                     *sinf;
        struct acpi_device      *device;
        struct input_dev        *input_dev;
        struct backlight_device *backlight;
-       unsigned int            keymap[KEYMAP_SIZE];
 };
 
 struct pcc_keyinput {
@@ -267,7 +267,7 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device)
        }
 }
 
-static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
 {
        acpi_status status;
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -285,6 +285,7 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
        hkey = buffer.pointer;
        if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+               status = AE_ERROR;
                goto end;
        }
 
@@ -298,12 +299,12 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
        for (i = 0; i < hkey->package.count; i++) {
                union acpi_object *element = &(hkey->package.elements[i]);
                if (likely(element->type == ACPI_TYPE_INTEGER)) {
-                       sinf[i] = element->integer.value;
+                       pcc->sinf[i] = element->integer.value;
                } else
                        ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                         "Invalid HKEY.SINF data\n"));
        }
-       sinf[hkey->package.count] = -1;
+       pcc->sinf[hkey->package.count] = -1;
 
 end:
        kfree(buffer.pointer);
@@ -321,7 +322,7 @@ static int bl_get(struct backlight_device *bd)
 {
        struct pcc_acpi *pcc = bl_get_data(bd);
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        return pcc->sinf[SINF_AC_CUR_BRIGHT];
@@ -333,7 +334,7 @@ static int bl_set_status(struct backlight_device *bd)
        int bright = bd->props.brightness;
        int rc;
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
@@ -367,7 +368,7 @@ static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
        struct acpi_device *acpi = to_acpi_device(dev);
        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
@@ -379,7 +380,7 @@ static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
        struct acpi_device *acpi = to_acpi_device(dev);
        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
@@ -391,7 +392,7 @@ static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
        struct acpi_device *acpi = to_acpi_device(dev);
        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
@@ -403,7 +404,7 @@ static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
        struct acpi_device *acpi = to_acpi_device(dev);
        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+       if (!acpi_pcc_retrieve_biosdata(pcc))
                return -EIO;
 
        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
@@ -446,56 +447,10 @@ static struct attribute_group pcc_attr_group = {
 
 /* hotkey input device driver */
 
-static int pcc_getkeycode(struct input_dev *dev,
-                         unsigned int scancode, unsigned int *keycode)
-{
-       struct pcc_acpi *pcc = input_get_drvdata(dev);
-
-       if (scancode >= ARRAY_SIZE(pcc->keymap))
-               return -EINVAL;
-
-       *keycode = pcc->keymap[scancode];
-
-       return 0;
-}
-
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
-               if (pcc->keymap[i] == keycode)
-                       return i+1;
-       }
-
-       return 0;
-}
-
-static int pcc_setkeycode(struct input_dev *dev,
-                         unsigned int scancode, unsigned int keycode)
-{
-       struct pcc_acpi *pcc = input_get_drvdata(dev);
-       int oldkeycode;
-
-       if (scancode >= ARRAY_SIZE(pcc->keymap))
-               return -EINVAL;
-
-       oldkeycode = pcc->keymap[scancode];
-       pcc->keymap[scancode] = keycode;
-
-       set_bit(keycode, dev->keybit);
-
-       if (!keymap_get_by_keycode(pcc, oldkeycode))
-               clear_bit(oldkeycode, dev->keybit);
-
-       return 0;
-}
-
 static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
 {
        struct input_dev *hotk_input_dev = pcc->input_dev;
        int rc;
-       int key_code, hkey_num;
        unsigned long long result;
 
        rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
@@ -508,25 +463,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
 
        acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
 
-       hkey_num = result & 0xf;
-
-       if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
+       if (!sparse_keymap_report_event(hotk_input_dev,
+                                       result & 0xf, result & 0x80, false))
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "hotkey number out of range: %d\n",
-                                 hkey_num));
-               return;
-       }
-
-       key_code = pcc->keymap[hkey_num];
-
-       if (key_code != KEY_RESERVED) {
-               int pushed = (result & 0x80) ? TRUE : FALSE;
-
-               input_report_key(hotk_input_dev, key_code, pushed);
-               input_sync(hotk_input_dev);
-       }
-
-       return;
+                                 "Unknown hotkey event: %d\n", result));
 }
 
 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -545,40 +485,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
 
 static int acpi_pcc_init_input(struct pcc_acpi *pcc)
 {
-       int i, rc;
+       struct input_dev *input_dev;
+       int error;
 
-       pcc->input_dev = input_allocate_device();
-       if (!pcc->input_dev) {
+       input_dev = input_allocate_device();
+       if (!input_dev) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                  "Couldn't allocate input device for hotkey"));
                return -ENOMEM;
        }
 
-       pcc->input_dev->evbit[0] = BIT(EV_KEY);
-
-       pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
-       pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
-       pcc->input_dev->id.bustype = BUS_HOST;
-       pcc->input_dev->id.vendor = 0x0001;
-       pcc->input_dev->id.product = 0x0001;
-       pcc->input_dev->id.version = 0x0100;
-       pcc->input_dev->getkeycode = pcc_getkeycode;
-       pcc->input_dev->setkeycode = pcc_setkeycode;
+       input_dev->name = ACPI_PCC_DRIVER_NAME;
+       input_dev->phys = ACPI_PCC_INPUT_PHYS;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor = 0x0001;
+       input_dev->id.product = 0x0001;
+       input_dev->id.version = 0x0100;
 
-       /* load initial keymap */
-       memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+       error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
+       if (error) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                                 "Unable to setup input device keymap\n"));
+               goto err_free_dev;
+       }
 
-       for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
-               __set_bit(pcc->keymap[i], pcc->input_dev->keybit);
-       __clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+       error = input_register_device(input_dev);
+       if (error) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                                 "Unable to register input device\n"));
+               goto err_free_keymap;
+       }
 
-       input_set_drvdata(pcc->input_dev, pcc);
+       pcc->input_dev = input_dev;
+       return 0;
 
-       rc = input_register_device(pcc->input_dev);
-       if (rc < 0)
-               input_free_device(pcc->input_dev);
+ err_free_keymap:
+       sparse_keymap_free(input_dev);
+ err_free_dev:
+       input_free_device(input_dev);
+       return error;
+}
 
-       return rc;
+static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
+{
+       sparse_keymap_free(pcc->input_dev);
+       input_unregister_device(pcc->input_dev);
+       /*
+        * No need to input_free_device() since core input API refcounts
+        * and free()s the device.
+        */
 }
 
 /* kernel module interface */
@@ -636,12 +591,13 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
        if (result) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                  "Error installing keyinput handler\n"));
-               goto out_hotkey;
+               goto out_sinf;
        }
 
-       if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+       if (!acpi_pcc_retrieve_biosdata(pcc)) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                 "Couldn't retrieve BIOS data\n"));
+               result = -EIO;
                goto out_input;
        }
        /* initialize backlight */
@@ -651,7 +607,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
                                                   &pcc_backlight_ops, &props);
        if (IS_ERR(pcc->backlight)) {
                result = PTR_ERR(pcc->backlight);
-               goto out_sinf;
+               goto out_input;
        }
 
        /* read the initial brightness setting from the hardware */
@@ -669,12 +625,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
 
 out_backlight:
        backlight_device_unregister(pcc->backlight);
+out_input:
+       acpi_pcc_destroy_input(pcc);
 out_sinf:
        kfree(pcc->sinf);
-out_input:
-       input_unregister_device(pcc->input_dev);
-       /* no need to input_free_device() since core input API refcount and
-        * free()s the device */
 out_hotkey:
        kfree(pcc);
 
@@ -709,9 +663,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
 
        backlight_device_unregister(pcc->backlight);
 
-       input_unregister_device(pcc->input_dev);
-       /* no need to input_free_device() since core input API refcount and
-        * free()s the device */
+       acpi_pcc_destroy_input(pcc);
 
        kfree(pcc->sinf);
        kfree(pcc);
index ff4b476f1950856f101959c7c1ccc6caa2e89b4a..1d07d6d09f27a4f94c67de17b9c3cead101b0e84 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 #define ACPI_TOPSTAR_CLASS "topstar"
 
@@ -26,52 +27,37 @@ struct topstar_hkey {
        struct input_dev *inputdev;
 };
 
-struct tps_key_entry {
-       u8 code;
-       u16 keycode;
-};
-
-static struct tps_key_entry topstar_keymap[] = {
-       { 0x80, KEY_BRIGHTNESSUP },
-       { 0x81, KEY_BRIGHTNESSDOWN },
-       { 0x83, KEY_VOLUMEUP },
-       { 0x84, KEY_VOLUMEDOWN },
-       { 0x85, KEY_MUTE },
-       { 0x86, KEY_SWITCHVIDEOMODE },
-       { 0x87, KEY_F13 }, /* touchpad enable/disable key */
-       { 0x88, KEY_WLAN },
-       { 0x8a, KEY_WWW },
-       { 0x8b, KEY_MAIL },
-       { 0x8c, KEY_MEDIA },
-       { 0x96, KEY_F14 }, /* G key? */
-       { }
-};
-
-static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
-{
-       struct tps_key_entry *key;
-
-       for (key = topstar_keymap; key->code; key++)
-               if (code == key->code)
-                       return key;
+static const struct key_entry topstar_keymap[] = {
+       { KE_KEY, 0x80, { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY, 0x83, { KEY_VOLUMEUP } },
+       { KE_KEY, 0x84, { KEY_VOLUMEDOWN } },
+       { KE_KEY, 0x85, { KEY_MUTE } },
+       { KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } },
+       { KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */
+       { KE_KEY, 0x88, { KEY_WLAN } },
+       { KE_KEY, 0x8a, { KEY_WWW } },
+       { KE_KEY, 0x8b, { KEY_MAIL } },
+       { KE_KEY, 0x8c, { KEY_MEDIA } },
 
-       return NULL;
-}
-
-static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
-{
-       struct tps_key_entry *key;
+       /* Known non hotkey events don't handled or that we don't care yet */
+       { KE_IGNORE, 0x8e, },
+       { KE_IGNORE, 0x8f, },
+       { KE_IGNORE, 0x90, },
 
-       for (key = topstar_keymap; key->code; key++)
-               if (code == key->keycode)
-                       return key;
+       /*
+        * 'G key' generate two event codes, convert to only
+        * one event/key code for now, consider replacing by
+        * a switch (3G switch - SW_3G?)
+        */
+       { KE_KEY, 0x96, { KEY_F14 } },
+       { KE_KEY, 0x97, { KEY_F14 } },
 
-       return NULL;
-}
+       { KE_END, 0 }
+};
 
 static void acpi_topstar_notify(struct acpi_device *device, u32 event)
 {
-       struct tps_key_entry *key;
        static bool dup_evnt[2];
        bool *dup;
        struct topstar_hkey *hkey = acpi_driver_data(device);
@@ -86,27 +72,8 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event)
                *dup = true;
        }
 
-       /*
-        * 'G key' generate two event codes, convert to only
-        * one event/key code for now (3G switch?)
-        */
-       if (event == 0x97)
-               event = 0x96;
-
-       key = tps_get_key_by_scancode(event);
-       if (key) {
-               input_report_key(hkey->inputdev, key->keycode, 1);
-               input_sync(hkey->inputdev);
-               input_report_key(hkey->inputdev, key->keycode, 0);
-               input_sync(hkey->inputdev);
-               return;
-       }
-
-       /* Known non hotkey events don't handled or that we don't care yet */
-       if (event == 0x8e || event == 0x8f || event == 0x90)
-               return;
-
-       pr_info("unknown event = 0x%02x\n", event);
+       if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true))
+               pr_info("unknown event = 0x%02x\n", event);
 }
 
 static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
@@ -127,62 +94,41 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
        return 0;
 }
 
-static int topstar_getkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int *keycode)
-{
-       struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
-
-       if (!key)
-               return -EINVAL;
-
-       *keycode = key->keycode;
-       return 0;
-}
-
-static int topstar_setkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int keycode)
-{
-       struct tps_key_entry *key;
-       int old_keycode;
-
-       key = tps_get_key_by_scancode(scancode);
-
-       if (!key)
-               return -EINVAL;
-
-       old_keycode = key->keycode;
-       key->keycode = keycode;
-       set_bit(keycode, dev->keybit);
-       if (!tps_get_key_by_keycode(old_keycode))
-               clear_bit(old_keycode, dev->keybit);
-       return 0;
-}
-
 static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
 {
-       struct tps_key_entry *key;
+       struct input_dev *input;
+       int error;
 
-       hkey->inputdev = input_allocate_device();
-       if (!hkey->inputdev) {
+       input = input_allocate_device();
+       if (!input) {
                pr_err("Unable to allocate input device\n");
-               return -ENODEV;
+               return -ENOMEM;
        }
-       hkey->inputdev->name = "Topstar Laptop extra buttons";
-       hkey->inputdev->phys = "topstar/input0";
-       hkey->inputdev->id.bustype = BUS_HOST;
-       hkey->inputdev->getkeycode = topstar_getkeycode;
-       hkey->inputdev->setkeycode = topstar_setkeycode;
-       for (key = topstar_keymap; key->code; key++) {
-               set_bit(EV_KEY, hkey->inputdev->evbit);
-               set_bit(key->keycode, hkey->inputdev->keybit);
+
+       input->name = "Topstar Laptop extra buttons";
+       input->phys = "topstar/input0";
+       input->id.bustype = BUS_HOST;
+
+       error = sparse_keymap_setup(input, topstar_keymap, NULL);
+       if (error) {
+               pr_err("Unable to setup input device keymap\n");
+               goto err_free_dev;
        }
-       if (input_register_device(hkey->inputdev)) {
+
+       error = input_register_device(input);
+       if (error) {
                pr_err("Unable to register input device\n");
-               input_free_device(hkey->inputdev);
-               return -ENODEV;
+               goto err_free_keymap;
        }
 
+       hkey->inputdev = input;
        return 0;
+
+ err_free_keymap:
+       sparse_keymap_free(input);
+ err_free_dev:
+       input_free_device(input);
+       return error;
 }
 
 static int acpi_topstar_add(struct acpi_device *device)
@@ -216,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device, int type)
 
        acpi_topstar_fncx_switch(device, false);
 
+       sparse_keymap_free(tps_hkey->inputdev);
        input_unregister_device(tps_hkey->inputdev);
        kfree(tps_hkey);
 
index 7d67a45bb2b0328c34919ec4de44dff490110852..06f304f46e0229427e039180abb6731bceb403bd 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
 
@@ -121,36 +122,28 @@ static const struct acpi_device_id toshiba_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
 
-struct key_entry {
-       char type;
-       u16 code;
-       u16 keycode;
-};
-
-enum {KE_KEY, KE_END};
-
-static struct key_entry toshiba_acpi_keymap[]  = {
-       {KE_KEY, 0x101, KEY_MUTE},
-       {KE_KEY, 0x102, KEY_ZOOMOUT},
-       {KE_KEY, 0x103, KEY_ZOOMIN},
-       {KE_KEY, 0x13b, KEY_COFFEE},
-       {KE_KEY, 0x13c, KEY_BATTERY},
-       {KE_KEY, 0x13d, KEY_SLEEP},
-       {KE_KEY, 0x13e, KEY_SUSPEND},
-       {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
-       {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
-       {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
-       {KE_KEY, 0x142, KEY_WLAN},
-       {KE_KEY, 0x143, KEY_PROG1},
-       {KE_KEY, 0xb05, KEY_PROG2},
-       {KE_KEY, 0xb06, KEY_WWW},
-       {KE_KEY, 0xb07, KEY_MAIL},
-       {KE_KEY, 0xb30, KEY_STOP},
-       {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
-       {KE_KEY, 0xb32, KEY_NEXTSONG},
-       {KE_KEY, 0xb33, KEY_PLAYPAUSE},
-       {KE_KEY, 0xb5a, KEY_MEDIA},
-       {KE_END, 0, 0},
+static const struct key_entry toshiba_acpi_keymap[] __initconst = {
+       { KE_KEY, 0x101, { KEY_MUTE } },
+       { KE_KEY, 0x102, { KEY_ZOOMOUT } },
+       { KE_KEY, 0x103, { KEY_ZOOMIN } },
+       { KE_KEY, 0x13b, { KEY_COFFEE } },
+       { KE_KEY, 0x13c, { KEY_BATTERY } },
+       { KE_KEY, 0x13d, { KEY_SLEEP } },
+       { KE_KEY, 0x13e, { KEY_SUSPEND } },
+       { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
+       { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0x142, { KEY_WLAN } },
+       { KE_KEY, 0x143, { KEY_PROG1 } },
+       { KE_KEY, 0xb05, { KEY_PROG2 } },
+       { KE_KEY, 0xb06, { KEY_WWW } },
+       { KE_KEY, 0xb07, { KEY_MAIL } },
+       { KE_KEY, 0xb30, { KEY_STOP } },
+       { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
+       { KE_KEY, 0xb32, { KEY_NEXTSONG } },
+       { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
+       { KE_KEY, 0xb5a, { KEY_MEDIA } },
+       { KE_END, 0 },
 };
 
 /* utility
@@ -852,64 +845,9 @@ static struct backlight_ops toshiba_backlight_data = {
         .update_status  = set_lcd_status,
 };
 
-static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
-{
-       struct key_entry *key;
-
-       for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
-               if (code == key->code)
-                       return key;
-
-       return NULL;
-}
-
-static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
-{
-       struct key_entry *key;
-
-       for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
-               if (code == key->keycode && key->type == KE_KEY)
-                       return key;
-
-       return NULL;
-}
-
-static int toshiba_acpi_getkeycode(struct input_dev *dev,
-                                  unsigned int scancode, unsigned int *keycode)
-{
-       struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
-
-       if (key && key->type == KE_KEY) {
-               *keycode = key->keycode;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int toshiba_acpi_setkeycode(struct input_dev *dev,
-                                  unsigned int scancode, unsigned int keycode)
-{
-       struct key_entry *key;
-       unsigned int old_keycode;
-
-       key = toshiba_acpi_get_entry_by_scancode(scancode);
-       if (key && key->type == KE_KEY) {
-               old_keycode = key->keycode;
-               key->keycode = keycode;
-               set_bit(keycode, dev->keybit);
-               if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
-                       clear_bit(old_keycode, dev->keybit);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
 static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
 {
        u32 hci_result, value;
-       struct key_entry *key;
 
        if (event != 0x80)
                return;
@@ -922,19 +860,11 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
                        if (value & 0x80)
                                continue;
 
-                       key = toshiba_acpi_get_entry_by_scancode
-                               (value);
-                       if (!key) {
+                       if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
+                                                       value, 1, true)) {
                                printk(MY_INFO "Unknown key %x\n",
                                       value);
-                               continue;
                        }
-                       input_report_key(toshiba_acpi.hotkey_dev,
-                                        key->keycode, 1);
-                       input_sync(toshiba_acpi.hotkey_dev);
-                       input_report_key(toshiba_acpi.hotkey_dev,
-                                        key->keycode, 0);
-                       input_sync(toshiba_acpi.hotkey_dev);
                } else if (hci_result == HCI_NOT_SUPPORTED) {
                        /* This is a workaround for an unresolved issue on
                         * some machines where system events sporadically
@@ -945,34 +875,17 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
        } while (hci_result != HCI_EMPTY);
 }
 
-static int toshiba_acpi_setup_keyboard(char *device)
+static int __init toshiba_acpi_setup_keyboard(char *device)
 {
        acpi_status status;
-       acpi_handle handle;
-       int result;
-       const struct key_entry *key;
+       int error;
 
-       status = acpi_get_handle(NULL, device, &handle);
+       status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
        if (ACPI_FAILURE(status)) {
                printk(MY_INFO "Unable to get notification device\n");
                return -ENODEV;
        }
 
-       toshiba_acpi.handle = handle;
-
-       status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
-       if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Unable to enable hotkeys\n");
-               return -ENODEV;
-       }
-
-       status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
-                                             toshiba_acpi_notify, NULL);
-       if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Unable to install hotkey notification\n");
-               return -ENODEV;
-       }
-
        toshiba_acpi.hotkey_dev = input_allocate_device();
        if (!toshiba_acpi.hotkey_dev) {
                printk(MY_INFO "Unable to register input device\n");
@@ -982,27 +895,54 @@ static int toshiba_acpi_setup_keyboard(char *device)
        toshiba_acpi.hotkey_dev->name = "Toshiba input device";
        toshiba_acpi.hotkey_dev->phys = device;
        toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
-       toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
-       toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
 
-       for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
-               set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
-               set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
+       error = sparse_keymap_setup(toshiba_acpi.hotkey_dev,
+                                   toshiba_acpi_keymap, NULL);
+       if (error)
+               goto err_free_dev;
+
+       status = acpi_install_notify_handler(toshiba_acpi.handle,
+                               ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
+       if (ACPI_FAILURE(status)) {
+               printk(MY_INFO "Unable to install hotkey notification\n");
+               error = -ENODEV;
+               goto err_free_keymap;
+       }
+
+       status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
+       if (ACPI_FAILURE(status)) {
+               printk(MY_INFO "Unable to enable hotkeys\n");
+               error = -ENODEV;
+               goto err_remove_notify;
        }
 
-       result = input_register_device(toshiba_acpi.hotkey_dev);
-       if (result) {
+       error = input_register_device(toshiba_acpi.hotkey_dev);
+       if (error) {
                printk(MY_INFO "Unable to register input device\n");
-               return result;
+               goto err_remove_notify;
        }
 
        return 0;
+
+ err_remove_notify:
+       acpi_remove_notify_handler(toshiba_acpi.handle,
+                                  ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+ err_free_keymap:
+       sparse_keymap_free(toshiba_acpi.hotkey_dev);
+ err_free_dev:
+       input_free_device(toshiba_acpi.hotkey_dev);
+       toshiba_acpi.hotkey_dev = NULL;
+       return error;
 }
 
 static void toshiba_acpi_exit(void)
 {
-       if (toshiba_acpi.hotkey_dev)
+       if (toshiba_acpi.hotkey_dev) {
+               acpi_remove_notify_handler(toshiba_acpi.handle,
+                               ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+               sparse_keymap_free(toshiba_acpi.hotkey_dev);
                input_unregister_device(toshiba_acpi.hotkey_dev);
+       }
 
        if (toshiba_acpi.bt_rfk) {
                rfkill_unregister(toshiba_acpi.bt_rfk);
@@ -1017,9 +957,6 @@ static void toshiba_acpi_exit(void)
        if (toshiba_proc_dir)
                remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
 
-       acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
-                                  toshiba_acpi_notify);
-
        if (toshiba_acpi.illumination_installed)
                led_classdev_unregister(&toshiba_led);
 
index b2978a04317f9de32755a719b4c7abe215e588b6..104b77c87ef5ae36e0c4502c6487e1fb3aac428e 100644 (file)
@@ -27,6 +27,8 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -44,9 +46,8 @@ MODULE_LICENSE("GPL");
 
 #define ACPI_WMI_CLASS "wmi"
 
-#define PREFIX "ACPI: WMI: "
-
 static DEFINE_MUTEX(wmi_data_lock);
+static LIST_HEAD(wmi_block_list);
 
 struct guid_block {
        char guid[16];
@@ -67,10 +68,9 @@ struct wmi_block {
        acpi_handle handle;
        wmi_notify_handler handler;
        void *handler_data;
-       struct device *dev;
+       struct device dev;
 };
 
-static struct wmi_block wmi_blocks;
 
 /*
  * If the GUID data block is marked as expensive, we must enable and
@@ -110,7 +110,7 @@ static struct acpi_driver acpi_wmi_driver = {
                .add = acpi_wmi_add,
                .remove = acpi_wmi_remove,
                .notify = acpi_wmi_notify,
-               },
+       },
 };
 
 /*
@@ -128,30 +128,18 @@ static struct acpi_driver acpi_wmi_driver = {
  */
 static int wmi_parse_hexbyte(const u8 *src)
 {
-       unsigned int x; /* For correct wrapping */
        int h;
+       int value;
 
        /* high part */
-       x = src[0];
-       if (x - '0' <= '9' - '0') {
-               h = x - '0';
-       } else if (x - 'a' <= 'f' - 'a') {
-               h = x - 'a' + 10;
-       } else if (x - 'A' <= 'F' - 'A') {
-               h = x - 'A' + 10;
-       } else {
+       h = value = hex_to_bin(src[0]);
+       if (value < 0)
                return -1;
-       }
-       h <<= 4;
 
        /* low part */
-       x = src[1];
-       if (x - '0' <= '9' - '0')
-               return h | (x - '0');
-       if (x - 'a' <= 'f' - 'a')
-               return h | (x - 'a' + 10);
-       if (x - 'A' <= 'F' - 'A')
-               return h | (x - 'A' + 10);
+       value = hex_to_bin(src[1]);
+       if (value >= 0)
+               return (h << 4) | value;
        return -1;
 }
 
@@ -232,7 +220,7 @@ static int wmi_gtoa(const char *in, char *out)
        for (i = 10; i <= 15; i++)
                out += sprintf(out, "%02X", in[i] & 0xFF);
 
-       out = '\0';
+       *out = '\0';
        return 0;
 }
 
@@ -246,7 +234,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
        wmi_parse_guid(guid_string, tmp);
        wmi_swap_bytes(tmp, guid_input);
 
-       list_for_each(p, &wmi_blocks.list) {
+       list_for_each(p, &wmi_block_list) {
                wblock = list_entry(p, struct wmi_block, list);
                block = &wblock->gblock;
 
@@ -487,30 +475,29 @@ const struct acpi_buffer *in)
 }
 EXPORT_SYMBOL_GPL(wmi_set_block);
 
-static void wmi_dump_wdg(struct guid_block *g)
+static void wmi_dump_wdg(const struct guid_block *g)
 {
        char guid_string[37];
 
        wmi_gtoa(g->guid, guid_string);
-       printk(KERN_INFO PREFIX "%s:\n", guid_string);
-       printk(KERN_INFO PREFIX "\tobject_id: %c%c\n",
-              g->object_id[0], g->object_id[1]);
-       printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id);
-       printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved);
-       printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count);
-       printk(KERN_INFO PREFIX "\tflags: %#x", g->flags);
+
+       pr_info("%s:\n", guid_string);
+       pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
+       pr_info("\tnotify_id: %02X\n", g->notify_id);
+       pr_info("\treserved: %02X\n", g->reserved);
+       pr_info("\tinstance_count: %d\n", g->instance_count);
+       pr_info("\tflags: %#x ", g->flags);
        if (g->flags) {
-               printk(" ");
                if (g->flags & ACPI_WMI_EXPENSIVE)
-                       printk("ACPI_WMI_EXPENSIVE ");
+                       pr_cont("ACPI_WMI_EXPENSIVE ");
                if (g->flags & ACPI_WMI_METHOD)
-                       printk("ACPI_WMI_METHOD ");
+                       pr_cont("ACPI_WMI_METHOD ");
                if (g->flags & ACPI_WMI_STRING)
-                       printk("ACPI_WMI_STRING ");
+                       pr_cont("ACPI_WMI_STRING ");
                if (g->flags & ACPI_WMI_EVENT)
-                       printk("ACPI_WMI_EVENT ");
+                       pr_cont("ACPI_WMI_EVENT ");
        }
-       printk("\n");
+       pr_cont("\n");
 
 }
 
@@ -522,7 +509,7 @@ static void wmi_notify_debug(u32 value, void *context)
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
-               printk(KERN_INFO "wmi: bad event status 0x%x\n", status);
+               pr_info("bad event status 0x%x\n", status);
                return;
        }
 
@@ -531,22 +518,22 @@ static void wmi_notify_debug(u32 value, void *context)
        if (!obj)
                return;
 
-       printk(KERN_INFO PREFIX "DEBUG Event ");
+       pr_info("DEBUG Event ");
        switch(obj->type) {
        case ACPI_TYPE_BUFFER:
-               printk("BUFFER_TYPE - length %d\n", obj->buffer.length);
+               pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
                break;
        case ACPI_TYPE_STRING:
-               printk("STRING_TYPE - %s\n", obj->string.pointer);
+               pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
                break;
        case ACPI_TYPE_INTEGER:
-               printk("INTEGER_TYPE - %llu\n", obj->integer.value);
+               pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
                break;
        case ACPI_TYPE_PACKAGE:
-               printk("PACKAGE_TYPE - %d elements\n", obj->package.count);
+               pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
                break;
        default:
-               printk("object type 0x%X\n", obj->type);
+               pr_cont("object type 0x%X\n", obj->type);
        }
        kfree(obj);
 }
@@ -633,7 +620,7 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
        params[0].type = ACPI_TYPE_INTEGER;
        params[0].integer.value = event;
 
-       list_for_each(p, &wmi_blocks.list) {
+       list_for_each(p, &wmi_block_list) {
                wblock = list_entry(p, struct wmi_block, list);
                gblock = &wblock->gblock;
 
@@ -662,7 +649,7 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
 /*
  * sysfs interface
  */
-static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        char guid_string[37];
@@ -676,7 +663,11 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
 
        return sprintf(buf, "wmi:%s\n", guid_string);
 }
-static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static struct device_attribute wmi_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL
+};
 
 static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -702,108 +693,71 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 static void wmi_dev_free(struct device *dev)
 {
-       kfree(dev);
+       struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
+
+       kfree(wmi_block);
 }
 
 static struct class wmi_class = {
        .name = "wmi",
        .dev_release = wmi_dev_free,
        .dev_uevent = wmi_dev_uevent,
+       .dev_attrs = wmi_dev_attrs,
 };
 
-static int wmi_create_devs(void)
+static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
+                                          acpi_handle handle)
 {
-       int result;
-       char guid_string[37];
-       struct guid_block *gblock;
        struct wmi_block *wblock;
-       struct list_head *p;
-       struct device *guid_dev;
-
-       /* Create devices for all the GUIDs */
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-
-               guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-               if (!guid_dev)
-                       return -ENOMEM;
-
-               wblock->dev = guid_dev;
-
-               guid_dev->class = &wmi_class;
-               dev_set_drvdata(guid_dev, wblock);
-
-               gblock = &wblock->gblock;
-
-               wmi_gtoa(gblock->guid, guid_string);
-               dev_set_name(guid_dev, guid_string);
-
-               result = device_register(guid_dev);
-               if (result)
-                       return result;
+       int error;
+       char guid_string[37];
 
-               result = device_create_file(guid_dev, &dev_attr_modalias);
-               if (result)
-                       return result;
+       wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+       if (!wblock) {
+               error = -ENOMEM;
+               goto err_out;
        }
 
-       return 0;
-}
+       wblock->handle = handle;
+       wblock->gblock = *gblock;
 
-static void wmi_remove_devs(void)
-{
-       struct guid_block *gblock;
-       struct wmi_block *wblock;
-       struct list_head *p;
-       struct device *guid_dev;
+       wblock->dev.class = &wmi_class;
 
-       /* Delete devices for all the GUIDs */
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
+       wmi_gtoa(gblock->guid, guid_string);
+       dev_set_name(&wblock->dev, guid_string);
 
-               guid_dev = wblock->dev;
-               gblock = &wblock->gblock;
+       dev_set_drvdata(&wblock->dev, wblock);
 
-               device_remove_file(guid_dev, &dev_attr_modalias);
+       error = device_register(&wblock->dev);
+       if (error)
+               goto err_free;
 
-               device_unregister(guid_dev);
-       }
-}
+       list_add_tail(&wblock->list, &wmi_block_list);
+       return wblock;
 
-static void wmi_class_exit(void)
-{
-       wmi_remove_devs();
-       class_unregister(&wmi_class);
+err_free:
+       kfree(wblock);
+err_out:
+       return ERR_PTR(error);
 }
 
-static int wmi_class_init(void)
+static void wmi_free_devices(void)
 {
-       int ret;
-
-       ret = class_register(&wmi_class);
-       if (ret)
-               return ret;
+       struct wmi_block *wblock, *next;
 
-       ret = wmi_create_devs();
-       if (ret)
-               wmi_class_exit();
-
-       return ret;
+       /* Delete devices for all the GUIDs */
+       list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
+               device_unregister(&wblock->dev);
 }
 
 static bool guid_already_parsed(const char *guid_string)
 {
-       struct guid_block *gblock;
        struct wmi_block *wblock;
-       struct list_head *p;
 
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-               gblock = &wblock->gblock;
-
-               if (strncmp(gblock->guid, guid_string, 16) == 0)
+       list_for_each_entry(wblock, &wmi_block_list, list)
+               if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
                        return true;
-       }
+
        return false;
 }
 
@@ -814,30 +768,29 @@ static acpi_status parse_wdg(acpi_handle handle)
 {
        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *obj;
-       struct guid_block *gblock;
+       const struct guid_block *gblock;
        struct wmi_block *wblock;
        char guid_string[37];
        acpi_status status;
+       int retval;
        u32 i, total;
 
        status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
-
        if (ACPI_FAILURE(status))
-               return status;
+               return -ENXIO;
 
        obj = (union acpi_object *) out.pointer;
+       if (!obj)
+               return -ENXIO;
 
-       if (obj->type != ACPI_TYPE_BUFFER)
-               return AE_ERROR;
-
-       total = obj->buffer.length / sizeof(struct guid_block);
-
-       gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
-       if (!gblock) {
-               status = AE_NO_MEMORY;
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               retval = -ENXIO;
                goto out_free_pointer;
        }
 
+       gblock = (const struct guid_block *)obj->buffer.pointer;
+       total = obj->buffer.length / sizeof(struct guid_block);
+
        for (i = 0; i < total; i++) {
                /*
                  Some WMI devices, like those for nVidia hooks, have a
@@ -848,34 +801,32 @@ static acpi_status parse_wdg(acpi_handle handle)
                */
                if (guid_already_parsed(gblock[i].guid) == true) {
                        wmi_gtoa(gblock[i].guid, guid_string);
-                       printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
-                               guid_string);
+                       pr_info("Skipping duplicate GUID %s\n", guid_string);
                        continue;
                }
+
                if (debug_dump_wdg)
                        wmi_dump_wdg(&gblock[i]);
 
-               wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
-               if (!wblock) {
-                       status = AE_NO_MEMORY;
-                       goto out_free_gblock;
+               wblock = wmi_create_device(&gblock[i], handle);
+               if (IS_ERR(wblock)) {
+                       retval = PTR_ERR(wblock);
+                       wmi_free_devices();
+                       break;
                }
 
-               wblock->gblock = gblock[i];
-               wblock->handle = handle;
                if (debug_event) {
                        wblock->handler = wmi_notify_debug;
-                       status = wmi_method_enable(wblock, 1);
+                       wmi_method_enable(wblock, 1);
                }
-               list_add_tail(&wblock->list, &wmi_blocks.list);
        }
 
-out_free_gblock:
-       kfree(gblock);
+       retval = 0;
+
 out_free_pointer:
        kfree(out.pointer);
 
-       return status;
+       return retval;
 }
 
 /*
@@ -929,7 +880,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
        struct list_head *p;
        char guid_string[37];
 
-       list_for_each(p, &wmi_blocks.list) {
+       list_for_each(p, &wmi_block_list) {
                wblock = list_entry(p, struct wmi_block, list);
                block = &wblock->gblock;
 
@@ -939,8 +890,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
                                wblock->handler(event, wblock->handler_data);
                        if (debug_event) {
                                wmi_gtoa(wblock->gblock.guid, guid_string);
-                               printk(KERN_INFO PREFIX "DEBUG Event GUID:"
-                                      " %s\n", guid_string);
+                               pr_info("DEBUG Event GUID: %s\n", guid_string);
                        }
 
                        acpi_bus_generate_netlink_event(
@@ -955,6 +905,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
 {
        acpi_remove_address_space_handler(device->handle,
                                ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
+       wmi_free_devices();
 
        return 0;
 }
@@ -962,68 +913,57 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
 static int acpi_wmi_add(struct acpi_device *device)
 {
        acpi_status status;
-       int result = 0;
+       int error;
 
        status = acpi_install_address_space_handler(device->handle,
                                                    ACPI_ADR_SPACE_EC,
                                                    &acpi_wmi_ec_space_handler,
                                                    NULL, NULL);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       status = parse_wdg(device->handle);
        if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+               pr_err("Error installing EC region handler\n");
                return -ENODEV;
        }
 
-       return result;
+       error = parse_wdg(device->handle);
+       if (error) {
+               acpi_remove_address_space_handler(device->handle,
+                                                 ACPI_ADR_SPACE_EC,
+                                                 &acpi_wmi_ec_space_handler);
+               pr_err("Failed to parse WDG method\n");
+               return error;
+       }
+
+       return 0;
 }
 
 static int __init acpi_wmi_init(void)
 {
-       int result;
-
-       INIT_LIST_HEAD(&wmi_blocks.list);
+       int error;
 
        if (acpi_disabled)
                return -ENODEV;
 
-       result = acpi_bus_register_driver(&acpi_wmi_driver);
+       error = class_register(&wmi_class);
+       if (error)
+               return error;
 
-       if (result < 0) {
-               printk(KERN_INFO PREFIX "Error loading mapper\n");
-               return -ENODEV;
+       error = acpi_bus_register_driver(&acpi_wmi_driver);
+       if (error) {
+               pr_err("Error loading mapper\n");
+               class_unregister(&wmi_class);
+               return error;
        }
 
-       result = wmi_class_init();
-       if (result) {
-               acpi_bus_unregister_driver(&acpi_wmi_driver);
-               return result;
-       }
-
-       printk(KERN_INFO PREFIX "Mapper loaded\n");
-
-       return result;
+       pr_info("Mapper loaded\n");
+       return 0;
 }
 
 static void __exit acpi_wmi_exit(void)
 {
-       struct list_head *p, *tmp;
-       struct wmi_block *wblock;
-
-       wmi_class_exit();
-
        acpi_bus_unregister_driver(&acpi_wmi_driver);
+       class_unregister(&wmi_class);
 
-       list_for_each_safe(p, tmp, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-
-               list_del(p);
-               kfree(wblock);
-       }
-
-       printk(KERN_INFO PREFIX "Mapper unloaded\n");
+       pr_info("Mapper unloaded\n");
 }
 
 subsys_initcall(acpi_wmi_init);
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
new file mode 100644 (file)
index 0000000..e549eee
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Support for rfkill through the OLPC XO-1 laptop embedded controller
+ *
+ * Copyright (C) 2010 One Laptop per Child
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+#include <asm/olpc.h>
+
+static int rfkill_set_block(void *data, bool blocked)
+{
+       unsigned char cmd;
+       if (blocked)
+               cmd = EC_WLAN_ENTER_RESET;
+       else
+               cmd = EC_WLAN_LEAVE_RESET;
+
+       return olpc_ec_cmd(cmd, NULL, 0, NULL, 0);
+}
+
+static const struct rfkill_ops rfkill_ops = {
+       .set_block = rfkill_set_block,
+};
+
+static int __devinit xo1_rfkill_probe(struct platform_device *pdev)
+{
+       struct rfkill *rfk;
+       int r;
+
+       rfk = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_WLAN,
+                          &rfkill_ops, NULL);
+       if (!rfk)
+               return -ENOMEM;
+
+       r = rfkill_register(rfk);
+       if (r) {
+               rfkill_destroy(rfk);
+               return r;
+       }
+
+       platform_set_drvdata(pdev, rfk);
+       return 0;
+}
+
+static int __devexit xo1_rfkill_remove(struct platform_device *pdev)
+{
+       struct rfkill *rfk = platform_get_drvdata(pdev);
+       rfkill_unregister(rfk);
+       rfkill_destroy(rfk);
+       return 0;
+}
+
+static struct platform_driver xo1_rfkill_driver = {
+       .driver = {
+               .name = "xo1-rfkill",
+               .owner = THIS_MODULE,
+       },
+       .probe          = xo1_rfkill_probe,
+       .remove         = __devexit_p(xo1_rfkill_remove),
+};
+
+static int __init xo1_rfkill_init(void)
+{
+       return platform_driver_register(&xo1_rfkill_driver);
+}
+
+static void __exit xo1_rfkill_exit(void)
+{
+       platform_driver_unregister(&xo1_rfkill_driver);
+}
+
+MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:xo1-rfkill");
+
+module_init(xo1_rfkill_init);
+module_exit(xo1_rfkill_exit);
index 0bab84ebb15da8961e20be1ebfd120355ea3cdea..19bc73695475078a2b3a419e9ccfb9c4a4979882 100644 (file)
@@ -12,11 +12,12 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol);
 
 #define PNP_EISA_ID_MASK 0x7fffffff
 void pnp_eisa_id_to_string(u32 id, char *str);
-struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid);
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id,
+                             const char *pnpid);
 struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid);
 
 int pnp_add_device(struct pnp_dev *dev);
-struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id);
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id);
 
 int pnp_add_card(struct pnp_card *card);
 void pnp_remove_card(struct pnp_card *card);
index 88b3cde525968a2f6ee5e3b9be37e3177125a52f..0f34d962fd3c53bf4de3002524eab809899e4ec5 100644 (file)
@@ -124,7 +124,8 @@ static void pnp_release_device(struct device *dmdev)
        kfree(dev);
 }
 
-struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid)
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
+                             const char *pnpid)
 {
        struct pnp_dev *dev;
        struct pnp_id *dev_id;
@@ -194,8 +195,9 @@ int pnp_add_device(struct pnp_dev *dev)
        for (id = dev->id; id; id = id->next)
                len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);
 
-       pnp_dbg(&dev->dev, "%s device, IDs%s (%s)\n",
-               dev->protocol->name, buf, dev->active ? "active" : "disabled");
+       dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs%s (%s)\n",
+                  dev->protocol->name, buf,
+                  dev->active ? "active" : "disabled");
        return 0;
 }
 
index cd11b113494fabf7ca2367a2567bbbbc8af71ac7..d1dbb9df53faa7bc7e9b6fe8de8158595188c949 100644 (file)
@@ -236,7 +236,7 @@ void pnp_unregister_driver(struct pnp_driver *drv)
  * @dev: pointer to the desired device
  * @id: pointer to an EISA id string
  */
-struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id)
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
 {
        struct pnp_id *dev_id, *ptr;
 
index dc4e32e031e9d61f77a3d706d8582ac48285b039..2d73dfcecdbb4e2098e3d881a6a091a9e8ca5e62 100644 (file)
@@ -28,7 +28,7 @@
 #include "../base.h"
 #include "pnpacpi.h"
 
-static int num = 0;
+static int num;
 
 /* We need only to blacklist devices that have already an acpi driver that
  * can't use pnp layer. We don't need to blacklist device that are directly
@@ -59,7 +59,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev)
 #define TEST_ALPHA(c) \
        if (!('@' <= (c) || (c) <= 'Z')) \
                return 0
-static int __init ispnpidacpi(char *id)
+static int __init ispnpidacpi(const char *id)
 {
        TEST_ALPHA(id[0]);
        TEST_ALPHA(id[1]);
@@ -180,11 +180,24 @@ struct pnp_protocol pnpacpi_protocol = {
 };
 EXPORT_SYMBOL(pnpacpi_protocol);
 
+static char *pnpacpi_get_id(struct acpi_device *device)
+{
+       struct acpi_hardware_id *id;
+
+       list_for_each_entry(id, &device->pnp.ids, list) {
+               if (ispnpidacpi(id->id))
+                       return id->id;
+       }
+
+       return NULL;
+}
+
 static int __init pnpacpi_add_device(struct acpi_device *device)
 {
        acpi_handle temp = NULL;
        acpi_status status;
        struct pnp_dev *dev;
+       char *pnpid;
        struct acpi_hardware_id *id;
 
        /*
@@ -192,11 +205,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
         * driver should not be loaded.
         */
        status = acpi_get_handle(device->handle, "_CRS", &temp);
-       if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
-           is_exclusive_device(device) || (!device->status.present))
+       if (ACPI_FAILURE(status))
+               return 0;
+
+       pnpid = pnpacpi_get_id(device);
+       if (!pnpid)
+               return 0;
+
+       if (is_exclusive_device(device) || !device->status.present)
                return 0;
 
-       dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
+       dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
        if (!dev)
                return -ENOMEM;
 
@@ -227,7 +246,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
                pnpacpi_parse_resource_option_data(dev);
 
        list_for_each_entry(id, &device->pnp.ids, list) {
-               if (!strcmp(id->id, acpi_device_hid(device)))
+               if (!strcmp(id->id, pnpid))
                        continue;
                if (!ispnpidacpi(id->id))
                        continue;
index e3446ab8b563743d462756fb7237225a8a492f79..a925e6b63d72cff9953672c285210de80c3c488e 100644 (file)
@@ -523,7 +523,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
        res->start = irq;
        res->end = irq;
 
-       pnp_dbg(&dev->dev, "  add %pr\n", res);
+       dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
        return pnp_res;
 }
 
@@ -544,7 +544,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
        res->start = dma;
        res->end = dma;
 
-       pnp_dbg(&dev->dev, "  add %pr\n", res);
+       dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
        return pnp_res;
 }
 
@@ -568,7 +568,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
        res->start = start;
        res->end = end;
 
-       pnp_dbg(&dev->dev, "  add %pr\n", res);
+       dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
        return pnp_res;
 }
 
@@ -592,7 +592,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
        res->start = start;
        res->end = end;
 
-       pnp_dbg(&dev->dev, "  add %pr\n", res);
+       dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
        return pnp_res;
 }
 
@@ -616,7 +616,7 @@ struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
        res->start = start;
        res->end = end;
 
-       pnp_dbg(&dev->dev, "  add %pr\n", res);
+       dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
        return pnp_res;
 }
 
index 07343568a12ec81ca6b8948e6754190b5ce9a49e..60d83d983a36d7fb0be13eb056d4db3849e7fe21 100644 (file)
@@ -64,8 +64,7 @@ config TEST_POWER
 
 config BATTERY_DS2760
        tristate "DS2760 battery driver (HP iPAQ & others)"
-       select W1
-       select W1_SLAVE_DS2760
+       depends on W1 && W1_SLAVE_DS2760
        help
          Say Y here to enable support for batteries with ds2760 chip.
 
@@ -109,6 +108,13 @@ config BATTERY_WM97XX
        help
          Say Y to enable support for battery measured by WM97xx aux port.
 
+config BATTERY_BQ20Z75
+        tristate "TI BQ20z75 gas gauge"
+        depends on I2C
+        help
+         Say Y to include support for TI BQ20z75 SBS-compliant
+         gas gauge and protection IC.
+
 config BATTERY_BQ27x00
        tristate "BQ27x00 battery driver"
        depends on I2C
@@ -166,4 +172,17 @@ config BATTERY_INTEL_MID
          Say Y here to enable the battery driver on Intel MID
          platforms.
 
+config CHARGER_ISP1704
+       tristate "ISP1704 USB Charger Detection"
+       depends on USB_OTG_UTILS
+       help
+         Say Y to enable support for USB Charger Detection with
+         ISP1707/ISP1704 USB transceivers.
+
+config CHARGER_TWL4030
+       tristate "OMAP TWL4030 BCI charger driver"
+       depends on TWL4030_CORE
+       help
+         Say Y here to enable support for TWL4030 Battery Charge Interface.
+
 endif # POWER_SUPPLY
index 10143aaf4ee3b40ca636e0a63f55ac83e7bf7720..c75772eb157c09fe915d756ebe9ba38ee0c4e43f 100644 (file)
@@ -1,16 +1,8 @@
-power_supply-objs := power_supply_core.o
+ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
 
-ifeq ($(CONFIG_SYSFS),y)
-power_supply-objs += power_supply_sysfs.o
-endif
-
-ifeq ($(CONFIG_LEDS_TRIGGERS),y)
-power_supply-objs += power_supply_leds.o
-endif
-
-ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+power_supply-y                         := power_supply_core.o
+power_supply-$(CONFIG_SYSFS)           += power_supply_sysfs.o
+power_supply-$(CONFIG_LEDS_TRIGGERS)   += power_supply_leds.o
 
 obj-$(CONFIG_POWER_SUPPLY)     += power_supply.o
 
@@ -29,6 +21,7 @@ obj-$(CONFIG_BATTERY_OLPC)    += olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
 obj-$(CONFIG_BATTERY_COLLIE)   += collie_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
+obj-$(CONFIG_BATTERY_BQ20Z75)  += bq20z75.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
@@ -37,3 +30,5 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)   += jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)        += intel_mid_battery.o
+obj-$(CONFIG_CHARGER_ISP1704)  += isp1704_charger.o
+obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c
new file mode 100644 (file)
index 0000000..492da27
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Gas Gauge driver for TI's BQ20Z75
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+enum {
+       REG_MANUFACTURER_DATA,
+       REG_TEMPERATURE,
+       REG_VOLTAGE,
+       REG_CURRENT,
+       REG_CAPACITY,
+       REG_TIME_TO_EMPTY,
+       REG_TIME_TO_FULL,
+       REG_STATUS,
+       REG_CYCLE_COUNT,
+       REG_SERIAL_NUMBER,
+       REG_REMAINING_CAPACITY,
+       REG_FULL_CHARGE_CAPACITY,
+       REG_DESIGN_CAPACITY,
+       REG_DESIGN_VOLTAGE,
+};
+
+/* manufacturer access defines */
+#define MANUFACTURER_ACCESS_STATUS     0x0006
+#define MANUFACTURER_ACCESS_SLEEP      0x0011
+
+/* battery status value bits */
+#define BATTERY_DISCHARGING            0x40
+#define BATTERY_FULL_CHARGED           0x20
+#define BATTERY_FULL_DISCHARGED                0x10
+
+#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \
+       .psp = _psp, \
+       .addr = _addr, \
+       .min_value = _min_value, \
+       .max_value = _max_value, \
+}
+
+static const struct bq20z75_device_data {
+       enum power_supply_property psp;
+       u8 addr;
+       int min_value;
+       int max_value;
+} bq20z75_data[] = {
+       [REG_MANUFACTURER_DATA] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
+       [REG_TEMPERATURE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
+       [REG_VOLTAGE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
+       [REG_CURRENT] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768,
+                       32767),
+       [REG_CAPACITY] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
+       [REG_REMAINING_CAPACITY] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
+       [REG_FULL_CHARGE_CAPACITY] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
+       [REG_TIME_TO_EMPTY] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
+                       65535),
+       [REG_TIME_TO_FULL] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0,
+                       65535),
+       [REG_STATUS] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
+       [REG_CYCLE_COUNT] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
+       [REG_DESIGN_CAPACITY] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
+                       65535),
+       [REG_DESIGN_VOLTAGE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
+                       65535),
+       [REG_SERIAL_NUMBER] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
+};
+
+static enum power_supply_property bq20z75_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CYCLE_COUNT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+       POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_ENERGY_NOW,
+       POWER_SUPPLY_PROP_ENERGY_FULL,
+       POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+};
+
+struct bq20z75_info {
+       struct i2c_client       *client;
+       struct power_supply     power_supply;
+};
+
+static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
+{
+       s32 ret;
+
+       ret = i2c_smbus_read_word_data(client, address);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s: i2c read at address 0x%x failed\n",
+                       __func__, address);
+               return ret;
+       }
+       return le16_to_cpu(ret);
+}
+
+static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
+       u16 value)
+{
+       s32 ret;
+
+       ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s: i2c write to address 0x%x failed\n",
+                       __func__, address);
+               return ret;
+       }
+       return 0;
+}
+
+static int bq20z75_get_battery_presence_and_health(
+       struct i2c_client *client, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       s32 ret;
+
+       /* Write to ManufacturerAccess with
+        * ManufacturerAccess command and then
+        * read the status */
+       ret = bq20z75_write_word_data(client,
+               bq20z75_data[REG_MANUFACTURER_DATA].addr,
+               MANUFACTURER_ACCESS_STATUS);
+       if (ret < 0)
+               return ret;
+
+
+       ret = bq20z75_read_word_data(client,
+               bq20z75_data[REG_MANUFACTURER_DATA].addr);
+       if (ret < 0)
+               return ret;
+
+       if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
+           ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
+               val->intval = 0;
+               return 0;
+       }
+
+       /* Mask the upper nibble of 2nd byte and
+        * lower byte of response then
+        * shift the result by 8 to get status*/
+       ret &= 0x0F00;
+       ret >>= 8;
+       if (psp == POWER_SUPPLY_PROP_PRESENT) {
+               if (ret == 0x0F)
+                       /* battery removed */
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+       } else if (psp == POWER_SUPPLY_PROP_HEALTH) {
+               if (ret == 0x09)
+                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+               else if (ret == 0x0B)
+                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+               else if (ret == 0x0C)
+                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
+               else
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+       }
+
+       return 0;
+}
+
+static int bq20z75_get_battery_property(struct i2c_client *client,
+       int reg_offset, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       s32 ret;
+
+       ret = bq20z75_read_word_data(client,
+               bq20z75_data[reg_offset].addr);
+       if (ret < 0)
+               return ret;
+
+       /* returned values are 16 bit */
+       if (bq20z75_data[reg_offset].min_value < 0)
+               ret = (s16)ret;
+
+       if (ret >= bq20z75_data[reg_offset].min_value &&
+           ret <= bq20z75_data[reg_offset].max_value) {
+               val->intval = ret;
+               if (psp == POWER_SUPPLY_PROP_STATUS) {
+                       if (ret & BATTERY_FULL_CHARGED)
+                               val->intval = POWER_SUPPLY_STATUS_FULL;
+                       else if (ret & BATTERY_FULL_DISCHARGED)
+                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       else if (ret & BATTERY_DISCHARGING)
+                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                       else
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               }
+       } else {
+               if (psp == POWER_SUPPLY_PROP_STATUS)
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+               else
+                       val->intval = 0;
+       }
+
+       return 0;
+}
+
+static void  bq20z75_unit_adjustment(struct i2c_client *client,
+       enum power_supply_property psp, union power_supply_propval *val)
+{
+#define BASE_UNIT_CONVERSION           1000
+#define BATTERY_MODE_CAP_MULT_WATT     (10 * BASE_UNIT_CONVERSION)
+#define TIME_UNIT_CONVERSION           600
+#define TEMP_KELVIN_TO_CELCIUS         2731
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+               val->intval *= BATTERY_MODE_CAP_MULT_WATT;
+               break;
+
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               val->intval *= BASE_UNIT_CONVERSION;
+               break;
+
+       case POWER_SUPPLY_PROP_TEMP:
+               /* bq20z75 provides battery tempreture in 0.1°K
+                * so convert it to 0.1°C */
+               val->intval -= TEMP_KELVIN_TO_CELCIUS;
+               val->intval *= 10;
+               break;
+
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+               val->intval *= TIME_UNIT_CONVERSION;
+               break;
+
+       default:
+               dev_dbg(&client->dev,
+                       "%s: no need for unit conversion %d\n", __func__, psp);
+       }
+}
+
+static int bq20z75_get_battery_capacity(struct i2c_client *client,
+       int reg_offset, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       s32 ret;
+
+       ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
+       if (ret < 0)
+               return ret;
+
+       if (psp == POWER_SUPPLY_PROP_CAPACITY) {
+               /* bq20z75 spec says that this can be >100 %
+               * even if max value is 100 % */
+               val->intval = min(ret, 100);
+       } else
+               val->intval = ret;
+
+       return 0;
+}
+
+static char bq20z75_serial[5];
+static int bq20z75_get_battery_serial_number(struct i2c_client *client,
+       union power_supply_propval *val)
+{
+       int ret;
+
+       ret = bq20z75_read_word_data(client,
+               bq20z75_data[REG_SERIAL_NUMBER].addr);
+       if (ret < 0)
+               return ret;
+
+       ret = sprintf(bq20z75_serial, "%04x", ret);
+       val->strval = bq20z75_serial;
+
+       return 0;
+}
+
+static int bq20z75_get_property(struct power_supply *psy,
+       enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       int count;
+       int ret;
+       struct bq20z75_info *bq20z75_device = container_of(psy,
+                               struct bq20z75_info, power_supply);
+       struct i2c_client *client = bq20z75_device->client;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = bq20z75_get_battery_presence_and_health(client, psp, val);
+               if (ret)
+                       return ret;
+               break;
+
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CAPACITY:
+               for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
+                       if (psp == bq20z75_data[count].psp)
+                               break;
+               }
+
+               ret = bq20z75_get_battery_capacity(client, count, psp, val);
+               if (ret)
+                       return ret;
+
+               break;
+
+       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+               ret = bq20z75_get_battery_serial_number(client, val);
+               if (ret)
+                       return ret;
+               break;
+
+       case POWER_SUPPLY_PROP_STATUS:
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+       case POWER_SUPPLY_PROP_TEMP:
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
+                       if (psp == bq20z75_data[count].psp)
+                               break;
+               }
+
+               ret = bq20z75_get_battery_property(client, count, psp, val);
+               if (ret)
+                       return ret;
+
+               break;
+
+       default:
+               dev_err(&client->dev,
+                       "%s: INVALID property\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Convert units to match requirements for power supply class */
+       bq20z75_unit_adjustment(client, psp, val);
+
+       dev_dbg(&client->dev,
+               "%s: property = %d, value = %d\n", __func__, psp, val->intval);
+
+       return 0;
+}
+
+static int bq20z75_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct bq20z75_info *bq20z75_device;
+       int rc;
+
+       bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
+       if (!bq20z75_device)
+               return -ENOMEM;
+
+       bq20z75_device->client = client;
+       bq20z75_device->power_supply.name = "battery";
+       bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
+       bq20z75_device->power_supply.properties = bq20z75_properties;
+       bq20z75_device->power_supply.num_properties =
+               ARRAY_SIZE(bq20z75_properties);
+       bq20z75_device->power_supply.get_property = bq20z75_get_property;
+
+       i2c_set_clientdata(client, bq20z75_device);
+
+       rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
+       if (rc) {
+               dev_err(&client->dev,
+                       "%s: Failed to register power supply\n", __func__);
+               kfree(bq20z75_device);
+               return rc;
+       }
+
+       dev_info(&client->dev,
+               "%s: battery gas gauge device registered\n", client->name);
+
+       return 0;
+}
+
+static int bq20z75_remove(struct i2c_client *client)
+{
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
+
+       power_supply_unregister(&bq20z75_device->power_supply);
+       kfree(bq20z75_device);
+       bq20z75_device = NULL;
+
+       return 0;
+}
+
+#if defined CONFIG_PM
+static int bq20z75_suspend(struct i2c_client *client,
+       pm_message_t state)
+{
+       s32 ret;
+
+       /* write to manufacturer access with sleep command */
+       ret = bq20z75_write_word_data(client,
+               bq20z75_data[REG_MANUFACTURER_DATA].addr,
+               MANUFACTURER_ACCESS_SLEEP);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+#else
+#define bq20z75_suspend                NULL
+#endif
+/* any smbus transaction will wake up bq20z75 */
+#define bq20z75_resume         NULL
+
+static const struct i2c_device_id bq20z75_id[] = {
+       { "bq20z75", 0 },
+       {}
+};
+
+static struct i2c_driver bq20z75_battery_driver = {
+       .probe          = bq20z75_probe,
+       .remove         = bq20z75_remove,
+       .suspend        = bq20z75_suspend,
+       .resume         = bq20z75_resume,
+       .id_table       = bq20z75_id,
+       .driver = {
+               .name   = "bq20z75-battery",
+       },
+};
+
+static int __init bq20z75_battery_init(void)
+{
+       return i2c_add_driver(&bq20z75_battery_driver);
+}
+module_init(bq20z75_battery_init);
+
+static void __exit bq20z75_battery_exit(void)
+{
+       i2c_del_driver(&bq20z75_battery_driver);
+}
+module_exit(bq20z75_battery_exit);
+
+MODULE_DESCRIPTION("BQ20z75 battery monitor driver");
+MODULE_LICENSE("GPL");
index 3ec9c6a8896b5ea9c22c0da72705b51ab79ca6fc..eff0273d4030d71a745f109a25754be52eaa1d8e 100644 (file)
@@ -418,6 +418,7 @@ static int bq27x00_battery_remove(struct i2c_client *client)
 
        power_supply_unregister(&di->bat);
 
+       kfree(di->bus);
        kfree(di->bat.name);
 
        mutex_lock(&battery_mutex);
index 4d3b27228a2e0ea6bd844f9ae9fbb4161059a3eb..b3c01c16a1640773ade9a1d09b813e9356c30c8b 100644 (file)
@@ -586,6 +586,7 @@ static int ds2760_battery_remove(struct platform_device *pdev)
                                          &di->set_charged_work);
        destroy_workqueue(di->monitor_wqueue);
        power_supply_unregister(&di->bat);
+       kfree(di);
 
        return 0;
 }
index 84d3c43cf2bc83f92ea05c1a381d113f4f7b6375..6957e8af64490d006d383b7ce253bd7faddca0f4 100644 (file)
@@ -44,8 +44,8 @@ struct ds278x_info;
 
 struct ds278x_battery_ops {
        int (*get_battery_current)(struct ds278x_info *info, int *current_uA);
-       int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uA);
-       int (*get_battery_capacity)(struct ds278x_info *info, int *capacity_uA);
+       int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV);
+       int (*get_battery_capacity)(struct ds278x_info *info, int *capacity);
 };
 
 #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
@@ -137,7 +137,7 @@ static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
        return 0;
 }
 
-static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
+static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV)
 {
        s16 raw;
        int err;
@@ -149,7 +149,7 @@ static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
        err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
        if (err)
                return err;
-       *voltage_uA = (raw / 32) * 4800;
+       *voltage_uV = (raw / 32) * 4800;
        return 0;
 }
 
@@ -177,7 +177,7 @@ static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
        return 0;
 }
 
-static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
+static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
 {
        s16 raw;
        int err;
@@ -189,7 +189,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
        err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
        if (err)
                return err;
-       *voltage_uA = (raw / 8) * 1220;
+       *voltage_uV = (raw / 8) * 1220;
        return 0;
 }
 
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
new file mode 100644 (file)
index 0000000..7251218
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * ISP1704 USB Charger Detection driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/delay.h>
+
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Vendor specific Power Control register */
+#define ISP1704_PWR_CTRL               0x3d
+#define ISP1704_PWR_CTRL_SWCTRL                (1 << 0)
+#define ISP1704_PWR_CTRL_DET_COMP      (1 << 1)
+#define ISP1704_PWR_CTRL_BVALID_RISE   (1 << 2)
+#define ISP1704_PWR_CTRL_BVALID_FALL   (1 << 3)
+#define ISP1704_PWR_CTRL_DP_WKPU_EN    (1 << 4)
+#define ISP1704_PWR_CTRL_VDAT_DET      (1 << 5)
+#define ISP1704_PWR_CTRL_DPVSRC_EN     (1 << 6)
+#define ISP1704_PWR_CTRL_HWDETECT      (1 << 7)
+
+#define NXP_VENDOR_ID                  0x04cc
+
+static u16 isp170x_id[] = {
+       0x1704,
+       0x1707,
+};
+
+struct isp1704_charger {
+       struct device           *dev;
+       struct power_supply     psy;
+       struct otg_transceiver  *otg;
+       struct notifier_block   nb;
+       struct work_struct      work;
+
+       char                    model[7];
+       unsigned                present:1;
+};
+
+/*
+ * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
+ * is actually a dedicated charger, the following steps need to be taken.
+ */
+static inline int isp1704_charger_verify(struct isp1704_charger *isp)
+{
+       int     ret = 0;
+       u8      r;
+
+       /* Reset the transceiver */
+       r = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+       r |= ULPI_FUNC_CTRL_RESET;
+       otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+       usleep_range(1000, 2000);
+
+       /* Set normal mode */
+       r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK);
+       otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+
+       /* Clear the DP and DM pull-down bits */
+       r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN;
+       otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r);
+
+       /* Enable strong pull-up on DP (1.5K) and reset */
+       r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r);
+       usleep_range(1000, 2000);
+
+       /* Read the line state */
+       if (!otg_io_read(isp->otg, ULPI_DEBUG)) {
+               /* Disable strong pull-up on DP (1.5K) */
+               otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+                               ULPI_FUNC_CTRL_TERMSELECT);
+               return 1;
+       }
+
+       /* Is it a charger or PS/2 connection */
+
+       /* Enable weak pull-up resistor on DP */
+       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+                       ISP1704_PWR_CTRL_DP_WKPU_EN);
+
+       /* Disable strong pull-up on DP (1.5K) */
+       otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+                       ULPI_FUNC_CTRL_TERMSELECT);
+
+       /* Enable weak pull-down resistor on DM */
+       otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL),
+                       ULPI_OTG_CTRL_DM_PULLDOWN);
+
+       /* It's a charger if the line states are clear */
+       if (!(otg_io_read(isp->otg, ULPI_DEBUG)))
+               ret = 1;
+
+       /* Disable weak pull-up resistor on DP */
+       otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL),
+                       ISP1704_PWR_CTRL_DP_WKPU_EN);
+
+       return ret;
+}
+
+static inline int isp1704_charger_detect(struct isp1704_charger *isp)
+{
+       unsigned long   timeout;
+       u8              r;
+       int             ret = 0;
+
+       /* set SW control bit in PWR_CTRL register */
+       otg_io_write(isp->otg, ISP1704_PWR_CTRL,
+                       ISP1704_PWR_CTRL_SWCTRL);
+
+       /* enable manual charger detection */
+       r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
+       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+       usleep_range(1000, 2000);
+
+       timeout = jiffies + msecs_to_jiffies(300);
+       do {
+               /* Check if there is a charger */
+               if (otg_io_read(isp->otg, ISP1704_PWR_CTRL)
+                               & ISP1704_PWR_CTRL_VDAT_DET) {
+                       ret = isp1704_charger_verify(isp);
+                       break;
+               }
+       } while (!time_after(jiffies, timeout));
+
+       return ret;
+}
+
+static void isp1704_charger_work(struct work_struct *data)
+{
+       int                     detect;
+       struct isp1704_charger  *isp =
+               container_of(data, struct isp1704_charger, work);
+
+       /*
+        * FIXME Only supporting dedicated chargers even though isp1704 can
+        * detect HUB and HOST chargers. If the device has already been
+        * enumerated, the detection will break the connection.
+        */
+       if (isp->otg->state != OTG_STATE_B_IDLE)
+               return;
+
+       /* disable data pullups */
+       if (isp->otg->gadget)
+               usb_gadget_disconnect(isp->otg->gadget);
+
+       /* detect charger */
+       detect = isp1704_charger_detect(isp);
+       if (detect) {
+               isp->present = detect;
+               power_supply_changed(&isp->psy);
+       }
+
+       /* enable data pullups */
+       if (isp->otg->gadget)
+               usb_gadget_connect(isp->otg->gadget);
+}
+
+static int isp1704_notifier_call(struct notifier_block *nb,
+               unsigned long event, void *unused)
+{
+       struct isp1704_charger *isp =
+               container_of(nb, struct isp1704_charger, nb);
+
+       switch (event) {
+       case USB_EVENT_VBUS:
+               schedule_work(&isp->work);
+               break;
+       case USB_EVENT_NONE:
+               if (isp->present) {
+                       isp->present = 0;
+                       power_supply_changed(&isp->psy);
+               }
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+
+       return NOTIFY_OK;
+}
+
+static int isp1704_charger_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct isp1704_charger *isp =
+               container_of(psy, struct isp1704_charger, psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = isp->present;
+               break;
+       case POWER_SUPPLY_PROP_MODEL_NAME:
+               val->strval = isp->model;
+               break;
+       case POWER_SUPPLY_PROP_MANUFACTURER:
+               val->strval = "NXP";
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static enum power_supply_property power_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
+{
+       int vendor;
+       int product;
+       int i;
+       int ret = -ENODEV;
+
+       /* Test ULPI interface */
+       ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa);
+       if (ret < 0)
+               return ret;
+
+       ret = otg_io_read(isp->otg, ULPI_SCRATCH);
+       if (ret < 0)
+               return ret;
+
+       if (ret != 0xaa)
+               return -ENODEV;
+
+       /* Verify the product and vendor id matches */
+       vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW);
+       vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8;
+       if (vendor != NXP_VENDOR_ID)
+               return -ENODEV;
+
+       product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW);
+       product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8;
+
+       for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) {
+               if (product == isp170x_id[i]) {
+                       sprintf(isp->model, "isp%x", product);
+                       return product;
+               }
+       }
+
+       dev_err(isp->dev, "product id %x not matching known ids", product);
+
+       return -ENODEV;
+}
+
+static int __devinit isp1704_charger_probe(struct platform_device *pdev)
+{
+       struct isp1704_charger  *isp;
+       int                     ret = -ENODEV;
+
+       isp = kzalloc(sizeof *isp, GFP_KERNEL);
+       if (!isp)
+               return -ENOMEM;
+
+       isp->otg = otg_get_transceiver();
+       if (!isp->otg)
+               goto fail0;
+
+       ret = isp1704_test_ulpi(isp);
+       if (ret < 0)
+               goto fail1;
+
+       isp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, isp);
+
+       isp->psy.name           = "isp1704";
+       isp->psy.type           = POWER_SUPPLY_TYPE_USB;
+       isp->psy.properties     = power_props;
+       isp->psy.num_properties = ARRAY_SIZE(power_props);
+       isp->psy.get_property   = isp1704_charger_get_property;
+
+       ret = power_supply_register(isp->dev, &isp->psy);
+       if (ret)
+               goto fail1;
+
+       /*
+        * REVISIT: using work in order to allow the otg notifications to be
+        * made atomically in the future.
+        */
+       INIT_WORK(&isp->work, isp1704_charger_work);
+
+       isp->nb.notifier_call = isp1704_notifier_call;
+
+       ret = otg_register_notifier(isp->otg, &isp->nb);
+       if (ret)
+               goto fail2;
+
+       dev_info(isp->dev, "registered with product id %s\n", isp->model);
+
+       return 0;
+fail2:
+       power_supply_unregister(&isp->psy);
+fail1:
+       otg_put_transceiver(isp->otg);
+fail0:
+       kfree(isp);
+
+       dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret);
+
+       return ret;
+}
+
+static int __devexit isp1704_charger_remove(struct platform_device *pdev)
+{
+       struct isp1704_charger *isp = platform_get_drvdata(pdev);
+
+       otg_unregister_notifier(isp->otg, &isp->nb);
+       power_supply_unregister(&isp->psy);
+       otg_put_transceiver(isp->otg);
+       kfree(isp);
+
+       return 0;
+}
+
+static struct platform_driver isp1704_charger_driver = {
+       .driver = {
+               .name = "isp1704_charger",
+       },
+       .probe = isp1704_charger_probe,
+       .remove = __devexit_p(isp1704_charger_remove),
+};
+
+static int __init isp1704_charger_init(void)
+{
+       return platform_driver_register(&isp1704_charger_driver);
+}
+module_init(isp1704_charger_init);
+
+static void __exit isp1704_charger_exit(void)
+{
+       platform_driver_unregister(&isp1704_charger_driver);
+}
+module_exit(isp1704_charger_exit);
+
+MODULE_ALIAS("platform:isp1704_charger");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("ISP170x USB Charger driver");
+MODULE_LICENSE("GPL");
index 20c4b952e9bd1f6cbd75887b79f81b226a36a436..a8108a73593e49e19b64ce29e72c45c8b3c9d879 100644 (file)
@@ -383,6 +383,7 @@ static int __devexit jz_battery_remove(struct platform_device *pdev)
 
        iounmap(jz_battery->base);
        release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
+       kfree(jz_battery);
 
        return 0;
 }
index aafc1c506eda54fecd6ecad24b48b56ee00deded..5bc1dcf7785ec20874c191206ecc982768b93cbc 100644 (file)
@@ -271,14 +271,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (int)be16_to_cpu(ec_word) * 9760L / 32;
+               val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
                ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120;
+               val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
@@ -299,7 +299,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
+               val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
                break;
        case POWER_SUPPLY_PROP_TEMP_AMBIENT:
                ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
@@ -313,7 +313,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (int)be16_to_cpu(ec_word) * 6250 / 15;
+               val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15;
                break;
        case POWER_SUPPLY_PROP_SERIAL_NUMBER:
                ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
index 066f994e6fe5ac4b74dda65ba658450b283cbe9f..4fa52e1781a225e5bad152a6dd9a6c5e76752503 100644 (file)
@@ -456,6 +456,7 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
                pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
 
+       sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group);
        power_supply_unregister(&mbc->usb);
        power_supply_unregister(&mbc->adapter);
        power_supply_unregister(&mbc->ac);
index 9d30eeb8c8104187320794eca0e11e8d191c8ad0..cd1f90754a3a301ebdbdd71da8bac4ad8265a580 100644 (file)
@@ -42,7 +42,8 @@ static ssize_t power_supply_show_property(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf) {
        static char *type_text[] = {
-               "Battery", "UPS", "Mains", "USB"
+               "Battery", "UPS", "Mains", "USB",
+               "USB_DCP", "USB_CDP", "USB_ACA"
        };
        static char *status_text[] = {
                "Unknown", "Charging", "Discharging", "Not charging", "Full"
@@ -138,6 +139,7 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(voltage_min_design),
        POWER_SUPPLY_ATTR(voltage_now),
        POWER_SUPPLY_ATTR(voltage_avg),
+       POWER_SUPPLY_ATTR(current_max),
        POWER_SUPPLY_ATTR(current_now),
        POWER_SUPPLY_ATTR(current_avg),
        POWER_SUPPLY_ATTR(power_now),
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
new file mode 100644 (file)
index 0000000..ff1f423
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * TWL4030/TPS65950 BCI (Battery Charger Interface) driver
+ *
+ * Copyright (C) 2010 Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * based on twl4030_bci_battery.c by TI
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/twl.h>
+#include <linux/power_supply.h>
+#include <linux/notifier.h>
+#include <linux/usb/otg.h>
+
+#define TWL4030_BCIMSTATEC     0x02
+#define TWL4030_BCIICHG                0x08
+#define TWL4030_BCIVAC         0x0a
+#define TWL4030_BCIVBUS                0x0c
+#define TWL4030_BCIMFSTS4      0x10
+#define TWL4030_BCICTL1                0x23
+
+#define TWL4030_BCIAUTOWEN     BIT(5)
+#define TWL4030_CONFIG_DONE    BIT(4)
+#define TWL4030_BCIAUTOUSB     BIT(1)
+#define TWL4030_BCIAUTOAC      BIT(0)
+#define TWL4030_CGAIN          BIT(5)
+#define TWL4030_USBFASTMCHG    BIT(2)
+#define TWL4030_STS_VBUS       BIT(7)
+#define TWL4030_STS_USB_ID     BIT(2)
+
+/* BCI interrupts */
+#define TWL4030_WOVF           BIT(0) /* Watchdog overflow */
+#define TWL4030_TMOVF          BIT(1) /* Timer overflow */
+#define TWL4030_ICHGHIGH       BIT(2) /* Battery charge current high */
+#define TWL4030_ICHGLOW                BIT(3) /* Battery cc. low / FSM state change */
+#define TWL4030_ICHGEOC                BIT(4) /* Battery current end-of-charge */
+#define TWL4030_TBATOR2                BIT(5) /* Battery temperature out of range 2 */
+#define TWL4030_TBATOR1                BIT(6) /* Battery temperature out of range 1 */
+#define TWL4030_BATSTS         BIT(7) /* Battery status */
+
+#define TWL4030_VBATLVL                BIT(0) /* VBAT level */
+#define TWL4030_VBATOV         BIT(1) /* VBAT overvoltage */
+#define TWL4030_VBUSOV         BIT(2) /* VBUS overvoltage */
+#define TWL4030_ACCHGOV                BIT(3) /* Ac charger overvoltage */
+
+#define TWL4030_MSTATEC_USB            BIT(4)
+#define TWL4030_MSTATEC_AC             BIT(5)
+#define TWL4030_MSTATEC_MASK           0x0f
+#define TWL4030_MSTATEC_QUICK1         0x02
+#define TWL4030_MSTATEC_QUICK7         0x07
+#define TWL4030_MSTATEC_COMPLETE1      0x0b
+#define TWL4030_MSTATEC_COMPLETE4      0x0e
+
+static bool allow_usb;
+module_param(allow_usb, bool, 1);
+MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
+
+struct twl4030_bci {
+       struct device           *dev;
+       struct power_supply     ac;
+       struct power_supply     usb;
+       struct otg_transceiver  *transceiver;
+       struct notifier_block   otg_nb;
+       int                     irq_chg;
+       int                     irq_bci;
+};
+
+/*
+ * clear and set bits on an given register on a given module
+ */
+static int twl4030_clear_set(u8 mod_no, u8 clear, u8 set, u8 reg)
+{
+       u8 val = 0;
+       int ret;
+
+       ret = twl_i2c_read_u8(mod_no, &val, reg);
+       if (ret)
+               return ret;
+
+       val &= ~clear;
+       val |= set;
+
+       return twl_i2c_write_u8(mod_no, val, reg);
+}
+
+static int twl4030_bci_read(u8 reg, u8 *val)
+{
+       return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg);
+}
+
+static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
+{
+       return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0,
+                       TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
+                       TWL4030_PM_MASTER_BOOT_BCI);
+}
+
+static int twl4030bci_read_adc_val(u8 reg)
+{
+       int ret, temp;
+       u8 val;
+
+       /* read MSB */
+       ret = twl4030_bci_read(reg + 1, &val);
+       if (ret)
+               return ret;
+
+       temp = (int)(val & 0x03) << 8;
+
+       /* read LSB */
+       ret = twl4030_bci_read(reg, &val);
+       if (ret)
+               return ret;
+
+       return temp | val;
+}
+
+/*
+ * Check if VBUS power is present
+ */
+static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
+{
+       int ret;
+       u8 hwsts;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
+                             TWL4030_PM_MASTER_STS_HW_CONDITIONS);
+       if (ret < 0)
+               return 0;
+
+       dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts);
+
+       /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
+       if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Enable/Disable USB Charge funtionality.
+ */
+static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
+{
+       int ret;
+
+       if (enable) {
+               /* Check for USB charger conneted */
+               if (!twl4030_bci_have_vbus(bci))
+                       return -ENODEV;
+
+               /*
+                * Until we can find out what current the device can provide,
+                * require a module param to enable USB charging.
+                */
+               if (!allow_usb) {
+                       dev_warn(bci->dev, "USB charging is disabled.\n");
+                       return -EACCES;
+               }
+
+               /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+               ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
+               if (ret < 0)
+                       return ret;
+
+               /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
+               ret = twl4030_clear_set(TWL4030_MODULE_MAIN_CHARGE, 0,
+                       TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+       } else {
+               ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+       }
+
+       return ret;
+}
+
+/*
+ * Enable/Disable AC Charge funtionality.
+ */
+static int twl4030_charger_enable_ac(bool enable)
+{
+       int ret;
+
+       if (enable)
+               ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
+       else
+               ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0);
+
+       return ret;
+}
+
+/*
+ * TWL4030 CHG_PRES (AC charger presence) events
+ */
+static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
+{
+       struct twl4030_bci *bci = arg;
+
+       dev_dbg(bci->dev, "CHG_PRES irq\n");
+       power_supply_changed(&bci->ac);
+       power_supply_changed(&bci->usb);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * TWL4030 BCI monitoring events
+ */
+static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
+{
+       struct twl4030_bci *bci = arg;
+       u8 irqs1, irqs2;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs1,
+                             TWL4030_INTERRUPTS_BCIISR1A);
+       if (ret < 0)
+               return IRQ_HANDLED;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs2,
+                             TWL4030_INTERRUPTS_BCIISR2A);
+       if (ret < 0)
+               return IRQ_HANDLED;
+
+       dev_dbg(bci->dev, "BCI irq %02x %02x\n", irqs2, irqs1);
+
+       if (irqs1 & (TWL4030_ICHGLOW | TWL4030_ICHGEOC)) {
+               /* charger state change, inform the core */
+               power_supply_changed(&bci->ac);
+               power_supply_changed(&bci->usb);
+       }
+
+       /* various monitoring events, for now we just log them here */
+       if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1))
+               dev_warn(bci->dev, "battery temperature out of range\n");
+
+       if (irqs1 & TWL4030_BATSTS)
+               dev_crit(bci->dev, "battery disconnected\n");
+
+       if (irqs2 & TWL4030_VBATOV)
+               dev_crit(bci->dev, "VBAT overvoltage\n");
+
+       if (irqs2 & TWL4030_VBUSOV)
+               dev_crit(bci->dev, "VBUS overvoltage\n");
+
+       if (irqs2 & TWL4030_ACCHGOV)
+               dev_crit(bci->dev, "Ac charger overvoltage\n");
+
+       return IRQ_HANDLED;
+}
+
+static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
+                              void *priv)
+{
+       struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+
+       dev_dbg(bci->dev, "OTG notify %lu\n", val);
+
+       switch (val) {
+       case USB_EVENT_VBUS:
+       case USB_EVENT_CHARGER:
+               twl4030_charger_enable_usb(bci, true);
+               break;
+       case USB_EVENT_NONE:
+               twl4030_charger_enable_usb(bci, false);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+/*
+ * TI provided formulas:
+ * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
+ * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
+ * Here we use integer approximation of:
+ * CGAIN == 0: val * 1.6618 - 0.85
+ * CGAIN == 1: (val * 1.6618 - 0.85) * 2
+ */
+static int twl4030_charger_get_current(void)
+{
+       int curr;
+       int ret;
+       u8 bcictl1;
+
+       curr = twl4030bci_read_adc_val(TWL4030_BCIICHG);
+       if (curr < 0)
+               return curr;
+
+       ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
+       if (ret)
+               return ret;
+
+       ret = (curr * 16618 - 850 * 10000) / 10;
+       if (bcictl1 & TWL4030_CGAIN)
+               ret *= 2;
+
+       return ret;
+}
+
+/*
+ * Returns the main charge FSM state
+ * Or < 0 on failure.
+ */
+static int twl4030bci_state(struct twl4030_bci *bci)
+{
+       int ret;
+       u8 state;
+
+       ret = twl4030_bci_read(TWL4030_BCIMSTATEC, &state);
+       if (ret) {
+               pr_err("twl4030_bci: error reading BCIMSTATEC\n");
+               return ret;
+       }
+
+       dev_dbg(bci->dev, "state: %02x\n", state);
+
+       return state;
+}
+
+static int twl4030_bci_state_to_status(int state)
+{
+       state &= TWL4030_MSTATEC_MASK;
+       if (TWL4030_MSTATEC_QUICK1 <= state && state <= TWL4030_MSTATEC_QUICK7)
+               return POWER_SUPPLY_STATUS_CHARGING;
+       else if (TWL4030_MSTATEC_COMPLETE1 <= state &&
+                                       state <= TWL4030_MSTATEC_COMPLETE4)
+               return POWER_SUPPLY_STATUS_FULL;
+       else
+               return POWER_SUPPLY_STATUS_NOT_CHARGING;
+}
+
+static int twl4030_bci_get_property(struct power_supply *psy,
+                                   enum power_supply_property psp,
+                                   union power_supply_propval *val)
+{
+       struct twl4030_bci *bci = dev_get_drvdata(psy->dev->parent);
+       int is_charging;
+       int state;
+       int ret;
+
+       state = twl4030bci_state(bci);
+       if (state < 0)
+               return state;
+
+       if (psy->type == POWER_SUPPLY_TYPE_USB)
+               is_charging = state & TWL4030_MSTATEC_USB;
+       else
+               is_charging = state & TWL4030_MSTATEC_AC;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               if (is_charging)
+                       val->intval = twl4030_bci_state_to_status(state);
+               else
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               /* charging must be active for meaningful result */
+               if (!is_charging)
+                       return -ENODATA;
+               if (psy->type == POWER_SUPPLY_TYPE_USB) {
+                       ret = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
+                       if (ret < 0)
+                               return ret;
+                       /* BCIVBUS uses ADCIN8, 7/1023 V/step */
+                       val->intval = ret * 6843;
+               } else {
+                       ret = twl4030bci_read_adc_val(TWL4030_BCIVAC);
+                       if (ret < 0)
+                               return ret;
+                       /* BCIVAC uses ADCIN11, 10/1023 V/step */
+                       val->intval = ret * 9775;
+               }
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (!is_charging)
+                       return -ENODATA;
+               /* current measurement is shared between AC and USB */
+               ret = twl4030_charger_get_current();
+               if (ret < 0)
+                       return ret;
+               val->intval = ret;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = is_charging &&
+                       twl4030_bci_state_to_status(state) !=
+                               POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum power_supply_property twl4030_charger_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+static int __init twl4030_bci_probe(struct platform_device *pdev)
+{
+       struct twl4030_bci *bci;
+       int ret;
+       int reg;
+
+       bci = kzalloc(sizeof(*bci), GFP_KERNEL);
+       if (bci == NULL)
+               return -ENOMEM;
+
+       bci->dev = &pdev->dev;
+       bci->irq_chg = platform_get_irq(pdev, 0);
+       bci->irq_bci = platform_get_irq(pdev, 1);
+
+       platform_set_drvdata(pdev, bci);
+
+       bci->ac.name = "twl4030_ac";
+       bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
+       bci->ac.properties = twl4030_charger_props;
+       bci->ac.num_properties = ARRAY_SIZE(twl4030_charger_props);
+       bci->ac.get_property = twl4030_bci_get_property;
+
+       ret = power_supply_register(&pdev->dev, &bci->ac);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register ac: %d\n", ret);
+               goto fail_register_ac;
+       }
+
+       bci->usb.name = "twl4030_usb";
+       bci->usb.type = POWER_SUPPLY_TYPE_USB;
+       bci->usb.properties = twl4030_charger_props;
+       bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
+       bci->usb.get_property = twl4030_bci_get_property;
+
+       ret = power_supply_register(&pdev->dev, &bci->usb);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
+               goto fail_register_usb;
+       }
+
+       ret = request_threaded_irq(bci->irq_chg, NULL,
+                       twl4030_charger_interrupt, 0, pdev->name, bci);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "could not request irq %d, status %d\n",
+                       bci->irq_chg, ret);
+               goto fail_chg_irq;
+       }
+
+       ret = request_threaded_irq(bci->irq_bci, NULL,
+                       twl4030_bci_interrupt, 0, pdev->name, bci);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "could not request irq %d, status %d\n",
+                       bci->irq_bci, ret);
+               goto fail_bci_irq;
+       }
+
+       bci->transceiver = otg_get_transceiver();
+       if (bci->transceiver != NULL) {
+               bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
+               otg_register_notifier(bci->transceiver, &bci->otg_nb);
+       }
+
+       /* Enable interrupts now. */
+       reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
+               TWL4030_TBATOR1 | TWL4030_BATSTS);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+                              TWL4030_INTERRUPTS_BCIIMR1A);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
+               goto fail_unmask_interrupts;
+       }
+
+       reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+                              TWL4030_INTERRUPTS_BCIIMR2A);
+       if (ret < 0)
+               dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
+
+       twl4030_charger_enable_ac(true);
+       twl4030_charger_enable_usb(bci, true);
+
+       return 0;
+
+fail_unmask_interrupts:
+       if (bci->transceiver != NULL) {
+               otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
+               otg_put_transceiver(bci->transceiver);
+       }
+       free_irq(bci->irq_bci, bci);
+fail_bci_irq:
+       free_irq(bci->irq_chg, bci);
+fail_chg_irq:
+       power_supply_unregister(&bci->usb);
+fail_register_usb:
+       power_supply_unregister(&bci->ac);
+fail_register_ac:
+       platform_set_drvdata(pdev, NULL);
+       kfree(bci);
+
+       return ret;
+}
+
+static int __exit twl4030_bci_remove(struct platform_device *pdev)
+{
+       struct twl4030_bci *bci = platform_get_drvdata(pdev);
+
+       twl4030_charger_enable_ac(false);
+       twl4030_charger_enable_usb(bci, false);
+
+       /* mask interrupts */
+       twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
+                        TWL4030_INTERRUPTS_BCIIMR1A);
+       twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
+                        TWL4030_INTERRUPTS_BCIIMR2A);
+
+       if (bci->transceiver != NULL) {
+               otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
+               otg_put_transceiver(bci->transceiver);
+       }
+       free_irq(bci->irq_bci, bci);
+       free_irq(bci->irq_chg, bci);
+       power_supply_unregister(&bci->usb);
+       power_supply_unregister(&bci->ac);
+       platform_set_drvdata(pdev, NULL);
+       kfree(bci);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_bci_driver = {
+       .driver = {
+               .name   = "twl4030_bci",
+               .owner  = THIS_MODULE,
+       },
+       .remove = __exit_p(twl4030_bci_remove),
+};
+
+static int __init twl4030_bci_init(void)
+{
+       return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe);
+}
+module_init(twl4030_bci_init);
+
+static void __exit twl4030_bci_exit(void)
+{
+       platform_driver_unregister(&twl4030_bci_driver);
+}
+module_exit(twl4030_bci_exit);
+
+MODULE_AUTHOR("Gražydas Ignotas");
+MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_bci");
index fbcc36dae470472fd685228ea261a349e664d145..ddf8cf5f3204032f835892487ba085e058f49c82 100644 (file)
@@ -267,7 +267,6 @@ static void wm831x_config_battery(struct wm831x *wm831x)
        ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1,
                              WM831X_CHG_ENA_MASK |
                              WM831X_CHG_FAST_MASK |
-                             WM831X_CHG_ITERM_MASK |
                              WM831X_CHG_ITERM_MASK,
                              reg1);
        if (ret != 0)
@@ -612,6 +611,7 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev)
        power_supply_unregister(&wm831x_power->battery);
        power_supply_unregister(&wm831x_power->wall);
        power_supply_unregister(&wm831x_power->usb);
+       kfree(wm831x_power);
        return 0;
 }
 
index 48ca7132cc05da18a16c9136f3974219bce4a3d3..2785a0f16c9f656bd910e09ba0a37ed223c7078c 100644 (file)
@@ -765,15 +765,15 @@ config RTC_DRV_AT32AP700X
          AT32AP700x family processors.
 
 config RTC_DRV_AT91RM9200
-       tristate "AT91RM9200 or AT91SAM9RL"
-       depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
+       tristate "AT91RM9200 or some AT91SAM9 RTC"
+       depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
        help
          Driver for the internal RTC (Realtime Clock) module found on
-         Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips
+         Atmel AT91RM9200's and some  AT91SAM9 chips. On AT91SAM9 chips
          this is powered by the backup power supply.
 
 config RTC_DRV_AT91SAM9
-       tristate "AT91SAM9x/AT91CAP9"
+       tristate "AT91SAM9x/AT91CAP9 RTT as RTC"
        depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
        help
          RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
@@ -781,8 +781,8 @@ config RTC_DRV_AT91SAM9
          supply (such as a small coin cell battery), but do not need to
          be used as RTCs.
 
-         (On AT91SAM9rl chips you probably want to use the dedicated RTC
-         module and leave the RTT available for other uses.)
+         (On AT91SAM9rl and AT91SAM9G45 chips you probably want to use the
+         dedicated RTC module and leave the RTT available for other uses.)
 
 config RTC_DRV_AT91SAM9_RTT
        int
index aa95f1001761534d187eb06ceab7597faa24f51d..fb613d70c2cbb32e381bba6951568bc217ac8d5c 100644 (file)
@@ -1099,16 +1099,30 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        cqr = (struct dasd_ccw_req *) intparm;
        if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
                     (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
-                    (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {
+                    ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
+                     (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
+                                                 SCSW_STCTL_ALERT_STATUS))))) {
                if (cqr && cqr->status == DASD_CQR_IN_IO)
                        cqr->status = DASD_CQR_QUEUED;
+               if (cqr)
+                       memcpy(&cqr->irb, irb, sizeof(*irb));
                device = dasd_device_from_cdev_locked(cdev);
-               if (!IS_ERR(device)) {
-                       dasd_device_clear_timer(device);
-                       device->discipline->handle_unsolicited_interrupt(device,
-                                                                        irb);
+               if (IS_ERR(device))
+                       return;
+               /* ignore unsolicited interrupts for DIAG discipline */
+               if (device->discipline == dasd_diag_discipline_pointer) {
                        dasd_put_device(device);
+                       return;
                }
+               device->discipline->dump_sense_dbf(device, irb,
+                                                  "unsolicited");
+               if ((device->features & DASD_FEATURE_ERPLOG))
+                       device->discipline->dump_sense(device, cqr,
+                                                      irb);
+               dasd_device_clear_timer(device);
+               device->discipline->handle_unsolicited_interrupt(device,
+                                                                irb);
+               dasd_put_device(device);
                return;
        }
 
index e82d427ff5ebc8bf14a0e227e0ae5c32077bd797..968c76cf71276e91c8d21c5d523c3f4a214cbade 100644 (file)
@@ -221,6 +221,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
        ccw->cmd_code = CCW_CMD_DCTL;
        ccw->count = 4;
        ccw->cda = (__u32)(addr_t) DCTL_data;
+       dctl_cqr->flags = erp->flags;
        dctl_cqr->function = dasd_3990_erp_DCTL;
        dctl_cqr->refers = erp;
        dctl_cqr->startdev = device;
@@ -1710,6 +1711,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
        ccw->cda = cpa;
 
        /* fill erp related fields */
+       erp->flags = default_erp->flags;
        erp->function = dasd_3990_erp_action_1B_32;
        erp->refers = default_erp->refers;
        erp->startdev = device;
@@ -2354,6 +2356,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
                ccw->cda      = (long)(cqr->cpaddr);
        }
 
+       erp->flags = cqr->flags;
        erp->function = dasd_3990_erp_add_erp;
        erp->refers   = cqr;
        erp->startdev = device;
index 2b3bc3ec0541e2886d75a0058d347b29bb5fa61a..266b34b55403c638a946d918fb0f45f84b203f6d 100644 (file)
@@ -228,25 +228,22 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
 }
 
 /* Handle external interruption. */
-static void
-dasd_ext_handler(__u16 code)
+static void dasd_ext_handler(unsigned int ext_int_code,
+                            unsigned int param32, unsigned long param64)
 {
        struct dasd_ccw_req *cqr, *next;
        struct dasd_device *device;
        unsigned long long expires;
        unsigned long flags;
-       u8 int_code, status;
        addr_t ip;
        int rc;
 
-       int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
-       status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
-       switch (int_code) {
+       switch (ext_int_code >> 24) {
        case DASD_DIAG_CODE_31BIT:
-               ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+               ip = (addr_t) param32;
                break;
        case DASD_DIAG_CODE_64BIT:
-               ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+               ip = (addr_t) param64;
                break;
        default:
                return;
@@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code)
        cqr->stopclk = get_clock();
 
        expires = 0;
-       if (status == 0) {
+       if ((ext_int_code & 0xff0000) == 0) {
                cqr->status = DASD_CQR_SUCCESS;
                /* Start first request on queue if possible -> fast_io. */
                if (!list_empty(&device->ccw_queue)) {
@@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code)
        } else {
                cqr->status = DASD_CQR_QUEUED;
                DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
-                           "request %p was %d (%d retries left)", cqr, status,
-                           cqr->retries);
+                             "request %p was %d (%d retries left)", cqr,
+                             (ext_int_code >> 16) & 0xff, cqr->retries);
                dasd_diag_erp(device);
        }
 
index b8c78267ff3ef01ef0e60a1e211784629f2f094e..4f71fbe60c8294df766d783c2ace72c33ef0d50a 100644 (file)
 #define DEV_CLASS_FBA  0x01
 #define DEV_CLASS_ECKD 0x04
 
-#define DASD_DIAG_LC_INT_CODE          132
-#define DASD_DIAG_LC_INT_STATUS                133
-#define DASD_DIAG_LC_INT_PARM_31BIT    128
-#define DASD_DIAG_LC_INT_PARM_64BIT    4536
 #define DASD_DIAG_CODE_31BIT           0x03
 #define DASD_DIAG_CODE_64BIT           0x07
 
index 59b4ecfb967b956e7c8d626cad5794ab300cede6..50cf96389d2c319c3d67d95a039e00157adc0078 100644 (file)
@@ -1776,13 +1776,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
        }
 
        /* summary unit check */
-       if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
-           (irb->ecw[7] == 0x0D)) {
+       sense = dasd_get_sense(irb);
+       if (sense && (sense[7] == 0x0D) &&
+           (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
                dasd_alias_handle_summary_unit_check(device, irb);
                return;
        }
 
-       sense = dasd_get_sense(irb);
        /* service information message SIM */
        if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
            ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
@@ -1791,26 +1791,15 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
                return;
        }
 
-       if ((scsw_cc(&irb->scsw) == 1) &&
-           (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
-           (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) &&
-           (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) {
+       if ((scsw_cc(&irb->scsw) == 1) && !sense &&
+           (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
+           (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
+           (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
                /* fake irb do nothing, they are handled elsewhere */
                dasd_schedule_device_bh(device);
                return;
        }
 
-       if (!sense) {
-               /* just report other unsolicited interrupts */
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
-                           "unsolicited interrupt received");
-       } else {
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
-                           "unsolicited interrupt received "
-                           "(sense available)");
-               device->discipline->dump_sense_dbf(device, irb, "unsolicited");
-       }
-
        dasd_schedule_device_bh(device);
        return;
 };
@@ -3093,19 +3082,19 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
                         char *reason)
 {
        u64 *sense;
+       u64 *stat;
 
        sense = (u64 *) dasd_get_sense(irb);
+       stat = (u64 *) &irb->scsw;
        if (sense) {
-               DBF_DEV_EVENT(DBF_EMERG, device,
-                             "%s: %s %02x%02x%02x %016llx %016llx %016llx "
-                             "%016llx", reason,
-                             scsw_is_tm(&irb->scsw) ? "t" : "c",
-                             scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
-                             scsw_dstat(&irb->scsw), sense[0], sense[1],
-                             sense[2], sense[3]);
+               DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : "
+                             "%016llx %016llx %016llx %016llx",
+                             reason, *stat, *((u32 *) (stat + 1)),
+                             sense[0], sense[1], sense[2], sense[3]);
        } else {
-               DBF_DEV_EVENT(DBF_EMERG, device, "%s",
-                             "SORRY - NO VALID SENSE AVAILABLE\n");
+               DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : %s",
+                             reason, *stat, *((u32 *) (stat + 1)),
+                             "NO VALID SENSE");
        }
 }
 
@@ -3131,9 +3120,12 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                      " I/O status report for device %s:\n",
                      dev_name(&device->cdev->dev));
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                      " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n",
-                      req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
-                      scsw_cc(&irb->scsw), req ? req->intrc : 0);
+                      " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
+                      "CS:%02X RC:%d\n",
+                      req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
+                      scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
+                      scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
+                      req ? req->intrc : 0);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing CCW: %p\n",
                       dev_name(&device->cdev->dev),
@@ -3234,11 +3226,13 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                      " I/O status report for device %s:\n",
                      dev_name(&device->cdev->dev));
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                      " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d "
-                      "fcxs: 0x%02X schxs: 0x%02X\n", req,
-                      scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
-                      scsw_cc(&irb->scsw), req->intrc,
-                      irb->scsw.tm.fcxs, irb->scsw.tm.schxs);
+                      " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
+                      "CS:%02X fcxs:%02X schxs:%02X RC:%d\n",
+                      req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
+                      scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
+                      scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
+                      irb->scsw.tm.fcxs, irb->scsw.tm.schxs,
+                      req ? req->intrc : 0);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing TCW: %p\n",
                       dev_name(&device->cdev->dev),
@@ -3246,7 +3240,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
 
        tsb = NULL;
        sense = NULL;
-       if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01))
+       if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01))
                tsb = tcw_get_tsb(
                        (struct tcw *)(unsigned long)irb->scsw.tm.tcw);
 
@@ -3344,7 +3338,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
 static void dasd_eckd_dump_sense(struct dasd_device *device,
                                 struct dasd_ccw_req *req, struct irb *irb)
 {
-       if (req && scsw_is_tm(&req->irb.scsw))
+       if (scsw_is_tm(&irb->scsw))
                dasd_eckd_dump_sense_tcw(device, req, irb);
        else
                dasd_eckd_dump_sense_ccw(device, req, irb);
index 2eb02559280927594f7a10efbfe19ead060be9aa..c4a6a31bd9cdcb623e241389e8787b7cd0436f56 100644 (file)
@@ -251,7 +251,6 @@ static ssize_t dasd_stats_proc_write(struct file *file,
        buffer = dasd_get_user_string(user_buf, user_len);
        if (IS_ERR(buffer))
                return PTR_ERR(buffer);
-       DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer);
 
        /* check for valid verbs */
        str = skip_spaces(buffer);
index 5707a80b96b669d055ed26572051de637ccd7ae2..35cc4686b99b458d75a9422ca89394fe4e16ba14 100644 (file)
@@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb)
 /* Handler for external interruption. Perform request post-processing.
  * Prepare read event data request if necessary. Start processing of next
  * request on queue. */
-static void
-sclp_interrupt_handler(__u16 code)
+static void sclp_interrupt_handler(unsigned int ext_int_code,
+                                  unsigned int param32, unsigned long param64)
 {
        struct sclp_req *req;
        u32 finished_sccb;
        u32 evbuf_pending;
 
        spin_lock(&sclp_lock);
-       finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
-       evbuf_pending = S390_lowcore.ext_params & 0x3;
+       finished_sccb = param32 & 0xfffffff8;
+       evbuf_pending = param32 & 0x3;
        if (finished_sccb) {
                del_timer(&sclp_request_timer);
                sclp_running_state = sclp_running_state_reset_pending;
@@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate);
 
 /* Handler for external interruption used during initialization. Modify
  * request state to done. */
-static void
-sclp_check_handler(__u16 code)
+static void sclp_check_handler(unsigned int ext_int_code,
+                              unsigned int param32, unsigned long param64)
 {
        u32 finished_sccb;
 
-       finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
+       finished_sccb = param32 & 0xfffffff8;
        /* Is this the interrupt we are waiting for? */
        if (finished_sccb == 0)
                return;
index 0d6dc4b92cc2daacc90a2a8e5210d84b560e7a72..9f661426e4a1e28494bbe3054ee412696e0a6ad1 100644 (file)
@@ -215,7 +215,7 @@ static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
 
 static int vmlogrdr_get_recording_class_AB(void)
 {
-       char cp_command[]="QUERY COMMAND RECORDING ";
+       static const char cp_command[] = "QUERY COMMAND RECORDING ";
        char cp_response[80];
        char *tail;
        int len,i;
@@ -638,7 +638,7 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
                                              char *buf)
 {
 
-       char cp_command[] = "QUERY RECORDING ";
+       static const char cp_command[] = "QUERY RECORDING ";
        int len;
 
        cpcmd(cp_command, buf, 4096, NULL);
index 13cb60162e429675a2f0233e903f48ccea9d89ed..76058a5166eda01681a368f061f59afcbe609454 100644 (file)
@@ -79,17 +79,15 @@ static int pure_hex(char **cp, unsigned int *val, int min_digit,
                    int max_digit, int max_val)
 {
        int diff;
-       unsigned int value;
 
        diff = 0;
        *val = 0;
 
-       while (isxdigit(**cp) && (diff <= max_digit)) {
+       while (diff <= max_digit) {
+               int value = hex_to_bin(**cp);
 
-               if (isdigit(**cp))
-                       value = **cp - '0';
-               else
-                       value = tolower(**cp) - 'a' + 10;
+               if (value < 0)
+                       break;
                *val = *val * 16 + value;
                (*cp)++;
                diff++;
index 6c9fa15aac7b2c1770afccdc2a0abef461e1eae8..2d32233943a917c7f6ae9949122a78e3f962a60c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chp.c
  *
- *    Copyright IBM Corp. 1999,2007
+ *    Copyright IBM Corp. 1999,2010
  *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
  *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
@@ -54,12 +54,6 @@ static struct work_struct cfg_work;
 /* Wait queue for configure completion events. */
 static wait_queue_head_t cfg_wait_queue;
 
-/* Return channel_path struct for given chpid. */
-static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
-{
-       return channel_subsystems[chpid.cssid]->chps[chpid.id];
-}
-
 /* Set vary state for given chpid. */
 static void set_chp_logically_online(struct chp_id chpid, int onoff)
 {
@@ -241,11 +235,13 @@ static ssize_t chp_status_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
        struct channel_path *chp = to_channelpath(dev);
+       int status;
 
-       if (!chp)
-               return 0;
-       return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") :
-               sprintf(buf, "offline\n"));
+       mutex_lock(&chp->lock);
+       status = chp->state;
+       mutex_unlock(&chp->lock);
+
+       return status ? sprintf(buf, "online\n") : sprintf(buf, "offline\n");
 }
 
 static ssize_t chp_status_write(struct device *dev,
@@ -261,15 +257,18 @@ static ssize_t chp_status_write(struct device *dev,
        if (!num_args)
                return count;
 
-       if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))
+       if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
+               mutex_lock(&cp->lock);
                error = s390_vary_chpid(cp->chpid, 1);
-       else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))
+               mutex_unlock(&cp->lock);
+       } else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
+               mutex_lock(&cp->lock);
                error = s390_vary_chpid(cp->chpid, 0);
-       else
+               mutex_unlock(&cp->lock);
+       } else
                error = -EINVAL;
 
        return error < 0 ? error : count;
-
 }
 
 static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
@@ -315,10 +314,12 @@ static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        struct channel_path *chp = to_channelpath(dev);
+       u8 type;
 
-       if (!chp)
-               return 0;
-       return sprintf(buf, "%x\n", chp->desc.desc);
+       mutex_lock(&chp->lock);
+       type = chp->desc.desc;
+       mutex_unlock(&chp->lock);
+       return sprintf(buf, "%x\n", type);
 }
 
 static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
@@ -395,6 +396,7 @@ int chp_new(struct chp_id chpid)
        chp->state = 1;
        chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
        chp->dev.release = chp_release;
+       mutex_init(&chp->lock);
 
        /* Obtain channel path description and fill it in. */
        ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
@@ -464,7 +466,10 @@ void *chp_get_chp_desc(struct chp_id chpid)
        desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
        if (!desc)
                return NULL;
+
+       mutex_lock(&chp->lock);
        memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+       mutex_unlock(&chp->lock);
        return desc;
 }
 
index 26c3d22461764b56630958bbbfa6cb9714b166b0..12b4903d6fe373f171b83a8a8a7d9ffc2e9a8b26 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chp.h
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007,2010
  *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <asm/chpid.h>
 #include "chsc.h"
 #include "css.h"
@@ -40,16 +41,23 @@ static inline int chp_test_bit(u8 *bitmap, int num)
 
 
 struct channel_path {
+       struct device dev;
        struct chp_id chpid;
+       struct mutex lock; /* Serialize access to below members. */
        int state;
        struct channel_path_desc desc;
        /* Channel-measurement related stuff: */
        int cmg;
        int shared;
        void *cmg_chars;
-       struct device dev;
 };
 
+/* Return channel_path struct for given chpid. */
+static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
+{
+       return channel_subsystems[chpid.cssid]->chps[chpid.id];
+}
+
 int chp_get_status(struct chp_id chpid);
 u8 chp_get_sch_opm(struct subchannel *sch);
 int chp_is_registered(struct chp_id chpid);
index 4cbb1a6ca33c809c6fd9366f891b7c6e44ac39d9..1aaddea673e07310e2db903c547a21a1ec36636e 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
  *
- *    Copyright IBM Corp. 1999,2008
+ *    Copyright IBM Corp. 1999,2010
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
@@ -29,8 +29,8 @@
 #include "chsc.h"
 
 static void *sei_page;
-static DEFINE_SPINLOCK(siosl_lock);
-static DEFINE_SPINLOCK(sda_lock);
+static void *chsc_page;
+static DEFINE_SPINLOCK(chsc_page_lock);
 
 /**
  * chsc_error_from_response() - convert a chsc response to an error
@@ -85,17 +85,15 @@ struct chsc_ssd_area {
 
 int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 {
-       unsigned long page;
        struct chsc_ssd_area *ssd_area;
        int ccode;
        int ret;
        int i;
        int mask;
 
-       page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!page)
-               return -ENOMEM;
-       ssd_area = (struct chsc_ssd_area *) page;
+       spin_lock_irq(&chsc_page_lock);
+       memset(chsc_page, 0, PAGE_SIZE);
+       ssd_area = chsc_page;
        ssd_area->request.length = 0x0010;
        ssd_area->request.code = 0x0004;
        ssd_area->ssid = schid.ssid;
@@ -106,25 +104,25 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
        /* Check response. */
        if (ccode > 0) {
                ret = (ccode == 3) ? -ENODEV : -EBUSY;
-               goto out_free;
+               goto out;
        }
        ret = chsc_error_from_response(ssd_area->response.code);
        if (ret != 0) {
                CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
                              schid.ssid, schid.sch_no,
                              ssd_area->response.code);
-               goto out_free;
+               goto out;
        }
        if (!ssd_area->sch_valid) {
                ret = -ENODEV;
-               goto out_free;
+               goto out;
        }
        /* Copy data */
        ret = 0;
        memset(ssd, 0, sizeof(struct chsc_ssd_info));
        if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
            (ssd_area->st != SUBCHANNEL_TYPE_MSG))
-               goto out_free;
+               goto out;
        ssd->path_mask = ssd_area->path_mask;
        ssd->fla_valid_mask = ssd_area->fla_valid_mask;
        for (i = 0; i < 8; i++) {
@@ -136,8 +134,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
                if (ssd_area->fla_valid_mask & mask)
                        ssd->fla[i] = ssd_area->fla[i];
        }
-out_free:
-       free_page(page);
+out:
+       spin_unlock_irq(&chsc_page_lock);
        return ret;
 }
 
@@ -497,6 +495,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
  */
 int chsc_chp_vary(struct chp_id chpid, int on)
 {
+       struct channel_path *chp = chpid_to_chp(chpid);
        struct chp_link link;
 
        memset(&link, 0, sizeof(struct chp_link));
@@ -506,11 +505,12 @@ int chsc_chp_vary(struct chp_id chpid, int on)
        /*
         * Redo PathVerification on the devices the chpid connects to
         */
-
-       if (on)
+       if (on) {
+               /* Try to update the channel path descritor. */
+               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
                for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
                                           __s390_vary_chpid_on, &link);
-       else
+       else
                for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
                                           NULL, &link);
 
@@ -552,7 +552,7 @@ cleanup:
        return ret;
 }
 
-int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
+int __chsc_do_secm(struct channel_subsystem *css, int enable)
 {
        struct {
                struct chsc_header request;
@@ -573,7 +573,9 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
        } __attribute__ ((packed)) *secm_area;
        int ret, ccode;
 
-       secm_area = page;
+       spin_lock_irq(&chsc_page_lock);
+       memset(chsc_page, 0, PAGE_SIZE);
+       secm_area = chsc_page;
        secm_area->request.length = 0x0050;
        secm_area->request.code = 0x0016;
 
@@ -584,8 +586,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
        secm_area->operation_code = enable ? 0 : 1;
 
        ccode = chsc(secm_area);
-       if (ccode > 0)
-               return (ccode == 3) ? -ENODEV : -EBUSY;
+       if (ccode > 0) {
+               ret = (ccode == 3) ? -ENODEV : -EBUSY;
+               goto out;
+       }
 
        switch (secm_area->response.code) {
        case 0x0102:
@@ -598,37 +602,32 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
        if (ret != 0)
                CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
                              secm_area->response.code);
+out:
+       spin_unlock_irq(&chsc_page_lock);
        return ret;
 }
 
 int
 chsc_secm(struct channel_subsystem *css, int enable)
 {
-       void  *secm_area;
        int ret;
 
-       secm_area = (void *)get_zeroed_page(GFP_KERNEL |  GFP_DMA);
-       if (!secm_area)
-               return -ENOMEM;
-
        if (enable && !css->cm_enabled) {
                css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
                css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
                if (!css->cub_addr1 || !css->cub_addr2) {
                        free_page((unsigned long)css->cub_addr1);
                        free_page((unsigned long)css->cub_addr2);
-                       free_page((unsigned long)secm_area);
                        return -ENOMEM;
                }
        }
-       ret = __chsc_do_secm(css, enable, secm_area);
+       ret = __chsc_do_secm(css, enable);
        if (!ret) {
                css->cm_enabled = enable;
                if (css->cm_enabled) {
                        ret = chsc_add_cmg_attr(css);
                        if (ret) {
-                               memset(secm_area, 0, PAGE_SIZE);
-                               __chsc_do_secm(css, 0, secm_area);
+                               __chsc_do_secm(css, 0);
                                css->cm_enabled = 0;
                        }
                } else
@@ -638,44 +637,24 @@ chsc_secm(struct channel_subsystem *css, int enable)
                free_page((unsigned long)css->cub_addr1);
                free_page((unsigned long)css->cub_addr2);
        }
-       free_page((unsigned long)secm_area);
        return ret;
 }
 
 int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
-                                    int c, int m,
-                                    struct chsc_response_struct *resp)
+                                    int c, int m, void *page)
 {
+       struct chsc_scpd *scpd_area;
        int ccode, ret;
 
-       struct {
-               struct chsc_header request;
-               u32 : 2;
-               u32 m : 1;
-               u32 c : 1;
-               u32 fmt : 4;
-               u32 cssid : 8;
-               u32 : 4;
-               u32 rfmt : 4;
-               u32 first_chpid : 8;
-               u32 : 24;
-               u32 last_chpid : 8;
-               u32 zeroes1;
-               struct chsc_header response;
-               u8 data[PAGE_SIZE - 20];
-       } __attribute__ ((packed)) *scpd_area;
-
        if ((rfmt == 1) && !css_general_characteristics.fcs)
                return -EINVAL;
        if ((rfmt == 2) && !css_general_characteristics.cib)
                return -EINVAL;
-       scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!scpd_area)
-               return -ENOMEM;
 
+       memset(page, 0, PAGE_SIZE);
+       scpd_area = page;
        scpd_area->request.length = 0x0010;
        scpd_area->request.code = 0x0002;
-
        scpd_area->cssid = chpid.cssid;
        scpd_area->first_chpid = chpid.id;
        scpd_area->last_chpid = chpid.id;
@@ -685,20 +664,13 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
        scpd_area->rfmt = rfmt;
 
        ccode = chsc(scpd_area);
-       if (ccode > 0) {
-               ret = (ccode == 3) ? -ENODEV : -EBUSY;
-               goto out;
-       }
+       if (ccode > 0)
+               return (ccode == 3) ? -ENODEV : -EBUSY;
 
        ret = chsc_error_from_response(scpd_area->response.code);
-       if (ret == 0)
-               /* Success. */
-               memcpy(resp, &scpd_area->response, scpd_area->response.length);
-       else
+       if (ret)
                CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
                              scpd_area->response.code);
-out:
-       free_page((unsigned long)scpd_area);
        return ret;
 }
 EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);
@@ -707,17 +679,19 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid,
                                          struct channel_path_desc *desc)
 {
        struct chsc_response_struct *chsc_resp;
+       struct chsc_scpd *scpd_area;
+       unsigned long flags;
        int ret;
 
-       chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL);
-       if (!chsc_resp)
-               return -ENOMEM;
-       ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
+       spin_lock_irqsave(&chsc_page_lock, flags);
+       scpd_area = chsc_page;
+       ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area);
        if (ret)
-               goto out_free;
+               goto out;
+       chsc_resp = (void *)&scpd_area->response;
        memcpy(desc, &chsc_resp->data, sizeof(*desc));
-out_free:
-       kfree(chsc_resp);
+out:
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -725,33 +699,22 @@ static void
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
                          struct cmg_chars *chars)
 {
-       switch (chp->cmg) {
-       case 2:
-       case 3:
-               chp->cmg_chars = kmalloc(sizeof(struct cmg_chars),
-                                        GFP_KERNEL);
-               if (chp->cmg_chars) {
-                       int i, mask;
-                       struct cmg_chars *cmg_chars;
-
-                       cmg_chars = chp->cmg_chars;
-                       for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
-                               mask = 0x80 >> (i + 3);
-                               if (cmcv & mask)
-                                       cmg_chars->values[i] = chars->values[i];
-                               else
-                                       cmg_chars->values[i] = 0;
-                       }
-               }
-               break;
-       default:
-               /* No cmg-dependent data. */
-               break;
+       struct cmg_chars *cmg_chars;
+       int i, mask;
+
+       cmg_chars = chp->cmg_chars;
+       for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
+               mask = 0x80 >> (i + 3);
+               if (cmcv & mask)
+                       cmg_chars->values[i] = chars->values[i];
+               else
+                       cmg_chars->values[i] = 0;
        }
 }
 
 int chsc_get_channel_measurement_chars(struct channel_path *chp)
 {
+       struct cmg_chars *cmg_chars;
        int ccode, ret;
 
        struct {
@@ -775,13 +738,16 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                u32 data[NR_MEASUREMENT_CHARS];
        } __attribute__ ((packed)) *scmc_area;
 
-       scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!scmc_area)
+       chp->cmg_chars = NULL;
+       cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
+       if (!cmg_chars)
                return -ENOMEM;
 
+       spin_lock_irq(&chsc_page_lock);
+       memset(chsc_page, 0, PAGE_SIZE);
+       scmc_area = chsc_page;
        scmc_area->request.length = 0x0010;
        scmc_area->request.code = 0x0022;
-
        scmc_area->first_chpid = chp->chpid.id;
        scmc_area->last_chpid = chp->chpid.id;
 
@@ -792,53 +758,65 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
        }
 
        ret = chsc_error_from_response(scmc_area->response.code);
-       if (ret == 0) {
-               /* Success. */
-               if (!scmc_area->not_valid) {
-                       chp->cmg = scmc_area->cmg;
-                       chp->shared = scmc_area->shared;
-                       chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
-                                                 (struct cmg_chars *)
-                                                 &scmc_area->data);
-               } else {
-                       chp->cmg = -1;
-                       chp->shared = -1;
-               }
-       } else {
+       if (ret) {
                CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
                              scmc_area->response.code);
+               goto out;
+       }
+       if (scmc_area->not_valid) {
+               chp->cmg = -1;
+               chp->shared = -1;
+               goto out;
        }
+       chp->cmg = scmc_area->cmg;
+       chp->shared = scmc_area->shared;
+       if (chp->cmg != 2 && chp->cmg != 3) {
+               /* No cmg-dependent data. */
+               goto out;
+       }
+       chp->cmg_chars = cmg_chars;
+       chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
+                                 (struct cmg_chars *) &scmc_area->data);
 out:
-       free_page((unsigned long)scmc_area);
+       spin_unlock_irq(&chsc_page_lock);
+       if (!chp->cmg_chars)
+               kfree(cmg_chars);
+
        return ret;
 }
 
-int __init chsc_alloc_sei_area(void)
+int __init chsc_init(void)
 {
        int ret;
 
        sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!sei_page) {
-               CIO_MSG_EVENT(0, "Can't allocate page for processing of "
-                             "chsc machine checks!\n");
-               return -ENOMEM;
+       chsc_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sei_page || !chsc_page) {
+               ret = -ENOMEM;
+               goto out_err;
        }
        ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);
        if (ret)
-               kfree(sei_page);
+               goto out_err;
+       return ret;
+out_err:
+       free_page((unsigned long)chsc_page);
+       free_page((unsigned long)sei_page);
        return ret;
 }
 
-void __init chsc_free_sei_area(void)
+void __init chsc_init_cleanup(void)
 {
        crw_unregister_handler(CRW_RSC_CSS);
-       kfree(sei_page);
+       free_page((unsigned long)chsc_page);
+       free_page((unsigned long)sei_page);
 }
 
 int chsc_enable_facility(int operation_code)
 {
+       unsigned long flags;
        int ret;
-       static struct {
+       struct {
                struct chsc_header request;
                u8 reserved1:4;
                u8 format:4;
@@ -851,32 +829,33 @@ int chsc_enable_facility(int operation_code)
                u32 reserved5:4;
                u32 format2:4;
                u32 reserved6:24;
-       } __attribute__ ((packed, aligned(4096))) sda_area;
+       } __attribute__ ((packed)) *sda_area;
 
-       spin_lock(&sda_lock);
-       memset(&sda_area, 0, sizeof(sda_area));
-       sda_area.request.length = 0x0400;
-       sda_area.request.code = 0x0031;
-       sda_area.operation_code = operation_code;
+       spin_lock_irqsave(&chsc_page_lock, flags);
+       memset(chsc_page, 0, PAGE_SIZE);
+       sda_area = chsc_page;
+       sda_area->request.length = 0x0400;
+       sda_area->request.code = 0x0031;
+       sda_area->operation_code = operation_code;
 
-       ret = chsc(&sda_area);
+       ret = chsc(sda_area);
        if (ret > 0) {
                ret = (ret == 3) ? -ENODEV : -EBUSY;
                goto out;
        }
 
-       switch (sda_area.response.code) {
+       switch (sda_area->response.code) {
        case 0x0101:
                ret = -EOPNOTSUPP;
                break;
        default:
-               ret = chsc_error_from_response(sda_area.response.code);
+               ret = chsc_error_from_response(sda_area->response.code);
        }
        if (ret != 0)
                CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
-                             operation_code, sda_area.response.code);
- out:
-       spin_unlock(&sda_lock);
+                             operation_code, sda_area->response.code);
+out:
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -895,13 +874,12 @@ chsc_determine_css_characteristics(void)
                struct chsc_header response;
                u32 reserved4;
                u32 general_char[510];
-               u32 chsc_char[518];
+               u32 chsc_char[508];
        } __attribute__ ((packed)) *scsc_area;
 
-       scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!scsc_area)
-               return -ENOMEM;
-
+       spin_lock_irq(&chsc_page_lock);
+       memset(chsc_page, 0, PAGE_SIZE);
+       scsc_area = chsc_page;
        scsc_area->request.length = 0x0010;
        scsc_area->request.code = 0x0010;
 
@@ -921,7 +899,7 @@ chsc_determine_css_characteristics(void)
                CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
                              scsc_area->response.code);
 exit:
-       free_page ((unsigned long) scsc_area);
+       spin_unlock_irq(&chsc_page_lock);
        return result;
 }
 
@@ -976,29 +954,29 @@ int chsc_sstpi(void *page, void *result, size_t size)
        return (rr->response.code == 0x0001) ? 0 : -EIO;
 }
 
-static struct {
-       struct chsc_header request;
-       u32 word1;
-       struct subchannel_id sid;
-       u32 word3;
-       struct chsc_header response;
-       u32 word[11];
-} __attribute__ ((packed)) siosl_area __attribute__ ((__aligned__(PAGE_SIZE)));
-
 int chsc_siosl(struct subchannel_id schid)
 {
+       struct {
+               struct chsc_header request;
+               u32 word1;
+               struct subchannel_id sid;
+               u32 word3;
+               struct chsc_header response;
+               u32 word[11];
+       } __attribute__ ((packed)) *siosl_area;
        unsigned long flags;
        int ccode;
        int rc;
 
-       spin_lock_irqsave(&siosl_lock, flags);
-       memset(&siosl_area, 0, sizeof(siosl_area));
-       siosl_area.request.length = 0x0010;
-       siosl_area.request.code = 0x0046;
-       siosl_area.word1 = 0x80000000;
-       siosl_area.sid = schid;
+       spin_lock_irqsave(&chsc_page_lock, flags);
+       memset(chsc_page, 0, PAGE_SIZE);
+       siosl_area = chsc_page;
+       siosl_area->request.length = 0x0010;
+       siosl_area->request.code = 0x0046;
+       siosl_area->word1 = 0x80000000;
+       siosl_area->sid = schid;
 
-       ccode = chsc(&siosl_area);
+       ccode = chsc(siosl_area);
        if (ccode > 0) {
                if (ccode == 3)
                        rc = -ENODEV;
@@ -1008,17 +986,16 @@ int chsc_siosl(struct subchannel_id schid)
                              schid.ssid, schid.sch_no, ccode);
                goto out;
        }
-       rc = chsc_error_from_response(siosl_area.response.code);
+       rc = chsc_error_from_response(siosl_area->response.code);
        if (rc)
                CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n",
                              schid.ssid, schid.sch_no,
-                             siosl_area.response.code);
+                             siosl_area->response.code);
        else
                CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n",
                              schid.ssid, schid.sch_no);
 out:
-       spin_unlock_irqrestore(&siosl_lock, flags);
-
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return rc;
 }
 EXPORT_SYMBOL_GPL(chsc_siosl);
index 5453013f094b37b2106978812406e7183549742a..6693f5e3176f3657dfd6195dcc99fb12d6c1e9d4 100644 (file)
@@ -57,21 +57,39 @@ struct chsc_ssd_info {
        struct chp_id chpid[8];
        u16 fla[8];
 };
+
+struct chsc_scpd {
+       struct chsc_header request;
+       u32:2;
+       u32 m:1;
+       u32 c:1;
+       u32 fmt:4;
+       u32 cssid:8;
+       u32:4;
+       u32 rfmt:4;
+       u32 first_chpid:8;
+       u32:24;
+       u32 last_chpid:8;
+       u32 zeroes1;
+       struct chsc_header response;
+       u8 data[PAGE_SIZE - 20];
+} __attribute__ ((packed));
+
+
 extern int chsc_get_ssd_info(struct subchannel_id schid,
                             struct chsc_ssd_info *ssd);
 extern int chsc_determine_css_characteristics(void);
-extern int chsc_alloc_sei_area(void);
-extern void chsc_free_sei_area(void);
+extern int chsc_init(void);
+extern void chsc_init_cleanup(void);
 
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
-int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page);
+int __chsc_do_secm(struct channel_subsystem *css, int enable);
 
 int chsc_chp_vary(struct chp_id chpid, int on);
 int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
-                                    int c, int m,
-                                    struct chsc_response_struct *resp);
+                                    int c, int m, void *page);
 int chsc_determine_base_channel_path_desc(struct chp_id chpid,
                                          struct channel_path_desc *desc);
 void chsc_chp_online(struct chp_id chpid);
index f2b77e7bfc6f389aa11061a2c9986edfd98ff735..3c3f3ffe21794fde9ce1a4c89cd06f182b385637 100644 (file)
@@ -688,25 +688,31 @@ out_free:
 
 static int chsc_ioctl_chpd(void __user *user_chpd)
 {
+       struct chsc_scpd *scpd_area;
        struct chsc_cpd_info *chpd;
        int ret;
 
        chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
-       if (!chpd)
-               return -ENOMEM;
+       scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!scpd_area || !chpd) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
        if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
                ret = -EFAULT;
                goto out_free;
        }
        ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
                                               chpd->rfmt, chpd->c, chpd->m,
-                                              &chpd->chpdb);
+                                              scpd_area);
        if (ret)
                goto out_free;
+       memcpy(&chpd->chpdb, &scpd_area->response, scpd_area->response.length);
        if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
                ret = -EFAULT;
 out_free:
        kfree(chpd);
+       free_page((unsigned long)scpd_area);
        return ret;
 }
 
index ca8e1c240c3c29b9dd7be4cda58be76cbaa49c63..a5050e2171504043d48e9aeaa78dc4dffc9536ac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * driver for channel subsystem
  *
- * Copyright IBM Corp. 2002, 2009
+ * Copyright IBM Corp. 2002, 2010
  *
  * Author(s): Arnd Bergmann (arndb@de.ibm.com)
  *           Cornelia Huck (cornelia.huck@de.ibm.com)
@@ -577,7 +577,7 @@ static int __unset_registered(struct device *dev, void *data)
        return 0;
 }
 
-void css_schedule_eval_all_unreg(void)
+static void css_schedule_eval_all_unreg(void)
 {
        unsigned long flags;
        struct idset *unreg_set;
@@ -790,7 +790,6 @@ static struct notifier_block css_reboot_notifier = {
 static int css_power_event(struct notifier_block *this, unsigned long event,
                           void *ptr)
 {
-       void *secm_area;
        int ret, i;
 
        switch (event) {
@@ -806,15 +805,8 @@ static int css_power_event(struct notifier_block *this, unsigned long event,
                                mutex_unlock(&css->mutex);
                                continue;
                        }
-                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
-                                                           GFP_DMA);
-                       if (secm_area) {
-                               if (__chsc_do_secm(css, 0, secm_area))
-                                       ret = NOTIFY_BAD;
-                               free_page((unsigned long)secm_area);
-                       } else
+                       if (__chsc_do_secm(css, 0))
                                ret = NOTIFY_BAD;
-
                        mutex_unlock(&css->mutex);
                }
                break;
@@ -830,15 +822,8 @@ static int css_power_event(struct notifier_block *this, unsigned long event,
                                mutex_unlock(&css->mutex);
                                continue;
                        }
-                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
-                                                           GFP_DMA);
-                       if (secm_area) {
-                               if (__chsc_do_secm(css, 1, secm_area))
-                                       ret = NOTIFY_BAD;
-                               free_page((unsigned long)secm_area);
-                       } else
+                       if (__chsc_do_secm(css, 1))
                                ret = NOTIFY_BAD;
-
                        mutex_unlock(&css->mutex);
                }
                /* search for subchannels, which appeared during hibernation */
@@ -863,14 +848,11 @@ static int __init css_bus_init(void)
 {
        int ret, i;
 
-       ret = chsc_determine_css_characteristics();
-       if (ret == -ENOMEM)
-               goto out;
-
-       ret = chsc_alloc_sei_area();
+       ret = chsc_init();
        if (ret)
-               goto out;
+               return ret;
 
+       chsc_determine_css_characteristics();
        /* Try to enable MSS. */
        ret = chsc_enable_facility(CHSC_SDA_OC_MSS);
        if (ret)
@@ -956,9 +938,9 @@ out_unregister:
        }
        bus_unregister(&css_bus_type);
 out:
-       crw_unregister_handler(CRW_RSC_CSS);
-       chsc_free_sei_area();
+       crw_unregister_handler(CRW_RSC_SCH);
        idset_free(slow_subchannel_set);
+       chsc_init_cleanup();
        pr_alert("The CSS device driver initialization failed with "
                 "errno=%d\n", ret);
        return ret;
@@ -978,9 +960,9 @@ static void __init css_bus_cleanup(void)
                device_unregister(&css->device);
        }
        bus_unregister(&css_bus_type);
-       crw_unregister_handler(CRW_RSC_CSS);
-       chsc_free_sei_area();
+       crw_unregister_handler(CRW_RSC_SCH);
        idset_free(slow_subchannel_set);
+       chsc_init_cleanup();
        isc_unregister(IO_SCH_ISC);
 }
 
@@ -1048,7 +1030,16 @@ subsys_initcall_sync(channel_subsystem_init_sync);
 
 void channel_subsystem_reinit(void)
 {
+       struct channel_path *chp;
+       struct chp_id chpid;
+
        chsc_enable_facility(CHSC_SDA_OC_MSS);
+       chp_id_for_each(&chpid) {
+               chp = chpid_to_chp(chpid);
+               if (!chp)
+                       continue;
+               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+       }
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1200,6 +1191,7 @@ static int css_pm_restore(struct device *dev)
        struct subchannel *sch = to_subchannel(dev);
        struct css_driver *drv;
 
+       css_update_ssd_info(sch);
        if (!sch->dev.driver)
                return 0;
        drv = to_cssdriver(sch->dev.driver);
index 51bd3687d163fa3dfcce9454211aaa1ad654a328..2ff8a22d42574242eb0a07c1ab1d38f73cc81d6b 100644 (file)
@@ -1147,6 +1147,7 @@ err:
 static int io_subchannel_chp_event(struct subchannel *sch,
                                   struct chp_link *link, int event)
 {
+       struct ccw_device *cdev = sch_get_cdev(sch);
        int mask;
 
        mask = chp_ssd_get_mask(&sch->ssd_info, link);
@@ -1156,22 +1157,30 @@ static int io_subchannel_chp_event(struct subchannel *sch,
        case CHP_VARY_OFF:
                sch->opm &= ~mask;
                sch->lpm &= ~mask;
+               if (cdev)
+                       cdev->private->path_gone_mask |= mask;
                io_subchannel_terminate_path(sch, mask);
                break;
        case CHP_VARY_ON:
                sch->opm |= mask;
                sch->lpm |= mask;
+               if (cdev)
+                       cdev->private->path_new_mask |= mask;
                io_subchannel_verify(sch);
                break;
        case CHP_OFFLINE:
                if (cio_update_schib(sch))
                        return -ENODEV;
+               if (cdev)
+                       cdev->private->path_gone_mask |= mask;
                io_subchannel_terminate_path(sch, mask);
                break;
        case CHP_ONLINE:
                if (cio_update_schib(sch))
                        return -ENODEV;
                sch->lpm |= mask & sch->opm;
+               if (cdev)
+                       cdev->private->path_new_mask |= mask;
                io_subchannel_verify(sch);
                break;
        }
@@ -1196,6 +1205,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
                cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
        while (ret == -EBUSY) {
                cdev->private->state = DEV_STATE_QUIESCE;
+               cdev->private->iretry = 255;
                ret = ccw_device_cancel_halt_clear(cdev);
                if (ret == -EBUSY) {
                        ccw_device_set_timeout(cdev, HZ/10);
@@ -1468,9 +1478,13 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
                        goto out;
                break;
        case IO_SCH_UNREG_ATTACH:
+               if (cdev->private->flags.resuming) {
+                       /* Device will be handled later. */
+                       rc = 0;
+                       goto out;
+               }
                /* Unregister ccw device. */
-               if (!cdev->private->flags.resuming)
-                       ccw_device_unregister(cdev);
+               ccw_device_unregister(cdev);
                break;
        default:
                break;
index c9b852647f018fcba3c6e6ce682f2698d3374a11..a845695ac314dc5dd7e1c3733bacd35216a88235 100644 (file)
@@ -174,7 +174,10 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
                ret = cio_clear (sch);
                return (ret == 0) ? -EBUSY : ret;
        }
-       panic("Can't stop i/o on subchannel.\n");
+       /* Function was unsuccessful */
+       CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n",
+                     cdev->private->dev_id.ssid, cdev->private->dev_id.devno);
+       return -EIO;
 }
 
 void ccw_device_update_sense_data(struct ccw_device *cdev)
@@ -349,9 +352,13 @@ out:
 
 static void ccw_device_oper_notify(struct ccw_device *cdev)
 {
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
        if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) {
                /* Reenable channel measurements, if needed. */
                ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
+               /* Save indication for new paths. */
+               cdev->private->path_new_mask = sch->vpm;
                return;
        }
        /* Driver doesn't want device back. */
@@ -462,6 +469,32 @@ static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e)
        }
 }
 
+static void ccw_device_report_path_events(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int path_event[8];
+       int chp, mask;
+
+       for (chp = 0, mask = 0x80; chp < 8; chp++, mask >>= 1) {
+               path_event[chp] = PE_NONE;
+               if (mask & cdev->private->path_gone_mask & ~(sch->vpm))
+                       path_event[chp] |= PE_PATH_GONE;
+               if (mask & cdev->private->path_new_mask & sch->vpm)
+                       path_event[chp] |= PE_PATH_AVAILABLE;
+               if (mask & cdev->private->pgid_reset_mask & sch->vpm)
+                       path_event[chp] |= PE_PATHGROUP_ESTABLISHED;
+       }
+       if (cdev->online && cdev->drv->path_event)
+               cdev->drv->path_event(cdev, path_event);
+}
+
+static void ccw_device_reset_path_events(struct ccw_device *cdev)
+{
+       cdev->private->path_gone_mask = 0;
+       cdev->private->path_new_mask = 0;
+       cdev->private->pgid_reset_mask = 0;
+}
+
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
@@ -498,6 +531,7 @@ callback:
                                              &cdev->private->irb);
                        memset(&cdev->private->irb, 0, sizeof(struct irb));
                }
+               ccw_device_report_path_events(cdev);
                break;
        case -ETIME:
        case -EUSERS:
@@ -516,6 +550,7 @@ callback:
                ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                break;
        }
+       ccw_device_reset_path_events(cdev);
 }
 
 /*
@@ -734,13 +769,14 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        int ret;
 
        ccw_device_set_timeout(cdev, 0);
+       cdev->private->iretry = 255;
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
                cdev->private->state = DEV_STATE_TIMEOUT_KILL;
                return;
        }
-       if (ret == -ENODEV)
+       if (ret)
                dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
        else if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
@@ -837,6 +873,7 @@ void ccw_device_kill_io(struct ccw_device *cdev)
 {
        int ret;
 
+       cdev->private->iretry = 255;
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
index 82a5ad0d63f67e368736ab273e10714428d1d523..07a4fd29f0968f5e7bb485761a1b340525a9eeac 100644 (file)
@@ -213,6 +213,17 @@ static void spid_start(struct ccw_device *cdev)
        spid_do(cdev);
 }
 
+static int pgid_is_reset(struct pgid *p)
+{
+       char *c;
+
+       for (c = (char *)p + 1; c < (char *)(p + 1); c++) {
+               if (*c != 0)
+                       return 0;
+       }
+       return 1;
+}
+
 static int pgid_cmp(struct pgid *p1, struct pgid *p2)
 {
        return memcmp((char *) p1 + 1, (char *) p2 + 1,
@@ -223,7 +234,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2)
  * Determine pathgroup state from PGID data.
  */
 static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
-                        int *mismatch, int *reserved, int *reset)
+                        int *mismatch, int *reserved, u8 *reset)
 {
        struct pgid *pgid = &cdev->private->pgid[0];
        struct pgid *first = NULL;
@@ -238,9 +249,8 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
                        continue;
                if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE)
                        *reserved = 1;
-               if (pgid->inf.ps.state1 == SNID_STATE1_RESET) {
-                       /* A PGID was reset. */
-                       *reset = 1;
+               if (pgid_is_reset(pgid)) {
+                       *reset |= lpm;
                        continue;
                }
                if (!first) {
@@ -307,7 +317,7 @@ static void snid_done(struct ccw_device *cdev, int rc)
        struct pgid *pgid;
        int mismatch = 0;
        int reserved = 0;
-       int reset = 0;
+       u8 reset = 0;
        u8 donepm;
 
        if (rc)
@@ -321,11 +331,12 @@ static void snid_done(struct ccw_device *cdev, int rc)
                donepm = pgid_to_donepm(cdev);
                sch->vpm = donepm & sch->opm;
                cdev->private->pgid_todo_mask &= ~donepm;
+               cdev->private->pgid_reset_mask |= reset;
                pgid_fill(cdev, pgid);
        }
 out:
        CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
-                     "todo=%02x mism=%d rsvd=%d reset=%d\n", id->ssid,
+                     "todo=%02x mism=%d rsvd=%d reset=%02x\n", id->ssid,
                      id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm,
                      cdev->private->pgid_todo_mask, mismatch, reserved, reset);
        switch (rc) {
index 469ef93f2302128da21cb6ce6f75751c04f957d3..d024d2c21897bb1852f36db4a028ba4b55ad11b7 100644 (file)
@@ -151,8 +151,11 @@ struct ccw_device_private {
        struct subchannel_id schid;     /* subchannel number */
        struct ccw_request req;         /* internal I/O request */
        int iretry;
-       u8 pgid_valid_mask;             /* mask of valid PGIDs */
-       u8 pgid_todo_mask;              /* mask of PGIDs to be adjusted */
+       u8 pgid_valid_mask;     /* mask of valid PGIDs */
+       u8 pgid_todo_mask;      /* mask of PGIDs to be adjusted */
+       u8 pgid_reset_mask;     /* mask of PGIDs which were reset */
+       u8 path_gone_mask;      /* mask of paths, that became unavailable */
+       u8 path_new_mask;       /* mask of paths, that became available */
        struct {
                unsigned int fast:1;    /* post with "channel end" */
                unsigned int repall:1;  /* report every interrupt status */
index 91c6028d7b74016157bba24247da45cf5aac141d..8fd8c62455e94f6b8ce3ead082df2d6fd8ce43dc 100644 (file)
@@ -154,14 +154,7 @@ static inline int ap_instructions_available(void)
  */
 static int ap_interrupts_available(void)
 {
-       unsigned long long facility_bits[2];
-
-       if (stfle(facility_bits, 2) <= 1)
-               return 0;
-       if (!(facility_bits[0] & (1ULL << 61)) ||
-           !(facility_bits[1] & (1ULL << 62)))
-               return 0;
-       return 1;
+       return test_facility(1) && test_facility(2);
 }
 
 /**
index 5a46b8c5d68ae3e04b0c804cdce75eaa658f0f81..375aeeaf9ea5e9b9a97e47e6e0ee5a4ba73f78b3 100644 (file)
@@ -372,21 +372,22 @@ static void hotplug_devices(struct work_struct *dummy)
 /*
  * we emulate the request_irq behaviour on top of s390 extints
  */
-static void kvm_extint_handler(u16 code)
+static void kvm_extint_handler(unsigned int ext_int_code,
+                              unsigned int param32, unsigned long param64)
 {
        struct virtqueue *vq;
        u16 subcode;
        u32 param;
 
-       subcode = S390_lowcore.cpu_addr;
+       subcode = ext_int_code >> 16;
        if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
                return;
 
        /* The LSB might be overloaded, we have to mask it */
-       vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL);
+       vq = (struct virtqueue *)(param64 & ~1UL);
 
        /* We use ext_params to decide what this interrupt means */
-       param = S390_lowcore.ext_params & VIRTIO_PARAM_MASK;
+       param = param32 & VIRTIO_PARAM_MASK;
 
        switch (param) {
        case VIRTIO_PARAM_CONFIG_CHANGED:
index 13f48e28a1e1f3b8e4c80c73d9cfecb9eb50c077..a624f5af4320d4b5e7158d2be4032d1501eb5336 100644 (file)
@@ -461,7 +461,7 @@ static int jsflash_init(void)
 {
        int rc;
        struct jsflash *jsf;
-       int node;
+       phandle node;
        char banner[128];
        struct linux_prom_registers reg0;
 
index 58aa2154655b01385b14e63df1abf81a24d32b9d..664ceb0a158cf8213d8a9e03f064ffbff795595d 100644 (file)
@@ -181,13 +181,8 @@ struct m68k_serial {
 /* 
  * Define the number of ports supported and their irqs.
  */
-#ifndef CONFIG_68328_SERIAL_UART2
 #define NR_PORTS 1
 #define UART_IRQ_DEFNS {UART_IRQ_NUM}
-#else
-#define NR_PORTS 2
-#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM}
-#endif
 
 #endif /* __KERNEL__ */
 #endif /* !(_MC683XX_SERIAL_H) */
index 9278164843970672742c9bb63841a98a4445f962..aff9dcd051c65c6eac6adaea5b4088ebe6e74408 100644 (file)
@@ -1410,6 +1410,33 @@ config SERIAL_OF_PLATFORM
          Currently, only 8250 compatible ports are supported, but
          others can easily be added.
 
+config SERIAL_OMAP
+       tristate "OMAP serial port support"
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+       select SERIAL_CORE
+       help
+         If you have a machine based on an Texas Instruments OMAP CPU you
+         can enable its onboard serial ports by enabling this option.
+
+         By enabling this option you take advantage of dma feature available
+         with the omap-serial driver. DMA support can be enabled from platform
+         data.
+
+config SERIAL_OMAP_CONSOLE
+       bool "Console on OMAP serial port"
+       depends on SERIAL_OMAP
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this option if you would like to use omap serial port as
+         console.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyOx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
+
 config SERIAL_OF_PLATFORM_NWPSERIAL
        tristate "NWP serial port driver"
        depends on PPC_OF && PPC_DCR
index 1ca4fd599ffebb231126a917a31783a43ee29bee..c5705765454f997c6865e5d4dfaa2ec8cefdc75d 100644 (file)
@@ -88,3 +88,4 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
 obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)      += mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)   += mfd.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
index 2af8fd1131234be29fd612b207da23543c78870b..17849dcb9adc7e0e5090231192eef1778faeb8bb 100644 (file)
@@ -31,8 +31,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
 {
        struct resource resource;
        struct device_node *np = ofdev->dev.of_node;
-       const unsigned int *clk, *spd;
-       const u32 *prop;
+       const __be32 *clk, *spd;
+       const __be32 *prop;
        int ret, prop_size;
 
        memset(port, 0, sizeof *port);
@@ -55,23 +55,23 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
        /* Check for shifted address mapping */
        prop = of_get_property(np, "reg-offset", &prop_size);
        if (prop && (prop_size == sizeof(u32)))
-               port->mapbase += *prop;
+               port->mapbase += be32_to_cpup(prop);
 
        /* Check for registers offset within the devices address range */
        prop = of_get_property(np, "reg-shift", &prop_size);
        if (prop && (prop_size == sizeof(u32)))
-               port->regshift = *prop;
+               port->regshift = be32_to_cpup(prop);
 
        port->irq = irq_of_parse_and_map(np, 0);
        port->iotype = UPIO_MEM;
        port->type = type;
-       port->uartclk = *clk;
+       port->uartclk = be32_to_cpup(clk);
        port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
                | UPF_FIXED_PORT | UPF_FIXED_TYPE;
        port->dev = &ofdev->dev;
        /* If current-speed was set, then try not to change it. */
        if (spd)
-               port->custom_divisor = *clk / (16 * (*spd));
+               port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
 
        return 0;
 }
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
new file mode 100644 (file)
index 0000000..14365f7
--- /dev/null
@@ -0,0 +1,1333 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *     Govindraj R     <govindraj.raja@ti.com>
+ *     Thara Gopinath  <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Note: This driver is made seperate from 8250 driver as we cannot
+ * over load 8250 driver with omap platform specific configuration for
+ * features like DMA, it makes easier to implement features like DMA and
+ * hardware flow control and software flow control configuration with
+ * this driver as required for the omap-platform.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/omap-serial.h>
+
+static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
+
+/* Forward declaration of functions */
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
+static void serial_omap_rx_timeout(unsigned long uart_no);
+static int serial_omap_start_rxdma(struct uart_omap_port *up);
+
+static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
+{
+       offset <<= up->port.regshift;
+       return readw(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_omap_port *up, int offset, int value)
+{
+       offset <<= up->port.regshift;
+       writew(value, up->port.membase + offset);
+}
+
+static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
+{
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+/*
+ * serial_omap_get_divisor - calculate divisor value
+ * @port: uart port info
+ * @baud: baudrate for which divisor needs to be calculated.
+ *
+ * We have written our own function to get the divisor so as to support
+ * 13x mode. 3Mbps Baudrate as an different divisor.
+ * Reference OMAP TRM Chapter 17:
+ * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
+ * referring to oversampling - divisor value
+ * baudrate 460,800 to 3,686,400 all have divisor 13
+ * except 3,000,000 which has divisor value 16
+ */
+static unsigned int
+serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int divisor;
+
+       if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
+               divisor = 13;
+       else
+               divisor = 16;
+       return port->uartclk/(baud * divisor);
+}
+
+static void serial_omap_stop_rxdma(struct uart_omap_port *up)
+{
+       if (up->uart_dma.rx_dma_used) {
+               del_timer(&up->uart_dma.rx_timer);
+               omap_stop_dma(up->uart_dma.rx_dma_channel);
+               omap_free_dma(up->uart_dma.rx_dma_channel);
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_used = false;
+       }
+}
+
+static void serial_omap_enable_ms(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_omap_stop_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma &&
+               up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
+               /*
+                * Check if dma is still active. If yes do nothing,
+                * return. Else stop dma
+                */
+               if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
+                       return;
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               omap_free_dma(up->uart_dma.tx_dma_channel);
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_stop_rx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma)
+               serial_omap_stop_rxdma(up);
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_omap_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int flag;
+       unsigned char ch, lsr = *status;
+       int max_count = 256;
+
+       do {
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (lsr & UART_LSR_PE) {
+                               up->port.icount.parity++;
+                       } else if (lsr & UART_LSR_FE) {
+                               up->port.icount.frame++;
+                       }
+
+                       if (lsr & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       lsr &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               lsr |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (lsr & UART_LSR_BI)
+                               flag = TTY_BREAK;
+                       else if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ignore_char:
+               lsr = serial_in(up, UART_LSR);
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+}
+
+static void transmit_chars(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_omap_stop_tx(&up->port);
+               return;
+       }
+       count = up->port.fifosize / 4;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_omap_stop_tx(&up->port);
+}
+
+static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
+{
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_start_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       struct circ_buf *xmit;
+       unsigned int start;
+       int ret = 0;
+
+       if (!up->use_dma) {
+               serial_omap_enable_ier_thri(up);
+               return;
+       }
+
+       if (up->uart_dma.tx_dma_used)
+               return;
+
+       xmit = &up->port.state->xmit;
+
+       if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_tx,
+                               "UART Tx DMA",
+                               (void *)uart_tx_dma_callback, up,
+                               &(up->uart_dma.tx_dma_channel));
+
+               if (ret < 0) {
+                       serial_omap_enable_ier_thri(up);
+                       return;
+               }
+       }
+       spin_lock(&(up->uart_dma.tx_lock));
+       up->uart_dma.tx_dma_used = true;
+       spin_unlock(&(up->uart_dma.tx_lock));
+
+       start = up->uart_dma.tx_buf_dma_phys +
+                               (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys +
+                       UART_XMIT_SIZE) - start;
+
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static unsigned int check_modem_status(struct uart_omap_port *up)
+{
+       unsigned int status;
+
+       status = serial_in(up, UART_MSR);
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return status;
+
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.state != NULL) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change
+                               (&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change
+                               (&up->port, status & UART_MSR_CTS);
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       return status;
+}
+
+/**
+ * serial_omap_irq() - This handles the interrupt from one port
+ * @irq: uart port irq number
+ * @dev_id: uart port info
+ */
+static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+{
+       struct uart_omap_port *up = dev_id;
+       unsigned int iir, lsr;
+       unsigned long flags;
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       if (iir & UART_IIR_RLSI) {
+               if (!up->use_dma) {
+                       if (lsr & UART_LSR_DR)
+                               receive_chars(up, &lsr);
+               } else {
+                       up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+                       if ((serial_omap_start_rxdma(up) != 0) &&
+                                       (lsr & UART_LSR_DR))
+                               receive_chars(up, &lsr);
+               }
+       }
+
+       check_modem_status(up);
+       if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       up->port_activity = jiffies;
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_omap_tx_empty(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       unsigned int ret = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_omap_get_mctrl(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char status;
+       unsigned int ret = 0;
+
+       status = check_modem_status(up);
+       dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
+
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char mcr = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_omap_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial_omap_startup(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
+                               up->name, up);
+       if (retval)
+               return retval;
+
+       dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_omap_clear_fifos(up);
+       /* For Hardware flow control */
+       serial_out(up, UART_MCR, UART_MCR_RTS);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_in(up, UART_LSR);
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+       spin_lock_irqsave(&up->port.lock, flags);
+       /*
+        * Most PC uarts need OUT2 raised to enable interrupts.
+        */
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       up->msr_saved_flags = 0;
+       if (up->use_dma) {
+               free_page((unsigned long)up->port.state->xmit.buf);
+               up->port.state->xmit.buf = dma_alloc_coherent(NULL,
+                       UART_XMIT_SIZE,
+                       (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+                       0);
+               init_timer(&(up->uart_dma.rx_timer));
+               up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+               up->uart_dma.rx_timer.data = up->pdev->id;
+               /* Currently the buffer size is 4KB. Can increase it */
+               up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
+                       up->uart_dma.rx_buf_size,
+                       (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
+       }
+       /*
+        * Finally, enable interrupts. Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_out(up, UART_IER, up->ier);
+
+       up->port_activity = jiffies;
+       return 0;
+}
+
+static void serial_omap_shutdown(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_omap_clear_fifos(up);
+
+       /*
+        * Read data port to reset things, and then free the irq
+        */
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       if (up->use_dma) {
+               dma_free_coherent(up->port.dev,
+                       UART_XMIT_SIZE, up->port.state->xmit.buf,
+                       up->uart_dma.tx_buf_dma_phys);
+               up->port.state->xmit.buf = NULL;
+               serial_omap_stop_rx(port);
+               dma_free_coherent(up->port.dev,
+                       up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
+                       up->uart_dma.rx_buf_dma_phys);
+               up->uart_dma.rx_buf = NULL;
+       }
+       free_irq(up->port.irq, up);
+}
+
+static inline void
+serial_omap_configure_xonxoff
+               (struct uart_omap_port *up, struct ktermios *termios)
+{
+       unsigned char efr = 0;
+
+       up->lcr = serial_in(up, UART_LCR);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+       serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+       serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+       /* clear SW control mode bits */
+       efr = up->efr;
+       efr &= OMAP_UART_SW_CLR;
+
+       /*
+        * IXON Flag:
+        * Enable XON/XOFF flow control on output.
+        * Transmit XON1, XOFF1
+        */
+       if (termios->c_iflag & IXON)
+               efr |= OMAP_UART_SW_TX;
+
+       /*
+        * IXOFF Flag:
+        * Enable XON/XOFF flow control on input.
+        * Receiver compares XON1, XOFF1.
+        */
+       if (termios->c_iflag & IXOFF)
+               efr |= OMAP_UART_SW_RX;
+
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+       up->mcr = serial_in(up, UART_MCR);
+
+       /*
+        * IXANY Flag:
+        * Enable any character to restart output.
+        * Operation resumes after receiving any
+        * character after recognition of the XOFF character
+        */
+       if (termios->c_iflag & IXANY)
+               up->mcr |= UART_MCR_XONANY;
+
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+       serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+       /* Enable special char function UARTi.EFR_REG[5] and
+        * load the new software flow control mode IXON or IXOFF
+        * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+        */
+       serial_out(up, UART_EFR, efr | UART_EFR_SCD);
+       serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+       serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, up->lcr);
+}
+
+static void
+serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
+                       struct ktermios *old)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char cval = 0;
+       unsigned char efr = 0;
+       unsigned long flags = 0;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
+       quot = serial_omap_get_divisor(port, baud);
+
+       up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
+                       UART_FCR_ENABLE_FIFO;
+       if (up->use_dma)
+               up->fcr |= UART_FCR_DMA_SELECT;
+
+       /*
+        * Ok, we're now changing the port state. Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * Modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, cval);         /* reset DLAB */
+
+       /* FIFOs and DMA Settings */
+
+       /* FCR can be changed only when the
+        * baud clock is not running
+        * DLL_REG and DLH_REG set to 0.
+        */
+       serial_out(up, UART_LCR, UART_LCR_DLAB);
+       serial_out(up, UART_DLL, 0);
+       serial_out(up, UART_DLM, 0);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, UART_LCR_DLAB);
+       up->mcr = serial_in(up, UART_MCR);
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       /* FIFO ENABLE, DMA MODE */
+       serial_out(up, UART_FCR, up->fcr);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+       if (up->use_dma) {
+               serial_out(up, UART_TI752_TLR, 0);
+               serial_out(up, UART_OMAP_SCR,
+                       (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
+       }
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, UART_LCR_DLAB);
+       serial_out(up, UART_MCR, up->mcr);
+
+       /* Protocol, Baud Rate, and Interrupt Settings */
+
+       serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, 0);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, cval);
+
+       if (baud > 230400 && baud != 3000000)
+               serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
+       else
+               serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
+
+       /* Hardware Flow Control Configuration */
+
+       if (termios->c_cflag & CRTSCTS) {
+               efr |= (UART_EFR_CTS | UART_EFR_RTS);
+               serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+               up->mcr = serial_in(up, UART_MCR);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+               serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+               up->efr = serial_in(up, UART_EFR);
+               serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+               serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+               serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+               serial_out(up, UART_LCR, UART_LCR_DLAB);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+               serial_out(up, UART_LCR, cval);
+       }
+
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       /* Software Flow Control Configuration */
+       if (termios->c_iflag & (IXON | IXOFF))
+               serial_omap_configure_xonxoff(up, termios);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
+}
+
+static void
+serial_omap_pm(struct uart_port *port, unsigned int state,
+              unsigned int oldstate)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char efr;
+
+       dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+       efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
+       serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+       serial_out(up, UART_EFR, efr);
+       serial_out(up, UART_LCR, 0);
+       /* Enable module level wake up */
+       serial_out(up, UART_OMAP_WER,
+               (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
+}
+
+static void serial_omap_release_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_release_port+\n");
+}
+
+static int serial_omap_request_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_request_port+\n");
+       return 0;
+}
+
+static void serial_omap_config_port(struct uart_port *port, int flags)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
+                                                       up->pdev->id);
+       up->port.type = PORT_OMAP;
+}
+
+static int
+serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       dev_dbg(port->dev, "serial_omap_verify_port+\n");
+       return -EINVAL;
+}
+
+static const char *
+serial_omap_type(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
+       return up->name;
+}
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void wait_for_xmitr(struct uart_omap_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
+
+                       udelay(1);
+               }
+       }
+}
+
+static void serial_omap_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+static void
+serial_omap_console_write(struct console *co, const char *s,
+               unsigned int count)
+{
+       struct uart_omap_port *up = serial_omap_console_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock(&up->port.lock);
+       else
+               spin_lock(&up->port.lock);
+
+       /*
+        * First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial_omap_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+       /*
+        * The receive handling will happen properly because the
+        * receive ready bit will still be set; it is not cleared
+        * on read.  However, modem control will not, we must
+        * call it if we have saved something in the saved flags
+        * while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init
+serial_omap_console_setup(struct console *co, char *options)
+{
+       struct uart_omap_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (serial_omap_console_ports[co->index] == NULL)
+               return -ENODEV;
+       up = serial_omap_console_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_omap_console = {
+       .name           = OMAP_SERIAL_NAME,
+       .write          = serial_omap_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_omap_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_omap_reg,
+};
+
+static void serial_omap_add_console_port(struct uart_omap_port *up)
+{
+       serial_omap_console_ports[up->pdev->id] = up;
+}
+
+#define OMAP_CONSOLE   (&serial_omap_console)
+
+#else
+
+#define OMAP_CONSOLE   NULL
+
+static inline void serial_omap_add_console_port(struct uart_omap_port *up)
+{}
+
+#endif
+
+static struct uart_ops serial_omap_pops = {
+       .tx_empty       = serial_omap_tx_empty,
+       .set_mctrl      = serial_omap_set_mctrl,
+       .get_mctrl      = serial_omap_get_mctrl,
+       .stop_tx        = serial_omap_stop_tx,
+       .start_tx       = serial_omap_start_tx,
+       .stop_rx        = serial_omap_stop_rx,
+       .enable_ms      = serial_omap_enable_ms,
+       .break_ctl      = serial_omap_break_ctl,
+       .startup        = serial_omap_startup,
+       .shutdown       = serial_omap_shutdown,
+       .set_termios    = serial_omap_set_termios,
+       .pm             = serial_omap_pm,
+       .type           = serial_omap_type,
+       .release_port   = serial_omap_release_port,
+       .request_port   = serial_omap_request_port,
+       .config_port    = serial_omap_config_port,
+       .verify_port    = serial_omap_verify_port,
+};
+
+static struct uart_driver serial_omap_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "OMAP-SERIAL",
+       .dev_name       = OMAP_SERIAL_NAME,
+       .nr             = OMAP_MAX_HSUART_PORTS,
+       .cons           = OMAP_CONSOLE,
+};
+
+static int
+serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct uart_omap_port *up = platform_get_drvdata(pdev);
+
+       if (up)
+               uart_suspend_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static int serial_omap_resume(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       if (up)
+               uart_resume_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static void serial_omap_rx_timeout(unsigned long uart_no)
+{
+       struct uart_omap_port *up = ui[uart_no];
+       unsigned int curr_dma_pos, curr_transmitted_size;
+       int ret = 0;
+
+       curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
+       if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+                            (curr_dma_pos == 0)) {
+               if (jiffies_to_msecs(jiffies - up->port_activity) <
+                                                       RX_TIMEOUT) {
+                       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+               } else {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+               return;
+       }
+
+       curr_transmitted_size = curr_dma_pos -
+                                       up->uart_dma.prev_rx_dma_pos;
+       up->port.icount.rx += curr_transmitted_size;
+       tty_insert_flip_string(up->port.state->port.tty,
+                       up->uart_dma.rx_buf +
+                       (up->uart_dma.prev_rx_dma_pos -
+                       up->uart_dma.rx_buf_dma_phys),
+                       curr_transmitted_size);
+       tty_flip_buffer_push(up->port.state->port.tty);
+       up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
+       if (up->uart_dma.rx_buf_size +
+                       up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+               ret = serial_omap_start_rxdma(up);
+               if (ret < 0) {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+       } else  {
+               mod_timer(&up->uart_dma.rx_timer, jiffies +
+                       usecs_to_jiffies(up->uart_dma.rx_timeout));
+       }
+       up->port_activity = jiffies;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       return;
+}
+
+static int serial_omap_start_rxdma(struct uart_omap_port *up)
+{
+       int ret = 0;
+
+       if (up->uart_dma.rx_dma_channel == -1) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_rx,
+                               "UART Rx DMA",
+                               (void *)uart_rx_dma_callback, up,
+                               &(up->uart_dma.rx_dma_channel));
+               if (ret < 0)
+                       return ret;
+
+               omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+               omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC,
+                               up->uart_dma.rx_buf_dma_phys, 0, 0);
+               omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.rx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_rx, 0);
+       }
+       up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.rx_dma_channel);
+       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+       up->uart_dma.rx_dma_used = true;
+       return ret;
+}
+
+static void serial_omap_continue_tx(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       unsigned int start = up->uart_dma.tx_buf_dma_phys
+                       + (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       if (uart_circ_empty(xmit))
+               return;
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)data;
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+                       (UART_XMIT_SIZE - 1);
+       up->port.icount.tx += up->uart_dma.tx_buf_size;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&(up->uart_dma.tx_lock));
+               serial_omap_stop_tx(&up->port);
+               up->uart_dma.tx_dma_used = false;
+               spin_unlock(&(up->uart_dma.tx_lock));
+       } else {
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               serial_omap_continue_tx(up);
+       }
+       up->port_activity = jiffies;
+       return;
+}
+
+static int serial_omap_probe(struct platform_device *pdev)
+{
+       struct uart_omap_port   *up;
+       struct resource         *mem, *irq, *dma_tx, *dma_rx;
+       struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+       int ret = -ENOSPC;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                                    pdev->dev.driver->name)) {
+               dev_err(&pdev->dev, "memory region already claimed\n");
+               return -EBUSY;
+       }
+
+       dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+       if (!dma_rx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+       if (!dma_tx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       up = kzalloc(sizeof(*up), GFP_KERNEL);
+       if (up == NULL) {
+               ret = -ENOMEM;
+               goto do_release_region;
+       }
+       sprintf(up->name, "OMAP UART%d", pdev->id);
+       up->pdev = pdev;
+       up->port.dev = &pdev->dev;
+       up->port.type = PORT_OMAP;
+       up->port.iotype = UPIO_MEM;
+       up->port.irq = irq->start;
+
+       up->port.regshift = 2;
+       up->port.fifosize = 64;
+       up->port.ops = &serial_omap_pops;
+       up->port.line = pdev->id;
+
+       up->port.membase = omap_up_info->membase;
+       up->port.mapbase = omap_up_info->mapbase;
+       up->port.flags = omap_up_info->flags;
+       up->port.irqflags = omap_up_info->irqflags;
+       up->port.uartclk = omap_up_info->uartclk;
+       up->uart_dma.uart_base = mem->start;
+
+       if (omap_up_info->dma_enabled) {
+               up->uart_dma.uart_dma_tx = dma_tx->start;
+               up->uart_dma.uart_dma_rx = dma_rx->start;
+               up->use_dma = 1;
+               up->uart_dma.rx_buf_size = 4096;
+               up->uart_dma.rx_timeout = 2;
+               spin_lock_init(&(up->uart_dma.tx_lock));
+               spin_lock_init(&(up->uart_dma.rx_lock));
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       ui[pdev->id] = up;
+       serial_omap_add_console_port(up);
+
+       ret = uart_add_one_port(&serial_omap_reg, &up->port);
+       if (ret != 0)
+               goto do_release_region;
+
+       platform_set_drvdata(pdev, up);
+       return 0;
+err:
+       dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
+                               pdev->id, __func__, ret);
+do_release_region:
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       return ret;
+}
+
+static int serial_omap_remove(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       platform_set_drvdata(dev, NULL);
+       if (up) {
+               uart_remove_one_port(&serial_omap_reg, &up->port);
+               kfree(up);
+       }
+       return 0;
+}
+
+static struct platform_driver serial_omap_driver = {
+       .probe          = serial_omap_probe,
+       .remove         = serial_omap_remove,
+
+       .suspend        = serial_omap_suspend,
+       .resume         = serial_omap_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init serial_omap_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&serial_omap_reg);
+       if (ret != 0)
+               return ret;
+       ret = platform_driver_register(&serial_omap_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_omap_reg);
+       return ret;
+}
+
+static void __exit serial_omap_exit(void)
+{
+       platform_driver_unregister(&serial_omap_driver);
+       uart_unregister_driver(&serial_omap_reg);
+}
+
+module_init(serial_omap_init);
+module_exit(serial_omap_exit);
+
+MODULE_DESCRIPTION("OMAP High Speed UART driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
index 9b52f77a93057af3aa7ba8e69d002190f1b4aaab..d2352ac437c58db944b0848d1fcc8dde10da0ce7 100644 (file)
 # define SCSPTR0       0xffe00024      /* 16 bit SCIF */
 # define SCSPTR1       0xffe10024      /* 16 bit SCIF */
 # define SCIF_ORER     0x0001          /* Overrun error bit */
-# define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+
+#if defined(CONFIG_SH_SH2007)
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
+# define SCSCR_INIT(port)      0x38
+#else
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
+# define SCSCR_INIT(port)      0x3a
+#endif
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
       defined(CONFIG_CPU_SUBTYPE_SH7786)
 # define SCSPTR0       0xffea0024      /* 16 bit SCIF */
@@ -616,9 +624,10 @@ static inline int sci_rxd_in(struct uart_port *port)
  * -- Mitch Davis - 15 Jul 2000
  */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
+#if (defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
+     defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
+    !defined(CONFIG_SH_SH2007)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
       defined(CONFIG_CPU_SUBTYPE_SH7720) || \
index a54de0b9b3dfe3f40c56c983d2ca64ce75cc4335..f168a6159961f621631a7af9a78d0099be61cbc3 100644 (file)
@@ -1,24 +1,5 @@
-config INTC_USERIMASK
-       bool "Userspace interrupt masking support"
-       depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
-       help
-         This enables support for hardware-assisted userspace hardirq
-         masking.
+menu "SuperH / SH-Mobile Driver Options"
 
-         SH-4A and newer interrupt blocks all support a special shadowed
-         page with all non-masking registers obscured when mapped in to
-         userspace. This is primarily for use by userspace device
-         drivers that are using special priority levels.
+source "drivers/sh/intc/Kconfig"
 
-         If in doubt, say N.
-
-config INTC_BALANCING
-       bool "Hardware IRQ balancing support"
-       depends on SMP && SUPERH && CPU_SUBTYPE_SH7786
-       help
-         This enables support for IRQ auto-distribution mode on SH-X3
-         SMP parts. All of the balancing and CPU wakeup decisions are
-         taken care of automatically by hardware for distributed
-         vectors.
-
-         If in doubt, say N.
+endmenu
index 08fc653a825caf66894f52296018619d2a762dbd..24e6cec0ae8dfb51efbb704f6e37d0228ddcc3fe 100644 (file)
@@ -1,10 +1,9 @@
 #
 # Makefile for the SuperH specific drivers.
 #
-obj-y  := clk.o intc.o
+obj-y  := intc/
 
-obj-$(CONFIG_SUPERHYWAY)       += superhyway/
+obj-$(CONFIG_HAVE_CLK)         += clk/
 obj-$(CONFIG_MAPLE)            += maple/
-
+obj-$(CONFIG_SUPERHYWAY)       += superhyway/
 obj-$(CONFIG_GENERIC_GPIO)     += pfc.o
-obj-$(CONFIG_SH_CLK_CPG)       += clk-cpg.o
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk-cpg.c
deleted file mode 100644 (file)
index 8c024b9..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-#include <linux/clk.h>
-#include <linux/compiler.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/sh_clk.h>
-
-static int sh_clk_mstp32_enable(struct clk *clk)
-{
-       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
-                    clk->enable_reg);
-       return 0;
-}
-
-static void sh_clk_mstp32_disable(struct clk *clk)
-{
-       __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
-                    clk->enable_reg);
-}
-
-static struct clk_ops sh_clk_mstp32_clk_ops = {
-       .enable         = sh_clk_mstp32_enable,
-       .disable        = sh_clk_mstp32_disable,
-       .recalc         = followparent_recalc,
-};
-
-int __init sh_clk_mstp32_register(struct clk *clks, int nr)
-{
-       struct clk *clkp;
-       int ret = 0;
-       int k;
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-               clkp->ops = &sh_clk_mstp32_clk_ops;
-               ret |= clk_register(clkp);
-       }
-
-       return ret;
-}
-
-static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
-{
-       return clk_rate_table_round(clk, clk->freq_table, rate);
-}
-
-static int sh_clk_div6_divisors[64] = {
-       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
-       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
-       49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
-};
-
-static struct clk_div_mult_table sh_clk_div6_table = {
-       .divisors = sh_clk_div6_divisors,
-       .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
-};
-
-static unsigned long sh_clk_div6_recalc(struct clk *clk)
-{
-       struct clk_div_mult_table *table = &sh_clk_div6_table;
-       unsigned int idx;
-
-       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-                            table, NULL);
-
-       idx = __raw_readl(clk->enable_reg) & 0x003f;
-
-       return clk->freq_table[idx].frequency;
-}
-
-static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
-{
-       struct clk_div_mult_table *table = &sh_clk_div6_table;
-       u32 value;
-       int ret, i;
-
-       if (!clk->parent_table || !clk->parent_num)
-               return -EINVAL;
-
-       /* Search the parent */
-       for (i = 0; i < clk->parent_num; i++)
-               if (clk->parent_table[i] == parent)
-                       break;
-
-       if (i == clk->parent_num)
-               return -ENODEV;
-
-       ret = clk_reparent(clk, parent);
-       if (ret < 0)
-               return ret;
-
-       value = __raw_readl(clk->enable_reg) &
-               ~(((1 << clk->src_width) - 1) << clk->src_shift);
-
-       __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
-
-       /* Rebuild the frequency table */
-       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-                            table, &clk->arch_flags);
-
-       return 0;
-}
-
-static int sh_clk_div6_set_rate(struct clk *clk,
-                               unsigned long rate, int algo_id)
-{
-       unsigned long value;
-       int idx;
-
-       idx = clk_rate_table_find(clk, clk->freq_table, rate);
-       if (idx < 0)
-               return idx;
-
-       value = __raw_readl(clk->enable_reg);
-       value &= ~0x3f;
-       value |= idx;
-       __raw_writel(value, clk->enable_reg);
-       return 0;
-}
-
-static int sh_clk_div6_enable(struct clk *clk)
-{
-       unsigned long value;
-       int ret;
-
-       ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
-       if (ret == 0) {
-               value = __raw_readl(clk->enable_reg);
-               value &= ~0x100; /* clear stop bit to enable clock */
-               __raw_writel(value, clk->enable_reg);
-       }
-       return ret;
-}
-
-static void sh_clk_div6_disable(struct clk *clk)
-{
-       unsigned long value;
-
-       value = __raw_readl(clk->enable_reg);
-       value |= 0x100; /* stop clock */
-       value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
-       __raw_writel(value, clk->enable_reg);
-}
-
-static struct clk_ops sh_clk_div6_clk_ops = {
-       .recalc         = sh_clk_div6_recalc,
-       .round_rate     = sh_clk_div_round_rate,
-       .set_rate       = sh_clk_div6_set_rate,
-       .enable         = sh_clk_div6_enable,
-       .disable        = sh_clk_div6_disable,
-};
-
-static struct clk_ops sh_clk_div6_reparent_clk_ops = {
-       .recalc         = sh_clk_div6_recalc,
-       .round_rate     = sh_clk_div_round_rate,
-       .set_rate       = sh_clk_div6_set_rate,
-       .enable         = sh_clk_div6_enable,
-       .disable        = sh_clk_div6_disable,
-       .set_parent     = sh_clk_div6_set_parent,
-};
-
-static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
-                                          struct clk_ops *ops)
-{
-       struct clk *clkp;
-       void *freq_table;
-       int nr_divs = sh_clk_div6_table.nr_divisors;
-       int freq_table_size = sizeof(struct cpufreq_frequency_table);
-       int ret = 0;
-       int k;
-
-       freq_table_size *= (nr_divs + 1);
-       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
-       if (!freq_table) {
-               pr_err("sh_clk_div6_register: unable to alloc memory\n");
-               return -ENOMEM;
-       }
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-
-               clkp->ops = ops;
-               clkp->id = -1;
-               clkp->freq_table = freq_table + (k * freq_table_size);
-               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
-
-               ret = clk_register(clkp);
-       }
-
-       return ret;
-}
-
-int __init sh_clk_div6_register(struct clk *clks, int nr)
-{
-       return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
-}
-
-int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
-{
-       return sh_clk_div6_register_ops(clks, nr,
-                                       &sh_clk_div6_reparent_clk_ops);
-}
-
-static unsigned long sh_clk_div4_recalc(struct clk *clk)
-{
-       struct clk_div4_table *d4t = clk->priv;
-       struct clk_div_mult_table *table = d4t->div_mult_table;
-       unsigned int idx;
-
-       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-                            table, &clk->arch_flags);
-
-       idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
-
-       return clk->freq_table[idx].frequency;
-}
-
-static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
-{
-       struct clk_div4_table *d4t = clk->priv;
-       struct clk_div_mult_table *table = d4t->div_mult_table;
-       u32 value;
-       int ret;
-
-       /* we really need a better way to determine parent index, but for
-        * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
-        * no CLK_ENABLE_ON_INIT means external clock...
-        */
-
-       if (parent->flags & CLK_ENABLE_ON_INIT)
-               value = __raw_readl(clk->enable_reg) & ~(1 << 7);
-       else
-               value = __raw_readl(clk->enable_reg) | (1 << 7);
-
-       ret = clk_reparent(clk, parent);
-       if (ret < 0)
-               return ret;
-
-       __raw_writel(value, clk->enable_reg);
-
-       /* Rebiuld the frequency table */
-       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
-                            table, &clk->arch_flags);
-
-       return 0;
-}
-
-static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
-{
-       struct clk_div4_table *d4t = clk->priv;
-       unsigned long value;
-       int idx = clk_rate_table_find(clk, clk->freq_table, rate);
-       if (idx < 0)
-               return idx;
-
-       value = __raw_readl(clk->enable_reg);
-       value &= ~(0xf << clk->enable_bit);
-       value |= (idx << clk->enable_bit);
-       __raw_writel(value, clk->enable_reg);
-
-       if (d4t->kick)
-               d4t->kick(clk);
-
-       return 0;
-}
-
-static int sh_clk_div4_enable(struct clk *clk)
-{
-       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
-       return 0;
-}
-
-static void sh_clk_div4_disable(struct clk *clk)
-{
-       __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
-}
-
-static struct clk_ops sh_clk_div4_clk_ops = {
-       .recalc         = sh_clk_div4_recalc,
-       .set_rate       = sh_clk_div4_set_rate,
-       .round_rate     = sh_clk_div_round_rate,
-};
-
-static struct clk_ops sh_clk_div4_enable_clk_ops = {
-       .recalc         = sh_clk_div4_recalc,
-       .set_rate       = sh_clk_div4_set_rate,
-       .round_rate     = sh_clk_div_round_rate,
-       .enable         = sh_clk_div4_enable,
-       .disable        = sh_clk_div4_disable,
-};
-
-static struct clk_ops sh_clk_div4_reparent_clk_ops = {
-       .recalc         = sh_clk_div4_recalc,
-       .set_rate       = sh_clk_div4_set_rate,
-       .round_rate     = sh_clk_div_round_rate,
-       .enable         = sh_clk_div4_enable,
-       .disable        = sh_clk_div4_disable,
-       .set_parent     = sh_clk_div4_set_parent,
-};
-
-static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
-                       struct clk_div4_table *table, struct clk_ops *ops)
-{
-       struct clk *clkp;
-       void *freq_table;
-       int nr_divs = table->div_mult_table->nr_divisors;
-       int freq_table_size = sizeof(struct cpufreq_frequency_table);
-       int ret = 0;
-       int k;
-
-       freq_table_size *= (nr_divs + 1);
-       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
-       if (!freq_table) {
-               pr_err("sh_clk_div4_register: unable to alloc memory\n");
-               return -ENOMEM;
-       }
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-
-               clkp->ops = ops;
-               clkp->id = -1;
-               clkp->priv = table;
-
-               clkp->freq_table = freq_table + (k * freq_table_size);
-               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
-
-               ret = clk_register(clkp);
-       }
-
-       return ret;
-}
-
-int __init sh_clk_div4_register(struct clk *clks, int nr,
-                               struct clk_div4_table *table)
-{
-       return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
-}
-
-int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
-                               struct clk_div4_table *table)
-{
-       return sh_clk_div4_register_ops(clks, nr, table,
-                                       &sh_clk_div4_enable_clk_ops);
-}
-
-int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
-                               struct clk_div4_table *table)
-{
-       return sh_clk_div4_register_ops(clks, nr, table,
-                                       &sh_clk_div4_reparent_clk_ops);
-}
diff --git a/drivers/sh/clk.c b/drivers/sh/clk.c
deleted file mode 100644 (file)
index 5d84ada..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * drivers/sh/clk.c - SuperH clock framework
- *
- *  Copyright (C) 2005 - 2009  Paul Mundt
- *
- * This clock framework is derived from the OMAP version by:
- *
- *     Copyright (C) 2004 - 2008 Nokia Corporation
- *     Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
- *
- *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/kobject.h>
-#include <linux/sysdev.h>
-#include <linux/seq_file.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-#include <linux/cpufreq.h>
-#include <linux/clk.h>
-#include <linux/sh_clk.h>
-
-static LIST_HEAD(clock_list);
-static DEFINE_SPINLOCK(clock_lock);
-static DEFINE_MUTEX(clock_list_sem);
-
-void clk_rate_table_build(struct clk *clk,
-                         struct cpufreq_frequency_table *freq_table,
-                         int nr_freqs,
-                         struct clk_div_mult_table *src_table,
-                         unsigned long *bitmap)
-{
-       unsigned long mult, div;
-       unsigned long freq;
-       int i;
-
-       for (i = 0; i < nr_freqs; i++) {
-               div = 1;
-               mult = 1;
-
-               if (src_table->divisors && i < src_table->nr_divisors)
-                       div = src_table->divisors[i];
-
-               if (src_table->multipliers && i < src_table->nr_multipliers)
-                       mult = src_table->multipliers[i];
-
-               if (!div || !mult || (bitmap && !test_bit(i, bitmap)))
-                       freq = CPUFREQ_ENTRY_INVALID;
-               else
-                       freq = clk->parent->rate * mult / div;
-
-               freq_table[i].index = i;
-               freq_table[i].frequency = freq;
-       }
-
-       /* Termination entry */
-       freq_table[i].index = i;
-       freq_table[i].frequency = CPUFREQ_TABLE_END;
-}
-
-long clk_rate_table_round(struct clk *clk,
-                         struct cpufreq_frequency_table *freq_table,
-                         unsigned long rate)
-{
-       unsigned long rate_error, rate_error_prev = ~0UL;
-       unsigned long rate_best_fit = rate;
-       unsigned long highest, lowest;
-       int i;
-
-       highest = lowest = 0;
-
-       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               unsigned long freq = freq_table[i].frequency;
-
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
-               if (freq > highest)
-                       highest = freq;
-               if (freq < lowest)
-                       lowest = freq;
-
-               rate_error = abs(freq - rate);
-               if (rate_error < rate_error_prev) {
-                       rate_best_fit = freq;
-                       rate_error_prev = rate_error;
-               }
-
-               if (rate_error == 0)
-                       break;
-       }
-
-       if (rate >= highest)
-               rate_best_fit = highest;
-       if (rate <= lowest)
-               rate_best_fit = lowest;
-
-       return rate_best_fit;
-}
-
-int clk_rate_table_find(struct clk *clk,
-                       struct cpufreq_frequency_table *freq_table,
-                       unsigned long rate)
-{
-       int i;
-
-       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               unsigned long freq = freq_table[i].frequency;
-
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
-               if (freq == rate)
-                       return i;
-       }
-
-       return -ENOENT;
-}
-
-/* Used for clocks that always have same value as the parent clock */
-unsigned long followparent_recalc(struct clk *clk)
-{
-       return clk->parent ? clk->parent->rate : 0;
-}
-
-int clk_reparent(struct clk *child, struct clk *parent)
-{
-       list_del_init(&child->sibling);
-       if (parent)
-               list_add(&child->sibling, &parent->children);
-       child->parent = parent;
-
-       /* now do the debugfs renaming to reattach the child
-          to the proper parent */
-
-       return 0;
-}
-
-/* Propagate rate to children */
-void propagate_rate(struct clk *tclk)
-{
-       struct clk *clkp;
-
-       list_for_each_entry(clkp, &tclk->children, sibling) {
-               if (clkp->ops && clkp->ops->recalc)
-                       clkp->rate = clkp->ops->recalc(clkp);
-
-               propagate_rate(clkp);
-       }
-}
-
-static void __clk_disable(struct clk *clk)
-{
-       if (WARN(!clk->usecount, "Trying to disable clock %s with 0 usecount\n",
-                clk->name))
-               return;
-
-       if (!(--clk->usecount)) {
-               if (likely(clk->ops && clk->ops->disable))
-                       clk->ops->disable(clk);
-               if (likely(clk->parent))
-                       __clk_disable(clk->parent);
-       }
-}
-
-void clk_disable(struct clk *clk)
-{
-       unsigned long flags;
-
-       if (!clk)
-               return;
-
-       spin_lock_irqsave(&clock_lock, flags);
-       __clk_disable(clk);
-       spin_unlock_irqrestore(&clock_lock, flags);
-}
-EXPORT_SYMBOL_GPL(clk_disable);
-
-static int __clk_enable(struct clk *clk)
-{
-       int ret = 0;
-
-       if (clk->usecount++ == 0) {
-               if (clk->parent) {
-                       ret = __clk_enable(clk->parent);
-                       if (unlikely(ret))
-                               goto err;
-               }
-
-               if (clk->ops && clk->ops->enable) {
-                       ret = clk->ops->enable(clk);
-                       if (ret) {
-                               if (clk->parent)
-                                       __clk_disable(clk->parent);
-                               goto err;
-                       }
-               }
-       }
-
-       return ret;
-err:
-       clk->usecount--;
-       return ret;
-}
-
-int clk_enable(struct clk *clk)
-{
-       unsigned long flags;
-       int ret;
-
-       if (!clk)
-               return -EINVAL;
-
-       spin_lock_irqsave(&clock_lock, flags);
-       ret = __clk_enable(clk);
-       spin_unlock_irqrestore(&clock_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(clk_enable);
-
-static LIST_HEAD(root_clks);
-
-/**
- * recalculate_root_clocks - recalculate and propagate all root clocks
- *
- * Recalculates all root clocks (clocks with no parent), which if the
- * clock's .recalc is set correctly, should also propagate their rates.
- * Called at init.
- */
-void recalculate_root_clocks(void)
-{
-       struct clk *clkp;
-
-       list_for_each_entry(clkp, &root_clks, sibling) {
-               if (clkp->ops && clkp->ops->recalc)
-                       clkp->rate = clkp->ops->recalc(clkp);
-               propagate_rate(clkp);
-       }
-}
-
-int clk_register(struct clk *clk)
-{
-       if (clk == NULL || IS_ERR(clk))
-               return -EINVAL;
-
-       /*
-        * trap out already registered clocks
-        */
-       if (clk->node.next || clk->node.prev)
-               return 0;
-
-       mutex_lock(&clock_list_sem);
-
-       INIT_LIST_HEAD(&clk->children);
-       clk->usecount = 0;
-
-       if (clk->parent)
-               list_add(&clk->sibling, &clk->parent->children);
-       else
-               list_add(&clk->sibling, &root_clks);
-
-       list_add(&clk->node, &clock_list);
-       if (clk->ops && clk->ops->init)
-               clk->ops->init(clk);
-       mutex_unlock(&clock_list_sem);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clock_list_sem);
-       list_del(&clk->sibling);
-       list_del(&clk->node);
-       mutex_unlock(&clock_list_sem);
-}
-EXPORT_SYMBOL_GPL(clk_unregister);
-
-void clk_enable_init_clocks(void)
-{
-       struct clk *clkp;
-
-       list_for_each_entry(clkp, &clock_list, node)
-               if (clkp->flags & CLK_ENABLE_ON_INIT)
-                       clk_enable(clkp);
-}
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-EXPORT_SYMBOL_GPL(clk_get_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       return clk_set_rate_ex(clk, rate, 0);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
-{
-       int ret = -EOPNOTSUPP;
-       unsigned long flags;
-
-       spin_lock_irqsave(&clock_lock, flags);
-
-       if (likely(clk->ops && clk->ops->set_rate)) {
-               ret = clk->ops->set_rate(clk, rate, algo_id);
-               if (ret != 0)
-                       goto out_unlock;
-       } else {
-               clk->rate = rate;
-               ret = 0;
-       }
-
-       if (clk->ops && clk->ops->recalc)
-               clk->rate = clk->ops->recalc(clk);
-
-       propagate_rate(clk);
-
-out_unlock:
-       spin_unlock_irqrestore(&clock_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       unsigned long flags;
-       int ret = -EINVAL;
-
-       if (!parent || !clk)
-               return ret;
-       if (clk->parent == parent)
-               return 0;
-
-       spin_lock_irqsave(&clock_lock, flags);
-       if (clk->usecount == 0) {
-               if (clk->ops->set_parent)
-                       ret = clk->ops->set_parent(clk, parent);
-               else
-                       ret = clk_reparent(clk, parent);
-
-               if (ret == 0) {
-                       pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
-                                clk->name, clk->parent->name, clk->rate);
-                       if (clk->ops->recalc)
-                               clk->rate = clk->ops->recalc(clk);
-                       propagate_rate(clk);
-               }
-       } else
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&clock_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
-       return clk->parent;
-}
-EXPORT_SYMBOL_GPL(clk_get_parent);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       if (likely(clk->ops && clk->ops->round_rate)) {
-               unsigned long flags, rounded;
-
-               spin_lock_irqsave(&clock_lock, flags);
-               rounded = clk->ops->round_rate(clk, rate);
-               spin_unlock_irqrestore(&clock_lock, flags);
-
-               return rounded;
-       }
-
-       return clk_get_rate(clk);
-}
-EXPORT_SYMBOL_GPL(clk_round_rate);
-
-#ifdef CONFIG_PM
-static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
-{
-       static pm_message_t prev_state;
-       struct clk *clkp;
-
-       switch (state.event) {
-       case PM_EVENT_ON:
-               /* Resumeing from hibernation */
-               if (prev_state.event != PM_EVENT_FREEZE)
-                       break;
-
-               list_for_each_entry(clkp, &clock_list, node) {
-                       if (likely(clkp->ops)) {
-                               unsigned long rate = clkp->rate;
-
-                               if (likely(clkp->ops->set_parent))
-                                       clkp->ops->set_parent(clkp,
-                                               clkp->parent);
-                               if (likely(clkp->ops->set_rate))
-                                       clkp->ops->set_rate(clkp,
-                                               rate, NO_CHANGE);
-                               else if (likely(clkp->ops->recalc))
-                                       clkp->rate = clkp->ops->recalc(clkp);
-                       }
-               }
-               break;
-       case PM_EVENT_FREEZE:
-               break;
-       case PM_EVENT_SUSPEND:
-               break;
-       }
-
-       prev_state = state;
-       return 0;
-}
-
-static int clks_sysdev_resume(struct sys_device *dev)
-{
-       return clks_sysdev_suspend(dev, PMSG_ON);
-}
-
-static struct sysdev_class clks_sysdev_class = {
-       .name = "clks",
-};
-
-static struct sysdev_driver clks_sysdev_driver = {
-       .suspend = clks_sysdev_suspend,
-       .resume = clks_sysdev_resume,
-};
-
-static struct sys_device clks_sysdev_dev = {
-       .cls = &clks_sysdev_class,
-};
-
-static int __init clk_sysdev_init(void)
-{
-       sysdev_class_register(&clks_sysdev_class);
-       sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
-       sysdev_register(&clks_sysdev_dev);
-
-       return 0;
-}
-subsys_initcall(clk_sysdev_init);
-#endif
-
-/*
- *     debugfs support to trace clock tree hierarchy and attributes
- */
-static struct dentry *clk_debugfs_root;
-
-static int clk_debugfs_register_one(struct clk *c)
-{
-       int err;
-       struct dentry *d, *child, *child_tmp;
-       struct clk *pa = c->parent;
-       char s[255];
-       char *p = s;
-
-       p += sprintf(p, "%s", c->name);
-       if (c->id >= 0)
-               sprintf(p, ":%d", c->id);
-       d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
-       if (!d)
-               return -ENOMEM;
-       c->dentry = d;
-
-       d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       return 0;
-
-err_out:
-       d = c->dentry;
-       list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
-               debugfs_remove(child);
-       debugfs_remove(c->dentry);
-       return err;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
-       int err;
-       struct clk *pa = c->parent;
-
-       if (pa && !pa->dentry) {
-               err = clk_debugfs_register(pa);
-               if (err)
-                       return err;
-       }
-
-       if (!c->dentry && c->name) {
-               err = clk_debugfs_register_one(c);
-               if (err)
-                       return err;
-       }
-       return 0;
-}
-
-static int __init clk_debugfs_init(void)
-{
-       struct clk *c;
-       struct dentry *d;
-       int err;
-
-       d = debugfs_create_dir("clock", NULL);
-       if (!d)
-               return -ENOMEM;
-       clk_debugfs_root = d;
-
-       list_for_each_entry(c, &clock_list, node) {
-               err = clk_debugfs_register(c);
-               if (err)
-                       goto err_out;
-       }
-       return 0;
-err_out:
-       debugfs_remove_recursive(clk_debugfs_root);
-       return err;
-}
-late_initcall(clk_debugfs_init);
diff --git a/drivers/sh/clk/Makefile b/drivers/sh/clk/Makefile
new file mode 100644 (file)
index 0000000..5d15ebf
--- /dev/null
@@ -0,0 +1,3 @@
+obj-y  := core.o
+
+obj-$(CONFIG_SH_CLK_CPG)       += cpg.o
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
new file mode 100644 (file)
index 0000000..fd0d1b9
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * SuperH clock framework
+ *
+ *  Copyright (C) 2005 - 2010  Paul Mundt
+ *
+ * This clock framework is derived from the OMAP version by:
+ *
+ *     Copyright (C) 2004 - 2008 Nokia Corporation
+ *     Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ *
+ * 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.
+ */
+#define pr_fmt(fmt) "clock: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
+
+static LIST_HEAD(clock_list);
+static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(clock_list_sem);
+
+void clk_rate_table_build(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         int nr_freqs,
+                         struct clk_div_mult_table *src_table,
+                         unsigned long *bitmap)
+{
+       unsigned long mult, div;
+       unsigned long freq;
+       int i;
+
+       clk->nr_freqs = nr_freqs;
+
+       for (i = 0; i < nr_freqs; i++) {
+               div = 1;
+               mult = 1;
+
+               if (src_table->divisors && i < src_table->nr_divisors)
+                       div = src_table->divisors[i];
+
+               if (src_table->multipliers && i < src_table->nr_multipliers)
+                       mult = src_table->multipliers[i];
+
+               if (!div || !mult || (bitmap && !test_bit(i, bitmap)))
+                       freq = CPUFREQ_ENTRY_INVALID;
+               else
+                       freq = clk->parent->rate * mult / div;
+
+               freq_table[i].index = i;
+               freq_table[i].frequency = freq;
+       }
+
+       /* Termination entry */
+       freq_table[i].index = i;
+       freq_table[i].frequency = CPUFREQ_TABLE_END;
+}
+
+struct clk_rate_round_data;
+
+struct clk_rate_round_data {
+       unsigned long rate;
+       unsigned int min, max;
+       long (*func)(unsigned int, struct clk_rate_round_data *);
+       void *arg;
+};
+
+#define for_each_frequency(pos, r, freq)                       \
+       for (pos = r->min, freq = r->func(pos, r);              \
+            pos <= r->max; pos++, freq = r->func(pos, r))      \
+               if (unlikely(freq == 0))                        \
+                       ;                                       \
+               else
+
+static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
+{
+       unsigned long rate_error, rate_error_prev = ~0UL;
+       unsigned long rate_best_fit = rounder->rate;
+       unsigned long highest, lowest, freq;
+       int i;
+
+       highest = 0;
+       lowest = ~0UL;
+
+       for_each_frequency(i, rounder, freq) {
+               if (freq > highest)
+                       highest = freq;
+               if (freq < lowest)
+                       lowest = freq;
+
+               rate_error = abs(freq - rounder->rate);
+               if (rate_error < rate_error_prev) {
+                       rate_best_fit = freq;
+                       rate_error_prev = rate_error;
+               }
+
+               if (rate_error == 0)
+                       break;
+       }
+
+       if (rounder->rate >= highest)
+               rate_best_fit = highest;
+       if (rounder->rate <= lowest)
+               rate_best_fit = lowest;
+
+       return rate_best_fit;
+}
+
+static long clk_rate_table_iter(unsigned int pos,
+                               struct clk_rate_round_data *rounder)
+{
+       struct cpufreq_frequency_table *freq_table = rounder->arg;
+       unsigned long freq = freq_table[pos].frequency;
+
+       if (freq == CPUFREQ_ENTRY_INVALID)
+               freq = 0;
+
+       return freq;
+}
+
+long clk_rate_table_round(struct clk *clk,
+                         struct cpufreq_frequency_table *freq_table,
+                         unsigned long rate)
+{
+       struct clk_rate_round_data table_round = {
+               .min    = 0,
+               .max    = clk->nr_freqs - 1,
+               .func   = clk_rate_table_iter,
+               .arg    = freq_table,
+               .rate   = rate,
+       };
+
+       if (clk->nr_freqs < 1)
+               return 0;
+
+       return clk_rate_round_helper(&table_round);
+}
+
+static long clk_rate_div_range_iter(unsigned int pos,
+                                   struct clk_rate_round_data *rounder)
+{
+       return clk_get_rate(rounder->arg) / pos;
+}
+
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+                             unsigned int div_max, unsigned long rate)
+{
+       struct clk_rate_round_data div_range_round = {
+               .min    = div_min,
+               .max    = div_max,
+               .func   = clk_rate_div_range_iter,
+               .arg    = clk_get_parent(clk),
+               .rate   = rate,
+       };
+
+       return clk_rate_round_helper(&div_range_round);
+}
+
+int clk_rate_table_find(struct clk *clk,
+                       struct cpufreq_frequency_table *freq_table,
+                       unsigned long rate)
+{
+       int i;
+
+       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               unsigned long freq = freq_table[i].frequency;
+
+               if (freq == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               if (freq == rate)
+                       return i;
+       }
+
+       return -ENOENT;
+}
+
+/* Used for clocks that always have same value as the parent clock */
+unsigned long followparent_recalc(struct clk *clk)
+{
+       return clk->parent ? clk->parent->rate : 0;
+}
+
+int clk_reparent(struct clk *child, struct clk *parent)
+{
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+
+       /* now do the debugfs renaming to reattach the child
+          to the proper parent */
+
+       return 0;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct clk *tclk)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               if (clkp->ops && clkp->ops->recalc)
+                       clkp->rate = clkp->ops->recalc(clkp);
+
+               propagate_rate(clkp);
+       }
+}
+
+static void __clk_disable(struct clk *clk)
+{
+       if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n",
+                clk))
+               return;
+
+       if (!(--clk->usecount)) {
+               if (likely(clk->ops && clk->ops->disable))
+                       clk->ops->disable(clk);
+               if (likely(clk->parent))
+                       __clk_disable(clk->parent);
+       }
+}
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       if (!clk)
+               return;
+
+       spin_lock_irqsave(&clock_lock, flags);
+       __clk_disable(clk);
+       spin_unlock_irqrestore(&clock_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->usecount++ == 0) {
+               if (clk->parent) {
+                       ret = __clk_enable(clk->parent);
+                       if (unlikely(ret))
+                               goto err;
+               }
+
+               if (clk->ops && clk->ops->enable) {
+                       ret = clk->ops->enable(clk);
+                       if (ret) {
+                               if (clk->parent)
+                                       __clk_disable(clk->parent);
+                               goto err;
+                       }
+               }
+       }
+
+       return ret;
+err:
+       clk->usecount--;
+       return ret;
+}
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+       int ret;
+
+       if (!clk)
+               return -EINVAL;
+
+       spin_lock_irqsave(&clock_lock, flags);
+       ret = __clk_enable(clk);
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+static LIST_HEAD(root_clks);
+
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+void recalculate_root_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &root_clks, sibling) {
+               if (clkp->ops && clkp->ops->recalc)
+                       clkp->rate = clkp->ops->recalc(clkp);
+               propagate_rate(clkp);
+       }
+}
+
+static struct clk_mapping dummy_mapping;
+
+static struct clk *lookup_root_clock(struct clk *clk)
+{
+       while (clk->parent)
+               clk = clk->parent;
+
+       return clk;
+}
+
+static int clk_establish_mapping(struct clk *clk)
+{
+       struct clk_mapping *mapping = clk->mapping;
+
+       /*
+        * Propagate mappings.
+        */
+       if (!mapping) {
+               struct clk *clkp;
+
+               /*
+                * dummy mapping for root clocks with no specified ranges
+                */
+               if (!clk->parent) {
+                       clk->mapping = &dummy_mapping;
+                       return 0;
+               }
+
+               /*
+                * If we're on a child clock and it provides no mapping of its
+                * own, inherit the mapping from its root clock.
+                */
+               clkp = lookup_root_clock(clk);
+               mapping = clkp->mapping;
+               BUG_ON(!mapping);
+       }
+
+       /*
+        * Establish initial mapping.
+        */
+       if (!mapping->base && mapping->phys) {
+               kref_init(&mapping->ref);
+
+               mapping->base = ioremap_nocache(mapping->phys, mapping->len);
+               if (unlikely(!mapping->base))
+                       return -ENXIO;
+       } else if (mapping->base) {
+               /*
+                * Bump the refcount for an existing mapping
+                */
+               kref_get(&mapping->ref);
+       }
+
+       clk->mapping = mapping;
+       return 0;
+}
+
+static void clk_destroy_mapping(struct kref *kref)
+{
+       struct clk_mapping *mapping;
+
+       mapping = container_of(kref, struct clk_mapping, ref);
+
+       iounmap(mapping->base);
+}
+
+static void clk_teardown_mapping(struct clk *clk)
+{
+       struct clk_mapping *mapping = clk->mapping;
+
+       /* Nothing to do */
+       if (mapping == &dummy_mapping)
+               return;
+
+       kref_put(&mapping->ref, clk_destroy_mapping);
+       clk->mapping = NULL;
+}
+
+int clk_register(struct clk *clk)
+{
+       int ret;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       /*
+        * trap out already registered clocks
+        */
+       if (clk->node.next || clk->node.prev)
+               return 0;
+
+       mutex_lock(&clock_list_sem);
+
+       INIT_LIST_HEAD(&clk->children);
+       clk->usecount = 0;
+
+       ret = clk_establish_mapping(clk);
+       if (unlikely(ret))
+               goto out_unlock;
+
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
+
+       list_add(&clk->node, &clock_list);
+       if (clk->ops && clk->ops->init)
+               clk->ops->init(clk);
+
+out_unlock:
+       mutex_unlock(&clock_list_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+       mutex_lock(&clock_list_sem);
+       list_del(&clk->sibling);
+       list_del(&clk->node);
+       clk_teardown_mapping(clk);
+       mutex_unlock(&clock_list_sem);
+}
+EXPORT_SYMBOL_GPL(clk_unregister);
+
+void clk_enable_init_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &clock_list, node)
+               if (clkp->flags & CLK_ENABLE_ON_INIT)
+                       clk_enable(clkp);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
+       int ret = -EOPNOTSUPP;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clock_lock, flags);
+
+       if (likely(clk->ops && clk->ops->set_rate)) {
+               ret = clk->ops->set_rate(clk, rate, algo_id);
+               if (ret != 0)
+                       goto out_unlock;
+       } else {
+               clk->rate = rate;
+               ret = 0;
+       }
+
+       if (clk->ops && clk->ops->recalc)
+               clk->rate = clk->ops->recalc(clk);
+
+       propagate_rate(clk);
+
+out_unlock:
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (!parent || !clk)
+               return ret;
+       if (clk->parent == parent)
+               return 0;
+
+       spin_lock_irqsave(&clock_lock, flags);
+       if (clk->usecount == 0) {
+               if (clk->ops->set_parent)
+                       ret = clk->ops->set_parent(clk, parent);
+               else
+                       ret = clk_reparent(clk, parent);
+
+               if (ret == 0) {
+                       if (clk->ops->recalc)
+                               clk->rate = clk->ops->recalc(clk);
+                       pr_debug("set parent of %p to %p (new rate %ld)\n",
+                                clk, clk->parent, clk->rate);
+                       propagate_rate(clk);
+               }
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&clock_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (likely(clk->ops && clk->ops->round_rate)) {
+               unsigned long flags, rounded;
+
+               spin_lock_irqsave(&clock_lock, flags);
+               rounded = clk->ops->round_rate(clk, rate);
+               spin_unlock_irqrestore(&clock_lock, flags);
+
+               return rounded;
+       }
+
+       return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+#ifdef CONFIG_PM
+static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+       static pm_message_t prev_state;
+       struct clk *clkp;
+
+       switch (state.event) {
+       case PM_EVENT_ON:
+               /* Resumeing from hibernation */
+               if (prev_state.event != PM_EVENT_FREEZE)
+                       break;
+
+               list_for_each_entry(clkp, &clock_list, node) {
+                       if (likely(clkp->ops)) {
+                               unsigned long rate = clkp->rate;
+
+                               if (likely(clkp->ops->set_parent))
+                                       clkp->ops->set_parent(clkp,
+                                               clkp->parent);
+                               if (likely(clkp->ops->set_rate))
+                                       clkp->ops->set_rate(clkp,
+                                               rate, NO_CHANGE);
+                               else if (likely(clkp->ops->recalc))
+                                       clkp->rate = clkp->ops->recalc(clkp);
+                       }
+               }
+               break;
+       case PM_EVENT_FREEZE:
+               break;
+       case PM_EVENT_SUSPEND:
+               break;
+       }
+
+       prev_state = state;
+       return 0;
+}
+
+static int clks_sysdev_resume(struct sys_device *dev)
+{
+       return clks_sysdev_suspend(dev, PMSG_ON);
+}
+
+static struct sysdev_class clks_sysdev_class = {
+       .name = "clks",
+};
+
+static struct sysdev_driver clks_sysdev_driver = {
+       .suspend = clks_sysdev_suspend,
+       .resume = clks_sysdev_resume,
+};
+
+static struct sys_device clks_sysdev_dev = {
+       .cls = &clks_sysdev_class,
+};
+
+static int __init clk_sysdev_init(void)
+{
+       sysdev_class_register(&clks_sysdev_class);
+       sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
+       sysdev_register(&clks_sysdev_dev);
+
+       return 0;
+}
+subsys_initcall(clk_sysdev_init);
+#endif
+
+/*
+ *     debugfs support to trace clock tree hierarchy and attributes
+ */
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+       int err;
+       struct dentry *d, *child, *child_tmp;
+       struct clk *pa = c->parent;
+       char s[255];
+       char *p = s;
+
+       p += sprintf(p, "%p", c);
+       d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
+       if (!d)
+               return -ENOMEM;
+       c->dentry = d;
+
+       d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       return 0;
+
+err_out:
+       d = c->dentry;
+       list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
+               debugfs_remove(child);
+       debugfs_remove(c->dentry);
+       return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+       int err;
+       struct clk *pa = c->parent;
+
+       if (pa && !pa->dentry) {
+               err = clk_debugfs_register(pa);
+               if (err)
+                       return err;
+       }
+
+       if (!c->dentry) {
+               err = clk_debugfs_register_one(c);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+       struct clk *c;
+       struct dentry *d;
+       int err;
+
+       d = debugfs_create_dir("clock", NULL);
+       if (!d)
+               return -ENOMEM;
+       clk_debugfs_root = d;
+
+       list_for_each_entry(c, &clock_list, node) {
+               err = clk_debugfs_register(c);
+               if (err)
+                       goto err_out;
+       }
+       return 0;
+err_out:
+       debugfs_remove_recursive(clk_debugfs_root);
+       return err;
+}
+late_initcall(clk_debugfs_init);
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
new file mode 100644 (file)
index 0000000..3aea5f0
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
+ *
+ *  Copyright (C) 2010  Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+
+static int sh_clk_mstp32_enable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
+                    clk->enable_reg);
+       return 0;
+}
+
+static void sh_clk_mstp32_disable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
+                    clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_mstp32_clk_ops = {
+       .enable         = sh_clk_mstp32_enable,
+       .disable        = sh_clk_mstp32_disable,
+       .recalc         = followparent_recalc,
+};
+
+int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+       struct clk *clkp;
+       int ret = 0;
+       int k;
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+               clkp->ops = &sh_clk_mstp32_clk_ops;
+               ret |= clk_register(clkp);
+       }
+
+       return ret;
+}
+
+static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_rate_table_round(clk, clk->freq_table, rate);
+}
+
+static int sh_clk_div6_divisors[64] = {
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+       49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+};
+
+static struct clk_div_mult_table sh_clk_div6_table = {
+       .divisors = sh_clk_div6_divisors,
+       .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
+};
+
+static unsigned long sh_clk_div6_recalc(struct clk *clk)
+{
+       struct clk_div_mult_table *table = &sh_clk_div6_table;
+       unsigned int idx;
+
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, NULL);
+
+       idx = __raw_readl(clk->enable_reg) & 0x003f;
+
+       return clk->freq_table[idx].frequency;
+}
+
+static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct clk_div_mult_table *table = &sh_clk_div6_table;
+       u32 value;
+       int ret, i;
+
+       if (!clk->parent_table || !clk->parent_num)
+               return -EINVAL;
+
+       /* Search the parent */
+       for (i = 0; i < clk->parent_num; i++)
+               if (clk->parent_table[i] == parent)
+                       break;
+
+       if (i == clk->parent_num)
+               return -ENODEV;
+
+       ret = clk_reparent(clk, parent);
+       if (ret < 0)
+               return ret;
+
+       value = __raw_readl(clk->enable_reg) &
+               ~(((1 << clk->src_width) - 1) << clk->src_shift);
+
+       __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
+
+       /* Rebuild the frequency table */
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, &clk->arch_flags);
+
+       return 0;
+}
+
+static int sh_clk_div6_set_rate(struct clk *clk,
+                               unsigned long rate, int algo_id)
+{
+       unsigned long value;
+       int idx;
+
+       idx = clk_rate_table_find(clk, clk->freq_table, rate);
+       if (idx < 0)
+               return idx;
+
+       value = __raw_readl(clk->enable_reg);
+       value &= ~0x3f;
+       value |= idx;
+       __raw_writel(value, clk->enable_reg);
+       return 0;
+}
+
+static int sh_clk_div6_enable(struct clk *clk)
+{
+       unsigned long value;
+       int ret;
+
+       ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+       if (ret == 0) {
+               value = __raw_readl(clk->enable_reg);
+               value &= ~0x100; /* clear stop bit to enable clock */
+               __raw_writel(value, clk->enable_reg);
+       }
+       return ret;
+}
+
+static void sh_clk_div6_disable(struct clk *clk)
+{
+       unsigned long value;
+
+       value = __raw_readl(clk->enable_reg);
+       value |= 0x100; /* stop clock */
+       value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
+       __raw_writel(value, clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_div6_clk_ops = {
+       .recalc         = sh_clk_div6_recalc,
+       .round_rate     = sh_clk_div_round_rate,
+       .set_rate       = sh_clk_div6_set_rate,
+       .enable         = sh_clk_div6_enable,
+       .disable        = sh_clk_div6_disable,
+};
+
+static struct clk_ops sh_clk_div6_reparent_clk_ops = {
+       .recalc         = sh_clk_div6_recalc,
+       .round_rate     = sh_clk_div_round_rate,
+       .set_rate       = sh_clk_div6_set_rate,
+       .enable         = sh_clk_div6_enable,
+       .disable        = sh_clk_div6_disable,
+       .set_parent     = sh_clk_div6_set_parent,
+};
+
+static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
+                                          struct clk_ops *ops)
+{
+       struct clk *clkp;
+       void *freq_table;
+       int nr_divs = sh_clk_div6_table.nr_divisors;
+       int freq_table_size = sizeof(struct cpufreq_frequency_table);
+       int ret = 0;
+       int k;
+
+       freq_table_size *= (nr_divs + 1);
+       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+       if (!freq_table) {
+               pr_err("sh_clk_div6_register: unable to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+
+               clkp->ops = ops;
+               clkp->freq_table = freq_table + (k * freq_table_size);
+               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+               ret = clk_register(clkp);
+       }
+
+       return ret;
+}
+
+int __init sh_clk_div6_register(struct clk *clks, int nr)
+{
+       return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
+}
+
+int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
+{
+       return sh_clk_div6_register_ops(clks, nr,
+                                       &sh_clk_div6_reparent_clk_ops);
+}
+
+static unsigned long sh_clk_div4_recalc(struct clk *clk)
+{
+       struct clk_div4_table *d4t = clk->priv;
+       struct clk_div_mult_table *table = d4t->div_mult_table;
+       unsigned int idx;
+
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, &clk->arch_flags);
+
+       idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
+
+       return clk->freq_table[idx].frequency;
+}
+
+static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct clk_div4_table *d4t = clk->priv;
+       struct clk_div_mult_table *table = d4t->div_mult_table;
+       u32 value;
+       int ret;
+
+       /* we really need a better way to determine parent index, but for
+        * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
+        * no CLK_ENABLE_ON_INIT means external clock...
+        */
+
+       if (parent->flags & CLK_ENABLE_ON_INIT)
+               value = __raw_readl(clk->enable_reg) & ~(1 << 7);
+       else
+               value = __raw_readl(clk->enable_reg) | (1 << 7);
+
+       ret = clk_reparent(clk, parent);
+       if (ret < 0)
+               return ret;
+
+       __raw_writel(value, clk->enable_reg);
+
+       /* Rebiuld the frequency table */
+       clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+                            table, &clk->arch_flags);
+
+       return 0;
+}
+
+static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+       struct clk_div4_table *d4t = clk->priv;
+       unsigned long value;
+       int idx = clk_rate_table_find(clk, clk->freq_table, rate);
+       if (idx < 0)
+               return idx;
+
+       value = __raw_readl(clk->enable_reg);
+       value &= ~(0xf << clk->enable_bit);
+       value |= (idx << clk->enable_bit);
+       __raw_writel(value, clk->enable_reg);
+
+       if (d4t->kick)
+               d4t->kick(clk);
+
+       return 0;
+}
+
+static int sh_clk_div4_enable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
+       return 0;
+}
+
+static void sh_clk_div4_disable(struct clk *clk)
+{
+       __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_div4_clk_ops = {
+       .recalc         = sh_clk_div4_recalc,
+       .set_rate       = sh_clk_div4_set_rate,
+       .round_rate     = sh_clk_div_round_rate,
+};
+
+static struct clk_ops sh_clk_div4_enable_clk_ops = {
+       .recalc         = sh_clk_div4_recalc,
+       .set_rate       = sh_clk_div4_set_rate,
+       .round_rate     = sh_clk_div_round_rate,
+       .enable         = sh_clk_div4_enable,
+       .disable        = sh_clk_div4_disable,
+};
+
+static struct clk_ops sh_clk_div4_reparent_clk_ops = {
+       .recalc         = sh_clk_div4_recalc,
+       .set_rate       = sh_clk_div4_set_rate,
+       .round_rate     = sh_clk_div_round_rate,
+       .enable         = sh_clk_div4_enable,
+       .disable        = sh_clk_div4_disable,
+       .set_parent     = sh_clk_div4_set_parent,
+};
+
+static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
+                       struct clk_div4_table *table, struct clk_ops *ops)
+{
+       struct clk *clkp;
+       void *freq_table;
+       int nr_divs = table->div_mult_table->nr_divisors;
+       int freq_table_size = sizeof(struct cpufreq_frequency_table);
+       int ret = 0;
+       int k;
+
+       freq_table_size *= (nr_divs + 1);
+       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+       if (!freq_table) {
+               pr_err("sh_clk_div4_register: unable to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+
+               clkp->ops = ops;
+               clkp->priv = table;
+
+               clkp->freq_table = freq_table + (k * freq_table_size);
+               clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+               ret = clk_register(clkp);
+       }
+
+       return ret;
+}
+
+int __init sh_clk_div4_register(struct clk *clks, int nr,
+                               struct clk_div4_table *table)
+{
+       return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
+}
+
+int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
+                               struct clk_div4_table *table)
+{
+       return sh_clk_div4_register_ops(clks, nr, table,
+                                       &sh_clk_div4_enable_clk_ops);
+}
+
+int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
+                               struct clk_div4_table *table)
+{
+       return sh_clk_div4_register_ops(clks, nr, table,
+                                       &sh_clk_div4_reparent_clk_ops);
+}
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
deleted file mode 100644 (file)
index e91a23e..0000000
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Shared interrupt handling code for IPR and INTC2 types of IRQs.
- *
- * Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009, 2010 Paul Mundt
- *
- * Based on intc2.c and ipr.c
- *
- * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- * Copyright (C) 2005, 2006  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/sh_intc.h>
-#include <linux/sysdev.h>
-#include <linux/list.h>
-#include <linux/topology.h>
-#include <linux/bitmap.h>
-#include <linux/cpumask.h>
-#include <asm/sizes.h>
-
-#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
-       ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
-        ((addr_e) << 16) | ((addr_d << 24)))
-
-#define _INTC_SHIFT(h) (h & 0x1f)
-#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
-#define _INTC_FN(h) ((h >> 9) & 0xf)
-#define _INTC_MODE(h) ((h >> 13) & 0x7)
-#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
-#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
-
-struct intc_handle_int {
-       unsigned int irq;
-       unsigned long handle;
-};
-
-struct intc_window {
-       phys_addr_t phys;
-       void __iomem *virt;
-       unsigned long size;
-};
-
-struct intc_desc_int {
-       struct list_head list;
-       struct sys_device sysdev;
-       pm_message_t state;
-       unsigned long *reg;
-#ifdef CONFIG_SMP
-       unsigned long *smp;
-#endif
-       unsigned int nr_reg;
-       struct intc_handle_int *prio;
-       unsigned int nr_prio;
-       struct intc_handle_int *sense;
-       unsigned int nr_sense;
-       struct intc_window *window;
-       unsigned int nr_windows;
-       struct irq_chip chip;
-};
-
-static LIST_HEAD(intc_list);
-
-/*
- * The intc_irq_map provides a global map of bound IRQ vectors for a
- * given platform. Allocation of IRQs are either static through the CPU
- * vector map, or dynamic in the case of board mux vectors or MSI.
- *
- * As this is a central point for all IRQ controllers on the system,
- * each of the available sources are mapped out here. This combined with
- * sparseirq makes it quite trivial to keep the vector map tightly packed
- * when dynamically creating IRQs, as well as tying in to otherwise
- * unused irq_desc positions in the sparse array.
- */
-static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
-static DEFINE_SPINLOCK(vector_lock);
-
-#ifdef CONFIG_SMP
-#define IS_SMP(x) x.smp
-#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
-#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
-#else
-#define IS_SMP(x) 0
-#define INTC_REG(d, x, c) (d->reg[(x)])
-#define SMP_NR(d, x) 1
-#endif
-
-static unsigned int intc_prio_level[NR_IRQS];  /* for now */
-static unsigned int default_prio_level = 2;    /* 2 - 16 */
-static unsigned long ack_handle[NR_IRQS];
-#ifdef CONFIG_INTC_BALANCING
-static unsigned long dist_handle[NR_IRQS];
-#endif
-
-static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
-{
-       struct irq_chip *chip = get_irq_chip(irq);
-       return container_of(chip, struct intc_desc_int, chip);
-}
-
-static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
-                                      unsigned long address)
-{
-       struct intc_window *window;
-       int k;
-
-       /* scan through physical windows and convert address */
-       for (k = 0; k < d->nr_windows; k++) {
-               window = d->window + k;
-
-               if (address < window->phys)
-                       continue;
-
-               if (address >= (window->phys + window->size))
-                       continue;
-
-               address -= window->phys;
-               address += (unsigned long)window->virt;
-
-               return address;
-       }
-
-       /* no windows defined, register must be 1:1 mapped virt:phys */
-       return address;
-}
-
-static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
-{
-       unsigned int k;
-
-       address = intc_phys_to_virt(d, address);
-
-       for (k = 0; k < d->nr_reg; k++) {
-               if (d->reg[k] == address)
-                       return k;
-       }
-
-       BUG();
-       return 0;
-}
-
-static inline unsigned int set_field(unsigned int value,
-                                    unsigned int field_value,
-                                    unsigned int handle)
-{
-       unsigned int width = _INTC_WIDTH(handle);
-       unsigned int shift = _INTC_SHIFT(handle);
-
-       value &= ~(((1 << width) - 1) << shift);
-       value |= field_value << shift;
-       return value;
-}
-
-static void write_8(unsigned long addr, unsigned long h, unsigned long data)
-{
-       __raw_writeb(set_field(0, data, h), addr);
-       (void)__raw_readb(addr);        /* Defeat write posting */
-}
-
-static void write_16(unsigned long addr, unsigned long h, unsigned long data)
-{
-       __raw_writew(set_field(0, data, h), addr);
-       (void)__raw_readw(addr);        /* Defeat write posting */
-}
-
-static void write_32(unsigned long addr, unsigned long h, unsigned long data)
-{
-       __raw_writel(set_field(0, data, h), addr);
-       (void)__raw_readl(addr);        /* Defeat write posting */
-}
-
-static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
-{
-       unsigned long flags;
-       local_irq_save(flags);
-       __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
-       (void)__raw_readb(addr);        /* Defeat write posting */
-       local_irq_restore(flags);
-}
-
-static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
-{
-       unsigned long flags;
-       local_irq_save(flags);
-       __raw_writew(set_field(__raw_readw(addr), data, h), addr);
-       (void)__raw_readw(addr);        /* Defeat write posting */
-       local_irq_restore(flags);
-}
-
-static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
-{
-       unsigned long flags;
-       local_irq_save(flags);
-       __raw_writel(set_field(__raw_readl(addr), data, h), addr);
-       (void)__raw_readl(addr);        /* Defeat write posting */
-       local_irq_restore(flags);
-}
-
-enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
-
-static void (*intc_reg_fns[])(unsigned long addr,
-                             unsigned long h,
-                             unsigned long data) = {
-       [REG_FN_WRITE_BASE + 0] = write_8,
-       [REG_FN_WRITE_BASE + 1] = write_16,
-       [REG_FN_WRITE_BASE + 3] = write_32,
-       [REG_FN_MODIFY_BASE + 0] = modify_8,
-       [REG_FN_MODIFY_BASE + 1] = modify_16,
-       [REG_FN_MODIFY_BASE + 3] = modify_32,
-};
-
-enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
-       MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
-       MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
-       MODE_PRIO_REG,       /* Priority value written to enable interrupt */
-       MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
-};
-
-static void intc_mode_field(unsigned long addr,
-                           unsigned long handle,
-                           void (*fn)(unsigned long,
-                                      unsigned long,
-                                      unsigned long),
-                           unsigned int irq)
-{
-       fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
-}
-
-static void intc_mode_zero(unsigned long addr,
-                          unsigned long handle,
-                          void (*fn)(unsigned long,
-                                      unsigned long,
-                                      unsigned long),
-                          unsigned int irq)
-{
-       fn(addr, handle, 0);
-}
-
-static void intc_mode_prio(unsigned long addr,
-                          unsigned long handle,
-                          void (*fn)(unsigned long,
-                                      unsigned long,
-                                      unsigned long),
-                          unsigned int irq)
-{
-       fn(addr, handle, intc_prio_level[irq]);
-}
-
-static void (*intc_enable_fns[])(unsigned long addr,
-                                unsigned long handle,
-                                void (*fn)(unsigned long,
-                                           unsigned long,
-                                           unsigned long),
-                                unsigned int irq) = {
-       [MODE_ENABLE_REG] = intc_mode_field,
-       [MODE_MASK_REG] = intc_mode_zero,
-       [MODE_DUAL_REG] = intc_mode_field,
-       [MODE_PRIO_REG] = intc_mode_prio,
-       [MODE_PCLR_REG] = intc_mode_prio,
-};
-
-static void (*intc_disable_fns[])(unsigned long addr,
-                                 unsigned long handle,
-                                 void (*fn)(unsigned long,
-                                            unsigned long,
-                                            unsigned long),
-                                 unsigned int irq) = {
-       [MODE_ENABLE_REG] = intc_mode_zero,
-       [MODE_MASK_REG] = intc_mode_field,
-       [MODE_DUAL_REG] = intc_mode_field,
-       [MODE_PRIO_REG] = intc_mode_zero,
-       [MODE_PCLR_REG] = intc_mode_field,
-};
-
-#ifdef CONFIG_INTC_BALANCING
-static inline void intc_balancing_enable(unsigned int irq)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long handle = dist_handle[irq];
-       unsigned long addr;
-
-       if (irq_balancing_disabled(irq) || !handle)
-               return;
-
-       addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
-       intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long handle = dist_handle[irq];
-       unsigned long addr;
-
-       if (irq_balancing_disabled(irq) || !handle)
-               return;
-
-       addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
-       intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
-}
-
-static unsigned int intc_dist_data(struct intc_desc *desc,
-                                  struct intc_desc_int *d,
-                                  intc_enum enum_id)
-{
-       struct intc_mask_reg *mr = desc->hw.mask_regs;
-       unsigned int i, j, fn, mode;
-       unsigned long reg_e, reg_d;
-
-       for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
-               mr = desc->hw.mask_regs + i;
-
-               /*
-                * Skip this entry if there's no auto-distribution
-                * register associated with it.
-                */
-               if (!mr->dist_reg)
-                       continue;
-
-               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
-                       if (mr->enum_ids[j] != enum_id)
-                               continue;
-
-                       fn = REG_FN_MODIFY_BASE;
-                       mode = MODE_ENABLE_REG;
-                       reg_e = mr->dist_reg;
-                       reg_d = mr->dist_reg;
-
-                       fn += (mr->reg_width >> 3) - 1;
-                       return _INTC_MK(fn, mode,
-                                       intc_get_reg(d, reg_e),
-                                       intc_get_reg(d, reg_d),
-                                       1,
-                                       (mr->reg_width - 1) - j);
-               }
-       }
-
-       /*
-        * It's possible we've gotten here with no distribution options
-        * available for the IRQ in question, so we just skip over those.
-        */
-       return 0;
-}
-#else
-static inline void intc_balancing_enable(unsigned int irq)
-{
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
-}
-#endif
-
-static inline void _intc_enable(unsigned int irq, unsigned long handle)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long addr;
-       unsigned int cpu;
-
-       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
-#ifdef CONFIG_SMP
-               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
-                       continue;
-#endif
-               addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
-               intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
-                                                   [_INTC_FN(handle)], irq);
-       }
-
-       intc_balancing_enable(irq);
-}
-
-static void intc_enable(unsigned int irq)
-{
-       _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
-}
-
-static void intc_disable(unsigned int irq)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long handle = (unsigned long)get_irq_chip_data(irq);
-       unsigned long addr;
-       unsigned int cpu;
-
-       intc_balancing_disable(irq);
-
-       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
-#ifdef CONFIG_SMP
-               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
-                       continue;
-#endif
-               addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
-               intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
-                                                    [_INTC_FN(handle)], irq);
-       }
-}
-
-static void (*intc_enable_noprio_fns[])(unsigned long addr,
-                                       unsigned long handle,
-                                       void (*fn)(unsigned long,
-                                                  unsigned long,
-                                                  unsigned long),
-                                       unsigned int irq) = {
-       [MODE_ENABLE_REG] = intc_mode_field,
-       [MODE_MASK_REG] = intc_mode_zero,
-       [MODE_DUAL_REG] = intc_mode_field,
-       [MODE_PRIO_REG] = intc_mode_field,
-       [MODE_PCLR_REG] = intc_mode_field,
-};
-
-static void intc_enable_disable(struct intc_desc_int *d,
-                               unsigned long handle, int do_enable)
-{
-       unsigned long addr;
-       unsigned int cpu;
-       void (*fn)(unsigned long, unsigned long,
-                  void (*)(unsigned long, unsigned long, unsigned long),
-                  unsigned int);
-
-       if (do_enable) {
-               for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
-                       addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
-                       fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
-                       fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
-               }
-       } else {
-               for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
-                       addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
-                       fn = intc_disable_fns[_INTC_MODE(handle)];
-                       fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
-               }
-       }
-}
-
-static int intc_set_wake(unsigned int irq, unsigned int on)
-{
-       return 0; /* allow wakeup, but setup hardware in intc_suspend() */
-}
-
-#ifdef CONFIG_SMP
-/*
- * This is held with the irq desc lock held, so we don't require any
- * additional locking here at the intc desc level. The affinity mask is
- * later tested in the enable/disable paths.
- */
-static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
-{
-       if (!cpumask_intersects(cpumask, cpu_online_mask))
-               return -1;
-
-       cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
-
-       return 0;
-}
-#endif
-
-static void intc_mask_ack(unsigned int irq)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned long handle = ack_handle[irq];
-       unsigned long addr;
-
-       intc_disable(irq);
-
-       /* read register and write zero only to the associated bit */
-       if (handle) {
-               addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
-               switch (_INTC_FN(handle)) {
-               case REG_FN_MODIFY_BASE + 0:    /* 8bit */
-                       __raw_readb(addr);
-                       __raw_writeb(0xff ^ set_field(0, 1, handle), addr);
-                       break;
-               case REG_FN_MODIFY_BASE + 1:    /* 16bit */
-                       __raw_readw(addr);
-                       __raw_writew(0xffff ^ set_field(0, 1, handle), addr);
-                       break;
-               case REG_FN_MODIFY_BASE + 3:    /* 32bit */
-                       __raw_readl(addr);
-                       __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
-                       break;
-               default:
-                       BUG();
-                       break;
-               }
-       }
-}
-
-static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
-                                            unsigned int nr_hp,
-                                            unsigned int irq)
-{
-       int i;
-
-       /*
-        * this doesn't scale well, but...
-        *
-        * this function should only be used for cerain uncommon
-        * operations such as intc_set_priority() and intc_set_sense()
-        * and in those rare cases performance doesn't matter that much.
-        * keeping the memory footprint low is more important.
-        *
-        * one rather simple way to speed this up and still keep the
-        * memory footprint down is to make sure the array is sorted
-        * and then perform a bisect to lookup the irq.
-        */
-       for (i = 0; i < nr_hp; i++) {
-               if ((hp + i)->irq != irq)
-                       continue;
-
-               return hp + i;
-       }
-
-       return NULL;
-}
-
-int intc_set_priority(unsigned int irq, unsigned int prio)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       struct intc_handle_int *ihp;
-
-       if (!intc_prio_level[irq] || prio <= 1)
-               return -EINVAL;
-
-       ihp = intc_find_irq(d->prio, d->nr_prio, irq);
-       if (ihp) {
-               if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
-                       return -EINVAL;
-
-               intc_prio_level[irq] = prio;
-
-               /*
-                * only set secondary masking method directly
-                * primary masking method is using intc_prio_level[irq]
-                * priority level will be set during next enable()
-                */
-               if (_INTC_FN(ihp->handle) != REG_FN_ERR)
-                       _intc_enable(irq, ihp->handle);
-       }
-       return 0;
-}
-
-#define VALID(x) (x | 0x80)
-
-static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
-       [IRQ_TYPE_EDGE_FALLING] = VALID(0),
-       [IRQ_TYPE_EDGE_RISING] = VALID(1),
-       [IRQ_TYPE_LEVEL_LOW] = VALID(2),
-       /* SH7706, SH7707 and SH7709 do not support high level triggered */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
-    !defined(CONFIG_CPU_SUBTYPE_SH7709)
-       [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
-#endif
-};
-
-static int intc_set_sense(unsigned int irq, unsigned int type)
-{
-       struct intc_desc_int *d = get_intc_desc(irq);
-       unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
-       struct intc_handle_int *ihp;
-       unsigned long addr;
-
-       if (!value)
-               return -EINVAL;
-
-       ihp = intc_find_irq(d->sense, d->nr_sense, irq);
-       if (ihp) {
-               addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
-               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
-       }
-       return 0;
-}
-
-static intc_enum __init intc_grp_id(struct intc_desc *desc,
-                                   intc_enum enum_id)
-{
-       struct intc_group *g = desc->hw.groups;
-       unsigned int i, j;
-
-       for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
-               g = desc->hw.groups + i;
-
-               for (j = 0; g->enum_ids[j]; j++) {
-                       if (g->enum_ids[j] != enum_id)
-                               continue;
-
-                       return g->enum_id;
-               }
-       }
-
-       return 0;
-}
-
-static unsigned int __init _intc_mask_data(struct intc_desc *desc,
-                                          struct intc_desc_int *d,
-                                          intc_enum enum_id,
-                                          unsigned int *reg_idx,
-                                          unsigned int *fld_idx)
-{
-       struct intc_mask_reg *mr = desc->hw.mask_regs;
-       unsigned int fn, mode;
-       unsigned long reg_e, reg_d;
-
-       while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
-               mr = desc->hw.mask_regs + *reg_idx;
-
-               for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
-                       if (mr->enum_ids[*fld_idx] != enum_id)
-                               continue;
-
-                       if (mr->set_reg && mr->clr_reg) {
-                               fn = REG_FN_WRITE_BASE;
-                               mode = MODE_DUAL_REG;
-                               reg_e = mr->clr_reg;
-                               reg_d = mr->set_reg;
-                       } else {
-                               fn = REG_FN_MODIFY_BASE;
-                               if (mr->set_reg) {
-                                       mode = MODE_ENABLE_REG;
-                                       reg_e = mr->set_reg;
-                                       reg_d = mr->set_reg;
-                               } else {
-                                       mode = MODE_MASK_REG;
-                                       reg_e = mr->clr_reg;
-                                       reg_d = mr->clr_reg;
-                               }
-                       }
-
-                       fn += (mr->reg_width >> 3) - 1;
-                       return _INTC_MK(fn, mode,
-                                       intc_get_reg(d, reg_e),
-                                       intc_get_reg(d, reg_d),
-                                       1,
-                                       (mr->reg_width - 1) - *fld_idx);
-               }
-
-               *fld_idx = 0;
-               (*reg_idx)++;
-       }
-
-       return 0;
-}
-
-static unsigned int __init intc_mask_data(struct intc_desc *desc,
-                                         struct intc_desc_int *d,
-                                         intc_enum enum_id, int do_grps)
-{
-       unsigned int i = 0;
-       unsigned int j = 0;
-       unsigned int ret;
-
-       ret = _intc_mask_data(desc, d, enum_id, &i, &j);
-       if (ret)
-               return ret;
-
-       if (do_grps)
-               return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
-       return 0;
-}
-
-static unsigned int __init _intc_prio_data(struct intc_desc *desc,
-                                          struct intc_desc_int *d,
-                                          intc_enum enum_id,
-                                          unsigned int *reg_idx,
-                                          unsigned int *fld_idx)
-{
-       struct intc_prio_reg *pr = desc->hw.prio_regs;
-       unsigned int fn, n, mode, bit;
-       unsigned long reg_e, reg_d;
-
-       while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
-               pr = desc->hw.prio_regs + *reg_idx;
-
-               for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
-                       if (pr->enum_ids[*fld_idx] != enum_id)
-                               continue;
-
-                       if (pr->set_reg && pr->clr_reg) {
-                               fn = REG_FN_WRITE_BASE;
-                               mode = MODE_PCLR_REG;
-                               reg_e = pr->set_reg;
-                               reg_d = pr->clr_reg;
-                       } else {
-                               fn = REG_FN_MODIFY_BASE;
-                               mode = MODE_PRIO_REG;
-                               if (!pr->set_reg)
-                                       BUG();
-                               reg_e = pr->set_reg;
-                               reg_d = pr->set_reg;
-                       }
-
-                       fn += (pr->reg_width >> 3) - 1;
-                       n = *fld_idx + 1;
-
-                       BUG_ON(n * pr->field_width > pr->reg_width);
-
-                       bit = pr->reg_width - (n * pr->field_width);
-
-                       return _INTC_MK(fn, mode,
-                                       intc_get_reg(d, reg_e),
-                                       intc_get_reg(d, reg_d),
-                                       pr->field_width, bit);
-               }
-
-               *fld_idx = 0;
-               (*reg_idx)++;
-       }
-
-       return 0;
-}
-
-static unsigned int __init intc_prio_data(struct intc_desc *desc,
-                                         struct intc_desc_int *d,
-                                         intc_enum enum_id, int do_grps)
-{
-       unsigned int i = 0;
-       unsigned int j = 0;
-       unsigned int ret;
-
-       ret = _intc_prio_data(desc, d, enum_id, &i, &j);
-       if (ret)
-               return ret;
-
-       if (do_grps)
-               return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
-       return 0;
-}
-
-static void __init intc_enable_disable_enum(struct intc_desc *desc,
-                                           struct intc_desc_int *d,
-                                           intc_enum enum_id, int enable)
-{
-       unsigned int i, j, data;
-
-       /* go through and enable/disable all mask bits */
-       i = j = 0;
-       do {
-               data = _intc_mask_data(desc, d, enum_id, &i, &j);
-               if (data)
-                       intc_enable_disable(d, data, enable);
-               j++;
-       } while (data);
-
-       /* go through and enable/disable all priority fields */
-       i = j = 0;
-       do {
-               data = _intc_prio_data(desc, d, enum_id, &i, &j);
-               if (data)
-                       intc_enable_disable(d, data, enable);
-
-               j++;
-       } while (data);
-}
-
-static unsigned int __init intc_ack_data(struct intc_desc *desc,
-                                         struct intc_desc_int *d,
-                                         intc_enum enum_id)
-{
-       struct intc_mask_reg *mr = desc->hw.ack_regs;
-       unsigned int i, j, fn, mode;
-       unsigned long reg_e, reg_d;
-
-       for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
-               mr = desc->hw.ack_regs + i;
-
-               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
-                       if (mr->enum_ids[j] != enum_id)
-                               continue;
-
-                       fn = REG_FN_MODIFY_BASE;
-                       mode = MODE_ENABLE_REG;
-                       reg_e = mr->set_reg;
-                       reg_d = mr->set_reg;
-
-                       fn += (mr->reg_width >> 3) - 1;
-                       return _INTC_MK(fn, mode,
-                                       intc_get_reg(d, reg_e),
-                                       intc_get_reg(d, reg_d),
-                                       1,
-                                       (mr->reg_width - 1) - j);
-               }
-       }
-
-       return 0;
-}
-
-static unsigned int __init intc_sense_data(struct intc_desc *desc,
-                                          struct intc_desc_int *d,
-                                          intc_enum enum_id)
-{
-       struct intc_sense_reg *sr = desc->hw.sense_regs;
-       unsigned int i, j, fn, bit;
-
-       for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
-               sr = desc->hw.sense_regs + i;
-
-               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
-                       if (sr->enum_ids[j] != enum_id)
-                               continue;
-
-                       fn = REG_FN_MODIFY_BASE;
-                       fn += (sr->reg_width >> 3) - 1;
-
-                       BUG_ON((j + 1) * sr->field_width > sr->reg_width);
-
-                       bit = sr->reg_width - ((j + 1) * sr->field_width);
-
-                       return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
-                                       0, sr->field_width, bit);
-               }
-       }
-
-       return 0;
-}
-
-static void __init intc_register_irq(struct intc_desc *desc,
-                                    struct intc_desc_int *d,
-                                    intc_enum enum_id,
-                                    unsigned int irq)
-{
-       struct intc_handle_int *hp;
-       unsigned int data[2], primary;
-
-       /*
-        * Register the IRQ position with the global IRQ map
-        */
-       set_bit(irq, intc_irq_map);
-
-       /*
-        * Prefer single interrupt source bitmap over other combinations:
-        *
-        * 1. bitmap, single interrupt source
-        * 2. priority, single interrupt source
-        * 3. bitmap, multiple interrupt sources (groups)
-        * 4. priority, multiple interrupt sources (groups)
-        */
-       data[0] = intc_mask_data(desc, d, enum_id, 0);
-       data[1] = intc_prio_data(desc, d, enum_id, 0);
-
-       primary = 0;
-       if (!data[0] && data[1])
-               primary = 1;
-
-       if (!data[0] && !data[1])
-               pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
-                          irq, irq2evt(irq));
-
-       data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
-       data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
-
-       if (!data[primary])
-               primary ^= 1;
-
-       BUG_ON(!data[primary]); /* must have primary masking method */
-
-       disable_irq_nosync(irq);
-       set_irq_chip_and_handler_name(irq, &d->chip,
-                                     handle_level_irq, "level");
-       set_irq_chip_data(irq, (void *)data[primary]);
-
-       /*
-        * set priority level
-        * - this needs to be at least 2 for 5-bit priorities on 7780
-        */
-       intc_prio_level[irq] = default_prio_level;
-
-       /* enable secondary masking method if present */
-       if (data[!primary])
-               _intc_enable(irq, data[!primary]);
-
-       /* add irq to d->prio list if priority is available */
-       if (data[1]) {
-               hp = d->prio + d->nr_prio;
-               hp->irq = irq;
-               hp->handle = data[1];
-
-               if (primary) {
-                       /*
-                        * only secondary priority should access registers, so
-                        * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
-                        */
-                       hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
-                       hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
-               }
-               d->nr_prio++;
-       }
-
-       /* add irq to d->sense list if sense is available */
-       data[0] = intc_sense_data(desc, d, enum_id);
-       if (data[0]) {
-               (d->sense + d->nr_sense)->irq = irq;
-               (d->sense + d->nr_sense)->handle = data[0];
-               d->nr_sense++;
-       }
-
-       /* irq should be disabled by default */
-       d->chip.mask(irq);
-
-       if (desc->hw.ack_regs)
-               ack_handle[irq] = intc_ack_data(desc, d, enum_id);
-
-#ifdef CONFIG_INTC_BALANCING
-       if (desc->hw.mask_regs)
-               dist_handle[irq] = intc_dist_data(desc, d, enum_id);
-#endif
-
-#ifdef CONFIG_ARM
-       set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
-}
-
-static unsigned int __init save_reg(struct intc_desc_int *d,
-                                   unsigned int cnt,
-                                   unsigned long value,
-                                   unsigned int smp)
-{
-       if (value) {
-               value = intc_phys_to_virt(d, value);
-
-               d->reg[cnt] = value;
-#ifdef CONFIG_SMP
-               d->smp[cnt] = smp;
-#endif
-               return 1;
-       }
-
-       return 0;
-}
-
-static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
-{
-       generic_handle_irq((unsigned int)get_irq_data(irq));
-}
-
-int __init register_intc_controller(struct intc_desc *desc)
-{
-       unsigned int i, k, smp;
-       struct intc_hw_desc *hw = &desc->hw;
-       struct intc_desc_int *d;
-       struct resource *res;
-
-       pr_info("Registered controller '%s' with %u IRQs\n",
-               desc->name, hw->nr_vectors);
-
-       d = kzalloc(sizeof(*d), GFP_NOWAIT);
-       if (!d)
-               goto err0;
-
-       INIT_LIST_HEAD(&d->list);
-       list_add(&d->list, &intc_list);
-
-       if (desc->num_resources) {
-               d->nr_windows = desc->num_resources;
-               d->window = kzalloc(d->nr_windows * sizeof(*d->window),
-                                   GFP_NOWAIT);
-               if (!d->window)
-                       goto err1;
-
-               for (k = 0; k < d->nr_windows; k++) {
-                       res = desc->resource + k;
-                       WARN_ON(resource_type(res) != IORESOURCE_MEM);
-                       d->window[k].phys = res->start;
-                       d->window[k].size = resource_size(res);
-                       d->window[k].virt = ioremap_nocache(res->start,
-                                                        resource_size(res));
-                       if (!d->window[k].virt)
-                               goto err2;
-               }
-       }
-
-       d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
-#ifdef CONFIG_INTC_BALANCING
-       if (d->nr_reg)
-               d->nr_reg += hw->nr_mask_regs;
-#endif
-       d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
-       d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
-       d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
-
-       d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
-       if (!d->reg)
-               goto err2;
-
-#ifdef CONFIG_SMP
-       d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
-       if (!d->smp)
-               goto err3;
-#endif
-       k = 0;
-
-       if (hw->mask_regs) {
-               for (i = 0; i < hw->nr_mask_regs; i++) {
-                       smp = IS_SMP(hw->mask_regs[i]);
-                       k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
-                       k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
-#ifdef CONFIG_INTC_BALANCING
-                       k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
-#endif
-               }
-       }
-
-       if (hw->prio_regs) {
-               d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
-                                 GFP_NOWAIT);
-               if (!d->prio)
-                       goto err4;
-
-               for (i = 0; i < hw->nr_prio_regs; i++) {
-                       smp = IS_SMP(hw->prio_regs[i]);
-                       k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
-                       k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
-               }
-       }
-
-       if (hw->sense_regs) {
-               d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
-                                  GFP_NOWAIT);
-               if (!d->sense)
-                       goto err5;
-
-               for (i = 0; i < hw->nr_sense_regs; i++)
-                       k += save_reg(d, k, hw->sense_regs[i].reg, 0);
-       }
-
-       d->chip.name = desc->name;
-       d->chip.mask = intc_disable;
-       d->chip.unmask = intc_enable;
-       d->chip.mask_ack = intc_disable;
-       d->chip.enable = intc_enable;
-       d->chip.disable = intc_disable;
-       d->chip.shutdown = intc_disable;
-       d->chip.set_type = intc_set_sense;
-       d->chip.set_wake = intc_set_wake;
-#ifdef CONFIG_SMP
-       d->chip.set_affinity = intc_set_affinity;
-#endif
-
-       if (hw->ack_regs) {
-               for (i = 0; i < hw->nr_ack_regs; i++)
-                       k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
-
-               d->chip.mask_ack = intc_mask_ack;
-       }
-
-       /* disable bits matching force_disable before registering irqs */
-       if (desc->force_disable)
-               intc_enable_disable_enum(desc, d, desc->force_disable, 0);
-
-       /* disable bits matching force_enable before registering irqs */
-       if (desc->force_enable)
-               intc_enable_disable_enum(desc, d, desc->force_enable, 0);
-
-       BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
-
-       /* register the vectors one by one */
-       for (i = 0; i < hw->nr_vectors; i++) {
-               struct intc_vect *vect = hw->vectors + i;
-               unsigned int irq = evt2irq(vect->vect);
-               struct irq_desc *irq_desc;
-
-               if (!vect->enum_id)
-                       continue;
-
-               irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
-               if (unlikely(!irq_desc)) {
-                       pr_err("can't get irq_desc for %d\n", irq);
-                       continue;
-               }
-
-               intc_register_irq(desc, d, vect->enum_id, irq);
-
-               for (k = i + 1; k < hw->nr_vectors; k++) {
-                       struct intc_vect *vect2 = hw->vectors + k;
-                       unsigned int irq2 = evt2irq(vect2->vect);
-
-                       if (vect->enum_id != vect2->enum_id)
-                               continue;
-
-                       /*
-                        * In the case of multi-evt handling and sparse
-                        * IRQ support, each vector still needs to have
-                        * its own backing irq_desc.
-                        */
-                       irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
-                       if (unlikely(!irq_desc)) {
-                               pr_err("can't get irq_desc for %d\n", irq2);
-                               continue;
-                       }
-
-                       vect2->enum_id = 0;
-
-                       /* redirect this interrupts to the first one */
-                       set_irq_chip(irq2, &dummy_irq_chip);
-                       set_irq_chained_handler(irq2, intc_redirect_irq);
-                       set_irq_data(irq2, (void *)irq);
-               }
-       }
-
-       /* enable bits matching force_enable after registering irqs */
-       if (desc->force_enable)
-               intc_enable_disable_enum(desc, d, desc->force_enable, 1);
-
-       return 0;
-err5:
-       kfree(d->prio);
-err4:
-#ifdef CONFIG_SMP
-       kfree(d->smp);
-err3:
-#endif
-       kfree(d->reg);
-err2:
-       for (k = 0; k < d->nr_windows; k++)
-               if (d->window[k].virt)
-                       iounmap(d->window[k].virt);
-
-       kfree(d->window);
-err1:
-       kfree(d);
-err0:
-       pr_err("unable to allocate INTC memory\n");
-
-       return -ENOMEM;
-}
-
-#ifdef CONFIG_INTC_USERIMASK
-static void __iomem *uimask;
-
-int register_intc_userimask(unsigned long addr)
-{
-       if (unlikely(uimask))
-               return -EBUSY;
-
-       uimask = ioremap_nocache(addr, SZ_4K);
-       if (unlikely(!uimask))
-               return -ENOMEM;
-
-       pr_info("userimask support registered for levels 0 -> %d\n",
-               default_prio_level - 1);
-
-       return 0;
-}
-
-static ssize_t
-show_intc_userimask(struct sysdev_class *cls,
-                   struct sysdev_class_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
-}
-
-static ssize_t
-store_intc_userimask(struct sysdev_class *cls,
-                    struct sysdev_class_attribute *attr,
-                    const char *buf, size_t count)
-{
-       unsigned long level;
-
-       level = simple_strtoul(buf, NULL, 10);
-
-       /*
-        * Minimal acceptable IRQ levels are in the 2 - 16 range, but
-        * these are chomped so as to not interfere with normal IRQs.
-        *
-        * Level 1 is a special case on some CPUs in that it's not
-        * directly settable, but given that USERIMASK cuts off below a
-        * certain level, we don't care about this limitation here.
-        * Level 0 on the other hand equates to user masking disabled.
-        *
-        * We use default_prio_level as a cut off so that only special
-        * case opt-in IRQs can be mangled.
-        */
-       if (level >= default_prio_level)
-               return -EINVAL;
-
-       __raw_writel(0xa5 << 24 | level << 4, uimask);
-
-       return count;
-}
-
-static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
-                        show_intc_userimask, store_intc_userimask);
-#endif
-
-static ssize_t
-show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
-{
-       struct intc_desc_int *d;
-
-       d = container_of(dev, struct intc_desc_int, sysdev);
-
-       return sprintf(buf, "%s\n", d->chip.name);
-}
-
-static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
-
-static int intc_suspend(struct sys_device *dev, pm_message_t state)
-{
-       struct intc_desc_int *d;
-       struct irq_desc *desc;
-       int irq;
-
-       /* get intc controller associated with this sysdev */
-       d = container_of(dev, struct intc_desc_int, sysdev);
-
-       switch (state.event) {
-       case PM_EVENT_ON:
-               if (d->state.event != PM_EVENT_FREEZE)
-                       break;
-               for_each_irq_desc(irq, desc) {
-                       if (desc->handle_irq == intc_redirect_irq)
-                               continue;
-                       if (desc->chip != &d->chip)
-                               continue;
-                       if (desc->status & IRQ_DISABLED)
-                               intc_disable(irq);
-                       else
-                               intc_enable(irq);
-               }
-               break;
-       case PM_EVENT_FREEZE:
-               /* nothing has to be done */
-               break;
-       case PM_EVENT_SUSPEND:
-               /* enable wakeup irqs belonging to this intc controller */
-               for_each_irq_desc(irq, desc) {
-                       if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
-                               intc_enable(irq);
-               }
-               break;
-       }
-       d->state = state;
-
-       return 0;
-}
-
-static int intc_resume(struct sys_device *dev)
-{
-       return intc_suspend(dev, PMSG_ON);
-}
-
-static struct sysdev_class intc_sysdev_class = {
-       .name = "intc",
-       .suspend = intc_suspend,
-       .resume = intc_resume,
-};
-
-/* register this intc as sysdev to allow suspend/resume */
-static int __init register_intc_sysdevs(void)
-{
-       struct intc_desc_int *d;
-       int error;
-       int id = 0;
-
-       error = sysdev_class_register(&intc_sysdev_class);
-#ifdef CONFIG_INTC_USERIMASK
-       if (!error && uimask)
-               error = sysdev_class_create_file(&intc_sysdev_class,
-                                                &attr_userimask);
-#endif
-       if (!error) {
-               list_for_each_entry(d, &intc_list, list) {
-                       d->sysdev.id = id;
-                       d->sysdev.cls = &intc_sysdev_class;
-                       error = sysdev_register(&d->sysdev);
-                       if (error == 0)
-                               error = sysdev_create_file(&d->sysdev,
-                                                          &attr_name);
-                       if (error)
-                               break;
-
-                       id++;
-               }
-       }
-
-       if (error)
-               pr_err("sysdev registration error\n");
-
-       return error;
-}
-device_initcall(register_intc_sysdevs);
-
-/*
- * Dynamic IRQ allocation and deallocation
- */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
-{
-       unsigned int irq = 0, new;
-       unsigned long flags;
-       struct irq_desc *desc;
-
-       spin_lock_irqsave(&vector_lock, flags);
-
-       /*
-        * First try the wanted IRQ
-        */
-       if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
-               new = irq_want;
-       } else {
-               /* .. then fall back to scanning. */
-               new = find_first_zero_bit(intc_irq_map, nr_irqs);
-               if (unlikely(new == nr_irqs))
-                       goto out_unlock;
-
-               __set_bit(new, intc_irq_map);
-       }
-
-       desc = irq_to_desc_alloc_node(new, node);
-       if (unlikely(!desc)) {
-               pr_err("can't get irq_desc for %d\n", new);
-               goto out_unlock;
-       }
-
-       desc = move_irq_desc(desc, node);
-       irq = new;
-
-out_unlock:
-       spin_unlock_irqrestore(&vector_lock, flags);
-
-       if (irq > 0) {
-               dynamic_irq_init(irq);
-#ifdef CONFIG_ARM
-               set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
-       }
-
-       return irq;
-}
-
-int create_irq(void)
-{
-       int nid = cpu_to_node(smp_processor_id());
-       int irq;
-
-       irq = create_irq_nr(NR_IRQS_LEGACY, nid);
-       if (irq == 0)
-               irq = -1;
-
-       return irq;
-}
-
-void destroy_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       dynamic_irq_cleanup(irq);
-
-       spin_lock_irqsave(&vector_lock, flags);
-       __clear_bit(irq, intc_irq_map);
-       spin_unlock_irqrestore(&vector_lock, flags);
-}
-
-int reserve_irq_vector(unsigned int irq)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&vector_lock, flags);
-       if (test_and_set_bit(irq, intc_irq_map))
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&vector_lock, flags);
-
-       return ret;
-}
-
-void reserve_irq_legacy(void)
-{
-       unsigned long flags;
-       int i, j;
-
-       spin_lock_irqsave(&vector_lock, flags);
-       j = find_first_bit(intc_irq_map, nr_irqs);
-       for (i = 0; i < j; i++)
-               __set_bit(i, intc_irq_map);
-       spin_unlock_irqrestore(&vector_lock, flags);
-}
diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig
new file mode 100644 (file)
index 0000000..c88cbcc
--- /dev/null
@@ -0,0 +1,35 @@
+comment "Interrupt controller options"
+
+config INTC_USERIMASK
+       bool "Userspace interrupt masking support"
+       depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
+       help
+         This enables support for hardware-assisted userspace hardirq
+         masking.
+
+         SH-4A and newer interrupt blocks all support a special shadowed
+         page with all non-masking registers obscured when mapped in to
+         userspace. This is primarily for use by userspace device
+         drivers that are using special priority levels.
+
+         If in doubt, say N.
+
+config INTC_BALANCING
+       bool "Hardware IRQ balancing support"
+       depends on SMP && SUPERH && CPU_SHX3
+       help
+         This enables support for IRQ auto-distribution mode on SH-X3
+         SMP parts. All of the balancing and CPU wakeup decisions are
+         taken care of automatically by hardware for distributed
+         vectors.
+
+         If in doubt, say N.
+
+config INTC_MAPPING_DEBUG
+       bool "Expose IRQ to per-controller id mapping via debugfs"
+       depends on DEBUG_FS
+       help
+         This will create a debugfs entry for showing the relationship
+         between system IRQs and the per-controller id tables.
+
+         If in doubt, say N.
diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile
new file mode 100644 (file)
index 0000000..bb5df86
--- /dev/null
@@ -0,0 +1,5 @@
+obj-y  := access.o chip.o core.o dynamic.o handle.o virq.o
+
+obj-$(CONFIG_INTC_BALANCING)           += balancing.o
+obj-$(CONFIG_INTC_USERIMASK)           += userimask.o
+obj-$(CONFIG_INTC_MAPPING_DEBUG)       += virq-debugfs.o
diff --git a/drivers/sh/intc/access.c b/drivers/sh/intc/access.c
new file mode 100644 (file)
index 0000000..f892ae1
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Common INTC2 register accessors
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include "internals.h"
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
+{
+       struct intc_window *window;
+       int k;
+
+       /* scan through physical windows and convert address */
+       for (k = 0; k < d->nr_windows; k++) {
+               window = d->window + k;
+
+               if (address < window->phys)
+                       continue;
+
+               if (address >= (window->phys + window->size))
+                       continue;
+
+               address -= window->phys;
+               address += (unsigned long)window->virt;
+
+               return address;
+       }
+
+       /* no windows defined, register must be 1:1 mapped virt:phys */
+       return address;
+}
+
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
+{
+       unsigned int k;
+
+       address = intc_phys_to_virt(d, address);
+
+       for (k = 0; k < d->nr_reg; k++) {
+               if (d->reg[k] == address)
+                       return k;
+       }
+
+       BUG();
+       return 0;
+}
+
+unsigned int intc_set_field_from_handle(unsigned int value,
+                                       unsigned int field_value,
+                                       unsigned int handle)
+{
+       unsigned int width = _INTC_WIDTH(handle);
+       unsigned int shift = _INTC_SHIFT(handle);
+
+       value &= ~(((1 << width) - 1) << shift);
+       value |= field_value << shift;
+       return value;
+}
+
+unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
+{
+       unsigned int width = _INTC_WIDTH(handle);
+       unsigned int shift = _INTC_SHIFT(handle);
+       unsigned int mask = ((1 << width) - 1) << shift;
+
+       return (value & mask) >> shift;
+}
+
+static unsigned long test_8(unsigned long addr, unsigned long h,
+                           unsigned long ignore)
+{
+       return intc_get_field_from_handle(__raw_readb(addr), h);
+}
+
+static unsigned long test_16(unsigned long addr, unsigned long h,
+                            unsigned long ignore)
+{
+       return intc_get_field_from_handle(__raw_readw(addr), h);
+}
+
+static unsigned long test_32(unsigned long addr, unsigned long h,
+                            unsigned long ignore)
+{
+       return intc_get_field_from_handle(__raw_readl(addr), h);
+}
+
+static unsigned long write_8(unsigned long addr, unsigned long h,
+                            unsigned long data)
+{
+       __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
+       (void)__raw_readb(addr);        /* Defeat write posting */
+       return 0;
+}
+
+static unsigned long write_16(unsigned long addr, unsigned long h,
+                             unsigned long data)
+{
+       __raw_writew(intc_set_field_from_handle(0, data, h), addr);
+       (void)__raw_readw(addr);        /* Defeat write posting */
+       return 0;
+}
+
+static unsigned long write_32(unsigned long addr, unsigned long h,
+                             unsigned long data)
+{
+       __raw_writel(intc_set_field_from_handle(0, data, h), addr);
+       (void)__raw_readl(addr);        /* Defeat write posting */
+       return 0;
+}
+
+static unsigned long modify_8(unsigned long addr, unsigned long h,
+                             unsigned long data)
+{
+       unsigned long flags;
+       unsigned int value;
+       local_irq_save(flags);
+       value = intc_set_field_from_handle(__raw_readb(addr), data, h);
+       __raw_writeb(value, addr);
+       (void)__raw_readb(addr);        /* Defeat write posting */
+       local_irq_restore(flags);
+       return 0;
+}
+
+static unsigned long modify_16(unsigned long addr, unsigned long h,
+                              unsigned long data)
+{
+       unsigned long flags;
+       unsigned int value;
+       local_irq_save(flags);
+       value = intc_set_field_from_handle(__raw_readw(addr), data, h);
+       __raw_writew(value, addr);
+       (void)__raw_readw(addr);        /* Defeat write posting */
+       local_irq_restore(flags);
+       return 0;
+}
+
+static unsigned long modify_32(unsigned long addr, unsigned long h,
+                              unsigned long data)
+{
+       unsigned long flags;
+       unsigned int value;
+       local_irq_save(flags);
+       value = intc_set_field_from_handle(__raw_readl(addr), data, h);
+       __raw_writel(value, addr);
+       (void)__raw_readl(addr);        /* Defeat write posting */
+       local_irq_restore(flags);
+       return 0;
+}
+
+static unsigned long intc_mode_field(unsigned long addr,
+                                    unsigned long handle,
+                                    unsigned long (*fn)(unsigned long,
+                                               unsigned long,
+                                               unsigned long),
+                                    unsigned int irq)
+{
+       return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
+}
+
+static unsigned long intc_mode_zero(unsigned long addr,
+                                   unsigned long handle,
+                                   unsigned long (*fn)(unsigned long,
+                                              unsigned long,
+                                              unsigned long),
+                                   unsigned int irq)
+{
+       return fn(addr, handle, 0);
+}
+
+static unsigned long intc_mode_prio(unsigned long addr,
+                                   unsigned long handle,
+                                   unsigned long (*fn)(unsigned long,
+                                              unsigned long,
+                                              unsigned long),
+                                   unsigned int irq)
+{
+       return fn(addr, handle, intc_get_prio_level(irq));
+}
+
+unsigned long (*intc_reg_fns[])(unsigned long addr,
+                               unsigned long h,
+                               unsigned long data) = {
+       [REG_FN_TEST_BASE + 0] = test_8,
+       [REG_FN_TEST_BASE + 1] = test_16,
+       [REG_FN_TEST_BASE + 3] = test_32,
+       [REG_FN_WRITE_BASE + 0] = write_8,
+       [REG_FN_WRITE_BASE + 1] = write_16,
+       [REG_FN_WRITE_BASE + 3] = write_32,
+       [REG_FN_MODIFY_BASE + 0] = modify_8,
+       [REG_FN_MODIFY_BASE + 1] = modify_16,
+       [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+unsigned long (*intc_enable_fns[])(unsigned long addr,
+                                  unsigned long handle,
+                                  unsigned long (*fn)(unsigned long,
+                                           unsigned long,
+                                           unsigned long),
+                                  unsigned int irq) = {
+       [MODE_ENABLE_REG] = intc_mode_field,
+       [MODE_MASK_REG] = intc_mode_zero,
+       [MODE_DUAL_REG] = intc_mode_field,
+       [MODE_PRIO_REG] = intc_mode_prio,
+       [MODE_PCLR_REG] = intc_mode_prio,
+};
+
+unsigned long (*intc_disable_fns[])(unsigned long addr,
+                                   unsigned long handle,
+                                   unsigned long (*fn)(unsigned long,
+                                            unsigned long,
+                                            unsigned long),
+                                   unsigned int irq) = {
+       [MODE_ENABLE_REG] = intc_mode_zero,
+       [MODE_MASK_REG] = intc_mode_field,
+       [MODE_DUAL_REG] = intc_mode_field,
+       [MODE_PRIO_REG] = intc_mode_zero,
+       [MODE_PCLR_REG] = intc_mode_field,
+};
+
+unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
+                                         unsigned long handle,
+                                         unsigned long (*fn)(unsigned long,
+                                               unsigned long,
+                                               unsigned long),
+                                         unsigned int irq) = {
+       [MODE_ENABLE_REG] = intc_mode_field,
+       [MODE_MASK_REG] = intc_mode_zero,
+       [MODE_DUAL_REG] = intc_mode_field,
+       [MODE_PRIO_REG] = intc_mode_field,
+       [MODE_PCLR_REG] = intc_mode_field,
+};
diff --git a/drivers/sh/intc/balancing.c b/drivers/sh/intc/balancing.c
new file mode 100644 (file)
index 0000000..cec7a96
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Support for hardware-managed IRQ auto-distribution.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include "internals.h"
+
+static unsigned long dist_handle[NR_IRQS];
+
+void intc_balancing_enable(unsigned int irq)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long handle = dist_handle[irq];
+       unsigned long addr;
+
+       if (irq_balancing_disabled(irq) || !handle)
+               return;
+
+       addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+       intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
+}
+
+void intc_balancing_disable(unsigned int irq)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long handle = dist_handle[irq];
+       unsigned long addr;
+
+       if (irq_balancing_disabled(irq) || !handle)
+               return;
+
+       addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+       intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
+}
+
+static unsigned int intc_dist_data(struct intc_desc *desc,
+                                  struct intc_desc_int *d,
+                                  intc_enum enum_id)
+{
+       struct intc_mask_reg *mr = desc->hw.mask_regs;
+       unsigned int i, j, fn, mode;
+       unsigned long reg_e, reg_d;
+
+       for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
+               mr = desc->hw.mask_regs + i;
+
+               /*
+                * Skip this entry if there's no auto-distribution
+                * register associated with it.
+                */
+               if (!mr->dist_reg)
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+                       if (mr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = REG_FN_MODIFY_BASE;
+                       mode = MODE_ENABLE_REG;
+                       reg_e = mr->dist_reg;
+                       reg_d = mr->dist_reg;
+
+                       fn += (mr->reg_width >> 3) - 1;
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       1,
+                                       (mr->reg_width - 1) - j);
+               }
+       }
+
+       /*
+        * It's possible we've gotten here with no distribution options
+        * available for the IRQ in question, so we just skip over those.
+        */
+       return 0;
+}
+
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+                         struct intc_desc_int *d, intc_enum id)
+{
+       unsigned long flags;
+
+       /*
+        * Nothing to do for this IRQ.
+        */
+       if (!desc->hw.mask_regs)
+               return;
+
+       raw_spin_lock_irqsave(&intc_big_lock, flags);
+       dist_handle[irq] = intc_dist_data(desc, d, id);
+       raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
new file mode 100644 (file)
index 0000000..35c0370
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * IRQ chip definitions for INTC IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include "internals.h"
+
+void _intc_enable(unsigned int irq, unsigned long handle)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long addr;
+       unsigned int cpu;
+
+       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+#ifdef CONFIG_SMP
+               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+                       continue;
+#endif
+               addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+               intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+                                                   [_INTC_FN(handle)], irq);
+       }
+
+       intc_balancing_enable(irq);
+}
+
+static void intc_enable(unsigned int irq)
+{
+       _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
+}
+
+static void intc_disable(unsigned int irq)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long handle = (unsigned long)get_irq_chip_data(irq);
+       unsigned long addr;
+       unsigned int cpu;
+
+       intc_balancing_disable(irq);
+
+       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+#ifdef CONFIG_SMP
+               if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+                       continue;
+#endif
+               addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+               intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+                                                    [_INTC_FN(handle)], irq);
+       }
+}
+
+static int intc_set_wake(unsigned int irq, unsigned int on)
+{
+       return 0; /* allow wakeup, but setup hardware in intc_suspend() */
+}
+
+#ifdef CONFIG_SMP
+/*
+ * This is held with the irq desc lock held, so we don't require any
+ * additional locking here at the intc desc level. The affinity mask is
+ * later tested in the enable/disable paths.
+ */
+static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+{
+       if (!cpumask_intersects(cpumask, cpu_online_mask))
+               return -1;
+
+       cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
+
+       return 0;
+}
+#endif
+
+static void intc_mask_ack(unsigned int irq)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long handle = intc_get_ack_handle(irq);
+       unsigned long addr;
+
+       intc_disable(irq);
+
+       /* read register and write zero only to the associated bit */
+       if (handle) {
+               unsigned int value;
+
+               addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+               value = intc_set_field_from_handle(0, 1, handle);
+
+               switch (_INTC_FN(handle)) {
+               case REG_FN_MODIFY_BASE + 0:    /* 8bit */
+                       __raw_readb(addr);
+                       __raw_writeb(0xff ^ value, addr);
+                       break;
+               case REG_FN_MODIFY_BASE + 1:    /* 16bit */
+                       __raw_readw(addr);
+                       __raw_writew(0xffff ^ value, addr);
+                       break;
+               case REG_FN_MODIFY_BASE + 3:    /* 32bit */
+                       __raw_readl(addr);
+                       __raw_writel(0xffffffff ^ value, addr);
+                       break;
+               default:
+                       BUG();
+                       break;
+               }
+       }
+}
+
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+                                            unsigned int nr_hp,
+                                            unsigned int irq)
+{
+       int i;
+
+       /*
+        * this doesn't scale well, but...
+        *
+        * this function should only be used for cerain uncommon
+        * operations such as intc_set_priority() and intc_set_type()
+        * and in those rare cases performance doesn't matter that much.
+        * keeping the memory footprint low is more important.
+        *
+        * one rather simple way to speed this up and still keep the
+        * memory footprint down is to make sure the array is sorted
+        * and then perform a bisect to lookup the irq.
+        */
+       for (i = 0; i < nr_hp; i++) {
+               if ((hp + i)->irq != irq)
+                       continue;
+
+               return hp + i;
+       }
+
+       return NULL;
+}
+
+int intc_set_priority(unsigned int irq, unsigned int prio)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       struct intc_handle_int *ihp;
+
+       if (!intc_get_prio_level(irq) || prio <= 1)
+               return -EINVAL;
+
+       ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+       if (ihp) {
+               if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+                       return -EINVAL;
+
+               intc_set_prio_level(irq, prio);
+
+               /*
+                * only set secondary masking method directly
+                * primary masking method is using intc_prio_level[irq]
+                * priority level will be set during next enable()
+                */
+               if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+                       _intc_enable(irq, ihp->handle);
+       }
+       return 0;
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+       [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+       [IRQ_TYPE_EDGE_RISING] = VALID(1),
+       [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+       /* SH7706, SH7707 and SH7709 do not support high level triggered */
+#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7709)
+       [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+#endif
+};
+
+static int intc_set_type(unsigned int irq, unsigned int type)
+{
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+       struct intc_handle_int *ihp;
+       unsigned long addr;
+
+       if (!value)
+               return -EINVAL;
+
+       ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+       if (ihp) {
+               addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+       }
+
+       return 0;
+}
+
+struct irq_chip intc_irq_chip  = {
+       .mask           = intc_disable,
+       .unmask         = intc_enable,
+       .mask_ack       = intc_mask_ack,
+       .enable         = intc_enable,
+       .disable        = intc_disable,
+       .shutdown       = intc_disable,
+       .set_type       = intc_set_type,
+       .set_wake       = intc_set_wake,
+#ifdef CONFIG_SMP
+       .set_affinity   = intc_set_affinity,
+#endif
+};
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
new file mode 100644 (file)
index 0000000..306ed28
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000  Kazumoto Kojima
+ * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sh_intc.h>
+#include <linux/sysdev.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/radix-tree.h>
+#include "internals.h"
+
+LIST_HEAD(intc_list);
+DEFINE_RAW_SPINLOCK(intc_big_lock);
+unsigned int nr_intc_controllers;
+
+/*
+ * Default priority level
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+static unsigned int default_prio_level = 2;    /* 2 - 16 */
+static unsigned int intc_prio_level[NR_IRQS];  /* for now */
+
+unsigned int intc_get_dfl_prio_level(void)
+{
+       return default_prio_level;
+}
+
+unsigned int intc_get_prio_level(unsigned int irq)
+{
+       return intc_prio_level[irq];
+}
+
+void intc_set_prio_level(unsigned int irq, unsigned int level)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&intc_big_lock, flags);
+       intc_prio_level[irq] = level;
+       raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
+{
+       generic_handle_irq((unsigned int)get_irq_data(irq));
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+                                    struct intc_desc_int *d,
+                                    intc_enum enum_id,
+                                    unsigned int irq)
+{
+       struct intc_handle_int *hp;
+       unsigned int data[2], primary;
+       unsigned long flags;
+
+       /*
+        * Register the IRQ position with the global IRQ map, then insert
+        * it in to the radix tree.
+        */
+       reserve_irq_vector(irq);
+
+       raw_spin_lock_irqsave(&intc_big_lock, flags);
+       radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
+       raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+
+       /*
+        * Prefer single interrupt source bitmap over other combinations:
+        *
+        * 1. bitmap, single interrupt source
+        * 2. priority, single interrupt source
+        * 3. bitmap, multiple interrupt sources (groups)
+        * 4. priority, multiple interrupt sources (groups)
+        */
+       data[0] = intc_get_mask_handle(desc, d, enum_id, 0);
+       data[1] = intc_get_prio_handle(desc, d, enum_id, 0);
+
+       primary = 0;
+       if (!data[0] && data[1])
+               primary = 1;
+
+       if (!data[0] && !data[1])
+               pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
+                          irq, irq2evt(irq));
+
+       data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1);
+       data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1);
+
+       if (!data[primary])
+               primary ^= 1;
+
+       BUG_ON(!data[primary]); /* must have primary masking method */
+
+       disable_irq_nosync(irq);
+       set_irq_chip_and_handler_name(irq, &d->chip,
+                                     handle_level_irq, "level");
+       set_irq_chip_data(irq, (void *)data[primary]);
+
+       /*
+        * set priority level
+        */
+       intc_set_prio_level(irq, intc_get_dfl_prio_level());
+
+       /* enable secondary masking method if present */
+       if (data[!primary])
+               _intc_enable(irq, data[!primary]);
+
+       /* add irq to d->prio list if priority is available */
+       if (data[1]) {
+               hp = d->prio + d->nr_prio;
+               hp->irq = irq;
+               hp->handle = data[1];
+
+               if (primary) {
+                       /*
+                        * only secondary priority should access registers, so
+                        * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+                        */
+                       hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+                       hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+               }
+               d->nr_prio++;
+       }
+
+       /* add irq to d->sense list if sense is available */
+       data[0] = intc_get_sense_handle(desc, d, enum_id);
+       if (data[0]) {
+               (d->sense + d->nr_sense)->irq = irq;
+               (d->sense + d->nr_sense)->handle = data[0];
+               d->nr_sense++;
+       }
+
+       /* irq should be disabled by default */
+       d->chip.mask(irq);
+
+       intc_set_ack_handle(irq, desc, d, enum_id);
+       intc_set_dist_handle(irq, desc, d, enum_id);
+
+       activate_irq(irq);
+}
+
+static unsigned int __init save_reg(struct intc_desc_int *d,
+                                   unsigned int cnt,
+                                   unsigned long value,
+                                   unsigned int smp)
+{
+       if (value) {
+               value = intc_phys_to_virt(d, value);
+
+               d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+               d->smp[cnt] = smp;
+#endif
+               return 1;
+       }
+
+       return 0;
+}
+
+int __init register_intc_controller(struct intc_desc *desc)
+{
+       unsigned int i, k, smp;
+       struct intc_hw_desc *hw = &desc->hw;
+       struct intc_desc_int *d;
+       struct resource *res;
+
+       pr_info("Registered controller '%s' with %u IRQs\n",
+               desc->name, hw->nr_vectors);
+
+       d = kzalloc(sizeof(*d), GFP_NOWAIT);
+       if (!d)
+               goto err0;
+
+       INIT_LIST_HEAD(&d->list);
+       list_add_tail(&d->list, &intc_list);
+
+       raw_spin_lock_init(&d->lock);
+
+       d->index = nr_intc_controllers;
+
+       if (desc->num_resources) {
+               d->nr_windows = desc->num_resources;
+               d->window = kzalloc(d->nr_windows * sizeof(*d->window),
+                                   GFP_NOWAIT);
+               if (!d->window)
+                       goto err1;
+
+               for (k = 0; k < d->nr_windows; k++) {
+                       res = desc->resource + k;
+                       WARN_ON(resource_type(res) != IORESOURCE_MEM);
+                       d->window[k].phys = res->start;
+                       d->window[k].size = resource_size(res);
+                       d->window[k].virt = ioremap_nocache(res->start,
+                                                        resource_size(res));
+                       if (!d->window[k].virt)
+                               goto err2;
+               }
+       }
+
+       d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
+#ifdef CONFIG_INTC_BALANCING
+       if (d->nr_reg)
+               d->nr_reg += hw->nr_mask_regs;
+#endif
+       d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
+       d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
+       d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
+       d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0;
+
+       d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
+       if (!d->reg)
+               goto err2;
+
+#ifdef CONFIG_SMP
+       d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
+       if (!d->smp)
+               goto err3;
+#endif
+       k = 0;
+
+       if (hw->mask_regs) {
+               for (i = 0; i < hw->nr_mask_regs; i++) {
+                       smp = IS_SMP(hw->mask_regs[i]);
+                       k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
+                       k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
+#ifdef CONFIG_INTC_BALANCING
+                       k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
+#endif
+               }
+       }
+
+       if (hw->prio_regs) {
+               d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
+                                 GFP_NOWAIT);
+               if (!d->prio)
+                       goto err4;
+
+               for (i = 0; i < hw->nr_prio_regs; i++) {
+                       smp = IS_SMP(hw->prio_regs[i]);
+                       k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
+                       k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
+               }
+       }
+
+       if (hw->sense_regs) {
+               d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
+                                  GFP_NOWAIT);
+               if (!d->sense)
+                       goto err5;
+
+               for (i = 0; i < hw->nr_sense_regs; i++)
+                       k += save_reg(d, k, hw->sense_regs[i].reg, 0);
+       }
+
+       if (hw->subgroups)
+               for (i = 0; i < hw->nr_subgroups; i++)
+                       if (hw->subgroups[i].reg)
+                               k+= save_reg(d, k, hw->subgroups[i].reg, 0);
+
+       memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip));
+       d->chip.name = desc->name;
+
+       if (hw->ack_regs)
+               for (i = 0; i < hw->nr_ack_regs; i++)
+                       k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
+       else
+               d->chip.mask_ack = d->chip.disable;
+
+       /* disable bits matching force_disable before registering irqs */
+       if (desc->force_disable)
+               intc_enable_disable_enum(desc, d, desc->force_disable, 0);
+
+       /* disable bits matching force_enable before registering irqs */
+       if (desc->force_enable)
+               intc_enable_disable_enum(desc, d, desc->force_enable, 0);
+
+       BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
+
+       /* register the vectors one by one */
+       for (i = 0; i < hw->nr_vectors; i++) {
+               struct intc_vect *vect = hw->vectors + i;
+               unsigned int irq = evt2irq(vect->vect);
+               struct irq_desc *irq_desc;
+
+               if (!vect->enum_id)
+                       continue;
+
+               irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
+               if (unlikely(!irq_desc)) {
+                       pr_err("can't get irq_desc for %d\n", irq);
+                       continue;
+               }
+
+               intc_irq_xlate_set(irq, vect->enum_id, d);
+               intc_register_irq(desc, d, vect->enum_id, irq);
+
+               for (k = i + 1; k < hw->nr_vectors; k++) {
+                       struct intc_vect *vect2 = hw->vectors + k;
+                       unsigned int irq2 = evt2irq(vect2->vect);
+
+                       if (vect->enum_id != vect2->enum_id)
+                               continue;
+
+                       /*
+                        * In the case of multi-evt handling and sparse
+                        * IRQ support, each vector still needs to have
+                        * its own backing irq_desc.
+                        */
+                       irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
+                       if (unlikely(!irq_desc)) {
+                               pr_err("can't get irq_desc for %d\n", irq2);
+                               continue;
+                       }
+
+                       vect2->enum_id = 0;
+
+                       /* redirect this interrupts to the first one */
+                       set_irq_chip(irq2, &dummy_irq_chip);
+                       set_irq_chained_handler(irq2, intc_redirect_irq);
+                       set_irq_data(irq2, (void *)irq);
+               }
+       }
+
+       intc_subgroup_init(desc, d);
+
+       /* enable bits matching force_enable after registering irqs */
+       if (desc->force_enable)
+               intc_enable_disable_enum(desc, d, desc->force_enable, 1);
+
+       nr_intc_controllers++;
+
+       return 0;
+err5:
+       kfree(d->prio);
+err4:
+#ifdef CONFIG_SMP
+       kfree(d->smp);
+err3:
+#endif
+       kfree(d->reg);
+err2:
+       for (k = 0; k < d->nr_windows; k++)
+               if (d->window[k].virt)
+                       iounmap(d->window[k].virt);
+
+       kfree(d->window);
+err1:
+       kfree(d);
+err0:
+       pr_err("unable to allocate INTC memory\n");
+
+       return -ENOMEM;
+}
+
+static ssize_t
+show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+       struct intc_desc_int *d;
+
+       d = container_of(dev, struct intc_desc_int, sysdev);
+
+       return sprintf(buf, "%s\n", d->chip.name);
+}
+
+static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+
+static int intc_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct intc_desc_int *d;
+       struct irq_desc *desc;
+       int irq;
+
+       /* get intc controller associated with this sysdev */
+       d = container_of(dev, struct intc_desc_int, sysdev);
+
+       switch (state.event) {
+       case PM_EVENT_ON:
+               if (d->state.event != PM_EVENT_FREEZE)
+                       break;
+
+               for_each_irq_desc(irq, desc) {
+                       /*
+                        * This will catch the redirect and VIRQ cases
+                        * due to the dummy_irq_chip being inserted.
+                        */
+                       if (desc->chip != &d->chip)
+                               continue;
+                       if (desc->status & IRQ_DISABLED)
+                               desc->chip->disable(irq);
+                       else
+                               desc->chip->enable(irq);
+               }
+               break;
+       case PM_EVENT_FREEZE:
+               /* nothing has to be done */
+               break;
+       case PM_EVENT_SUSPEND:
+               /* enable wakeup irqs belonging to this intc controller */
+               for_each_irq_desc(irq, desc) {
+                       if (desc->chip != &d->chip)
+                               continue;
+                       if ((desc->status & IRQ_WAKEUP))
+                               desc->chip->enable(irq);
+               }
+               break;
+       }
+
+       d->state = state;
+
+       return 0;
+}
+
+static int intc_resume(struct sys_device *dev)
+{
+       return intc_suspend(dev, PMSG_ON);
+}
+
+struct sysdev_class intc_sysdev_class = {
+       .name           = "intc",
+       .suspend        = intc_suspend,
+       .resume         = intc_resume,
+};
+
+/* register this intc as sysdev to allow suspend/resume */
+static int __init register_intc_sysdevs(void)
+{
+       struct intc_desc_int *d;
+       int error;
+
+       error = sysdev_class_register(&intc_sysdev_class);
+       if (!error) {
+               list_for_each_entry(d, &intc_list, list) {
+                       d->sysdev.id = d->index;
+                       d->sysdev.cls = &intc_sysdev_class;
+                       error = sysdev_register(&d->sysdev);
+                       if (error == 0)
+                               error = sysdev_create_file(&d->sysdev,
+                                                          &attr_name);
+                       if (error)
+                               break;
+               }
+       }
+
+       if (error)
+               pr_err("sysdev registration error\n");
+
+       return error;
+}
+device_initcall(register_intc_sysdevs);
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
new file mode 100644 (file)
index 0000000..6caecdf
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Dynamic IRQ management
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * Modelled after arch/x86/kernel/apic/io_apic.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/irq.h>
+#include <linux/bitmap.h>
+#include <linux/spinlock.h>
+#include "internals.h" /* only for activate_irq() damage.. */
+
+/*
+ * The intc_irq_map provides a global map of bound IRQ vectors for a
+ * given platform. Allocation of IRQs are either static through the CPU
+ * vector map, or dynamic in the case of board mux vectors or MSI.
+ *
+ * As this is a central point for all IRQ controllers on the system,
+ * each of the available sources are mapped out here. This combined with
+ * sparseirq makes it quite trivial to keep the vector map tightly packed
+ * when dynamically creating IRQs, as well as tying in to otherwise
+ * unused irq_desc positions in the sparse array.
+ */
+static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
+static DEFINE_RAW_SPINLOCK(vector_lock);
+
+/*
+ * Dynamic IRQ allocation and deallocation
+ */
+unsigned int create_irq_nr(unsigned int irq_want, int node)
+{
+       unsigned int irq = 0, new;
+       unsigned long flags;
+       struct irq_desc *desc;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+
+       /*
+        * First try the wanted IRQ
+        */
+       if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
+               new = irq_want;
+       } else {
+               /* .. then fall back to scanning. */
+               new = find_first_zero_bit(intc_irq_map, nr_irqs);
+               if (unlikely(new == nr_irqs))
+                       goto out_unlock;
+
+               __set_bit(new, intc_irq_map);
+       }
+
+       desc = irq_to_desc_alloc_node(new, node);
+       if (unlikely(!desc)) {
+               pr_err("can't get irq_desc for %d\n", new);
+               goto out_unlock;
+       }
+
+       desc = move_irq_desc(desc, node);
+       irq = new;
+
+out_unlock:
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+       if (irq > 0) {
+               dynamic_irq_init(irq);
+               activate_irq(irq);
+       }
+
+       return irq;
+}
+
+int create_irq(void)
+{
+       int nid = cpu_to_node(smp_processor_id());
+       int irq;
+
+       irq = create_irq_nr(NR_IRQS_LEGACY, nid);
+       if (irq == 0)
+               irq = -1;
+
+       return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       dynamic_irq_cleanup(irq);
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       __clear_bit(irq, intc_irq_map);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+int reserve_irq_vector(unsigned int irq)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       if (test_and_set_bit(irq, intc_irq_map))
+               ret = -EBUSY;
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+       return ret;
+}
+
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
+{
+       unsigned long flags;
+       int i;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       for (i = 0; i < nr_vecs; i++)
+               __set_bit(evt2irq(vectors[i].vect), intc_irq_map);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+void reserve_irq_legacy(void)
+{
+       unsigned long flags;
+       int i, j;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       j = find_first_bit(intc_irq_map, nr_irqs);
+       for (i = 0; i < j; i++)
+               __set_bit(i, intc_irq_map);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
diff --git a/drivers/sh/intc/handle.c b/drivers/sh/intc/handle.c
new file mode 100644 (file)
index 0000000..057ce56
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static unsigned long ack_handle[NR_IRQS];
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+                                   intc_enum enum_id)
+{
+       struct intc_group *g = desc->hw.groups;
+       unsigned int i, j;
+
+       for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
+               g = desc->hw.groups + i;
+
+               for (j = 0; g->enum_ids[j]; j++) {
+                       if (g->enum_ids[j] != enum_id)
+                               continue;
+
+                       return g->enum_id;
+               }
+       }
+
+       return 0;
+}
+
+static unsigned int __init _intc_mask_data(struct intc_desc *desc,
+                                          struct intc_desc_int *d,
+                                          intc_enum enum_id,
+                                          unsigned int *reg_idx,
+                                          unsigned int *fld_idx)
+{
+       struct intc_mask_reg *mr = desc->hw.mask_regs;
+       unsigned int fn, mode;
+       unsigned long reg_e, reg_d;
+
+       while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
+               mr = desc->hw.mask_regs + *reg_idx;
+
+               for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
+                       if (mr->enum_ids[*fld_idx] != enum_id)
+                               continue;
+
+                       if (mr->set_reg && mr->clr_reg) {
+                               fn = REG_FN_WRITE_BASE;
+                               mode = MODE_DUAL_REG;
+                               reg_e = mr->clr_reg;
+                               reg_d = mr->set_reg;
+                       } else {
+                               fn = REG_FN_MODIFY_BASE;
+                               if (mr->set_reg) {
+                                       mode = MODE_ENABLE_REG;
+                                       reg_e = mr->set_reg;
+                                       reg_d = mr->set_reg;
+                               } else {
+                                       mode = MODE_MASK_REG;
+                                       reg_e = mr->clr_reg;
+                                       reg_d = mr->clr_reg;
+                               }
+                       }
+
+                       fn += (mr->reg_width >> 3) - 1;
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       1,
+                                       (mr->reg_width - 1) - *fld_idx);
+               }
+
+               *fld_idx = 0;
+               (*reg_idx)++;
+       }
+
+       return 0;
+}
+
+unsigned int __init
+intc_get_mask_handle(struct intc_desc *desc, struct intc_desc_int *d,
+                    intc_enum enum_id, int do_grps)
+{
+       unsigned int i = 0;
+       unsigned int j = 0;
+       unsigned int ret;
+
+       ret = _intc_mask_data(desc, d, enum_id, &i, &j);
+       if (ret)
+               return ret;
+
+       if (do_grps)
+               return intc_get_mask_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static unsigned int __init _intc_prio_data(struct intc_desc *desc,
+                                          struct intc_desc_int *d,
+                                          intc_enum enum_id,
+                                          unsigned int *reg_idx,
+                                          unsigned int *fld_idx)
+{
+       struct intc_prio_reg *pr = desc->hw.prio_regs;
+       unsigned int fn, n, mode, bit;
+       unsigned long reg_e, reg_d;
+
+       while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
+               pr = desc->hw.prio_regs + *reg_idx;
+
+               for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
+                       if (pr->enum_ids[*fld_idx] != enum_id)
+                               continue;
+
+                       if (pr->set_reg && pr->clr_reg) {
+                               fn = REG_FN_WRITE_BASE;
+                               mode = MODE_PCLR_REG;
+                               reg_e = pr->set_reg;
+                               reg_d = pr->clr_reg;
+                       } else {
+                               fn = REG_FN_MODIFY_BASE;
+                               mode = MODE_PRIO_REG;
+                               if (!pr->set_reg)
+                                       BUG();
+                               reg_e = pr->set_reg;
+                               reg_d = pr->set_reg;
+                       }
+
+                       fn += (pr->reg_width >> 3) - 1;
+                       n = *fld_idx + 1;
+
+                       BUG_ON(n * pr->field_width > pr->reg_width);
+
+                       bit = pr->reg_width - (n * pr->field_width);
+
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       pr->field_width, bit);
+               }
+
+               *fld_idx = 0;
+               (*reg_idx)++;
+       }
+
+       return 0;
+}
+
+unsigned int __init
+intc_get_prio_handle(struct intc_desc *desc, struct intc_desc_int *d,
+                    intc_enum enum_id, int do_grps)
+{
+       unsigned int i = 0;
+       unsigned int j = 0;
+       unsigned int ret;
+
+       ret = _intc_prio_data(desc, d, enum_id, &i, &j);
+       if (ret)
+               return ret;
+
+       if (do_grps)
+               return intc_get_prio_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static unsigned int __init intc_ack_data(struct intc_desc *desc,
+                                         struct intc_desc_int *d,
+                                         intc_enum enum_id)
+{
+       struct intc_mask_reg *mr = desc->hw.ack_regs;
+       unsigned int i, j, fn, mode;
+       unsigned long reg_e, reg_d;
+
+       for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
+               mr = desc->hw.ack_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+                       if (mr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = REG_FN_MODIFY_BASE;
+                       mode = MODE_ENABLE_REG;
+                       reg_e = mr->set_reg;
+                       reg_d = mr->set_reg;
+
+                       fn += (mr->reg_width >> 3) - 1;
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       1,
+                                       (mr->reg_width - 1) - j);
+               }
+       }
+
+       return 0;
+}
+
+static void intc_enable_disable(struct intc_desc_int *d,
+                               unsigned long handle, int do_enable)
+{
+       unsigned long addr;
+       unsigned int cpu;
+       unsigned long (*fn)(unsigned long, unsigned long,
+                  unsigned long (*)(unsigned long, unsigned long,
+                                    unsigned long),
+                  unsigned int);
+
+       if (do_enable) {
+               for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+                       addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+                       fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
+                       fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+               }
+       } else {
+               for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+                       addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+                       fn = intc_disable_fns[_INTC_MODE(handle)];
+                       fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+               }
+       }
+}
+
+void __init intc_enable_disable_enum(struct intc_desc *desc,
+                                    struct intc_desc_int *d,
+                                    intc_enum enum_id, int enable)
+{
+       unsigned int i, j, data;
+
+       /* go through and enable/disable all mask bits */
+       i = j = 0;
+       do {
+               data = _intc_mask_data(desc, d, enum_id, &i, &j);
+               if (data)
+                       intc_enable_disable(d, data, enable);
+               j++;
+       } while (data);
+
+       /* go through and enable/disable all priority fields */
+       i = j = 0;
+       do {
+               data = _intc_prio_data(desc, d, enum_id, &i, &j);
+               if (data)
+                       intc_enable_disable(d, data, enable);
+
+               j++;
+       } while (data);
+}
+
+unsigned int __init
+intc_get_sense_handle(struct intc_desc *desc, struct intc_desc_int *d,
+                     intc_enum enum_id)
+{
+       struct intc_sense_reg *sr = desc->hw.sense_regs;
+       unsigned int i, j, fn, bit;
+
+       for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
+               sr = desc->hw.sense_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+                       if (sr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = REG_FN_MODIFY_BASE;
+                       fn += (sr->reg_width >> 3) - 1;
+
+                       BUG_ON((j + 1) * sr->field_width > sr->reg_width);
+
+                       bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+                       return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+                                       0, sr->field_width, bit);
+               }
+       }
+
+       return 0;
+}
+
+
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+                        struct intc_desc_int *d, intc_enum id)
+{
+       unsigned long flags;
+
+       /*
+        * Nothing to do for this IRQ.
+        */
+       if (!desc->hw.ack_regs)
+               return;
+
+       raw_spin_lock_irqsave(&intc_big_lock, flags);
+       ack_handle[irq] = intc_ack_data(desc, d, id);
+       raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+unsigned long intc_get_ack_handle(unsigned int irq)
+{
+       return ack_handle[irq];
+}
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
new file mode 100644 (file)
index 0000000..d49482c
--- /dev/null
@@ -0,0 +1,186 @@
+#include <linux/sh_intc.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/radix-tree.h>
+#include <linux/sysdev.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+       ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+        ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h)         (h & 0x1f)
+#define _INTC_WIDTH(h)         ((h >> 5) & 0xf)
+#define _INTC_FN(h)            ((h >> 9) & 0xf)
+#define _INTC_MODE(h)          ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h)                ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h)                ((h >> 24) & 0xff)
+
+#ifdef CONFIG_SMP
+#define IS_SMP(x)              (x.smp)
+#define INTC_REG(d, x, c)      (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x)           ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x)              0
+#define INTC_REG(d, x, c)      (d->reg[(x)])
+#define SMP_NR(d, x)           1
+#endif
+
+struct intc_handle_int {
+       unsigned int irq;
+       unsigned long handle;
+};
+
+struct intc_window {
+       phys_addr_t phys;
+       void __iomem *virt;
+       unsigned long size;
+};
+
+struct intc_map_entry {
+       intc_enum enum_id;
+       struct intc_desc_int *desc;
+};
+
+struct intc_subgroup_entry {
+       unsigned int pirq;
+       intc_enum enum_id;
+       unsigned long handle;
+};
+
+struct intc_desc_int {
+       struct list_head list;
+       struct sys_device sysdev;
+       struct radix_tree_root tree;
+       pm_message_t state;
+       raw_spinlock_t lock;
+       unsigned int index;
+       unsigned long *reg;
+#ifdef CONFIG_SMP
+       unsigned long *smp;
+#endif
+       unsigned int nr_reg;
+       struct intc_handle_int *prio;
+       unsigned int nr_prio;
+       struct intc_handle_int *sense;
+       unsigned int nr_sense;
+       struct intc_window *window;
+       unsigned int nr_windows;
+       struct irq_chip chip;
+};
+
+
+enum {
+       REG_FN_ERR = 0,
+       REG_FN_TEST_BASE = 1,
+       REG_FN_WRITE_BASE = 5,
+       REG_FN_MODIFY_BASE = 9
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+       MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
+       MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
+       MODE_PRIO_REG,       /* Priority value written to enable interrupt */
+       MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
+};
+
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
+{
+       struct irq_chip *chip = get_irq_chip(irq);
+
+       return container_of(chip, struct intc_desc_int, chip);
+}
+
+/*
+ * Grumble.
+ */
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+        */
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       /* same effect on other architectures */
+       set_irq_noprobe(irq);
+#endif
+}
+
+/* access.c */
+extern unsigned long
+(*intc_reg_fns[])(unsigned long addr, unsigned long h, unsigned long data);
+
+extern unsigned long
+(*intc_enable_fns[])(unsigned long addr, unsigned long handle,
+                    unsigned long (*fn)(unsigned long,
+                               unsigned long, unsigned long),
+                    unsigned int irq);
+extern unsigned long
+(*intc_disable_fns[])(unsigned long addr, unsigned long handle,
+                     unsigned long (*fn)(unsigned long,
+                               unsigned long, unsigned long),
+                     unsigned int irq);
+extern unsigned long
+(*intc_enable_noprio_fns[])(unsigned long addr, unsigned long handle,
+                           unsigned long (*fn)(unsigned long,
+                               unsigned long, unsigned long),
+                           unsigned int irq);
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_set_field_from_handle(unsigned int value,
+                           unsigned int field_value,
+                           unsigned int handle);
+unsigned long intc_get_field_from_handle(unsigned int value,
+                                        unsigned int handle);
+
+/* balancing.c */
+#ifdef CONFIG_INTC_BALANCING
+void intc_balancing_enable(unsigned int irq);
+void intc_balancing_disable(unsigned int irq);
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+                         struct intc_desc_int *d, intc_enum id);
+#else
+static inline void intc_balancing_enable(unsigned int irq) { }
+static inline void intc_balancing_disable(unsigned int irq) { }
+static inline void
+intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+                    struct intc_desc_int *d, intc_enum id) { }
+#endif
+
+/* chip.c */
+extern struct irq_chip intc_irq_chip;
+void _intc_enable(unsigned int irq, unsigned long handle);
+
+/* core.c */
+extern struct list_head intc_list;
+extern raw_spinlock_t intc_big_lock;
+extern unsigned int nr_intc_controllers;
+extern struct sysdev_class intc_sysdev_class;
+
+unsigned int intc_get_dfl_prio_level(void);
+unsigned int intc_get_prio_level(unsigned int irq);
+void intc_set_prio_level(unsigned int irq, unsigned int level);
+
+/* handle.c */
+unsigned int intc_get_mask_handle(struct intc_desc *desc,
+                                 struct intc_desc_int *d,
+                                 intc_enum enum_id, int do_grps);
+unsigned int intc_get_prio_handle(struct intc_desc *desc,
+                                 struct intc_desc_int *d,
+                                 intc_enum enum_id, int do_grps);
+unsigned int intc_get_sense_handle(struct intc_desc *desc,
+                                  struct intc_desc_int *d,
+                                  intc_enum enum_id);
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+                        struct intc_desc_int *d, intc_enum id);
+unsigned long intc_get_ack_handle(unsigned int irq);
+void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
+                             intc_enum enum_id, int enable);
+
+/* virq.c */
+void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq);
diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c
new file mode 100644 (file)
index 0000000..e32304b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Support for hardware-assisted userspace interrupt masking.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/sizes.h>
+#include "internals.h"
+
+static void __iomem *uimask;
+
+static ssize_t
+show_intc_userimask(struct sysdev_class *cls,
+                   struct sysdev_class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
+}
+
+static ssize_t
+store_intc_userimask(struct sysdev_class *cls,
+                    struct sysdev_class_attribute *attr,
+                    const char *buf, size_t count)
+{
+       unsigned long level;
+
+       level = simple_strtoul(buf, NULL, 10);
+
+       /*
+        * Minimal acceptable IRQ levels are in the 2 - 16 range, but
+        * these are chomped so as to not interfere with normal IRQs.
+        *
+        * Level 1 is a special case on some CPUs in that it's not
+        * directly settable, but given that USERIMASK cuts off below a
+        * certain level, we don't care about this limitation here.
+        * Level 0 on the other hand equates to user masking disabled.
+        *
+        * We use the default priority level as a cut off so that only
+        * special case opt-in IRQs can be mangled.
+        */
+       if (level >= intc_get_dfl_prio_level())
+               return -EINVAL;
+
+       __raw_writel(0xa5 << 24 | level << 4, uimask);
+
+       return count;
+}
+
+static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
+                        show_intc_userimask, store_intc_userimask);
+
+
+static int __init userimask_sysdev_init(void)
+{
+       if (unlikely(!uimask))
+               return -ENXIO;
+
+       return sysdev_class_create_file(&intc_sysdev_class, &attr_userimask);
+}
+late_initcall(userimask_sysdev_init);
+
+int register_intc_userimask(unsigned long addr)
+{
+       if (unlikely(uimask))
+               return -EBUSY;
+
+       uimask = ioremap_nocache(addr, SZ_4K);
+       if (unlikely(!uimask))
+               return -ENOMEM;
+
+       pr_info("userimask support registered for levels 0 -> %d\n",
+               intc_get_dfl_prio_level() - 1);
+
+       return 0;
+}
diff --git a/drivers/sh/intc/virq-debugfs.c b/drivers/sh/intc/virq-debugfs.c
new file mode 100644 (file)
index 0000000..9e62ba9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Support for virtual IRQ subgroups debugfs mapping.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * Modelled after arch/powerpc/kernel/irq.c.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include "internals.h"
+
+static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
+{
+       int i;
+
+       seq_printf(m, "%-5s  %-7s  %-15s\n", "irq", "enum", "chip name");
+
+       for (i = 1; i < nr_irqs; i++) {
+               struct intc_map_entry *entry = intc_irq_xlate_get(i);
+               struct intc_desc_int *desc = entry->desc;
+
+               if (!desc)
+                       continue;
+
+               seq_printf(m, "%5d  ", i);
+               seq_printf(m, "0x%05x  ", entry->enum_id);
+               seq_printf(m, "%-15s\n", desc->chip.name);
+       }
+
+       return 0;
+}
+
+static int intc_irq_xlate_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, intc_irq_xlate_debug, inode->i_private);
+}
+
+static const struct file_operations intc_irq_xlate_fops = {
+       .open = intc_irq_xlate_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init intc_irq_xlate_init(void)
+{
+       /*
+        * XXX.. use arch_debugfs_dir here when all of the intc users are
+        * converted.
+        */
+       if (debugfs_create_file("intc_irq_xlate", S_IRUGO, NULL, NULL,
+                               &intc_irq_xlate_fops) == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+fs_initcall(intc_irq_xlate_init);
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
new file mode 100644 (file)
index 0000000..643dfd4
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Support for virtual IRQ subgroups.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static struct intc_map_entry intc_irq_xlate[NR_IRQS];
+
+struct intc_virq_list {
+       unsigned int irq;
+       struct intc_virq_list *next;
+};
+
+#define for_each_virq(entry, head) \
+       for (entry = head; entry; entry = entry->next)
+
+/*
+ * Tags for the radix tree
+ */
+#define INTC_TAG_VIRQ_NEEDS_ALLOC      0
+
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&intc_big_lock, flags);
+       intc_irq_xlate[irq].enum_id = id;
+       intc_irq_xlate[irq].desc = d;
+       raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq)
+{
+       return intc_irq_xlate + irq;
+}
+
+int intc_irq_lookup(const char *chipname, intc_enum enum_id)
+{
+       struct intc_map_entry *ptr;
+       struct intc_desc_int *d;
+       int irq = -1;
+
+       list_for_each_entry(d, &intc_list, list) {
+               int tagged;
+
+               if (strcmp(d->chip.name, chipname) != 0)
+                       continue;
+
+               /*
+                * Catch early lookups for subgroup VIRQs that have not
+                * yet been allocated an IRQ. This already includes a
+                * fast-path out if the tree is untagged, so there is no
+                * need to explicitly test the root tree.
+                */
+               tagged = radix_tree_tag_get(&d->tree, enum_id,
+                                           INTC_TAG_VIRQ_NEEDS_ALLOC);
+               if (unlikely(tagged))
+                       break;
+
+               ptr = radix_tree_lookup(&d->tree, enum_id);
+               if (ptr) {
+                       irq = ptr - intc_irq_xlate;
+                       break;
+               }
+       }
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(intc_irq_lookup);
+
+static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
+{
+       struct intc_virq_list **last, *entry;
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       /* scan for duplicates */
+       last = (struct intc_virq_list **)&desc->handler_data;
+       for_each_virq(entry, desc->handler_data) {
+               if (entry->irq == virq)
+                       return 0;
+               last = &entry->next;
+       }
+
+       entry = kzalloc(sizeof(struct intc_virq_list), GFP_ATOMIC);
+       if (!entry) {
+               pr_err("can't allocate VIRQ mapping for %d\n", virq);
+               return -ENOMEM;
+       }
+
+       entry->irq = virq;
+
+       *last = entry;
+
+       return 0;
+}
+
+static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct intc_virq_list *entry, *vlist = get_irq_data(irq);
+       struct intc_desc_int *d = get_intc_desc(irq);
+
+       desc->chip->mask_ack(irq);
+
+       for_each_virq(entry, vlist) {
+               unsigned long addr, handle;
+
+               handle = (unsigned long)get_irq_data(entry->irq);
+               addr = INTC_REG(d, _INTC_ADDR_E(handle), 0);
+
+               if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0))
+                       generic_handle_irq(entry->irq);
+       }
+
+       desc->chip->unmask(irq);
+}
+
+static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
+                                              struct intc_desc_int *d,
+                                              unsigned int index)
+{
+       unsigned int fn = REG_FN_TEST_BASE + (subgroup->reg_width >> 3) - 1;
+
+       return _INTC_MK(fn, MODE_ENABLE_REG, intc_get_reg(d, subgroup->reg),
+                       0, 1, (subgroup->reg_width - 1) - index);
+}
+
+static void __init intc_subgroup_init_one(struct intc_desc *desc,
+                                         struct intc_desc_int *d,
+                                         struct intc_subgroup *subgroup)
+{
+       struct intc_map_entry *mapped;
+       unsigned int pirq;
+       unsigned long flags;
+       int i;
+
+       mapped = radix_tree_lookup(&d->tree, subgroup->parent_id);
+       if (!mapped) {
+               WARN_ON(1);
+               return;
+       }
+
+       pirq = mapped - intc_irq_xlate;
+
+       raw_spin_lock_irqsave(&d->lock, flags);
+
+       for (i = 0; i < ARRAY_SIZE(subgroup->enum_ids); i++) {
+               struct intc_subgroup_entry *entry;
+               int err;
+
+               if (!subgroup->enum_ids[i])
+                       continue;
+
+               entry = kmalloc(sizeof(*entry), GFP_NOWAIT);
+               if (!entry)
+                       break;
+
+               entry->pirq = pirq;
+               entry->enum_id = subgroup->enum_ids[i];
+               entry->handle = intc_subgroup_data(subgroup, d, i);
+
+               err = radix_tree_insert(&d->tree, entry->enum_id, entry);
+               if (unlikely(err < 0))
+                       break;
+
+               radix_tree_tag_set(&d->tree, entry->enum_id,
+                                  INTC_TAG_VIRQ_NEEDS_ALLOC);
+       }
+
+       raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d)
+{
+       int i;
+
+       if (!desc->hw.subgroups)
+               return;
+
+       for (i = 0; i < desc->hw.nr_subgroups; i++)
+               intc_subgroup_init_one(desc, d, desc->hw.subgroups + i);
+}
+
+static void __init intc_subgroup_map(struct intc_desc_int *d)
+{
+       struct intc_subgroup_entry *entries[32];
+       unsigned long flags;
+       unsigned int nr_found;
+       int i;
+
+       raw_spin_lock_irqsave(&d->lock, flags);
+
+restart:
+       nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
+                       (void ***)entries, 0, ARRAY_SIZE(entries),
+                       INTC_TAG_VIRQ_NEEDS_ALLOC);
+
+       for (i = 0; i < nr_found; i++) {
+               struct intc_subgroup_entry *entry;
+               int irq;
+
+               entry = radix_tree_deref_slot((void **)entries[i]);
+               if (unlikely(!entry))
+                       continue;
+               if (unlikely(entry == RADIX_TREE_RETRY))
+                       goto restart;
+
+               irq = create_irq();
+               if (unlikely(irq < 0)) {
+                       pr_err("no more free IRQs, bailing..\n");
+                       break;
+               }
+
+               pr_info("Setting up a chained VIRQ from %d -> %d\n",
+                       irq, entry->pirq);
+
+               intc_irq_xlate_set(irq, entry->enum_id, d);
+
+               set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq),
+                                             handle_simple_irq, "virq");
+               set_irq_chip_data(irq, get_irq_chip_data(entry->pirq));
+
+               set_irq_data(irq, (void *)entry->handle);
+
+               set_irq_chained_handler(entry->pirq, intc_virq_handler);
+               add_virq_to_pirq(entry->pirq, irq);
+
+               radix_tree_tag_clear(&d->tree, entry->enum_id,
+                                    INTC_TAG_VIRQ_NEEDS_ALLOC);
+               radix_tree_replace_slot((void **)entries[i],
+                                       &intc_irq_xlate[irq]);
+       }
+
+       raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_finalize(void)
+{
+       struct intc_desc_int *d;
+
+       list_for_each_entry(d, &intc_list, list)
+               if (radix_tree_tagged(&d->tree, INTC_TAG_VIRQ_NEEDS_ALLOC))
+                       intc_subgroup_map(d);
+}
index cf0303acab8edb2f1e9d23e4f30cb12330635645..75934e3ea34e848b4e3612b031d77635da1451d1 100644 (file)
@@ -7,6 +7,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -559,10 +561,8 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
        struct pinmux_data_reg *dr = NULL;
        int bit = 0;
 
-       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
-               BUG();
-               return 0;
-       }
+       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+               return -EINVAL;
 
        return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
 }
@@ -581,7 +581,7 @@ int register_pinmux(struct pinmux_info *pip)
 {
        struct gpio_chip *chip = &pip->chip;
 
-       pr_info("sh pinmux: %s handling gpio %d -> %d\n",
+       pr_info("%s handling gpio %d -> %d\n",
                pip->name, pip->first_gpio, pip->last_gpio);
 
        setup_data_regs(pip);
@@ -602,3 +602,10 @@ int register_pinmux(struct pinmux_info *pip)
 
        return gpiochip_add(chip);
 }
+
+int unregister_pinmux(struct pinmux_info *pip)
+{
+       pr_info("%s deregistering\n", pip->name);
+
+       return gpiochip_remove(&pip->chip);
+}
index 4b9eec68fad6b84bca9c2f5f6f397f0e9be79c45..78f9fd02c1b27c3ebf0753e1d9a995212b96ba48 100644 (file)
@@ -329,6 +329,13 @@ config SPI_STMP3XXX
        help
          SPI driver for Freescale STMP37xx/378x SoC SSP interface
 
+config SPI_TEGRA
+       tristate "Nvidia Tegra SPI controller"
+       depends on ARCH_TEGRA
+       select TEGRA_SYSTEM_DMA
+       help
+         SPI driver for NVidia Tegra SoCs
+
 config SPI_TOPCLIFF_PCH
        tristate "Topcliff PCH SPI Controller"
        depends on PCI
index 557aaadf56b2df40620a3b02073b44b78f09fb66..8bc1a5abac1fea65c166ba1c1a15e4c63b25a05d 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_PPC4xx)              += spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx_hw.o
 obj-$(CONFIG_SPI_S3C64XX)              += spi_s3c64xx.o
+obj-$(CONFIG_SPI_TEGRA)                        += spi_tegra.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH)         += spi_topcliff_pch.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c
new file mode 100644 (file)
index 0000000..bb7df02
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * Driver for Nvidia TEGRA spi controller.
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/spi/spi.h>
+
+#include <mach/dma.h>
+
+#define SLINK_COMMAND          0x000
+#define   SLINK_BIT_LENGTH(x)          (((x) & 0x1f) << 0)
+#define   SLINK_WORD_SIZE(x)           (((x) & 0x1f) << 5)
+#define   SLINK_BOTH_EN                        (1 << 10)
+#define   SLINK_CS_SW                  (1 << 11)
+#define   SLINK_CS_VALUE               (1 << 12)
+#define   SLINK_CS_POLARITY            (1 << 13)
+#define   SLINK_IDLE_SDA_DRIVE_LOW     (0 << 16)
+#define   SLINK_IDLE_SDA_DRIVE_HIGH    (1 << 16)
+#define   SLINK_IDLE_SDA_PULL_LOW      (2 << 16)
+#define   SLINK_IDLE_SDA_PULL_HIGH     (3 << 16)
+#define   SLINK_IDLE_SDA_MASK          (3 << 16)
+#define   SLINK_CS_POLARITY1           (1 << 20)
+#define   SLINK_CK_SDA                 (1 << 21)
+#define   SLINK_CS_POLARITY2           (1 << 22)
+#define   SLINK_CS_POLARITY3           (1 << 23)
+#define   SLINK_IDLE_SCLK_DRIVE_LOW    (0 << 24)
+#define   SLINK_IDLE_SCLK_DRIVE_HIGH   (1 << 24)
+#define   SLINK_IDLE_SCLK_PULL_LOW     (2 << 24)
+#define   SLINK_IDLE_SCLK_PULL_HIGH    (3 << 24)
+#define   SLINK_IDLE_SCLK_MASK         (3 << 24)
+#define   SLINK_M_S                    (1 << 28)
+#define   SLINK_WAIT                   (1 << 29)
+#define   SLINK_GO                     (1 << 30)
+#define   SLINK_ENB                    (1 << 31)
+
+#define SLINK_COMMAND2         0x004
+#define   SLINK_LSBFE                  (1 << 0)
+#define   SLINK_SSOE                   (1 << 1)
+#define   SLINK_SPIE                   (1 << 4)
+#define   SLINK_BIDIROE                        (1 << 6)
+#define   SLINK_MODFEN                 (1 << 7)
+#define   SLINK_INT_SIZE(x)            (((x) & 0x1f) << 8)
+#define   SLINK_CS_ACTIVE_BETWEEN      (1 << 17)
+#define   SLINK_SS_EN_CS(x)            (((x) & 0x3) << 18)
+#define   SLINK_SS_SETUP(x)            (((x) & 0x3) << 20)
+#define   SLINK_FIFO_REFILLS_0         (0 << 22)
+#define   SLINK_FIFO_REFILLS_1         (1 << 22)
+#define   SLINK_FIFO_REFILLS_2         (2 << 22)
+#define   SLINK_FIFO_REFILLS_3         (3 << 22)
+#define   SLINK_FIFO_REFILLS_MASK      (3 << 22)
+#define   SLINK_WAIT_PACK_INT(x)       (((x) & 0x7) << 26)
+#define   SLINK_SPC0                   (1 << 29)
+#define   SLINK_TXEN                   (1 << 30)
+#define   SLINK_RXEN                   (1 << 31)
+
+#define SLINK_STATUS           0x008
+#define   SLINK_COUNT(val)             (((val) >> 0) & 0x1f)
+#define   SLINK_WORD(val)              (((val) >> 5) & 0x1f)
+#define   SLINK_BLK_CNT(val)           (((val) >> 0) & 0xffff)
+#define   SLINK_MODF                   (1 << 16)
+#define   SLINK_RX_UNF                 (1 << 18)
+#define   SLINK_TX_OVF                 (1 << 19)
+#define   SLINK_TX_FULL                        (1 << 20)
+#define   SLINK_TX_EMPTY               (1 << 21)
+#define   SLINK_RX_FULL                        (1 << 22)
+#define   SLINK_RX_EMPTY               (1 << 23)
+#define   SLINK_TX_UNF                 (1 << 24)
+#define   SLINK_RX_OVF                 (1 << 25)
+#define   SLINK_TX_FLUSH               (1 << 26)
+#define   SLINK_RX_FLUSH               (1 << 27)
+#define   SLINK_SCLK                   (1 << 28)
+#define   SLINK_ERR                    (1 << 29)
+#define   SLINK_RDY                    (1 << 30)
+#define   SLINK_BSY                    (1 << 31)
+
+#define SLINK_MAS_DATA         0x010
+#define SLINK_SLAVE_DATA       0x014
+
+#define SLINK_DMA_CTL          0x018
+#define   SLINK_DMA_BLOCK_SIZE(x)      (((x) & 0xffff) << 0)
+#define   SLINK_TX_TRIG_1              (0 << 16)
+#define   SLINK_TX_TRIG_4              (1 << 16)
+#define   SLINK_TX_TRIG_8              (2 << 16)
+#define   SLINK_TX_TRIG_16             (3 << 16)
+#define   SLINK_TX_TRIG_MASK           (3 << 16)
+#define   SLINK_RX_TRIG_1              (0 << 18)
+#define   SLINK_RX_TRIG_4              (1 << 18)
+#define   SLINK_RX_TRIG_8              (2 << 18)
+#define   SLINK_RX_TRIG_16             (3 << 18)
+#define   SLINK_RX_TRIG_MASK           (3 << 18)
+#define   SLINK_PACKED                 (1 << 20)
+#define   SLINK_PACK_SIZE_4            (0 << 21)
+#define   SLINK_PACK_SIZE_8            (1 << 21)
+#define   SLINK_PACK_SIZE_16           (2 << 21)
+#define   SLINK_PACK_SIZE_32           (3 << 21)
+#define   SLINK_PACK_SIZE_MASK         (3 << 21)
+#define   SLINK_IE_TXC                 (1 << 26)
+#define   SLINK_IE_RXC                 (1 << 27)
+#define   SLINK_DMA_EN                 (1 << 31)
+
+#define SLINK_STATUS2          0x01c
+#define   SLINK_TX_FIFO_EMPTY_COUNT(val)       (((val) & 0x3f) >> 0)
+#define   SLINK_RX_FIFO_FULL_COUNT(val)                (((val) & 0x3f) >> 16)
+
+#define SLINK_TX_FIFO          0x100
+#define SLINK_RX_FIFO          0x180
+
+static const unsigned long spi_tegra_req_sels[] = {
+       TEGRA_DMA_REQ_SEL_SL2B1,
+       TEGRA_DMA_REQ_SEL_SL2B2,
+       TEGRA_DMA_REQ_SEL_SL2B3,
+       TEGRA_DMA_REQ_SEL_SL2B4,
+};
+
+#define BB_LEN                 32
+
+struct spi_tegra_data {
+       struct spi_master       *master;
+       struct platform_device  *pdev;
+       spinlock_t              lock;
+
+       struct clk              *clk;
+       void __iomem            *base;
+       unsigned long           phys;
+
+       u32                     cur_speed;
+
+       struct list_head        queue;
+       struct spi_transfer     *cur;
+       unsigned                cur_pos;
+       unsigned                cur_len;
+       unsigned                cur_bytes_per_word;
+
+       /* The tegra spi controller has a bug which causes the first word
+        * in PIO transactions to be garbage.  Since packed DMA transactions
+        * require transfers to be 4 byte aligned we need a bounce buffer
+        * for the generic case.
+        */
+       struct tegra_dma_req    rx_dma_req;
+       struct tegra_dma_channel *rx_dma;
+       u32                     *rx_bb;
+       dma_addr_t              rx_bb_phys;
+};
+
+
+static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
+                                           unsigned long reg)
+{
+       return readl(tspi->base + reg);
+}
+
+static inline void spi_tegra_writel(struct spi_tegra_data *tspi,
+                                   unsigned long val,
+                                   unsigned long reg)
+{
+       writel(val, tspi->base + reg);
+}
+
+static void spi_tegra_go(struct spi_tegra_data *tspi)
+{
+       unsigned long val;
+
+       wmb();
+
+       val = spi_tegra_readl(tspi, SLINK_DMA_CTL);
+       val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN;
+       val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size / 4 - 1);
+       spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
+
+       tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
+
+       val |= SLINK_DMA_EN;
+       spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
+}
+
+static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi,
+                                 struct spi_transfer *t)
+{
+       unsigned len = min(t->len - tspi->cur_pos, BB_LEN *
+                          tspi->cur_bytes_per_word);
+       u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_pos;
+       int i, j;
+       unsigned long val;
+
+       val = spi_tegra_readl(tspi, SLINK_COMMAND);
+       val &= ~SLINK_WORD_SIZE(~0);
+       val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1);
+       spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+       for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
+               val = 0;
+               for (j = 0; j < tspi->cur_bytes_per_word; j++)
+                       val |= tx_buf[i + j] << j * 8;
+
+               spi_tegra_writel(tspi, val, SLINK_TX_FIFO);
+       }
+
+       tspi->rx_dma_req.size = len / tspi->cur_bytes_per_word * 4;
+
+       return len;
+}
+
+static unsigned spi_tegra_drain_rx_fifo(struct spi_tegra_data *tspi,
+                                 struct spi_transfer *t)
+{
+       unsigned len = tspi->cur_len;
+       u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos;
+       int i, j;
+       unsigned long val;
+
+       for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
+               val = tspi->rx_bb[i / tspi->cur_bytes_per_word];
+               for (j = 0; j < tspi->cur_bytes_per_word; j++)
+                       rx_buf[i + j] = (val >> (j * 8)) & 0xff;
+       }
+
+       return len;
+}
+
+static void spi_tegra_start_transfer(struct spi_device *spi,
+                                   struct spi_transfer *t)
+{
+       struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+       u32 speed;
+       u8 bits_per_word;
+       unsigned long val;
+
+       speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
+       bits_per_word = t->bits_per_word ? t->bits_per_word  :
+               spi->bits_per_word;
+
+       tspi->cur_bytes_per_word = (bits_per_word - 1) / 8 + 1;
+
+       if (speed != tspi->cur_speed)
+               clk_set_rate(tspi->clk, speed);
+
+       if (tspi->cur_speed == 0)
+               clk_enable(tspi->clk);
+
+       tspi->cur_speed = speed;
+
+       val = spi_tegra_readl(tspi, SLINK_COMMAND2);
+       val &= ~SLINK_SS_EN_CS(~0) | SLINK_RXEN | SLINK_TXEN;
+       if (t->rx_buf)
+               val |= SLINK_RXEN;
+       if (t->tx_buf)
+               val |= SLINK_TXEN;
+       val |= SLINK_SS_EN_CS(spi->chip_select);
+       val |= SLINK_SPIE;
+       spi_tegra_writel(tspi, val, SLINK_COMMAND2);
+
+       val = spi_tegra_readl(tspi, SLINK_COMMAND);
+       val &= ~SLINK_BIT_LENGTH(~0);
+       val |= SLINK_BIT_LENGTH(bits_per_word - 1);
+
+       /* FIXME: should probably control CS manually so that we can be sure
+        * it does not go low between transfer and to support delay_usecs
+        * correctly.
+        */
+       val &= ~SLINK_IDLE_SCLK_MASK & ~SLINK_CK_SDA & ~SLINK_CS_SW;
+
+       if (spi->mode & SPI_CPHA)
+               val |= SLINK_CK_SDA;
+
+       if (spi->mode & SPI_CPOL)
+               val |= SLINK_IDLE_SCLK_DRIVE_HIGH;
+       else
+               val |= SLINK_IDLE_SCLK_DRIVE_LOW;
+
+       val |= SLINK_M_S;
+
+       spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+       spi_tegra_writel(tspi, SLINK_RX_FLUSH | SLINK_TX_FLUSH, SLINK_STATUS);
+
+       tspi->cur = t;
+       tspi->cur_pos = 0;
+       tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, t);
+
+       spi_tegra_go(tspi);
+}
+
+static void spi_tegra_start_message(struct spi_device *spi,
+                                   struct spi_message *m)
+{
+       struct spi_transfer *t;
+
+       m->actual_length = 0;
+       m->status = 0;
+
+       t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list);
+       spi_tegra_start_transfer(spi, t);
+}
+
+static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req)
+{
+       struct spi_tegra_data *tspi = req->dev;
+       unsigned long flags;
+       struct spi_message *m;
+       struct spi_device *spi;
+       int timeout = 0;
+       unsigned long val;
+
+       /* the SPI controller may come back with both the BSY and RDY bits
+        * set.  In this case we need to wait for the BSY bit to clear so
+        * that we are sure the DMA is finished.  1000 reads was empirically
+        * determined to be long enough.
+        */
+       while (timeout++ < 1000) {
+               if (!(spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY))
+                       break;
+       }
+
+       spin_lock_irqsave(&tspi->lock, flags);
+
+       val = spi_tegra_readl(tspi, SLINK_STATUS);
+       val |= SLINK_RDY;
+       spi_tegra_writel(tspi, val, SLINK_STATUS);
+
+       m = list_first_entry(&tspi->queue, struct spi_message, queue);
+
+       if (timeout >= 1000)
+               m->status = -EIO;
+
+       spi = m->state;
+
+       tspi->cur_pos += spi_tegra_drain_rx_fifo(tspi, tspi->cur);
+       m->actual_length += tspi->cur_pos;
+
+       if (tspi->cur_pos < tspi->cur->len) {
+               tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, tspi->cur);
+               spi_tegra_go(tspi);
+       } else if (!list_is_last(&tspi->cur->transfer_list,
+                                &m->transfers)) {
+               tspi->cur =  list_first_entry(&tspi->cur->transfer_list,
+                                             struct spi_transfer,
+                                             transfer_list);
+               spi_tegra_start_transfer(spi, tspi->cur);
+       } else {
+               list_del(&m->queue);
+
+               m->complete(m->context);
+
+               if (!list_empty(&tspi->queue)) {
+                       m = list_first_entry(&tspi->queue, struct spi_message,
+                                            queue);
+                       spi = m->state;
+                       spi_tegra_start_message(spi, m);
+               } else {
+                       clk_disable(tspi->clk);
+                       tspi->cur_speed = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&tspi->lock, flags);
+}
+
+static int spi_tegra_setup(struct spi_device *spi)
+{
+       struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+       unsigned long cs_bit;
+       unsigned long val;
+       unsigned long flags;
+
+       dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n",
+               spi->bits_per_word,
+               spi->mode & SPI_CPOL ? "" : "~",
+               spi->mode & SPI_CPHA ? "" : "~",
+               spi->max_speed_hz);
+
+
+       switch (spi->chip_select) {
+       case 0:
+               cs_bit = SLINK_CS_POLARITY;
+               break;
+
+       case 1:
+               cs_bit = SLINK_CS_POLARITY1;
+               break;
+
+       case 2:
+               cs_bit = SLINK_CS_POLARITY2;
+               break;
+
+       case 4:
+               cs_bit = SLINK_CS_POLARITY3;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&tspi->lock, flags);
+
+       val = spi_tegra_readl(tspi, SLINK_COMMAND);
+       if (spi->mode & SPI_CS_HIGH)
+               val |= cs_bit;
+       else
+               val &= ~cs_bit;
+       spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+       spin_unlock_irqrestore(&tspi->lock, flags);
+
+       return 0;
+}
+
+static int spi_tegra_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+       struct spi_transfer *t;
+       unsigned long flags;
+       int was_empty;
+
+       if (list_empty(&m->transfers) || !m->complete)
+               return -EINVAL;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->bits_per_word < 0 || t->bits_per_word > 32)
+                       return -EINVAL;
+
+               if (t->len == 0)
+                       return -EINVAL;
+
+               if (!t->rx_buf && !t->tx_buf)
+                       return -EINVAL;
+       }
+
+       m->state = spi;
+
+       spin_lock_irqsave(&tspi->lock, flags);
+       was_empty = list_empty(&tspi->queue);
+       list_add_tail(&m->queue, &tspi->queue);
+
+       if (was_empty)
+               spi_tegra_start_message(spi, m);
+
+       spin_unlock_irqrestore(&tspi->lock, flags);
+
+       return 0;
+}
+
+static int __init spi_tegra_probe(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct spi_tegra_data   *tspi;
+       struct resource         *r;
+       int ret;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *tspi);
+       if (master == NULL) {
+               dev_err(&pdev->dev, "master allocation failed\n");
+               return -ENOMEM;
+       }
+
+       /* the spi->mode bits understood by this driver: */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+       master->bus_num = pdev->id;
+
+       master->setup = spi_tegra_setup;
+       master->transfer = spi_tegra_transfer;
+       master->num_chipselect = 4;
+
+       dev_set_drvdata(&pdev->dev, master);
+       tspi = spi_master_get_devdata(master);
+       tspi->master = master;
+       tspi->pdev = pdev;
+       spin_lock_init(&tspi->lock);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENODEV;
+               goto err0;
+       }
+
+       if (!request_mem_region(r->start, (r->end - r->start) + 1,
+                               dev_name(&pdev->dev))) {
+               ret = -EBUSY;
+               goto err0;
+       }
+
+       tspi->phys = r->start;
+       tspi->base = ioremap(r->start, r->end - r->start + 1);
+       if (!tspi->base) {
+               dev_err(&pdev->dev, "can't ioremap iomem\n");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       tspi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR_OR_NULL(tspi->clk)) {
+               dev_err(&pdev->dev, "can not get clock\n");
+               ret = PTR_ERR(tspi->clk);
+               goto err2;
+       }
+
+       INIT_LIST_HEAD(&tspi->queue);
+
+       tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
+       if (!tspi->rx_dma) {
+               dev_err(&pdev->dev, "can not allocate rx dma channel\n");
+               ret = -ENODEV;
+               goto err3;
+       }
+
+       tspi->rx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+                                        &tspi->rx_bb_phys, GFP_KERNEL);
+       if (!tspi->rx_bb) {
+               dev_err(&pdev->dev, "can not allocate rx bounce buffer\n");
+               ret = -ENOMEM;
+               goto err4;
+       }
+
+       tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
+       tspi->rx_dma_req.to_memory = 1;
+       tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys;
+       tspi->rx_dma_req.dest_bus_width = 32;
+       tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
+       tspi->rx_dma_req.source_bus_width = 32;
+       tspi->rx_dma_req.source_wrap = 4;
+       tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
+       tspi->rx_dma_req.dev = tspi;
+
+       ret = spi_register_master(master);
+
+       if (ret < 0)
+               goto err5;
+
+       return ret;
+
+err5:
+       dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+                         tspi->rx_bb, tspi->rx_bb_phys);
+err4:
+       tegra_dma_free_channel(tspi->rx_dma);
+err3:
+       clk_put(tspi->clk);
+err2:
+       iounmap(tspi->base);
+err1:
+       release_mem_region(r->start, (r->end - r->start) + 1);
+err0:
+       spi_master_put(master);
+       return ret;
+}
+
+static int __devexit spi_tegra_remove(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct spi_tegra_data   *tspi;
+       struct resource         *r;
+
+       master = dev_get_drvdata(&pdev->dev);
+       tspi = spi_master_get_devdata(master);
+
+       tegra_dma_free_channel(tspi->rx_dma);
+
+       dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+                         tspi->rx_bb, tspi->rx_bb_phys);
+
+       clk_put(tspi->clk);
+       iounmap(tspi->base);
+
+       spi_master_put(master);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(r->start, (r->end - r->start) + 1);
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:spi_tegra");
+
+static struct platform_driver spi_tegra_driver = {
+       .driver = {
+               .name =         "spi_tegra",
+               .owner =        THIS_MODULE,
+       },
+       .remove =       __devexit_p(spi_tegra_remove),
+};
+
+static int __init spi_tegra_init(void)
+{
+       return platform_driver_probe(&spi_tegra_driver, spi_tegra_probe);
+}
+module_init(spi_tegra_init);
+
+static void __exit spi_tegra_exit(void)
+{
+       platform_driver_unregister(&spi_tegra_driver);
+}
+module_exit(spi_tegra_exit);
+
+MODULE_LICENSE("GPL");
index 335311a98fdcb0d4451c8fa2bfd604f937bae637..8e03e76002393935ee1a600eac19a7824fde4f0d 100644 (file)
@@ -139,8 +139,6 @@ source "drivers/staging/adis16255/Kconfig"
 
 source "drivers/staging/xgifb/Kconfig"
 
-source "drivers/staging/mrst-touchscreen/Kconfig"
-
 source "drivers/staging/msm/Kconfig"
 
 source "drivers/staging/lirc/Kconfig"
index e3f1e1b6095e5e790db3b9af1de06e7e29d4f9b7..0e7d7559d379890c9c5e509f5745c6fa3d68b15a 100644 (file)
@@ -51,7 +51,6 @@ obj-$(CONFIG_CXT1E1)          += cxt1e1/
 obj-$(CONFIG_TI_ST)            += ti-st/
 obj-$(CONFIG_ADIS16255)                += adis16255/
 obj-$(CONFIG_FB_XGI)           += xgifb/
-obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH)     += mrst-touchscreen/
 obj-$(CONFIG_MSM_STAGING)      += msm/
 obj-$(CONFIG_EASYCAP)          += easycap/
 obj-$(CONFIG_SOLO6X10)         += solo6x10/
diff --git a/drivers/staging/mrst-touchscreen/Kconfig b/drivers/staging/mrst-touchscreen/Kconfig
deleted file mode 100644 (file)
index c2af492..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-config TOUCHSCREEN_INTEL_MID
-       tristate "Intel MID platform resistive touchscreen"
-       depends on INTEL_SCU_IPC
-       default y
-       help
-         Say Y here if you have a Intel MID based touchscreen
-         If unsure, say N.
diff --git a/drivers/staging/mrst-touchscreen/Makefile b/drivers/staging/mrst-touchscreen/Makefile
deleted file mode 100644 (file)
index 2d638b0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o
-
-
diff --git a/drivers/staging/mrst-touchscreen/TODO b/drivers/staging/mrst-touchscreen/TODO
deleted file mode 100644 (file)
index 7157028..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-- Move the driver to not think it is SPI (requires fixing some of the SFI
-  and firmware side)
diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
deleted file mode 100644 (file)
index abba22f..0000000
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver
- *
- * Copyright (C) 2008 Intel Corp
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; ifnot, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
- *                         Ramesh Agarwal (ramesh.agarwal@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * TODO:
- *     kill off mrstouch_debug eventually
- *     review conversion of r/m/w sequences
- *     Replace interrupt mutex abuse
- *     Kill of mrstouchdevp pointer
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/param.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <asm/intel_scu_ipc.h>
-
-
-#if defined(MRSTOUCH_DEBUG)
-#define mrstouch_debug(fmt, args...)\
-       do { \
-               printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
-               printk(KERN_DEBUG fmt, ##args); \
-       } while (0);
-#else
-#define mrstouch_debug(fmt, args...)
-#endif
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_ID1   0x00 /*PMIC ID1 register */
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_INT   0x04 /*PMIC interrupt register */
-#define PMIC_REG_MINT  0x05 /*PMIC interrupt mask register */
-
-/* ADC Interrupt registers */
-#define PMIC_REG_ADCINT   0x5F /*ADC interrupt register */
-#define PMIC_REG_MADCINT  0x60 /*ADC interrupt mask register */
-
-/* ADC Control registers */
-#define PMIC_REG_ADCCNTL1    0x61 /*ADC control register */
-
-/* ADC Channel Selection registers */
-#define PMICADDR0     0xA4
-#define END_OF_CHANNEL 0x1F
-
-/* ADC Result register */
-#define PMIC_REG_ADCSNS0H   0x64
-
-/* ADC channels for touch screen */
-#define MRST_TS_CHAN10   0xA /* Touch screen X+ connection */
-#define MRST_TS_CHAN11   0xB /* Touch screen X- connection */
-#define MRST_TS_CHAN12   0xC /* Touch screen Y+ connection */
-#define MRST_TS_CHAN13   0xD /* Touch screen Y- connection */
-
-/* Touch screen coordinate constants */
-#define TOUCH_PRESSURE         50
-#define TOUCH_PRESSURE_FS      100
-
-#define XMOVE_LIMIT    5
-#define YMOVE_LIMIT    5
-#define XYMOVE_CNT     3
-
-#define MAX_10BIT      ((1<<10)-1)
-
-/* Touch screen channel BIAS constants */
-#define XBIAS          0x20
-#define YBIAS          0x40
-#define ZBIAS          0x80
-
-/* Touch screen coordinates */
-#define MIN_X          10
-#define MAX_X          1024
-#define MIN_Y          10
-#define MAX_Y          1024
-#define WAIT_ADC_COMPLETION 10
-
-/* PMIC ADC round robin delays */
-#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
-#define ADC_LOOP_DELAY1 0x1 /* 4.5  ms approximate */
-
-/* PMIC Vendor Identifiers */
-#define PMIC_VENDOR_FS  0 /* PMIC vendor FreeScale */
-#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
-#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
-#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
-
-/* Touch screen device structure */
-struct mrstouch_dev {
-       struct spi_device *spi; /* SPI device associated with touch screen */
-       struct input_dev *input; /* input device for touchscreen*/
-       char            phys[32]; /* Device name */
-       struct task_struct *pendet_thrd; /* PENDET interrupt handler */
-       struct mutex lock; /* Sync between interrupt and PENDET handler */
-       bool            busy; /* Busy flag */
-       u16             asr; /* Address selection register */
-       int             irq;    /* Touch screen IRQ # */
-       uint            vendor;  /* PMIC vendor */
-       uint            rev;  /* PMIC revision */
-       bool            suspended; /* Device suspended status */
-       bool            disabled;  /* Device disabled status */
-       u16             x;  /* X coordinate */
-       u16             y;  /* Y coordinate */
-       bool            pendown;  /* PEN position */
-} ;
-
-
-/* Global Pointer to Touch screen device */
-static struct mrstouch_dev *mrstouchdevp;
-
-/* Utility to read PMIC ID */
-static int mrstouch_pmic_id(uint *vendor, uint *rev)
-{
-       int err;
-       u8 r;
-
-       err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
-       if (err)
-               return err;
-
-       *vendor = r & 0x7;
-       *rev = (r >> 3) & 0x7;
-
-       return 0;
-}
-
-/*
- * Parse ADC channels to find end of the channel configured by other ADC user
- * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
- */
-static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
-{
-       int err, i, j, found;
-       u32 r32;
-
-       found = -1;
-
-       for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
-               if (found >= 0)
-                       break;
-
-               err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
-               if (err)
-                       return err;
-
-               for (j = 0; j < 32; j+= 8) {
-                       if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
-                               found = i;
-                               break;
-                       }
-               }
-       }
-       if (found < 0)
-               return 0;
-
-       if (tsdev->vendor == PMIC_VENDOR_FS) {
-               if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
-                       return -ENOSPC;
-       } else {
-               if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
-                       return -ENOSPC;
-       }
-       return found;
-}
-
-/* Utility to enable/disable pendet.
- * pendet set to true enables PENDET interrupt
- * pendet set to false disables PENDET interrupt
- * Also clears RND mask bit
-*/
-static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
-{
-       u16 reg;
-       u8 r;
-       u8 pendet_enabled = 0;
-       int retry = 0;
-       int err;
-
-       err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
-       if (err)
-               return err;
-
-       if (pendet) {
-               reg &= ~0x0005;
-               reg |= 0x2000; /* Enable pendet */
-       } else
-               reg &= 0xDFFF; /* Disable pendet */
-
-       /* Set MADCINT and update ADCCNTL1 (next reg byte) */
-       err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
-       if (!pendet || err)
-               return err;
-
-       /*
-        * Sometimes even after the register write succeeds
-        * the PMIC register value is not updated. Retry few iterations
-        * to enable pendet.
-        */
-
-       err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
-       pendet_enabled = (r >> 5) & 0x01;
-
-       retry = 0;
-       while (!err && !pendet_enabled) {
-               retry++;
-               msleep(10);
-               err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8);
-               if (err)
-                       break;
-               err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
-               if (err == 0)
-                       pendet_enabled = (r >> 5) & 0x01;
-               if (retry >= 10) {
-                       dev_err(&tsdev->spi->dev, "Touch screen disabled.\n");
-                       return -EIO;
-               }
-       }
-       return 0;
-}
-
-/* To read PMIC ADC touch screen result
- * Reads ADC storage registers for higher 7 and lower 3 bits
- * converts the two readings to single value and turns off gain bit
- */
-static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
-{
-       int err;
-       u16 result;
-       u32 res;
-
-       result = PMIC_REG_ADCSNS0H + offset;
-
-       if (chan == MRST_TS_CHAN12)
-               result += 4;
-
-       err = intel_scu_ipc_ioread32(result, &res);
-       if (err)
-               return err;
-
-       /* Mash the bits up */
-
-       *vp = (res & 0xFF) << 3;        /* Highest 7 bits */
-       *vp |= (res >> 8) & 0x07;       /* Lower 3 bits */
-       *vp &= 0x3FF;
-
-       res >>= 16;
-
-       *vm = (res & 0xFF) << 3;        /* Highest 7 bits */
-       *vm |= (res >> 8) & 0x07;       /* Lower 3 bits */
-       *vm &= 0x3FF;
-
-       return 0;
-}
-
-/* To configure touch screen channels
- * Writes touch screen channels to ADC address selection registers
- */
-static int mrstouch_ts_chan_set(uint offset)
-{
-       int count;
-       u16 chan;
-       u16 reg[5];
-       u8 data[5];
-
-       chan = PMICADDR0 + offset;
-       for (count = 0; count <= 3; count++) {
-               reg[count] = chan++;
-               data[count] = MRST_TS_CHAN10 + count;
-       }
-       reg[count] = chan;
-       data[count] = END_OF_CHANNEL;
-
-       return intel_scu_ipc_writev(reg, data, 5);
-}
-
-/* Initialize ADC */
-static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
-{
-       int err, start;
-       u8 ra, rm;
-
-       err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
-       if (err) {
-               dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
-               return err;
-       }
-
-       start = mrstouch_chan_parse(tsdev);
-       if (start < 0) {
-               dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
-               return start;
-       }
-
-       tsdev->asr = start;
-
-       mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
-
-       /* ADC power on, start, enable PENDET and set loop delay
-        * ADC loop delay is set to 4.5 ms approximately
-        * Loop delay more than this results in jitter in adc readings
-        * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
-        * interrupt generation sometimes.
-        */
-
-       if (tsdev->vendor == PMIC_VENDOR_FS) {
-               ra = 0xE0 | ADC_LOOP_DELAY0;
-               rm = 0x5;
-       } else {
-               /* NEC and MAXIm not consistent with loop delay 0 */
-               ra = 0xE0 | ADC_LOOP_DELAY1;
-               rm = 0x0;
-
-               /* configure touch screen channels */
-               err = mrstouch_ts_chan_set(tsdev->asr);
-               if (err)
-                       return err;
-       }
-       err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
-       if (err == 0)
-               err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
-       return err;
-}
-
-/* Reports x,y coordinates to event subsystem */
-static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
-{
-       int xdiff, ydiff;
-
-       if (tsdev->pendown && z <= TOUCH_PRESSURE) {
-               /* Pen removed, report button release */
-               mrstouch_debug("BTN REL(%d)", z);
-               input_report_key(tsdev->input, BTN_TOUCH, 0);
-               tsdev->pendown = false;
-       }
-
-       xdiff = abs(x - tsdev->x);
-       ydiff = abs(y - tsdev->y);
-
-       /*
-       if x and y values changes for XYMOVE_CNT readings it is considered
-       as stylus is moving. This is required to differentiate between stylus
-       movement and jitter
-       */
-       if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
-               /* Spurious values, release button if touched and return */
-               if (tsdev->pendown) {
-                       mrstouch_debug("BTN REL(%d)", z);
-                       input_report_key(tsdev->input, BTN_TOUCH, 0);
-                       tsdev->pendown = false;
-               }
-               return;
-       } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
-               tsdev->x = x;
-               tsdev->y = y;
-
-               input_report_abs(tsdev->input, ABS_X, x);
-               input_report_abs(tsdev->input, ABS_Y, y);
-               input_sync(tsdev->input);
-       }
-
-
-       if (!tsdev->pendown && z > TOUCH_PRESSURE) {
-               /* Pen touched, report button touch */
-               mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
-               input_report_key(tsdev->input, BTN_TOUCH, 1);
-               tsdev->pendown = true;
-       }
-}
-
-
-/* Utility to start ADC, used by freescale handler */
-static int pendet_mask(void)
-{
-       return  intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
-}
-
-/* Utility to stop ADC, used by freescale handler */
-static int pendet_umask(void)
-{
-       return  intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
-}
-
-/* Utility to read ADC, used by freescale handler */
-static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
-{
-       int err;
-       u16 x, y, z, result;
-       u16 reg[4];
-       u8 data[4];
-
-       result = PMIC_REG_ADCSNS0H + tsdev->asr;
-
-       reg[0] = result + 4;
-       reg[1] = result + 5;
-       reg[2] = result + 16;
-       reg[3] = result + 17;
-
-       err = intel_scu_ipc_readv(reg, data, 4);
-       if (err)
-               goto ipc_error;
-
-       x = data[0] << 3; /* Higher 7 bits */
-       x |= data[1] & 0x7; /* Lower 3 bits */
-       x &= 0x3FF;
-
-       y = data[2] << 3; /* Higher 7 bits */
-       y |= data[3] & 0x7; /* Lower 3 bits */
-       y &= 0x3FF;
-
-       /* Read Z value */
-       reg[0] = result + 28;
-       reg[1] = result + 29;
-
-       err = intel_scu_ipc_readv(reg, data, 4);
-       if (err)
-               goto ipc_error;
-
-       z = data[0] << 3; /* Higher 7 bits */
-       z |= data[1] & 0x7; /* Lower 3 bits */
-       z &= 0x3FF;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
-       mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
-#endif
-
-       if (z >= TOUCH_PRESSURE_FS) {
-               mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
-               return TOUCH_PRESSURE - 1;
-       } else {
-               mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
-               return TOUCH_PRESSURE + 1;
-       }
-
-       return 0;
-
-ipc_error:
-       dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n");
-       return err;
-}
-
-/* To handle free scale pmic pendet interrupt */
-static int pmic0_pendet(void *dev_id)
-{
-       int err, count;
-       u16 chan;
-       unsigned int touched;
-       struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
-       u16 reg[5];
-       u8 data[5];
-
-       chan = PMICADDR0 + tsdev->asr;
-
-       /* Set X BIAS */
-       for (count = 0; count <= 3; count++) {
-               reg[count] = chan++;
-               data[count] = 0x2A;
-       }
-       reg[count] =  chan++; /* Dummy */
-       data[count] = 0;
-
-       err = intel_scu_ipc_writev(reg, data, 5);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /* Set Y BIAS */
-       for (count = 0; count <= 3; count++) {
-               reg[count] = chan++;
-               data[count] = 0x4A;
-       }
-       reg[count] = chan++; /* Dummy */
-       data[count] = 0;
-
-       err = intel_scu_ipc_writev(reg, data, 5);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /* Set Z BIAS */
-       err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /*Read touch screen channels till pen removed
-        * Freescale reports constant value of z for all points
-        * z is high when screen is not touched and low when touched
-        * Map high z value to not touched and low z value to pen touched
-        */
-       touched = mrstouch_pmic_fs_adc_read(tsdev);
-       while (touched > TOUCH_PRESSURE) {
-               touched = mrstouch_pmic_fs_adc_read(tsdev);
-               msleep(WAIT_ADC_COMPLETION);
-       }
-
-       /* Clear all TS channels */
-       chan = PMICADDR0 + tsdev->asr;
-       for (count = 0; count <= 4; count++) {
-               reg[count] = chan++;
-               data[count] = 0;
-       }
-       err = intel_scu_ipc_writev(reg, data, 5);
-       if (err)
-               goto ipc_error;
-
-       for (count = 0; count <= 4; count++) {
-               reg[count] = chan++;
-               data[count] = 0;
-       }
-       err = intel_scu_ipc_writev(reg, data, 5);
-       if (err)
-               goto ipc_error;
-
-       err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
-       if (err)
-               goto ipc_error;
-
-       return 0;
-
-ipc_error:
-       dev_err(&tsdev->spi->dev, "ipc error during pendet\n");
-       return err;
-}
-
-
-/* To enable X, Y and Z bias values
- * Enables YPYM for X channels and XPXM for Y channels
- */
-static int mrstouch_ts_bias_set(uint offset, uint bias)
-{
-       int count;
-       u16 chan, start;
-       u16 reg[4];
-       u8 data[4];
-
-       chan = PMICADDR0 + offset;
-       start = MRST_TS_CHAN10;
-
-       for (count = 0; count <= 3; count++) {
-               reg[count] = chan++;
-               data[count] = bias | (start + count);
-       }
-       return intel_scu_ipc_writev(reg, data, 4);
-}
-
-/* To read touch screen channel values */
-static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
-{
-       int err;
-       u16 xp, xm, yp, ym, zp, zm;
-
-       /* configure Y bias for X channels */
-       err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /* read x+ and x- channels */
-       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
-       if (err)
-               goto ipc_error;
-
-       /* configure x bias for y channels */
-       err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /* read y+ and y- channels */
-       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
-       if (err)
-               goto ipc_error;
-
-       /* configure z bias for x and y channels */
-       err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
-       if (err)
-               goto ipc_error;
-
-       msleep(WAIT_ADC_COMPLETION);
-
-       /* read z+ and z- channels */
-       err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
-       if (err)
-               goto ipc_error;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
-       printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
-#endif
-
-#if defined(MRSTOUCH_PRINT_XYZM)
-       printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
-#endif
-
-       mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
-
-       return zp;
-
-ipc_error:
-       dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
-       return err;
-}
-
-/* PENDET interrupt handler function for NEC and MAXIM */
-static void pmic12_pendet(void *data)
-{
-       unsigned int touched;
-       struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
-
-       /* read touch screen channels till pen removed */
-       do {
-               touched = mrstouch_adc_read(tsdev);
-       } while (touched > TOUCH_PRESSURE);
-}
-
-/* Handler to process PENDET interrupt */
-int mrstouch_pendet(void *data)
-{
-       struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
-       while (1) {
-               /* Wait for PENDET interrupt */
-               if (mutex_lock_interruptible(&tsdev->lock)) {
-                       msleep(WAIT_ADC_COMPLETION);
-                       continue;
-               }
-
-               if (tsdev->busy)
-                       return 0;
-
-               tsdev->busy = true;
-
-               if (tsdev->vendor == PMIC_VENDOR_NEC ||
-                       tsdev->vendor == PMIC_VENDOR_MAXIM) {
-                       /* PENDET must be disabled in NEC before reading ADC */
-                       pendet_enable(tsdev,false); /* Disbale PENDET */
-                       pmic12_pendet(tsdev);
-                       pendet_enable(tsdev, true); /*Enable PENDET */
-               } else if (tsdev->vendor == PMIC_VENDOR_FS) {
-                       pendet_umask(); /* Stop ADC */
-                       pmic0_pendet(tsdev);
-                       pendet_mask(); /* Stop ADC */
-               } else
-               dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
-                               tsdev->vendor);
-
-               tsdev->busy = false;
-
-       }
-       return 0;
-}
-
-/* PENDET interrupt handler */
-static irqreturn_t pendet_intr_handler(int irq, void *handle)
-{
-       struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
-
-       mutex_unlock(&tsdev->lock);
-       return IRQ_HANDLED;
-}
-
-/* Intializes input device and registers with input subsystem */
-static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
-{
-       int err = 0;
-
-       mrstouch_debug("%s", __func__);
-
-       tsdev->input = input_allocate_device();
-       if (!tsdev->input) {
-               dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n");
-               return -EINVAL;
-       }
-
-       tsdev->input->name = "mrst_touchscreen";
-       snprintf(tsdev->phys, sizeof(tsdev->phys),
-                       "%s/input0", dev_name(&spi->dev));
-       tsdev->input->phys = tsdev->phys;
-       tsdev->input->dev.parent = &spi->dev;
-
-       tsdev->input->id.vendor = tsdev->vendor;
-       tsdev->input->id.version = tsdev->rev;
-
-       tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
-       input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
-       input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
-
-       err = input_register_device(tsdev->input);
-       if (err) {
-               dev_err(&tsdev->spi->dev, "unable to register input device\n");
-               input_free_device(tsdev->input);
-               return err;
-       }
-
-       mrstouch_debug("%s", "mrstouch initialized");
-
-       return 0;
-
-}
-
-/* Probe function for touch screen driver */
-static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
-{
-       int err;
-       unsigned int myirq;
-       struct mrstouch_dev *tsdev;
-
-       mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
-
-       mrstouchdevp = NULL;
-       myirq = mrstouch_spi->irq;
-
-       if (!mrstouch_spi->irq) {
-               dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
-               return -EINVAL;
-       }
-
-       tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
-       if (!tsdev) {
-               dev_err(&mrstouch_spi->dev, "unable to allocate memory\n");
-               return -ENOMEM;
-       }
-
-       tsdev->irq = myirq;
-       mrstouchdevp = tsdev;
-
-       err = mrstouch_adc_init(tsdev);
-       if (err) {
-               dev_err(&mrstouch_spi->dev, "ADC init failed\n");
-               goto mrstouch_err_free_mem;
-       }
-
-       dev_set_drvdata(&mrstouch_spi->dev, tsdev);
-       tsdev->spi = mrstouch_spi;
-
-       err = ts_input_dev_init(tsdev, mrstouch_spi);
-       if (err) {
-               dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
-               goto mrstouch_err_free_mem;
-       }
-
-       mutex_init(&tsdev->lock);
-       mutex_lock(&tsdev->lock)
-
-       mrstouch_debug("Requesting IRQ-%d", myirq);
-       err = request_irq(myirq, pendet_intr_handler,
-                               0, "mrstouch", tsdev);
-       if (err) {
-               dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
-               goto mrstouch_err_free_mem;
-       }
-
-       tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
-                               (void *)tsdev, "pendet handler");
-       if (IS_ERR(tsdev->pendet_thrd)) {
-               dev_err(&tsdev->spi->dev, "kthread_run failed\n");
-               err = PTR_ERR(tsdev->pendet_thrd);
-               goto mrstouch_err_free_mem;
-       }
-       mrstouch_debug("%s", "Driver initialized");
-       return 0;
-
-mrstouch_err_free_mem:
-       kfree(tsdev);
-       return err;
-}
-
-static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       mrstouch_debug("%s", __func__);
-       mrstouchdevp->suspended = 1;
-       return 0;
-}
-
-static int mrstouch_resume(struct spi_device *spi)
-{
-       mrstouch_debug("%s", __func__);
-       mrstouchdevp->suspended = 0;
-       return 0;
-}
-
-static int mrstouch_remove(struct spi_device *spi)
-{
-       mrstouch_debug("%s", __func__);
-       free_irq(mrstouchdevp->irq, mrstouchdevp);
-       input_unregister_device(mrstouchdevp->input);
-       input_free_device(mrstouchdevp->input);
-       if (mrstouchdevp->pendet_thrd)
-               kthread_stop(mrstouchdevp->pendet_thrd);
-       kfree(mrstouchdevp);
-       return 0;
-}
-
-static struct spi_driver mrstouch_driver = {
-       .driver = {
-               .name   = "pmic_touch",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
-       },
-       .probe          = mrstouch_probe,
-       .suspend        = mrstouch_suspend,
-       .resume         = mrstouch_resume,
-       .remove         = mrstouch_remove,
-};
-
-static int __init mrstouch_module_init(void)
-{
-       int err;
-
-       mrstouch_debug("%s", __func__);
-       err = spi_register_driver(&mrstouch_driver);
-       if (err) {
-               mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
-               return -1;
-       }
-
-       return 0;
-}
-
-static void __exit mrstouch_module_exit(void)
-{
-       mrstouch_debug("%s", __func__);
-       spi_unregister_driver(&mrstouch_driver);
-       return;
-}
-
-module_init(mrstouch_module_init);
-module_exit(mrstouch_module_exit);
-
-MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
-MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
-MODULE_LICENSE("GPL");
index 97dae297ca3c1483006c05b52f25b92386971330..c62d30017c07257bb7ac073a465f3e1adfa148ce 100644 (file)
@@ -882,12 +882,8 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
 static int pohmelfs_fsync(struct file *file, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 0,       /* sys_fsync did this */
-       };
 
-       return sync_inode(inode, &wbc);
+       return sync_inode_metadata(inode, 1);
 }
 
 ssize_t pohmelfs_write(struct file *file, const char __user *buf,
index 7d71019b84c20685d3ddac4763dc245f15d7cefe..c85ff5e9e70013e53445279a92c831cd1e44957f 100644 (file)
@@ -12,4 +12,4 @@ TODO:
 - get rid of non-linux related stuff
 
 Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>
index 095fa53666909e02e2325badb15bfe5f63dc139b..e2f63c0ea09df16286ea8c4ad04a743ff3d0a9b5 100644 (file)
@@ -276,6 +276,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
        struct inode *inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = current_fsuid();
                inode->i_gid = current_fsgid();
index e4f59505520889e86ecd7d131e9ba283cdbf3dc9..f276e9594f00eab91ff7f789b58e80e7a95a8bcc 100644 (file)
@@ -980,6 +980,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
        if (likely(inode)) {
                struct timespec current_time = CURRENT_TIME;
 
+               inode->i_ino     = get_next_ino();
                inode->i_mode    = perms->mode;
                inode->i_uid     = perms->uid;
                inode->i_gid     = perms->gid;
index d1d72d946b04d465014b593e7cd6c39604a57f4e..ba145e7fbe03ef27fcd37598dc46a9f1fb31eb27 100644 (file)
@@ -1991,6 +1991,7 @@ gadgetfs_make_inode (struct super_block *sb,
        struct inode *inode = new_inode (sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = default_uid;
                inode->i_gid = default_gid;
index 61d3ca6619bb1fec36204f812915a5ebe6e7c37c..cb5cd422f3f513a163d606fde97f0f2f646f48a8 100644 (file)
@@ -54,7 +54,6 @@
 
 #include <plat/dma.h>
 #include <plat/usb.h>
-#include <plat/control.h>
 
 #include "omap_udc.h"
 
@@ -2309,21 +2308,12 @@ static char *trx_mode(unsigned m, int enabled)
 static int proc_otg_show(struct seq_file *s)
 {
        u32             tmp;
-       u32             trans;
-       char            *ctrl_name;
+       u32             trans = 0;
+       char            *ctrl_name = "(UNKNOWN)";
 
+       /* XXX This needs major revision for OMAP2+ */
        tmp = omap_readl(OTG_REV);
-       if (cpu_is_omap24xx()) {
-               /*
-                * REVISIT: Not clear how this works on OMAP2.  trans
-                * is ANDed to produce bits 7 and 8, which might make
-                * sense for USB_TRANSCEIVER_CTRL on OMAP1,
-                * but with CONTROL_DEVCONF, these bits have something to
-                * do with the frame adjustment counter and McBSP2.
-                */
-               ctrl_name = "control_devconf";
-               trans = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-       } else {
+       if (cpu_class_is_omap1()) {
                ctrl_name = "tranceiver_ctrl";
                trans = omap_readw(USB_TRANSCEIVER_CTRL);
        }
index 77be3c24a4279d0aca3cc268164cf20960e135f5..3076b1cc05df3508cc991425f3f39fe3ddb77222 100644 (file)
@@ -2397,7 +2397,7 @@ static const struct dev_pm_ops r8a66597_dev_pm_ops = {
 #define R8A66597_DEV_PM_OPS    NULL
 #endif
 
-static int __init_or_module r8a66597_remove(struct platform_device *pdev)
+static int __devexit r8a66597_remove(struct platform_device *pdev)
 {
        struct r8a66597         *r8a66597 = dev_get_drvdata(&pdev->dev);
        struct usb_hcd          *hcd = r8a66597_to_hcd(r8a66597);
@@ -2542,7 +2542,7 @@ clean_up:
 
 static struct platform_driver r8a66597_driver = {
        .probe =        r8a66597_probe,
-       .remove =       r8a66597_remove,
+       .remove =       __devexit_p(r8a66597_remove),
        .driver         = {
                .name = (char *) hcd_name,
                .owner  = THIS_MODULE,
index bac8e7a6f17bcda8d21ab8c874b2cc648975fe3b..d100f54ed65066078e717f4c3c6fe2a5d0bb29c8 100644 (file)
@@ -12,8 +12,7 @@ menuconfig UWB
          technology using a wide spectrum (3.1-10.6GHz). It is
          optimized for in-room use (480Mbps at 2 meters, 110Mbps at
          10m). It serves as the transport layer for other protocols,
-         such as Wireless USB (WUSB), IP (WLP) and upcoming
-         Bluetooth and 1394
+         such as Wireless USB (WUSB).
 
          The topology is peer to peer; however, higher level
          protocols (such as WUSB) might impose a master/slave
@@ -58,13 +57,6 @@ config UWB_WHCI
           To compile this driver select Y (built in) or M (module). It
           is safe to select any even if you do not have the hardware.
 
-config UWB_WLP
-       tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)"
-       depends on UWB && NET
-       help
-         This is a common library for drivers that implement
-         networking over UWB.
-
 config UWB_I1480U
         tristate "Support for Intel Wireless UWB Link 1480 HWA"
         depends on UWB_HWA
@@ -77,14 +69,4 @@ config UWB_I1480U
          To compile this driver select Y (built in) or M (module). It
          is safe to select any even if you do not have the hardware.
 
-config UWB_I1480U_WLP
-        tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface"
-        depends on UWB_I1480U &&  UWB_WLP && NET
-        help
-         This driver enables WLP support for the i1480 when connected via
-         USB. WLP is the WiMedia Link Protocol, or IP over UWB.
-
-         To compile this driver select Y (built in) or M (module). It
-         is safe to select any even if you don't have the hardware.
-
 endif # UWB
index 2f98d080fe787b4817f9768bc10fc6381a2a43f7..d47dd6e2942c76d6cee5705d5a106c2ecfe7ad76 100644 (file)
@@ -1,5 +1,4 @@
 obj-$(CONFIG_UWB)              += uwb.o
-obj-$(CONFIG_UWB_WLP)          += wlp/
 obj-$(CONFIG_UWB_WHCI)         += umc.o whci.o whc-rc.o
 obj-$(CONFIG_UWB_HWA)          += hwa-rc.o
 obj-$(CONFIG_UWB_I1480U)       += i1480/
index 212bbc7d4c32e5455d765b6d03d085f6392006a0..d69da1684cfbfc2bd46114768c5b177afa13ea65 100644 (file)
@@ -1,2 +1 @@
 obj-$(CONFIG_UWB_I1480U)       += dfu/ i1480-est.o
-obj-$(CONFIG_UWB_I1480U_WLP)   += i1480u-wlp/
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h
deleted file mode 100644 (file)
index 18a8b0e..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Intel 1480 Wireless UWB Link
- * WLP specific definitions
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#ifndef __i1480_wlp_h__
-#define __i1480_wlp_h__
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/uwb.h>
-#include <linux/if_ether.h>
-#include <asm/byteorder.h>
-
-/* New simplified header format? */
-#undef WLP_HDR_FMT_2           /* FIXME: rename */
-
-/**
- * Values of the Delivery ID & Type field when PCA or DRP
- *
- * The Delivery ID & Type field in the WLP TX header indicates whether
- * the frame is PCA or DRP. This is done based on the high level bit of
- * this field.
- * We use this constant to test if the traffic is PCA or DRP as follows:
- * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)
- *     this is DRP traffic
- * else
- *     this is PCA traffic
- */
-enum deliver_id_type_bit {
-       WLP_DRP = 8,
-};
-
-/**
- * WLP TX header
- *
- * Indicates UWB/WLP-specific transmission parameters for a network
- * packet.
- */
-struct wlp_tx_hdr {
-       /* dword 0 */
-       struct uwb_dev_addr dstaddr;
-       u8                  key_index;
-       u8                  mac_params;
-       /* dword 1 */
-       u8                  phy_params;
-#ifndef WLP_HDR_FMT_2
-       u8                  reserved;
-       __le16              oui01;              /* FIXME: not so sure if __le16 or u8[2] */
-       /* dword 2 */
-       u8                  oui2;               /*        if all LE, it could be merged */
-       __le16              prid;
-#endif
-} __attribute__((packed));
-
-static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr)
-{
-       return hdr->mac_params & 0x0f;
-}
-
-static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr)
-{
-       return (hdr->mac_params >> 4) & 0x07;
-}
-
-static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr)
-{
-       return (hdr->mac_params >> 7) & 0x01;
-}
-
-static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id)
-{
-       hdr->mac_params = (hdr->mac_params & ~0x0f) | id;
-}
-
-static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr,
-                                            enum uwb_ack_pol policy)
-{
-       hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4);
-}
-
-static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts)
-{
-       hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7);
-}
-
-static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr)
-{
-       return hdr->phy_params & 0x0f;
-}
-
-static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr)
-{
-       return (hdr->phy_params >> 4) & 0x0f;
-}
-
-static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate)
-{
-       hdr->phy_params = (hdr->phy_params & ~0x0f) | rate;
-}
-
-static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr)
-{
-       hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4);
-}
-
-
-/**
- * WLP RX header
- *
- * Provides UWB/WLP-specific transmission data for a received
- * network packet.
- */
-struct wlp_rx_hdr {
-       /* dword 0 */
-       struct uwb_dev_addr dstaddr;
-       struct uwb_dev_addr srcaddr;
-       /* dword 1 */
-       u8                  LQI;
-       s8                  RSSI;
-       u8                  reserved3;
-#ifndef WLP_HDR_FMT_2
-       u8                  oui0;
-       /* dword 2 */
-       __le16              oui12;
-       __le16              prid;
-#endif
-} __attribute__((packed));
-
-
-/** User configurable options for WLP */
-struct wlp_options {
-       struct mutex mutex; /* access to user configurable options*/
-       struct wlp_tx_hdr def_tx_hdr;   /* default tx hdr */
-       u8 pca_base_priority;
-       u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/
-};
-
-
-static inline
-void wlp_options_init(struct wlp_options *options)
-{
-       mutex_init(&options->mutex);
-       wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM);
-       wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1);
-       /* FIXME: default to phy caps */
-       wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480);
-#ifndef WLP_HDR_FMT_2
-       options->def_tx_hdr.prid = cpu_to_le16(0x0000);
-#endif
-}
-
-
-/* sysfs helpers */
-
-extern ssize_t uwb_pca_base_priority_store(struct wlp_options *,
-                                          const char *, size_t);
-extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *);
-extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *);
-extern ssize_t uwb_ack_policy_store(struct wlp_options *,
-                                   const char *, size_t);
-extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *);
-extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *);
-extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *);
-
-
-/** Simple bandwidth allocation (temporary and too simple) */
-struct wlp_bw_allocs {
-       const char *name;
-       struct {
-               u8 mask, stream;
-       } tx, rx;
-};
-
-
-#endif /* #ifndef __i1480_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile
deleted file mode 100644 (file)
index fe6709b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o
-
-i1480u-wlp-objs :=     \
-       lc.o            \
-       netdev.o        \
-       rx.o            \
-       sysfs.o         \
-       tx.o
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
deleted file mode 100644 (file)
index 2e31f53..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Intel 1480 Wireless UWB Link USB
- * Header formats, constants, general internal interfaces
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * This is not an standard interface.
- *
- * FIXME: docs
- *
- * i1480u-wlp is pretty simple: two endpoints, one for tx, one for
- * rx. rx is polled. Network packets (ethernet, whatever) are wrapped
- * in i1480 TX or RX headers (for sending over the air), and these
- * packets are wrapped in UNTD headers (for sending to the WLP UWB
- * controller).
- *
- * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets
- * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the
- * i1480 packet is broken in chunks/packets:
- *
- * UNTD-1st.hdr + i1480.hdr + payload
- * UNTD-next.hdr + payload
- * ...
- * UNTD-last.hdr + payload
- *
- * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE.
- *
- * All HW structures and bitmaps are little endian, so we need to play
- * ugly tricks when defining bitfields. Hoping for the day GCC
- * implements __attribute__((endian(1234))).
- *
- * FIXME: ROADMAP to the whole implementation
- */
-
-#ifndef __i1480u_wlp_h__
-#define __i1480u_wlp_h__
-
-#include <linux/usb.h>
-#include <linux/netdevice.h>
-#include <linux/uwb.h>         /* struct uwb_rc, struct uwb_notifs_handler */
-#include <linux/wlp.h>
-#include "../i1480-wlp.h"
-
-#undef i1480u_FLOW_CONTROL     /* Enable flow control code */
-
-/**
- * Basic flow control
- */
-enum {
-       i1480u_TX_INFLIGHT_MAX = 1000,
-       i1480u_TX_INFLIGHT_THRESHOLD = 100,
-};
-
-/** Maximum size of a transaction that we can tx/rx */
-enum {
-       /* Maximum packet size computed as follows: max UNTD header (8) +
-        * i1480 RX header (8) + max Ethernet header and payload (4096) +
-        * Padding added by skb_reserve (2) to make post Ethernet payload
-        * start on 16 byte boundary*/
-       i1480u_MAX_RX_PKT_SIZE = 4114,
-       i1480u_MAX_FRG_SIZE = 512,
-       i1480u_RX_BUFS = 9,
-};
-
-
-/**
- * UNTD packet type
- *
- * We need to fragment any payload whose UNTD packet is going to be
- * bigger than i1480u_MAX_FRG_SIZE.
- */
-enum i1480u_pkt_type {
-       i1480u_PKT_FRAG_1ST = 0x1,
-       i1480u_PKT_FRAG_NXT = 0x0,
-       i1480u_PKT_FRAG_LST = 0x2,
-       i1480u_PKT_FRAG_CMP = 0x3
-};
-enum {
-       i1480u_PKT_NONE = 0x4,
-};
-
-/** USB Network Transfer Descriptor - common */
-struct untd_hdr {
-       u8     type;
-       __le16 len;
-} __attribute__((packed));
-
-static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr)
-{
-       return hdr->type & 0x03;
-}
-
-static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr)
-{
-       return (hdr->type >> 2) & 0x01;
-}
-
-static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type)
-{
-       hdr->type = (hdr->type & ~0x03) | type;
-}
-
-static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx)
-{
-       hdr->type = (hdr->type & ~0x04) | (rx_tx << 2);
-}
-
-
-/**
- * USB Network Transfer Descriptor - Complete Packet
- *
- * This is for a packet that is smaller (header + payload) than
- * i1480u_MAX_FRG_SIZE.
- *
- * @hdr.total_len is the size of the payload; the payload doesn't
- * count this header nor the padding, but includes the size of i1480
- * header.
- */
-struct untd_hdr_cmp {
-       struct untd_hdr hdr;
-       u8              padding;
-} __attribute__((packed));
-
-
-/**
- * USB Network Transfer Descriptor - First fragment
- *
- * @hdr.len is the size of the *whole packet* (excluding UNTD
- * headers); @fragment_len is the size of the payload (excluding UNTD
- * headers, but including i1480 headers).
- */
-struct untd_hdr_1st {
-       struct untd_hdr hdr;
-       __le16          fragment_len;
-       u8              padding[3];
-} __attribute__((packed));
-
-
-/**
- * USB Network Transfer Descriptor - Next / Last [Rest]
- *
- * @hdr.len is the size of the payload, not including headrs.
- */
-struct untd_hdr_rst {
-       struct untd_hdr hdr;
-       u8              padding;
-} __attribute__((packed));
-
-
-/**
- * Transmission context
- *
- * Wraps all the stuff needed to track a pending/active tx
- * operation.
- */
-struct i1480u_tx {
-       struct list_head list_node;
-       struct i1480u *i1480u;
-       struct urb *urb;
-
-       struct sk_buff *skb;
-       struct wlp_tx_hdr *wlp_tx_hdr;
-
-       void *buf;      /* if NULL, no new buf was used */
-       size_t buf_size;
-};
-
-/**
- * Basic flow control
- *
- * We maintain a basic flow control counter. "count" how many TX URBs are
- * outstanding. Only allow "max"
- * TX URBs to be outstanding. If this value is reached the queue will be
- * stopped. The queue will be restarted when there are
- * "threshold" URBs outstanding.
- * Maintain a counter of how many time the TX queue needed to be restarted
- * due to the "max" being exceeded and the "threshold" reached again. The
- * timestamp "restart_ts" is to keep track from when the counter was last
- * queried (see sysfs handling of file wlp_tx_inflight).
- */
-struct i1480u_tx_inflight {
-       atomic_t count;
-       unsigned long max;
-       unsigned long threshold;
-       unsigned long restart_ts;
-       atomic_t restart_count;
-};
-
-/**
- * Instance of a i1480u WLP interface
- *
- * Keeps references to the USB device that wraps it, as well as it's
- * interface and associated UWB host controller. As well, it also
- * keeps a link to the netdevice for integration into the networking
- * stack.
- * We maintian separate error history for the tx and rx endpoints because
- * the implementation does not rely on locking - having one shared
- * structure between endpoints may cause problems. Adding locking to the
- * implementation will have higher cost than adding a separate structure.
- */
-struct i1480u {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       struct net_device *net_dev;
-
-       spinlock_t lock;
-
-       /* RX context handling */
-       struct sk_buff *rx_skb;
-       struct uwb_dev_addr rx_srcaddr;
-       size_t rx_untd_pkt_size;
-       struct i1480u_rx_buf {
-               struct i1480u *i1480u;  /* back pointer */
-               struct urb *urb;
-               struct sk_buff *data;   /* i1480u_MAX_RX_PKT_SIZE each */
-       } rx_buf[i1480u_RX_BUFS];       /* N bufs */
-
-       spinlock_t tx_list_lock;        /* TX context */
-       struct list_head tx_list;
-       u8 tx_stream;
-
-       struct stats lqe_stats, rssi_stats;     /* radio statistics */
-
-       /* Options we can set from sysfs */
-       struct wlp_options options;
-       struct uwb_notifs_handler uwb_notifs_handler;
-       struct edc tx_errors;
-       struct edc rx_errors;
-       struct wlp wlp;
-#ifdef i1480u_FLOW_CONTROL
-       struct urb *notif_urb;
-       struct edc notif_edc;           /* error density counter */
-       u8 notif_buffer[1];
-#endif
-       struct i1480u_tx_inflight tx_inflight;
-};
-
-/* Internal interfaces */
-extern void i1480u_rx_cb(struct urb *urb);
-extern int i1480u_rx_setup(struct i1480u *);
-extern void i1480u_rx_release(struct i1480u *);
-extern void i1480u_tx_release(struct i1480u *);
-extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *,
-                            struct uwb_dev_addr *);
-extern void i1480u_stop_queue(struct wlp *);
-extern void i1480u_start_queue(struct wlp *);
-extern int i1480u_sysfs_setup(struct i1480u *);
-extern void i1480u_sysfs_release(struct i1480u *);
-
-/* netdev interface */
-extern int i1480u_open(struct net_device *);
-extern int i1480u_stop(struct net_device *);
-extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *,
-                                               struct net_device *);
-extern void i1480u_tx_timeout(struct net_device *);
-extern int i1480u_set_config(struct net_device *, struct ifmap *);
-extern int i1480u_change_mtu(struct net_device *, int);
-extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs);
-
-/* bandwidth allocation callback */
-extern void  i1480u_bw_alloc_cb(struct uwb_rsv *);
-
-/* Sys FS */
-extern struct attribute_group i1480u_wlp_attr_group;
-
-#endif /* #ifndef __i1480u_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
deleted file mode 100644 (file)
index def778c..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * This implements a very simple network driver for the WLP USB
- * device that is associated to a UWB (Ultra Wide Band) host.
- *
- * This is seen as an interface of a composite device. Once the UWB
- * host has an association to another WLP capable device, the
- * networking interface (aka WLP) can start to send packets back and
- * forth.
- *
- * Limitations:
- *
- *  - Hand cranked; can't ifup the interface until there is an association
- *
- *  - BW allocation very simplistic [see i1480u_mas_set() and callees].
- *
- *
- * ROADMAP:
- *
- *   ENTRY POINTS (driver model):
- *
- *     i1480u_driver_{exit,init}(): initialization of the driver.
- *
- *     i1480u_probe(): called by the driver code when a device
- *                     matching 'i1480u_id_table' is connected.
- *
- *                     This allocs a netdev instance, inits with
- *                     i1480u_add(), then registers_netdev().
- *         i1480u_init()
- *         i1480u_add()
- *
- *     i1480u_disconnect(): device has been disconnected/module
- *                          is being removed.
- *         i1480u_rm()
- */
-#include <linux/gfp.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-
-#include "i1480u-wlp.h"
-
-
-
-static inline
-void i1480u_init(struct i1480u *i1480u)
-{
-       /* nothing so far... doesn't it suck? */
-       spin_lock_init(&i1480u->lock);
-       INIT_LIST_HEAD(&i1480u->tx_list);
-       spin_lock_init(&i1480u->tx_list_lock);
-       wlp_options_init(&i1480u->options);
-       edc_init(&i1480u->tx_errors);
-       edc_init(&i1480u->rx_errors);
-#ifdef i1480u_FLOW_CONTROL
-       edc_init(&i1480u->notif_edc);
-#endif
-       stats_init(&i1480u->lqe_stats);
-       stats_init(&i1480u->rssi_stats);
-       wlp_init(&i1480u->wlp);
-}
-
-/**
- * Fill WLP device information structure
- *
- * The structure will contain a few character arrays, each ending with a
- * null terminated string. Each string has to fit (excluding terminating
- * character) into a specified range obtained from the WLP substack.
- *
- * It is still not clear exactly how this device information should be
- * obtained. Until we find out we use the USB device descriptor as backup, some
- * information elements have intuitive mappings, other not.
- */
-static
-void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info)
-{
-       struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
-       struct usb_device *usb_dev = i1480u->usb_dev;
-       /* Treat device name and model name the same */
-       if (usb_dev->descriptor.iProduct) {
-               usb_string(usb_dev, usb_dev->descriptor.iProduct,
-                          dev_info->name, sizeof(dev_info->name));
-               usb_string(usb_dev, usb_dev->descriptor.iProduct,
-                          dev_info->model_name, sizeof(dev_info->model_name));
-       }
-       if (usb_dev->descriptor.iManufacturer)
-               usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
-                          dev_info->manufacturer,
-                          sizeof(dev_info->manufacturer));
-       scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x",
-                 __le16_to_cpu(usb_dev->descriptor.bcdDevice));
-       if (usb_dev->descriptor.iSerialNumber)
-               usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
-                          dev_info->serial, sizeof(dev_info->serial));
-       /* FIXME: where should we obtain category? */
-       dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
-       /* FIXME: Complete OUI and OUIsubdiv attributes */
-}
-
-#ifdef i1480u_FLOW_CONTROL
-/**
- * Callback for the notification endpoint
- *
- * This mostly controls the xon/xoff protocol. In case of hard error,
- * we stop the queue. If not, we always retry.
- */
-static
-void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs)
-{
-       struct i1480u *i1480u = urb->context;
-       struct usb_interface *usb_iface = i1480u->usb_iface;
-       struct device *dev = &usb_iface->dev;
-       int result;
-
-       switch (urb->status) {
-       case 0:                         /* Got valid data, do xon/xoff */
-               switch (i1480u->notif_buffer[0]) {
-               case 'N':
-                       dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies);
-                       netif_stop_queue(i1480u->net_dev);
-                       break;
-               case 'A':
-                       dev_err(dev, "XON STARTING queue at %lu\n", jiffies);
-                       netif_start_queue(i1480u->net_dev);
-                       break;
-               default:
-                       dev_err(dev, "NEP: unknown data 0x%02hhx\n",
-                               i1480u->notif_buffer[0]);
-               }
-               break;
-       case -ECONNRESET:               /* Controlled situation ... */
-       case -ENOENT:                   /* we killed the URB... */
-               dev_err(dev, "NEP: URB reset/noent %d\n", urb->status);
-               goto error;
-       case -ESHUTDOWN:                /* going away! */
-               dev_err(dev, "NEP: URB down %d\n", urb->status);
-               goto error;
-       default:                        /* Retry unless it gets ugly */
-               if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "NEP: URB max acceptable errors "
-                               "exceeded; resetting device\n");
-                       goto error_reset;
-               }
-               dev_err(dev, "NEP: URB error %d\n", urb->status);
-               break;
-       }
-       result = usb_submit_urb(urb, GFP_ATOMIC);
-       if (result < 0) {
-               dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n",
-                       result);
-               goto error_reset;
-       }
-       return;
-
-error_reset:
-       wlp_reset_all(&i1480-wlp);
-error:
-       netif_stop_queue(i1480u->net_dev);
-       return;
-}
-#endif
-
-static const struct net_device_ops i1480u_netdev_ops = {
-       .ndo_open       = i1480u_open,
-       .ndo_stop       = i1480u_stop,
-       .ndo_start_xmit = i1480u_hard_start_xmit,
-       .ndo_tx_timeout = i1480u_tx_timeout,
-       .ndo_set_config = i1480u_set_config,
-       .ndo_change_mtu = i1480u_change_mtu,
-};
-
-static
-int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
-{
-       int result = -ENODEV;
-       struct wlp *wlp = &i1480u->wlp;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       struct net_device *net_dev = i1480u->net_dev;
-       struct uwb_rc *rc;
-       struct uwb_dev *uwb_dev;
-#ifdef i1480u_FLOW_CONTROL
-       struct usb_endpoint_descriptor *epd;
-#endif
-
-       i1480u->usb_dev = usb_get_dev(usb_dev);
-       i1480u->usb_iface = iface;
-       rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev);
-       if (rc == NULL) {
-               dev_err(&iface->dev, "Cannot get associated UWB Radio "
-                       "Controller\n");
-               goto out;
-       }
-       wlp->xmit_frame = i1480u_xmit_frame;
-       wlp->fill_device_info = i1480u_fill_device_info;
-       wlp->stop_queue = i1480u_stop_queue;
-       wlp->start_queue = i1480u_start_queue;
-       result = wlp_setup(wlp, rc, net_dev);
-       if (result < 0) {
-               dev_err(&iface->dev, "Cannot setup WLP\n");
-               goto error_wlp_setup;
-       }
-       result = 0;
-       ether_setup(net_dev);                   /* make it an etherdevice */
-       uwb_dev = &rc->uwb_dev;
-       /* FIXME: hookup address change notifications? */
-
-       memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data,
-              sizeof(net_dev->dev_addr));
-
-       net_dev->hard_header_len = sizeof(struct untd_hdr_cmp)
-               + sizeof(struct wlp_tx_hdr)
-               + WLP_DATA_HLEN
-               + ETH_HLEN;
-       net_dev->mtu = 3500;
-       net_dev->tx_queue_len = 20;             /* FIXME: maybe use 1000? */
-
-/*     net_dev->flags &= ~IFF_BROADCAST;       FIXME: BUG in firmware */
-       /* FIXME: multicast disabled */
-       net_dev->flags &= ~IFF_MULTICAST;
-       net_dev->features &= ~NETIF_F_SG;
-       net_dev->features &= ~NETIF_F_FRAGLIST;
-       /* All NETIF_F_*_CSUM disabled */
-       net_dev->features |= NETIF_F_HIGHDMA;
-       net_dev->watchdog_timeo = 5*HZ;         /* FIXME: a better default? */
-
-       net_dev->netdev_ops = &i1480u_netdev_ops;
-
-#ifdef i1480u_FLOW_CONTROL
-       /* Notification endpoint setup (submitted when we open the device) */
-       i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (i1480u->notif_urb == NULL) {
-               dev_err(&iface->dev, "Unable to allocate notification URB\n");
-               result = -ENOMEM;
-               goto error_urb_alloc;
-       }
-       epd = &iface->cur_altsetting->endpoint[0].desc;
-       usb_fill_int_urb(i1480u->notif_urb, usb_dev,
-                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
-                        i1480u->notif_buffer, sizeof(i1480u->notif_buffer),
-                        i1480u_notif_cb, i1480u, epd->bInterval);
-
-#endif
-
-       i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX;
-       i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
-       i1480u->tx_inflight.restart_ts = jiffies;
-       usb_set_intfdata(iface, i1480u);
-       return result;
-
-#ifdef i1480u_FLOW_CONTROL
-error_urb_alloc:
-#endif
-       wlp_remove(wlp);
-error_wlp_setup:
-       uwb_rc_put(rc);
-out:
-       usb_put_dev(i1480u->usb_dev);
-       return result;
-}
-
-static void i1480u_rm(struct i1480u *i1480u)
-{
-       struct uwb_rc *rc = i1480u->wlp.rc;
-       usb_set_intfdata(i1480u->usb_iface, NULL);
-#ifdef i1480u_FLOW_CONTROL
-       usb_kill_urb(i1480u->notif_urb);
-       usb_free_urb(i1480u->notif_urb);
-#endif
-       wlp_remove(&i1480u->wlp);
-       uwb_rc_put(rc);
-       usb_put_dev(i1480u->usb_dev);
-}
-
-/** Just setup @net_dev's i1480u private data */
-static void i1480u_netdev_setup(struct net_device *net_dev)
-{
-       struct i1480u *i1480u = netdev_priv(net_dev);
-       /* Initialize @i1480u */
-       memset(i1480u, 0, sizeof(*i1480u));
-       i1480u_init(i1480u);
-}
-
-/**
- * Probe a i1480u interface and register it
- *
- * @iface:   USB interface to link to
- * @id:      USB class/subclass/protocol id
- * @returns: 0 if ok, < 0 errno code on error.
- *
- * Does basic housekeeping stuff and then allocs a netdev with space
- * for the i1480u  data. Initializes, registers in i1480u, registers in
- * netdev, ready to go.
- */
-static int i1480u_probe(struct usb_interface *iface,
-                       const struct usb_device_id *id)
-{
-       int result;
-       struct net_device *net_dev;
-       struct device *dev = &iface->dev;
-       struct i1480u *i1480u;
-
-       /* Allocate instance [calls i1480u_netdev_setup() on it] */
-       result = -ENOMEM;
-       net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup);
-       if (net_dev == NULL) {
-               dev_err(dev, "no memory for network device instance\n");
-               goto error_alloc_netdev;
-       }
-       SET_NETDEV_DEV(net_dev, dev);
-       i1480u = netdev_priv(net_dev);
-       i1480u->net_dev = net_dev;
-       result = i1480u_add(i1480u, iface);     /* Now setup all the wlp stuff */
-       if (result < 0) {
-               dev_err(dev, "cannot add i1480u device: %d\n", result);
-               goto error_i1480u_add;
-       }
-       result = register_netdev(net_dev);      /* Okey dokey, bring it up */
-       if (result < 0) {
-               dev_err(dev, "cannot register network device: %d\n", result);
-               goto error_register_netdev;
-       }
-       i1480u_sysfs_setup(i1480u);
-       if (result < 0)
-               goto error_sysfs_init;
-       return 0;
-
-error_sysfs_init:
-       unregister_netdev(net_dev);
-error_register_netdev:
-       i1480u_rm(i1480u);
-error_i1480u_add:
-       free_netdev(net_dev);
-error_alloc_netdev:
-       return result;
-}
-
-
-/**
- * Disconect a i1480u from the system.
- *
- * i1480u_stop() has been called before, so al the rx and tx contexts
- * have been taken down already. Make sure the queue is stopped,
- * unregister netdev and i1480u, free and kill.
- */
-static void i1480u_disconnect(struct usb_interface *iface)
-{
-       struct i1480u *i1480u;
-       struct net_device *net_dev;
-
-       i1480u = usb_get_intfdata(iface);
-       net_dev = i1480u->net_dev;
-       netif_stop_queue(net_dev);
-#ifdef i1480u_FLOW_CONTROL
-       usb_kill_urb(i1480u->notif_urb);
-#endif
-       i1480u_sysfs_release(i1480u);
-       unregister_netdev(net_dev);
-       i1480u_rm(i1480u);
-       free_netdev(net_dev);
-}
-
-static struct usb_device_id i1480u_id_table[] = {
-       {
-               .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
-                               |  USB_DEVICE_ID_MATCH_DEV_INFO \
-                               |  USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor = 0x8086,
-               .idProduct = 0x0c3b,
-               .bDeviceClass = 0xef,
-               .bDeviceSubClass = 0x02,
-               .bDeviceProtocol = 0x02,
-               .bInterfaceClass = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(usb, i1480u_id_table);
-
-static struct usb_driver i1480u_driver = {
-       .name =         KBUILD_MODNAME,
-       .probe =        i1480u_probe,
-       .disconnect =   i1480u_disconnect,
-       .id_table =     i1480u_id_table,
-};
-
-static int __init i1480u_driver_init(void)
-{
-       return usb_register(&i1480u_driver);
-}
-module_init(i1480u_driver_init);
-
-
-static void __exit i1480u_driver_exit(void)
-{
-       usb_deregister(&i1480u_driver);
-}
-module_exit(i1480u_driver_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c
deleted file mode 100644 (file)
index f98f6ce..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * Implementation of the netdevice linkage (except tx and rx related stuff).
- *
- * ROADMAP:
- *
- *   ENTRY POINTS (Net device):
- *
- *     i1480u_open(): Called when we ifconfig up the interface;
- *                    associates to a UWB host controller, reserves
- *                    bandwidth (MAS), sets up RX USB URB and starts
- *                    the queue.
- *
- *     i1480u_stop(): Called when we ifconfig down a interface;
- *                    reverses _open().
- *
- *     i1480u_set_config():
- */
-
-#include <linux/slab.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-
-#include "i1480u-wlp.h"
-
-struct i1480u_cmd_set_ip_mas {
-       struct uwb_rccb     rccb;
-       struct uwb_dev_addr addr;
-       u8                  stream;
-       u8                  owner;
-       u8                  type;       /* enum uwb_drp_type */
-       u8                  baMAS[32];
-} __attribute__((packed));
-
-
-static
-int i1480u_set_ip_mas(
-       struct uwb_rc *rc,
-       const struct uwb_dev_addr *dstaddr,
-       u8 stream, u8 owner, u8 type, unsigned long *mas)
-{
-
-       int result;
-       struct i1480u_cmd_set_ip_mas *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       result = -ENOMEM;
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       cmd->rccb.bCommandType = 0xfd;
-       cmd->rccb.wCommand = cpu_to_le16(0x000e);
-       cmd->addr = *dstaddr;
-       cmd->stream = stream;
-       cmd->owner = owner;
-       cmd->type = type;
-       if (mas == NULL)
-               memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS));
-       else
-               memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS));
-       reply.rceb.bEventType = 0xfd;
-       reply.rceb.wEvent = cpu_to_le16(0x000e);
-       result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_FAIL) {
-               dev_err(&rc->uwb_dev.dev,
-                       "SET-IP-MAS: command execution failed: %d\n",
-                       reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-error_kzalloc:
-       return result;
-}
-
-/*
- * Inform a WLP interface of a MAS reservation
- *
- * @rc is assumed refcnted.
- */
-/* FIXME: detect if remote device is WLP capable? */
-static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc,
-                             u8 stream, u8 owner, u8 type, unsigned long *mas)
-{
-       int result = 0;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner,
-                                  type, mas);
-       if (result < 0) {
-               char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE];
-               uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf),
-                                  &rc->uwb_dev.dev_addr);
-               uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf),
-                                  &uwb_dev->dev_addr);
-               dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n",
-                       rcaddrbuf, devaddrbuf, result);
-       }
-       return result;
-}
-
-/**
- * Called by bandwidth allocator when change occurs in reservation.
- *
- * @rsv:     The reservation that is being established, modified, or
- *           terminated.
- *
- * When a reservation is established, modified, or terminated the upper layer
- * (WLP here) needs set/update the currently available Media Access Slots
- * that can be use for IP traffic.
- *
- * Our action taken during failure depends on how the reservation is being
- * changed:
- * - if reservation is being established we do nothing if we cannot set the
- *   new MAS to be used
- * - if reservation is being terminated we revert back to PCA whether the
- *   SET IP MAS command succeeds or not.
- */
-void i1480u_bw_alloc_cb(struct uwb_rsv *rsv)
-{
-       int result = 0;
-       struct i1480u *i1480u = rsv->pal_priv;
-       struct device *dev = &i1480u->usb_iface->dev;
-       struct uwb_dev *target_dev = rsv->target.dev;
-       struct uwb_rc *rc = i1480u->wlp.rc;
-       u8 stream = rsv->stream;
-       int type = rsv->type;
-       int is_owner = rsv->owner == &rc->uwb_dev;
-       unsigned long *bmp = rsv->mas.bm;
-
-       dev_err(dev, "WLP callback called - sending set ip mas\n");
-       /*user cannot change options while setting configuration*/
-       mutex_lock(&i1480u->options.mutex);
-       switch (rsv->state) {
-       case UWB_RSV_STATE_T_ACCEPTED:
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
-                                       type, bmp);
-               if (result < 0) {
-                       dev_err(dev, "MAS reservation failed: %d\n", result);
-                       goto out;
-               }
-               if (is_owner) {
-                       wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
-                                                       WLP_DRP | stream);
-                       wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0);
-               }
-               break;
-       case UWB_RSV_STATE_NONE:
-               /* revert back to PCA */
-               result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
-                                           type, bmp);
-               if (result < 0)
-                       dev_err(dev, "MAS reservation failed: %d\n", result);
-               /* Revert to PCA even though SET IP MAS failed. */
-               wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
-                                               i1480u->options.pca_base_priority);
-               wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1);
-               break;
-       default:
-               dev_err(dev, "unexpected WLP reservation state: %s (%d).\n",
-                       uwb_rsv_state_str(rsv->state), rsv->state);
-               break;
-       }
-out:
-       mutex_unlock(&i1480u->options.mutex);
-       return;
-}
-
-/**
- *
- * Called on 'ifconfig up'
- */
-int i1480u_open(struct net_device *net_dev)
-{
-       int result;
-       struct i1480u *i1480u = netdev_priv(net_dev);
-       struct wlp *wlp = &i1480u->wlp;
-       struct uwb_rc *rc;
-       struct device *dev = &i1480u->usb_iface->dev;
-
-       rc = wlp->rc;
-       result = i1480u_rx_setup(i1480u);               /* Alloc RX stuff */
-       if (result < 0)
-               goto error_rx_setup;
-
-       result = uwb_radio_start(&wlp->pal);
-       if (result < 0)
-               goto error_radio_start;
-
-       netif_wake_queue(net_dev);
-#ifdef i1480u_FLOW_CONTROL
-       result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "Can't submit notification URB: %d\n", result);
-               goto error_notif_urb_submit;
-       }
-#endif
-       /* Interface is up with an address, now we can create WSS */
-       result = wlp_wss_setup(net_dev, &wlp->wss);
-       if (result < 0) {
-               dev_err(dev, "Can't create WSS: %d. \n", result);
-               goto error_wss_setup;
-       }
-       return 0;
-error_wss_setup:
-#ifdef i1480u_FLOW_CONTROL
-       usb_kill_urb(i1480u->notif_urb);
-error_notif_urb_submit:
-#endif
-       uwb_radio_stop(&wlp->pal);
-error_radio_start:
-       netif_stop_queue(net_dev);
-       i1480u_rx_release(i1480u);
-error_rx_setup:
-       return result;
-}
-
-
-/**
- * Called on 'ifconfig down'
- */
-int i1480u_stop(struct net_device *net_dev)
-{
-       struct i1480u *i1480u = netdev_priv(net_dev);
-       struct wlp *wlp = &i1480u->wlp;
-
-       BUG_ON(wlp->rc == NULL);
-       wlp_wss_remove(&wlp->wss);
-       netif_carrier_off(net_dev);
-#ifdef i1480u_FLOW_CONTROL
-       usb_kill_urb(i1480u->notif_urb);
-#endif
-       netif_stop_queue(net_dev);
-       uwb_radio_stop(&wlp->pal);
-       i1480u_rx_release(i1480u);
-       i1480u_tx_release(i1480u);
-       return 0;
-}
-
-/**
- *
- * Change the interface config--we probably don't have to do anything.
- */
-int i1480u_set_config(struct net_device *net_dev, struct ifmap *map)
-{
-       int result;
-       struct i1480u *i1480u = netdev_priv(net_dev);
-       BUG_ON(i1480u->wlp.rc == NULL);
-       result = 0;
-       return result;
-}
-
-/**
- * Change the MTU of the interface
- */
-int i1480u_change_mtu(struct net_device *net_dev, int mtu)
-{
-       static union {
-               struct wlp_tx_hdr tx;
-               struct wlp_rx_hdr rx;
-       } i1480u_all_hdrs;
-
-       if (mtu < ETH_HLEN)     /* We encap eth frames */
-               return -ERANGE;
-       if (mtu > 4000 - sizeof(i1480u_all_hdrs))
-               return -ERANGE;
-       net_dev->mtu = mtu;
-       return 0;
-}
-
-/**
- * Stop the network queue
- *
- * Enable WLP substack to stop network queue. We also set the flow control
- * threshold at this time to prevent the flow control from restarting the
- * queue.
- *
- * we are loosing the current threshold value here ... FIXME?
- */
-void i1480u_stop_queue(struct wlp *wlp)
-{
-       struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
-       struct net_device *net_dev = i1480u->net_dev;
-       i1480u->tx_inflight.threshold = 0;
-       netif_stop_queue(net_dev);
-}
-
-/**
- * Start the network queue
- *
- * Enable WLP substack to start network queue. Also re-enable the flow
- * control to manage the queue again.
- *
- * We re-enable the flow control by storing the default threshold in the
- * flow control threshold. This means that if the user modified the
- * threshold before the queue was stopped and restarted that information
- * will be lost. FIXME?
- */
-void i1480u_start_queue(struct wlp *wlp)
-{
-       struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
-       struct net_device *net_dev = i1480u->net_dev;
-       i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
-       netif_start_queue(net_dev);
-}
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c
deleted file mode 100644 (file)
index d4e51e1..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * i1480u's RX handling is simple. i1480u will send the received
- * network packets broken up in fragments; 1 to N fragments make a
- * packet, we assemble them together and deliver the packet with netif_rx().
- *
- * Beacuse each USB transfer is a *single* fragment (except when the
- * transfer contains a first fragment), each URB called thus
- * back contains one or two fragments. So we queue N URBs, each with its own
- * fragment buffer. When a URB is done, we process it (adding to the
- * current skb from the fragment buffer until complete). Once
- * processed, we requeue the URB. There is always a bunch of URBs
- * ready to take data, so the intergap should be minimal.
- *
- * An URB's transfer buffer is the data field of a socket buffer. This
- * reduces copying as data can be passed directly to network layer. If a
- * complete packet or 1st fragment is received the URB's transfer buffer is
- * taken away from it and used to send data to the network layer. In this
- * case a new transfer buffer is allocated to the URB before being requeued.
- * If a "NEXT" or "LAST" fragment is received, the fragment contents is
- * appended to the RX packet under construction and the transfer buffer
- * is reused. To be able to use this buffer to assemble complete packets
- * we set each buffer's size to that of the MAX ethernet packet that can
- * be received. There is thus room for improvement in memory usage.
- *
- * When the max tx fragment size increases, we should be able to read
- * data into the skbs directly with very simple code.
- *
- * ROADMAP:
- *
- *   ENTRY POINTS:
- *
- *     i1480u_rx_setup(): setup RX context [from i1480u_open()]
- *
- *     i1480u_rx_release(): release RX context [from i1480u_stop()]
- *
- *     i1480u_rx_cb(): called when the RX USB URB receives a
- *                     packet. It removes the header and pushes it up
- *                     the Linux netdev stack with netif_rx().
- *
- *       i1480u_rx_buffer()
- *         i1480u_drop() and i1480u_fix()
- *         i1480u_skb_deliver
- *
- */
-
-#include <linux/gfp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "i1480u-wlp.h"
-
-/*
- * Setup the RX context
- *
- * Each URB is provided with a transfer_buffer that is the data field
- * of a new socket buffer.
- */
-int i1480u_rx_setup(struct i1480u *i1480u)
-{
-       int result, cnt;
-       struct device *dev = &i1480u->usb_iface->dev;
-       struct net_device *net_dev = i1480u->net_dev;
-       struct usb_endpoint_descriptor *epd;
-       struct sk_buff *skb;
-
-       /* Alloc RX stuff */
-       i1480u->rx_skb = NULL;  /* not in process of receiving packet */
-       result = -ENOMEM;
-       epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc;
-       for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
-               struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt];
-               rx_buf->i1480u = i1480u;
-               skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
-               if (!skb) {
-                       dev_err(dev,
-                               "RX: cannot allocate RX buffer %d\n", cnt);
-                       result = -ENOMEM;
-                       goto error;
-               }
-               skb->dev = net_dev;
-               skb->ip_summed = CHECKSUM_NONE;
-               skb_reserve(skb, 2);
-               rx_buf->data = skb;
-               rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (unlikely(rx_buf->urb == NULL)) {
-                       dev_err(dev, "RX: cannot allocate URB %d\n", cnt);
-                       result = -ENOMEM;
-                       goto error;
-               }
-               usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev,
-                         usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress),
-                         rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2,
-                         i1480u_rx_cb, rx_buf);
-               result = usb_submit_urb(rx_buf->urb, GFP_NOIO);
-               if (unlikely(result < 0)) {
-                       dev_err(dev, "RX: cannot submit URB %d: %d\n",
-                               cnt, result);
-                       goto error;
-               }
-       }
-       return 0;
-
-error:
-       i1480u_rx_release(i1480u);
-       return result;
-}
-
-
-/* Release resources associated to the rx context */
-void i1480u_rx_release(struct i1480u *i1480u)
-{
-       int cnt;
-       for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
-               if (i1480u->rx_buf[cnt].data)
-                       dev_kfree_skb(i1480u->rx_buf[cnt].data);
-               if (i1480u->rx_buf[cnt].urb) {
-                       usb_kill_urb(i1480u->rx_buf[cnt].urb);
-                       usb_free_urb(i1480u->rx_buf[cnt].urb);
-               }
-       }
-       if (i1480u->rx_skb != NULL)
-               dev_kfree_skb(i1480u->rx_skb);
-}
-
-static
-void i1480u_rx_unlink_urbs(struct i1480u *i1480u)
-{
-       int cnt;
-       for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
-               if (i1480u->rx_buf[cnt].urb)
-                       usb_unlink_urb(i1480u->rx_buf[cnt].urb);
-       }
-}
-
-/* Fix an out-of-sequence packet */
-#define i1480u_fix(i1480u, msg...)                     \
-do {                                                   \
-       if (printk_ratelimit())                         \
-               dev_err(&i1480u->usb_iface->dev, msg);  \
-       dev_kfree_skb_irq(i1480u->rx_skb);              \
-       i1480u->rx_skb = NULL;                          \
-       i1480u->rx_untd_pkt_size = 0;                   \
-} while (0)
-
-
-/* Drop an out-of-sequence packet */
-#define i1480u_drop(i1480u, msg...)                    \
-do {                                                   \
-       if (printk_ratelimit())                         \
-               dev_err(&i1480u->usb_iface->dev, msg);  \
-       i1480u->net_dev->stats.rx_dropped++;                    \
-} while (0)
-
-
-
-
-/* Finalizes setting up the SKB and delivers it
- *
- * We first pass the incoming frame to WLP substack for verification. It
- * may also be a WLP association frame in which case WLP will take over the
- * processing. If WLP does not take it over it will still verify it, if the
- * frame is invalid the skb will be freed by WLP and we will not continue
- * parsing.
- * */
-static
-void i1480u_skb_deliver(struct i1480u *i1480u)
-{
-       int should_parse;
-       struct net_device *net_dev = i1480u->net_dev;
-       struct device *dev = &i1480u->usb_iface->dev;
-
-       should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
-                                        &i1480u->rx_srcaddr);
-       if (!should_parse)
-               goto out;
-       i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
-       net_dev->stats.rx_packets++;
-       net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size;
-
-       netif_rx(i1480u->rx_skb);               /* deliver */
-out:
-       i1480u->rx_skb = NULL;
-       i1480u->rx_untd_pkt_size = 0;
-}
-
-
-/*
- * Process a buffer of data received from the USB RX endpoint
- *
- * First fragment arrives with next or last fragment. All other fragments
- * arrive alone.
- *
- * /me hates long functions.
- */
-static
-void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf)
-{
-       unsigned pkt_completed = 0;     /* !0 when we got all pkt fragments */
-       size_t untd_hdr_size, untd_frg_size;
-       size_t i1480u_hdr_size;
-       struct wlp_rx_hdr *i1480u_hdr = NULL;
-
-       struct i1480u *i1480u = rx_buf->i1480u;
-       struct sk_buff *skb = rx_buf->data;
-       int size_left = rx_buf->urb->actual_length;
-       void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */
-       struct untd_hdr *untd_hdr;
-
-       struct net_device *net_dev = i1480u->net_dev;
-       struct device *dev = &i1480u->usb_iface->dev;
-       struct sk_buff *new_skb;
-
-#if 0
-       dev_fnstart(dev,
-                   "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left);
-       dev_err(dev, "RX packet, %zu bytes\n", size_left);
-       dump_bytes(dev, ptr, size_left);
-#endif
-       i1480u_hdr_size = sizeof(struct wlp_rx_hdr);
-
-       while (size_left > 0) {
-               if (pkt_completed) {
-                       i1480u_drop(i1480u, "RX: fragment follows completed"
-                                        "packet in same buffer. Dropping\n");
-                       break;
-               }
-               untd_hdr = ptr;
-               if (size_left < sizeof(*untd_hdr)) {    /*  Check the UNTD header */
-                       i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n");
-                       goto out;
-               }
-               if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) {  /* Paranoia: TX set? */
-                       i1480u_drop(i1480u, "RX: TX bit set! Dropping\n");
-                       goto out;
-               }
-               switch (untd_hdr_type(untd_hdr)) {      /* Check the UNTD header type */
-               case i1480u_PKT_FRAG_1ST: {
-                       struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr;
-                       dev_dbg(dev, "1st fragment\n");
-                       untd_hdr_size = sizeof(struct untd_hdr_1st);
-                       if (i1480u->rx_skb != NULL)
-                               i1480u_fix(i1480u, "RX: 1st fragment out of "
-                                       "sequence! Fixing\n");
-                       if (size_left < untd_hdr_size + i1480u_hdr_size) {
-                               i1480u_drop(i1480u, "RX: short 1st fragment! "
-                                       "Dropping\n");
-                               goto out;
-                       }
-                       i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len)
-                                                - i1480u_hdr_size;
-                       untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len);
-                       if (size_left < untd_hdr_size + untd_frg_size) {
-                               i1480u_drop(i1480u,
-                                           "RX: short payload! Dropping\n");
-                               goto out;
-                       }
-                       i1480u->rx_skb = skb;
-                       i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size;
-                       i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
-                       skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size);
-                       skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
-                       stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
-                       stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
-                       rx_buf->data = NULL; /* need to create new buffer */
-                       break;
-               }
-               case i1480u_PKT_FRAG_NXT: {
-                       dev_dbg(dev, "nxt fragment\n");
-                       untd_hdr_size = sizeof(struct untd_hdr_rst);
-                       if (i1480u->rx_skb == NULL) {
-                               i1480u_drop(i1480u, "RX: next fragment out of "
-                                           "sequence! Dropping\n");
-                               goto out;
-                       }
-                       if (size_left < untd_hdr_size) {
-                               i1480u_drop(i1480u, "RX: short NXT fragment! "
-                                           "Dropping\n");
-                               goto out;
-                       }
-                       untd_frg_size = le16_to_cpu(untd_hdr->len);
-                       if (size_left < untd_hdr_size + untd_frg_size) {
-                               i1480u_drop(i1480u,
-                                           "RX: short payload! Dropping\n");
-                               goto out;
-                       }
-                       memmove(skb_put(i1480u->rx_skb, untd_frg_size),
-                                       ptr + untd_hdr_size, untd_frg_size);
-                       break;
-               }
-               case i1480u_PKT_FRAG_LST: {
-                       dev_dbg(dev, "Lst fragment\n");
-                       untd_hdr_size = sizeof(struct untd_hdr_rst);
-                       if (i1480u->rx_skb == NULL) {
-                               i1480u_drop(i1480u, "RX: last fragment out of "
-                                           "sequence! Dropping\n");
-                               goto out;
-                       }
-                       if (size_left < untd_hdr_size) {
-                               i1480u_drop(i1480u, "RX: short LST fragment! "
-                                           "Dropping\n");
-                               goto out;
-                       }
-                       untd_frg_size = le16_to_cpu(untd_hdr->len);
-                       if (size_left < untd_frg_size + untd_hdr_size) {
-                               i1480u_drop(i1480u,
-                                           "RX: short payload! Dropping\n");
-                               goto out;
-                       }
-                       memmove(skb_put(i1480u->rx_skb, untd_frg_size),
-                                       ptr + untd_hdr_size, untd_frg_size);
-                       pkt_completed = 1;
-                       break;
-               }
-               case i1480u_PKT_FRAG_CMP: {
-                       dev_dbg(dev, "cmp fragment\n");
-                       untd_hdr_size = sizeof(struct untd_hdr_cmp);
-                       if (i1480u->rx_skb != NULL)
-                               i1480u_fix(i1480u, "RX: fix out-of-sequence CMP"
-                                          " fragment!\n");
-                       if (size_left < untd_hdr_size + i1480u_hdr_size) {
-                               i1480u_drop(i1480u, "RX: short CMP fragment! "
-                                           "Dropping\n");
-                               goto out;
-                       }
-                       i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len);
-                       untd_frg_size = i1480u->rx_untd_pkt_size;
-                       if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) {
-                               i1480u_drop(i1480u,
-                                           "RX: short payload! Dropping\n");
-                               goto out;
-                       }
-                       i1480u->rx_skb = skb;
-                       i1480u_hdr = (void *) untd_hdr + untd_hdr_size;
-                       i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
-                       stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
-                       stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
-                       skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size);
-                       skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
-                       rx_buf->data = NULL;    /* for hand off skb to network stack */
-                       pkt_completed = 1;
-                       i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */
-                       break;
-               }
-               default:
-                       i1480u_drop(i1480u, "RX: unknown packet type %u! "
-                                   "Dropping\n", untd_hdr_type(untd_hdr));
-                       goto out;
-               }
-               size_left -= untd_hdr_size + untd_frg_size;
-               if (size_left > 0)
-                       ptr += untd_hdr_size + untd_frg_size;
-       }
-       if (pkt_completed)
-               i1480u_skb_deliver(i1480u);
-out:
-       /* recreate needed RX buffers*/
-       if (rx_buf->data == NULL) {
-               /* buffer is being used to receive packet, create new */
-               new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
-               if (!new_skb) {
-                       if (printk_ratelimit())
-                               dev_err(dev,
-                               "RX: cannot allocate RX buffer\n");
-               } else {
-                       new_skb->dev = net_dev;
-                       new_skb->ip_summed = CHECKSUM_NONE;
-                       skb_reserve(new_skb, 2);
-                       rx_buf->data = new_skb;
-               }
-       }
-       return;
-}
-
-
-/*
- * Called when an RX URB has finished receiving or has found some kind
- * of error condition.
- *
- * LIMITATIONS:
- *
- *  - We read USB-transfers, each transfer contains a SINGLE fragment
- *    (can contain a complete packet, or a 1st, next, or last fragment
- *    of a packet).
- *    Looks like a transfer can contain more than one fragment (07/18/06)
- *
- *  - Each transfer buffer is the size of the maximum packet size (minus
- *    headroom), i1480u_MAX_PKT_SIZE - 2
- *
- *  - We always read the full USB-transfer, no partials.
- *
- *  - Each transfer is read directly into a skb. This skb will be used to
- *    send data to the upper layers if it is the first fragment or a complete
- *    packet. In the other cases the data will be copied from the skb to
- *    another skb that is being prepared for the upper layers from a prev
- *    first fragment.
- *
- * It is simply too much of a pain. Gosh, there should be a unified
- * SG infrastructure for *everything* [so that I could declare a SG
- * buffer, pass it to USB for receiving, append some space to it if
- * I wish, receive more until I have the whole chunk, adapt
- * pointers on each fragment to remove hardware headers and then
- * attach that to an skbuff and netif_rx()].
- */
-void i1480u_rx_cb(struct urb *urb)
-{
-       int result;
-       int do_parse_buffer = 1;
-       struct i1480u_rx_buf *rx_buf = urb->context;
-       struct i1480u *i1480u = rx_buf->i1480u;
-       struct device *dev = &i1480u->usb_iface->dev;
-       unsigned long flags;
-       u8 rx_buf_idx = rx_buf - i1480u->rx_buf;
-
-       switch (urb->status) {
-       case 0:
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-       case -ESHUTDOWN:        /* going away! */
-               dev_err(dev, "RX URB[%u]: goind down %d\n",
-                       rx_buf_idx, urb->status);
-               goto error;
-       default:
-               dev_err(dev, "RX URB[%u]: unknown status %d\n",
-                       rx_buf_idx, urb->status);
-               if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS,
-                                       EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "RX: max acceptable errors exceeded,"
-                                       " resetting device.\n");
-                       i1480u_rx_unlink_urbs(i1480u);
-                       wlp_reset_all(&i1480u->wlp);
-                       goto error;
-               }
-               do_parse_buffer = 0;
-               break;
-       }
-       spin_lock_irqsave(&i1480u->lock, flags);
-       /* chew the data fragments, extract network packets */
-       if (do_parse_buffer) {
-               i1480u_rx_buffer(rx_buf);
-               if (rx_buf->data) {
-                       rx_buf->urb->transfer_buffer = rx_buf->data->data;
-                       result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC);
-                       if (result < 0) {
-                               dev_err(dev, "RX URB[%u]: cannot submit %d\n",
-                                       rx_buf_idx, result);
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&i1480u->lock, flags);
-error:
-       return;
-}
-
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
deleted file mode 100644 (file)
index 4ffaf54..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Sysfs interfaces
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/device.h>
-
-#include "i1480u-wlp.h"
-
-
-/**
- *
- * @dev: Class device from the net_device; assumed refcnted.
- *
- * Yes, I don't lock--we assume it is refcounted and I am getting a
- * single byte value that is kind of atomic to read.
- */
-ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf)
-{
-       return sprintf(buf, "%u\n",
-                      wlp_tx_hdr_phy_rate(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_phy_rate_show);
-
-
-ssize_t uwb_phy_rate_store(struct wlp_options *options,
-                          const char *buf, size_t size)
-{
-       ssize_t result;
-       unsigned rate;
-
-       result = sscanf(buf, "%u\n", &rate);
-       if (result != 1) {
-               result = -EINVAL;
-               goto out;
-       }
-       result = -EINVAL;
-       if (rate >= UWB_PHY_RATE_INVALID)
-               goto out;
-       wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate);
-       result = 0;
-out:
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_phy_rate_store);
-
-
-ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf)
-{
-       return sprintf(buf, "%u\n",
-                      wlp_tx_hdr_rts_cts(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_rts_cts_show);
-
-
-ssize_t uwb_rts_cts_store(struct wlp_options *options,
-                         const char *buf, size_t size)
-{
-       ssize_t result;
-       unsigned value;
-
-       result = sscanf(buf, "%u\n", &value);
-       if (result != 1) {
-               result = -EINVAL;
-               goto out;
-       }
-       result = -EINVAL;
-       wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value);
-       result = 0;
-out:
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_rts_cts_store);
-
-
-ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf)
-{
-       return sprintf(buf, "%u\n",
-                      wlp_tx_hdr_ack_policy(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_ack_policy_show);
-
-
-ssize_t uwb_ack_policy_store(struct wlp_options *options,
-                            const char *buf, size_t size)
-{
-       ssize_t result;
-       unsigned value;
-
-       result = sscanf(buf, "%u\n", &value);
-       if (result != 1 || value > UWB_ACK_B_REQ) {
-               result = -EINVAL;
-               goto out;
-       }
-       wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value);
-       result = 0;
-out:
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_ack_policy_store);
-
-
-/**
- * Show the PCA base priority.
- *
- * We can access without locking, as the value is (for now) orthogonal
- * to other values.
- */
-ssize_t uwb_pca_base_priority_show(const struct wlp_options *options,
-                                  char *buf)
-{
-       return sprintf(buf, "%u\n",
-                      options->pca_base_priority);
-}
-EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show);
-
-
-/**
- * Set the PCA base priority.
- *
- * We can access without locking, as the value is (for now) orthogonal
- * to other values.
- */
-ssize_t uwb_pca_base_priority_store(struct wlp_options *options,
-                                   const char *buf, size_t size)
-{
-       ssize_t result = -EINVAL;
-       u8 pca_base_priority;
-
-       result = sscanf(buf, "%hhu\n", &pca_base_priority);
-       if (result != 1) {
-               result = -EINVAL;
-               goto out;
-       }
-       result = -EINVAL;
-       if (pca_base_priority >= 8)
-               goto out;
-       options->pca_base_priority = pca_base_priority;
-       /* Update TX header if we are currently using PCA. */
-       if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0)
-               wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority);
-       result = 0;
-out:
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store);
-
-/**
- * Show current inflight values
- *
- * Will print the current MAX and THRESHOLD values for the basic flow
- * control. In addition it will report how many times the TX queue needed
- * to be restarted since the last time this query was made.
- */
-static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight,
-                                   char *buf)
-{
-       ssize_t result;
-       unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ;
-       unsigned long restart_count = atomic_read(&inflight->restart_count);
-
-       result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n"
-                          "#read: threshold max inflight_count restarts "
-                          "seconds restarts/sec\n"
-                          "#write: threshold max\n",
-                          inflight->threshold, inflight->max,
-                          atomic_read(&inflight->count),
-                          restart_count, sec_elapsed,
-                          sec_elapsed == 0 ? 0 : restart_count/sec_elapsed);
-       inflight->restart_ts = jiffies;
-       atomic_set(&inflight->restart_count, 0);
-       return result;
-}
-
-static
-ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight,
-                               const char *buf, size_t size)
-{
-       unsigned long in_threshold, in_max;
-       ssize_t result;
-       result = sscanf(buf, "%lu %lu", &in_threshold, &in_max);
-       if (result != 2)
-               return -EINVAL;
-       if (in_max <= in_threshold)
-               return -EINVAL;
-       inflight->max = in_max;
-       inflight->threshold = in_threshold;
-       return size;
-}
-/*
- * Glue (or function adaptors) for accesing info on sysfs
- *
- * [we need this indirection because the PCI driver does almost the
- * same]
- *
- * Linux 2.6.21 changed how 'struct netdevice' does attributes (from
- * having a 'struct class_dev' to having a 'struct device'). That is
- * quite of a pain.
- *
- * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE()
- * create adaptors for extracting the 'struct i1480u' from a 'struct
- * dev' and calling a function for doing a sysfs operation (as we have
- * them factorized already). i1480u_ATTR creates the attribute file
- * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a
- * class_device_attr_NAME or device_attr_NAME (for group registration).
- */
-
-#define i1480u_SHOW(name, fn, param)                           \
-static ssize_t i1480u_show_##name(struct device *dev,          \
-                                 struct device_attribute *attr,\
-                                 char *buf)                    \
-{                                                              \
-       struct i1480u *i1480u = netdev_priv(to_net_dev(dev));   \
-       return fn(&i1480u->param, buf);                         \
-}
-
-#define i1480u_STORE(name, fn, param)                          \
-static ssize_t i1480u_store_##name(struct device *dev,         \
-                                  struct device_attribute *attr,\
-                                  const char *buf, size_t size)\
-{                                                              \
-       struct i1480u *i1480u = netdev_priv(to_net_dev(dev));   \
-       return fn(&i1480u->param, buf, size);                   \
-}
-
-#define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm,  \
-                                            i1480u_show_##name,\
-                                            i1480u_store_##name)
-
-#define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name,                \
-                                       S_IRUGO,                \
-                                       i1480u_show_##name, NULL)
-
-#define i1480u_ATTR_NAME(a) (dev_attr_##a)
-
-
-/*
- * Sysfs adaptors
- */
-i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options);
-i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options);
-i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options);
-i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options);
-i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options);
-i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options);
-i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options);
-i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options);
-i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_eda, wlp_eda_show, wlp);
-i1480u_STORE(wlp_eda, wlp_eda_store, wlp);
-i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp);
-i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp);
-i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp);
-i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp);
-i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp);
-i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp);
-i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp);
-i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp);
-i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp);
-i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp);
-i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp);
-i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp);
-i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp);
-i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp);
-i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp);
-i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp);
-i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp);
-i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp);
-i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp);
-i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp);
-i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp);
-i1480u_ATTR_SHOW(wlp_neighborhood);
-
-i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss);
-i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss);
-i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR);
-
-/*
- * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over
- * the last 256 received WLP frames (ECMA-368 13.3).
- *
- * [the -7dB that have to be substracted from the LQI to make the LQE
- * are already taken into account].
- */
-i1480u_SHOW(wlp_lqe, stats_show, lqe_stats);
-i1480u_STORE(wlp_lqe, stats_store, lqe_stats);
-i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR);
-
-/*
- * Show the Receive Signal Strength Indicator averaged over all the
- * received WLP frames (ECMA-368 13.3). Still is not clear what
- * this value is, but is kind of a percentage of the signal strength
- * at the antenna.
- */
-i1480u_SHOW(wlp_rssi, stats_show, rssi_stats);
-i1480u_STORE(wlp_rssi, stats_store, rssi_stats);
-i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR);
-
-/**
- * We maintain a basic flow control counter. "count" how many TX URBs are
- * outstanding. Only allow "max"
- * TX URBs to be outstanding. If this value is reached the queue will be
- * stopped. The queue will be restarted when there are
- * "threshold" URBs outstanding.
- */
-i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight);
-i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight);
-i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR);
-
-static struct attribute *i1480u_attrs[] = {
-       &i1480u_ATTR_NAME(uwb_phy_rate).attr,
-       &i1480u_ATTR_NAME(uwb_rts_cts).attr,
-       &i1480u_ATTR_NAME(uwb_ack_policy).attr,
-       &i1480u_ATTR_NAME(uwb_pca_base_priority).attr,
-       &i1480u_ATTR_NAME(wlp_lqe).attr,
-       &i1480u_ATTR_NAME(wlp_rssi).attr,
-       &i1480u_ATTR_NAME(wlp_eda).attr,
-       &i1480u_ATTR_NAME(wlp_uuid).attr,
-       &i1480u_ATTR_NAME(wlp_dev_name).attr,
-       &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr,
-       &i1480u_ATTR_NAME(wlp_dev_model_name).attr,
-       &i1480u_ATTR_NAME(wlp_dev_model_nr).attr,
-       &i1480u_ATTR_NAME(wlp_dev_serial).attr,
-       &i1480u_ATTR_NAME(wlp_dev_prim_category).attr,
-       &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr,
-       &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr,
-       &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr,
-       &i1480u_ATTR_NAME(wlp_neighborhood).attr,
-       &i1480u_ATTR_NAME(wss_activate).attr,
-       &i1480u_ATTR_NAME(wlp_tx_inflight).attr,
-       NULL,
-};
-
-static struct attribute_group i1480u_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = i1480u_attrs,
-};
-
-int i1480u_sysfs_setup(struct i1480u *i1480u)
-{
-       int result;
-       struct device *dev = &i1480u->usb_iface->dev;
-       result = sysfs_create_group(&i1480u->net_dev->dev.kobj,
-                                   &i1480u_attr_group);
-       if (result < 0)
-               dev_err(dev, "cannot initialize sysfs attributes: %d\n",
-                       result);
-       return result;
-}
-
-
-void i1480u_sysfs_release(struct i1480u *i1480u)
-{
-       sysfs_remove_group(&i1480u->net_dev->dev.kobj,
-                          &i1480u_attr_group);
-}
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c
deleted file mode 100644 (file)
index 3c117a3..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Deal with TX (massaging data to transmit, handling it)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Transmission engine. Get an skb, create from that a WLP transmit
- * context, add a WLP TX header (which we keep prefilled in the
- * device's instance), fill out the target-specific fields and
- * fire it.
- *
- * ROADMAP:
- *
- *   Entry points:
- *
- *     i1480u_tx_release(): called by i1480u_disconnect() to release
- *                          pending tx contexts.
- *
- *     i1480u_tx_cb(): callback for TX contexts (USB URBs)
- *       i1480u_tx_destroy():
- *
- *     i1480u_tx_timeout(): called for timeout handling from the
- *                          network stack.
- *
- *     i1480u_hard_start_xmit(): called for transmitting an skb from
- *                               the network stack. Will interact with WLP
- *                               substack to verify and prepare frame.
- *       i1480u_xmit_frame(): actual transmission on hardware
- *
- *         i1480u_tx_create()      Creates TX context
- *            i1480u_tx_create_1()    For packets in 1 fragment
- *            i1480u_tx_create_n()    For packets in >1 fragments
- *
- * TODO:
- *
- * - FIXME: rewrite using usb_sg_*(), add asynch support to
- *          usb_sg_*(). It might not make too much sense as most of
- *          the times the MTU will be smaller than one page...
- */
-
-#include <linux/slab.h>
-#include "i1480u-wlp.h"
-
-enum {
-       /* This is only for Next and Last TX packets */
-       i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE
-               - sizeof(struct untd_hdr_rst),
-};
-
-/* Free resources allocated to a i1480u tx context. */
-static
-void i1480u_tx_free(struct i1480u_tx *wtx)
-{
-       kfree(wtx->buf);
-       if (wtx->skb)
-               dev_kfree_skb_irq(wtx->skb);
-       usb_free_urb(wtx->urb);
-       kfree(wtx);
-}
-
-static
-void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&i1480u->tx_list_lock, flags);        /* not active any more */
-       list_del(&wtx->list_node);
-       i1480u_tx_free(wtx);
-       spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-}
-
-static
-void i1480u_tx_unlink_urbs(struct i1480u *i1480u)
-{
-       unsigned long flags;
-       struct i1480u_tx *wtx, *next;
-
-       spin_lock_irqsave(&i1480u->tx_list_lock, flags);
-       list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
-               usb_unlink_urb(wtx->urb);
-       }
-       spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-}
-
-
-/*
- * Callback for a completed tx USB URB.
- *
- * TODO:
- *
- * - FIXME: recover errors more gracefully
- * - FIXME: handle NAKs (I dont think they come here) for flow ctl
- */
-static
-void i1480u_tx_cb(struct urb *urb)
-{
-       struct i1480u_tx *wtx = urb->context;
-       struct i1480u *i1480u = wtx->i1480u;
-       struct net_device *net_dev = i1480u->net_dev;
-       struct device *dev = &i1480u->usb_iface->dev;
-       unsigned long flags;
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&i1480u->lock, flags);
-               net_dev->stats.tx_packets++;
-               net_dev->stats.tx_bytes += urb->actual_length;
-               spin_unlock_irqrestore(&i1480u->lock, flags);
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-               dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status);
-               netif_stop_queue(net_dev);
-               break;
-       case -ESHUTDOWN:        /* going away! */
-               dev_dbg(dev, "notif endp: down %d\n", urb->status);
-               netif_stop_queue(net_dev);
-               break;
-       default:
-               dev_err(dev, "TX: unknown URB status %d\n", urb->status);
-               if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS,
-                                       EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "TX: max acceptable errors exceeded."
-                                       "Reset device.\n");
-                       netif_stop_queue(net_dev);
-                       i1480u_tx_unlink_urbs(i1480u);
-                       wlp_reset_all(&i1480u->wlp);
-               }
-               break;
-       }
-       i1480u_tx_destroy(i1480u, wtx);
-       if (atomic_dec_return(&i1480u->tx_inflight.count)
-           <= i1480u->tx_inflight.threshold
-           && netif_queue_stopped(net_dev)
-           && i1480u->tx_inflight.threshold != 0) {
-               netif_start_queue(net_dev);
-               atomic_inc(&i1480u->tx_inflight.restart_count);
-       }
-       return;
-}
-
-
-/*
- * Given a buffer that doesn't fit in a single fragment, create an
- * scatter/gather structure for delivery to the USB pipe.
- *
- * Implements functionality of i1480u_tx_create().
- *
- * @wtx:       tx descriptor
- * @skb:       skb to send
- * @gfp_mask:  gfp allocation mask
- * @returns:    Pointer to @wtx if ok, NULL on error.
- *
- * Sorry, TOO LONG a function, but breaking it up is kind of hard
- *
- * This will break the buffer in chunks smaller than
- * i1480u_MAX_FRG_SIZE (including the header) and add proper headers
- * to each:
- *
- *   1st header           \
- *   i1480 tx header      |  fragment 1
- *   fragment data        /
- *   nxt header           \  fragment 2
- *   fragment data        /
- *   ..
- *   ..
- *   last header          \  fragment 3
- *   last fragment data   /
- *
- * This does not fill the i1480 TX header, it is left up to the
- * caller to do that; you can get it from @wtx->wlp_tx_hdr.
- *
- * This function consumes the skb unless there is an error.
- */
-static
-int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb,
-                      gfp_t gfp_mask)
-{
-       int result;
-       void *pl;
-       size_t pl_size;
-
-       void *pl_itr, *buf_itr;
-       size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0;
-       struct untd_hdr_1st *untd_hdr_1st;
-       struct wlp_tx_hdr *wlp_tx_hdr;
-       struct untd_hdr_rst *untd_hdr_rst;
-
-       wtx->skb = NULL;
-       pl = skb->data;
-       pl_itr = pl;
-       pl_size = skb->len;
-       pl_size_left = pl_size; /* payload size */
-       /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus
-        * the headers */
-       pl_size_1st = i1480u_MAX_FRG_SIZE
-               - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr);
-       BUG_ON(pl_size_1st > pl_size);
-       pl_size_left -= pl_size_1st;
-       /* The rest have an smaller header (no i1480 TX header). We
-        * need to break up the payload in blocks smaller than
-        * i1480u_MAX_PL_SIZE (payload excluding header). */
-       frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE;
-       /* Allocate space for the new buffer. In this new buffer we'll
-        * place the headers followed by the data fragment, headers,
-        * data fragments, etc..
-        */
-       result = -ENOMEM;
-       wtx->buf_size = sizeof(*untd_hdr_1st)
-               + sizeof(*wlp_tx_hdr)
-               + frgs * sizeof(*untd_hdr_rst)
-               + pl_size;
-       wtx->buf = kmalloc(wtx->buf_size, gfp_mask);
-       if (wtx->buf == NULL)
-               goto error_buf_alloc;
-
-       buf_itr = wtx->buf;             /* We got the space, let's fill it up */
-       /* Fill 1st fragment */
-       untd_hdr_1st = buf_itr;
-       buf_itr += sizeof(*untd_hdr_1st);
-       untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST);
-       untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0);
-       untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr));
-       untd_hdr_1st->fragment_len =
-               cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr));
-       memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding));
-       /* Set up i1480 header info */
-       wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr;
-       buf_itr += sizeof(*wlp_tx_hdr);
-       /* Copy the first fragment */
-       memcpy(buf_itr, pl_itr, pl_size_1st);
-       pl_itr += pl_size_1st;
-       buf_itr += pl_size_1st;
-
-       /* Now do each remaining fragment */
-       result = -EINVAL;
-       while (pl_size_left > 0) {
-               if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf
-                   > wtx->buf_size) {
-                       printk(KERN_ERR "BUG: no space for header\n");
-                       goto error_bug;
-               }
-               untd_hdr_rst = buf_itr;
-               buf_itr += sizeof(*untd_hdr_rst);
-               if (pl_size_left > i1480u_MAX_PL_SIZE) {
-                       frg_pl_size = i1480u_MAX_PL_SIZE;
-                       untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT);
-               } else {
-                       frg_pl_size = pl_size_left;
-                       untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST);
-               }
-               untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0);
-               untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size);
-               untd_hdr_rst->padding = 0;
-               if (buf_itr + frg_pl_size - wtx->buf
-                   > wtx->buf_size) {
-                       printk(KERN_ERR "BUG: no space for payload\n");
-                       goto error_bug;
-               }
-               memcpy(buf_itr, pl_itr, frg_pl_size);
-               buf_itr += frg_pl_size;
-               pl_itr += frg_pl_size;
-               pl_size_left -= frg_pl_size;
-       }
-       dev_kfree_skb_irq(skb);
-       return 0;
-
-error_bug:
-       printk(KERN_ERR
-              "BUG: skb %u bytes\n"
-              "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n"
-              "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n",
-              skb->len,
-              frg_pl_size, i1480u_MAX_FRG_SIZE,
-              buf_itr - wtx->buf, wtx->buf_size, pl_size_left);
-
-       kfree(wtx->buf);
-error_buf_alloc:
-       return result;
-}
-
-
-/*
- * Given a buffer that fits in a single fragment, fill out a @wtx
- * struct for transmitting it down the USB pipe.
- *
- * Uses the fact that we have space reserved in front of the skbuff
- * for hardware headers :]
- *
- * This does not fill the i1480 TX header, it is left up to the
- * caller to do that; you can get it from @wtx->wlp_tx_hdr.
- *
- * @pl:                pointer to payload data
- * @pl_size:    size of the payuload
- *
- * This function does not consume the @skb.
- */
-static
-int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb,
-                      gfp_t gfp_mask)
-{
-       struct untd_hdr_cmp *untd_hdr_cmp;
-       struct wlp_tx_hdr *wlp_tx_hdr;
-
-       wtx->buf = NULL;
-       wtx->skb = skb;
-       BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr));
-       wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr));
-       wtx->wlp_tx_hdr = wlp_tx_hdr;
-       BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp));
-       untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp));
-
-       untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP);
-       untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0);
-       untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp));
-       untd_hdr_cmp->padding = 0;
-       return 0;
-}
-
-
-/*
- * Given a skb to transmit, massage it to become palatable for the TX pipe
- *
- * This will break the buffer in chunks smaller than
- * i1480u_MAX_FRG_SIZE and add proper headers to each.
- *
- *   1st header           \
- *   i1480 tx header      |  fragment 1
- *   fragment data        /
- *   nxt header           \  fragment 2
- *   fragment data        /
- *   ..
- *   ..
- *   last header          \  fragment 3
- *   last fragment data   /
- *
- * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE.
- *
- * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the
- * following is composed:
- *
- *   complete header      \
- *   i1480 tx header      | single fragment
- *   packet data          /
- *
- * We were going to use s/g support, but because the interface is
- * synch and at the end there is plenty of overhead to do it, it
- * didn't seem that worth for data that is going to be smaller than
- * one page.
- */
-static
-struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u,
-                                  struct sk_buff *skb, gfp_t gfp_mask)
-{
-       int result;
-       struct usb_endpoint_descriptor *epd;
-       int usb_pipe;
-       unsigned long flags;
-
-       struct i1480u_tx *wtx;
-       const size_t pl_max_size =
-               i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp)
-               - sizeof(struct wlp_tx_hdr);
-
-       wtx = kmalloc(sizeof(*wtx), gfp_mask);
-       if (wtx == NULL)
-               goto error_wtx_alloc;
-       wtx->urb = usb_alloc_urb(0, gfp_mask);
-       if (wtx->urb == NULL)
-               goto error_urb_alloc;
-       epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc;
-       usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress);
-       /* Fits in a single complete packet or need to split? */
-       if (skb->len > pl_max_size) {
-               result = i1480u_tx_create_n(wtx, skb, gfp_mask);
-               if (result < 0)
-                       goto error_create;
-               usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
-                                 wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx);
-       } else {
-               result = i1480u_tx_create_1(wtx, skb, gfp_mask);
-               if (result < 0)
-                       goto error_create;
-               usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
-                                 skb->data, skb->len, i1480u_tx_cb, wtx);
-       }
-       spin_lock_irqsave(&i1480u->tx_list_lock, flags);
-       list_add(&wtx->list_node, &i1480u->tx_list);
-       spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-       return wtx;
-
-error_create:
-       kfree(wtx->urb);
-error_urb_alloc:
-       kfree(wtx);
-error_wtx_alloc:
-       return NULL;
-}
-
-/*
- * Actual fragmentation and transmission of frame
- *
- * @wlp:  WLP substack data structure
- * @skb:  To be transmitted
- * @dst:  Device address of destination
- * @returns: 0 on success, <0 on failure
- *
- * This function can also be called directly (not just from
- * hard_start_xmit), so we also check here if the interface is up before
- * taking sending anything.
- */
-int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb,
-                     struct uwb_dev_addr *dst)
-{
-       int result = -ENXIO;
-       struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
-       struct device *dev = &i1480u->usb_iface->dev;
-       struct net_device *net_dev = i1480u->net_dev;
-       struct i1480u_tx *wtx;
-       struct wlp_tx_hdr *wlp_tx_hdr;
-       static unsigned char dev_bcast[2] = { 0xff, 0xff };
-
-       BUG_ON(i1480u->wlp.rc == NULL);
-       if ((net_dev->flags & IFF_UP) == 0)
-               goto out;
-       result = -EBUSY;
-       if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) {
-               netif_stop_queue(net_dev);
-               goto error_max_inflight;
-       }
-       result = -ENOMEM;
-       wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC);
-       if (unlikely(wtx == NULL)) {
-               if (printk_ratelimit())
-                       dev_err(dev, "TX: no memory for WLP TX URB,"
-                               "dropping packet (in flight %d)\n",
-                               atomic_read(&i1480u->tx_inflight.count));
-               netif_stop_queue(net_dev);
-               goto error_wtx_alloc;
-       }
-       wtx->i1480u = i1480u;
-       /* Fill out the i1480 header; @i1480u->def_tx_hdr read without
-        * locking. We do so because they are kind of orthogonal to
-        * each other (and thus not changed in an atomic batch).
-        * The ETH header is right after the WLP TX header. */
-       wlp_tx_hdr = wtx->wlp_tx_hdr;
-       *wlp_tx_hdr = i1480u->options.def_tx_hdr;
-       wlp_tx_hdr->dstaddr = *dst;
-       if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast))
-           && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) {
-               /*Broadcast message directed to DRP host. Send as best effort
-                * on PCA. */
-               wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority);
-       }
-
-       result = usb_submit_urb(wtx->urb, GFP_ATOMIC);          /* Go baby */
-       if (result < 0) {
-               dev_err(dev, "TX: cannot submit URB: %d\n", result);
-               /* We leave the freeing of skb to calling function */
-               wtx->skb = NULL;
-               goto error_tx_urb_submit;
-       }
-       atomic_inc(&i1480u->tx_inflight.count);
-       net_dev->trans_start = jiffies;
-       return result;
-
-error_tx_urb_submit:
-       i1480u_tx_destroy(i1480u, wtx);
-error_wtx_alloc:
-error_max_inflight:
-out:
-       return result;
-}
-
-
-/*
- * Transmit an skb  Called when an skbuf has to be transmitted
- *
- * The skb is first passed to WLP substack to ensure this is a valid
- * frame. If valid the device address of destination will be filled and
- * the WLP header prepended to the skb. If this step fails we fake sending
- * the frame, if we return an error the network stack will just keep trying.
- *
- * Broadcast frames inside a WSS needs to be treated special as multicast is
- * not supported. A broadcast frame is sent as unicast to each member of the
- * WSS - this is done by the WLP substack when it finds a broadcast frame.
- * So, we test if the WLP substack took over the skb and only transmit it
- * if it has not (been taken over).
- *
- * @net_dev->xmit_lock is held
- */
-netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb,
-                                        struct net_device *net_dev)
-{
-       int result;
-       struct i1480u *i1480u = netdev_priv(net_dev);
-       struct device *dev = &i1480u->usb_iface->dev;
-       struct uwb_dev_addr dst;
-
-       if ((net_dev->flags & IFF_UP) == 0)
-               goto error;
-       result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst);
-       if (result < 0) {
-               dev_err(dev, "WLP verification of TX frame failed (%d). "
-                       "Dropping packet.\n", result);
-               goto error;
-       } else if (result == 1) {
-               /* trans_start time will be set when WLP actually transmits
-                * the frame */
-               goto out;
-       }
-       result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst);
-       if (result < 0) {
-               dev_err(dev, "Frame TX failed (%d).\n", result);
-               goto error;
-       }
-       return NETDEV_TX_OK;
-error:
-       dev_kfree_skb_any(skb);
-       net_dev->stats.tx_dropped++;
-out:
-       return NETDEV_TX_OK;
-}
-
-
-/*
- * Called when a pkt transmission doesn't complete in a reasonable period
- * Device reset may sleep - do it outside of interrupt context (delayed)
- */
-void i1480u_tx_timeout(struct net_device *net_dev)
-{
-       struct i1480u *i1480u = netdev_priv(net_dev);
-
-       wlp_reset_all(&i1480u->wlp);
-}
-
-
-void i1480u_tx_release(struct i1480u *i1480u)
-{
-       unsigned long flags;
-       struct i1480u_tx *wtx, *next;
-       int count = 0, empty;
-
-       spin_lock_irqsave(&i1480u->tx_list_lock, flags);
-       list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
-               count++;
-               usb_unlink_urb(wtx->urb);
-       }
-       spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-       count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */
-       /*
-        * We don't like this sollution too much (dirty as it is), but
-        * it is cheaper than putting a refcount on each i1480u_tx and
-        * i1480uting for all of them to go away...
-        *
-        * Called when no more packets can be added to tx_list
-        * so can i1480ut for it to be empty.
-        */
-       while (1) {
-               spin_lock_irqsave(&i1480u->tx_list_lock, flags);
-               empty = list_empty(&i1480u->tx_list);
-               spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-               if (empty)
-                       break;
-               count--;
-               BUG_ON(count == 0);
-               msleep(20);
-       }
-}
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile
deleted file mode 100644 (file)
index c72c11d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-$(CONFIG_UWB_WLP) := wlp.o
-
-wlp-objs :=    \
-       driver.o        \
-       eda.o           \
-       messages.o      \
-       sysfs.o         \
-       txrx.o          \
-       wlp-lc.o        \
-       wss-lc.o
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c
deleted file mode 100644 (file)
index cb8d699..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Life cycle of WLP substack
- *
- * FIXME: Docs
- */
-
-#include <linux/module.h>
-
-static int __init wlp_subsys_init(void)
-{
-       return 0;
-}
-module_init(wlp_subsys_init);
-
-static void __exit wlp_subsys_exit(void)
-{
-       return;
-}
-module_exit(wlp_subsys_exit);
-
-MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>");
-MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c
deleted file mode 100644 (file)
index 086fc0c..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Ethernet to device address cache
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * We need to be able to map ethernet addresses to device addresses
- * and back because there is not explicit relationship between the eth
- * addresses used in the ETH frames and the device addresses (no, it
- * would not have been simpler to force as ETH address the MBOA MAC
- * address...no, not at all :).
- *
- * A device has one MBOA MAC address and one device address. It is possible
- * for a device to have more than one virtual MAC address (although a
- * virtual address can be the same as the MBOA MAC address). The device
- * address is guaranteed to be unique among the devices in the extended
- * beacon group (see ECMA 17.1.1). We thus use the device address as index
- * to this cache. We do allow searching based on virtual address as this
- * is how Ethernet frames will be addressed.
- *
- * We need to support virtual EUI-48. Although, right now the virtual
- * EUI-48 will always be the same as the MAC SAP address. The EDA cache
- * entry thus contains a MAC SAP address as well as the virtual address
- * (used to map the network stack address to a neighbor). When we move
- * to support more than one virtual MAC on a host then this organization
- * will have to change. Perhaps a neighbor has a list of WSSs, each with a
- * tag and virtual EUI-48.
- *
- * On data transmission
- * it is used to determine if the neighbor is connected and what WSS it
- * belongs to. With this we know what tag to add to the WLP frame. Storing
- * the WSS in the EDA cache may be overkill because we only support one
- * WSS. Hopefully we will support more than one WSS at some point.
- * On data reception it is used to determine the WSS based on
- * the tag and address of the transmitting neighbor.
- */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-#include "wlp-internal.h"
-
-
-/* FIXME: cache is not purged, only on device close */
-
-/* FIXME: does not scale, change to dynamic array */
-
-/*
- * Initialize the EDA cache
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * Call when the interface is being brought up
- *
- * NOTE: Keep it as a separate function as the implementation will
- *       change and be more complex.
- */
-void wlp_eda_init(struct wlp_eda *eda)
-{
-       INIT_LIST_HEAD(&eda->cache);
-       spin_lock_init(&eda->lock);
-}
-
-/*
- * Release the EDA cache
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * Called when the interface is brought down
- */
-void wlp_eda_release(struct wlp_eda *eda)
-{
-       unsigned long flags;
-       struct wlp_eda_node *itr, *next;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
-               list_del(&itr->list_node);
-               kfree(itr);
-       }
-       spin_unlock_irqrestore(&eda->lock, flags);
-}
-
-/*
- * Add an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * An address mapping is initially created when the neighbor device is seen
- * for the first time (it is "onair"). At this time the neighbor is not
- * connected or associated with a WSS so we only populate the Ethernet and
- * Device address fields.
- *
- */
-int wlp_eda_create_node(struct wlp_eda *eda,
-                       const unsigned char eth_addr[ETH_ALEN],
-                       const struct uwb_dev_addr *dev_addr)
-{
-       int result = 0;
-       struct wlp_eda_node *itr;
-       unsigned long flags;
-
-       BUG_ON(dev_addr == NULL || eth_addr == NULL);
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(itr, &eda->cache, list_node) {
-               if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
-                       printk(KERN_ERR "EDA cache already contains entry "
-                              "for neighbor %02x:%02x\n",
-                              dev_addr->data[1], dev_addr->data[0]);
-                       result = -EEXIST;
-                       goto out_unlock;
-               }
-       }
-       itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
-       if (itr != NULL) {
-               memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
-               itr->dev_addr = *dev_addr;
-               list_add(&itr->list_node, &eda->cache);
-       } else
-               result = -ENOMEM;
-out_unlock:
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-/*
- * Remove entry from EDA cache
- *
- * This is done when the device goes off air.
- */
-void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
-{
-       struct wlp_eda_node *itr, *next;
-       unsigned long flags;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
-               if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
-                       list_del(&itr->list_node);
-                       kfree(itr);
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&eda->lock, flags);
-}
-
-/*
- * Update an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- */
-int wlp_eda_update_node(struct wlp_eda *eda,
-                       const struct uwb_dev_addr *dev_addr,
-                       struct wlp_wss *wss,
-                       const unsigned char virt_addr[ETH_ALEN],
-                       const u8 tag, const enum wlp_wss_connect state)
-{
-       int result = -ENOENT;
-       struct wlp_eda_node *itr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(itr, &eda->cache, list_node) {
-               if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
-                       /* Found it, update it */
-                       itr->wss = wss;
-                       memcpy(itr->virt_addr, virt_addr,
-                              sizeof(itr->virt_addr));
-                       itr->tag = tag;
-                       itr->state = state;
-                       result = 0;
-                       goto out_unlock;
-               }
-       }
-       /* Not found */
-out_unlock:
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-/*
- * Update only state field of an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- */
-int wlp_eda_update_node_state(struct wlp_eda *eda,
-                             const struct uwb_dev_addr *dev_addr,
-                             const enum wlp_wss_connect state)
-{
-       int result = -ENOENT;
-       struct wlp_eda_node *itr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(itr, &eda->cache, list_node) {
-               if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
-                       /* Found it, update it */
-                       itr->state = state;
-                       result = 0;
-                       goto out_unlock;
-               }
-       }
-       /* Not found */
-out_unlock:
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-/*
- * Return contents of EDA cache entry
- *
- * @dev_addr: index to EDA cache
- * @eda_entry: pointer to where contents of EDA cache will be copied
- */
-int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
-                     struct wlp_eda_node *eda_entry)
-{
-       int result = -ENOENT;
-       struct wlp_eda_node *itr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(itr, &eda->cache, list_node) {
-               if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
-                       *eda_entry = *itr;
-                       result = 0;
-                       goto out_unlock;
-               }
-       }
-       /* Not found */
-out_unlock:
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-/*
- * Execute function for every element in the cache
- *
- * @function: function to execute on element of cache (must be atomic)
- * @priv:     private data of function
- * @returns:  result of first function that failed, or last function
- *            executed if no function failed.
- *
- * Stop executing when function returns error for any element in cache.
- *
- * IMPORTANT: We are using a spinlock here: the function executed on each
- * element has to be atomic.
- */
-int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
-                    void *priv)
-{
-       int result = 0;
-       struct wlp *wlp = container_of(eda, struct wlp, eda);
-       struct wlp_eda_node *entry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(entry, &eda->cache, list_node) {
-               result = (*function)(wlp, entry, priv);
-               if (result < 0)
-                       break;
-       }
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-/*
- * Execute function for single element in the cache (return dev addr)
- *
- * @virt_addr: index into EDA cache used to determine which element to
- *             execute the function on
- * @dev_addr: device address of element in cache will be returned using
- *            @dev_addr
- * @function: function to execute on element of cache (must be atomic)
- * @priv:     private data of function
- * @returns:  result of function
- *
- * IMPORTANT: We are using a spinlock here: the function executed on the
- * element has to be atomic.
- */
-int wlp_eda_for_virtual(struct wlp_eda *eda,
-                       const unsigned char virt_addr[ETH_ALEN],
-                       struct uwb_dev_addr *dev_addr,
-                       wlp_eda_for_each_f function,
-                       void *priv)
-{
-       int result = 0;
-       struct wlp *wlp = container_of(eda, struct wlp, eda);
-       struct wlp_eda_node *itr;
-       unsigned long flags;
-       int found = 0;
-
-       spin_lock_irqsave(&eda->lock, flags);
-       list_for_each_entry(itr, &eda->cache, list_node) {
-               if (!memcmp(itr->virt_addr, virt_addr,
-                          sizeof(itr->virt_addr))) {
-                       result = (*function)(wlp, itr, priv);
-                       *dev_addr = itr->dev_addr;
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found)
-               result = -ENODEV;
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-
-static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
-                                         "WLP_WSS_CONNECTED",
-                                         "WLP_WSS_CONNECT_FAILED",
-};
-
-static const char *wlp_wss_connect_state_str(unsigned id)
-{
-       if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
-               return "unknown WSS connection state";
-       return __wlp_wss_connect_state[id];
-}
-
-/*
- * View EDA cache from user space
- *
- * A debugging feature to give user visibility into the EDA cache. Also
- * used to display members of WSS to user (called from wlp_wss_members_show())
- */
-ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-       struct wlp_eda_node *entry;
-       unsigned long flags;
-       struct wlp_eda *eda = &wlp->eda;
-       spin_lock_irqsave(&eda->lock, flags);
-       result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
-                          "tag state virt_addr\n");
-       list_for_each_entry(entry, &eda->cache, list_node) {
-               result += scnprintf(buf + result, PAGE_SIZE - result,
-                                   "%pM %02x:%02x %p 0x%02x %s %pM\n",
-                                   entry->eth_addr,
-                                   entry->dev_addr.data[1],
-                                   entry->dev_addr.data[0], entry->wss,
-                                   entry->tag,
-                                   wlp_wss_connect_state_str(entry->state),
-                                   entry->virt_addr);
-               if (result >= PAGE_SIZE)
-                       break;
-       }
-       spin_unlock_irqrestore(&eda->lock, flags);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_eda_show);
-
-/*
- * Add new EDA cache entry based on user input in sysfs
- *
- * Should only be used for debugging.
- *
- * The WSS is assumed to be the only WSS supported. This needs to be
- * redesigned when we support more than one WSS.
- */
-ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
-{
-       ssize_t result;
-       struct wlp_eda *eda = &wlp->eda;
-       u8 eth_addr[6];
-       struct uwb_dev_addr dev_addr;
-       u8 tag;
-       unsigned state;
-
-       result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
-                       "%02hhx:%02hhx %02hhx %u\n",
-                       &eth_addr[0], &eth_addr[1],
-                       &eth_addr[2], &eth_addr[3],
-                       &eth_addr[4], &eth_addr[5],
-                       &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
-       switch (result) {
-       case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
-               /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
-               result = -ENOSYS;
-               break;
-       case 10:
-               state = state >= 1 ? 1 : 0;
-               result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
-               if (result < 0 && result != -EEXIST)
-                       goto error;
-               /* Set virtual addr to be same as MAC */
-               result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
-                                            eth_addr, tag, state);
-               if (result < 0)
-                       goto error;
-               break;
-       default: /* bad format */
-               result = -EINVAL;
-       }
-error:
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_eda_store);
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c
deleted file mode 100644 (file)
index 3a8e033..0000000
+++ /dev/null
@@ -1,1798 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Message construction and parsing
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#include <linux/wlp.h>
-#include <linux/slab.h>
-
-#include "wlp-internal.h"
-
-static
-const char *__wlp_assoc_frame[] = {
-       [WLP_ASSOC_D1] = "WLP_ASSOC_D1",
-       [WLP_ASSOC_D2] = "WLP_ASSOC_D2",
-       [WLP_ASSOC_M1] = "WLP_ASSOC_M1",
-       [WLP_ASSOC_M2] = "WLP_ASSOC_M2",
-       [WLP_ASSOC_M3] = "WLP_ASSOC_M3",
-       [WLP_ASSOC_M4] = "WLP_ASSOC_M4",
-       [WLP_ASSOC_M5] = "WLP_ASSOC_M5",
-       [WLP_ASSOC_M6] = "WLP_ASSOC_M6",
-       [WLP_ASSOC_M7] = "WLP_ASSOC_M7",
-       [WLP_ASSOC_M8] = "WLP_ASSOC_M8",
-       [WLP_ASSOC_F0] = "WLP_ASSOC_F0",
-       [WLP_ASSOC_E1] = "WLP_ASSOC_E1",
-       [WLP_ASSOC_E2] = "WLP_ASSOC_E2",
-       [WLP_ASSOC_C1] = "WLP_ASSOC_C1",
-       [WLP_ASSOC_C2] = "WLP_ASSOC_C2",
-       [WLP_ASSOC_C3] = "WLP_ASSOC_C3",
-       [WLP_ASSOC_C4] = "WLP_ASSOC_C4",
-};
-
-static const char *wlp_assoc_frame_str(unsigned id)
-{
-       if (id >= ARRAY_SIZE(__wlp_assoc_frame))
-               return "unknown association frame";
-       return __wlp_assoc_frame[id];
-}
-
-static const char *__wlp_assc_error[] = {
-       "none",
-       "Authenticator Failure",
-       "Rogue activity suspected",
-       "Device busy",
-       "Setup Locked",
-       "Registrar not ready",
-       "Invalid WSS selection",
-       "Message timeout",
-       "Enrollment session timeout",
-       "Device password invalid",
-       "Unsupported version",
-       "Internal error",
-       "Undefined error",
-       "Numeric comparison failure",
-       "Waiting for user input",
-};
-
-static const char *wlp_assc_error_str(unsigned id)
-{
-       if (id >= ARRAY_SIZE(__wlp_assc_error))
-               return "unknown WLP association error";
-       return __wlp_assc_error[id];
-}
-
-static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type,
-                                   size_t len)
-{
-       hdr->type = cpu_to_le16(type);
-       hdr->length = cpu_to_le16(len);
-}
-
-/*
- * Populate fields of a constant sized attribute
- *
- * @returns: total size of attribute including size of new value
- *
- * We have two instances of this function (wlp_pset and wlp_set): one takes
- * the value as a parameter, the other takes a pointer to the value as
- * parameter. They thus only differ in how the value is assigned to the
- * attribute.
- *
- * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of
- * sizeof(type) to be able to use this same code for the structures that
- * contain 8bit enum values and be able to deal with pointer types.
- */
-#define wlp_set(type, type_code, name)                                 \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
-{                                                                      \
-       wlp_set_attr_hdr(&attr->hdr, type_code,                         \
-                        sizeof(*attr) - sizeof(struct wlp_attr_hdr));  \
-       attr->name = value;                                             \
-       return sizeof(*attr);                                           \
-}
-
-#define wlp_pset(type, type_code, name)                                        \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
-{                                                                      \
-       wlp_set_attr_hdr(&attr->hdr, type_code,                         \
-                        sizeof(*attr) - sizeof(struct wlp_attr_hdr));  \
-       attr->name = *value;                                            \
-       return sizeof(*attr);                                           \
-}
-
-/**
- * Populate fields of a variable attribute
- *
- * @returns: total size of attribute including size of new value
- *
- * Provided with a pointer to the memory area reserved for the
- * attribute structure, the field is populated with the value. The
- * reserved memory has to contain enough space for the value.
- */
-#define wlp_vset(type, type_code, name)                                        \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \
-                               size_t len)                             \
-{                                                                      \
-       wlp_set_attr_hdr(&attr->hdr, type_code, len);                   \
-       memcpy(attr->name, value, len);                                 \
-       return sizeof(*attr) + len;                                     \
-}
-
-wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name)
-wlp_vset(char *, WLP_ATTR_MANUF, manufacturer)
-wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type)
-wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name)
-wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr)
-wlp_vset(char *, WLP_ATTR_SERIAL, serial)
-wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid)
-wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
-/*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/
-wlp_set(u8, WLP_ATTR_WLP_VER, version)
-wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
-wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
-wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
-wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
-wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast)
-wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce)
-wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce)
-wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag)
-wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt)
-
-/**
- * Fill in the WSS information attributes
- *
- * We currently only support one WSS, and this is assumed in this function
- * that can populate only one WSS information attribute.
- */
-static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr,
-                              struct wlp_wss *wss)
-{
-       size_t datalen;
-       void *ptr = attr->wss_info;
-       size_t used = sizeof(*attr);
-
-       datalen = sizeof(struct wlp_wss_info) + strlen(wss->name);
-       wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen);
-       used = wlp_set_wssid(ptr, &wss->wssid);
-       used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name));
-       used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll);
-       used += wlp_set_wss_sec_status(ptr + used, wss->secure_status);
-       used += wlp_set_wss_bcast(ptr + used, &wss->bcast);
-       return sizeof(*attr) + used;
-}
-
-/**
- * Verify attribute header
- *
- * @hdr:     Pointer to attribute header that will be verified.
- * @type:    Expected attribute type.
- * @len:     Expected length of attribute value (excluding header).
- *
- * Most attribute values have a known length even when they do have a
- * length field. This knowledge can be used via this function to verify
- * that the length field matches the expected value.
- */
-static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr,
-                      enum wlp_attr_type type, unsigned len)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-
-       if (le16_to_cpu(hdr->type) != type) {
-               dev_err(dev, "WLP: unexpected header type. Expected "
-                       "%u, got %u.\n", type, le16_to_cpu(hdr->type));
-               return -EINVAL;
-       }
-       if (le16_to_cpu(hdr->length) != len) {
-               dev_err(dev, "WLP: unexpected length in header. Expected "
-                       "%u, got %u.\n", len, le16_to_cpu(hdr->length));
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/**
- * Check if header of WSS information attribute valid
- *
- * @returns: length of WSS attributes (value of length attribute field) if
- *             valid WSS information attribute found
- *           -ENODATA if no WSS information attribute found
- *           -EIO other error occured
- *
- * The WSS information attribute is optional. The function will be provided
- * with a pointer to data that could _potentially_ be a WSS information
- * attribute. If a valid WSS information attribute is found it will return
- * 0, if no WSS information attribute is found it will return -ENODATA, and
- * another error will be returned if it is a WSS information attribute, but
- * some parsing failure occured.
- */
-static int wlp_check_wss_info_attr_hdr(struct wlp *wlp,
-                                      struct wlp_attr_hdr *hdr, size_t buflen)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       size_t len;
-       int result = 0;
-
-       if (buflen < sizeof(*hdr)) {
-               dev_err(dev, "WLP: Not enough space in buffer to parse"
-                       " WSS information attribute header.\n");
-               result = -EIO;
-               goto out;
-       }
-       if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) {
-               /* WSS information is optional */
-               result = -ENODATA;
-               goto out;
-       }
-       len = le16_to_cpu(hdr->length);
-       if (buflen < sizeof(*hdr) + len) {
-               dev_err(dev, "WLP: Not enough space in buffer to parse "
-                       "variable data. Got %d, expected %d.\n",
-                       (int)buflen, (int)(sizeof(*hdr) + len));
-               result = -EIO;
-               goto out;
-       }
-       result = len;
-out:
-       return result;
-}
-
-
-static ssize_t wlp_get_attribute(struct wlp *wlp, u16 type_code,
-       struct wlp_attr_hdr *attr_hdr, void *value, ssize_t value_len,
-       ssize_t buflen)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       ssize_t attr_len = sizeof(*attr_hdr) + value_len;
-       if (buflen < 0)
-               return -EINVAL;
-       if (buflen < attr_len) {
-               dev_err(dev, "WLP: Not enough space in buffer to parse"
-                       " attribute field. Need %d, received %zu\n",
-                       (int)attr_len, buflen);
-               return -EIO;
-       }
-       if (wlp_check_attr_hdr(wlp, attr_hdr, type_code, value_len) < 0) {
-               dev_err(dev, "WLP: Header verification failed. \n");
-               return -EINVAL;
-       }
-       memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), value_len);
-       return attr_len;
-}
-
-static ssize_t wlp_vget_attribute(struct wlp *wlp, u16 type_code,
-       struct wlp_attr_hdr *attr_hdr, void *value, ssize_t max_value_len,
-       ssize_t buflen)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       size_t len;
-       if (buflen < 0)
-               return -EINVAL;
-       if (buflen < sizeof(*attr_hdr)) {
-               dev_err(dev, "WLP: Not enough space in buffer to parse"
-                       " header.\n");
-               return -EIO;
-       }
-       if (le16_to_cpu(attr_hdr->type) != type_code) {
-               dev_err(dev, "WLP: Unexpected attribute type. Got %u, "
-                       "expected %u.\n", le16_to_cpu(attr_hdr->type),
-                       type_code);
-               return -EINVAL;
-       }
-       len = le16_to_cpu(attr_hdr->length);
-       if (len > max_value_len) {
-               dev_err(dev, "WLP: Attribute larger than maximum "
-                       "allowed. Received %zu, max is %d.\n", len,
-                       (int)max_value_len);
-               return -EFBIG;
-       }
-       if (buflen < sizeof(*attr_hdr) + len) {
-               dev_err(dev, "WLP: Not enough space in buffer to parse "
-                       "variable data.\n");
-               return -EIO;
-       }
-       memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), len);
-       return sizeof(*attr_hdr) + len;
-}
-
-/**
- * Get value of attribute from fixed size attribute field.
- *
- * @attr:    Pointer to attribute field.
- * @value:   Pointer to variable in which attribute value will be placed.
- * @buflen:  Size of buffer in which attribute field (including header)
- *           can be found.
- * @returns: Amount of given buffer consumed by parsing for this attribute.
- *
- * The size and type of the value is known by the type of the attribute.
- */
-#define wlp_get(type, type_code, name)                                 \
-ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr,  \
-                     type *value, ssize_t buflen)                      \
-{                                                                      \
-       return wlp_get_attribute(wlp, (type_code), &attr->hdr,          \
-                                value, sizeof(*value), buflen);        \
-}
-
-#define wlp_get_sparse(type, type_code, name) \
-       static wlp_get(type, type_code, name)
-
-/**
- * Get value of attribute from variable sized attribute field.
- *
- * @max:     The maximum size of this attribute. This value is dictated by
- *           the maximum value from the WLP specification.
- *
- * @attr:    Pointer to attribute field.
- * @value:   Pointer to variable that will contain the value. The memory
- *           must already have been allocated for this value.
- * @buflen:  Size of buffer in which attribute field (including header)
- *           can be found.
- * @returns: Amount of given bufferconsumed by parsing for this attribute.
- */
-#define wlp_vget(type_val, type_code, name, max)                       \
-static ssize_t wlp_get_##name(struct wlp *wlp,                         \
-                             struct wlp_attr_##name *attr,             \
-                             type_val *value, ssize_t buflen)          \
-{                                                                      \
-       return wlp_vget_attribute(wlp, (type_code), &attr->hdr,         \
-                             value, (max), buflen);                    \
-}
-
-wlp_get(u8, WLP_ATTR_WLP_VER, version)
-wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
-wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
-wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
-wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e)
-wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r)
-wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid)
-wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
-wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
-wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast)
-wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag)
-wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt)
-wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce)
-wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce)
-
-/* The buffers for the device info attributes can be found in the
- * wlp_device_info struct. These buffers contain one byte more than the
- * max allowed by the spec - this is done to be able to add the
- * terminating \0 for user display. This terminating byte is not required
- * in the actual attribute field (because it has a length field) so the
- * maximum allowed for this value is one less than its size in the
- * structure.
- */
-wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name,
-        FIELD_SIZEOF(struct wlp_wss, name) - 1)
-wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name,
-        FIELD_SIZEOF(struct wlp_device_info, name) - 1)
-wlp_vget(char, WLP_ATTR_MANUF, manufacturer,
-        FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1)
-wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name,
-        FIELD_SIZEOF(struct wlp_device_info, model_name) - 1)
-wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr,
-        FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1)
-wlp_vget(char, WLP_ATTR_SERIAL, serial,
-        FIELD_SIZEOF(struct wlp_device_info, serial) - 1)
-
-/**
- * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info
- *
- * @attr: pointer to WSS name attribute in WSS information attribute field
- * @info: structure that will be populated with data from WSS information
- *        field (WSS name, Accept enroll, secure status, broadcast address)
- * @buflen: size of buffer
- *
- * Although the WSSID attribute forms part of the WSS info attribute it is
- * retrieved separately and stored in a different location.
- */
-static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp,
-                                     struct wlp_attr_hdr *attr,
-                                     struct wlp_wss_tmp_info *info,
-                                     ssize_t buflen)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       void *ptr = attr;
-       size_t used = 0;
-       ssize_t result = -EINVAL;
-
-       result = wlp_get_wss_name(wlp, ptr, info->name, buflen);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS name from "
-                       "WSS info in D2 message.\n");
-               goto error_parse;
-       }
-       used += result;
-
-       result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll,
-                                    buflen - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain accepting "
-                       "enrollment from WSS info in D2 message.\n");
-               goto error_parse;
-       }
-       if (info->accept_enroll != 0 && info->accept_enroll != 1) {
-               dev_err(dev, "WLP: invalid value for accepting "
-                       "enrollment in D2 message.\n");
-               result = -EINVAL;
-               goto error_parse;
-       }
-       used += result;
-
-       result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status,
-                                       buflen - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain secure "
-                       "status from WSS info in D2 message.\n");
-               goto error_parse;
-       }
-       if (info->sec_status != 0 && info->sec_status != 1) {
-               dev_err(dev, "WLP: invalid value for secure "
-                       "status in D2 message.\n");
-               result = -EINVAL;
-               goto error_parse;
-       }
-       used += result;
-
-       result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast,
-                                  buflen - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain broadcast "
-                       "address from WSS info in D2 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = used;
-error_parse:
-       return result;
-}
-
-/**
- * Create a new WSSID entry for the neighbor, allocate temporary storage
- *
- * Each neighbor can have many WSS active. We maintain a list of WSSIDs
- * advertised by neighbor. During discovery we also cache information about
- * these WSS in temporary storage.
- *
- * The temporary storage will be removed after it has been used (eg.
- * displayed to user), the wssid element will be removed from the list when
- * the neighbor is rediscovered or when it disappears.
- */
-static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp,
-                                             struct wlp_neighbor_e *neighbor)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_wssid_e *wssid_e;
-
-       wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL);
-       if (wssid_e == NULL) {
-               dev_err(dev, "WLP: unable to allocate memory "
-                       "for WSS information.\n");
-               goto error_alloc;
-       }
-       wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL);
-       if (wssid_e->info == NULL) {
-               dev_err(dev, "WLP: unable to allocate memory "
-                       "for temporary WSS information.\n");
-               kfree(wssid_e);
-               wssid_e = NULL;
-               goto error_alloc;
-       }
-       list_add(&wssid_e->node, &neighbor->wssid);
-error_alloc:
-       return wssid_e;
-}
-
-/**
- * Parse WSS information attribute
- *
- * @attr: pointer to WSS information attribute header
- * @buflen: size of buffer in which WSS information attribute appears
- * @wssid: will place wssid from WSS info attribute in this location
- * @wss_info: will place other information from WSS information attribute
- * in this location
- *
- * memory for @wssid and @wss_info must be allocated when calling this
- */
-static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr,
-                               size_t buflen, struct wlp_uuid *wssid,
-                               struct wlp_wss_tmp_info *wss_info)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       ssize_t result;
-       size_t len;
-       size_t used = 0;
-       void *ptr;
-
-       result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr,
-                                            buflen);
-       if (result < 0)
-               goto out;
-       len = result;
-       used = sizeof(*attr);
-       ptr = attr;
-
-       result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n");
-               goto out;
-       }
-       used += result;
-       result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info,
-                                       buflen - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS information "
-                       "from WSS information attributes. \n");
-               goto out;
-       }
-       used += result;
-       if (len + sizeof(*attr) != used) {
-               dev_err(dev, "WLP: Amount of data parsed does not "
-                       "match length field. Parsed %zu, length "
-                       "field %zu. \n", used, len);
-               result = -EINVAL;
-               goto out;
-       }
-       result = used;
-out:
-       return result;
-}
-
-/**
- * Retrieve WSS info from association frame
- *
- * @attr:     pointer to WSS information attribute
- * @neighbor: ptr to neighbor being discovered, NULL if enrollment in
- *            progress
- * @wss:      ptr to WSS being enrolled in, NULL if discovery in progress
- * @buflen:   size of buffer in which WSS information appears
- *
- * The WSS information attribute appears in the D2 association message.
- * This message is used in two ways: to discover all neighbors or to enroll
- * into a WSS activated by a neighbor. During discovery we only want to
- * store the WSS info in a cache, to be deleted right after it has been
- * used (eg. displayed to the user). During enrollment we store the WSS
- * information for the lifetime of enrollment.
- *
- * During discovery we are interested in all WSS information, during
- * enrollment we are only interested in the WSS being enrolled in. Even so,
- * when in enrollment we keep parsing the message after finding the WSS of
- * interest, this simplifies the calling routine in that it can be sure
- * that all WSS information attributes have been parsed out of the message.
- *
- * Association frame is process with nbmutex held. The list access is safe.
- */
-static ssize_t wlp_get_all_wss_info(struct wlp *wlp,
-                                   struct wlp_attr_wss_info *attr,
-                                   struct wlp_neighbor_e *neighbor,
-                                   struct wlp_wss *wss, ssize_t buflen)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       size_t used = 0;
-       ssize_t result = -EINVAL;
-       struct wlp_attr_wss_info *cur;
-       struct wlp_uuid wssid;
-       struct wlp_wss_tmp_info wss_info;
-       unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */
-       struct wlp_wssid_e *wssid_e;
-       char buf[WLP_WSS_UUID_STRSIZE];
-
-       if (buflen < 0)
-               goto out;
-
-       if (neighbor != NULL && wss == NULL)
-               enroll = 0; /* discovery */
-       else if (wss != NULL && neighbor == NULL)
-               enroll = 1; /* enrollment */
-       else
-               goto out;
-
-       cur = attr;
-       while (buflen - used > 0) {
-               memset(&wss_info, 0, sizeof(wss_info));
-               cur = (void *)cur + used;
-               result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid,
-                                         &wss_info);
-               if (result == -ENODATA) {
-                       result = used;
-                       goto out;
-               } else if (result < 0) {
-                       dev_err(dev, "WLP: Unable to parse WSS information "
-                               "from WSS information attribute. \n");
-                       result = -EINVAL;
-                       goto error_parse;
-               }
-               if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
-                       if (wss_info.accept_enroll != 1) {
-                               dev_err(dev, "WLP: Requested WSS does "
-                                       "not accept enrollment.\n");
-                               result = -EINVAL;
-                               goto out;
-                       }
-                       memcpy(wss->name, wss_info.name, sizeof(wss->name));
-                       wss->bcast = wss_info.bcast;
-                       wss->secure_status = wss_info.sec_status;
-                       wss->accept_enroll = wss_info.accept_enroll;
-                       wss->state = WLP_WSS_STATE_PART_ENROLLED;
-                       wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
-                       dev_dbg(dev, "WLP: Found WSS %s. Enrolling.\n", buf);
-               } else {
-                       wssid_e = wlp_create_wssid_e(wlp, neighbor);
-                       if (wssid_e == NULL) {
-                               dev_err(dev, "WLP: Cannot create new WSSID "
-                                       "entry for neighbor %02x:%02x.\n",
-                                       neighbor->uwb_dev->dev_addr.data[1],
-                                       neighbor->uwb_dev->dev_addr.data[0]);
-                               result = -ENOMEM;
-                               goto out;
-                       }
-                       wssid_e->wssid = wssid;
-                       *wssid_e->info = wss_info;
-               }
-               used += result;
-       }
-       result = used;
-error_parse:
-       if (result < 0 && !enroll) /* this was a discovery */
-               wlp_remove_neighbor_tmp_info(neighbor);
-out:
-       return result;
-
-}
-
-/**
- * Parse WSS information attributes into cache for discovery
- *
- * @attr: the first WSS information attribute in message
- * @neighbor: the neighbor whose cache will be populated
- * @buflen: size of the input buffer
- */
-static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp,
-                                        struct wlp_attr_wss_info *attr,
-                                        struct wlp_neighbor_e *neighbor,
-                                        ssize_t buflen)
-{
-       return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen);
-}
-
-/**
- * Parse WSS information attributes into WSS struct for enrollment
- *
- * @attr: the first WSS information attribute in message
- * @wss: the WSS that will be enrolled
- * @buflen: size of the input buffer
- */
-static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp,
-                                         struct wlp_attr_wss_info *attr,
-                                         struct wlp_wss *wss, ssize_t buflen)
-{
-       return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen);
-}
-
-/**
- * Construct a D1 association frame
- *
- * We use the radio control functions to determine the values of the device
- * properties. These are of variable length and the total space needed is
- * tallied first before we start constructing the message. The radio
- * control functions return strings that are terminated with \0. This
- * character should not be included in the message (there is a length field
- * accompanying it in the attribute).
- */
-static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
-                             struct sk_buff **skb)
-{
-
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-       struct wlp_device_info *info;
-       size_t used = 0;
-       struct wlp_frame_assoc *_d1;
-       struct sk_buff *_skb;
-       void *d1_itr;
-
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to setup device "
-                               "information for D1 message.\n");
-                       goto error;
-               }
-       }
-       info = wlp->dev_info;
-       _skb = dev_alloc_skb(sizeof(*_d1)
-                     + sizeof(struct wlp_attr_uuid_e)
-                     + sizeof(struct wlp_attr_wss_sel_mthd)
-                     + sizeof(struct wlp_attr_dev_name)
-                     + strlen(info->name)
-                     + sizeof(struct wlp_attr_manufacturer)
-                     + strlen(info->manufacturer)
-                     + sizeof(struct wlp_attr_model_name)
-                     + strlen(info->model_name)
-                     + sizeof(struct wlp_attr_model_nr)
-                     + strlen(info->model_nr)
-                     + sizeof(struct wlp_attr_serial)
-                     + strlen(info->serial)
-                     + sizeof(struct wlp_attr_prim_dev_type)
-                     + sizeof(struct wlp_attr_wlp_assc_err));
-       if (_skb == NULL) {
-               dev_err(dev, "WLP: Cannot allocate memory for association "
-                       "message.\n");
-               result = -ENOMEM;
-               goto error;
-       }
-       _d1 = (void *) _skb->data;
-       _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-       _d1->hdr.type = WLP_FRAME_ASSOCIATION;
-       _d1->type = WLP_ASSOC_D1;
-
-       wlp_set_version(&_d1->version, WLP_VERSION);
-       wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1);
-       d1_itr = _d1->attr;
-       used = wlp_set_uuid_e(d1_itr, &wlp->uuid);
-       used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT);
-       used += wlp_set_dev_name(d1_itr + used, info->name,
-                                strlen(info->name));
-       used += wlp_set_manufacturer(d1_itr + used, info->manufacturer,
-                                    strlen(info->manufacturer));
-       used += wlp_set_model_name(d1_itr + used, info->model_name,
-                                  strlen(info->model_name));
-       used += wlp_set_model_nr(d1_itr + used, info->model_nr,
-                                strlen(info->model_nr));
-       used += wlp_set_serial(d1_itr + used, info->serial,
-                              strlen(info->serial));
-       used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type);
-       used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE);
-       skb_put(_skb, sizeof(*_d1) + used);
-       *skb = _skb;
-error:
-       return result;
-}
-
-/**
- * Construct a D2 association frame
- *
- * We use the radio control functions to determine the values of the device
- * properties. These are of variable length and the total space needed is
- * tallied first before we start constructing the message. The radio
- * control functions return strings that are terminated with \0. This
- * character should not be included in the message (there is a length field
- * accompanying it in the attribute).
- */
-static
-int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
-                      struct sk_buff **skb, struct wlp_uuid *uuid_e)
-{
-
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-       struct wlp_device_info *info;
-       size_t used = 0;
-       struct wlp_frame_assoc *_d2;
-       struct sk_buff *_skb;
-       void *d2_itr;
-       size_t mem_needed;
-
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to setup device "
-                               "information for D2 message.\n");
-                       goto error;
-               }
-       }
-       info = wlp->dev_info;
-       mem_needed = sizeof(*_d2)
-                     + sizeof(struct wlp_attr_uuid_e)
-                     + sizeof(struct wlp_attr_uuid_r)
-                     + sizeof(struct wlp_attr_dev_name)
-                     + strlen(info->name)
-                     + sizeof(struct wlp_attr_manufacturer)
-                     + strlen(info->manufacturer)
-                     + sizeof(struct wlp_attr_model_name)
-                     + strlen(info->model_name)
-                     + sizeof(struct wlp_attr_model_nr)
-                     + strlen(info->model_nr)
-                     + sizeof(struct wlp_attr_serial)
-                     + strlen(info->serial)
-                     + sizeof(struct wlp_attr_prim_dev_type)
-                     + sizeof(struct wlp_attr_wlp_assc_err);
-       if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
-               mem_needed += sizeof(struct wlp_attr_wss_info)
-                             + sizeof(struct wlp_wss_info)
-                             + strlen(wlp->wss.name);
-       _skb = dev_alloc_skb(mem_needed);
-       if (_skb == NULL) {
-               dev_err(dev, "WLP: Cannot allocate memory for association "
-                       "message.\n");
-               result = -ENOMEM;
-               goto error;
-       }
-       _d2 = (void *) _skb->data;
-       _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-       _d2->hdr.type = WLP_FRAME_ASSOCIATION;
-       _d2->type = WLP_ASSOC_D2;
-
-       wlp_set_version(&_d2->version, WLP_VERSION);
-       wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2);
-       d2_itr = _d2->attr;
-       used = wlp_set_uuid_e(d2_itr, uuid_e);
-       used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid);
-       if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
-               used += wlp_set_wss_info(d2_itr + used, &wlp->wss);
-       used += wlp_set_dev_name(d2_itr + used, info->name,
-                                strlen(info->name));
-       used += wlp_set_manufacturer(d2_itr + used, info->manufacturer,
-                                    strlen(info->manufacturer));
-       used += wlp_set_model_name(d2_itr + used, info->model_name,
-                                  strlen(info->model_name));
-       used += wlp_set_model_nr(d2_itr + used, info->model_nr,
-                                strlen(info->model_nr));
-       used += wlp_set_serial(d2_itr + used, info->serial,
-                              strlen(info->serial));
-       used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type);
-       used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE);
-       skb_put(_skb, sizeof(*_d2) + used);
-       *skb = _skb;
-error:
-       return result;
-}
-
-/**
- * Allocate memory for and populate fields of F0 association frame
- *
- * Currently (while focusing on unsecure enrollment) we ignore the
- * nonce's that could be placed in the message. Only the error field is
- * populated by the value provided by the caller.
- */
-static
-int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb,
-                      enum wlp_assc_error error)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = -ENOMEM;
-       struct {
-               struct wlp_frame_assoc f0_hdr;
-               struct wlp_attr_enonce enonce;
-               struct wlp_attr_rnonce rnonce;
-               struct wlp_attr_wlp_assc_err assc_err;
-       } *f0;
-       struct sk_buff *_skb;
-       struct wlp_nonce tmp;
-
-       _skb = dev_alloc_skb(sizeof(*f0));
-       if (_skb == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for F0 "
-                       "association frame. \n");
-               goto error_alloc;
-       }
-       f0 = (void *) _skb->data;
-       f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-       f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
-       f0->f0_hdr.type = WLP_ASSOC_F0;
-       wlp_set_version(&f0->f0_hdr.version, WLP_VERSION);
-       wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0);
-       memset(&tmp, 0, sizeof(tmp));
-       wlp_set_enonce(&f0->enonce, &tmp);
-       wlp_set_rnonce(&f0->rnonce, &tmp);
-       wlp_set_wlp_assc_err(&f0->assc_err, error);
-       skb_put(_skb, sizeof(*f0));
-       *skb = _skb;
-       result = 0;
-error_alloc:
-       return result;
-}
-
-/**
- * Parse F0 frame
- *
- * We just retrieve the values and print it as an error to the user.
- * Calling function already knows an error occured (F0 indicates error), so
- * we just parse the content as debug for higher layers.
- */
-int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *f0 = (void *) skb->data;
-       void *ptr = skb->data;
-       size_t len = skb->len;
-       size_t used;
-       ssize_t result;
-       struct wlp_nonce enonce, rnonce;
-       enum wlp_assc_error assc_err;
-       char enonce_buf[WLP_WSS_NONCE_STRSIZE];
-       char rnonce_buf[WLP_WSS_NONCE_STRSIZE];
-
-       used = sizeof(*f0);
-       result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Enrollee nonce "
-                       "attribute from F0 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Registrar nonce "
-                       "attribute from F0 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WLP Association error "
-                       "attribute from F0 message.\n");
-               goto error_parse;
-       }
-       wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce);
-       wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce);
-       dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee "
-               "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n",
-               enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err));
-       result = 0;
-error_parse:
-       return result;
-}
-
-/**
- * Retrieve variable device information from association message
- *
- * The device information parsed is not required in any message. This
- * routine will thus not fail if an attribute is not present.
- * The attributes are expected in a certain order, even if all are not
- * present. The "attribute type" value is used to ensure the attributes
- * are parsed in the correct order.
- *
- * If an error is encountered during parsing the function will return an
- * error code, when this happens the given device_info structure may be
- * partially filled.
- */
-static
-int wlp_get_variable_info(struct wlp *wlp, void *data,
-                         struct wlp_device_info *dev_info, ssize_t len)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       size_t used = 0;
-       struct wlp_attr_hdr *hdr;
-       ssize_t result = 0;
-       unsigned last = 0;
-
-       while (len - used > 0) {
-               if (len - used < sizeof(*hdr)) {
-                       dev_err(dev, "WLP: Partial data in frame, cannot "
-                               "parse. \n");
-                       goto error_parse;
-               }
-               hdr = data + used;
-               switch (le16_to_cpu(hdr->type)) {
-               case WLP_ATTR_MANUF:
-                       if (last >= WLP_ATTR_MANUF) {
-                               dev_err(dev, "WLP: Incorrect order of "
-                                       "attribute values in D1 msg.\n");
-                               goto error_parse;
-                       }
-                       result = wlp_get_manufacturer(wlp, data + used,
-                                                     dev_info->manufacturer,
-                                                     len - used);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to obtain "
-                                       "Manufacturer attribute from D1 "
-                                       "message.\n");
-                               goto error_parse;
-                       }
-                       last = WLP_ATTR_MANUF;
-                       used += result;
-                       break;
-               case WLP_ATTR_MODEL_NAME:
-                       if (last >= WLP_ATTR_MODEL_NAME) {
-                               dev_err(dev, "WLP: Incorrect order of "
-                                       "attribute values in D1 msg.\n");
-                               goto error_parse;
-                       }
-                       result = wlp_get_model_name(wlp, data + used,
-                                                   dev_info->model_name,
-                                                   len - used);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to obtain Model "
-                                       "name attribute from D1 message.\n");
-                               goto error_parse;
-                       }
-                       last = WLP_ATTR_MODEL_NAME;
-                       used += result;
-                       break;
-               case WLP_ATTR_MODEL_NR:
-                       if (last >= WLP_ATTR_MODEL_NR) {
-                               dev_err(dev, "WLP: Incorrect order of "
-                                       "attribute values in D1 msg.\n");
-                               goto error_parse;
-                       }
-                       result = wlp_get_model_nr(wlp, data + used,
-                                                 dev_info->model_nr,
-                                                 len - used);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to obtain Model "
-                                       "number attribute from D1 message.\n");
-                               goto error_parse;
-                       }
-                       last = WLP_ATTR_MODEL_NR;
-                       used += result;
-                       break;
-               case WLP_ATTR_SERIAL:
-                       if (last >= WLP_ATTR_SERIAL) {
-                               dev_err(dev, "WLP: Incorrect order of "
-                                       "attribute values in D1 msg.\n");
-                               goto error_parse;
-                       }
-                       result = wlp_get_serial(wlp, data + used,
-                                               dev_info->serial, len - used);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to obtain Serial "
-                                       "number attribute from D1 message.\n");
-                               goto error_parse;
-                       }
-                       last = WLP_ATTR_SERIAL;
-                       used += result;
-                       break;
-               case WLP_ATTR_PRI_DEV_TYPE:
-                       if (last >= WLP_ATTR_PRI_DEV_TYPE) {
-                               dev_err(dev, "WLP: Incorrect order of "
-                                       "attribute values in D1 msg.\n");
-                               goto error_parse;
-                       }
-                       result = wlp_get_prim_dev_type(wlp, data + used,
-                                                      &dev_info->prim_dev_type,
-                                                      len - used);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to obtain Primary "
-                                       "device type attribute from D1 "
-                                       "message.\n");
-                               goto error_parse;
-                       }
-                       dev_info->prim_dev_type.category =
-                               le16_to_cpu(dev_info->prim_dev_type.category);
-                       dev_info->prim_dev_type.subID =
-                               le16_to_cpu(dev_info->prim_dev_type.subID);
-                       last = WLP_ATTR_PRI_DEV_TYPE;
-                       used += result;
-                       break;
-               default:
-                       /* This is not variable device information. */
-                       goto out;
-                       break;
-               }
-       }
-out:
-       return used;
-error_parse:
-       return -EINVAL;
-}
-
-/**
- * Parse incoming D1 frame, populate attribute values
- *
- * Caller provides pointers to memory already allocated for attributes
- * expected in the D1 frame. These variables will be populated.
- */
-static
-int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
-                      struct wlp_uuid *uuid_e,
-                      enum wlp_wss_sel_mthd *sel_mthd,
-                      struct wlp_device_info *dev_info,
-                      enum wlp_assc_error *assc_err)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *d1 = (void *) skb->data;
-       void *ptr = skb->data;
-       size_t len = skb->len;
-       size_t used;
-       ssize_t result;
-
-       used = sizeof(*d1);
-       result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 "
-                       "message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS selection method "
-                       "from D1 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
-                                    len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Name from D1 "
-                       "message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Information from "
-                       "D1 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WLP Association Error "
-                       "Information from D1 message.\n");
-               goto error_parse;
-       }
-       result = 0;
-error_parse:
-       return result;
-}
-/**
- * Handle incoming D1 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a D2 frame in response.
- *
- * It is not clear what to do with most fields in the incoming D1 frame. We
- * retrieve and discard the information here for now.
- */
-void wlp_handle_d1_frame(struct work_struct *ws)
-{
-       struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
-                                                 struct wlp_assoc_frame_ctx,
-                                                 ws);
-       struct wlp *wlp = frame_ctx->wlp;
-       struct wlp_wss *wss = &wlp->wss;
-       struct sk_buff *skb = frame_ctx->skb;
-       struct uwb_dev_addr *src = &frame_ctx->src;
-       int result;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_uuid uuid_e;
-       enum wlp_wss_sel_mthd sel_mthd = 0;
-       struct wlp_device_info dev_info;
-       enum wlp_assc_error assc_err;
-       struct sk_buff *resp = NULL;
-
-       /* Parse D1 frame */
-       mutex_lock(&wss->mutex);
-       mutex_lock(&wlp->mutex); /* to access wlp->uuid */
-       memset(&dev_info, 0, sizeof(dev_info));
-       result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
-                                   &assc_err);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
-               kfree_skb(skb);
-               goto out;
-       }
-
-       kfree_skb(skb);
-       if (!wlp_uuid_is_set(&wlp->uuid)) {
-               dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
-                       "proceed. Respong to D1 message with error F0.\n");
-               result = wlp_build_assoc_f0(wlp, &resp,
-                                           WLP_ASSOC_ERROR_NOT_READY);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to construct F0 message.\n");
-                       goto out;
-               }
-       } else {
-               /* Construct D2 frame */
-               result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to construct D2 message.\n");
-                       goto out;
-               }
-       }
-       /* Send D2 frame */
-       BUG_ON(wlp->xmit_frame == NULL);
-       result = wlp->xmit_frame(wlp, resp, src);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to transmit D2 association "
-                       "message: %d\n", result);
-               if (result == -ENXIO)
-                       dev_err(dev, "WLP: Is network interface up? \n");
-               /* We could try again ... */
-               dev_kfree_skb_any(resp); /* we need to free if tx fails */
-       }
-out:
-       kfree(frame_ctx);
-       mutex_unlock(&wlp->mutex);
-       mutex_unlock(&wss->mutex);
-}
-
-/**
- * Parse incoming D2 frame, create and populate temporary cache
- *
- * @skb: socket buffer in which D2 frame can be found
- * @neighbor: the neighbor that sent the D2 frame
- *
- * Will allocate memory for temporary storage of information learned during
- * discovery.
- */
-int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb,
-                               struct wlp_neighbor_e *neighbor)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *d2 = (void *) skb->data;
-       void *ptr = skb->data;
-       size_t len = skb->len;
-       size_t used;
-       ssize_t result;
-       struct wlp_uuid uuid_e;
-       struct wlp_device_info *nb_info;
-       enum wlp_assc_error assc_err;
-
-       used = sizeof(*d2);
-       result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
-               dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
-                       "local UUID sent in D1. \n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor,
-                                          len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS information "
-                       "from D2 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
-       if (neighbor->info == NULL) {
-               dev_err(dev, "WLP: cannot allocate memory to store device "
-                       "info.\n");
-               result = -ENOMEM;
-               goto error_parse;
-       }
-       nb_info = neighbor->info;
-       result = wlp_get_dev_name(wlp, ptr + used, nb_info->name,
-                                 len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Name from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Information from "
-                       "D2 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WLP Association Error "
-                       "Information from D2 message.\n");
-               goto error_parse;
-       }
-       if (assc_err != WLP_ASSOC_ERROR_NONE) {
-               dev_err(dev, "WLP: neighbor device returned association "
-                       "error %d\n", assc_err);
-               result = -EINVAL;
-               goto error_parse;
-       }
-       result = 0;
-error_parse:
-       if (result < 0)
-               wlp_remove_neighbor_tmp_info(neighbor);
-       return result;
-}
-
-/**
- * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in
- *
- * @wss: our WSS that will be enrolled
- * @skb: socket buffer in which D2 frame can be found
- * @neighbor: the neighbor that sent the D2 frame
- * @wssid: the wssid of the WSS in which we want to enroll
- *
- * Forms part of enrollment sequence. We are trying to enroll in WSS with
- * @wssid by using @neighbor as registrar. A D1 message was sent to
- * @neighbor and now we need to parse the D2 response. The neighbor's
- * response is searched for the requested WSS and if found (and it accepts
- * enrollment), we store the information.
- */
-int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb,
-                                struct wlp_neighbor_e *neighbor,
-                                struct wlp_uuid *wssid)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       void *ptr = skb->data;
-       size_t len = skb->len;
-       size_t used;
-       ssize_t result;
-       struct wlp_uuid uuid_e;
-       struct wlp_uuid uuid_r;
-       struct wlp_device_info nb_info;
-       enum wlp_assc_error assc_err;
-       char uuid_bufA[WLP_WSS_UUID_STRSIZE];
-       char uuid_bufB[WLP_WSS_UUID_STRSIZE];
-
-       used = sizeof(struct wlp_frame_assoc);
-       result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
-               dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
-                       "local UUID sent in D1. \n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) {
-               wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA),
-                                  &neighbor->uuid);
-               wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r);
-               dev_err(dev, "WLP: UUID of neighbor does not match UUID "
-                       "learned during discovery. Originally discovered: %s, "
-                       "now from D2 message: %s\n", uuid_bufA, uuid_bufB);
-               result = -EINVAL;
-               goto error_parse;
-       }
-       used += result;
-       wss->wssid = *wssid;
-       result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS information "
-                       "from D2 message.\n");
-               goto error_parse;
-       }
-       if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
-               dev_err(dev, "WLP: D2 message did not contain information "
-                       "for successful enrollment. \n");
-               result = -EINVAL;
-               goto error_parse;
-       }
-       used += result;
-       /* Place device information on stack to continue parsing of message */
-       result = wlp_get_dev_name(wlp, ptr + used, nb_info.name,
-                                 len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Name from D2 "
-                       "message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain Device Information from "
-                       "D2 message.\n");
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WLP Association Error "
-                       "Information from D2 message.\n");
-               goto error_parse;
-       }
-       if (assc_err != WLP_ASSOC_ERROR_NONE) {
-               dev_err(dev, "WLP: neighbor device returned association "
-                       "error %d\n", assc_err);
-               if (wss->state == WLP_WSS_STATE_PART_ENROLLED) {
-                       dev_err(dev, "WLP: Enrolled in WSS (should not "
-                               "happen according to spec). Undoing. \n");
-                       wlp_wss_reset(wss);
-               }
-               result = -EINVAL;
-               goto error_parse;
-       }
-       result = 0;
-error_parse:
-       return result;
-}
-
-/**
- * Parse C3/C4 frame into provided variables
- *
- * @wssid: will point to copy of wssid retrieved from C3/C4 frame
- * @tag:   will point to copy of tag retrieved from C3/C4 frame
- * @virt_addr: will point to copy of virtual address retrieved from C3/C4
- * frame.
- *
- * Calling function has to allocate memory for these values.
- *
- * skb contains a valid C3/C4 frame, return the individual fields of this
- * frame in the provided variables.
- */
-int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb,
-                      struct wlp_uuid *wssid, u8 *tag,
-                      struct uwb_mac_addr *virt_addr)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result;
-       void *ptr = skb->data;
-       size_t len = skb->len;
-       size_t used;
-       struct wlp_frame_assoc *assoc = ptr;
-
-       used = sizeof(*assoc);
-       result = wlp_get_wssid(wlp, ptr + used, wssid, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSSID attribute from "
-                       "%s message.\n", wlp_assoc_frame_str(assoc->type));
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS tag attribute from "
-                       "%s message.\n", wlp_assoc_frame_str(assoc->type));
-               goto error_parse;
-       }
-       used += result;
-       result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSS virtual address "
-                       "attribute from %s message.\n",
-                       wlp_assoc_frame_str(assoc->type));
-               goto error_parse;
-       }
-error_parse:
-       return result;
-}
-
-/**
- * Allocate memory for and populate fields of C1 or C2 association frame
- *
- * The C1 and C2 association frames appear identical - except for the type.
- */
-static
-int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss,
-                        struct sk_buff **skb, enum wlp_assoc_type type)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result  = -ENOMEM;
-       struct {
-               struct wlp_frame_assoc c_hdr;
-               struct wlp_attr_wssid wssid;
-       } *c;
-       struct sk_buff *_skb;
-
-       _skb = dev_alloc_skb(sizeof(*c));
-       if (_skb == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for C1/C2 "
-                       "association frame. \n");
-               goto error_alloc;
-       }
-       c = (void *) _skb->data;
-       c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-       c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
-       c->c_hdr.type = type;
-       wlp_set_version(&c->c_hdr.version, WLP_VERSION);
-       wlp_set_msg_type(&c->c_hdr.msg_type, type);
-       wlp_set_wssid(&c->wssid, &wss->wssid);
-       skb_put(_skb, sizeof(*c));
-       *skb = _skb;
-       result = 0;
-error_alloc:
-       return result;
-}
-
-
-static
-int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss,
-                      struct sk_buff **skb)
-{
-       return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1);
-}
-
-static
-int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss,
-                      struct sk_buff **skb)
-{
-       return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2);
-}
-
-
-/**
- * Allocate memory for and populate fields of C3 or C4 association frame
- *
- * The C3 and C4 association frames appear identical - except for the type.
- */
-static
-int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss,
-                        struct sk_buff **skb, enum wlp_assoc_type type)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result  = -ENOMEM;
-       struct {
-               struct wlp_frame_assoc c_hdr;
-               struct wlp_attr_wssid wssid;
-               struct wlp_attr_wss_tag wss_tag;
-               struct wlp_attr_wss_virt wss_virt;
-       } *c;
-       struct sk_buff *_skb;
-
-       _skb = dev_alloc_skb(sizeof(*c));
-       if (_skb == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for C3/C4 "
-                       "association frame. \n");
-               goto error_alloc;
-       }
-       c = (void *) _skb->data;
-       c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-       c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
-       c->c_hdr.type = type;
-       wlp_set_version(&c->c_hdr.version, WLP_VERSION);
-       wlp_set_msg_type(&c->c_hdr.msg_type, type);
-       wlp_set_wssid(&c->wssid, &wss->wssid);
-       wlp_set_wss_tag(&c->wss_tag, wss->tag);
-       wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr);
-       skb_put(_skb, sizeof(*c));
-       *skb = _skb;
-       result = 0;
-error_alloc:
-       return result;
-}
-
-static
-int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss,
-                      struct sk_buff **skb)
-{
-       return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3);
-}
-
-static
-int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss,
-                      struct sk_buff **skb)
-{
-       return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4);
-}
-
-
-#define wlp_send_assoc(type, id)                                       \
-static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \
-                                struct uwb_dev_addr *dev_addr)         \
-{                                                                      \
-       struct device *dev = &wlp->rc->uwb_dev.dev;                     \
-       int result;                                                     \
-       struct sk_buff *skb = NULL;                                     \
-                                                                       \
-       /* Build the frame */                                           \
-       result = wlp_build_assoc_##type(wlp, wss, &skb);                \
-       if (result < 0) {                                               \
-               dev_err(dev, "WLP: Unable to construct %s association " \
-                       "frame: %d\n", wlp_assoc_frame_str(id), result);\
-               goto error_build_assoc;                                 \
-       }                                                               \
-       /* Send the frame */                                            \
-       BUG_ON(wlp->xmit_frame == NULL);                                \
-       result = wlp->xmit_frame(wlp, skb, dev_addr);                   \
-       if (result < 0) {                                               \
-               dev_err(dev, "WLP: Unable to transmit %s association "  \
-                       "message: %d\n", wlp_assoc_frame_str(id),       \
-                       result);                                        \
-               if (result == -ENXIO)                                   \
-                       dev_err(dev, "WLP: Is network interface "       \
-                               "up? \n");                              \
-               goto error_xmit;                                        \
-       }                                                               \
-       return 0;                                                       \
-error_xmit:                                                            \
-       /* We could try again ... */                                    \
-       dev_kfree_skb_any(skb);/*we need to free if tx fails*/          \
-error_build_assoc:                                                     \
-       return result;                                                  \
-}
-
-wlp_send_assoc(d1, WLP_ASSOC_D1)
-wlp_send_assoc(c1, WLP_ASSOC_C1)
-wlp_send_assoc(c3, WLP_ASSOC_C3)
-
-int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss,
-                        struct uwb_dev_addr *dev_addr,
-                        enum wlp_assoc_type type)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       switch (type) {
-       case WLP_ASSOC_D1:
-               result = wlp_send_assoc_d1(wlp, wss, dev_addr);
-               break;
-       case WLP_ASSOC_C1:
-               result = wlp_send_assoc_c1(wlp, wss, dev_addr);
-               break;
-       case WLP_ASSOC_C3:
-               result = wlp_send_assoc_c3(wlp, wss, dev_addr);
-               break;
-       default:
-               dev_err(dev, "WLP: Received request to send unknown "
-                       "association message.\n");
-               result = -EINVAL;
-               break;
-       }
-       return result;
-}
-
-/**
- * Handle incoming C1 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a C2 frame in response.
- */
-void wlp_handle_c1_frame(struct work_struct *ws)
-{
-       struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
-                                                 struct wlp_assoc_frame_ctx,
-                                                 ws);
-       struct wlp *wlp = frame_ctx->wlp;
-       struct wlp_wss *wss = &wlp->wss;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data;
-       unsigned int len = frame_ctx->skb->len;
-       struct uwb_dev_addr *src = &frame_ctx->src;
-       int result;
-       struct wlp_uuid wssid;
-       struct sk_buff *resp = NULL;
-
-       /* Parse C1 frame */
-       mutex_lock(&wss->mutex);
-       result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid,
-                              len - sizeof(*c1));
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n");
-               goto out;
-       }
-       if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
-           && wss->state == WLP_WSS_STATE_ACTIVE) {
-               /* Construct C2 frame */
-               result = wlp_build_assoc_c2(wlp, wss, &resp);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to construct C2 message.\n");
-                       goto out;
-               }
-       } else {
-               /* Construct F0 frame */
-               result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to construct F0 message.\n");
-                       goto out;
-               }
-       }
-       /* Send C2 frame */
-       BUG_ON(wlp->xmit_frame == NULL);
-       result = wlp->xmit_frame(wlp, resp, src);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to transmit response association "
-                       "message: %d\n", result);
-               if (result == -ENXIO)
-                       dev_err(dev, "WLP: Is network interface up? \n");
-               /* We could try again ... */
-               dev_kfree_skb_any(resp); /* we need to free if tx fails */
-       }
-out:
-       kfree_skb(frame_ctx->skb);
-       kfree(frame_ctx);
-       mutex_unlock(&wss->mutex);
-}
-
-/**
- * Handle incoming C3 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a C4 frame in response. If the C3 frame identifies a WSS that is locally
- * active then we connect to this neighbor (add it to our EDA cache).
- */
-void wlp_handle_c3_frame(struct work_struct *ws)
-{
-       struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
-                                                 struct wlp_assoc_frame_ctx,
-                                                 ws);
-       struct wlp *wlp = frame_ctx->wlp;
-       struct wlp_wss *wss = &wlp->wss;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct sk_buff *skb = frame_ctx->skb;
-       struct uwb_dev_addr *src = &frame_ctx->src;
-       int result;
-       struct sk_buff *resp = NULL;
-       struct wlp_uuid wssid;
-       u8 tag;
-       struct uwb_mac_addr virt_addr;
-
-       /* Parse C3 frame */
-       mutex_lock(&wss->mutex);
-       result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain values from C3 frame.\n");
-               goto out;
-       }
-       if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
-           && wss->state >= WLP_WSS_STATE_ACTIVE) {
-               result = wlp_eda_update_node(&wlp->eda, src, wss,
-                                            (void *) virt_addr.data, tag,
-                                            WLP_WSS_CONNECTED);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to update EDA cache "
-                               "with new connected neighbor information.\n");
-                       result = wlp_build_assoc_f0(wlp, &resp,
-                                                   WLP_ASSOC_ERROR_INT);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to construct F0 "
-                                       "message.\n");
-                               goto out;
-                       }
-               } else {
-                       wss->state = WLP_WSS_STATE_CONNECTED;
-                       /* Construct C4 frame */
-                       result = wlp_build_assoc_c4(wlp, wss, &resp);
-                       if (result < 0) {
-                               dev_err(dev, "WLP: Unable to construct C4 "
-                                       "message.\n");
-                               goto out;
-                       }
-               }
-       } else {
-               /* Construct F0 frame */
-               result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to construct F0 message.\n");
-                       goto out;
-               }
-       }
-       /* Send C4 frame */
-       BUG_ON(wlp->xmit_frame == NULL);
-       result = wlp->xmit_frame(wlp, resp, src);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to transmit response association "
-                       "message: %d\n", result);
-               if (result == -ENXIO)
-                       dev_err(dev, "WLP: Is network interface up? \n");
-               /* We could try again ... */
-               dev_kfree_skb_any(resp); /* we need to free if tx fails */
-       }
-out:
-       kfree_skb(frame_ctx->skb);
-       kfree(frame_ctx);
-       mutex_unlock(&wss->mutex);
-}
-
-
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
deleted file mode 100644 (file)
index 6627c94..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * sysfs functions
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: Docs
- *
- */
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-static
-size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
-                            struct wlp_wssid_e *wssid_e)
-{
-       size_t used = 0;
-       used += scnprintf(buf, bufsize, " WSS: ");
-       used += wlp_wss_uuid_print(buf + used, bufsize - used,
-                                  &wssid_e->wssid);
-
-       if (wssid_e->info != NULL) {
-               used += scnprintf(buf + used, bufsize - used, " ");
-               used += uwb_mac_addr_print(buf + used, bufsize - used,
-                                          &wssid_e->info->bcast);
-               used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
-                                 wssid_e->info->accept_enroll,
-                                 wssid_e->info->sec_status,
-                                 wssid_e->info->name);
-       }
-       return used;
-}
-
-/**
- * Print out information learned from neighbor discovery
- *
- * Some fields being printed may not be included in the device discovery
- * information (it is not mandatory). We are thus careful how the
- * information is printed to ensure it is clear to the user what field is
- * being referenced.
- * The information being printed is for one time use - temporary storage is
- * cleaned after it is printed.
- *
- * Ideally sysfs output should be on one line. The information printed here
- * contain a few strings so it will be hard to parse if they are all
- * printed on the same line - without agreeing on a standard field
- * separator.
- */
-static
-ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
-                                  size_t bufsize)
-{
-       size_t used = 0;
-       struct wlp_neighbor_e *neighb;
-       struct wlp_wssid_e *wssid_e;
-
-       mutex_lock(&wlp->nbmutex);
-       used = scnprintf(buf, bufsize, "#Neighbor information\n"
-                        "#uuid dev_addr\n"
-                        "# Device Name:\n# Model Name:\n# Manufacturer:\n"
-                        "# Model Nr:\n# Serial:\n"
-                        "# Pri Dev type: CategoryID OUI OUISubdiv "
-                        "SubcategoryID\n"
-                        "# WSS: WSSID WSS_name accept_enroll sec_status "
-                        "bcast\n"
-                        "# WSS: WSSID WSS_name accept_enroll sec_status "
-                        "bcast\n\n");
-       list_for_each_entry(neighb, &wlp->neighbors, node) {
-               if (bufsize - used <= 0)
-                       goto out;
-               used += wlp_wss_uuid_print(buf + used, bufsize - used,
-                                          &neighb->uuid);
-               buf[used++] = ' ';
-               used += uwb_dev_addr_print(buf + used, bufsize - used,
-                                          &neighb->uwb_dev->dev_addr);
-               if (neighb->info != NULL)
-                       used += scnprintf(buf + used, bufsize - used,
-                                         "\n Device Name: %s\n"
-                                         " Model Name: %s\n"
-                                         " Manufacturer:%s \n"
-                                         " Model Nr: %s\n"
-                                         " Serial: %s\n"
-                                         " Pri Dev type: "
-                                         "%u %02x:%02x:%02x %u %u\n",
-                                         neighb->info->name,
-                                         neighb->info->model_name,
-                                         neighb->info->manufacturer,
-                                         neighb->info->model_nr,
-                                         neighb->info->serial,
-                                         neighb->info->prim_dev_type.category,
-                                         neighb->info->prim_dev_type.OUI[0],
-                                         neighb->info->prim_dev_type.OUI[1],
-                                         neighb->info->prim_dev_type.OUI[2],
-                                         neighb->info->prim_dev_type.OUIsubdiv,
-                                         neighb->info->prim_dev_type.subID);
-               list_for_each_entry(wssid_e, &neighb->wssid, node) {
-                       used += wlp_wss_wssid_e_print(buf + used,
-                                                     bufsize - used,
-                                                     wssid_e);
-               }
-               buf[used++] = '\n';
-               wlp_remove_neighbor_tmp_info(neighb);
-       }
-
-
-out:
-       mutex_unlock(&wlp->nbmutex);
-       return used;
-}
-
-
-/**
- * Show properties of all WSS in neighborhood.
- *
- * Will trigger a complete discovery of WSS activated by this device and
- * its neighbors.
- */
-ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
-{
-       wlp_discover(wlp);
-       return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
-}
-EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
-
-static
-ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
-                                 size_t bufsize)
-{
-       ssize_t result;
-
-       result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
-       result += scnprintf(buf + result, bufsize - result, " ");
-       result += uwb_mac_addr_print(buf + result, bufsize - result,
-                                    &wss->bcast);
-       result += scnprintf(buf + result, bufsize - result,
-                           " 0x%02x %u ", wss->hash, wss->secure_status);
-       result += wlp_wss_key_print(buf + result, bufsize - result,
-                                   wss->master_key);
-       result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
-                           wss->tag);
-       result += uwb_mac_addr_print(buf + result, bufsize - result,
-                                    &wss->virtual_addr);
-       result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
-       result += scnprintf(buf + result, bufsize - result,
-                           "\n\n#WSSID\n#WSS broadcast address\n"
-                           "#WSS hash\n#WSS secure status\n"
-                           "#WSS master key\n#WSS local tag\n"
-                           "#WSS local virtual EUI-48\n#WSS name\n");
-       return result;
-}
-
-/**
- * Show which WSS is activated.
- */
-ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
-{
-       int result = 0;
-
-       if (mutex_lock_interruptible(&wss->mutex))
-               goto out;
-       if (wss->state >= WLP_WSS_STATE_ACTIVE)
-               result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
-       else
-               result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
-       result += scnprintf(buf + result, PAGE_SIZE - result,
-                       "\n\n"
-                       "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
-                       "NAME #create new WSS\n"
-                       "# echo WSSID [DEV ADDR] #enroll in and activate "
-                       "existing WSS, can request registrar\n"
-                       "#\n"
-                       "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
-                       "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
-                       "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
-                       "# NAME is the text string identifying the WSS\n"
-                       "# DEV ADDR is the device address of neighbor "
-                       "that should be registrar. Eg. 32:AB\n");
-
-       mutex_unlock(&wss->mutex);
-out:
-       return result;
-
-}
-EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
-
-/**
- * Create/activate a new WSS or enroll/activate in neighboring WSS
- *
- * The user can provide the WSSID of a WSS in which it wants to enroll.
- * Only the WSSID is necessary if the WSS have been discovered before. If
- * the WSS has not been discovered before, or the user wants to use a
- * particular neighbor as its registrar, then the user can also provide a
- * device address or the neighbor that will be used as registrar.
- *
- * A new WSS is created when the user provides a WSSID, secure status, and
- * WSS name.
- */
-ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
-                              const char *buf, size_t size)
-{
-       ssize_t result = -EINVAL;
-       struct wlp_uuid wssid;
-       struct uwb_dev_addr dev;
-       struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
-       char name[65];
-       unsigned sec_status, accept;
-       memset(name, 0, sizeof(name));
-       result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx:%02hhx",
-                       &wssid.data[0] , &wssid.data[1],
-                       &wssid.data[2] , &wssid.data[3],
-                       &wssid.data[4] , &wssid.data[5],
-                       &wssid.data[6] , &wssid.data[7],
-                       &wssid.data[8] , &wssid.data[9],
-                       &wssid.data[10], &wssid.data[11],
-                       &wssid.data[12], &wssid.data[13],
-                       &wssid.data[14], &wssid.data[15],
-                       &dev.data[1], &dev.data[0]);
-       if (result == 16 || result == 17) {
-               result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
-                               "%02hhx %02hhx %02hhx %02hhx "
-                               "%02hhx %02hhx %02hhx %02hhx "
-                               "%02hhx %02hhx %02hhx %02hhx "
-                               "%u %u %64c",
-                               &wssid.data[0] , &wssid.data[1],
-                               &wssid.data[2] , &wssid.data[3],
-                               &wssid.data[4] , &wssid.data[5],
-                               &wssid.data[6] , &wssid.data[7],
-                               &wssid.data[8] , &wssid.data[9],
-                               &wssid.data[10], &wssid.data[11],
-                               &wssid.data[12], &wssid.data[13],
-                               &wssid.data[14], &wssid.data[15],
-                               &sec_status, &accept, name);
-               if (result == 16)
-                       result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
-               else if (result == 19) {
-                       sec_status = sec_status == 0 ? 0 : 1;
-                       accept = accept == 0 ? 0 : 1;
-                       /* We read name using %c, so the newline needs to be
-                        * removed */
-                       if (strlen(name) != sizeof(name) - 1)
-                               name[strlen(name) - 1] = '\0';
-                       result = wlp_wss_create_activate(wss, &wssid, name,
-                                                        sec_status, accept);
-               } else
-                       result = -EINVAL;
-       } else if (result == 18)
-               result = wlp_wss_enroll_activate(wss, &wssid, &dev);
-       else
-               result = -EINVAL;
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
-
-/**
- * Show the UUID of this host
- */
-ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-
-       mutex_lock(&wlp->mutex);
-       result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
-       buf[result++] = '\n';
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_uuid_show);
-
-/**
- * Store a new UUID for this host
- *
- * According to the spec this should be encoded as an octet string in the
- * order the octets are shown in string representation in RFC 4122 (WLP
- * 0.99 [Table 6])
- *
- * We do not check value provided by user.
- */
-ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
-{
-       ssize_t result;
-       struct wlp_uuid uuid;
-
-       mutex_lock(&wlp->mutex);
-       result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx ",
-                       &uuid.data[0] , &uuid.data[1],
-                       &uuid.data[2] , &uuid.data[3],
-                       &uuid.data[4] , &uuid.data[5],
-                       &uuid.data[6] , &uuid.data[7],
-                       &uuid.data[8] , &uuid.data[9],
-                       &uuid.data[10], &uuid.data[11],
-                       &uuid.data[12], &uuid.data[13],
-                       &uuid.data[14], &uuid.data[15]);
-       if (result != 16) {
-               result = -EINVAL;
-               goto error;
-       }
-       wlp->uuid = uuid;
-error:
-       mutex_unlock(&wlp->mutex);
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_uuid_store);
-
-/**
- * Show contents of members of device information structure
- */
-#define wlp_dev_info_show(type)                                                \
-ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf)              \
-{                                                                      \
-       ssize_t result = 0;                                             \
-       mutex_lock(&wlp->mutex);                                        \
-       if (wlp->dev_info == NULL) {                                    \
-               result = __wlp_setup_device_info(wlp);                  \
-               if (result < 0)                                         \
-                       goto out;                                       \
-       }                                                               \
-       result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
-out:                                                                   \
-       mutex_unlock(&wlp->mutex);                                      \
-       return result;                                                  \
-}                                                                      \
-EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
-
-wlp_dev_info_show(name)
-wlp_dev_info_show(model_name)
-wlp_dev_info_show(model_nr)
-wlp_dev_info_show(manufacturer)
-wlp_dev_info_show(serial)
-
-/**
- * Store contents of members of device information structure
- */
-#define wlp_dev_info_store(type, len)                                  \
-ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
-{                                                                      \
-       ssize_t result;                                                 \
-       char format[10];                                                \
-       mutex_lock(&wlp->mutex);                                        \
-       if (wlp->dev_info == NULL) {                                    \
-               result = __wlp_alloc_device_info(wlp);                  \
-               if (result < 0)                                         \
-                       goto out;                                       \
-       }                                                               \
-       memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type));    \
-       sprintf(format, "%%%uc", len);                                  \
-       result = sscanf(buf, format, wlp->dev_info->type);              \
-out:                                                                   \
-       mutex_unlock(&wlp->mutex);                                      \
-       return result < 0 ? result : size;                              \
-}                                                                      \
-EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
-
-wlp_dev_info_store(name, 32)
-wlp_dev_info_store(manufacturer, 64)
-wlp_dev_info_store(model_name, 32)
-wlp_dev_info_store(model_nr, 32)
-wlp_dev_info_store(serial, 32)
-
-static
-const char *__wlp_dev_category[] = {
-       [WLP_DEV_CAT_COMPUTER] = "Computer",
-       [WLP_DEV_CAT_INPUT] = "Input device",
-       [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
-                                             "Copier",
-       [WLP_DEV_CAT_CAMERA] = "Camera",
-       [WLP_DEV_CAT_STORAGE] = "Storage Network",
-       [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
-       [WLP_DEV_CAT_DISPLAY] = "Display",
-       [WLP_DEV_CAT_MULTIM] = "Multimedia device",
-       [WLP_DEV_CAT_GAMING] = "Gaming device",
-       [WLP_DEV_CAT_TELEPHONE] = "Telephone",
-       [WLP_DEV_CAT_OTHER] = "Other",
-};
-
-static
-const char *wlp_dev_category_str(unsigned cat)
-{
-       if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
-           || cat == WLP_DEV_CAT_OTHER)
-               return __wlp_dev_category[cat];
-       return "unknown category";
-}
-
-ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = scnprintf(buf, PAGE_SIZE, "%s\n",
-                 wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
-out:
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
-
-ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
-                                   size_t size)
-{
-       ssize_t result;
-       u16 cat;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_alloc_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = sscanf(buf, "%hu", &cat);
-       if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
-           || cat == WLP_DEV_CAT_OTHER)
-               wlp->dev_info->prim_dev_type.category = cat;
-       else
-               result = -EINVAL;
-out:
-       mutex_unlock(&wlp->mutex);
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
-
-ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
-                          wlp->dev_info->prim_dev_type.OUI[0],
-                          wlp->dev_info->prim_dev_type.OUI[1],
-                          wlp->dev_info->prim_dev_type.OUI[2]);
-out:
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
-
-ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
-{
-       ssize_t result;
-       u8 OUI[3];
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_alloc_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = sscanf(buf, "%hhx:%hhx:%hhx",
-                       &OUI[0], &OUI[1], &OUI[2]);
-       if (result != 3) {
-               result = -EINVAL;
-               goto out;
-       } else
-               memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
-out:
-       mutex_unlock(&wlp->mutex);
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
-
-
-ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = scnprintf(buf, PAGE_SIZE, "%u\n",
-                          wlp->dev_info->prim_dev_type.OUIsubdiv);
-out:
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
-
-ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
-                                  size_t size)
-{
-       ssize_t result;
-       unsigned sub;
-       u8 max_sub = ~0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_alloc_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = sscanf(buf, "%u", &sub);
-       if (sub <= max_sub)
-               wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
-       else
-               result = -EINVAL;
-out:
-       mutex_unlock(&wlp->mutex);
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
-
-ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
-{
-       ssize_t result = 0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_setup_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = scnprintf(buf, PAGE_SIZE, "%u\n",
-                          wlp->dev_info->prim_dev_type.subID);
-out:
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
-
-ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
-                                 size_t size)
-{
-       ssize_t result;
-       unsigned sub;
-       __le16 max_sub = ~0;
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info == NULL) {
-               result = __wlp_alloc_device_info(wlp);
-               if (result < 0)
-                       goto out;
-       }
-       result = sscanf(buf, "%u", &sub);
-       if (sub <= max_sub)
-               wlp->dev_info->prim_dev_type.subID = sub;
-       else
-               result = -EINVAL;
-out:
-       mutex_unlock(&wlp->mutex);
-       return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
-
-/**
- * Subsystem implementation for interaction with individual WSS via sysfs
- *
- * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
- */
-
-#define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
-#define attr_to_wlp_wss_attr(_attr) \
-       container_of(_attr, struct wlp_wss_attribute, attr)
-
-/**
- * Sysfs subsystem: forward read calls
- *
- * Sysfs operation for forwarding read call to the show method of the
- * attribute owner
- */
-static
-ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
-                         char *buf)
-{
-       struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
-       struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
-       ssize_t ret = -EIO;
-
-       if (wss_attr->show)
-               ret = wss_attr->show(wss, buf);
-       return ret;
-}
-/**
- * Sysfs subsystem: forward write calls
- *
- * Sysfs operation for forwarding write call to the store method of the
- * attribute owner
- */
-static
-ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
-       struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
-       ssize_t ret = -EIO;
-
-       if (wss_attr->store)
-               ret = wss_attr->store(wss, buf, count);
-       return ret;
-}
-
-static const struct sysfs_ops wss_sysfs_ops = {
-       .show   = wlp_wss_attr_show,
-       .store  = wlp_wss_attr_store,
-};
-
-struct kobj_type wss_ktype = {
-       .release        = wlp_wss_release,
-       .sysfs_ops      = &wss_sysfs_ops,
-};
-
-
-/**
- * Sysfs files for individual WSS
- */
-
-/**
- * Print static properties of this WSS
- *
- * The name of a WSS may not be null teminated. It's max size is 64 bytes
- * so we copy it to a larger array just to make sure we print sane data.
- */
-static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
-{
-       int result = 0;
-
-       if (mutex_lock_interruptible(&wss->mutex))
-               goto out;
-       result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
-       mutex_unlock(&wss->mutex);
-out:
-       return result;
-}
-WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
-
-/**
- * Print all connected members of this WSS
- * The EDA cache contains all members of WSS neighborhood.
- */
-static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       return wlp_eda_show(wlp, buf);
-}
-WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
-
-static
-const char *__wlp_strstate[] = {
-       "none",
-       "partially enrolled",
-       "enrolled",
-       "active",
-       "connected",
-};
-
-static const char *wlp_wss_strstate(unsigned state)
-{
-       if (state >= ARRAY_SIZE(__wlp_strstate))
-               return "unknown state";
-       return __wlp_strstate[state];
-}
-
-/*
- * Print current state of this WSS
- */
-static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
-{
-       int result = 0;
-
-       if (mutex_lock_interruptible(&wss->mutex))
-               goto out;
-       result = scnprintf(buf, PAGE_SIZE, "%s\n",
-                          wlp_wss_strstate(wss->state));
-       mutex_unlock(&wss->mutex);
-out:
-       return result;
-}
-WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
-
-
-static
-struct attribute *wss_attrs[] = {
-       &wss_attr_properties.attr,
-       &wss_attr_members.attr,
-       &wss_attr_state.attr,
-       NULL,
-};
-
-struct attribute_group wss_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = wss_attrs,
-};
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
deleted file mode 100644 (file)
index 05dde44..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Message exchange infrastructure
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: Docs
- *
- */
-
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-/*
- * Direct incoming association msg to correct parsing routine
- *
- * We only expect D1, E1, C1, C3 messages as new. All other incoming
- * association messages should form part of an established session that is
- * handled elsewhere.
- * The handling of these messages often require calling sleeping functions
- * - this cannot be done in interrupt context. We use the kernel's
- * workqueue to handle these messages.
- */
-static
-void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
-                          struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *assoc = (void *) skb->data;
-       struct wlp_assoc_frame_ctx *frame_ctx;
-
-       frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC);
-       if (frame_ctx == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for association "
-                       "frame handling.\n");
-               kfree_skb(skb);
-               return;
-       }
-       frame_ctx->wlp = wlp;
-       frame_ctx->skb = skb;
-       frame_ctx->src = *src;
-       switch (assoc->type) {
-       case WLP_ASSOC_D1:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       case WLP_ASSOC_E1:
-               kfree_skb(skb); /* Temporary until we handle it */
-               kfree(frame_ctx); /* Temporary until we handle it */
-               break;
-       case WLP_ASSOC_C1:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       case WLP_ASSOC_C3:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       default:
-               dev_err(dev, "Received unexpected association frame. "
-                       "Type = %d \n", assoc->type);
-               kfree_skb(skb);
-               kfree(frame_ctx);
-               break;
-       }
-}
-
-/*
- * Process incoming association frame
- *
- * Although it could be possible to deal with some incoming association
- * messages without creating a new session we are keeping things simple. We
- * do not accept new association messages if there is a session in progress
- * and the messages do not belong to that session.
- *
- * If an association message arrives that causes the creation of a session
- * (WLP_ASSOC_E1) while we are in the process of creating a session then we
- * rely on the neighbor mutex to protect the data. That is, the new session
- * will not be started until the previous is completed.
- */
-static
-void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
-                            struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *assoc = (void *) skb->data;
-       struct wlp_session *session = wlp->session;
-       u8 version;
-
-       if (wlp_get_version(wlp, &assoc->version, &version,
-                           sizeof(assoc->version)) < 0)
-               goto error;
-       if (version != WLP_VERSION) {
-               dev_err(dev, "Unsupported WLP version in association "
-                       "message.\n");
-               goto error;
-       }
-       if (session != NULL) {
-               /* Function that created this session is still holding the
-                * &wlp->mutex to protect this session. */
-               if (assoc->type == session->exp_message ||
-                   assoc->type == WLP_ASSOC_F0) {
-                       if (!memcmp(&session->neighbor_addr, src,
-                                  sizeof(*src))) {
-                               session->data = skb;
-                               (session->cb)(wlp);
-                       } else {
-                               dev_err(dev, "Received expected message from "
-                                       "unexpected source.  Expected message "
-                                       "%d or F0 from %02x:%02x, but received "
-                                       "it from %02x:%02x. Dropping.\n",
-                                       session->exp_message,
-                                       session->neighbor_addr.data[1],
-                                       session->neighbor_addr.data[0],
-                                       src->data[1], src->data[0]);
-                               goto error;
-                       }
-               } else {
-                       dev_err(dev, "Association already in progress. "
-                               "Dropping.\n");
-                       goto error;
-               }
-       } else {
-               wlp_direct_assoc_frame(wlp, skb, src);
-       }
-       return;
-error:
-       kfree_skb(skb);
-}
-
-/*
- * Verify incoming frame is from connected neighbor, prep to pass to WLP client
- *
- * Verification proceeds according to WLP 0.99 [7.3.1]. The source address
- * is used to determine which neighbor is sending the frame and the WSS tag
- * is used to know to which WSS the frame belongs (we only support one WSS
- * so this test is straight forward).
- * With the WSS found we need to ensure that we are connected before
- * allowing the exchange of data frames.
- */
-static
-int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb,
-                            struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = -EINVAL;
-       struct wlp_eda_node eda_entry;
-       struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data;
-
-       /*verify*/
-       result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Incoming frame is from unknown "
-                               "neighbor %02x:%02x.\n", src->data[1],
-                               src->data[0]);
-               goto out;
-       }
-       if (hdr->tag != eda_entry.tag) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Tag of incoming frame from "
-                               "%02x:%02x does not match expected tag. "
-                               "Received 0x%02x, expected 0x%02x. \n",
-                               src->data[1], src->data[0], hdr->tag,
-                               eda_entry.tag);
-               result = -EINVAL;
-               goto out;
-       }
-       if (eda_entry.state != WLP_WSS_CONNECTED) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Incoming frame from "
-                               "%02x:%02x does is not from connected WSS.\n",
-                               src->data[1], src->data[0]);
-               result = -EINVAL;
-               goto out;
-       }
-       /*prep*/
-       skb_pull(skb, sizeof(*hdr));
-out:
-       return result;
-}
-
-/*
- * Receive a WLP frame from device
- *
- * @returns: 1 if calling function should free the skb
- *           0 if it successfully handled skb and freed it
- *           0 if error occured, will free skb in this case
- */
-int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb,
-                     struct uwb_dev_addr *src)
-{
-       unsigned len = skb->len;
-       void *ptr = skb->data;
-       struct wlp_frame_hdr *hdr;
-       int result = 0;
-
-       if (len < sizeof(*hdr)) {
-               dev_err(dev, "Not enough data to parse WLP header.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       hdr = ptr;
-       if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) {
-               dev_err(dev, "Not a WLP frame type.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       switch (hdr->type) {
-       case WLP_FRAME_STANDARD:
-               if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) {
-                       dev_err(dev, "Not enough data to parse Standard "
-                               "WLP header.\n");
-                       goto out;
-               }
-               result = wlp_verify_prep_rx_frame(wlp, skb, src);
-               if (result < 0) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "WLP: Verification of frame "
-                                       "from neighbor %02x:%02x failed.\n",
-                                       src->data[1], src->data[0]);
-                       goto out;
-               }
-               result = 1;
-               break;
-       case WLP_FRAME_ABBREVIATED:
-               dev_err(dev, "Abbreviated frame received. FIXME?\n");
-               kfree_skb(skb);
-               break;
-       case WLP_FRAME_CONTROL:
-               dev_err(dev, "Control frame received. FIXME?\n");
-               kfree_skb(skb);
-               break;
-       case WLP_FRAME_ASSOCIATION:
-               if (len < sizeof(struct wlp_frame_assoc)) {
-                       dev_err(dev, "Not enough data to parse Association "
-                               "WLP header.\n");
-                       goto out;
-               }
-               wlp_receive_assoc_frame(wlp, skb, src);
-               break;
-       default:
-               dev_err(dev, "Invalid frame received.\n");
-               result = -EINVAL;
-               break;
-       }
-out:
-       if (result < 0) {
-               kfree_skb(skb);
-               result = 0;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_receive_frame);
-
-
-/*
- * Verify frame from network stack, prepare for further transmission
- *
- * @skb:   the socket buffer that needs to be prepared for transmission (it
- *         is in need of a WLP header). If this is a broadcast frame we take
- *         over the entire transmission.
- *         If it is a unicast the WSS connection should already be established
- *         and transmission will be done by the calling function.
- * @dst:   On return this will contain the device address to which the
- *         frame is destined.
- * @returns: 0 on success no tx : WLP header successfully applied to skb buffer,
- *                                calling function can proceed with tx
- *           1 on success with tx : WLP will take over transmission of this
- *                                  frame
- *           <0 on error
- *
- * The network stack (WLP client) is attempting to transmit a frame. We can
- * only transmit data if a local WSS is at least active (connection will be
- * done here if this is a broadcast frame and neighbor also has the WSS
- * active).
- *
- * The frame can be either broadcast or unicast. Broadcast in a WSS is
- * supported via multicast, but we don't support multicast yet (until
- * devices start to support MAB IEs). If a broadcast frame needs to be
- * transmitted it is treated as a unicast frame to each neighbor. In this
- * case the WLP takes over transmission of the skb and returns 1
- * to the caller to indicate so. Also, in this case, if a neighbor has the
- * same WSS activated but is not connected then the WSS connection will be
- * done at this time. The neighbor's virtual address will be learned at
- * this time.
- *
- * The destination address in a unicast frame is the virtual address of the
- * neighbor. This address only becomes known when a WSS connection is
- * established. We thus rely on a broadcast frame to trigger the setup of
- * WSS connections to all neighbors before we are able to send unicast
- * frames to them. This seems reasonable as IP would usually use ARP first
- * before any unicast frames are sent.
- *
- * If we are already connected to the neighbor (neighbor's virtual address
- * is known) we just prepare the WLP header and the caller will continue to
- * send the frame.
- *
- * A failure in this function usually indicates something that cannot be
- * fixed automatically. So, if this function fails (@return < 0) the calling
- * function should not retry to send the frame as it will very likely keep
- * failing.
- *
- */
-int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
-                        struct sk_buff *skb, struct uwb_dev_addr *dst)
-{
-       int result = -EINVAL;
-       struct ethhdr *eth_hdr = (void *) skb->data;
-
-       if (is_multicast_ether_addr(eth_hdr->h_dest)) {
-               result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
-               if (result < 0) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "Unable to handle broadcast "
-                                       "frame from WLP client.\n");
-                       goto out;
-               }
-               dev_kfree_skb_irq(skb);
-               result = 1;
-               /* Frame will be transmitted by WLP. */
-       } else {
-               result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst,
-                                            wlp_wss_prep_hdr, skb);
-               if (unlikely(result < 0)) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "Unable to prepare "
-                                       "skb for transmission. \n");
-                       goto out;
-               }
-       }
-out:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame);
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h
deleted file mode 100644 (file)
index 3e8d5de..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Internal API
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#ifndef __WLP_INTERNAL_H__
-#define __WLP_INTERNAL_H__
-
-/**
- * State of WSS connection
- *
- * A device needs to connect to a neighbor in an activated WSS before data
- * can be transmitted. The spec also distinguishes between a new connection
- * attempt and a connection attempt after previous connection attempts. The
- * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99
- * [7.2.6]
- */
-enum wlp_wss_connect {
-       WLP_WSS_UNCONNECTED = 0,
-       WLP_WSS_CONNECTED,
-       WLP_WSS_CONNECT_FAILED,
-};
-
-extern struct kobj_type wss_ktype;
-extern struct attribute_group wss_attr_group;
-
-/* This should be changed to a dynamic array where entries are sorted
- * by eth_addr and search is done in a binary form
- *
- * Although thinking twice about it: this technologie's maximum reach
- * is 10 meters...unless you want to pack too much stuff in around
- * your radio controller/WLP device, the list will probably not be
- * too big.
- *
- * In any case, there is probably some data structure in the kernel
- * than we could reused for that already.
- *
- * The below structure is really just good while we support one WSS per
- * host.
- */
-struct wlp_eda_node {
-       struct list_head list_node;
-       unsigned char eth_addr[ETH_ALEN];
-       struct uwb_dev_addr dev_addr;
-       struct wlp_wss *wss;
-       unsigned char virt_addr[ETH_ALEN];
-       u8 tag;
-       enum wlp_wss_connect state;
-};
-
-typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *);
-
-extern void wlp_eda_init(struct wlp_eda *);
-extern void wlp_eda_release(struct wlp_eda *);
-extern int wlp_eda_create_node(struct wlp_eda *,
-                              const unsigned char eth_addr[ETH_ALEN],
-                              const struct uwb_dev_addr *);
-extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *);
-extern int wlp_eda_update_node(struct wlp_eda *,
-                              const struct uwb_dev_addr *,
-                              struct wlp_wss *,
-                              const unsigned char virt_addr[ETH_ALEN],
-                              const u8, const enum wlp_wss_connect);
-extern int wlp_eda_update_node_state(struct wlp_eda *,
-                                    const struct uwb_dev_addr *,
-                                    const enum wlp_wss_connect);
-
-extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *,
-                            struct wlp_eda_node *);
-extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *);
-extern int wlp_eda_for_virtual(struct wlp_eda *,
-                              const unsigned char eth_addr[ETH_ALEN],
-                              struct uwb_dev_addr *,
-                              wlp_eda_for_each_f , void *);
-
-
-extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *);
-
-extern size_t wlp_wss_key_print(char *, size_t, u8 *);
-
-/* Function called when no more references to WSS exists */
-extern void wlp_wss_release(struct kobject *);
-
-extern void wlp_wss_reset(struct wlp_wss *);
-extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *,
-                                  char *, unsigned, unsigned);
-extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *,
-                                  struct uwb_dev_addr *);
-extern ssize_t wlp_discover(struct wlp *);
-
-extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *,
-                              struct wlp_wss *, struct wlp_uuid *);
-extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *,
-                            struct uwb_dev_addr *);
-
-struct wlp_assoc_conn_ctx {
-       struct work_struct ws;
-       struct wlp *wlp;
-       struct sk_buff *skb;
-       struct wlp_eda_node eda_entry;
-};
-
-
-extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *);
-extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *);
-
-
-/* Message handling */
-struct wlp_assoc_frame_ctx {
-       struct work_struct ws;
-       struct wlp *wlp;
-       struct sk_buff *skb;
-       struct uwb_dev_addr src;
-};
-
-extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *);
-extern void wlp_handle_d1_frame(struct work_struct *);
-extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *,
-                                      struct wlp_neighbor_e *);
-extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *,
-                                       struct wlp_neighbor_e *,
-                                       struct wlp_uuid *);
-extern void wlp_handle_c1_frame(struct work_struct *);
-extern void wlp_handle_c3_frame(struct work_struct *);
-extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *,
-                               struct wlp_uuid *, u8 *,
-                               struct uwb_mac_addr *);
-extern int wlp_parse_f0(struct wlp *, struct sk_buff *);
-extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *,
-                               struct uwb_dev_addr *, enum wlp_assoc_type);
-extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *,
-                              u8 *, ssize_t);
-extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *,
-                            struct wlp_uuid *, ssize_t);
-extern int __wlp_alloc_device_info(struct wlp *);
-extern int __wlp_setup_device_info(struct wlp *);
-
-extern struct wlp_wss_attribute wss_attribute_properties;
-extern struct wlp_wss_attribute wss_attribute_members;
-extern struct wlp_wss_attribute wss_attribute_state;
-
-static inline
-size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid)
-{
-       size_t result;
-
-       result = scnprintf(buf, bufsize,
-                         "%02x:%02x:%02x:%02x:%02x:%02x:"
-                         "%02x:%02x:%02x:%02x:%02x:%02x:"
-                         "%02x:%02x:%02x:%02x",
-                         uuid->data[0], uuid->data[1],
-                         uuid->data[2], uuid->data[3],
-                         uuid->data[4], uuid->data[5],
-                         uuid->data[6], uuid->data[7],
-                         uuid->data[8], uuid->data[9],
-                         uuid->data[10], uuid->data[11],
-                         uuid->data[12], uuid->data[13],
-                         uuid->data[14], uuid->data[15]);
-       return result;
-}
-
-/**
- * FIXME: How should a nonce be displayed?
- */
-static inline
-size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce)
-{
-       size_t result;
-
-       result = scnprintf(buf, bufsize,
-                         "%02x %02x %02x %02x %02x %02x "
-                         "%02x %02x %02x %02x %02x %02x "
-                         "%02x %02x %02x %02x",
-                         nonce->data[0], nonce->data[1],
-                         nonce->data[2], nonce->data[3],
-                         nonce->data[4], nonce->data[5],
-                         nonce->data[6], nonce->data[7],
-                         nonce->data[8], nonce->data[9],
-                         nonce->data[10], nonce->data[11],
-                         nonce->data[12], nonce->data[13],
-                         nonce->data[14], nonce->data[15]);
-       return result;
-}
-
-
-static inline
-void wlp_session_cb(struct wlp *wlp)
-{
-       struct completion *completion = wlp->session->cb_priv;
-       complete(completion);
-}
-
-static inline
-int wlp_uuid_is_set(struct wlp_uuid *uuid)
-{
-       struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00,
-                                               0x00, 0x00, 0x00, 0x00,
-                                               0x00, 0x00, 0x00, 0x00,
-                                               0x00, 0x00, 0x00, 0x00} };
-
-       if (!memcmp(uuid, &zero_uuid, sizeof(*uuid)))
-               return 0;
-       return 1;
-}
-
-#endif /* __WLP_INTERNAL_H__ */
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
deleted file mode 100644 (file)
index 7f6a630..0000000
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-#include <linux/wlp.h>
-#include <linux/slab.h>
-
-#include "wlp-internal.h"
-
-static
-void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
-{
-       INIT_LIST_HEAD(&neighbor->wssid);
-}
-
-/**
- * Create area for device information storage
- *
- * wlp->mutex must be held
- */
-int __wlp_alloc_device_info(struct wlp *wlp)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       BUG_ON(wlp->dev_info != NULL);
-       wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
-       if (wlp->dev_info == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for "
-                       "device information.\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-
-/**
- * Fill in device information using function provided by driver
- *
- * wlp->mutex must be held
- */
-static
-void __wlp_fill_device_info(struct wlp *wlp)
-{
-       wlp->fill_device_info(wlp, wlp->dev_info);
-}
-
-/**
- * Setup device information
- *
- * Allocate area for device information and populate it.
- *
- * wlp->mutex must be held
- */
-int __wlp_setup_device_info(struct wlp *wlp)
-{
-       int result;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-
-       result = __wlp_alloc_device_info(wlp);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to allocate area for "
-                       "device information.\n");
-               return result;
-       }
-       __wlp_fill_device_info(wlp);
-       return 0;
-}
-
-/**
- * Remove information about neighbor stored temporarily
- *
- * Information learned during discovey should only be stored when the
- * device enrolls in the neighbor's WSS. We do need to store this
- * information temporarily in order to present it to the user.
- *
- * We are only interested in keeping neighbor WSS information if that
- * neighbor is accepting enrollment.
- *
- * should be called with wlp->nbmutex held
- */
-void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor)
-{
-       struct wlp_wssid_e *wssid_e, *next;
-       u8 keep;
-       if (!list_empty(&neighbor->wssid)) {
-               list_for_each_entry_safe(wssid_e, next, &neighbor->wssid,
-                                        node) {
-                       if (wssid_e->info != NULL) {
-                               keep = wssid_e->info->accept_enroll;
-                               kfree(wssid_e->info);
-                               wssid_e->info = NULL;
-                               if (!keep) {
-                                       list_del(&wssid_e->node);
-                                       kfree(wssid_e);
-                               }
-                       }
-               }
-       }
-       if (neighbor->info != NULL) {
-               kfree(neighbor->info);
-               neighbor->info = NULL;
-       }
-}
-
-/*
- * Populate WLP neighborhood cache with neighbor information
- *
- * A new neighbor is found. If it is discoverable then we add it to the
- * neighborhood cache.
- *
- */
-static
-int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev)
-{
-       int result = 0;
-       int discoverable;
-       struct wlp_neighbor_e *neighbor;
-
-       /*
-        * FIXME:
-        * Use contents of WLP IE found in beacon cache to determine if
-        * neighbor is discoverable.
-        * The device does not support WLP IE yet so this still needs to be
-        * done. Until then we assume all devices are discoverable.
-        */
-       discoverable = 1; /* will be changed when FIXME disappears */
-       if (discoverable) {
-               /* Add neighbor to cache for discovery */
-               neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL);
-               if (neighbor == NULL) {
-                       dev_err(&dev->dev, "Unable to create memory for "
-                               "new neighbor. \n");
-                       result = -ENOMEM;
-                       goto error_no_mem;
-               }
-               wlp_neighbor_init(neighbor);
-               uwb_dev_get(dev);
-               neighbor->uwb_dev = dev;
-               list_add(&neighbor->node, &wlp->neighbors);
-       }
-error_no_mem:
-       return result;
-}
-
-/**
- * Remove one neighbor from cache
- */
-static
-void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor)
-{
-       struct wlp_wssid_e *wssid_e, *next_wssid_e;
-
-       list_for_each_entry_safe(wssid_e, next_wssid_e,
-                                &neighbor->wssid, node) {
-               list_del(&wssid_e->node);
-               kfree(wssid_e);
-       }
-       uwb_dev_put(neighbor->uwb_dev);
-       list_del(&neighbor->node);
-       kfree(neighbor);
-}
-
-/**
- * Clear entire neighborhood cache.
- */
-static
-void __wlp_neighbors_release(struct wlp *wlp)
-{
-       struct wlp_neighbor_e *neighbor, *next;
-       if (list_empty(&wlp->neighbors))
-               return;
-       list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
-               __wlp_neighbor_release(neighbor);
-       }
-}
-
-static
-void wlp_neighbors_release(struct wlp *wlp)
-{
-       mutex_lock(&wlp->nbmutex);
-       __wlp_neighbors_release(wlp);
-       mutex_unlock(&wlp->nbmutex);
-}
-
-
-
-/**
- * Send D1 message to neighbor, receive D2 message
- *
- * @neighbor: neighbor to which D1 message will be sent
- * @wss:      if not NULL, it is an enrollment request for this WSS
- * @wssid:    if wss not NULL, this is the wssid of the WSS in which we
- *            want to enroll
- *
- * A D1/D2 exchange is done for one of two reasons: discovery or
- * enrollment. If done for discovery the D1 message is sent to the neighbor
- * and the contents of the D2 response is stored in a temporary cache.
- * If done for enrollment the @wss and @wssid are provided also. In this
- * case the D1 message is sent to the neighbor, the D2 response is parsed
- * for enrollment of the WSS with wssid.
- *
- * &wss->mutex is held
- */
-static
-int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
-                     struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
-       int result;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       DECLARE_COMPLETION_ONSTACK(completion);
-       struct wlp_session session;
-       struct sk_buff  *skb;
-       struct wlp_frame_assoc *resp;
-       struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
-
-       mutex_lock(&wlp->mutex);
-       if (!wlp_uuid_is_set(&wlp->uuid)) {
-               dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
-                       "proceed.\n");
-               result = -ENXIO;
-               goto out;
-       }
-       /* Send D1 association frame */
-       result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1);
-       if (result < 0) {
-               dev_err(dev, "Unable to send D1 frame to neighbor "
-                       "%02x:%02x (%d)\n", dev_addr->data[1],
-                       dev_addr->data[0], result);
-               goto out;
-       }
-       /* Create session, wait for response */
-       session.exp_message = WLP_ASSOC_D2;
-       session.cb = wlp_session_cb;
-       session.cb_priv = &completion;
-       session.neighbor_addr = *dev_addr;
-       BUG_ON(wlp->session != NULL);
-       wlp->session = &session;
-       /* Wait for D2/F0 frame */
-       result = wait_for_completion_interruptible_timeout(&completion,
-                                                  WLP_PER_MSG_TIMEOUT * HZ);
-       if (result == 0) {
-               result = -ETIMEDOUT;
-               dev_err(dev, "Timeout while sending D1 to neighbor "
-                            "%02x:%02x.\n", dev_addr->data[1],
-                            dev_addr->data[0]);
-               goto error_session;
-       }
-       if (result < 0) {
-               dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n",
-                       dev_addr->data[1], dev_addr->data[0]);
-               goto error_session;
-       }
-       /* Parse message in session->data: it will be either D2 or F0 */
-       skb = session.data;
-       resp = (void *) skb->data;
-
-       if (resp->type == WLP_ASSOC_F0) {
-               result = wlp_parse_f0(wlp, skb);
-               if (result < 0)
-                       dev_err(dev, "WLP: Unable to parse F0 from neighbor "
-                               "%02x:%02x.\n", dev_addr->data[1],
-                               dev_addr->data[0]);
-               result = -EINVAL;
-               goto error_resp_parse;
-       }
-       if (wss == NULL) {
-               /* Discovery */
-               result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to parse D2 message from "
-                               "neighbor %02x:%02x for discovery.\n",
-                               dev_addr->data[1], dev_addr->data[0]);
-                       goto error_resp_parse;
-               }
-       } else {
-               /* Enrollment */
-               result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor,
-                                                     wssid);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to parse D2 message from "
-                               "neighbor %02x:%02x for enrollment.\n",
-                               dev_addr->data[1], dev_addr->data[0]);
-                       goto error_resp_parse;
-               }
-       }
-error_resp_parse:
-       kfree_skb(skb);
-error_session:
-       wlp->session = NULL;
-out:
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-
-/**
- * Enroll into WSS of provided WSSID by using neighbor as registrar
- *
- * &wss->mutex is held
- */
-int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
-                       struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       char buf[WLP_WSS_UUID_STRSIZE];
-       struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
-
-       wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
-       result =  wlp_d1d2_exchange(wlp, neighbor, wss, wssid);
-       if (result < 0) {
-               dev_err(dev, "WLP: D1/D2 message exchange for enrollment "
-                       "failed. result = %d \n", result);
-               goto out;
-       }
-       if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
-               dev_err(dev, "WLP: Unable to enroll into WSS %s using "
-                       "neighbor %02x:%02x. \n", buf,
-                       dev_addr->data[1], dev_addr->data[0]);
-               result = -EINVAL;
-               goto out;
-       }
-       if (wss->secure_status == WLP_WSS_SECURE) {
-               dev_err(dev, "FIXME: need to complete secure enrollment.\n");
-               result = -EINVAL;
-               goto error;
-       } else {
-               wss->state = WLP_WSS_STATE_ENROLLED;
-               dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS "
-                       "%s using neighbor %02x:%02x. \n",
-                       buf, dev_addr->data[1], dev_addr->data[0]);
-       }
-out:
-       return result;
-error:
-       wlp_wss_reset(wss);
-       return result;
-}
-
-/**
- * Discover WSS information of neighbor's active WSS
- */
-static
-int wlp_discover_neighbor(struct wlp *wlp,
-                         struct wlp_neighbor_e *neighbor)
-{
-       return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL);
-}
-
-
-/**
- * Each neighbor in the neighborhood cache is discoverable. Discover it.
- *
- * Discovery is done through sending of D1 association frame and parsing
- * the D2 association frame response. Only wssid from D2 will be included
- * in neighbor cache, rest is just displayed to user and forgotten.
- *
- * The discovery is not done in parallel. This is simple and enables us to
- * maintain only one association context.
- *
- * The discovery of one neighbor does not affect the other, but if the
- * discovery of a neighbor fails it is removed from the neighborhood cache.
- */
-static
-int wlp_discover_all_neighbors(struct wlp *wlp)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_neighbor_e *neighbor, *next;
-
-       list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
-               result = wlp_discover_neighbor(wlp, neighbor);
-               if (result < 0) {
-                       dev_err(dev, "WLP: Unable to discover neighbor "
-                               "%02x:%02x, removing from neighborhood. \n",
-                               neighbor->uwb_dev->dev_addr.data[1],
-                               neighbor->uwb_dev->dev_addr.data[0]);
-                       __wlp_neighbor_release(neighbor);
-               }
-       }
-       return result;
-}
-
-static int wlp_add_neighbor_helper(struct device *dev, void *priv)
-{
-       struct wlp *wlp = priv;
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       return wlp_add_neighbor(wlp, uwb_dev);
-}
-
-/**
- * Discover WLP neighborhood
- *
- * Will send D1 association frame to all devices in beacon group that have
- * discoverable bit set in WLP IE. D2 frames will be received, information
- * displayed to user in @buf. Partial information (from D2 association
- * frame) will be cached to assist with future association
- * requests.
- *
- * The discovery of the WLP neighborhood is triggered by the user. This
- * should occur infrequently and we thus free current cache and re-allocate
- * memory if needed.
- *
- * If one neighbor fails during initial discovery (determining if it is a
- * neighbor or not), we fail all - note that interaction with neighbor has
- * not occured at this point so if a failure occurs we know something went wrong
- * locally. We thus undo everything.
- */
-ssize_t wlp_discover(struct wlp *wlp)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-
-       mutex_lock(&wlp->nbmutex);
-       /* Clear current neighborhood cache. */
-       __wlp_neighbors_release(wlp);
-       /* Determine which devices in neighborhood. Repopulate cache. */
-       result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp);
-       if (result < 0) {
-               /* May have partial neighbor information, release all. */
-               __wlp_neighbors_release(wlp);
-               goto error_dev_for_each;
-       }
-       /* Discover the properties of devices in neighborhood. */
-       result = wlp_discover_all_neighbors(wlp);
-       /* In case of failure we still print our partial results. */
-       if (result < 0) {
-               dev_err(dev, "Unable to fully discover neighborhood. \n");
-               result = 0;
-       }
-error_dev_for_each:
-       mutex_unlock(&wlp->nbmutex);
-       return result;
-}
-
-/**
- * Handle events from UWB stack
- *
- * We handle events conservatively. If a neighbor goes off the air we
- * remove it from the neighborhood. If an association process is in
- * progress this function will block waiting for the nbmutex to become
- * free. The association process will thus be allowed to complete before it
- * is removed.
- */
-static
-void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev,
-                      enum uwb_notifs event)
-{
-       struct wlp *wlp = _wlp;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_neighbor_e *neighbor, *next;
-       int result;
-       switch (event) {
-       case UWB_NOTIF_ONAIR:
-               result = wlp_eda_create_node(&wlp->eda,
-                                            uwb_dev->mac_addr.data,
-                                            &uwb_dev->dev_addr);
-               if (result < 0)
-                       dev_err(dev, "WLP: Unable to add new neighbor "
-                               "%02x:%02x to EDA cache.\n",
-                               uwb_dev->dev_addr.data[1],
-                               uwb_dev->dev_addr.data[0]);
-               break;
-       case UWB_NOTIF_OFFAIR:
-               wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr);
-               mutex_lock(&wlp->nbmutex);
-               list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
-                       if (neighbor->uwb_dev == uwb_dev)
-                               __wlp_neighbor_release(neighbor);
-               }
-               mutex_unlock(&wlp->nbmutex);
-               break;
-       default:
-               dev_err(dev, "don't know how to handle event %d from uwb\n",
-                               event);
-       }
-}
-
-static void wlp_channel_changed(struct uwb_pal *pal, int channel)
-{
-       struct wlp *wlp = container_of(pal, struct wlp, pal);
-
-       if (channel < 0)
-               netif_carrier_off(wlp->ndev);
-       else
-               netif_carrier_on(wlp->ndev);
-}
-
-int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev)
-{
-       int result;
-
-       BUG_ON(wlp->fill_device_info == NULL);
-       BUG_ON(wlp->xmit_frame == NULL);
-       BUG_ON(wlp->stop_queue == NULL);
-       BUG_ON(wlp->start_queue == NULL);
-
-       wlp->rc = rc;
-       wlp->ndev = ndev;
-       wlp_eda_init(&wlp->eda);/* Set up address cache */
-       wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb;
-       wlp->uwb_notifs_handler.data = wlp;
-       uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
-
-       uwb_pal_init(&wlp->pal);
-       wlp->pal.rc = rc;
-       wlp->pal.channel_changed = wlp_channel_changed;
-       result = uwb_pal_register(&wlp->pal);
-       if (result < 0)
-               uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_setup);
-
-void wlp_remove(struct wlp *wlp)
-{
-       wlp_neighbors_release(wlp);
-       uwb_pal_unregister(&wlp->pal);
-       uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
-       wlp_eda_release(&wlp->eda);
-       mutex_lock(&wlp->mutex);
-       if (wlp->dev_info != NULL)
-               kfree(wlp->dev_info);
-       mutex_unlock(&wlp->mutex);
-       wlp->rc = NULL;
-}
-EXPORT_SYMBOL_GPL(wlp_remove);
-
-/**
- * wlp_reset_all - reset the WLP hardware
- * @wlp: the WLP device to reset.
- *
- * This schedules a full hardware reset of the WLP device.  The radio
- * controller and any other PALs will also be reset.
- */
-void wlp_reset_all(struct wlp *wlp)
-{
-       uwb_rc_reset_all(wlp->rc);
-}
-EXPORT_SYMBOL_GPL(wlp_reset_all);
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c
deleted file mode 100644 (file)
index 67872c8..0000000
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Implementation of the WLP association protocol.
- *
- * FIXME: Docs
- *
- * A UWB network interface will configure a WSS through wlp_wss_setup() after
- * the interface has been assigned a MAC address, typically after
- * "ifconfig" has been called. When the interface goes down it should call
- * wlp_wss_remove().
- *
- * When the WSS is ready for use the user interacts via sysfs to create,
- * discover, and activate WSS.
- *
- * wlp_wss_enroll_activate()
- *
- * wlp_wss_create_activate()
- *     wlp_wss_set_wssid_hash()
- *             wlp_wss_comp_wssid_hash()
- *     wlp_wss_sel_bcast_addr()
- *     wlp_wss_sysfs_add()
- *
- * Called when no more references to WSS exist:
- *     wlp_wss_release()
- *             wlp_wss_reset()
- */
-#include <linux/etherdevice.h> /* for is_valid_ether_addr */
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key)
-{
-       size_t result;
-
-       result = scnprintf(buf, bufsize,
-                         "%02x %02x %02x %02x %02x %02x "
-                         "%02x %02x %02x %02x %02x %02x "
-                         "%02x %02x %02x %02x",
-                         key[0], key[1], key[2], key[3],
-                         key[4], key[5], key[6], key[7],
-                         key[8], key[9], key[10], key[11],
-                         key[12], key[13], key[14], key[15]);
-       return result;
-}
-
-/**
- * Compute WSSID hash
- * WLP Draft 0.99 [7.2.1]
- *
- * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR
- * of all octets in the WSSID.
- */
-static
-u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid)
-{
-       return wssid->data[0]  ^ wssid->data[1]  ^ wssid->data[2]
-              ^ wssid->data[3]  ^ wssid->data[4]  ^ wssid->data[5]
-              ^ wssid->data[6]  ^ wssid->data[7]  ^ wssid->data[8]
-              ^ wssid->data[9]  ^ wssid->data[10] ^ wssid->data[11]
-              ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14]
-              ^ wssid->data[15];
-}
-
-/**
- * Select a multicast EUI-48 for the WSS broadcast address.
- * WLP Draft 0.99 [7.2.1]
- *
- * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP
- * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive.
- *
- * This address is currently hardcoded.
- * FIXME?
- */
-static
-struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss)
-{
-       struct uwb_mac_addr bcast = {
-               .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 }
-       };
-       return bcast;
-}
-
-/**
- * Clear the contents of the WSS structure - all except kobj, mutex, virtual
- *
- * We do not want to reinitialize - the internal kobj should not change as
- * it still points to the parent received during setup. The mutex should
- * remain also. We thus just reset values individually.
- * The virutal address assigned to WSS will remain the same for the
- * lifetime of the WSS. We only reset the fields that can change during its
- * lifetime.
- */
-void wlp_wss_reset(struct wlp_wss *wss)
-{
-       memset(&wss->wssid, 0, sizeof(wss->wssid));
-       wss->hash = 0;
-       memset(&wss->name[0], 0, sizeof(wss->name));
-       memset(&wss->bcast, 0, sizeof(wss->bcast));
-       wss->secure_status = WLP_WSS_UNSECURE;
-       memset(&wss->master_key[0], 0, sizeof(wss->master_key));
-       wss->tag = 0;
-       wss->state = WLP_WSS_STATE_NONE;
-}
-
-/**
- * Create sysfs infrastructure for WSS
- *
- * The WSS is configured to have the interface as parent (see wlp_wss_setup())
- * a new sysfs directory that includes wssid as its name is created in the
- * interface's sysfs directory. The group of files interacting with WSS are
- * created also.
- */
-static
-int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result;
-
-       result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str);
-       if (result < 0)
-               return result;
-       wss->kobj.ktype = &wss_ktype;
-       result = kobject_init_and_add(&wss->kobj,
-                       &wss_ktype, wss->kobj.parent, "wlp");
-       if (result < 0) {
-               dev_err(dev, "WLP: Cannot register WSS kobject.\n");
-               goto error_kobject_register;
-       }
-       result = sysfs_create_group(&wss->kobj, &wss_attr_group);
-       if (result < 0) {
-               dev_err(dev, "WLP: Cannot register WSS attributes: %d\n",
-                       result);
-               goto error_sysfs_create_group;
-       }
-       return 0;
-error_sysfs_create_group:
-
-       kobject_put(&wss->kobj); /* will free name if needed */
-       return result;
-error_kobject_register:
-       kfree(wss->kobj.name);
-       wss->kobj.name = NULL;
-       wss->kobj.ktype = NULL;
-       return result;
-}
-
-
-/**
- * Release WSS
- *
- * No more references exist to this WSS. We should undo everything that was
- * done in wlp_wss_create_activate() except removing the group. The group
- * is not removed because an object can be unregistered before the group is
- * created. We also undo any additional operations on the WSS after this
- * (addition of members).
- *
- * If memory was allocated for the kobject's name then it will
- * be freed by the kobject system during this time.
- *
- * The EDA cache is removed and reinitialized when the WSS is removed. We
- * thus loose knowledge of members of this WSS at that time and need not do
- * it here.
- */
-void wlp_wss_release(struct kobject *kobj)
-{
-       struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj);
-
-       wlp_wss_reset(wss);
-}
-
-/**
- * Enroll into a WSS using provided neighbor as registrar
- *
- * First search the neighborhood information to learn which neighbor is
- * referred to, next proceed with enrollment.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid,
-                         struct uwb_dev_addr *dest)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_neighbor_e *neighbor;
-       int result = -ENXIO;
-       struct uwb_dev_addr *dev_addr;
-
-       mutex_lock(&wlp->nbmutex);
-       list_for_each_entry(neighbor, &wlp->neighbors, node) {
-               dev_addr = &neighbor->uwb_dev->dev_addr;
-               if (!memcmp(dest, dev_addr, sizeof(*dest))) {
-                       result = wlp_enroll_neighbor(wlp, neighbor, wss, wssid);
-                       break;
-               }
-       }
-       if (result == -ENXIO)
-               dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n",
-                       dest->data[1], dest->data[0]);
-       mutex_unlock(&wlp->nbmutex);
-       return result;
-}
-
-/**
- * Enroll into a WSS previously discovered
- *
- * User provides WSSID of WSS, search for neighbor that has this WSS
- * activated and attempt to enroll.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_neighbor_e *neighbor;
-       struct wlp_wssid_e *wssid_e;
-       char buf[WLP_WSS_UUID_STRSIZE];
-       int result = -ENXIO;
-
-
-       mutex_lock(&wlp->nbmutex);
-       list_for_each_entry(neighbor, &wlp->neighbors, node) {
-               list_for_each_entry(wssid_e, &neighbor->wssid, node) {
-                       if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) {
-                               result = wlp_enroll_neighbor(wlp, neighbor,
-                                                            wss, wssid);
-                               if (result == 0) /* enrollment success */
-                                       goto out;
-                               break;
-                       }
-               }
-       }
-out:
-       if (result == -ENXIO) {
-               wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-               dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf);
-       }
-       mutex_unlock(&wlp->nbmutex);
-       return result;
-}
-
-/**
- * Enroll into WSS with provided WSSID, registrar may be provided
- *
- * @wss: out WSS that will be enrolled
- * @wssid: wssid of neighboring WSS that we want to enroll in
- * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any
- *           neighbor can be used as registrar.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid,
-                  struct uwb_dev_addr *devaddr)
-{
-       int result;
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       char buf[WLP_WSS_UUID_STRSIZE];
-       struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
-
-       wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
-       if (wss->state != WLP_WSS_STATE_NONE) {
-               dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf);
-               result = -EEXIST;
-               goto error;
-       }
-       if (!memcmp(&bcast, devaddr, sizeof(bcast)))
-               result = wlp_wss_enroll_discovered(wss, wssid);
-       else
-               result = wlp_wss_enroll_target(wss, wssid, devaddr);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n",
-                       buf, result);
-               goto error;
-       }
-       dev_dbg(dev, "Successfully enrolled into WSS %s \n", buf);
-       result = wlp_wss_sysfs_add(wss, buf);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n");
-               wlp_wss_reset(wss);
-       }
-error:
-       return result;
-
-}
-
-/**
- * Activate given WSS
- *
- * Prior to activation a WSS must be enrolled. To activate a WSS a device
- * includes the WSS hash in the WLP IE in its beacon in each superframe.
- * WLP 0.99 [7.2.5].
- *
- * The WSS tag is also computed at this time. We only support one activated
- * WSS so we can use the hash as a tag - there will never be a conflict.
- *
- * We currently only support one activated WSS so only one WSS hash is
- * included in the WLP IE.
- */
-static
-int wlp_wss_activate(struct wlp_wss *wss)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct uwb_rc *uwb_rc = wlp->rc;
-       int result;
-       struct {
-               struct wlp_ie wlp_ie;
-               u8 hash; /* only include one hash */
-       } ie_data;
-
-       BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED);
-       wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid);
-       wss->tag = wss->hash;
-       memset(&ie_data, 0, sizeof(ie_data));
-       ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP;
-       ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr);
-       wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash));
-       ie_data.hash = wss->hash;
-       result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr,
-                              sizeof(ie_data));
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to add WLP IE to beacon. "
-                       "result = %d.\n", result);
-               goto error_wlp_ie;
-       }
-       wss->state = WLP_WSS_STATE_ACTIVE;
-       result = 0;
-error_wlp_ie:
-       return result;
-}
-
-/**
- * Enroll in and activate WSS identified by provided WSSID
- *
- * The neighborhood cache should contain a list of all neighbors and the
- * WSS they have activated. Based on that cache we search which neighbor we
- * can perform the association process with. The user also has option to
- * specify which neighbor it prefers as registrar.
- * Successful enrollment is followed by activation.
- * Successful activation will create the sysfs directory containing
- * specific information regarding this WSS.
- */
-int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
-                           struct uwb_dev_addr *devaddr)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-       char buf[WLP_WSS_UUID_STRSIZE];
-
-       mutex_lock(&wss->mutex);
-       result = wlp_wss_enroll(wss, wssid, devaddr);
-       if (result < 0) {
-               wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
-               dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf);
-               goto error_enroll;
-       }
-       result = wlp_wss_activate(wss);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment "
-                       "result = %d \n", result);
-               /* Undo enrollment */
-               wlp_wss_reset(wss);
-               goto error_activate;
-       }
-error_activate:
-error_enroll:
-       mutex_unlock(&wss->mutex);
-       return result;
-}
-
-/**
- * Create, enroll, and activate a new WSS
- *
- * @wssid: new wssid provided by user
- * @name:  WSS name requested by used.
- * @sec_status: security status requested by user
- *
- * A user requested the creation of a new WSS. All operations are done
- * locally. The new WSS will be stored locally, the hash will be included
- * in the WLP IE, and the sysfs infrastructure for this WSS will be
- * created.
- */
-int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
-                           char *name, unsigned sec_status, unsigned accept)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-       char buf[WLP_WSS_UUID_STRSIZE];
-
-       result = wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
-       if (!mutex_trylock(&wss->mutex)) {
-               dev_err(dev, "WLP: WLP association session in progress.\n");
-               return -EBUSY;
-       }
-       if (wss->state != WLP_WSS_STATE_NONE) {
-               dev_err(dev, "WLP: WSS already exists. Not creating new.\n");
-               result = -EEXIST;
-               goto out;
-       }
-       if (wss->kobj.parent == NULL) {
-               dev_err(dev, "WLP: WSS parent not ready. Is network interface "
-                      "up?\n");
-               result = -ENXIO;
-               goto out;
-       }
-       if (sec_status == WLP_WSS_SECURE) {
-               dev_err(dev, "WLP: FIXME Creation of secure WSS not "
-                       "supported yet.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       wss->wssid = *wssid;
-       memcpy(wss->name, name, sizeof(wss->name));
-       wss->bcast = wlp_wss_sel_bcast_addr(wss);
-       wss->secure_status = sec_status;
-       wss->accept_enroll = accept;
-       /*wss->virtual_addr is initialized in call to wlp_wss_setup*/
-       /* sysfs infrastructure */
-       result = wlp_wss_sysfs_add(wss, buf);
-       if (result < 0) {
-               dev_err(dev, "Cannot set up sysfs for WSS kobject.\n");
-               wlp_wss_reset(wss);
-               goto out;
-       } else
-               result = 0;
-       wss->state = WLP_WSS_STATE_ENROLLED;
-       result = wlp_wss_activate(wss);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to activate WSS. Undoing "
-                       "enrollment\n");
-               wlp_wss_reset(wss);
-               goto out;
-       }
-       result = 0;
-out:
-       mutex_unlock(&wss->mutex);
-       return result;
-}
-
-/**
- * Determine if neighbor has WSS activated
- *
- * @returns: 1 if neighbor has WSS activated, zero otherwise
- *
- * This can be done in two ways:
- * - send a C1 frame, parse C2/F0 response
- * - examine the WLP IE sent by the neighbor
- *
- * The WLP IE is not fully supported in hardware so we use the C1/C2 frame
- * exchange to determine if a WSS is activated. Using the WLP IE should be
- * faster and should be used when it becomes possible.
- */
-int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss,
-                     struct uwb_dev_addr *dev_addr)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       DECLARE_COMPLETION_ONSTACK(completion);
-       struct wlp_session session;
-       struct sk_buff  *skb;
-       struct wlp_frame_assoc *resp;
-       struct wlp_uuid wssid;
-
-       mutex_lock(&wlp->mutex);
-       /* Send C1 association frame */
-       result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1);
-       if (result < 0) {
-               dev_err(dev, "Unable to send C1 frame to neighbor "
-                       "%02x:%02x (%d)\n", dev_addr->data[1],
-                       dev_addr->data[0], result);
-               result = 0;
-               goto out;
-       }
-       /* Create session, wait for response */
-       session.exp_message = WLP_ASSOC_C2;
-       session.cb = wlp_session_cb;
-       session.cb_priv = &completion;
-       session.neighbor_addr = *dev_addr;
-       BUG_ON(wlp->session != NULL);
-       wlp->session = &session;
-       /* Wait for C2/F0 frame */
-       result = wait_for_completion_interruptible_timeout(&completion,
-                                                  WLP_PER_MSG_TIMEOUT * HZ);
-       if (result == 0) {
-               dev_err(dev, "Timeout while sending C1 to neighbor "
-                            "%02x:%02x.\n", dev_addr->data[1],
-                            dev_addr->data[0]);
-               goto out;
-       }
-       if (result < 0) {
-               dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n",
-                       dev_addr->data[1], dev_addr->data[0]);
-               result = 0;
-               goto out;
-       }
-       /* Parse message in session->data: it will be either C2 or F0 */
-       skb = session.data;
-       resp = (void *) skb->data;
-       if (resp->type == WLP_ASSOC_F0) {
-               result = wlp_parse_f0(wlp, skb);
-               if (result < 0)
-                       dev_err(dev, "WLP:  unable to parse incoming F0 "
-                               "frame from neighbor %02x:%02x.\n",
-                               dev_addr->data[1], dev_addr->data[0]);
-               result = 0;
-               goto error_resp_parse;
-       }
-       /* WLP version and message type fields have already been parsed */
-       result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid,
-                              skb->len - sizeof(*resp));
-       if (result < 0) {
-               dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n");
-               result = 0;
-               goto error_resp_parse;
-       }
-       if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)))
-               result = 1;
-       else {
-               dev_err(dev, "WLP: Received a C2 frame without matching "
-                       "WSSID.\n");
-               result = 0;
-       }
-error_resp_parse:
-       kfree_skb(skb);
-out:
-       wlp->session = NULL;
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-
-/**
- * Activate connection with neighbor by updating EDA cache
- *
- * @wss:       local WSS to which neighbor wants to connect
- * @dev_addr:  neighbor's address
- * @wssid:     neighbor's WSSID - must be same as our WSS's WSSID
- * @tag:       neighbor's WSS tag used to identify frames transmitted by it
- * @virt_addr: neighbor's virtual EUI-48
- */
-static
-int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss,
-                               struct uwb_dev_addr *dev_addr,
-                               struct wlp_uuid *wssid, u8 *tag,
-                               struct uwb_mac_addr *virt_addr)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-
-       if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) {
-               /* Update EDA cache */
-               result = wlp_eda_update_node(&wlp->eda, dev_addr, wss,
-                                            (void *) virt_addr->data, *tag,
-                                            WLP_WSS_CONNECTED);
-               if (result < 0)
-                       dev_err(dev, "WLP: Unable to update EDA cache "
-                               "with new connected neighbor information.\n");
-       } else {
-               dev_err(dev, "WLP: Neighbor does not have matching WSSID.\n");
-               result = -EINVAL;
-       }
-       return result;
-}
-
-/**
- * Connect to WSS neighbor
- *
- * Use C3/C4 exchange to determine if neighbor has WSS activated and
- * retrieve the WSS tag and virtual EUI-48 of the neighbor.
- */
-static
-int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss,
-                            struct uwb_dev_addr *dev_addr)
-{
-       int result;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_uuid wssid;
-       u8 tag;
-       struct uwb_mac_addr virt_addr;
-       DECLARE_COMPLETION_ONSTACK(completion);
-       struct wlp_session session;
-       struct wlp_frame_assoc *resp;
-       struct sk_buff *skb;
-
-       mutex_lock(&wlp->mutex);
-       /* Send C3 association frame */
-       result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3);
-       if (result < 0) {
-               dev_err(dev, "Unable to send C3 frame to neighbor "
-                       "%02x:%02x (%d)\n", dev_addr->data[1],
-                       dev_addr->data[0], result);
-               goto out;
-       }
-       /* Create session, wait for response */
-       session.exp_message = WLP_ASSOC_C4;
-       session.cb = wlp_session_cb;
-       session.cb_priv = &completion;
-       session.neighbor_addr = *dev_addr;
-       BUG_ON(wlp->session != NULL);
-       wlp->session = &session;
-       /* Wait for C4/F0 frame */
-       result = wait_for_completion_interruptible_timeout(&completion,
-                                                  WLP_PER_MSG_TIMEOUT * HZ);
-       if (result == 0) {
-               dev_err(dev, "Timeout while sending C3 to neighbor "
-                            "%02x:%02x.\n", dev_addr->data[1],
-                            dev_addr->data[0]);
-               result = -ETIMEDOUT;
-               goto out;
-       }
-       if (result < 0) {
-               dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n",
-                       dev_addr->data[1], dev_addr->data[0]);
-               goto out;
-       }
-       /* Parse message in session->data: it will be either C4 or F0 */
-       skb = session.data;
-       resp = (void *) skb->data;
-       if (resp->type == WLP_ASSOC_F0) {
-               result = wlp_parse_f0(wlp, skb);
-               if (result < 0)
-                       dev_err(dev, "WLP: unable to parse incoming F0 "
-                               "frame from neighbor %02x:%02x.\n",
-                               dev_addr->data[1], dev_addr->data[0]);
-               result = -EINVAL;
-               goto error_resp_parse;
-       }
-       result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n");
-               goto error_resp_parse;
-       }
-       result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag,
-                                            &virt_addr);
-       if (result < 0) {
-               dev_err(dev, "WLP: Unable to activate connection to "
-                       "neighbor %02x:%02x.\n", dev_addr->data[1],
-                       dev_addr->data[0]);
-               goto error_resp_parse;
-       }
-error_resp_parse:
-       kfree_skb(skb);
-out:
-       /* Record that we unsuccessfully tried to connect to this neighbor */
-       if (result < 0)
-               wlp_eda_update_node_state(&wlp->eda, dev_addr,
-                                         WLP_WSS_CONNECT_FAILED);
-       wlp->session = NULL;
-       mutex_unlock(&wlp->mutex);
-       return result;
-}
-
-/**
- * Connect to neighbor with common WSS, send pending frame
- *
- * This function is scheduled when a frame is destined to a neighbor with
- * which we do not have a connection. A copy of the EDA cache entry is
- * provided - not the actual cache entry (because it is protected by a
- * spinlock).
- *
- * First determine if neighbor has the same WSS activated, connect if it
- * does. The C3/C4 exchange is dual purpose to determine if neighbor has
- * WSS activated and proceed with the connection.
- *
- * The frame that triggered the connection setup is sent after connection
- * setup.
- *
- * network queue is stopped - we need to restart when done
- *
- */
-static
-void wlp_wss_connect_send(struct work_struct *ws)
-{
-       struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws,
-                                                 struct wlp_assoc_conn_ctx,
-                                                 ws);
-       struct wlp *wlp = conn_ctx->wlp;
-       struct sk_buff *skb = conn_ctx->skb;
-       struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry;
-       struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
-       struct wlp_wss *wss = &wlp->wss;
-       int result;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-
-       mutex_lock(&wss->mutex);
-       if (wss->state < WLP_WSS_STATE_ACTIVE) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Attempting to connect with "
-                               "WSS that is not active or connected.\n");
-               dev_kfree_skb(skb);
-               goto out;
-       }
-       /* Establish connection - send C3 rcv C4 */
-       result = wlp_wss_connect_neighbor(wlp, wss, dev_addr);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to establish connection "
-                               "with neighbor %02x:%02x.\n",
-                               dev_addr->data[1], dev_addr->data[0]);
-               dev_kfree_skb(skb);
-               goto out;
-       }
-       /* EDA entry changed, update the local copy being used */
-       result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Cannot find EDA entry for "
-                               "neighbor %02x:%02x \n",
-                               dev_addr->data[1], dev_addr->data[0]);
-       }
-       result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to prepare frame header for "
-                               "transmission (neighbor %02x:%02x). \n",
-                               dev_addr->data[1], dev_addr->data[0]);
-               dev_kfree_skb(skb);
-               goto out;
-       }
-       BUG_ON(wlp->xmit_frame == NULL);
-       result = wlp->xmit_frame(wlp, skb, dev_addr);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to transmit frame: %d\n",
-                               result);
-               if (result == -ENXIO)
-                       dev_err(dev, "WLP: Is network interface up? \n");
-               /* We could try again ... */
-               dev_kfree_skb(skb);/*we need to free if tx fails */
-       }
-out:
-       kfree(conn_ctx);
-       BUG_ON(wlp->start_queue == NULL);
-       wlp->start_queue(wlp);
-       mutex_unlock(&wss->mutex);
-}
-
-/**
- * Add WLP header to outgoing skb
- *
- * @eda_entry: pointer to neighbor's entry in the EDA cache
- * @_skb:      skb containing data destined to the neighbor
- */
-int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry,
-                    void *_skb)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-       unsigned char *eth_addr = eda_entry->eth_addr;
-       struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
-       struct sk_buff *skb = _skb;
-       struct wlp_frame_std_abbrv_hdr *std_hdr;
-
-       if (eda_entry->state == WLP_WSS_CONNECTED) {
-               /* Add WLP header */
-               BUG_ON(skb_headroom(skb) < sizeof(*std_hdr));
-               std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr));
-               std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
-               std_hdr->hdr.type = WLP_FRAME_STANDARD;
-               std_hdr->tag = eda_entry->wss->tag;
-       } else {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Destination neighbor (Ethernet: "
-                               "%pM, Dev: %02x:%02x) is not connected.\n",
-                               eth_addr, dev_addr->data[1], dev_addr->data[0]);
-               result = -EINVAL;
-       }
-       return result;
-}
-
-
-/**
- * Prepare skb for neighbor: connect if not already and prep WLP header
- *
- * This function is called in interrupt context, but it needs to sleep. We
- * temporarily stop the net queue to establish the WLP connection.
- * Setup of the WLP connection and restart of queue is scheduled
- * on the default work queue.
- *
- * run with eda->lock held (spinlock)
- */
-int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry,
-                        void *_skb)
-{
-       int result = 0;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct sk_buff *skb = _skb;
-       struct wlp_assoc_conn_ctx *conn_ctx;
-
-       if (eda_entry->state == WLP_WSS_UNCONNECTED) {
-               /* We don't want any more packets while we set up connection */
-               BUG_ON(wlp->stop_queue == NULL);
-               wlp->stop_queue(wlp);
-               conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC);
-               if (conn_ctx == NULL) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "WLP: Unable to allocate memory "
-                                       "for connection handling.\n");
-                       result = -ENOMEM;
-                       goto out;
-               }
-               conn_ctx->wlp = wlp;
-               conn_ctx->skb = skb;
-               conn_ctx->eda_entry = *eda_entry;
-               INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send);
-               schedule_work(&conn_ctx->ws);
-               result = 1;
-       } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) {
-               /* Previous connection attempts failed, don't retry - see
-                * conditions for connection in WLP 0.99 [7.6.2] */
-               if (printk_ratelimit())
-                       dev_err(dev, "Could not connect to neighbor "
-                        "previously. Not retrying. \n");
-               result = -ENONET;
-               goto out;
-       } else /* eda_entry->state == WLP_WSS_CONNECTED */
-               result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
-out:
-       return result;
-}
-
-/**
- * Emulate broadcast: copy skb, send copy to neighbor (connect if not already)
- *
- * We need to copy skbs in the case where we emulate broadcast through
- * unicast. We copy instead of clone because we are modifying the data of
- * the frame after copying ... clones share data so we cannot emulate
- * broadcast using clones.
- *
- * run with eda->lock held (spinlock)
- */
-int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry,
-                     void *_skb)
-{
-       int result = -ENOMEM;
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct sk_buff *skb = _skb;
-       struct sk_buff *copy;
-       struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
-
-       copy = skb_copy(skb, GFP_ATOMIC);
-       if (copy == NULL) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to copy skb for "
-                               "transmission.\n");
-               goto out;
-       }
-       result = wlp_wss_connect_prep(wlp, eda_entry, copy);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to connect/send skb "
-                               "to neighbor.\n");
-               dev_kfree_skb_irq(copy);
-               goto out;
-       } else if (result == 1)
-               /* Frame will be transmitted separately */
-               goto out;
-       BUG_ON(wlp->xmit_frame == NULL);
-       result = wlp->xmit_frame(wlp, copy, dev_addr);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Unable to transmit frame: %d\n",
-                               result);
-               if ((result == -ENXIO) && printk_ratelimit())
-                       dev_err(dev, "WLP: Is network interface up? \n");
-               /* We could try again ... */
-               dev_kfree_skb_irq(copy);/*we need to free if tx fails */
-       }
-out:
-       return result;
-}
-
-
-/**
- * Setup WSS
- *
- * Should be called by network driver after the interface has been given a
- * MAC address.
- */
-int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = 0;
-
-       mutex_lock(&wss->mutex);
-       wss->kobj.parent = &net_dev->dev.kobj;
-       if (!is_valid_ether_addr(net_dev->dev_addr)) {
-               dev_err(dev, "WLP: Invalid MAC address. Cannot use for"
-                      "virtual.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       memcpy(wss->virtual_addr.data, net_dev->dev_addr,
-              sizeof(wss->virtual_addr.data));
-out:
-       mutex_unlock(&wss->mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_wss_setup);
-
-/**
- * Remove WSS
- *
- * Called by client that configured WSS through wlp_wss_setup(). This
- * function is called when client no longer needs WSS, eg. client shuts
- * down.
- *
- * We remove the WLP IE from the beacon before initiating local cleanup.
- */
-void wlp_wss_remove(struct wlp_wss *wss)
-{
-       struct wlp *wlp = container_of(wss, struct wlp, wss);
-
-       mutex_lock(&wss->mutex);
-       if (wss->state == WLP_WSS_STATE_ACTIVE)
-               uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP);
-       if (wss->state != WLP_WSS_STATE_NONE) {
-               sysfs_remove_group(&wss->kobj, &wss_attr_group);
-               kobject_put(&wss->kobj);
-       }
-       wss->kobj.parent = NULL;
-       memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr));
-       /* Cleanup EDA cache */
-       wlp_eda_release(&wlp->eda);
-       wlp_eda_init(&wlp->eda);
-       mutex_unlock(&wss->mutex);
-}
-EXPORT_SYMBOL_GPL(wlp_wss_remove);
index dc06ff13455921f2d23748be845d6b51e3a92309..27c1fb4b1e0d71f91dcdd7d528dafa3b3457cb32 100644 (file)
@@ -17,6 +17,8 @@ source "drivers/gpu/vga/Kconfig"
 
 source "drivers/gpu/drm/Kconfig"
 
+source "drivers/gpu/stub/Kconfig"
+
 config VGASTATE
        tristate
        default n
@@ -1919,6 +1921,9 @@ config FB_SH_MOBILE_HDMI
        tristate "SuperH Mobile HDMI controller support"
        depends on FB_SH_MOBILE_LCDC
        select FB_MODE_HELPERS
+       select SOUND
+       select SND
+       select SND_SOC
        ---help---
          Driver for the on-chip SH-Mobile HDMI controller.
 
index f8d69ad36830310e1d9c49332d3835dcdb102c3a..5bf91236c70149f4050622e2c96677093c4eb45d 100644 (file)
@@ -2970,7 +2970,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
        struct atyfb_par *par = info->par;
        struct device_node *dp;
        char prop[128];
-       int node, len, i, j, ret;
+       phandle node;
+       int len, i, j, ret;
        u32 mem, chip_id;
 
        /*
index e77e8e4280fb4005854f68c5450031d4764b040b..4ea187d937681ae154eeaef876675dbf9fd5622c 100644 (file)
@@ -1079,7 +1079,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
         * clock can only be obtain by dividing this value by an even integer.
         * Fallback to a slower pixel clock if necessary. */
        pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
-       pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+       pixclock = min3(pixclock, fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2);
 
        if (AU1200_LCD_MAX_CLK % pixclock) {
                int diff = AU1200_LCD_MAX_CLK % pixclock;
index ca75cc2a87a559df36b93bbd4f495a7b013577ac..d7c6c3e0afc620ffd89a2fccdac5e7169c8c57e9 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl.h>
 
-#include <plat/mux.h>
-#include <plat/mux.h>
 #include <asm/mach-types.h>
 
 #include "omapfb.h"
index 881c9f77c75a58c4cce4016bb405794d3d922fa9..12327bbfdbbba94118597ba73a3df7bc360884c9 100644 (file)
@@ -40,7 +40,7 @@ config PANEL_TPO_TD043MTEA1
 
 config PANEL_ACX565AKM
        tristate "ACX565AKM Panel"
-       depends on OMAP2_DSS_SDI
+       depends on OMAP2_DSS_SDI && SPI
        select BACKLIGHT_CLASS_DEVICE
        help
          This is the LCD panel used on Nokia N900
index 07fbb8a733bb5ecd46c569e56d5ebe0c99714e61..e77310653207c1c8202c0bbabddc692c6df4f2b6 100644 (file)
@@ -587,6 +587,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
 
        dev_dbg(&dssdev->dev, "%s\n", __func__);
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        mutex_lock(&md->mutex);
 
        r = omapdss_sdi_display_enable(dssdev);
@@ -644,6 +647,9 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev)
 
        dev_dbg(&dssdev->dev, "%s\n", __func__);
 
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        mutex_lock(&md->mutex);
 
        if (!md->enabled) {
index 300eff5de1b4830490e6a5f36d48adf8b63a5b1e..395a68de399048f90b388b64416531695a07e223 100644 (file)
@@ -39,6 +39,9 @@ static int generic_panel_power_on(struct omap_dss_device *dssdev)
 {
        int r;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        r = omapdss_dpi_display_enable(dssdev);
        if (r)
                goto err0;
@@ -58,6 +61,9 @@ err0:
 
 static void generic_panel_power_off(struct omap_dss_device *dssdev)
 {
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
 
index 10267461991cde20a8a282099f89efe50df7adc3..0c6896cea2d0a2d01e593209b201d4d3a44555a5 100644 (file)
@@ -43,6 +43,9 @@ static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
 {
        int r;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        r = omapdss_dpi_display_enable(dssdev);
        if (r)
                goto err0;
@@ -65,6 +68,9 @@ err0:
 
 static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
 {
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
 
index 7d9eb2b1f5af39c8ad9433435c5ed3bb0315ffd6..9a138f650e0567e9e9f60118648fcd39543e06f6 100644 (file)
@@ -135,6 +135,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
 {
        int r = 0;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        r = omapdss_dpi_display_enable(dssdev);
        if (r)
                goto err0;
@@ -157,6 +160,9 @@ err0:
 
 static void sharp_ls_power_off(struct omap_dss_device *dssdev)
 {
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
 
index e320e67d06f3e80cec9bd8f5008d7eb7a07b3b9c..526e906c8a6c65ab4670308ff109a01a69473899 100644 (file)
@@ -46,6 +46,9 @@ static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
 {
        int r;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        r = omapdss_dpi_display_enable(dssdev);
        if (r)
                goto err0;
@@ -65,6 +68,9 @@ err0:
 
 static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
 {
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
 
index e866e76b13d02bfc746656c33d1167d94d7d84fb..dbe9d43b4850d80c7218719528ce3c57c473b944 100644 (file)
@@ -269,6 +269,9 @@ static int tpo_td043_power_on(struct omap_dss_device *dssdev)
        int nreset_gpio = dssdev->reset_gpio;
        int r;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
        r = omapdss_dpi_display_enable(dssdev);
        if (r)
                goto err0;
@@ -308,6 +311,9 @@ static void tpo_td043_power_off(struct omap_dss_device *dssdev)
        struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
        int nreset_gpio = dssdev->reset_gpio;
 
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
        tpo_td043_write(tpo_td043->spi, 3,
                        TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
 
index d71b5d9d71b15890d063e12d484066d7e27e095c..7db17b5e570c43c17afde3b01681c167c20b012c 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o
 omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
 omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
 omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
index b3a498f22d3625896db0b1dd8cdd9929ae938cea..8e89f604928098306485494ca829a7b11c42d0c3 100644 (file)
@@ -37,6 +37,7 @@
 #include <plat/clock.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 static struct {
        struct platform_device *pdev;
@@ -502,6 +503,8 @@ static int omap_dss_probe(struct platform_device *pdev)
 
        core.pdev = pdev;
 
+       dss_features_init();
+
        dss_init_overlay_managers(pdev);
        dss_init_overlays(pdev);
 
index 5ecdc000409429f385657c06271426296019e157..fa40fa59a9acf9c89b2b4b562472871dfd0a1a2f 100644 (file)
@@ -39,6 +39,7 @@
 #include <plat/display.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 /* DISPC */
 #define DISPC_BASE                     0x48050400
@@ -139,6 +140,22 @@ struct omap_dispc_isr_data {
        u32                     mask;
 };
 
+struct dispc_h_coef {
+       s8 hc4;
+       s8 hc3;
+       u8 hc2;
+       s8 hc1;
+       s8 hc0;
+};
+
+struct dispc_v_coef {
+       s8 vc22;
+       s8 vc2;
+       u8 vc1;
+       s8 vc0;
+       s8 vc00;
+};
+
 #define REG_GET(idx, start, end) \
        FLD_GET(dispc_read_reg(idx), start, end)
 
@@ -564,106 +581,77 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                int vscaleup, int five_taps)
 {
        /* Coefficients for horizontal up-sampling */
-       static const u32 coef_hup[8] = {
-               0x00800000,
-               0x0D7CF800,
-               0x1E70F5FF,
-               0x335FF5FE,
-               0xF74949F7,
-               0xF55F33FB,
-               0xF5701EFE,
-               0xF87C0DFF,
+       static const struct dispc_h_coef coef_hup[8] = {
+               {  0,   0, 128,   0,  0 },
+               { -1,  13, 124,  -8,  0 },
+               { -2,  30, 112, -11, -1 },
+               { -5,  51,  95, -11, -2 },
+               {  0,  -9,  73,  73, -9 },
+               { -2, -11,  95,  51, -5 },
+               { -1, -11, 112,  30, -2 },
+               {  0,  -8, 124,  13, -1 },
        };
 
-       /* Coefficients for horizontal down-sampling */
-       static const u32 coef_hdown[8] = {
-               0x24382400,
-               0x28371FFE,
-               0x2C361BFB,
-               0x303516F9,
-               0x11343311,
-               0x1635300C,
-               0x1B362C08,
-               0x1F372804,
+       /* Coefficients for vertical up-sampling */
+       static const struct dispc_v_coef coef_vup_3tap[8] = {
+               { 0,  0, 128,  0, 0 },
+               { 0,  3, 123,  2, 0 },
+               { 0, 12, 111,  5, 0 },
+               { 0, 32,  89,  7, 0 },
+               { 0,  0,  64, 64, 0 },
+               { 0,  7,  89, 32, 0 },
+               { 0,  5, 111, 12, 0 },
+               { 0,  2, 123,  3, 0 },
        };
 
-       /* Coefficients for horizontal and vertical up-sampling */
-       static const u32 coef_hvup[2][8] = {
-               {
-               0x00800000,
-               0x037B02FF,
-               0x0C6F05FE,
-               0x205907FB,
-               0x00404000,
-               0x075920FE,
-               0x056F0CFF,
-               0x027B0300,
-               },
-               {
-               0x00800000,
-               0x0D7CF8FF,
-               0x1E70F5FE,
-               0x335FF5FB,
-               0xF7404000,
-               0xF55F33FE,
-               0xF5701EFF,
-               0xF87C0D00,
-               },
+       static const struct dispc_v_coef coef_vup_5tap[8] = {
+               {  0,   0, 128,   0,  0 },
+               { -1,  13, 124,  -8,  0 },
+               { -2,  30, 112, -11, -1 },
+               { -5,  51,  95, -11, -2 },
+               {  0,  -9,  73,  73, -9 },
+               { -2, -11,  95,  51, -5 },
+               { -1, -11, 112,  30, -2 },
+               {  0,  -8, 124,  13, -1 },
        };
 
-       /* Coefficients for horizontal and vertical down-sampling */
-       static const u32 coef_hvdown[2][8] = {
-               {
-               0x24382400,
-               0x28391F04,
-               0x2D381B08,
-               0x3237170C,
-               0x123737F7,
-               0x173732F9,
-               0x1B382DFB,
-               0x1F3928FE,
-               },
-               {
-               0x24382400,
-               0x28371F04,
-               0x2C361B08,
-               0x3035160C,
-               0x113433F7,
-               0x163530F9,
-               0x1B362CFB,
-               0x1F3728FE,
-               },
+       /* Coefficients for horizontal down-sampling */
+       static const struct dispc_h_coef coef_hdown[8] = {
+               {   0, 36, 56, 36,  0 },
+               {   4, 40, 55, 31, -2 },
+               {   8, 44, 54, 27, -5 },
+               {  12, 48, 53, 22, -7 },
+               {  -9, 17, 52, 51, 17 },
+               {  -7, 22, 53, 48, 12 },
+               {  -5, 27, 54, 44,  8 },
+               {  -2, 31, 55, 40,  4 },
        };
 
-       /* Coefficients for vertical up-sampling */
-       static const u32 coef_vup[8] = {
-               0x00000000,
-               0x0000FF00,
-               0x0000FEFF,
-               0x0000FBFE,
-               0x000000F7,
-               0x0000FEFB,
-               0x0000FFFE,
-               0x000000FF,
+       /* Coefficients for vertical down-sampling */
+       static const struct dispc_v_coef coef_vdown_3tap[8] = {
+               { 0, 36, 56, 36, 0 },
+               { 0, 40, 57, 31, 0 },
+               { 0, 45, 56, 27, 0 },
+               { 0, 50, 55, 23, 0 },
+               { 0, 18, 55, 55, 0 },
+               { 0, 23, 55, 50, 0 },
+               { 0, 27, 56, 45, 0 },
+               { 0, 31, 57, 40, 0 },
        };
 
-
-       /* Coefficients for vertical down-sampling */
-       static const u32 coef_vdown[8] = {
-               0x00000000,
-               0x000004FE,
-               0x000008FB,
-               0x00000CF9,
-               0x0000F711,
-               0x0000F90C,
-               0x0000FB08,
-               0x0000FE04,
+       static const struct dispc_v_coef coef_vdown_5tap[8] = {
+               {   0, 36, 56, 36,  0 },
+               {   4, 40, 55, 31, -2 },
+               {   8, 44, 54, 27, -5 },
+               {  12, 48, 53, 22, -7 },
+               {  -9, 17, 52, 51, 17 },
+               {  -7, 22, 53, 48, 12 },
+               {  -5, 27, 54, 44,  8 },
+               {  -2, 31, 55, 40,  4 },
        };
 
-       const u32 *h_coef;
-       const u32 *hv_coef;
-       const u32 *hv_coef_mod;
-       const u32 *v_coef;
+       const struct dispc_h_coef *h_coef;
+       const struct dispc_v_coef *v_coef;
        int i;
 
        if (hscaleup)
@@ -671,47 +659,34 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
        else
                h_coef = coef_hdown;
 
-       if (vscaleup) {
-               hv_coef = coef_hvup[five_taps];
-               v_coef = coef_vup;
-
-               if (hscaleup)
-                       hv_coef_mod = NULL;
-               else
-                       hv_coef_mod = coef_hvdown[five_taps];
-       } else {
-               hv_coef = coef_hvdown[five_taps];
-               v_coef = coef_vdown;
-
-               if (hscaleup)
-                       hv_coef_mod = coef_hvup[five_taps];
-               else
-                       hv_coef_mod = NULL;
-       }
+       if (vscaleup)
+               v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
+       else
+               v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
 
        for (i = 0; i < 8; i++) {
                u32 h, hv;
 
-               h = h_coef[i];
-
-               hv = hv_coef[i];
-
-               if (hv_coef_mod) {
-                       hv &= 0xffffff00;
-                       hv |= (hv_coef_mod[i] & 0xff);
-               }
+               h = FLD_VAL(h_coef[i].hc0, 7, 0)
+                       | FLD_VAL(h_coef[i].hc1, 15, 8)
+                       | FLD_VAL(h_coef[i].hc2, 23, 16)
+                       | FLD_VAL(h_coef[i].hc3, 31, 24);
+               hv = FLD_VAL(h_coef[i].hc4, 7, 0)
+                       | FLD_VAL(v_coef[i].vc0, 15, 8)
+                       | FLD_VAL(v_coef[i].vc1, 23, 16)
+                       | FLD_VAL(v_coef[i].vc2, 31, 24);
 
                _dispc_write_firh_reg(plane, i, h);
                _dispc_write_firhv_reg(plane, i, hv);
        }
 
-       if (!five_taps)
-               return;
-
-       for (i = 0; i < 8; i++) {
-               u32 v;
-               v = v_coef[i];
-               _dispc_write_firv_reg(plane, i, v);
+       if (five_taps) {
+               for (i = 0; i < 8; i++) {
+                       u32 v;
+                       v = FLD_VAL(v_coef[i].vc00, 7, 0)
+                               | FLD_VAL(v_coef[i].vc22, 15, 8);
+                       _dispc_write_firv_reg(plane, i, v);
+               }
        }
 }
 
@@ -800,12 +775,12 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
 
 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
 {
-
-       BUG_ON(plane == OMAP_DSS_VIDEO1);
-
-       if (cpu_is_omap24xx())
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return;
 
+       BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+                       plane == OMAP_DSS_VIDEO1);
+
        if (plane == OMAP_DSS_GFX)
                REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
        else if (plane == OMAP_DSS_VIDEO2)
@@ -975,17 +950,14 @@ static void dispc_read_plane_fifo_sizes(void)
                                      DISPC_VID_FIFO_SIZE_STATUS(1) };
        u32 size;
        int plane;
+       u8 start, end;
 
        enable_clocks(1);
 
-       for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
-               if (cpu_is_omap24xx())
-                       size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
-               else if (cpu_is_omap34xx())
-                       size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
-               else
-                       BUG();
+       dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
+       for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
+               size = FLD_GET(dispc_read_reg(fsz_reg[plane]), start, end);
                dispc.fifo_size[plane] = size;
        }
 
@@ -1002,6 +974,8 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
        const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
                                       DISPC_VID_FIFO_THRESHOLD(0),
                                       DISPC_VID_FIFO_THRESHOLD(1) };
+       u8 hi_start, hi_end, lo_start, lo_end;
+
        enable_clocks(1);
 
        DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
@@ -1010,12 +984,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
                        REG_GET(ftrs_reg[plane], 27, 16),
                        low, high);
 
-       if (cpu_is_omap24xx())
-               dispc_write_reg(ftrs_reg[plane],
-                               FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
-       else
-               dispc_write_reg(ftrs_reg[plane],
-                               FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
+       dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
+       dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
+
+       dispc_write_reg(ftrs_reg[plane],
+                       FLD_VAL(high, hi_start, hi_end) |
+                       FLD_VAL(low, lo_start, lo_end));
 
        enable_clocks(0);
 }
@@ -1035,13 +1009,16 @@ static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
        u32 val;
        const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
                                      DISPC_VID_FIR(1) };
+       u8 hinc_start, hinc_end, vinc_start, vinc_end;
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       if (cpu_is_omap24xx())
-               val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
-       else
-               val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+       dss_feat_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end);
+       dss_feat_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end);
+
+       val = FLD_VAL(vinc, vinc_start, vinc_end) |
+                       FLD_VAL(hinc, hinc_start, hinc_end);
+
        dispc_write_reg(fir_reg[plane-1], val);
 }
 
@@ -1567,6 +1544,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
                case OMAP_DSS_COLOR_ARGB16:
                case OMAP_DSS_COLOR_ARGB32:
                case OMAP_DSS_COLOR_RGBA32:
+                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+                               return -EINVAL;
                case OMAP_DSS_COLOR_RGBX32:
                        if (cpu_is_omap24xx())
                                return -EINVAL;
@@ -1607,9 +1586,10 @@ static int _dispc_setup_plane(enum omap_plane plane,
                case OMAP_DSS_COLOR_ARGB16:
                case OMAP_DSS_COLOR_ARGB32:
                case OMAP_DSS_COLOR_RGBA32:
-                       if (cpu_is_omap24xx())
+                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                                return -EINVAL;
-                       if (plane == OMAP_DSS_VIDEO1)
+                       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+                                       plane == OMAP_DSS_VIDEO1)
                                return -EINVAL;
                        break;
 
@@ -2002,7 +1982,7 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
 }
 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
 {
-       if (cpu_is_omap24xx())
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return;
 
        enable_clocks(1);
@@ -2016,7 +1996,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
 {
        bool enabled;
 
-       if (cpu_is_omap24xx())
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return false;
 
        enable_clocks(1);
index b3fa3a7db911f40042dacc86fa025b42f6eabc1c..aa4f7a5fae29fca001d297d31982ae1f5b88f46c 100644 (file)
@@ -3274,7 +3274,6 @@ int dsi_init(struct platform_device *pdev)
 
        dsi.vdds_dsi_reg = dss_get_vdds_dsi();
        if (IS_ERR(dsi.vdds_dsi_reg)) {
-               iounmap(dsi.base);
                DSSERR("can't get VDDS_DSI regulator\n");
                r = PTR_ERR(dsi.vdds_dsi_reg);
                goto err2;
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
new file mode 100644 (file)
index 0000000..867f68d
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.c
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <plat/display.h>
+#include <plat/cpu.h>
+
+#include "dss_features.h"
+
+/* Defines a generic omap register field */
+struct dss_reg_field {
+       enum dss_feat_reg_field id;
+       u8 start, end;
+};
+
+struct omap_dss_features {
+       const struct dss_reg_field *reg_fields;
+       const int num_reg_fields;
+
+       const u32 has_feature;
+
+       const int num_mgrs;
+       const int num_ovls;
+       const enum omap_display_type *supported_displays;
+       const enum omap_color_mode *supported_color_modes;
+};
+
+/* This struct is assigned to one of the below during initialization */
+static struct omap_dss_features *omap_current_dss_features;
+
+static const struct dss_reg_field omap2_dss_reg_fields[] = {
+       { FEAT_REG_FIRHINC, 11, 0 },
+       { FEAT_REG_FIRVINC, 27, 16 },
+       { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 },
+       { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 },
+       { FEAT_REG_FIFOSIZE, 8, 0 },
+};
+
+static const struct dss_reg_field omap3_dss_reg_fields[] = {
+       { FEAT_REG_FIRHINC, 12, 0 },
+       { FEAT_REG_FIRVINC, 28, 16 },
+       { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 },
+       { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 },
+       { FEAT_REG_FIFOSIZE, 10, 0 },
+};
+
+static const enum omap_display_type omap2_dss_supported_displays[] = {
+       /* OMAP_DSS_CHANNEL_LCD */
+       OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+       OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+
+       /* OMAP_DSS_CHANNEL_DIGIT */
+       OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3_dss_supported_displays[] = {
+       /* OMAP_DSS_CHANNEL_LCD */
+       OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+       OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+
+       /* OMAP_DSS_CHANNEL_DIGIT */
+       OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+       OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+       OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+       OMAP_DSS_COLOR_UYVY,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+       OMAP_DSS_COLOR_UYVY,
+};
+
+static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+       OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+       OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+};
+
+/* OMAP2 DSS Features */
+static struct omap_dss_features omap2_dss_features = {
+       .reg_fields = omap2_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
+
+       .num_mgrs = 2,
+       .num_ovls = 3,
+       .supported_displays = omap2_dss_supported_displays,
+       .supported_color_modes = omap2_dss_supported_color_modes,
+};
+
+/* OMAP3 DSS Features */
+static struct omap_dss_features omap3_dss_features = {
+       .reg_fields = omap3_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+       .has_feature    = FEAT_GLOBAL_ALPHA,
+
+       .num_mgrs = 2,
+       .num_ovls = 3,
+       .supported_displays = omap3_dss_supported_displays,
+       .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
+/* Functions returning values related to a DSS feature */
+int dss_feat_get_num_mgrs(void)
+{
+       return omap_current_dss_features->num_mgrs;
+}
+
+int dss_feat_get_num_ovls(void)
+{
+       return omap_current_dss_features->num_ovls;
+}
+
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
+{
+       return omap_current_dss_features->supported_displays[channel];
+}
+
+enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
+{
+       return omap_current_dss_features->supported_color_modes[plane];
+}
+
+/* DSS has_feature check */
+bool dss_has_feature(enum dss_feat_id id)
+{
+       return omap_current_dss_features->has_feature & id;
+}
+
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
+{
+       if (id >= omap_current_dss_features->num_reg_fields)
+               BUG();
+
+       *start = omap_current_dss_features->reg_fields[id].start;
+       *end = omap_current_dss_features->reg_fields[id].end;
+}
+
+void dss_features_init(void)
+{
+       if (cpu_is_omap24xx())
+               omap_current_dss_features = &omap2_dss_features;
+       else
+               omap_current_dss_features = &omap3_dss_features;
+}
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
new file mode 100644 (file)
index 0000000..cb231ea
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DSS_FEATURES_H
+#define __OMAP2_DSS_FEATURES_H
+
+#define MAX_DSS_MANAGERS       2
+#define MAX_DSS_OVERLAYS       3
+
+/* DSS has feature id */
+enum dss_feat_id {
+       FEAT_GLOBAL_ALPHA       = 1 << 0,
+       FEAT_GLOBAL_ALPHA_VID1  = 1 << 1,
+};
+
+/* DSS register field id */
+enum dss_feat_reg_field {
+       FEAT_REG_FIRHINC,
+       FEAT_REG_FIRVINC,
+       FEAT_REG_FIFOHIGHTHRESHOLD,
+       FEAT_REG_FIFOLOWTHRESHOLD,
+       FEAT_REG_FIFOSIZE,
+};
+
+/* DSS Feature Functions */
+int dss_feat_get_num_mgrs(void);
+int dss_feat_get_num_ovls(void);
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
+
+bool dss_has_feature(enum dss_feat_id id);
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
+void dss_features_init(void);
+#endif
index 6a649ab5539ea3492c9f85599c93c891581b3dbb..545e9b9a4d92fc19eac470e5d62cb508461f0e4c 100644 (file)
@@ -33,6 +33,7 @@
 #include <plat/cpu.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 static int num_managers;
 static struct list_head manager_list;
@@ -448,8 +449,8 @@ struct manager_cache_data {
 
 static struct {
        spinlock_t lock;
-       struct overlay_cache_data overlay_cache[3];
-       struct manager_cache_data manager_cache[2];
+       struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
+       struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
 
        bool irq_enabled;
 } dss_cache;
@@ -882,12 +883,12 @@ static int configure_dispc(void)
 {
        struct overlay_cache_data *oc;
        struct manager_cache_data *mc;
-       const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
-       const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+       const int num_ovls = dss_feat_get_num_ovls();
+       const int num_mgrs = dss_feat_get_num_mgrs();
        int i;
        int r;
-       bool mgr_busy[2];
-       bool mgr_go[2];
+       bool mgr_busy[MAX_DSS_MANAGERS];
+       bool mgr_go[MAX_DSS_MANAGERS];
        bool busy;
 
        r = 0;
@@ -989,7 +990,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
 {
        struct overlay_cache_data *oc;
        struct manager_cache_data *mc;
-       const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
+       const int num_ovls = dss_feat_get_num_ovls();
        struct omap_overlay_manager *mgr;
        int i;
        u16 x, y, w, h;
@@ -1121,8 +1122,8 @@ void dss_start_update(struct omap_dss_device *dssdev)
 {
        struct manager_cache_data *mc;
        struct overlay_cache_data *oc;
-       const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
-       const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+       const int num_ovls = dss_feat_get_num_ovls();
+       const int num_mgrs = dss_feat_get_num_mgrs();
        struct omap_overlay_manager *mgr;
        int i;
 
@@ -1151,10 +1152,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
 {
        struct manager_cache_data *mc;
        struct overlay_cache_data *oc;
-       const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
-       const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+       const int num_ovls = dss_feat_get_num_ovls();
+       const int num_mgrs = dss_feat_get_num_mgrs();
        int i, r;
-       bool mgr_busy[2];
+       bool mgr_busy[MAX_DSS_MANAGERS];
 
        mgr_busy[0] = dispc_go_busy(0);
        mgr_busy[1] = dispc_go_busy(1);
@@ -1461,7 +1462,7 @@ int dss_init_overlay_managers(struct platform_device *pdev)
 
        num_managers = 0;
 
-       for (i = 0; i < 2; ++i) {
+       for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
                struct omap_overlay_manager *mgr;
                mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
 
@@ -1471,14 +1472,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
                case 0:
                        mgr->name = "lcd";
                        mgr->id = OMAP_DSS_CHANNEL_LCD;
-                       mgr->supported_displays =
-                               OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
-                               OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
                        break;
                case 1:
                        mgr->name = "tv";
                        mgr->id = OMAP_DSS_CHANNEL_DIGIT;
-                       mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
                        break;
                }
 
@@ -1494,6 +1491,8 @@ int dss_init_overlay_managers(struct platform_device *pdev)
                mgr->disable = &dss_mgr_disable;
 
                mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
+               mgr->supported_displays =
+                       dss_feat_get_supported_displays(mgr->id);
 
                dss_overlay_setup_dispc_manager(mgr);
 
index 244dca81a399a2efd047538846d53080d428bfaf..75642c22cac7f50724879ff3b8ef699b52aee14f 100644 (file)
@@ -35,6 +35,7 @@
 #include <plat/cpu.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 static int num_overlays;
 static struct list_head overlay_list;
@@ -237,7 +238,8 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
        /* Video1 plane does not support global alpha
         * to always make it 255 completely opaque
         */
-       if (ovl->id == OMAP_DSS_VIDEO1)
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+                       ovl->id == OMAP_DSS_VIDEO1)
                info.global_alpha = 255;
        else
                info.global_alpha = simple_strtoul(buf, NULL, 10);
@@ -510,11 +512,11 @@ static void omap_dss_add_overlay(struct omap_overlay *overlay)
        list_add_tail(&overlay->list, &overlay_list);
 }
 
-static struct omap_overlay *dispc_overlays[3];
+static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS];
 
 void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
 {
-       mgr->num_overlays = 3;
+       mgr->num_overlays = dss_feat_get_num_ovls();
        mgr->overlays = dispc_overlays;
 }
 
@@ -535,7 +537,7 @@ void dss_init_overlays(struct platform_device *pdev)
 
        num_overlays = 0;
 
-       for (i = 0; i < 3; ++i) {
+       for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
                struct omap_overlay *ovl;
                ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
 
@@ -545,18 +547,12 @@ void dss_init_overlays(struct platform_device *pdev)
                case 0:
                        ovl->name = "gfx";
                        ovl->id = OMAP_DSS_GFX;
-                       ovl->supported_modes = cpu_is_omap34xx() ?
-                               OMAP_DSS_COLOR_GFX_OMAP3 :
-                               OMAP_DSS_COLOR_GFX_OMAP2;
                        ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
                        break;
                case 1:
                        ovl->name = "vid1";
                        ovl->id = OMAP_DSS_VIDEO1;
-                       ovl->supported_modes = cpu_is_omap34xx() ?
-                               OMAP_DSS_COLOR_VID1_OMAP3 :
-                               OMAP_DSS_COLOR_VID_OMAP2;
                        ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
                                OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
@@ -564,9 +560,6 @@ void dss_init_overlays(struct platform_device *pdev)
                case 2:
                        ovl->name = "vid2";
                        ovl->id = OMAP_DSS_VIDEO2;
-                       ovl->supported_modes = cpu_is_omap34xx() ?
-                               OMAP_DSS_COLOR_VID2_OMAP3 :
-                               OMAP_DSS_COLOR_VID_OMAP2;
                        ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
                                OMAP_DSS_OVL_CAP_DISPC;
                        ovl->info.global_alpha = 255;
@@ -579,6 +572,9 @@ void dss_init_overlays(struct platform_device *pdev)
                ovl->get_overlay_info = &dss_ovl_get_overlay_info;
                ovl->wait_for_go = &dss_ovl_wait_for_go;
 
+               ovl->supported_modes =
+                       dss_feat_get_supported_color_modes(ovl->id);
+
                omap_dss_add_overlay(ovl);
 
                r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
@@ -651,7 +647,7 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
        }
 
        if (mgr) {
-               for (i = 0; i < 3; i++) {
+               for (i = 0; i < dss_feat_get_num_ovls(); i++) {
                        struct omap_overlay *ovl;
                        ovl = omap_dss_get_overlay(i);
                        if (!ovl->manager || force) {
index 43496d6c377fdfdfb7f830d0e9ae45ea923db383..65149b22cf373d7582e86af6da00107d60b8e9e1 100644 (file)
@@ -3,7 +3,7 @@ menuconfig FB_OMAP2
         depends on FB && OMAP2_DSS
 
        select OMAP2_VRAM
-       select OMAP2_VRFB
+       select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
         select FB_CFB_FILLRECT
         select FB_CFB_COPYAREA
         select FB_CFB_IMAGEBLIT
index 04034d410d6dee2e3d806c9a21793923585b7690..6a704f176c222a004f8732268e04cafb82ed1a70 100644 (file)
@@ -714,10 +714,10 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
                var->pixclock = timings.pixel_clock != 0 ?
                        KHZ2PICOS(timings.pixel_clock) :
                        0;
-               var->left_margin = timings.hfp;
-               var->right_margin = timings.hbp;
-               var->upper_margin = timings.vfp;
-               var->lower_margin = timings.vbp;
+               var->left_margin = timings.hbp;
+               var->right_margin = timings.hfp;
+               var->upper_margin = timings.vbp;
+               var->lower_margin = timings.vfp;
                var->hsync_len = timings.hsw;
                var->vsync_len = timings.vsw;
        } else {
@@ -2059,10 +2059,10 @@ static int omapfb_mode_to_timings(const char *mode_str,
 
        if (r != 0) {
                timings->pixel_clock = PICOS2KHZ(var.pixclock);
-               timings->hfp = var.left_margin;
-               timings->hbp = var.right_margin;
-               timings->vfp = var.upper_margin;
-               timings->vbp = var.lower_margin;
+               timings->hbp = var.left_margin;
+               timings->hfp = var.right_margin;
+               timings->vbp = var.upper_margin;
+               timings->vfp = var.lower_margin;
                timings->hsw = var.hsync_len;
                timings->vsw = var.vsync_len;
                timings->x_res = var.xres;
@@ -2198,6 +2198,16 @@ static int omapfb_probe(struct platform_device *pdev)
                goto err0;
        }
 
+       /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
+       *        available for OMAP2 and OMAP3
+       */
+       if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+               def_vrfb = 0;
+               dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
+                               "ignoring the module parameter vrfb=y\n");
+       }
+
+
        mutex_init(&fbdev->mtx);
 
        fbdev->dev = &pdev->dev;
index 2fde08cc66bf524f4f72594ee64cf72192f10800..ef989d94511c1fccdae24fbb1482ab986340f7f1 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
        return ioread8(hdmi->base + reg);
 }
 
+/*
+ *     HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+       return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+                            unsigned int reg,
+                            unsigned int value)
+{
+       struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+       hdmi_write(hdmi, value, reg);
+       return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+       .name = "sh_mobile_hdmi-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  |
+                        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  |
+                        SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                        SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+       },
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+       dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+       .probe          = sh_hdmi_snd_probe,
+       .read           = sh_hdmi_snd_read,
+       .write          = sh_hdmi_snd_write,
+};
+
+/*
+ *     HDMI video
+ */
+
 /* External video parameter settings */
 static void hdmi_external_video_param(struct sh_hdmi *hdmi)
 {
@@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
  */
 static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 {
+       u8 data;
+       struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
        /*
         * [7:4] L/R data swap control
         * [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
         * [6:5] set required down sampling rate if required
         * [4:3] set required audio source
         */
-       hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+       switch (pdata->flags & HDMI_SND_SRC_MASK) {
+       default:
+               /* fall through */
+       case HDMI_SND_SRC_I2S:
+               data = 0x0 << 3;
+               break;
+       case HDMI_SND_SRC_SPDIF:
+               data = 0x1 << 3;
+               break;
+       case HDMI_SND_SRC_DSD:
+               data = 0x2 << 3;
+               break;
+       case HDMI_SND_SRC_HBR:
+               data = 0x3 << 3;
+               break;
+       }
+       hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
 
        /* [3:0] set sending channel number for channel status */
        hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       ret =  snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+       if (ret < 0)
+               goto esndreg;
+
        hdmi->dev = &pdev->dev;
 
        hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@ eclkenable:
 erate:
        clk_put(hdmi->hdmi_clk);
 egetclk:
+       snd_soc_unregister_codec(&pdev->dev);
+esndreg:
        kfree(hdmi);
 
        return ret;
@@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
 
+       snd_soc_unregister_codec(&pdev->dev);
+
        pdata->lcd_chan->board_cfg.display_on = NULL;
        pdata->lcd_chan->board_cfg.display_off = NULL;
        pdata->lcd_chan->board_cfg.board_data = NULL;
index d72075a9f01c367ceb9e573f3a475774db6a4b80..7a1419279c8f501bf4d94a4101259cf6aaa0860e 100644 (file)
@@ -1243,8 +1243,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
                if (priv->ch[i].sglist)
                        vfree(priv->ch[i].sglist);
 
-               dma_free_coherent(&pdev->dev, info->fix.smem_len,
-                                 info->screen_base, priv->ch[i].dma_handle);
+               if (info->screen_base)
+                       dma_free_coherent(&pdev->dev, info->fix.smem_len,
+                                         info->screen_base,
+                                         priv->ch[i].dma_handle);
                fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
        }
index 0c9ce88e95e8880b8361973390efb2a989bbe142..68bd23476c64087b34a8cf22d5da491f7e635d9f 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
 #include <linux/io.h>
 #include <linux/xilinxfb.h>
 #include <linux/slab.h>
+
+#ifdef CONFIG_PPC_DCR
 #include <asm/dcr.h>
+#endif
 
 #define DRIVER_NAME            "xilinxfb"
 
@@ -123,10 +127,10 @@ struct xilinxfb_drvdata {
                                                registers */
        void __iomem    *regs;          /* virt. address of the control
                                                registers */
-
+#ifdef CONFIG_PPC_DCR
        dcr_host_t      dcr_host;
        unsigned int    dcr_len;
-
+#endif
        void            *fb_virt;       /* virt. address of the frame buffer */
        dma_addr_t      fb_phys;        /* phys. address of the frame buffer */
        int             fb_alloced;     /* Flag, was the fb memory alloced? */
@@ -152,9 +156,10 @@ static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
 {
        if (drvdata->flags & PLB_ACCESS_FLAG)
                out_be32(drvdata->regs + (offset << 2), val);
+#ifdef CONFIG_PPC_DCR
        else
                dcr_write(drvdata->dcr_host, offset, val);
-
+#endif
 }
 
 static int
@@ -383,8 +388,11 @@ static int xilinxfb_release(struct device *dev)
        if (drvdata->flags & PLB_ACCESS_FLAG) {
                iounmap(drvdata->regs);
                release_mem_region(drvdata->regs_phys, 8);
-       } else
+       }
+#ifdef CONFIG_PPC_DCR
+       else
                dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
+#endif
 
        kfree(drvdata);
        dev_set_drvdata(dev, NULL);
@@ -404,7 +412,7 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
        u32 tft_access;
        struct xilinxfb_platform_data pdata;
        struct resource res;
-       int size, rc, start;
+       int size, rc;
        struct xilinxfb_drvdata *drvdata;
 
        /* Copy with the default pdata (not a ptr reference!) */
@@ -437,7 +445,10 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
                        dev_err(&op->dev, "invalid address\n");
                        goto err;
                }
-       } else {
+       }
+#ifdef CONFIG_PPC_DCR
+       else {
+               int start;
                res.start = 0;
                start = dcr_resource_start(op->dev.of_node, 0);
                drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
@@ -447,6 +458,7 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
                        goto err;
                }
        }
+#endif
 
        prop = of_get_property(op->dev.of_node, "phys-size", &size);
        if ((prop) && (size >= sizeof(u32)*2)) {
index 81e3d610089439c7f6a168f56c5227781453729f..3dd4971160ef3efb6e3c485ef94af38641f16bdf 100644 (file)
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
-#include <linux/clk.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <mach/hardware.h>
 #include <plat/prcm.h>
 
@@ -61,8 +61,6 @@ struct omap_wdt_dev {
        void __iomem    *base;          /* physical */
        struct device   *dev;
        int             omap_wdt_users;
-       struct clk      *ick;
-       struct clk      *fck;
        struct resource *mem;
        struct miscdevice omap_wdt_miscdev;
 };
@@ -146,8 +144,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
        if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
                return -EBUSY;
 
-       clk_enable(wdev->ick);    /* Enable the interface clock */
-       clk_enable(wdev->fck);    /* Enable the functional clock */
+       pm_runtime_get_sync(wdev->dev);
 
        /* initialize prescaler */
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
@@ -177,8 +174,7 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
 
        omap_wdt_disable(wdev);
 
-       clk_disable(wdev->ick);
-       clk_disable(wdev->fck);
+       pm_runtime_put_sync(wdev->dev);
 #else
        printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
@@ -293,19 +289,7 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
 
        wdev->omap_wdt_users = 0;
        wdev->mem = mem;
-
-       wdev->ick = clk_get(&pdev->dev, "ick");
-       if (IS_ERR(wdev->ick)) {
-               ret = PTR_ERR(wdev->ick);
-               wdev->ick = NULL;
-               goto err_clk;
-       }
-       wdev->fck = clk_get(&pdev->dev, "fck");
-       if (IS_ERR(wdev->fck)) {
-               ret = PTR_ERR(wdev->fck);
-               wdev->fck = NULL;
-               goto err_clk;
-       }
+       wdev->dev = &pdev->dev;
 
        wdev->base = ioremap(res->start, resource_size(res));
        if (!wdev->base) {
@@ -315,8 +299,8 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdev);
 
-       clk_enable(wdev->ick);
-       clk_enable(wdev->fck);
+       pm_runtime_enable(wdev->dev);
+       pm_runtime_get_sync(wdev->dev);
 
        omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
@@ -334,11 +318,7 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
                __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
                timer_margin);
 
-       /* autogate OCP interface clock */
-       __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
-
-       clk_disable(wdev->ick);
-       clk_disable(wdev->fck);
+       pm_runtime_put_sync(wdev->dev);
 
        omap_wdt_dev = pdev;
 
@@ -350,12 +330,6 @@ err_misc:
 
 err_ioremap:
        wdev->base = NULL;
-
-err_clk:
-       if (wdev->ick)
-               clk_put(wdev->ick);
-       if (wdev->fck)
-               clk_put(wdev->fck);
        kfree(wdev);
 
 err_kzalloc:
@@ -387,8 +361,6 @@ static int __devexit omap_wdt_remove(struct platform_device *pdev)
        release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
 
-       clk_put(wdev->ick);
-       clk_put(wdev->fck);
        iounmap(wdev->base);
 
        kfree(wdev);
index 7d24b0d94ed4756615ef66b3304b270f66707ba4..347f17edad77bab15f1e5ca286a833a3a8392906 100644 (file)
@@ -261,7 +261,7 @@ static void init_evtchn_cpu_bindings(void)
        }
 #endif
 
-       memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0)));
+       memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
 }
 
 static inline void clear_evtchn(int port)
@@ -377,7 +377,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
                irq = find_unbound_irq();
 
                set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
-                                             handle_edge_irq, "event");
+                                             handle_fasteoi_irq, "event");
 
                evtchn_to_irq[evtchn] = irq;
                irq_info[irq] = mk_evtchn_info(evtchn);
@@ -435,6 +435,11 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
        irq = per_cpu(virq_to_irq, cpu)[virq];
 
        if (irq == -1) {
+               irq = find_unbound_irq();
+
+               set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
+                                             handle_percpu_irq, "virq");
+
                bind_virq.virq = virq;
                bind_virq.vcpu = cpu;
                if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
@@ -442,11 +447,6 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
                        BUG();
                evtchn = bind_virq.port;
 
-               irq = find_unbound_irq();
-
-               set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
-                                             handle_percpu_irq, "virq");
-
                evtchn_to_irq[evtchn] = irq;
                irq_info[irq] = mk_virq_info(evtchn, virq);
 
@@ -578,41 +578,75 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
 {
        struct shared_info *sh = HYPERVISOR_shared_info;
        int cpu = smp_processor_id();
+       unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu);
        int i;
        unsigned long flags;
        static DEFINE_SPINLOCK(debug_lock);
+       struct vcpu_info *v;
 
        spin_lock_irqsave(&debug_lock, flags);
 
-       printk("vcpu %d\n  ", cpu);
+       printk("\nvcpu %d\n  ", cpu);
 
        for_each_online_cpu(i) {
-               struct vcpu_info *v = per_cpu(xen_vcpu, i);
-               printk("%d: masked=%d pending=%d event_sel %08lx\n  ", i,
-                       (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask,
-                       v->evtchn_upcall_pending,
-                       v->evtchn_pending_sel);
+               int pending;
+               v = per_cpu(xen_vcpu, i);
+               pending = (get_irq_regs() && i == cpu)
+                       ? xen_irqs_disabled(get_irq_regs())
+                       : v->evtchn_upcall_mask;
+               printk("%d: masked=%d pending=%d event_sel %0*lx\n  ", i,
+                      pending, v->evtchn_upcall_pending,
+                      (int)(sizeof(v->evtchn_pending_sel)*2),
+                      v->evtchn_pending_sel);
+       }
+       v = per_cpu(xen_vcpu, cpu);
+
+       printk("\npending:\n   ");
+       for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
+               printk("%0*lx%s", (int)sizeof(sh->evtchn_pending[0])*2,
+                      sh->evtchn_pending[i],
+                      i % 8 == 0 ? "\n   " : " ");
+       printk("\nglobal mask:\n   ");
+       for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+               printk("%0*lx%s",
+                      (int)(sizeof(sh->evtchn_mask[0])*2),
+                      sh->evtchn_mask[i],
+                      i % 8 == 0 ? "\n   " : " ");
+
+       printk("\nglobally unmasked:\n   ");
+       for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+               printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
+                      sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
+                      i % 8 == 0 ? "\n   " : " ");
+
+       printk("\nlocal cpu%d mask:\n   ", cpu);
+       for (i = (NR_EVENT_CHANNELS/BITS_PER_LONG)-1; i >= 0; i--)
+               printk("%0*lx%s", (int)(sizeof(cpu_evtchn[0])*2),
+                      cpu_evtchn[i],
+                      i % 8 == 0 ? "\n   " : " ");
+
+       printk("\nlocally unmasked:\n   ");
+       for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
+               unsigned long pending = sh->evtchn_pending[i]
+                       & ~sh->evtchn_mask[i]
+                       & cpu_evtchn[i];
+               printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
+                      pending, i % 8 == 0 ? "\n   " : " ");
        }
-       printk("pending:\n   ");
-       for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
-               printk("%08lx%s", sh->evtchn_pending[i],
-                       i % 8 == 0 ? "\n   " : " ");
-       printk("\nmasks:\n   ");
-       for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
-               printk("%08lx%s", sh->evtchn_mask[i],
-                       i % 8 == 0 ? "\n   " : " ");
-
-       printk("\nunmasked:\n   ");
-       for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
-               printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
-                       i % 8 == 0 ? "\n   " : " ");
 
        printk("\npending list:\n");
-       for(i = 0; i < NR_EVENT_CHANNELS; i++) {
+       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
                if (sync_test_bit(i, sh->evtchn_pending)) {
-                       printk("  %d: event %d -> irq %d\n",
+                       int word_idx = i / BITS_PER_LONG;
+                       printk("  %d: event %d -> irq %d%s%s%s\n",
                               cpu_from_evtchn(i), i,
-                              evtchn_to_irq[i]);
+                              evtchn_to_irq[i],
+                              sync_test_bit(word_idx, &v->evtchn_pending_sel)
+                                            ? "" : " l2-clear",
+                              !sync_test_bit(i, sh->evtchn_mask)
+                                            ? "" : " globally-masked",
+                              sync_test_bit(i, cpu_evtchn)
+                                            ? "" : " locally-masked");
                }
        }
 
@@ -663,6 +697,9 @@ static void __xen_evtchn_do_upcall(void)
                                int irq = evtchn_to_irq[port];
                                struct irq_desc *desc;
 
+                               mask_evtchn(port);
+                               clear_evtchn(port);
+
                                if (irq != -1) {
                                        desc = irq_to_desc(irq);
                                        if (desc)
@@ -800,10 +837,10 @@ static void ack_dynirq(unsigned int irq)
 {
        int evtchn = evtchn_from_irq(irq);
 
-       move_native_irq(irq);
+       move_masked_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
-               clear_evtchn(evtchn);
+               unmask_evtchn(evtchn);
 }
 
 static int retrigger_dynirq(unsigned int irq)
@@ -959,7 +996,7 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
        .mask           = disable_dynirq,
        .unmask         = enable_dynirq,
 
-       .ack            = ack_dynirq,
+       .eoi            = ack_dynirq,
        .set_affinity   = set_affinity_irq,
        .retrigger      = retrigger_dynirq,
 };
index d409495876f11b24fabaebc01d57f02224fe459f..132939f3602014abb1c9c62e3c97236fd7d45e02 100644 (file)
 
 
 int xen_store_evtchn;
-EXPORT_SYMBOL(xen_store_evtchn);
+EXPORT_SYMBOL_GPL(xen_store_evtchn);
 
 struct xenstore_domain_interface *xen_store_interface;
+EXPORT_SYMBOL_GPL(xen_store_interface);
+
 static unsigned long xen_store_mfn;
 
 static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
index 25275c3bbdffe0b8889eed5def224f1b9a5ce0d2..4fde9440fe1f453aad9a4d6e4a98dceecbf6dbe4 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_XENFS) += xenfs.o
 
-xenfs-objs = super.o xenbus.o
\ No newline at end of file
+xenfs-y                          = super.o xenbus.o privcmd.o
+xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c
new file mode 100644 (file)
index 0000000..f80be7f
--- /dev/null
@@ -0,0 +1,404 @@
+/******************************************************************************
+ * privcmd.c
+ *
+ * Interface to privileged domain-0 commands.
+ *
+ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/uaccess.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
+#include <xen/privcmd.h>
+#include <xen/interface/xen.h>
+#include <xen/features.h>
+#include <xen/page.h>
+#include <xen/xen-ops.h>
+
+#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
+#endif
+
+static long privcmd_ioctl_hypercall(void __user *udata)
+{
+       struct privcmd_hypercall hypercall;
+       long ret;
+
+       if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
+               return -EFAULT;
+
+       ret = privcmd_call(hypercall.op,
+                          hypercall.arg[0], hypercall.arg[1],
+                          hypercall.arg[2], hypercall.arg[3],
+                          hypercall.arg[4]);
+
+       return ret;
+}
+
+static void free_page_list(struct list_head *pages)
+{
+       struct page *p, *n;
+
+       list_for_each_entry_safe(p, n, pages, lru)
+               __free_page(p);
+
+       INIT_LIST_HEAD(pages);
+}
+
+/*
+ * Given an array of items in userspace, return a list of pages
+ * containing the data.  If copying fails, either because of memory
+ * allocation failure or a problem reading user memory, return an
+ * error code; its up to the caller to dispose of any partial list.
+ */
+static int gather_array(struct list_head *pagelist,
+                       unsigned nelem, size_t size,
+                       void __user *data)
+{
+       unsigned pageidx;
+       void *pagedata;
+       int ret;
+
+       if (size > PAGE_SIZE)
+               return 0;
+
+       pageidx = PAGE_SIZE;
+       pagedata = NULL;        /* quiet, gcc */
+       while (nelem--) {
+               if (pageidx > PAGE_SIZE-size) {
+                       struct page *page = alloc_page(GFP_KERNEL);
+
+                       ret = -ENOMEM;
+                       if (page == NULL)
+                               goto fail;
+
+                       pagedata = page_address(page);
+
+                       list_add_tail(&page->lru, pagelist);
+                       pageidx = 0;
+               }
+
+               ret = -EFAULT;
+               if (copy_from_user(pagedata + pageidx, data, size))
+                       goto fail;
+
+               data += size;
+               pageidx += size;
+       }
+
+       ret = 0;
+
+fail:
+       return ret;
+}
+
+/*
+ * Call function "fn" on each element of the array fragmented
+ * over a list of pages.
+ */
+static int traverse_pages(unsigned nelem, size_t size,
+                         struct list_head *pos,
+                         int (*fn)(void *data, void *state),
+                         void *state)
+{
+       void *pagedata;
+       unsigned pageidx;
+       int ret = 0;
+
+       BUG_ON(size > PAGE_SIZE);
+
+       pageidx = PAGE_SIZE;
+       pagedata = NULL;        /* hush, gcc */
+
+       while (nelem--) {
+               if (pageidx > PAGE_SIZE-size) {
+                       struct page *page;
+                       pos = pos->next;
+                       page = list_entry(pos, struct page, lru);
+                       pagedata = page_address(page);
+                       pageidx = 0;
+               }
+
+               ret = (*fn)(pagedata + pageidx, state);
+               if (ret)
+                       break;
+               pageidx += size;
+       }
+
+       return ret;
+}
+
+struct mmap_mfn_state {
+       unsigned long va;
+       struct vm_area_struct *vma;
+       domid_t domain;
+};
+
+static int mmap_mfn_range(void *data, void *state)
+{
+       struct privcmd_mmap_entry *msg = data;
+       struct mmap_mfn_state *st = state;
+       struct vm_area_struct *vma = st->vma;
+       int rc;
+
+       /* Do not allow range to wrap the address space. */
+       if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
+           ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va))
+               return -EINVAL;
+
+       /* Range chunks must be contiguous in va space. */
+       if ((msg->va != st->va) ||
+           ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end))
+               return -EINVAL;
+
+       rc = xen_remap_domain_mfn_range(vma,
+                                       msg->va & PAGE_MASK,
+                                       msg->mfn, msg->npages,
+                                       vma->vm_page_prot,
+                                       st->domain);
+       if (rc < 0)
+               return rc;
+
+       st->va += msg->npages << PAGE_SHIFT;
+
+       return 0;
+}
+
+static long privcmd_ioctl_mmap(void __user *udata)
+{
+       struct privcmd_mmap mmapcmd;
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       int rc;
+       LIST_HEAD(pagelist);
+       struct mmap_mfn_state state;
+
+       if (!xen_initial_domain())
+               return -EPERM;
+
+       if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
+               return -EFAULT;
+
+       rc = gather_array(&pagelist,
+                         mmapcmd.num, sizeof(struct privcmd_mmap_entry),
+                         mmapcmd.entry);
+
+       if (rc || list_empty(&pagelist))
+               goto out;
+
+       down_write(&mm->mmap_sem);
+
+       {
+               struct page *page = list_first_entry(&pagelist,
+                                                    struct page, lru);
+               struct privcmd_mmap_entry *msg = page_address(page);
+
+               vma = find_vma(mm, msg->va);
+               rc = -EINVAL;
+
+               if (!vma || (msg->va != vma->vm_start) ||
+                   !privcmd_enforce_singleshot_mapping(vma))
+                       goto out_up;
+       }
+
+       state.va = vma->vm_start;
+       state.vma = vma;
+       state.domain = mmapcmd.dom;
+
+       rc = traverse_pages(mmapcmd.num, sizeof(struct privcmd_mmap_entry),
+                           &pagelist,
+                           mmap_mfn_range, &state);
+
+
+out_up:
+       up_write(&mm->mmap_sem);
+
+out:
+       free_page_list(&pagelist);
+
+       return rc;
+}
+
+struct mmap_batch_state {
+       domid_t domain;
+       unsigned long va;
+       struct vm_area_struct *vma;
+       int err;
+
+       xen_pfn_t __user *user;
+};
+
+static int mmap_batch_fn(void *data, void *state)
+{
+       xen_pfn_t *mfnp = data;
+       struct mmap_batch_state *st = state;
+
+       if (xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
+                                      st->vma->vm_page_prot, st->domain) < 0) {
+               *mfnp |= 0xf0000000U;
+               st->err++;
+       }
+       st->va += PAGE_SIZE;
+
+       return 0;
+}
+
+static int mmap_return_errors(void *data, void *state)
+{
+       xen_pfn_t *mfnp = data;
+       struct mmap_batch_state *st = state;
+
+       put_user(*mfnp, st->user++);
+
+       return 0;
+}
+
+static struct vm_operations_struct privcmd_vm_ops;
+
+static long privcmd_ioctl_mmap_batch(void __user *udata)
+{
+       int ret;
+       struct privcmd_mmapbatch m;
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       unsigned long nr_pages;
+       LIST_HEAD(pagelist);
+       struct mmap_batch_state state;
+
+       if (!xen_initial_domain())
+               return -EPERM;
+
+       if (copy_from_user(&m, udata, sizeof(m)))
+               return -EFAULT;
+
+       nr_pages = m.num;
+       if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
+               return -EINVAL;
+
+       ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
+                          m.arr);
+
+       if (ret || list_empty(&pagelist))
+               goto out;
+
+       down_write(&mm->mmap_sem);
+
+       vma = find_vma(mm, m.addr);
+       ret = -EINVAL;
+       if (!vma ||
+           vma->vm_ops != &privcmd_vm_ops ||
+           (m.addr != vma->vm_start) ||
+           ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
+           !privcmd_enforce_singleshot_mapping(vma)) {
+               up_write(&mm->mmap_sem);
+               goto out;
+       }
+
+       state.domain = m.dom;
+       state.vma = vma;
+       state.va = m.addr;
+       state.err = 0;
+
+       ret = traverse_pages(m.num, sizeof(xen_pfn_t),
+                            &pagelist, mmap_batch_fn, &state);
+
+       up_write(&mm->mmap_sem);
+
+       if (state.err > 0) {
+               ret = 0;
+
+               state.user = m.arr;
+               traverse_pages(m.num, sizeof(xen_pfn_t),
+                              &pagelist,
+                              mmap_return_errors, &state);
+       }
+
+out:
+       free_page_list(&pagelist);
+
+       return ret;
+}
+
+static long privcmd_ioctl(struct file *file,
+                         unsigned int cmd, unsigned long data)
+{
+       int ret = -ENOSYS;
+       void __user *udata = (void __user *) data;
+
+       switch (cmd) {
+       case IOCTL_PRIVCMD_HYPERCALL:
+               ret = privcmd_ioctl_hypercall(udata);
+               break;
+
+       case IOCTL_PRIVCMD_MMAP:
+               ret = privcmd_ioctl_mmap(udata);
+               break;
+
+       case IOCTL_PRIVCMD_MMAPBATCH:
+               ret = privcmd_ioctl_mmap_batch(udata);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
+              vma, vma->vm_start, vma->vm_end,
+              vmf->pgoff, vmf->virtual_address);
+
+       return VM_FAULT_SIGBUS;
+}
+
+static struct vm_operations_struct privcmd_vm_ops = {
+       .fault = privcmd_fault
+};
+
+static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       /* Unsupported for auto-translate guests. */
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return -ENOSYS;
+
+       /* DONTCOPY is essential for Xen as copy_page_range is broken. */
+       vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+       vma->vm_ops = &privcmd_vm_ops;
+       vma->vm_private_data = NULL;
+
+       return 0;
+}
+
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
+{
+       return (xchg(&vma->vm_private_data, (void *)1) == NULL);
+}
+#endif
+
+const struct file_operations privcmd_file_ops = {
+       .unlocked_ioctl = privcmd_ioctl,
+       .mmap = privcmd_mmap,
+};
index bd96340063c1d6175f633fa507e8c7e2bf34ba93..d6662b789b6bf05a3cc172623216ea662e681781 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/magic.h>
+#include <linux/mm.h>
+#include <linux/backing-dev.h>
 
 #include <xen/xen.h>
 
 MODULE_DESCRIPTION("Xen filesystem");
 MODULE_LICENSE("GPL");
 
+static int xenfs_set_page_dirty(struct page *page)
+{
+       return !TestSetPageDirty(page);
+}
+
+static const struct address_space_operations xenfs_aops = {
+       .set_page_dirty = xenfs_set_page_dirty,
+};
+
+static struct backing_dev_info xenfs_backing_dev_info = {
+       .ra_pages       = 0,    /* No readahead */
+       .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
+};
+
+static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
+{
+       struct inode *ret = new_inode(sb);
+
+       if (ret) {
+               ret->i_mode = mode;
+               ret->i_mapping->a_ops = &xenfs_aops;
+               ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
+               ret->i_uid = ret->i_gid = 0;
+               ret->i_blocks = 0;
+               ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+       }
+       return ret;
+}
+
+static struct dentry *xenfs_create_file(struct super_block *sb,
+                                       struct dentry *parent,
+                                       const char *name,
+                                       const struct file_operations *fops,
+                                       void *data,
+                                       int mode)
+{
+       struct dentry *dentry;
+       struct inode *inode;
+
+       dentry = d_alloc_name(parent, name);
+       if (!dentry)
+               return NULL;
+
+       inode = xenfs_make_inode(sb, S_IFREG | mode);
+       if (!inode) {
+               dput(dentry);
+               return NULL;
+       }
+
+       inode->i_fop = fops;
+       inode->i_private = data;
+
+       d_add(dentry, inode);
+       return dentry;
+}
+
 static ssize_t capabilities_read(struct file *file, char __user *buf,
                                 size_t size, loff_t *off)
 {
@@ -44,10 +102,23 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
                [1] = {},
                { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
                { "capabilities", &capabilities_file_ops, S_IRUGO },
+               { "privcmd", &privcmd_file_ops, S_IRUSR|S_IWUSR },
                {""},
        };
+       int rc;
 
-       return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
+       rc = simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
+       if (rc < 0)
+               return rc;
+
+       if (xen_initial_domain()) {
+               xenfs_create_file(sb, sb->s_root, "xsd_kva",
+                                 &xsd_kva_file_ops, NULL, S_IRUSR|S_IWUSR);
+               xenfs_create_file(sb, sb->s_root, "xsd_port",
+                                 &xsd_port_file_ops, NULL, S_IRUSR|S_IWUSR);
+       }
+
+       return rc;
 }
 
 static int xenfs_get_sb(struct file_system_type *fs_type,
@@ -66,11 +137,25 @@ static struct file_system_type xenfs_type = {
 
 static int __init xenfs_init(void)
 {
-       if (xen_domain())
-               return register_filesystem(&xenfs_type);
+       int err;
+       if (!xen_domain()) {
+               printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
+               return 0;
+       }
+
+       err = register_filesystem(&xenfs_type);
+       if (err) {
+               printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
+               goto out;
+       }
+
+       err = bdi_init(&xenfs_backing_dev_info);
+       if (err)
+               unregister_filesystem(&xenfs_type);
+
+ out:
 
-       printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
-       return 0;
+       return err;
 }
 
 static void __exit xenfs_exit(void)
index 51f08b2d0bf15a44732bd35a31ec18c36e5ed24c..b68aa6200003575549e7a5844ae7b43b6bec135f 100644 (file)
@@ -2,5 +2,8 @@
 #define _XENFS_XENBUS_H
 
 extern const struct file_operations xenbus_file_ops;
+extern const struct file_operations privcmd_file_ops;
+extern const struct file_operations xsd_kva_file_ops;
+extern const struct file_operations xsd_port_file_ops;
 
 #endif /* _XENFS_XENBUS_H */
diff --git a/drivers/xen/xenfs/xenstored.c b/drivers/xen/xenfs/xenstored.c
new file mode 100644 (file)
index 0000000..fef20db
--- /dev/null
@@ -0,0 +1,68 @@
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+#include <xen/page.h>
+
+#include "xenfs.h"
+#include "../xenbus/xenbus_comms.h"
+
+static ssize_t xsd_read(struct file *file, char __user *buf,
+                           size_t size, loff_t *off)
+{
+       const char *str = (const char *)file->private_data;
+       return simple_read_from_buffer(buf, size, off, str, strlen(str));
+}
+
+static int xsd_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+static int xsd_kva_open(struct inode *inode, struct file *file)
+{
+       file->private_data = (void *)kasprintf(GFP_KERNEL, "0x%p",
+                                              xen_store_interface);
+       if (!file->private_data)
+               return -ENOMEM;
+       return 0;
+}
+
+static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       size_t size = vma->vm_end - vma->vm_start;
+
+       if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
+               return -EINVAL;
+
+       if (remap_pfn_range(vma, vma->vm_start,
+                           virt_to_pfn(xen_store_interface),
+                           size, vma->vm_page_prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+const struct file_operations xsd_kva_file_ops = {
+       .open = xsd_kva_open,
+       .mmap = xsd_kva_mmap,
+       .read = xsd_read,
+       .release = xsd_release,
+};
+
+static int xsd_port_open(struct inode *inode, struct file *file)
+{
+       file->private_data = (void *)kasprintf(GFP_KERNEL, "%d",
+                                              xen_store_evtchn);
+       if (!file->private_data)
+               return -ENOMEM;
+       return 0;
+}
+
+const struct file_operations xsd_port_file_ops = {
+       .open = xsd_port_open,
+       .read = xsd_read,
+       .release = xsd_release,
+};
index 5a03ba8c8364e9cc4dde9655871d4a13b6ff2463..ba0cf0b601bb925fc3ce514d1f1dd55569feac91 100644 (file)
@@ -55,6 +55,7 @@ static int output_records(int outfd);
 
 static int sort_records = 0;
 static int wide_records = 0;
+static int include_jump = 0;
 
 static int usage(void)
 {
@@ -63,6 +64,7 @@ static int usage(void)
        fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
        fprintf(stderr, "       -w: wide records (16-bit length)\n");
        fprintf(stderr, "       -s: sort records by address\n");
+       fprintf(stderr, "       -j: include records for CS:IP/EIP address\n");
        return 1;
 }
 
@@ -73,7 +75,7 @@ int main(int argc, char **argv)
        uint8_t *data;
        int opt;
 
-       while ((opt = getopt(argc, argv, "ws")) != -1) {
+       while ((opt = getopt(argc, argv, "wsj")) != -1) {
                switch (opt) {
                case 'w':
                        wide_records = 1;
@@ -81,7 +83,9 @@ int main(int argc, char **argv)
                case 's':
                        sort_records = 1;
                        break;
-               default:
+               case 'j':
+                       include_jump = 1;
+                       break;
                        return usage();
                }
        }
@@ -128,6 +132,7 @@ static int process_ihex(uint8_t *data, ssize_t size)
 {
        struct ihex_binrec *record;
        uint32_t offset = 0;
+       uint32_t data32;
        uint8_t type, crc = 0, crcbyte = 0;
        int i, j;
        int line = 1;
@@ -223,8 +228,14 @@ next_record:
                        return -EINVAL;
                }
 
+               memcpy(&data32, &record->data[0], sizeof(data32));
+               data32 = htonl(data32);
+               memcpy(&record->data[0], &data32, sizeof(data32));
+
                /* These records contain the CS/IP or EIP where execution
-                * starts. Don't really know what to do with them. */
+                * starts. If requested output this as a record. */
+               if (include_jump)
+                       file_record(record);
                goto next_record;
 
        default:
index 9e670d527646fc4abe2be6f0dfc992f4a3178042..ef5905f7c8a39c9395362d5e368a846d43fcedbd 100644 (file)
@@ -1789,9 +1789,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                kfree(st);
        } else {
                /* Caching disabled. No need to get upto date stat info.
-                * This dentry will be released immediately. So, just i_count++
+                * This dentry will be released immediately. So, just hold the
+                * inode
                 */
-               atomic_inc(&old_dentry->d_inode->i_count);
+               ihold(old_dentry->d_inode);
        }
 
        dentry->d_op = old_dentry->d_op;
index 65781de44fc0e04998d3daa2bee8b51e215d9844..97673c955484463e4181d4e3f689742bbe558a06 100644 (file)
@@ -47,10 +47,12 @@ source "fs/nilfs2/Kconfig"
 
 endif # BLOCK
 
+config EXPORTFS
+       tristate
+
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EMBEDDED
        default y
-       select BKL # while lockd still uses it.
        help
          This option enables standard file locking support, required
           for filesystems like NFS and for the flock() system
@@ -222,9 +224,6 @@ config LOCKD_V4
        depends on FILE_LOCKING
        default y
 
-config EXPORTFS
-       tristate
-
 config NFS_ACL_SUPPORT
        tristate
        select FS_POSIX_ACL
index e6ec1d309b1d2ba43dd3e036a9f8dcfba9a757a1..26956fcec917f1792307e31d3b58bec32137d7ff 100644 (file)
@@ -29,10 +29,7 @@ obj-$(CONFIG_EVENTFD)                += eventfd.o
 obj-$(CONFIG_AIO)               += aio.o
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_COMPAT)           += compat.o compat_ioctl.o
-
-nfsd-$(CONFIG_NFSD)            := nfsctl.o
-obj-y                          += $(nfsd-y) $(nfsd-m)
-
+obj-$(CONFIG_NFSD_DEPRECATED)  += nfsctl.o
 obj-$(CONFIG_BINFMT_AOUT)      += binfmt_aout.o
 obj-$(CONFIG_BINFMT_EM86)      += binfmt_em86.o
 obj-$(CONFIG_BINFMT_MISC)      += binfmt_misc.o
index c4a9875bd1a60520c682bed74f7a27bc3d2e1da0..0a90dcd46de28d33f2768fde829ac7800abdc9e4 100644 (file)
@@ -894,9 +894,9 @@ affs_truncate(struct inode *inode)
                if (AFFS_SB(sb)->s_flags & SF_OFS) {
                        struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
                        u32 tmp;
-                       if (IS_ERR(ext_bh)) {
+                       if (IS_ERR(bh)) {
                                affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
-                                            ext, PTR_ERR(ext_bh));
+                                            ext, PTR_ERR(bh));
                                return;
                        }
                        tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
index 3a0fdec175ba6d5d84ea8ae27f117d0e2cc46644..5d828903ac69ced919eaa3d6eb2429a49922d0e2 100644 (file)
@@ -388,7 +388,7 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
                affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
                mark_buffer_dirty_inode(inode_bh, inode);
                inode->i_nlink = 2;
-               atomic_inc(&inode->i_count);
+               ihold(inode);
        }
        affs_fix_checksum(sb, bh);
        mark_buffer_dirty_inode(bh, inode);
index 0d38c09bd55e10f4eaf5f0e25ef11fa3d9d82919..5439e1bc9a86a5702094eaea35eb4c6ebd8e67fe 100644 (file)
@@ -1045,7 +1045,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
        if (ret < 0)
                goto link_error;
 
-       atomic_inc(&vnode->vfs_inode.i_count);
+       ihold(&vnode->vfs_inode);
        d_instantiate(dentry, &vnode->vfs_inode);
        key_put(key);
        _leave(" = 0");
index 722743b152d817e94d5ea44131c96026f45e6898..15690bb1d3b531e65ae9cce255eaf532081667db 100644 (file)
@@ -438,7 +438,6 @@ no_more:
  */
 int afs_writepage(struct page *page, struct writeback_control *wbc)
 {
-       struct backing_dev_info *bdi = page->mapping->backing_dev_info;
        struct afs_writeback *wb;
        int ret;
 
@@ -455,8 +454,6 @@ int afs_writepage(struct page *page, struct writeback_control *wbc)
        }
 
        wbc->nr_to_write -= ret;
-       if (wbc->nonblocking && bdi_write_congested(bdi))
-               wbc->encountered_congestion = 1;
 
        _leave(" = 0");
        return 0;
@@ -469,7 +466,6 @@ static int afs_writepages_region(struct address_space *mapping,
                                 struct writeback_control *wbc,
                                 pgoff_t index, pgoff_t end, pgoff_t *_next)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        struct afs_writeback *wb;
        struct page *page;
        int ret, n;
@@ -529,11 +525,6 @@ static int afs_writepages_region(struct address_space *mapping,
 
                wbc->nr_to_write -= ret;
 
-               if (wbc->nonblocking && bdi_write_congested(bdi)) {
-                       wbc->encountered_congestion = 1;
-                       break;
-               }
-
                cond_resched();
        } while (index < end && wbc->nr_to_write > 0);
 
@@ -548,24 +539,16 @@ static int afs_writepages_region(struct address_space *mapping,
 int afs_writepages(struct address_space *mapping,
                   struct writeback_control *wbc)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        pgoff_t start, end, next;
        int ret;
 
        _enter("");
 
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               _leave(" = 0 [congest]");
-               return 0;
-       }
-
        if (wbc->range_cyclic) {
                start = mapping->writeback_index;
                end = -1;
                ret = afs_writepages_region(mapping, wbc, start, end, &next);
-               if (start > 0 && wbc->nr_to_write > 0 && ret == 0 &&
-                   !(wbc->nonblocking && wbc->encountered_congestion))
+               if (start > 0 && wbc->nr_to_write > 0 && ret == 0)
                        ret = afs_writepages_region(mapping, wbc, 0, start,
                                                    &next);
                mapping->writeback_index = next;
index 250b0a73c8a8ca92b78c3a0282d2425ce7649dcf..8c8f6c5b6d7930657f7a3aadf44fe4b4dc96b738 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1543,7 +1543,19 @@ static void aio_batch_add(struct address_space *mapping,
        }
 
        abe = mempool_alloc(abe_pool, GFP_KERNEL);
-       BUG_ON(!igrab(mapping->host));
+
+       /*
+        * we should be using igrab here, but
+        * we don't want to hammer on the global
+        * inode spinlock just to take an extra
+        * reference on a file that we must already
+        * have a reference to.
+        *
+        * When we're called, we always have a reference
+        * on the file, so we must always have a reference
+        * on the inode, so ihold() is safe here.
+        */
+       ihold(mapping->host);
        abe->mapping = mapping;
        hlist_add_head(&abe->list, &batch_hash[bucket]);
        return;
index e4b75d6eda839d6fddae166904d1002f85a4d09f..5365527ca43fec37cdc021afbc21acf76c321889 100644 (file)
@@ -111,10 +111,9 @@ struct file *anon_inode_getfile(const char *name,
        path.mnt = mntget(anon_inode_mnt);
        /*
         * We know the anon_inode inode count is always greater than zero,
-        * so we can avoid doing an igrab() and we can use an open-coded
-        * atomic_inc().
+        * so ihold() is safe.
         */
-       atomic_inc(&anon_inode_inode->i_count);
+       ihold(anon_inode_inode);
 
        path.dentry->d_op = &anon_inodefs_dentry_operations;
        d_instantiate(path.dentry, anon_inode_inode);
@@ -194,6 +193,7 @@ static struct inode *anon_inode_mkinode(void)
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
+       inode->i_ino = get_next_ino();
        inode->i_fop = &anon_inode_fops;
 
        inode->i_mapping->a_ops = &anon_aops;
index 821b2b955dac2c7b847a91d7abc91d4e0162c838..ac87e49fa70604e4b8238cd95fbae7a3cc1dcb07 100644 (file)
@@ -398,6 +398,7 @@ struct inode *autofs4_get_inode(struct super_block *sb,
                inode->i_gid = sb->s_root->d_inode->i_gid;
        }
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_ino = get_next_ino();
 
        if (S_ISDIR(inf->mode)) {
                inode->i_nlink = 2;
index d967e052b779d80490e08e097f5849ddc88ae48d..685ecff3ab31728d2362a9be39f98dfbc76947c4 100644 (file)
@@ -176,7 +176,7 @@ static int bfs_link(struct dentry *old, struct inode *dir,
        inc_nlink(inode);
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(new, inode);
        mutex_unlock(&info->bfs_lock);
        return 0;
index 139fc8083f53cbd9351b3c4ebeeedc79f30102b4..29990f0eee0c90adb18771c2c327fc99ee32c765 100644 (file)
@@ -495,6 +495,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
        struct inode * inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_atime = inode->i_mtime = inode->i_ctime =
                        current_fs_time(inode->i_sb);
index b737451e2e9dde95ae0d098b0443f44af1d21899..dea3b628a6ce9a9058c24d2b13c364b7c6adb3c3 100644 (file)
@@ -48,6 +48,21 @@ inline struct block_device *I_BDEV(struct inode *inode)
 
 EXPORT_SYMBOL(I_BDEV);
 
+/*
+ * move the inode from it's current bdi to the a new bdi. if the inode is dirty
+ * we need to move it onto the dirty list of @dst so that the inode is always
+ * on the right list.
+ */
+static void bdev_inode_switch_bdi(struct inode *inode,
+                       struct backing_dev_info *dst)
+{
+       spin_lock(&inode_lock);
+       inode->i_data.backing_dev_info = dst;
+       if (inode->i_state & I_DIRTY)
+               list_move(&inode->i_wb_list, &dst->wb.b_dirty);
+       spin_unlock(&inode_lock);
+}
+
 static sector_t max_block(struct block_device *bdev)
 {
        sector_t retval = ~((sector_t)0);
@@ -550,7 +565,7 @@ EXPORT_SYMBOL(bdget);
  */
 struct block_device *bdgrab(struct block_device *bdev)
 {
-       atomic_inc(&bdev->bd_inode->i_count);
+       ihold(bdev->bd_inode);
        return bdev;
 }
 
@@ -580,7 +595,7 @@ static struct block_device *bd_acquire(struct inode *inode)
        spin_lock(&bdev_lock);
        bdev = inode->i_bdev;
        if (bdev) {
-               atomic_inc(&bdev->bd_inode->i_count);
+               ihold(bdev->bd_inode);
                spin_unlock(&bdev_lock);
                return bdev;
        }
@@ -591,12 +606,12 @@ static struct block_device *bd_acquire(struct inode *inode)
                spin_lock(&bdev_lock);
                if (!inode->i_bdev) {
                        /*
-                        * We take an additional bd_inode->i_count for inode,
+                        * We take an additional reference to bd_inode,
                         * and it's released in clear_inode() of inode.
                         * So, we can access it via ->i_mapping always
                         * without igrab().
                         */
-                       atomic_inc(&bdev->bd_inode->i_count);
+                       ihold(bdev->bd_inode);
                        inode->i_bdev = bdev;
                        inode->i_mapping = bdev->bd_inode->i_mapping;
                        list_add(&inode->i_devices, &bdev->bd_inodes);
@@ -1390,7 +1405,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                bdi = blk_get_backing_dev_info(bdev);
                                if (bdi == NULL)
                                        bdi = &default_backing_dev_info;
-                               bdev->bd_inode->i_data.backing_dev_info = bdi;
+                               bdev_inode_switch_bdi(bdev->bd_inode, bdi);
                        }
                        if (bdev->bd_invalidated)
                                rescan_partitions(disk, bdev);
@@ -1405,8 +1420,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        if (ret)
                                goto out_clear;
                        bdev->bd_contains = whole;
-                       bdev->bd_inode->i_data.backing_dev_info =
-                          whole->bd_inode->i_data.backing_dev_info;
+                       bdev_inode_switch_bdi(bdev->bd_inode,
+                               whole->bd_inode->i_data.backing_dev_info);
                        bdev->bd_part = disk_get_part(disk, partno);
                        if (!(disk->flags & GENHD_FL_UP) ||
                            !bdev->bd_part || !bdev->bd_part->nr_sects) {
@@ -1439,7 +1454,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        disk_put_part(bdev->bd_part);
        bdev->bd_disk = NULL;
        bdev->bd_part = NULL;
-       bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+       bdev_inode_switch_bdi(bdev->bd_inode, &default_backing_dev_info);
        if (bdev != bdev->bd_contains)
                __blkdev_put(bdev->bd_contains, mode, 1);
        bdev->bd_contains = NULL;
@@ -1533,7 +1548,8 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
                disk_put_part(bdev->bd_part);
                bdev->bd_part = NULL;
                bdev->bd_disk = NULL;
-               bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+               bdev_inode_switch_bdi(bdev->bd_inode,
+                                       &default_backing_dev_info);
                if (bdev != bdev->bd_contains)
                        victim = bdev->bd_contains;
                bdev->bd_contains = NULL;
index c03864406af3ed49b66599fc1cdace0b2bbd2e22..64f99cf69ce0c6b2da2cb62c4884fa44c150bdda 100644 (file)
@@ -3849,7 +3849,7 @@ again:
        p = &root->inode_tree.rb_node;
        parent = NULL;
 
-       if (hlist_unhashed(&inode->i_hash))
+       if (inode_unhashed(inode))
                return;
 
        spin_lock(&root->inode_lock);
@@ -4758,7 +4758,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        }
 
        btrfs_set_trans_block_group(trans, dir);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        err = btrfs_add_nondir(trans, dentry, inode, 1, index);
 
index 7f0b9b083f778676ed3024fbecf6c8a77fd399bc..5930e382959bc504c58bbb428588a372742d4aa4 100644 (file)
@@ -905,7 +905,6 @@ try_again:
 
                bh->b_state = 0;
                atomic_set(&bh->b_count, 0);
-               bh->b_private = NULL;
                bh->b_size = size;
 
                /* Link the buffer to its page */
@@ -1706,7 +1705,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
                 * and kswapd activity, but those code paths have their own
                 * higher-level throttling.
                 */
-               if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+               if (wbc->sync_mode != WB_SYNC_NONE) {
                        lock_buffer(bh);
                } else if (!trylock_buffer(bh)) {
                        redirty_page_for_writepage(wbc, page);
@@ -1834,9 +1833,11 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
 }
 EXPORT_SYMBOL(page_zero_new_buffers);
 
-int block_prepare_write(struct page *page, unsigned from, unsigned to,
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
                get_block_t *get_block)
 {
+       unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+       unsigned to = from + len;
        struct inode *inode = page->mapping->host;
        unsigned block_start, block_end;
        sector_t block;
@@ -1916,7 +1917,7 @@ int block_prepare_write(struct page *page, unsigned from, unsigned to,
        }
        return err;
 }
-EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(__block_write_begin);
 
 static int __block_commit_write(struct inode *inode, struct page *page,
                unsigned from, unsigned to)
@@ -1953,15 +1954,6 @@ static int __block_commit_write(struct inode *inode, struct page *page,
        return 0;
 }
 
-int __block_write_begin(struct page *page, loff_t pos, unsigned len,
-               get_block_t *get_block)
-{
-       unsigned start = pos & (PAGE_CACHE_SIZE - 1);
-
-       return block_prepare_write(page, start, start + len, get_block);
-}
-EXPORT_SYMBOL(__block_write_begin);
-
 /*
  * block_write_begin takes care of the basic task of block allocation and
  * bringing partial write blocks uptodate first.
@@ -2379,7 +2371,7 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
        else
                end = PAGE_CACHE_SIZE;
 
-       ret = block_prepare_write(page, 0, end, get_block);
+       ret = __block_write_begin(page, 0, end, get_block);
        if (!ret)
                ret = block_commit_write(page, 0, end);
 
@@ -2466,11 +2458,10 @@ int nobh_write_begin(struct address_space *mapping,
        *fsdata = NULL;
 
        if (page_has_buffers(page)) {
-               unlock_page(page);
-               page_cache_release(page);
-               *pagep = NULL;
-               return block_write_begin(mapping, pos, len, flags, pagep,
-                                        get_block);
+               ret = __block_write_begin(page, pos, len, get_block);
+               if (unlikely(ret))
+                       goto out_release;
+               return ret;
        }
 
        if (PageMappedToDisk(page))
index 51bcc5ce323024a995d300b4a6035ecf8e72e94b..e9c874abc9e1f4a7ec00b68595fdd674a4f1da2e 100644 (file)
@@ -591,7 +591,6 @@ static int ceph_writepages_start(struct address_space *mapping,
                                 struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc;
        pgoff_t index, start, end;
@@ -633,13 +632,6 @@ static int ceph_writepages_start(struct address_space *mapping,
 
        pagevec_init(&pvec, 0);
 
-       /* ?? */
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               dout(" writepages congested\n");
-               wbc->encountered_congestion = 1;
-               goto out_final;
-       }
-
        /* where to start/end? */
        if (wbc->range_cyclic) {
                start = mapping->writeback_index; /* Start from prev offset */
@@ -885,7 +877,6 @@ out:
                rc = 0;  /* vfs expects us to return 0 */
        ceph_put_snap_context(snapc);
        dout("writepages done, rc = %d\n", rc);
-out_final:
        return rc;
 }
 
index 8c81e7b14d53d5d347cf0701d5d65ef8cafb328e..45af003865d2607da7eb0f9ffdc43eed18f82b4d 100644 (file)
@@ -1303,7 +1303,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 static int cifs_writepages(struct address_space *mapping,
                           struct writeback_control *wbc)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        unsigned int bytes_to_write;
        unsigned int bytes_written;
        struct cifs_sb_info *cifs_sb;
@@ -1326,15 +1325,6 @@ static int cifs_writepages(struct address_space *mapping,
        int scanned = 0;
        int xid, long_op;
 
-       /*
-        * BB: Is this meaningful for a non-block-device file system?
-        * If it is, we should test it again after we do I/O
-        */
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
        cifs_sb = CIFS_SB(mapping->host->i_sb);
 
        /*
index a5bf5771a22a5ad1a1fbee69f8e55aa5b8723094..9060f08e70cf10d79eb224dccd40b601398e2a26 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
@@ -31,19 +32,23 @@ void coda_cache_enter(struct inode *inode, int mask)
 {
        struct coda_inode_info *cii = ITOC(inode);
 
+       spin_lock(&cii->c_lock);
        cii->c_cached_epoch = atomic_read(&permission_epoch);
        if (cii->c_uid != current_fsuid()) {
                cii->c_uid = current_fsuid();
                 cii->c_cached_perm = mask;
         } else
                 cii->c_cached_perm |= mask;
+       spin_unlock(&cii->c_lock);
 }
 
 /* remove cached acl from an inode */
 void coda_cache_clear_inode(struct inode *inode)
 {
        struct coda_inode_info *cii = ITOC(inode);
+       spin_lock(&cii->c_lock);
        cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
+       spin_unlock(&cii->c_lock);
 }
 
 /* remove all acl caches */
@@ -57,13 +62,15 @@ void coda_cache_clear_all(struct super_block *sb)
 int coda_cache_check(struct inode *inode, int mask)
 {
        struct coda_inode_info *cii = ITOC(inode);
-        int hit;
+       int hit;
        
-        hit = (mask & cii->c_cached_perm) == mask &&
-               cii->c_uid == current_fsuid() &&
-               cii->c_cached_epoch == atomic_read(&permission_epoch);
+       spin_lock(&cii->c_lock);
+       hit = (mask & cii->c_cached_perm) == mask &&
+           cii->c_uid == current_fsuid() &&
+           cii->c_cached_epoch == atomic_read(&permission_epoch);
+       spin_unlock(&cii->c_lock);
 
-        return hit;
+       return hit;
 }
 
 
index a7a780929eecb90c624d8fbd155bd32cea228f47..602240569c89ace556721e0f4d9c954bfd27c491 100644 (file)
@@ -45,13 +45,15 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
 static int coda_test_inode(struct inode *inode, void *data)
 {
        struct CodaFid *fid = (struct CodaFid *)data;
-       return coda_fideq(&(ITOC(inode)->c_fid), fid);
+       struct coda_inode_info *cii = ITOC(inode);
+       return coda_fideq(&cii->c_fid, fid);
 }
 
 static int coda_set_inode(struct inode *inode, void *data)
 {
        struct CodaFid *fid = (struct CodaFid *)data;
-       ITOC(inode)->c_fid = *fid;
+       struct coda_inode_info *cii = ITOC(inode);
+       cii->c_fid = *fid;
        return 0;
 }
 
@@ -71,6 +73,7 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
                cii = ITOC(inode);
                /* we still need to set i_ino for things like stat(2) */
                inode->i_ino = hash;
+               /* inode is locked and unique, no need to grab cii->c_lock */
                cii->c_mapcount = 0;
                unlock_new_inode(inode);
        }
@@ -107,14 +110,20 @@ int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_bloc
 }
 
 
+/* Although we treat Coda file identifiers as immutable, there is one
+ * special case for files created during a disconnection where they may
+ * not be globally unique. When an identifier collision is detected we
+ * first try to flush the cached inode from the kernel and finally
+ * resort to renaming/rehashing in-place. Userspace remembers both old
+ * and new values of the identifier to handle any in-flight upcalls.
+ * The real solution is to use globally unique UUIDs as identifiers, but
+ * retrofitting the existing userspace code for this is non-trivial. */
 void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid, 
                      struct CodaFid *newfid)
 {
-       struct coda_inode_info *cii;
+       struct coda_inode_info *cii = ITOC(inode);
        unsigned long hash = coda_f2i(newfid);
        
-       cii = ITOC(inode);
-
        BUG_ON(!coda_fideq(&cii->c_fid, oldfid));
 
        /* replace fid and rehash inode */
index ccd98b0f2b0b9c3d37f10b101a86b36572054240..5d8b35539601b819389057b9114dd49a75828597 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -116,15 +116,11 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
                goto exit;
        }
 
-       lock_kernel();
-
        error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
                             &type, &resfid);
        if (!error)
                error = coda_cnode_make(&inode, &resfid, dir->i_sb);
 
-       unlock_kernel();
-
        if (error && error != -ENOENT)
                return ERR_PTR(error);
 
@@ -140,28 +136,24 @@ exit:
 
 int coda_permission(struct inode *inode, int mask)
 {
-        int error = 0;
+       int error;
 
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
  
        if (!mask)
-               return 0; 
+               return 0;
 
        if ((mask & MAY_EXEC) && !execute_ok(inode))
                return -EACCES;
 
-       lock_kernel();
-
        if (coda_cache_check(inode, mask))
-               goto out; 
+               return 0;
 
-        error = venus_access(inode->i_sb, coda_i2f(inode), mask);
+       error = venus_access(inode->i_sb, coda_i2f(inode), mask);
     
        if (!error)
                coda_cache_enter(inode, mask);
 
- out:
-       unlock_kernel();
        return error;
 }
 
@@ -200,41 +192,34 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
 /* creation routines: create, mknod, mkdir, link, symlink */
 static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
 {
-        int error=0;
+       int error;
        const char *name=de->d_name.name;
        int length=de->d_name.len;
        struct inode *inode;
        struct CodaFid newfid;
        struct coda_vattr attrs;
 
-       lock_kernel();
-
-       if (coda_isroot(dir) && coda_iscontrol(name, length)) {
-               unlock_kernel();
+       if (coda_isroot(dir) && coda_iscontrol(name, length))
                return -EPERM;
-       }
 
        error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 
                                0, mode, &newfid, &attrs);
-
-        if ( error ) {
-               unlock_kernel();
-               d_drop(de);
-               return error;
-       }
+       if (error)
+               goto err_out;
 
        inode = coda_iget(dir->i_sb, &newfid, &attrs);
-       if ( IS_ERR(inode) ) {
-               unlock_kernel();
-               d_drop(de);
-               return PTR_ERR(inode);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
+               goto err_out;
        }
 
        /* invalidate the directory cnode's attributes */
        coda_dir_update_mtime(dir);
-       unlock_kernel();
        d_instantiate(de, inode);
        return 0;
+err_out:
+       d_drop(de);
+       return error;
 }
 
 static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -246,36 +231,29 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        int error;
        struct CodaFid newfid;
 
-       lock_kernel();
-
-       if (coda_isroot(dir) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        attrs.va_mode = mode;
        error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
                               name, len, &newfid, &attrs);
-        
-        if ( error ) {
-               unlock_kernel();
-               d_drop(de);
-               return error;
-        }
+       if (error)
+               goto err_out;
          
        inode = coda_iget(dir->i_sb, &newfid, &attrs);
-       if ( IS_ERR(inode) ) {
-               unlock_kernel();
-               d_drop(de);
-               return PTR_ERR(inode);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
+               goto err_out;
        }
 
        /* invalidate the directory cnode's attributes */
        coda_dir_inc_nlink(dir);
        coda_dir_update_mtime(dir);
-       unlock_kernel();
        d_instantiate(de, inode);
        return 0;
+err_out:
+       d_drop(de);
+       return error;
 }
 
 /* try to make de an entry in dir_inodde linked to source_de */ 
@@ -287,52 +265,38 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
        int len = de->d_name.len;
        int error;
 
-       lock_kernel();
-
-       if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        error = venus_link(dir_inode->i_sb, coda_i2f(inode),
                           coda_i2f(dir_inode), (const char *)name, len);
-
        if (error) {
                d_drop(de);
-               goto out;
+               return error;
        }
 
        coda_dir_update_mtime(dir_inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(de, inode);
        inc_nlink(inode);
-
-out:
-       unlock_kernel();
-       return(error);
+       return 0;
 }
 
 
 static int coda_symlink(struct inode *dir_inode, struct dentry *de,
                        const char *symname)
 {
-        const char *name = de->d_name.name;
+       const char *name = de->d_name.name;
        int len = de->d_name.len;
        int symlen;
-       int error = 0;
-
-       lock_kernel();
+       int error;
 
-       if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        symlen = strlen(symname);
-       if ( symlen > CODA_MAXPATHLEN ) {
-               unlock_kernel();
+       if (symlen > CODA_MAXPATHLEN)
                return -ENAMETOOLONG;
-       }
 
        /*
         * This entry is now negative. Since we do not create
@@ -343,10 +307,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
                              symname, symlen);
 
        /* mtime is no good anymore */
-       if ( !error )
+       if (!error)
                coda_dir_update_mtime(dir_inode);
 
-       unlock_kernel();
        return error;
 }
 
@@ -357,17 +320,12 @@ static int coda_unlink(struct inode *dir, struct dentry *de)
        const char *name = de->d_name.name;
        int len = de->d_name.len;
 
-       lock_kernel();
-
        error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
-       if ( error ) {
-               unlock_kernel();
+       if (error)
                return error;
-       }
 
        coda_dir_update_mtime(dir);
        drop_nlink(de->d_inode);
-       unlock_kernel();
        return 0;
 }
 
@@ -377,8 +335,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
        int len = de->d_name.len;
        int error;
 
-       lock_kernel();
-
        error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
        if (!error) {
                /* VFS may delete the child */
@@ -389,7 +345,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
                coda_dir_drop_nlink(dir);
                coda_dir_update_mtime(dir);
        }
-       unlock_kernel();
        return error;
 }
 
@@ -403,15 +358,12 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
        int new_length = new_dentry->d_name.len;
        int error;
 
-       lock_kernel();
-
        error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
                             coda_i2f(new_dir), old_length, new_length,
                             (const char *) old_name, (const char *)new_name);
-
-       if ( !error ) {
-               if ( new_dentry->d_inode ) {
-                       if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+       if (!error) {
+               if (new_dentry->d_inode) {
+                       if (S_ISDIR(new_dentry->d_inode->i_mode)) {
                                coda_dir_drop_nlink(old_dir);
                                coda_dir_inc_nlink(new_dir);
                        }
@@ -423,8 +375,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
                        coda_flag_inode(new_dir, C_VATTR);
                }
        }
-       unlock_kernel();
-
        return error;
 }
 
@@ -594,10 +544,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
        struct inode *inode = de->d_inode;
        struct coda_inode_info *cii;
 
-       if (!inode)
-               return 1;
-       lock_kernel();
-       if (coda_isroot(inode))
+       if (!inode || coda_isroot(inode))
                goto out;
        if (is_bad_inode(inode))
                goto bad;
@@ -617,13 +564,12 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
                goto out;
 
        /* clear the flags. */
+       spin_lock(&cii->c_lock);
        cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
-
+       spin_unlock(&cii->c_lock);
 bad:
-       unlock_kernel();
        return 0;
 out:
-       unlock_kernel();
        return 1;
 }
 
@@ -656,20 +602,19 @@ static int coda_dentry_delete(struct dentry * dentry)
 int coda_revalidate_inode(struct dentry *dentry)
 {
        struct coda_vattr attr;
-       int error = 0;
+       int error;
        int old_mode;
        ino_t old_ino;
        struct inode *inode = dentry->d_inode;
        struct coda_inode_info *cii = ITOC(inode);
 
-       lock_kernel();
-       if ( !cii->c_flags )
-               goto ok;
+       if (!cii->c_flags)
+               return 0;
 
        if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
                error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
-               if ( error )
-                       goto return_bad;
+               if (error)
+                       return -EIO;
 
                /* this inode may be lost if:
                   - it's ino changed 
@@ -688,17 +633,13 @@ int coda_revalidate_inode(struct dentry *dentry)
                /* the following can happen when a local fid is replaced 
                   with a global one, here we lose and declare the inode bad */
                if (inode->i_ino != old_ino)
-                       goto return_bad;
+                       return -EIO;
                
                coda_flag_inode_children(inode, C_FLUSH);
+
+               spin_lock(&cii->c_lock);
                cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
+               spin_unlock(&cii->c_lock);
        }
-
-ok:
-       unlock_kernel();
        return 0;
-
-return_bad:
-       unlock_kernel();
-       return -EIO;
 }
index ad3cd2abeeb48e561cadf63f65f9ae8d105dd621..c8b50ba4366a3a2aa0531ea61037ac9615edaaa0 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/stat.h>
 #include <linux/cred.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
@@ -109,19 +109,24 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 
        coda_inode = coda_file->f_path.dentry->d_inode;
        host_inode = host_file->f_path.dentry->d_inode;
+
+       cii = ITOC(coda_inode);
+       spin_lock(&cii->c_lock);
        coda_file->f_mapping = host_file->f_mapping;
        if (coda_inode->i_mapping == &coda_inode->i_data)
                coda_inode->i_mapping = host_inode->i_mapping;
 
        /* only allow additional mmaps as long as userspace isn't changing
         * the container file on us! */
-       else if (coda_inode->i_mapping != host_inode->i_mapping)
+       else if (coda_inode->i_mapping != host_inode->i_mapping) {
+               spin_unlock(&cii->c_lock);
                return -EBUSY;
+       }
 
        /* keep track of how often the coda_inode/host_file has been mmapped */
-       cii = ITOC(coda_inode);
        cii->c_mapcount++;
        cfi->cfi_mapcount++;
+       spin_unlock(&cii->c_lock);
 
        return host_file->f_op->mmap(host_file, vma);
 }
@@ -138,8 +143,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
        if (!cfi)
                return -ENOMEM;
 
-       lock_kernel();
-
        error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
                           &host_file);
        if (!host_file)
@@ -147,7 +150,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
 
        if (error) {
                kfree(cfi);
-               unlock_kernel();
                return error;
        }
 
@@ -159,8 +161,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
 
        BUG_ON(coda_file->private_data != NULL);
        coda_file->private_data = cfi;
-
-       unlock_kernel();
        return 0;
 }
 
@@ -171,9 +171,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        struct coda_file_info *cfi;
        struct coda_inode_info *cii;
        struct inode *host_inode;
-       int err = 0;
-
-       lock_kernel();
+       int err;
 
        cfi = CODA_FTOC(coda_file);
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -185,18 +183,18 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        cii = ITOC(coda_inode);
 
        /* did we mmap this file? */
+       spin_lock(&cii->c_lock);
        if (coda_inode->i_mapping == &host_inode->i_data) {
                cii->c_mapcount -= cfi->cfi_mapcount;
                if (!cii->c_mapcount)
                        coda_inode->i_mapping = &coda_inode->i_data;
        }
+       spin_unlock(&cii->c_lock);
 
        fput(cfi->cfi_container);
        kfree(coda_file->private_data);
        coda_file->private_data = NULL;
 
-       unlock_kernel();
-
        /* VFS fput ignores the return value from file_operations->release, so
         * there is no use returning an error here */
        return 0;
@@ -207,7 +205,7 @@ int coda_fsync(struct file *coda_file, int datasync)
        struct file *host_file;
        struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
        struct coda_file_info *cfi;
-       int err = 0;
+       int err;
 
        if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
              S_ISLNK(coda_inode->i_mode)))
@@ -218,11 +216,8 @@ int coda_fsync(struct file *coda_file, int datasync)
        host_file = cfi->cfi_container;
 
        err = vfs_fsync(host_file, datasync);
-       if ( !err && !datasync ) {
-               lock_kernel();
+       if (!err && !datasync)
                err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
-               unlock_kernel();
-       }
 
        return err;
 }
index bfe8179b1295e76ea4433fce9d2533e240eed840..7993b96ca348cdf6910fc60e048b61847c8d7097 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/file.h>
 #include <linux/vfs.h>
 #include <linux/slab.h>
@@ -51,6 +52,7 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
        ei->c_flags = 0;
        ei->c_uid = 0;
        ei->c_cached_perm = 0;
+       spin_lock_init(&ei->c_lock);
        return &ei->vfs_inode;
 }
 
@@ -143,13 +145,11 @@ static int get_device_index(struct coda_mount_data *data)
 static int coda_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *root = NULL;
-       struct venus_comm *vc = NULL;
+       struct venus_comm *vc;
        struct CodaFid fid;
        int error;
        int idx;
 
-       lock_kernel();
-
        idx = get_device_index((struct coda_mount_data *) data);
 
        /* Ignore errors in data, for backward compatibility */
@@ -159,23 +159,26 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
        printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
 
        vc = &coda_comms[idx];
+       mutex_lock(&vc->vc_mutex);
+
        if (!vc->vc_inuse) {
                printk("coda_read_super: No pseudo device\n");
-               unlock_kernel();
-               return -EINVAL;
+               error = -EINVAL;
+               goto unlock_out;
        }
 
-        if ( vc->vc_sb ) {
+       if (vc->vc_sb) {
                printk("coda_read_super: Device already mounted\n");
-               unlock_kernel();
-               return -EBUSY;
+               error = -EBUSY;
+               goto unlock_out;
        }
 
        error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
        if (error)
-               goto bdi_err;
+               goto unlock_out;
 
        vc->vc_sb = sb;
+       mutex_unlock(&vc->vc_mutex);
 
        sb->s_fs_info = vc;
        sb->s_flags |= MS_NOATIME;
@@ -204,28 +207,33 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
        printk("coda_read_super: rootinode is %ld dev %s\n", 
               root->i_ino, root->i_sb->s_id);
        sb->s_root = d_alloc_root(root);
-       if (!sb->s_root)
+       if (!sb->s_root) {
+               error = -EINVAL;
                goto error;
-       unlock_kernel();
+       }
        return 0;
 
- error:
-       bdi_destroy(&vc->bdi);
- bdi_err:
+error:
        if (root)
                iput(root);
-       if (vc)
-               vc->vc_sb = NULL;
 
-       unlock_kernel();
-       return -EINVAL;
+       mutex_lock(&vc->vc_mutex);
+       bdi_destroy(&vc->bdi);
+       vc->vc_sb = NULL;
+       sb->s_fs_info = NULL;
+unlock_out:
+       mutex_unlock(&vc->vc_mutex);
+       return error;
 }
 
 static void coda_put_super(struct super_block *sb)
 {
-       bdi_destroy(&coda_vcp(sb)->bdi);
-       coda_vcp(sb)->vc_sb = NULL;
+       struct venus_comm *vcp = coda_vcp(sb);
+       mutex_lock(&vcp->vc_mutex);
+       bdi_destroy(&vcp->bdi);
+       vcp->vc_sb = NULL;
        sb->s_fs_info = NULL;
+       mutex_unlock(&vcp->vc_mutex);
 
        printk("Coda: Bye bye.\n");
 }
@@ -251,8 +259,6 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
        struct coda_vattr vattr;
        int error;
 
-       lock_kernel();
-       
        memset(&vattr, 0, sizeof(vattr)); 
 
        inode->i_ctime = CURRENT_TIME_SEC;
@@ -262,13 +268,10 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
        /* Venus is responsible for truncating the container-file!!! */
        error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
 
-       if ( !error ) {
+       if (!error) {
                coda_vattr_to_iattr(inode, &vattr); 
                coda_cache_clear_inode(inode);
        }
-
-       unlock_kernel();
-
        return error;
 }
 
@@ -282,12 +285,8 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        int error;
        
-       lock_kernel();
-
        error = venus_statfs(dentry, buf);
 
-       unlock_kernel();
-
        if (error) {
                /* fake something like AFS does */
                buf->f_blocks = 9000000;
index 028a9a0f588b2664cee7ab65a3a7f8ccc88af61c..2fd89b5c5c7b06eab16db7a6b644520ef8476462 100644 (file)
@@ -23,8 +23,6 @@
 #include <linux/coda_fs_i.h>
 #include <linux/coda_psdev.h>
 
-#include <linux/smp_lock.h>
-
 /* pioctl ops */
 static int coda_ioctl_permission(struct inode *inode, int mask);
 static long coda_pioctl(struct file *filp, unsigned int cmd,
@@ -58,13 +56,9 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
        struct inode *target_inode = NULL;
        struct coda_inode_info *cnp;
 
-       lock_kernel();
-
        /* get the Pioctl data arguments from user space */
-       if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
-               error = -EINVAL;
-               goto out;
-       }
+       if (copy_from_user(&data, (void __user *)user_data, sizeof(data)))
+               return -EINVAL;
 
        /*
         * Look up the pathname. Note that the pathname is in
@@ -76,13 +70,12 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
                error = user_lpath(data.path, &path);
 
        if (error)
-               goto out;
-       else
-               target_inode = path.dentry->d_inode;
+               return error;
+
+       target_inode = path.dentry->d_inode;
 
        /* return if it is not a Coda inode */
        if (target_inode->i_sb != inode->i_sb) {
-               path_put(&path);
                error = -EINVAL;
                goto out;
        }
@@ -91,10 +84,7 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
        cnp = ITOC(target_inode);
 
        error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
-
-       path_put(&path);
-
 out:
-       unlock_kernel();
+       path_put(&path);
        return error;
 }
index fdc2f3ef7ecd6768d856511fb1cf12e7689282a5..62647a8595e47e2efcef12bc772620102fb7eaf8 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/device.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -67,8 +67,10 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
        unsigned int mask = POLLOUT | POLLWRNORM;
 
        poll_wait(file, &vcp->vc_waitq, wait);
+       mutex_lock(&vcp->vc_mutex);
        if (!list_empty(&vcp->vc_pending))
                 mask |= POLLIN | POLLRDNORM;
+       mutex_unlock(&vcp->vc_mutex);
 
        return mask;
 }
@@ -108,16 +110,9 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
                return -EFAULT;
 
         if (DOWNCALL(hdr.opcode)) {
-               struct super_block *sb = NULL;
-                union outputArgs *dcbuf;
+               union outputArgs *dcbuf;
                int size = sizeof(*dcbuf);
 
-               sb = vcp->vc_sb;
-               if ( !sb ) {
-                        count = nbytes;
-                        goto out;
-               }
-
                if  ( nbytes < sizeof(struct coda_out_hdr) ) {
                        printk("coda_downcall opc %d uniq %d, not enough!\n",
                               hdr.opcode, hdr.unique);
@@ -137,9 +132,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
                }
 
                /* what downcall errors does Venus handle ? */
-               lock_kernel();
-               error = coda_downcall(hdr.opcode, dcbuf, sb);
-               unlock_kernel();
+               error = coda_downcall(vcp, hdr.opcode, dcbuf);
 
                CODA_FREE(dcbuf, nbytes);
                if (error) {
@@ -152,7 +145,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
        }
         
        /* Look for the message on the processing queue. */
-       lock_kernel();
+       mutex_lock(&vcp->vc_mutex);
        list_for_each(lh, &vcp->vc_processing) {
                tmp = list_entry(lh, struct upc_req , uc_chain);
                if (tmp->uc_unique == hdr.unique) {
@@ -161,7 +154,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
                        break;
                }
        }
-       unlock_kernel();
+       mutex_unlock(&vcp->vc_mutex);
 
        if (!req) {
                printk("psdev_write: msg (%d, %d) not found\n", 
@@ -216,7 +209,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
        if (nbytes == 0)
                return 0;
 
-       lock_kernel();
+       mutex_lock(&vcp->vc_mutex);
 
        add_wait_queue(&vcp->vc_waitq, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
@@ -230,7 +223,9 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
                        retval = -ERESTARTSYS;
                        break;
                }
+               mutex_unlock(&vcp->vc_mutex);
                schedule();
+               mutex_lock(&vcp->vc_mutex);
        }
 
        set_current_state(TASK_RUNNING);
@@ -263,7 +258,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
        CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
        kfree(req);
 out:
-       unlock_kernel();
+       mutex_unlock(&vcp->vc_mutex);
        return (count ? count : retval);
 }
 
@@ -276,10 +271,10 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
        if (idx < 0 || idx >= MAX_CODADEVS)
                return -ENODEV;
 
-       lock_kernel();
-
        err = -EBUSY;
        vcp = &coda_comms[idx];
+       mutex_lock(&vcp->vc_mutex);
+
        if (!vcp->vc_inuse) {
                vcp->vc_inuse++;
 
@@ -293,7 +288,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
                err = 0;
        }
 
-       unlock_kernel();
+       mutex_unlock(&vcp->vc_mutex);
        return err;
 }
 
@@ -308,7 +303,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
                return -1;
        }
 
-       lock_kernel();
+       mutex_lock(&vcp->vc_mutex);
 
        /* Wakeup clients so they can return. */
        list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
@@ -333,7 +328,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
 
        file->private_data = NULL;
        vcp->vc_inuse--;
-       unlock_kernel();
+       mutex_unlock(&vcp->vc_mutex);
        return 0;
 }
 
@@ -362,9 +357,11 @@ static int init_coda_psdev(void)
                err = PTR_ERR(coda_psdev_class);
                goto out_chrdev;
        }               
-       for (i = 0; i < MAX_CODADEVS; i++)
+       for (i = 0; i < MAX_CODADEVS; i++) {
+               mutex_init(&(&coda_comms[i])->vc_mutex);
                device_create(coda_psdev_class, NULL,
                              MKDEV(CODA_PSDEV_MAJOR, i), NULL, "cfs%d", i);
+       }
        coda_sysctl_init();
        goto out;
 
index 4513b7258458716a082255c3d5a438592c505671..af78f007a2b0565418bf94b7793e7927315d2953 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
@@ -29,11 +28,9 @@ static int coda_symlink_filler(struct file *file, struct page *page)
        unsigned int len = PAGE_SIZE;
        char *p = kmap(page);
 
-       lock_kernel();
        cii = ITOC(inode);
 
        error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
-       unlock_kernel();
        if (error)
                goto fail;
        SetPageUptodate(page);
index b8893ab6f9e63acd5b15dfaac8489f5a996b524b..c3563cab9758423da3c90faa69ac6374a458855b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/vfs.h>
@@ -606,7 +607,8 @@ static void coda_unblock_signals(sigset_t *old)
                                 (r)->uc_opcode != CODA_RELEASE) || \
                                (r)->uc_flags & CODA_REQ_READ))
 
-static inline void coda_waitfor_upcall(struct upc_req *req)
+static inline void coda_waitfor_upcall(struct venus_comm *vcp,
+                                      struct upc_req *req)
 {
        DECLARE_WAITQUEUE(wait, current);
        unsigned long timeout = jiffies + coda_timeout * HZ;
@@ -639,10 +641,12 @@ static inline void coda_waitfor_upcall(struct upc_req *req)
                        break;
                }
 
+               mutex_unlock(&vcp->vc_mutex);
                if (blocked)
                        schedule_timeout(HZ);
                else
                        schedule();
+               mutex_lock(&vcp->vc_mutex);
        }
        if (blocked)
                coda_unblock_signals(&old);
@@ -667,18 +671,23 @@ static int coda_upcall(struct venus_comm *vcp,
 {
        union outputArgs *out;
        union inputArgs *sig_inputArgs;
-       struct upc_req *req, *sig_req;
-       int error = 0;
+       struct upc_req *req = NULL, *sig_req;
+       int error;
+
+       mutex_lock(&vcp->vc_mutex);
 
        if (!vcp->vc_inuse) {
                printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
-               return -ENXIO;
+               error = -ENXIO;
+               goto exit;
        }
 
        /* Format the request message. */
        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
-       if (!req)
-               return -ENOMEM;
+       if (!req) {
+               error = -ENOMEM;
+               goto exit;
+       }
 
        req->uc_data = (void *)buffer;
        req->uc_flags = 0;
@@ -705,7 +714,7 @@ static int coda_upcall(struct venus_comm *vcp,
         * ENODEV.  */
 
        /* Go to sleep.  Wake up on signals only after the timeout. */
-       coda_waitfor_upcall(req);
+       coda_waitfor_upcall(vcp, req);
 
        /* Op went through, interrupt or not... */
        if (req->uc_flags & CODA_REQ_WRITE) {
@@ -759,6 +768,7 @@ static int coda_upcall(struct venus_comm *vcp,
 
 exit:
        kfree(req);
+       mutex_unlock(&vcp->vc_mutex);
        return error;
 }
 
@@ -796,21 +806,24 @@ exit:
  *
  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 
-int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
 {
        struct inode *inode = NULL;
-       struct CodaFid *fid, *newfid;
+       struct CodaFid *fid = NULL, *newfid;
+       struct super_block *sb;
 
        /* Handle invalidation requests. */
-       if ( !sb || !sb->s_root)
-               return 0;
+       mutex_lock(&vcp->vc_mutex);
+       sb = vcp->vc_sb;
+       if (!sb || !sb->s_root)
+               goto unlock_out;
 
        switch (opcode) {
        case CODA_FLUSH:
                coda_cache_clear_all(sb);
                shrink_dcache_sb(sb);
                if (sb->s_root->d_inode)
-                   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+                       coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
                break;
 
        case CODA_PURGEUSER:
@@ -819,45 +832,53 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 
        case CODA_ZAPDIR:
                fid = &out->coda_zapdir.CodaFid;
-               inode = coda_fid_to_inode(fid, sb);
-               if (inode) {
-                       coda_flag_inode_children(inode, C_PURGE);
-                       coda_flag_inode(inode, C_VATTR);
-               }
                break;
 
        case CODA_ZAPFILE:
                fid = &out->coda_zapfile.CodaFid;
-               inode = coda_fid_to_inode(fid, sb);
-               if (inode)
-                       coda_flag_inode(inode, C_VATTR);
                break;
 
        case CODA_PURGEFID:
                fid = &out->coda_purgefid.CodaFid;
+               break;
+
+       case CODA_REPLACE:
+               fid = &out->coda_replace.OldFid;
+               break;
+       }
+       if (fid)
                inode = coda_fid_to_inode(fid, sb);
-               if (inode) {
-                       coda_flag_inode_children(inode, C_PURGE);
 
-                       /* catch the dentries later if some are still busy */
-                       coda_flag_inode(inode, C_PURGE);
-                       d_prune_aliases(inode);
+unlock_out:
+       mutex_unlock(&vcp->vc_mutex);
 
-               }
+       if (!inode)
+               return 0;
+
+       switch (opcode) {
+       case CODA_ZAPDIR:
+               coda_flag_inode_children(inode, C_PURGE);
+               coda_flag_inode(inode, C_VATTR);
+               break;
+
+       case CODA_ZAPFILE:
+               coda_flag_inode(inode, C_VATTR);
+               break;
+
+       case CODA_PURGEFID:
+               coda_flag_inode_children(inode, C_PURGE);
+
+               /* catch the dentries later if some are still busy */
+               coda_flag_inode(inode, C_PURGE);
+               d_prune_aliases(inode);
                break;
 
        case CODA_REPLACE:
-               fid = &out->coda_replace.OldFid;
                newfid = &out->coda_replace.NewFid;
-               inode = coda_fid_to_inode(fid, sb);
-               if (inode)
-                       coda_replace_fid(inode, fid, newfid);
+               coda_replace_fid(inode, fid, newfid);
                break;
        }
-
-       if (inode)
-               iput(inode);
-
+       iput(inode);
        return 0;
 }
 
index 0644a154672b93012a4d7a7f864ba7f505b43213..f03abdadc401d2266375dc3328cb977cecc41fdc 100644 (file)
@@ -1963,7 +1963,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
 }
 #endif /* HAVE_SET_RESTORE_SIGMASK */
 
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && !defined(CONFIG_NFSD_DEPRECATED)
 /* Stuff for NFS server syscalls... */
 struct compat_nfsctl_svc {
        u16                     svc32_port;
index cf78d44a8d6a8bcff1a546e3606058de97e90722..253476d78ed86f4d07ec04e3ef63578fccdfa223 100644 (file)
@@ -135,6 +135,7 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
 {
        struct inode * inode = new_inode(configfs_sb);
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mapping->a_ops = &configfs_aops;
                inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
                inode->i_op = &configfs_inode_operations;
index 83293be4814965373d4c81e5b7d91bc63f3a55c6..23702a9d4e6d130b6ef226d1157f1a484f93a282 100644 (file)
@@ -67,33 +67,43 @@ struct dentry_stat_t dentry_stat = {
        .age_limit = 45,
 };
 
-static void __d_free(struct dentry *dentry)
+static struct percpu_counter nr_dentry __cacheline_aligned_in_smp;
+static struct percpu_counter nr_dentry_unused __cacheline_aligned_in_smp;
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
+                  size_t *lenp, loff_t *ppos)
+{
+       dentry_stat.nr_dentry = percpu_counter_sum_positive(&nr_dentry);
+       dentry_stat.nr_unused = percpu_counter_sum_positive(&nr_dentry_unused);
+       return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+#endif
+
+static void __d_free(struct rcu_head *head)
 {
+       struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
+
        WARN_ON(!list_empty(&dentry->d_alias));
        if (dname_external(dentry))
                kfree(dentry->d_name.name);
        kmem_cache_free(dentry_cache, dentry); 
 }
 
-static void d_callback(struct rcu_head *head)
-{
-       struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu);
-       __d_free(dentry);
-}
-
 /*
- * no dcache_lock, please.  The caller must decrement dentry_stat.nr_dentry
- * inside dcache_lock.
+ * no dcache_lock, please.
  */
 static void d_free(struct dentry *dentry)
 {
+       percpu_counter_dec(&nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
+
        /* if dentry was never inserted into hash, immediate free is OK */
        if (hlist_unhashed(&dentry->d_hash))
-               __d_free(dentry);
+               __d_free(&dentry->d_u.d_rcu);
        else
-               call_rcu(&dentry->d_u.d_rcu, d_callback);
+               call_rcu(&dentry->d_u.d_rcu, __d_free);
 }
 
 /*
@@ -123,37 +133,34 @@ static void dentry_iput(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|add_tail|del|del_init) must be called with dcache_lock held.
+ * dentry_lru_(add|del|move_tail) must be called with dcache_lock held.
  */
 static void dentry_lru_add(struct dentry *dentry)
 {
-       list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
-       dentry->d_sb->s_nr_dentry_unused++;
-       dentry_stat.nr_unused++;
-}
-
-static void dentry_lru_add_tail(struct dentry *dentry)
-{
-       list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
-       dentry->d_sb->s_nr_dentry_unused++;
-       dentry_stat.nr_unused++;
+       if (list_empty(&dentry->d_lru)) {
+               list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+               dentry->d_sb->s_nr_dentry_unused++;
+               percpu_counter_inc(&nr_dentry_unused);
+       }
 }
 
 static void dentry_lru_del(struct dentry *dentry)
 {
        if (!list_empty(&dentry->d_lru)) {
-               list_del(&dentry->d_lru);
+               list_del_init(&dentry->d_lru);
                dentry->d_sb->s_nr_dentry_unused--;
-               dentry_stat.nr_unused--;
+               percpu_counter_dec(&nr_dentry_unused);
        }
 }
 
-static void dentry_lru_del_init(struct dentry *dentry)
+static void dentry_lru_move_tail(struct dentry *dentry)
 {
-       if (likely(!list_empty(&dentry->d_lru))) {
-               list_del_init(&dentry->d_lru);
-               dentry->d_sb->s_nr_dentry_unused--;
-               dentry_stat.nr_unused--;
+       if (list_empty(&dentry->d_lru)) {
+               list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+               dentry->d_sb->s_nr_dentry_unused++;
+               percpu_counter_inc(&nr_dentry_unused);
+       } else {
+               list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
        }
 }
 
@@ -172,7 +179,6 @@ static struct dentry *d_kill(struct dentry *dentry)
        struct dentry *parent;
 
        list_del(&dentry->d_u.d_child);
-       dentry_stat.nr_dentry--;        /* For d_free, below */
        /*drops the locks, at that point nobody can reach this dentry */
        dentry_iput(dentry);
        if (IS_ROOT(dentry))
@@ -237,13 +243,15 @@ repeat:
                if (dentry->d_op->d_delete(dentry))
                        goto unhash_it;
        }
+
        /* Unreachable? Get rid of it */
        if (d_unhashed(dentry))
                goto kill_it;
-       if (list_empty(&dentry->d_lru)) {
-               dentry->d_flags |= DCACHE_REFERENCED;
-               dentry_lru_add(dentry);
-       }
+
+       /* Otherwise leave it cached and ensure it's on the LRU */
+       dentry->d_flags |= DCACHE_REFERENCED;
+       dentry_lru_add(dentry);
+
        spin_unlock(&dentry->d_lock);
        spin_unlock(&dcache_lock);
        return;
@@ -318,11 +326,10 @@ int d_invalidate(struct dentry * dentry)
 EXPORT_SYMBOL(d_invalidate);
 
 /* This should be called _only_ with dcache_lock held */
-
 static inline struct dentry * __dget_locked(struct dentry *dentry)
 {
        atomic_inc(&dentry->d_count);
-       dentry_lru_del_init(dentry);
+       dentry_lru_del(dentry);
        return dentry;
 }
 
@@ -441,73 +448,27 @@ static void prune_one_dentry(struct dentry * dentry)
 
                if (dentry->d_op && dentry->d_op->d_delete)
                        dentry->d_op->d_delete(dentry);
-               dentry_lru_del_init(dentry);
+               dentry_lru_del(dentry);
                __d_drop(dentry);
                dentry = d_kill(dentry);
                spin_lock(&dcache_lock);
        }
 }
 
-/*
- * Shrink the dentry LRU on a given superblock.
- * @sb   : superblock to shrink dentry LRU.
- * @count: If count is NULL, we prune all dentries on superblock.
- * @flags: If flags is non-zero, we need to do special processing based on
- * which flags are set. This means we don't need to maintain multiple
- * similar copies of this loop.
- */
-static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
+static void shrink_dentry_list(struct list_head *list)
 {
-       LIST_HEAD(referenced);
-       LIST_HEAD(tmp);
        struct dentry *dentry;
-       int cnt = 0;
 
-       BUG_ON(!sb);
-       BUG_ON((flags & DCACHE_REFERENCED) && count == NULL);
-       spin_lock(&dcache_lock);
-       if (count != NULL)
-               /* called from prune_dcache() and shrink_dcache_parent() */
-               cnt = *count;
-restart:
-       if (count == NULL)
-               list_splice_init(&sb->s_dentry_lru, &tmp);
-       else {
-               while (!list_empty(&sb->s_dentry_lru)) {
-                       dentry = list_entry(sb->s_dentry_lru.prev,
-                                       struct dentry, d_lru);
-                       BUG_ON(dentry->d_sb != sb);
+       while (!list_empty(list)) {
+               dentry = list_entry(list->prev, struct dentry, d_lru);
+               dentry_lru_del(dentry);
 
-                       spin_lock(&dentry->d_lock);
-                       /*
-                        * If we are honouring the DCACHE_REFERENCED flag and
-                        * the dentry has this flag set, don't free it. Clear
-                        * the flag and put it back on the LRU.
-                        */
-                       if ((flags & DCACHE_REFERENCED)
-                               && (dentry->d_flags & DCACHE_REFERENCED)) {
-                               dentry->d_flags &= ~DCACHE_REFERENCED;
-                               list_move(&dentry->d_lru, &referenced);
-                               spin_unlock(&dentry->d_lock);
-                       } else {
-                               list_move_tail(&dentry->d_lru, &tmp);
-                               spin_unlock(&dentry->d_lock);
-                               cnt--;
-                               if (!cnt)
-                                       break;
-                       }
-                       cond_resched_lock(&dcache_lock);
-               }
-       }
-       while (!list_empty(&tmp)) {
-               dentry = list_entry(tmp.prev, struct dentry, d_lru);
-               dentry_lru_del_init(dentry);
-               spin_lock(&dentry->d_lock);
                /*
                 * We found an inuse dentry which was not removed from
                 * the LRU because of laziness during lookup.  Do not free
                 * it - just keep it off the LRU list.
                 */
+               spin_lock(&dentry->d_lock);
                if (atomic_read(&dentry->d_count)) {
                        spin_unlock(&dentry->d_lock);
                        continue;
@@ -516,13 +477,60 @@ restart:
                /* dentry->d_lock was dropped in prune_one_dentry() */
                cond_resched_lock(&dcache_lock);
        }
-       if (count == NULL && !list_empty(&sb->s_dentry_lru))
-               goto restart;
-       if (count != NULL)
-               *count = cnt;
+}
+
+/**
+ * __shrink_dcache_sb - shrink the dentry LRU on a given superblock
+ * @sb:                superblock to shrink dentry LRU.
+ * @count:     number of entries to prune
+ * @flags:     flags to control the dentry processing
+ *
+ * If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
+ */
+static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
+{
+       /* called from prune_dcache() and shrink_dcache_parent() */
+       struct dentry *dentry;
+       LIST_HEAD(referenced);
+       LIST_HEAD(tmp);
+       int cnt = *count;
+
+       spin_lock(&dcache_lock);
+       while (!list_empty(&sb->s_dentry_lru)) {
+               dentry = list_entry(sb->s_dentry_lru.prev,
+                               struct dentry, d_lru);
+               BUG_ON(dentry->d_sb != sb);
+
+               /*
+                * If we are honouring the DCACHE_REFERENCED flag and the
+                * dentry has this flag set, don't free it.  Clear the flag
+                * and put it back on the LRU.
+                */
+               if (flags & DCACHE_REFERENCED) {
+                       spin_lock(&dentry->d_lock);
+                       if (dentry->d_flags & DCACHE_REFERENCED) {
+                               dentry->d_flags &= ~DCACHE_REFERENCED;
+                               list_move(&dentry->d_lru, &referenced);
+                               spin_unlock(&dentry->d_lock);
+                               cond_resched_lock(&dcache_lock);
+                               continue;
+                       }
+                       spin_unlock(&dentry->d_lock);
+               }
+
+               list_move_tail(&dentry->d_lru, &tmp);
+               if (!--cnt)
+                       break;
+               cond_resched_lock(&dcache_lock);
+       }
+
+       *count = cnt;
+       shrink_dentry_list(&tmp);
+
        if (!list_empty(&referenced))
                list_splice(&referenced, &sb->s_dentry_lru);
        spin_unlock(&dcache_lock);
+
 }
 
 /**
@@ -538,7 +546,7 @@ static void prune_dcache(int count)
 {
        struct super_block *sb, *p = NULL;
        int w_count;
-       int unused = dentry_stat.nr_unused;
+       int unused = percpu_counter_sum_positive(&nr_dentry_unused);
        int prune_ratio;
        int pruned;
 
@@ -608,13 +616,19 @@ static void prune_dcache(int count)
  * shrink_dcache_sb - shrink dcache for a superblock
  * @sb: superblock
  *
- * Shrink the dcache for the specified super block. This
- * is used to free the dcache before unmounting a file
- * system
+ * Shrink the dcache for the specified super block. This is used to free
+ * the dcache before unmounting a file system.
  */
-void shrink_dcache_sb(struct super_block * sb)
+void shrink_dcache_sb(struct super_block *sb)
 {
-       __shrink_dcache_sb(sb, NULL, 0);
+       LIST_HEAD(tmp);
+
+       spin_lock(&dcache_lock);
+       while (!list_empty(&sb->s_dentry_lru)) {
+               list_splice_init(&sb->s_dentry_lru, &tmp);
+               shrink_dentry_list(&tmp);
+       }
+       spin_unlock(&dcache_lock);
 }
 EXPORT_SYMBOL(shrink_dcache_sb);
 
@@ -632,7 +646,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 
        /* detach this root from the system */
        spin_lock(&dcache_lock);
-       dentry_lru_del_init(dentry);
+       dentry_lru_del(dentry);
        __d_drop(dentry);
        spin_unlock(&dcache_lock);
 
@@ -646,7 +660,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
                        spin_lock(&dcache_lock);
                        list_for_each_entry(loop, &dentry->d_subdirs,
                                            d_u.d_child) {
-                               dentry_lru_del_init(loop);
+                               dentry_lru_del(loop);
                                __d_drop(loop);
                                cond_resched_lock(&dcache_lock);
                        }
@@ -703,20 +717,13 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
                         * otherwise we ascend to the parent and move to the
                         * next sibling if there is one */
                        if (!parent)
-                               goto out;
-
+                               return;
                        dentry = parent;
-
                } while (list_empty(&dentry->d_subdirs));
 
                dentry = list_entry(dentry->d_subdirs.next,
                                    struct dentry, d_u.d_child);
        }
-out:
-       /* several dentries were freed, need to correct nr_dentry */
-       spin_lock(&dcache_lock);
-       dentry_stat.nr_dentry -= detached;
-       spin_unlock(&dcache_lock);
 }
 
 /*
@@ -830,14 +837,15 @@ resume:
                struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
                next = tmp->next;
 
-               dentry_lru_del_init(dentry);
                /* 
                 * move only zero ref count dentries to the end 
                 * of the unused list for prune_dcache
                 */
                if (!atomic_read(&dentry->d_count)) {
-                       dentry_lru_add_tail(dentry);
+                       dentry_lru_move_tail(dentry);
                        found++;
+               } else {
+                       dentry_lru_del(dentry);
                }
 
                /*
@@ -900,12 +908,16 @@ EXPORT_SYMBOL(shrink_dcache_parent);
  */
 static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
 {
+       int nr_unused;
+
        if (nr) {
                if (!(gfp_mask & __GFP_FS))
                        return -1;
                prune_dcache(nr);
        }
-       return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
+
+       nr_unused = percpu_counter_sum_positive(&nr_dentry_unused);
+       return (nr_unused / 100) * sysctl_vfs_cache_pressure;
 }
 
 static struct shrinker dcache_shrinker = {
@@ -972,9 +984,10 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        spin_lock(&dcache_lock);
        if (parent)
                list_add(&dentry->d_u.d_child, &parent->d_subdirs);
-       dentry_stat.nr_dentry++;
        spin_unlock(&dcache_lock);
 
+       percpu_counter_inc(&nr_dentry);
+
        return dentry;
 }
 EXPORT_SYMBOL(d_alloc);
@@ -1478,33 +1491,26 @@ out:
  * This is used by ncpfs in its readdir implementation.
  * Zero is returned in the dentry is invalid.
  */
-int d_validate(struct dentry *dentry, struct dentry *dparent)
+int d_validate(struct dentry *dentry, struct dentry *parent)
 {
-       struct hlist_head *base;
-       struct hlist_node *lhp;
+       struct hlist_head *head = d_hash(parent, dentry->d_name.hash);
+       struct hlist_node *node;
+       struct dentry *d;
 
        /* Check whether the ptr might be valid at all.. */
        if (!kmem_ptr_validate(dentry_cache, dentry))
-               goto out;
-
-       if (dentry->d_parent != dparent)
-               goto out;
+               return 0;
+       if (dentry->d_parent != parent)
+               return 0;
 
-       spin_lock(&dcache_lock);
-       base = d_hash(dparent, dentry->d_name.hash);
-       hlist_for_each(lhp,base) { 
-               /* hlist_for_each_entry_rcu() not required for d_hash list
-                * as it is parsed under dcache_lock
-                */
-               if (dentry == hlist_entry(lhp, struct dentry, d_hash)) {
-                       __dget_locked(dentry);
-                       spin_unlock(&dcache_lock);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(d, node, head, d_hash) {
+               if (d == dentry) {
+                       dget(dentry);
                        return 1;
                }
        }
-       spin_unlock(&dcache_lock);
-out:
+       rcu_read_unlock();
        return 0;
 }
 EXPORT_SYMBOL(d_validate);
@@ -1994,7 +2000,7 @@ global_root:
  * Returns a pointer into the buffer or an error code if the
  * path was too long.
  *
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * "buflen" should be positive.
  *
  * If path is not reachable from the supplied root, then the value of
  * root is changed (without modifying refcounts).
@@ -2006,10 +2012,12 @@ char *__d_path(const struct path *path, struct path *root,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
+       spin_lock(&dcache_lock);
        error = prepend_path(path, root, &res, &buflen);
+       spin_unlock(&dcache_lock);
+
        if (error)
                return ERR_PTR(error);
-
        return res;
 }
 
@@ -2419,6 +2427,9 @@ static void __init dcache_init(void)
 {
        int loop;
 
+       percpu_counter_init(&nr_dentry, 0);
+       percpu_counter_init(&nr_dentry_unused, 0);
+
        /* 
         * A constructor could be added for stable state like the lists,
         * but it is probably not worth it because of the cache nature
index 30a87b3dbcac1286de7fa400f6855b2937796d5b..a4ed8380e98a630197edf4c556b8f4067a1c872f 100644 (file)
@@ -40,6 +40,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
        struct inode *inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                switch (mode & S_IFMT) {
index 48d74c7391d13f4f07393c45d19825e937ecbcd1..85882f6ba5f73c66b614a79ad3594a3dab5dc2b0 100644 (file)
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio)
  * filesystems can use it to hold additional state between get_block calls and
  * dio_complete.
  */
-static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async)
+static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is_async)
 {
        ssize_t transferred = 0;
 
index 6d2b6f93685813ba2b2119dc71c14a941061cf46..3aa75b8888a14589f268f54a8a7b57c490cbcf9c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -54,6 +54,7 @@
 #include <linux/fsnotify.h>
 #include <linux/fs_struct.h>
 #include <linux/pipe_fs_i.h>
+#include <linux/oom.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -759,6 +760,10 @@ static int exec_mmap(struct mm_struct *mm)
        tsk->mm = mm;
        tsk->active_mm = mm;
        activate_mm(active_mm, mm);
+       if (old_mm && tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+               atomic_dec(&old_mm->oom_disable_count);
+               atomic_inc(&tsk->mm->oom_disable_count);
+       }
        task_unlock(tsk);
        arch_pick_mmap_layout(mm);
        if (old_mm) {
index d91e9d829bc1bcc52cce4c4965d375a3eb7d356f..dcc941d82d67dc60448c8d97521850034df15b00 100644 (file)
@@ -420,7 +420,7 @@ int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
        err = exofs_write_begin(NULL, page->mapping, pos, len,
                                AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
        if (err)
-               EXOFS_ERR("exofs_set_link: exofs_write_begin FAILD => %d\n",
+               EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n",
                          err);
 
        de->inode_no = cpu_to_le64(inode->i_ino);
@@ -556,7 +556,7 @@ int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
        err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
                                                        &page, NULL);
        if (err)
-               EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILD => %d\n",
+               EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n",
                          err);
        if (pde)
                pde->rec_len = cpu_to_le16(to - from);
index 68cb23e3bb9828e88c2647a7f028db6d2f94bd78..b905c79b4f0afc88b7a1997009960f09f50f595f 100644 (file)
@@ -46,10 +46,6 @@ static int exofs_file_fsync(struct file *filp, int datasync)
 {
        int ret;
        struct inode *inode = filp->f_mapping->host;
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 0, /* metadata-only; caller takes care of data */
-       };
        struct super_block *sb;
 
        if (!(inode->i_state & I_DIRTY))
@@ -57,7 +53,7 @@ static int exofs_file_fsync(struct file *filp, int datasync)
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
                return 0;
 
-       ret = sync_inode(inode, &wbc);
+       ret = sync_inode_metadata(inode, 1);
 
        /* This is a good place to write the sb */
        /* TODO: Sechedule an sb-sync on create */
index 44602754f758c903f9e201206afecbbbb4fad3e4..42685424817b5d846cbf411bcff815f62f023fa4 100644 (file)
@@ -185,7 +185,7 @@ static void update_write_page(struct page *page, int ret)
 /* Called at the end of reads, to optionally unlock pages and update their
  * status.
  */
-static int __readpages_done(struct page_collect *pcol, bool do_unlock)
+static int __readpages_done(struct page_collect *pcol)
 {
        int i;
        u64 resid;
@@ -221,7 +221,7 @@ static int __readpages_done(struct page_collect *pcol, bool do_unlock)
                          page_stat ? "bad_bytes" : "good_bytes");
 
                ret = update_read_page(page, page_stat);
-               if (do_unlock)
+               if (!pcol->read_4_write)
                        unlock_page(page);
                length += PAGE_SIZE;
        }
@@ -236,7 +236,7 @@ static void readpages_done(struct exofs_io_state *ios, void *p)
 {
        struct page_collect *pcol = p;
 
-       __readpages_done(pcol, true);
+       __readpages_done(pcol);
        atomic_dec(&pcol->sbi->s_curr_pending);
        kfree(pcol);
 }
@@ -257,7 +257,7 @@ static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
        }
 }
 
-static int read_exec(struct page_collect *pcol, bool is_sync)
+static int read_exec(struct page_collect *pcol)
 {
        struct exofs_i_info *oi = exofs_i(pcol->inode);
        struct exofs_io_state *ios = pcol->ios;
@@ -267,17 +267,14 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
        if (!pcol->pages)
                return 0;
 
-       /* see comment in _readpage() about sync reads */
-       WARN_ON(is_sync && (pcol->nr_pages != 1));
-
        ios->pages = pcol->pages;
        ios->nr_pages = pcol->nr_pages;
        ios->length = pcol->length;
        ios->offset = pcol->pg_first << PAGE_CACHE_SHIFT;
 
-       if (is_sync) {
+       if (pcol->read_4_write) {
                exofs_oi_read(oi, pcol->ios);
-               return __readpages_done(pcol, false);
+               return __readpages_done(pcol);
        }
 
        pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
@@ -303,7 +300,7 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
        return 0;
 
 err:
-       if (!is_sync)
+       if (!pcol->read_4_write)
                _unlock_pcol_pages(pcol, ret, READ);
 
        pcol_free(pcol);
@@ -356,7 +353,7 @@ static int readpage_strip(void *data, struct page *page)
                EXOFS_DBGMSG("readpage_strip(0x%lx, 0x%lx) empty page,"
                             " splitting\n", inode->i_ino, page->index);
 
-               return read_exec(pcol, false);
+               return read_exec(pcol);
        }
 
 try_again:
@@ -366,7 +363,7 @@ try_again:
        } else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
                   page->index)) {
                /* Discontinuity detected, split the request */
-               ret = read_exec(pcol, false);
+               ret = read_exec(pcol);
                if (unlikely(ret))
                        goto fail;
                goto try_again;
@@ -391,7 +388,7 @@ try_again:
                          page, len, pcol->nr_pages, pcol->length);
 
                /* split the request, and start again with current page */
-               ret = read_exec(pcol, false);
+               ret = read_exec(pcol);
                if (unlikely(ret))
                        goto fail;
 
@@ -420,27 +417,24 @@ static int exofs_readpages(struct file *file, struct address_space *mapping,
                return ret;
        }
 
-       return read_exec(&pcol, false);
+       return read_exec(&pcol);
 }
 
-static int _readpage(struct page *page, bool is_sync)
+static int _readpage(struct page *page, bool read_4_write)
 {
        struct page_collect pcol;
        int ret;
 
        _pcol_init(&pcol, 1, page->mapping->host);
 
-       /* readpage_strip might call read_exec(,is_sync==false) at several
-        * places but not if we have a single page.
-        */
-       pcol.read_4_write = is_sync;
+       pcol.read_4_write = read_4_write;
        ret = readpage_strip(&pcol, page);
        if (ret) {
                EXOFS_ERR("_readpage => %d\n", ret);
                return ret;
        }
 
-       return read_exec(&pcol, is_sync);
+       return read_exec(&pcol);
 }
 
 /*
@@ -1036,6 +1030,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
        }
 
+       inode->i_mapping->backing_dev_info = sb->s_bdi;
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &exofs_file_inode_operations;
                inode->i_fop = &exofs_file_operations;
@@ -1072,8 +1067,10 @@ bad_inode:
 int __exofs_wait_obj_created(struct exofs_i_info *oi)
 {
        if (!obj_created(oi)) {
+               EXOFS_DBGMSG("!obj_created\n");
                BUG_ON(!obj_2bcreated(oi));
                wait_event(oi->i_wq, obj_created(oi));
+               EXOFS_DBGMSG("wait_event done\n");
        }
        return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
 }
@@ -1107,7 +1104,6 @@ static void create_done(struct exofs_io_state *ios, void *p)
 
        set_obj_created(oi);
 
-       atomic_dec(&inode->i_count);
        wake_up(&oi->i_wq);
 }
 
@@ -1135,6 +1131,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
 
        sbi = sb->s_fs_info;
 
+       inode->i_mapping->backing_dev_info = sb->s_bdi;
        sb->s_dirt = 1;
        inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
@@ -1157,17 +1154,11 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
        ios->obj.id = exofs_oi_objno(oi);
        exofs_make_credential(oi->i_cred, &ios->obj);
 
-       /* increment the refcount so that the inode will still be around when we
-        * reach the callback
-        */
-       atomic_inc(&inode->i_count);
-
        ios->done = create_done;
        ios->private = inode;
        ios->cred = oi->i_cred;
        ret = exofs_sbi_create(ios);
        if (ret) {
-               atomic_dec(&inode->i_count);
                exofs_put_io_state(ios);
                return ERR_PTR(ret);
        }
@@ -1257,12 +1248,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
        ios->out_attr_len = 1;
        ios->out_attr = &attr;
 
-       if (!obj_created(oi)) {
-               EXOFS_DBGMSG("!obj_created\n");
-               BUG_ON(!obj_2bcreated(oi));
-               wait_event(oi->i_wq, obj_created(oi));
-               EXOFS_DBGMSG("wait_event done\n");
-       }
+       wait_obj_created(oi);
 
        if (!do_sync) {
                args->sbi = sbi;
@@ -1325,12 +1311,12 @@ void exofs_evict_inode(struct inode *inode)
        inode->i_size = 0;
        end_writeback(inode);
 
-       /* if we are deleting an obj that hasn't been created yet, wait */
-       if (!obj_created(oi)) {
-               BUG_ON(!obj_2bcreated(oi));
-               wait_event(oi->i_wq, obj_created(oi));
-               /* ignore the error attempt a remove anyway */
-       }
+       /* if we are deleting an obj that hasn't been created yet, wait.
+        * This also makes sure that create_done cannot be called with an
+        * already evicted inode.
+        */
+       wait_obj_created(oi);
+       /* ignore the error, attempt a remove anyway */
 
        /* Now Remove the OSD objects */
        ret = exofs_get_io_state(&sbi->layout, &ios);
index b7dd0c23686376822ffd40c185bc9b1683796d31..264e95d02830f28d992eefb717460ccd0be09d4d 100644 (file)
@@ -153,7 +153,7 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir,
 
        inode->i_ctime = CURRENT_TIME;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        return exofs_add_nondir(dentry, inode);
 }
index e9e175949a637822a8689e757362673284af0d29..51b304056f10fcd47c18593a9a12bf56e8633063 100644 (file)
@@ -74,21 +74,20 @@ static struct dentry *
 find_disconnected_root(struct dentry *dentry)
 {
        dget(dentry);
-       spin_lock(&dentry->d_lock);
-       while (!IS_ROOT(dentry) &&
-              (dentry->d_parent->d_flags & DCACHE_DISCONNECTED)) {
-               struct dentry *parent = dentry->d_parent;
-               dget(parent);
-               spin_unlock(&dentry->d_lock);
+       while (!IS_ROOT(dentry)) {
+               struct dentry *parent = dget_parent(dentry);
+
+               if (!(parent->d_flags & DCACHE_DISCONNECTED)) {
+                       dput(parent);
+                       break;
+               }
+
                dput(dentry);
                dentry = parent;
-               spin_lock(&dentry->d_lock);
        }
-       spin_unlock(&dentry->d_lock);
        return dentry;
 }
 
-
 /*
  * Make sure target_dir is fully connected to the dentry tree.
  *
index 764109886ec00f8f8bfafed187e88d7ebed63202..2709b34206abdbc442377c2d02ed0d17e5959ec9 100644 (file)
@@ -98,7 +98,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
        if (IS_DIRSYNC(dir)) {
                err = write_one_page(page, 1);
                if (!err)
-                       err = ext2_sync_inode(dir);
+                       err = sync_inode_metadata(dir, 1);
        } else {
                unlock_page(page);
        }
index 416daa62242c5410e99ea455dca1854ddfbc0353..6346a2acf326075b2e23739a2ba9b55ce6d56c33 100644 (file)
@@ -120,7 +120,6 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 extern struct inode *ext2_iget (struct super_block *, unsigned long);
 extern int ext2_write_inode (struct inode *, struct writeback_control *);
 extern void ext2_evict_inode(struct inode *);
-extern int ext2_sync_inode (struct inode *);
 extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
index 533699c1604060417e2fb3cdc42d61f5c9b52bdc..40ad210a5049a6eed9b184b3c30750ce6951fa46 100644 (file)
@@ -1203,7 +1203,7 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
        inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
        if (inode_needs_sync(inode)) {
                sync_mapping_buffers(inode->i_mapping);
-               ext2_sync_inode (inode);
+               sync_inode_metadata(inode, 1);
        } else {
                mark_inode_dirty(inode);
        }
@@ -1523,15 +1523,6 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
        return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
 }
 
-int ext2_sync_inode(struct inode *inode)
-{
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 0,       /* sys_fsync did this */
-       };
-       return sync_inode(inode, &wbc);
-}
-
 int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        struct inode *inode = dentry->d_inode;
index 71efb0e9a3f2ababa1ae74033e5caa73332fba61..f8aecd2e32976c40b1af182a13a312ae0b8e23fe 100644 (file)
@@ -206,7 +206,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        err = ext2_add_link(dentry, inode);
        if (!err) {
index 85df87d0f7b70a01dde7b39826f6d9abbeb08799..0901320671da20631092a1cc57113e9a0ef46d8d 100644 (file)
@@ -1221,9 +1221,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
        }
 
        es = sbi->s_es;
-       if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
-           (old_mount_opt & EXT2_MOUNT_XIP)) &&
-           invalidate_inodes(sb)) {
+       if ((sbi->s_mount_opt ^ old_mount_opt) & EXT2_MOUNT_XIP) {
                ext2_msg(sb, KERN_WARNING, "warning: refusing change of "
                         "xip flag with busy inodes while remounting");
                sbi->s_mount_opt &= ~EXT2_MOUNT_XIP;
index 8c29ae15129ed06bacb04727d4e2d6da17700960..f84700be3274292808c9cfa2b9517274d9b17fc1 100644 (file)
@@ -699,7 +699,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
        EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
        inode->i_ctime = CURRENT_TIME_SEC;
        if (IS_SYNC(inode)) {
-               error = ext2_sync_inode (inode);
+               error = sync_inode_metadata(inode, 1);
                /* In case sync failed due to ENOSPC the inode was actually
                 * written (only some dirty data were not) so we just proceed
                 * as if nothing happened and cleanup the unused block */
index 5e0faf4cda797800713a335f3c6d3d5d64fcd2c2..ad05353040a12338c1a0c84626abcfc20f96408f 100644 (file)
@@ -1696,8 +1696,8 @@ static int ext3_journalled_writepage(struct page *page,
                 * doesn't seem much point in redirtying the page here.
                 */
                ClearPageChecked(page);
-               ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                       ext3_get_block);
+               ret = __block_write_begin(page, 0, PAGE_CACHE_SIZE,
+                                         ext3_get_block);
                if (ret != 0) {
                        ext3_journal_stop(handle);
                        goto out_unlock;
index 2b35ddb70d65535a53f98268310ab377ea94e1f2..bce9dce639b874989fc687173531728842557c24 100644 (file)
@@ -2260,7 +2260,7 @@ retry:
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inc_nlink(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        err = ext3_add_entry(handle, dentry, inode);
        if (!err) {
index 4b8debeb39652fa0e10bcf36d397d6125c750d1a..49635ef236f84d40b0090a78a1a96860fae1fb6b 100644 (file)
@@ -1538,10 +1538,10 @@ static int do_journal_get_write_access(handle_t *handle,
        if (!buffer_mapped(bh) || buffer_freed(bh))
                return 0;
        /*
-        * __block_prepare_write() could have dirtied some buffers. Clean
+        * __block_write_begin() could have dirtied some buffers. Clean
         * the dirty bit as jbd2_journal_get_write_access() could complain
         * otherwise about fs integrity issues. Setting of the dirty bit
-        * by __block_prepare_write() isn't a real problem here as we clear
+        * by __block_write_begin() isn't a real problem here as we clear
         * the bit before releasing a page lock and thus writeback cannot
         * ever write the buffer.
         */
@@ -2550,8 +2550,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                if (buffer_delay(bh))
                        return 0; /* Not sure this could or should happen */
                /*
-                * XXX: __block_prepare_write() unmaps passed block,
-                * is it OK?
+                * XXX: __block_write_begin() unmaps passed block, is it OK?
                 */
                ret = ext4_da_reserve_space(inode, iblock);
                if (ret)
@@ -2583,7 +2582,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
 /*
  * This function is used as a standard get_block_t calback function
  * when there is no desire to allocate any blocks.  It is used as a
- * callback function for block_prepare_write() and block_write_full_page().
+ * callback function for block_write_begin() and block_write_full_page().
  * These functions should only try to map a single block at a time.
  *
  * Since this function doesn't do block allocations even if the caller
@@ -2743,7 +2742,7 @@ static int ext4_writepage(struct page *page,
                 * all are mapped and non delay. We don't want to
                 * do block allocation here.
                 */
-               ret = block_prepare_write(page, 0, len,
+               ret = __block_write_begin(page, 0, len,
                                          noalloc_get_block_write);
                if (!ret) {
                        page_bufs = page_buffers(page);
index 19aa0d44d82283680f462f1cc2b76fe2fe220618..42f77b1dc72d810f48deb583baeb0f984c6fbc61 100644 (file)
@@ -2373,6 +2373,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
                printk(KERN_ERR "EXT4-fs: can't get new inode\n");
                goto err_freesgi;
        }
+       sbi->s_buddy_cache->i_ino = get_next_ino();
        EXT4_I(sbi->s_buddy_cache)->i_disksize = 0;
        for (i = 0; i < ngroups; i++) {
                desc = ext4_get_group_desc(sb, i, NULL);
index 314c0d3b3fa9aece3015a113b6d348b7bc2be4aa..bd39885b599854329922fa443a016e405aeac1f9 100644 (file)
@@ -2312,7 +2312,7 @@ retry:
 
        inode->i_ctime = ext4_current_time(inode);
        ext4_inc_count(handle, inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
index f8cc34f542c3a1cc8b4f53309ffae317ecdddf15..ecc8b3954ed6ca2558cf9a34e1b60fa3b9513290 100644 (file)
@@ -640,7 +640,7 @@ static void fasync_free_rcu(struct rcu_head *head)
  * match the state "is the filp on a fasync list".
  *
  */
-static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
+int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
 {
        struct fasync_struct *fa, **fp;
        int result = 0;
@@ -666,21 +666,31 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
        return result;
 }
 
+struct fasync_struct *fasync_alloc(void)
+{
+       return kmem_cache_alloc(fasync_cache, GFP_KERNEL);
+}
+
 /*
- * Add a fasync entry. Return negative on error, positive if
- * added, and zero if did nothing but change an existing one.
+ * NOTE! This can be used only for unused fasync entries:
+ * entries that actually got inserted on the fasync list
+ * need to be released by rcu - see fasync_remove_entry.
+ */
+void fasync_free(struct fasync_struct *new)
+{
+       kmem_cache_free(fasync_cache, new);
+}
+
+/*
+ * Insert a new entry into the fasync list.  Return the pointer to the
+ * old one if we didn't use the new one.
  *
  * NOTE! It is very important that the FASYNC flag always
  * match the state "is the filp on a fasync list".
  */
-static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
+struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new)
 {
-       struct fasync_struct *new, *fa, **fp;
-       int result = 0;
-
-       new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
-       if (!new)
-               return -ENOMEM;
+        struct fasync_struct *fa, **fp;
 
        spin_lock(&filp->f_lock);
        spin_lock(&fasync_lock);
@@ -691,8 +701,6 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
                spin_lock_irq(&fa->fa_lock);
                fa->fa_fd = fd;
                spin_unlock_irq(&fa->fa_lock);
-
-               kmem_cache_free(fasync_cache, new);
                goto out;
        }
 
@@ -702,13 +710,39 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
        new->fa_fd = fd;
        new->fa_next = *fapp;
        rcu_assign_pointer(*fapp, new);
-       result = 1;
        filp->f_flags |= FASYNC;
 
 out:
        spin_unlock(&fasync_lock);
        spin_unlock(&filp->f_lock);
-       return result;
+       return fa;
+}
+
+/*
+ * Add a fasync entry. Return negative on error, positive if
+ * added, and zero if did nothing but change an existing one.
+ */
+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
+{
+       struct fasync_struct *new;
+
+       new = fasync_alloc();
+       if (!new)
+               return -ENOMEM;
+
+       /*
+        * fasync_insert_entry() returns the old (update) entry if
+        * it existed.
+        *
+        * So free the (unused) new entry and return 0 to let the
+        * caller know that we didn't add any new fasync entries.
+        */
+       if (fasync_insert_entry(fd, filp, fapp, new)) {
+               fasync_free(new);
+               return 0;
+       }
+
+       return 1;
 }
 
 /*
index a04bdd81c11ca3799d4429d8c5eb3579621e0628..c3dee381f1b4ea588f2188a33b3237f8efc251df 100644 (file)
@@ -60,7 +60,7 @@ static inline void file_free(struct file *f)
 /*
  * Return the total number of open files in the system
  */
-static int get_nr_files(void)
+static long get_nr_files(void)
 {
        return percpu_counter_read_positive(&nr_files);
 }
@@ -68,7 +68,7 @@ static int get_nr_files(void)
 /*
  * Return the maximum number of open files in the system
  */
-int get_max_files(void)
+unsigned long get_max_files(void)
 {
        return files_stat.max_files;
 }
@@ -82,7 +82,7 @@ int proc_nr_files(ctl_table *table, int write,
                      void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        files_stat.nr_files = get_nr_files();
-       return proc_dointvec(table, write, buffer, lenp, ppos);
+       return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 #else
 int proc_nr_files(ctl_table *table, int write,
@@ -105,7 +105,7 @@ int proc_nr_files(ctl_table *table, int write,
 struct file *get_empty_filp(void)
 {
        const struct cred *cred = current_cred();
-       static int old_max;
+       static long old_max;
        struct file * f;
 
        /*
@@ -140,8 +140,7 @@ struct file *get_empty_filp(void)
 over:
        /* Ran out of filps - report that */
        if (get_nr_files() > old_max) {
-               printk(KERN_INFO "VFS: file-max limit %d reached\n",
-                                       get_max_files());
+               pr_info("VFS: file-max limit %lu reached\n", get_max_files());
                old_max = get_nr_files();
        }
        goto fail;
@@ -487,7 +486,7 @@ retry:
 
 void __init files_init(unsigned long mempages)
 { 
-       int n; 
+       unsigned long n;
 
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
@@ -498,9 +497,7 @@ void __init files_init(unsigned long mempages)
         */ 
 
        n = (mempages * (PAGE_SIZE / 1024)) / 10;
-       files_stat.max_files = n; 
-       if (files_stat.max_files < NR_FILE)
-               files_stat.max_files = NR_FILE;
+       files_stat.max_files = max_t(unsigned long, n, NR_FILE);
        files_defer_init();
        lg_lock_init(files_lglock);
        percpu_counter_init(&nr_files, 0);
index 79d1b4ea13e79bc6531761ed817f0011653492bd..8c04eac5079d34d5ecdec820e23990294cc1d2ba 100644 (file)
@@ -260,6 +260,7 @@ vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
        struct inode                    *ip = NULL;
 
        if ((ip = new_inode(sbp))) {
+               ip->i_ino = get_next_ino();
                vxfs_iinit(ip, vip);
                ip->i_mapping->a_ops = &vxfs_aops;
        }
index ab38fef1c9a1a52eab7128fa6a7dad217d4ad744..aed881a76b229602ece291fb8c55fbd5ec45ee90 100644 (file)
@@ -79,6 +79,11 @@ static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
        return sb->s_bdi;
 }
 
+static inline struct inode *wb_inode(struct list_head *head)
+{
+       return list_entry(head, struct inode, i_wb_list);
+}
+
 static void bdi_queue_work(struct backing_dev_info *bdi,
                struct wb_writeback_work *work)
 {
@@ -172,11 +177,11 @@ static void redirty_tail(struct inode *inode)
        if (!list_empty(&wb->b_dirty)) {
                struct inode *tail;
 
-               tail = list_entry(wb->b_dirty.next, struct inode, i_list);
+               tail = wb_inode(wb->b_dirty.next);
                if (time_before(inode->dirtied_when, tail->dirtied_when))
                        inode->dirtied_when = jiffies;
        }
-       list_move(&inode->i_list, &wb->b_dirty);
+       list_move(&inode->i_wb_list, &wb->b_dirty);
 }
 
 /*
@@ -186,7 +191,7 @@ static void requeue_io(struct inode *inode)
 {
        struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 
-       list_move(&inode->i_list, &wb->b_more_io);
+       list_move(&inode->i_wb_list, &wb->b_more_io);
 }
 
 static void inode_sync_complete(struct inode *inode)
@@ -227,14 +232,14 @@ static void move_expired_inodes(struct list_head *delaying_queue,
        int do_sb_sort = 0;
 
        while (!list_empty(delaying_queue)) {
-               inode = list_entry(delaying_queue->prev, struct inode, i_list);
+               inode = wb_inode(delaying_queue->prev);
                if (older_than_this &&
                    inode_dirtied_after(inode, *older_than_this))
                        break;
                if (sb && sb != inode->i_sb)
                        do_sb_sort = 1;
                sb = inode->i_sb;
-               list_move(&inode->i_list, &tmp);
+               list_move(&inode->i_wb_list, &tmp);
        }
 
        /* just one sb in list, splice to dispatch_queue and we're done */
@@ -245,12 +250,11 @@ static void move_expired_inodes(struct list_head *delaying_queue,
 
        /* Move inodes from one superblock together */
        while (!list_empty(&tmp)) {
-               inode = list_entry(tmp.prev, struct inode, i_list);
-               sb = inode->i_sb;
+               sb = wb_inode(tmp.prev)->i_sb;
                list_for_each_prev_safe(pos, node, &tmp) {
-                       inode = list_entry(pos, struct inode, i_list);
+                       inode = wb_inode(pos);
                        if (inode->i_sb == sb)
-                               list_move(&inode->i_list, dispatch_queue);
+                               list_move(&inode->i_wb_list, dispatch_queue);
                }
        }
 }
@@ -408,16 +412,13 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
                         * completion.
                         */
                        redirty_tail(inode);
-               } else if (atomic_read(&inode->i_count)) {
-                       /*
-                        * The inode is clean, inuse
-                        */
-                       list_move(&inode->i_list, &inode_in_use);
                } else {
                        /*
-                        * The inode is clean, unused
+                        * The inode is clean.  At this point we either have
+                        * a reference to the inode or it's on it's way out.
+                        * No need to add it back to the LRU.
                         */
-                       list_move(&inode->i_list, &inode_unused);
+                       list_del_init(&inode->i_wb_list);
                }
        }
        inode_sync_complete(inode);
@@ -465,8 +466,7 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
 {
        while (!list_empty(&wb->b_io)) {
                long pages_skipped;
-               struct inode *inode = list_entry(wb->b_io.prev,
-                                                struct inode, i_list);
+               struct inode *inode = wb_inode(wb->b_io.prev);
 
                if (inode->i_sb != sb) {
                        if (only_this_sb) {
@@ -487,10 +487,16 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
                        return 0;
                }
 
-               if (inode->i_state & (I_NEW | I_WILL_FREE)) {
+               /*
+                * Don't bother with new inodes or inodes beeing freed, first
+                * kind does not need peridic writeout yet, and for the latter
+                * kind writeout is handled by the freer.
+                */
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
                        requeue_io(inode);
                        continue;
                }
+
                /*
                 * Was this inode dirtied after sync_sb_inodes was called?
                 * This keeps sync from extra jobs and livelock.
@@ -498,7 +504,6 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
                if (inode_dirtied_after(inode, wbc->wb_start))
                        return 1;
 
-               BUG_ON(inode->i_state & I_FREEING);
                __iget(inode);
                pages_skipped = wbc->pages_skipped;
                writeback_single_inode(inode, wbc);
@@ -536,8 +541,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb,
                queue_io(wb, wbc->older_than_this);
 
        while (!list_empty(&wb->b_io)) {
-               struct inode *inode = list_entry(wb->b_io.prev,
-                                                struct inode, i_list);
+               struct inode *inode = wb_inode(wb->b_io.prev);
                struct super_block *sb = inode->i_sb;
 
                if (!pin_sb_for_writeback(sb)) {
@@ -582,7 +586,7 @@ static inline bool over_bground_thresh(void)
        global_dirty_limits(&background_thresh, &dirty_thresh);
 
        return (global_page_state(NR_FILE_DIRTY) +
-               global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
+               global_page_state(NR_UNSTABLE_NFS) > background_thresh);
 }
 
 /*
@@ -675,8 +679,7 @@ static long wb_writeback(struct bdi_writeback *wb,
                 */
                spin_lock(&inode_lock);
                if (!list_empty(&wb->b_more_io))  {
-                       inode = list_entry(wb->b_more_io.prev,
-                                               struct inode, i_list);
+                       inode = wb_inode(wb->b_more_io.prev);
                        trace_wbc_writeback_wait(&wbc, wb->bdi);
                        inode_wait_for_writeback(inode);
                }
@@ -721,9 +724,13 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb)
                return 0;
 
        wb->last_old_flush = jiffies;
+       /*
+        * Add in the number of potentially dirty inodes, because each inode
+        * write can dirty pagecache in the underlying blockdev.
+        */
        nr_pages = global_page_state(NR_FILE_DIRTY) +
                        global_page_state(NR_UNSTABLE_NFS) +
-                       (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+                       get_nr_dirty_inodes();
 
        if (nr_pages) {
                struct wb_writeback_work work = {
@@ -790,7 +797,7 @@ int bdi_writeback_thread(void *data)
        struct backing_dev_info *bdi = wb->bdi;
        long pages_written;
 
-       current->flags |= PF_FLUSHER | PF_SWAPWRITE;
+       current->flags |= PF_SWAPWRITE;
        set_freezable();
        wb->last_active = jiffies;
 
@@ -962,7 +969,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                 * dirty list.  Add blockdev inodes as well.
                 */
                if (!S_ISBLK(inode->i_mode)) {
-                       if (hlist_unhashed(&inode->i_hash))
+                       if (inode_unhashed(inode))
                                goto out;
                }
                if (inode->i_state & I_FREEING)
@@ -990,7 +997,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                        }
 
                        inode->dirtied_when = jiffies;
-                       list_move(&inode->i_list, &bdi->wb.b_dirty);
+                       list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
                }
        }
 out:
@@ -1090,8 +1097,7 @@ void writeback_inodes_sb(struct super_block *sb)
 
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
-       work.nr_pages = nr_dirty + nr_unstable +
-                       (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+       work.nr_pages = nr_dirty + nr_unstable + get_nr_dirty_inodes();
 
        bdi_queue_work(sb->s_bdi, &work);
        wait_for_completion(&done);
@@ -1198,3 +1204,23 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc)
        return ret;
 }
 EXPORT_SYMBOL(sync_inode);
+
+/**
+ * sync_inode - write an inode to disk
+ * @inode: the inode to sync
+ * @wait: wait for I/O to complete.
+ *
+ * Write an inode to disk and adjust it's dirty state after completion.
+ *
+ * Note: only writes the actual inode, no associated data or other metadata.
+ */
+int sync_inode_metadata(struct inode *inode, int wait)
+{
+       struct writeback_control wbc = {
+               .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE,
+               .nr_to_write = 0, /* metadata-only */
+       };
+
+       return sync_inode(inode, &wbc);
+}
+EXPORT_SYMBOL(sync_inode_metadata);
index 7367e177186f4b0efb96d1281134860058050e6d..4eba07661e5c562b50462d8feee6982e39fe2c4b 100644 (file)
@@ -222,6 +222,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
        if (!inode)
                return NULL;
 
+       inode->i_ino = get_next_ino();
        inode->i_mode = mode;
        inode->i_uid = fc->user_id;
        inode->i_gid = fc->group_id;
index cde755cca5642d41fb9cbbe05ac2d01f70f53c69..b98664275f02460c01c5fb2b01d1ddf933671b08 100644 (file)
@@ -809,11 +809,9 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
        int err;
        struct page *page = *pagep;
 
-       if (page && zeroing && count < PAGE_SIZE) {
-               void *mapaddr = kmap_atomic(page, KM_USER1);
-               memset(mapaddr, 0, PAGE_SIZE);
-               kunmap_atomic(mapaddr, KM_USER1);
-       }
+       if (page && zeroing && count < PAGE_SIZE)
+               clear_highpage(page);
+
        while (count) {
                if (cs->write && cs->pipebufs && page) {
                        return fuse_ref_page(cs, page, offset, count);
@@ -830,10 +828,10 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
                        }
                }
                if (page) {
-                       void *mapaddr = kmap_atomic(page, KM_USER1);
+                       void *mapaddr = kmap_atomic(page, KM_USER0);
                        void *buf = mapaddr + offset;
                        offset += fuse_copy_do(cs, &buf, &count);
-                       kunmap_atomic(mapaddr, KM_USER1);
+                       kunmap_atomic(mapaddr, KM_USER0);
                } else
                        offset += fuse_copy_do(cs, NULL, &count);
        }
index 6b24afb96aaedade304b48bb427e664eae8e6e53..4f36f8832b9b1b167321e119260da82d89b4cdf0 100644 (file)
@@ -618,7 +618,6 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        struct gfs2_alloc *al = NULL;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
        unsigned from = pos & (PAGE_CACHE_SIZE - 1);
-       unsigned to = from + len;
        struct page *page;
 
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
@@ -691,7 +690,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        }
 
 prepare_write:
-       error = block_prepare_write(page, from, to, gfs2_block_map);
+       error = __block_write_begin(page, from, len, gfs2_block_map);
 out:
        if (error == 0)
                return 0;
index f3b071f921aa6ea723e35b483675d4c5ee4151c8..939739c7b3f9deb30cf2a2df4ce3c4ba8290b697 100644 (file)
@@ -55,7 +55,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
                 * activity, but those code paths have their own higher-level
                 * throttling.
                 */
-               if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+               if (wbc->sync_mode != WB_SYNC_NONE) {
                        lock_buffer(bh);
                } else if (!trylock_buffer(bh)) {
                        redirty_page_for_writepage(wbc, page);
index aeafc233dc897fdb102df29bf052fc040b61faef..cade1acbcea9420dc7c69622888d820af24eea99 100644 (file)
@@ -1219,7 +1219,6 @@ fail_sb:
 fail_locking:
        init_locking(sdp, &mount_gh, UNDO);
 fail_lm:
-       invalidate_inodes(sb);
        gfs2_gl_hash_clear(sdp);
        gfs2_lm_unmount(sdp);
 fail_sys:
index 0534510200d5961887d3ee957d799e3b4669e76b..12cbea7502c26040fb90db5750e764bdd831079a 100644 (file)
@@ -255,7 +255,7 @@ out_parent:
        gfs2_holder_uninit(ghs);
        gfs2_holder_uninit(ghs + 1);
        if (!error) {
-               atomic_inc(&inode->i_count);
+               ihold(inode);
                d_instantiate(dentry, inode);
                mark_inode_dirty(inode);
        }
@@ -1294,7 +1294,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
        int error;
 
        if (!page_has_buffers(page)) {
-               error = block_prepare_write(page, from, to, gfs2_block_map);
+               error = __block_write_begin(page, from, to - from, gfs2_block_map);
                if (unlikely(error))
                        return error;
 
@@ -1313,7 +1313,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
                next += bh->b_size;
                if (buffer_mapped(bh)) {
                        if (end) {
-                               error = block_prepare_write(page, start, end,
+                               error = __block_write_begin(page, start, end - start,
                                                            gfs2_block_map);
                                if (unlikely(error))
                                        return error;
@@ -1328,7 +1328,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
        } while (next < to);
 
        if (end) {
-               error = block_prepare_write(page, start, end, gfs2_block_map);
+               error = __block_write_begin(page, start, end - start, gfs2_block_map);
                if (unlikely(error))
                        return error;
                empty_write_end(page, start, end);
index 047d1176096c79d6f0ce50227b8c098755fb0150..2b2c4997430b708113af14a08d4c58449b97ccbe 100644 (file)
@@ -857,7 +857,6 @@ restart:
        gfs2_clear_rgrpd(sdp);
        gfs2_jindex_free(sdp);
        /*  Take apart glock structures and buffer lists  */
-       invalidate_inodes(sdp->sd_vfs);
        gfs2_gl_hash_clear(sdp);
        /*  Unmount the locking protocol  */
        gfs2_lm_unmount(sdp);
index 4f55651aaa51e888e6c6dbcb19b78384e20caa61..c8cffb81e849e68e8e85d6e4c19666e6263e3f25 100644 (file)
@@ -147,8 +147,6 @@ struct hfs_sb_info {
        u16 blockoffset;
 
        int fs_div;
-
-       struct hlist_head rsrc_inodes;
 };
 
 #define HFS_FLG_BITMAP_DIRTY   0
@@ -254,17 +252,6 @@ static inline void hfs_bitmap_dirty(struct super_block *sb)
        sb->s_dirt = 1;
 }
 
-static inline void hfs_buffer_sync(struct buffer_head *bh)
-{
-       while (buffer_locked(bh)) {
-               wait_on_buffer(bh);
-       }
-       if (buffer_dirty(bh)) {
-               ll_rw_block(WRITE, 1, &bh);
-               wait_on_buffer(bh);
-       }
-}
-
 #define sb_bread512(sb, sec, data) ({                  \
        struct buffer_head *__bh;                       \
        sector_t __block;                               \
index 397b7adc7ce668dd2880fa73b4f5ee6cf1b050a2..dffb4e996643557f04ae1c83292bd729ef5adada 100644 (file)
@@ -524,7 +524,7 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
        HFS_I(inode)->rsrc_inode = dir;
        HFS_I(dir)->rsrc_inode = inode;
        igrab(dir);
-       hlist_add_head(&inode->i_hash, &HFS_SB(dir->i_sb)->rsrc_inodes);
+       hlist_add_fake(&inode->i_hash);
        mark_inode_dirty(inode);
 out:
        d_add(dentry, inode);
index 86428f5ac991c59dd46a088b25cffe12b5a13dee..1563d5ce57643e23ac08e3a7db02e0b336603c60 100644 (file)
@@ -220,7 +220,7 @@ int hfs_mdb_get(struct super_block *sb)
                mdb->drLsMod = hfs_mtime();
 
                mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
-               hfs_buffer_sync(HFS_SB(sb)->mdb_bh);
+               sync_dirty_buffer(HFS_SB(sb)->mdb_bh);
        }
 
        return 0;
@@ -287,7 +287,7 @@ void hfs_mdb_commit(struct super_block *sb)
                HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
                HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
                mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
-               hfs_buffer_sync(HFS_SB(sb)->alt_mdb_bh);
+               sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
        }
 
        if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) {
index 33254160f650e22da90ff1b0b153df229c81f0df..6ee1586f2334f0c05be1dd8a5305dc96be12674a 100644 (file)
@@ -382,7 +382,6 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
 
        sb->s_fs_info = sbi;
-       INIT_HLIST_HEAD(&sbi->rsrc_inodes);
 
        res = -EINVAL;
        if (!parse_options((char *)data, sbi)) {
index d236d85ec9d73f703384ecaa9d6522fe7433c775..e318bbc0daf6eb9ac4cd4dac18213cc7e7e89ea8 100644 (file)
@@ -286,7 +286,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
 
        inc_nlink(inode);
        hfsplus_instantiate(dst_dentry, inode, cnid);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
        sbi->file_count++;
index 78449280dae08471958a328afca7f225fe9d744f..8afd7e84f98d5d0417b8c256d60f0ff0329521db 100644 (file)
@@ -211,7 +211,7 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
         * appear hashed, but do not put on any lists.  hlist_del()
         * will work fine and require no locking.
         */
-       inode->i_hash.pprev = &inode->i_hash.next;
+       hlist_add_fake(&inode->i_hash);
 
        mark_inode_dirty(inode);
 out:
index 7c232c1487ee761f3557a705a49a2fc7e9da5fb1..bf15a43016b91b5e342bb16a442a19f4e9dadd33 100644 (file)
@@ -91,7 +91,6 @@ extern int rename_file(char *from, char *to);
 extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
                     long long *bfree_out, long long *bavail_out,
                     long long *files_out, long long *ffree_out,
-                    void *fsid_out, int fsid_size, long *namelen_out,
-                    long *spare_out);
+                    void *fsid_out, int fsid_size, long *namelen_out);
 
 #endif
index f7dc9b5f9ef8c80560cb545d937aa9818a3b646f..cd7c93917cc7c29636ee7c87a8846177e4098d23 100644 (file)
@@ -217,7 +217,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
        err = do_statfs(dentry->d_sb->s_fs_info,
                        &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
                        &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
-                       &sf->f_namelen, sf->f_spare);
+                       &sf->f_namelen);
        if (err)
                return err;
        sf->f_blocks = f_blocks;
index 6777aa06ce2cc894de1885f65c4d145e9bc8f0a8..d51a98384bc03b0410f7ba3d5c021804511d10bf 100644 (file)
@@ -94,8 +94,7 @@ void *open_dir(char *path, int *err_out)
 
        dir = opendir(path);
        *err_out = errno;
-       if (dir == NULL)
-               return NULL;
+
        return dir;
 }
 
@@ -205,7 +204,7 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
        if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
                if (fd >= 0) {
                        if (fchmod(fd, attrs->ia_mode) != 0)
-                               return (-errno);
+                               return -errno;
                } else if (chmod(file, attrs->ia_mode) != 0) {
                        return -errno;
                }
@@ -364,8 +363,7 @@ int rename_file(char *from, char *to)
 int do_statfs(char *root, long *bsize_out, long long *blocks_out,
              long long *bfree_out, long long *bavail_out,
              long long *files_out, long long *ffree_out,
-             void *fsid_out, int fsid_size, long *namelen_out,
-             long *spare_out)
+             void *fsid_out, int fsid_size, long *namelen_out)
 {
        struct statfs64 buf;
        int err;
@@ -384,10 +382,6 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out,
               sizeof(buf.f_fsid) > fsid_size ? fsid_size :
               sizeof(buf.f_fsid));
        *namelen_out = buf.f_namelen;
-       spare_out[0] = buf.f_spare[0];
-       spare_out[1] = buf.f_spare[1];
-       spare_out[2] = buf.f_spare[2];
-       spare_out[3] = buf.f_spare[3];
-       spare_out[4] = buf.f_spare[4];
+
        return 0;
 }
index 113eba3d3c386e139453abedb72f1da8dc844097..b14be3f781c714129d4fafbd17a7ff9874193b3f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/statfs.h>
 #include <linux/security.h>
 #include <linux/magic.h>
+#include <linux/migrate.h>
 
 #include <asm/uaccess.h>
 
@@ -455,6 +456,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
        inode = new_inode(sb);
        if (inode) {
                struct hugetlbfs_inode_info *info;
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = uid;
                inode->i_gid = gid;
@@ -573,6 +575,19 @@ static int hugetlbfs_set_page_dirty(struct page *page)
        return 0;
 }
 
+static int hugetlbfs_migrate_page(struct address_space *mapping,
+                               struct page *newpage, struct page *page)
+{
+       int rc;
+
+       rc = migrate_huge_page_move_mapping(mapping, newpage, page);
+       if (rc)
+               return rc;
+       migrate_page_copy(newpage, page);
+
+       return 0;
+}
+
 static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
@@ -659,6 +674,7 @@ static const struct address_space_operations hugetlbfs_aops = {
        .write_begin    = hugetlbfs_write_begin,
        .write_end      = hugetlbfs_write_end,
        .set_page_dirty = hugetlbfs_set_page_dirty,
+       .migratepage    = hugetlbfs_migrate_page,
 };
 
 
index 86464332e590dfdc9cbf041515f038f0de1d846d..ae2727ab0c3ab7695b14f256da0bccdfd3668d81 100644 (file)
 #include <linux/mount.h>
 #include <linux/async.h>
 #include <linux/posix_acl.h>
+#include <linux/ima.h>
 
 /*
  * This is needed for the following functions:
  *  - inode_has_buffers
- *  - invalidate_inode_buffers
  *  - invalidate_bdev
  *
  * FIXME: remove all knowledge of the buffer layer from this file
@@ -72,8 +72,7 @@ static unsigned int i_hash_shift __read_mostly;
  * allowing for low-overhead inode sync() operations.
  */
 
-LIST_HEAD(inode_in_use);
-LIST_HEAD(inode_unused);
+static LIST_HEAD(inode_lru);
 static struct hlist_head *inode_hashtable __read_mostly;
 
 /*
@@ -103,8 +102,41 @@ static DECLARE_RWSEM(iprune_sem);
  */
 struct inodes_stat_t inodes_stat;
 
+static struct percpu_counter nr_inodes __cacheline_aligned_in_smp;
+static struct percpu_counter nr_inodes_unused __cacheline_aligned_in_smp;
+
 static struct kmem_cache *inode_cachep __read_mostly;
 
+static inline int get_nr_inodes(void)
+{
+       return percpu_counter_sum_positive(&nr_inodes);
+}
+
+static inline int get_nr_inodes_unused(void)
+{
+       return percpu_counter_sum_positive(&nr_inodes_unused);
+}
+
+int get_nr_dirty_inodes(void)
+{
+       int nr_dirty = get_nr_inodes() - get_nr_inodes_unused();
+       return nr_dirty > 0 ? nr_dirty : 0;
+
+}
+
+/*
+ * Handle nr_inode sysctl
+ */
+#ifdef CONFIG_SYSCTL
+int proc_nr_inodes(ctl_table *table, int write,
+                  void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       inodes_stat.nr_inodes = get_nr_inodes();
+       inodes_stat.nr_unused = get_nr_inodes_unused();
+       return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+#endif
+
 static void wake_up_inode(struct inode *inode)
 {
        /*
@@ -192,6 +224,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_fsnotify_mask = 0;
 #endif
 
+       percpu_counter_inc(&nr_inodes);
+
        return 0;
 out:
        return -ENOMEM;
@@ -232,11 +266,13 @@ void __destroy_inode(struct inode *inode)
        if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED)
                posix_acl_release(inode->i_default_acl);
 #endif
+       percpu_counter_dec(&nr_inodes);
 }
 EXPORT_SYMBOL(__destroy_inode);
 
-void destroy_inode(struct inode *inode)
+static void destroy_inode(struct inode *inode)
 {
+       BUG_ON(!list_empty(&inode->i_lru));
        __destroy_inode(inode);
        if (inode->i_sb->s_op->destroy_inode)
                inode->i_sb->s_op->destroy_inode(inode);
@@ -255,6 +291,8 @@ void inode_init_once(struct inode *inode)
        INIT_HLIST_NODE(&inode->i_hash);
        INIT_LIST_HEAD(&inode->i_dentry);
        INIT_LIST_HEAD(&inode->i_devices);
+       INIT_LIST_HEAD(&inode->i_wb_list);
+       INIT_LIST_HEAD(&inode->i_lru);
        INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
        spin_lock_init(&inode->i_data.tree_lock);
        spin_lock_init(&inode->i_data.i_mmap_lock);
@@ -281,14 +319,109 @@ static void init_once(void *foo)
  */
 void __iget(struct inode *inode)
 {
-       if (atomic_inc_return(&inode->i_count) != 1)
-               return;
+       atomic_inc(&inode->i_count);
+}
+
+/*
+ * get additional reference to inode; caller must already hold one.
+ */
+void ihold(struct inode *inode)
+{
+       WARN_ON(atomic_inc_return(&inode->i_count) < 2);
+}
+EXPORT_SYMBOL(ihold);
+
+static void inode_lru_list_add(struct inode *inode)
+{
+       if (list_empty(&inode->i_lru)) {
+               list_add(&inode->i_lru, &inode_lru);
+               percpu_counter_inc(&nr_inodes_unused);
+       }
+}
 
-       if (!(inode->i_state & (I_DIRTY|I_SYNC)))
-               list_move(&inode->i_list, &inode_in_use);
-       inodes_stat.nr_unused--;
+static void inode_lru_list_del(struct inode *inode)
+{
+       if (!list_empty(&inode->i_lru)) {
+               list_del_init(&inode->i_lru);
+               percpu_counter_dec(&nr_inodes_unused);
+       }
+}
+
+static inline void __inode_sb_list_add(struct inode *inode)
+{
+       list_add(&inode->i_sb_list, &inode->i_sb->s_inodes);
 }
 
+/**
+ * inode_sb_list_add - add inode to the superblock list of inodes
+ * @inode: inode to add
+ */
+void inode_sb_list_add(struct inode *inode)
+{
+       spin_lock(&inode_lock);
+       __inode_sb_list_add(inode);
+       spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL_GPL(inode_sb_list_add);
+
+static inline void __inode_sb_list_del(struct inode *inode)
+{
+       list_del_init(&inode->i_sb_list);
+}
+
+static unsigned long hash(struct super_block *sb, unsigned long hashval)
+{
+       unsigned long tmp;
+
+       tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
+                       L1_CACHE_BYTES;
+       tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
+       return tmp & I_HASHMASK;
+}
+
+/**
+ *     __insert_inode_hash - hash an inode
+ *     @inode: unhashed inode
+ *     @hashval: unsigned long value used to locate this object in the
+ *             inode_hashtable.
+ *
+ *     Add an inode to the inode hash for this superblock.
+ */
+void __insert_inode_hash(struct inode *inode, unsigned long hashval)
+{
+       struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval);
+
+       spin_lock(&inode_lock);
+       hlist_add_head(&inode->i_hash, b);
+       spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL(__insert_inode_hash);
+
+/**
+ *     __remove_inode_hash - remove an inode from the hash
+ *     @inode: inode to unhash
+ *
+ *     Remove an inode from the superblock.
+ */
+static void __remove_inode_hash(struct inode *inode)
+{
+       hlist_del_init(&inode->i_hash);
+}
+
+/**
+ *     remove_inode_hash - remove an inode from the hash
+ *     @inode: inode to unhash
+ *
+ *     Remove an inode from the superblock.
+ */
+void remove_inode_hash(struct inode *inode)
+{
+       spin_lock(&inode_lock);
+       hlist_del_init(&inode->i_hash);
+       spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL(remove_inode_hash);
+
 void end_writeback(struct inode *inode)
 {
        might_sleep();
@@ -327,101 +460,113 @@ static void evict(struct inode *inode)
  */
 static void dispose_list(struct list_head *head)
 {
-       int nr_disposed = 0;
-
        while (!list_empty(head)) {
                struct inode *inode;
 
-               inode = list_first_entry(head, struct inode, i_list);
-               list_del(&inode->i_list);
+               inode = list_first_entry(head, struct inode, i_lru);
+               list_del_init(&inode->i_lru);
 
                evict(inode);
 
                spin_lock(&inode_lock);
-               hlist_del_init(&inode->i_hash);
-               list_del_init(&inode->i_sb_list);
+               __remove_inode_hash(inode);
+               __inode_sb_list_del(inode);
                spin_unlock(&inode_lock);
 
                wake_up_inode(inode);
                destroy_inode(inode);
-               nr_disposed++;
        }
-       spin_lock(&inode_lock);
-       inodes_stat.nr_inodes -= nr_disposed;
-       spin_unlock(&inode_lock);
 }
 
-/*
- * Invalidate all inodes for a device.
+/**
+ * evict_inodes        - evict all evictable inodes for a superblock
+ * @sb:                superblock to operate on
+ *
+ * Make sure that no inodes with zero refcount are retained.  This is
+ * called by superblock shutdown after having MS_ACTIVE flag removed,
+ * so any inode reaching zero refcount during or after that call will
+ * be immediately evicted.
  */
-static int invalidate_list(struct list_head *head, struct list_head *dispose)
+void evict_inodes(struct super_block *sb)
 {
-       struct list_head *next;
-       int busy = 0, count = 0;
-
-       next = head->next;
-       for (;;) {
-               struct list_head *tmp = next;
-               struct inode *inode;
+       struct inode *inode, *next;
+       LIST_HEAD(dispose);
 
-               /*
-                * We can reschedule here without worrying about the list's
-                * consistency because the per-sb list of inodes must not
-                * change during umount anymore, and because iprune_sem keeps
-                * shrink_icache_memory() away.
-                */
-               cond_resched_lock(&inode_lock);
+       down_write(&iprune_sem);
 
-               next = next->next;
-               if (tmp == head)
-                       break;
-               inode = list_entry(tmp, struct inode, i_sb_list);
-               if (inode->i_state & I_NEW)
+       spin_lock(&inode_lock);
+       list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+               if (atomic_read(&inode->i_count))
                        continue;
-               invalidate_inode_buffers(inode);
-               if (!atomic_read(&inode->i_count)) {
-                       list_move(&inode->i_list, dispose);
-                       WARN_ON(inode->i_state & I_NEW);
-                       inode->i_state |= I_FREEING;
-                       count++;
+
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+                       WARN_ON(1);
                        continue;
                }
-               busy = 1;
+
+               inode->i_state |= I_FREEING;
+
+               /*
+                * Move the inode off the IO lists and LRU once I_FREEING is
+                * set so that it won't get moved back on there if it is dirty.
+                */
+               list_move(&inode->i_lru, &dispose);
+               list_del_init(&inode->i_wb_list);
+               if (!(inode->i_state & (I_DIRTY | I_SYNC)))
+                       percpu_counter_dec(&nr_inodes_unused);
        }
-       /* only unused inodes may be cached with i_count zero */
-       inodes_stat.nr_unused -= count;
-       return busy;
+       spin_unlock(&inode_lock);
+
+       dispose_list(&dispose);
+       up_write(&iprune_sem);
 }
 
 /**
- *     invalidate_inodes       - discard the inodes on a device
- *     @sb: superblock
+ * invalidate_inodes   - attempt to free all inodes on a superblock
+ * @sb:                superblock to operate on
  *
- *     Discard all of the inodes for a given superblock. If the discard
- *     fails because there are busy inodes then a non zero value is returned.
- *     If the discard is successful all the inodes have been discarded.
+ * Attempts to free all inodes for a given superblock.  If there were any
+ * busy inodes return a non-zero value, else zero.
  */
 int invalidate_inodes(struct super_block *sb)
 {
-       int busy;
-       LIST_HEAD(throw_away);
+       int busy = 0;
+       struct inode *inode, *next;
+       LIST_HEAD(dispose);
 
        down_write(&iprune_sem);
+
        spin_lock(&inode_lock);
-       fsnotify_unmount_inodes(&sb->s_inodes);
-       busy = invalidate_list(&sb->s_inodes, &throw_away);
+       list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
+                       continue;
+               if (atomic_read(&inode->i_count)) {
+                       busy = 1;
+                       continue;
+               }
+
+               inode->i_state |= I_FREEING;
+
+               /*
+                * Move the inode off the IO lists and LRU once I_FREEING is
+                * set so that it won't get moved back on there if it is dirty.
+                */
+               list_move(&inode->i_lru, &dispose);
+               list_del_init(&inode->i_wb_list);
+               if (!(inode->i_state & (I_DIRTY | I_SYNC)))
+                       percpu_counter_dec(&nr_inodes_unused);
+       }
        spin_unlock(&inode_lock);
 
-       dispose_list(&throw_away);
+       dispose_list(&dispose);
        up_write(&iprune_sem);
 
        return busy;
 }
-EXPORT_SYMBOL(invalidate_inodes);
 
 static int can_unuse(struct inode *inode)
 {
-       if (inode->i_state)
+       if (inode->i_state & ~I_REFERENCED)
                return 0;
        if (inode_has_buffers(inode))
                return 0;
@@ -433,22 +578,24 @@ static int can_unuse(struct inode *inode)
 }
 
 /*
- * Scan `goal' inodes on the unused list for freeable ones. They are moved to
- * temporary list and then are freed outside inode_lock by dispose_list().
+ * Scan `goal' inodes on the unused list for freeable ones. They are moved to a
+ * temporary list and then are freed outside inode_lock by dispose_list().
  *
  * Any inodes which are pinned purely because of attached pagecache have their
- * pagecache removed.  We expect the final iput() on that inode to add it to
- * the front of the inode_unused list.  So look for it there and if the
- * inode is still freeable, proceed.  The right inode is found 99.9% of the
- * time in testing on a 4-way.
+ * pagecache removed.  If the inode has metadata buffers attached to
+ * mapping->private_list then try to remove them.
  *
- * If the inode has metadata buffers attached to mapping->private_list then
- * try to remove them.
+ * If the inode has the I_REFERENCED flag set, then it means that it has been
+ * used recently - the flag is set in iput_final(). When we encounter such an
+ * inode, clear the flag and move it to the back of the LRU so it gets another
+ * pass through the LRU before it gets reclaimed. This is necessary because of
+ * the fact we are doing lazy LRU updates to minimise lock contention so the
+ * LRU does not have strict ordering. Hence we don't want to reclaim inodes
+ * with this flag set because they are the inodes that are out of order.
  */
 static void prune_icache(int nr_to_scan)
 {
        LIST_HEAD(freeable);
-       int nr_pruned = 0;
        int nr_scanned;
        unsigned long reap = 0;
 
@@ -457,13 +604,26 @@ static void prune_icache(int nr_to_scan)
        for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
                struct inode *inode;
 
-               if (list_empty(&inode_unused))
+               if (list_empty(&inode_lru))
                        break;
 
-               inode = list_entry(inode_unused.prev, struct inode, i_list);
+               inode = list_entry(inode_lru.prev, struct inode, i_lru);
 
-               if (inode->i_state || atomic_read(&inode->i_count)) {
-                       list_move(&inode->i_list, &inode_unused);
+               /*
+                * Referenced or dirty inodes are still in use. Give them
+                * another pass through the LRU as we canot reclaim them now.
+                */
+               if (atomic_read(&inode->i_count) ||
+                   (inode->i_state & ~I_REFERENCED)) {
+                       list_del_init(&inode->i_lru);
+                       percpu_counter_dec(&nr_inodes_unused);
+                       continue;
+               }
+
+               /* recently referenced inodes get one more pass */
+               if (inode->i_state & I_REFERENCED) {
+                       list_move(&inode->i_lru, &inode_lru);
+                       inode->i_state &= ~I_REFERENCED;
                        continue;
                }
                if (inode_has_buffers(inode) || inode->i_data.nrpages) {
@@ -475,18 +635,23 @@ static void prune_icache(int nr_to_scan)
                        iput(inode);
                        spin_lock(&inode_lock);
 
-                       if (inode != list_entry(inode_unused.next,
-                                               struct inode, i_list))
+                       if (inode != list_entry(inode_lru.next,
+                                               struct inode, i_lru))
                                continue;       /* wrong inode or list_empty */
                        if (!can_unuse(inode))
                                continue;
                }
-               list_move(&inode->i_list, &freeable);
                WARN_ON(inode->i_state & I_NEW);
                inode->i_state |= I_FREEING;
-               nr_pruned++;
+
+               /*
+                * Move the inode off the IO lists and LRU once I_FREEING is
+                * set so that it won't get moved back on there if it is dirty.
+                */
+               list_move(&inode->i_lru, &freeable);
+               list_del_init(&inode->i_wb_list);
+               percpu_counter_dec(&nr_inodes_unused);
        }
-       inodes_stat.nr_unused -= nr_pruned;
        if (current_is_kswapd())
                __count_vm_events(KSWAPD_INODESTEAL, reap);
        else
@@ -518,7 +683,7 @@ static int shrink_icache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
                        return -1;
                prune_icache(nr);
        }
-       return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
+       return (get_nr_inodes_unused() / 100) * sysctl_vfs_cache_pressure;
 }
 
 static struct shrinker icache_shrinker = {
@@ -529,9 +694,6 @@ static struct shrinker icache_shrinker = {
 static void __wait_on_freeing_inode(struct inode *inode);
 /*
  * Called with the inode lock held.
- * NOTE: we are not increasing the inode-refcount, you must call __iget()
- * by hand after calling find_inode now! This simplifies iunique and won't
- * add any additional branch in the common code.
  */
 static struct inode *find_inode(struct super_block *sb,
                                struct hlist_head *head,
@@ -551,9 +713,10 @@ repeat:
                        __wait_on_freeing_inode(inode);
                        goto repeat;
                }
-               break;
+               __iget(inode);
+               return inode;
        }
-       return node ? inode : NULL;
+       return NULL;
 }
 
 /*
@@ -576,53 +739,49 @@ repeat:
                        __wait_on_freeing_inode(inode);
                        goto repeat;
                }
-               break;
+               __iget(inode);
+               return inode;
        }
-       return node ? inode : NULL;
-}
-
-static unsigned long hash(struct super_block *sb, unsigned long hashval)
-{
-       unsigned long tmp;
-
-       tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
-                       L1_CACHE_BYTES;
-       tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
-       return tmp & I_HASHMASK;
-}
-
-static inline void
-__inode_add_to_lists(struct super_block *sb, struct hlist_head *head,
-                       struct inode *inode)
-{
-       inodes_stat.nr_inodes++;
-       list_add(&inode->i_list, &inode_in_use);
-       list_add(&inode->i_sb_list, &sb->s_inodes);
-       if (head)
-               hlist_add_head(&inode->i_hash, head);
+       return NULL;
 }
 
-/**
- * inode_add_to_lists - add a new inode to relevant lists
- * @sb: superblock inode belongs to
- * @inode: inode to mark in use
+/*
+ * Each cpu owns a range of LAST_INO_BATCH numbers.
+ * 'shared_last_ino' is dirtied only once out of LAST_INO_BATCH allocations,
+ * to renew the exhausted range.
  *
- * When an inode is allocated it needs to be accounted for, added to the in use
- * list, the owning superblock and the inode hash. This needs to be done under
- * the inode_lock, so export a function to do this rather than the inode lock
- * itself. We calculate the hash list to add to here so it is all internal
- * which requires the caller to have already set up the inode number in the
- * inode to add.
+ * This does not significantly increase overflow rate because every CPU can
+ * consume at most LAST_INO_BATCH-1 unused inode numbers. So there is
+ * NR_CPUS*(LAST_INO_BATCH-1) wastage. At 4096 and 1024, this is ~0.1% of the
+ * 2^32 range, and is a worst-case. Even a 50% wastage would only increase
+ * overflow rate by 2x, which does not seem too significant.
+ *
+ * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+ * error if st_ino won't fit in target struct field. Use 32bit counter
+ * here to attempt to avoid that.
  */
-void inode_add_to_lists(struct super_block *sb, struct inode *inode)
+#define LAST_INO_BATCH 1024
+static DEFINE_PER_CPU(unsigned int, last_ino);
+
+unsigned int get_next_ino(void)
 {
-       struct hlist_head *head = inode_hashtable + hash(sb, inode->i_ino);
+       unsigned int *p = &get_cpu_var(last_ino);
+       unsigned int res = *p;
 
-       spin_lock(&inode_lock);
-       __inode_add_to_lists(sb, head, inode);
-       spin_unlock(&inode_lock);
+#ifdef CONFIG_SMP
+       if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) {
+               static atomic_t shared_last_ino;
+               int next = atomic_add_return(LAST_INO_BATCH, &shared_last_ino);
+
+               res = next - LAST_INO_BATCH;
+       }
+#endif
+
+       *p = ++res;
+       put_cpu_var(last_ino);
+       return res;
 }
-EXPORT_SYMBOL_GPL(inode_add_to_lists);
+EXPORT_SYMBOL(get_next_ino);
 
 /**
  *     new_inode       - obtain an inode
@@ -638,12 +797,6 @@ EXPORT_SYMBOL_GPL(inode_add_to_lists);
  */
 struct inode *new_inode(struct super_block *sb)
 {
-       /*
-        * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
-        * error if st_ino won't fit in target struct field. Use 32bit counter
-        * here to attempt to avoid that.
-        */
-       static unsigned int last_ino;
        struct inode *inode;
 
        spin_lock_prefetch(&inode_lock);
@@ -651,8 +804,7 @@ struct inode *new_inode(struct super_block *sb)
        inode = alloc_inode(sb);
        if (inode) {
                spin_lock(&inode_lock);
-               __inode_add_to_lists(sb, NULL, inode);
-               inode->i_ino = ++last_ino;
+               __inode_sb_list_add(inode);
                inode->i_state = 0;
                spin_unlock(&inode_lock);
        }
@@ -663,7 +815,7 @@ EXPORT_SYMBOL(new_inode);
 void unlock_new_inode(struct inode *inode)
 {
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-       if (inode->i_mode & S_IFDIR) {
+       if (S_ISDIR(inode->i_mode)) {
                struct file_system_type *type = inode->i_sb->s_type;
 
                /* Set new key only if filesystem hasn't already changed it */
@@ -720,7 +872,8 @@ static struct inode *get_new_inode(struct super_block *sb,
                        if (set(inode, data))
                                goto set_failed;
 
-                       __inode_add_to_lists(sb, head, inode);
+                       hlist_add_head(&inode->i_hash, head);
+                       __inode_sb_list_add(inode);
                        inode->i_state = I_NEW;
                        spin_unlock(&inode_lock);
 
@@ -735,7 +888,6 @@ static struct inode *get_new_inode(struct super_block *sb,
                 * us. Use the old inode instead of the one we just
                 * allocated.
                 */
-               __iget(old);
                spin_unlock(&inode_lock);
                destroy_inode(inode);
                inode = old;
@@ -767,7 +919,8 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
                old = find_inode_fast(sb, head, ino);
                if (!old) {
                        inode->i_ino = ino;
-                       __inode_add_to_lists(sb, head, inode);
+                       hlist_add_head(&inode->i_hash, head);
+                       __inode_sb_list_add(inode);
                        inode->i_state = I_NEW;
                        spin_unlock(&inode_lock);
 
@@ -782,7 +935,6 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
                 * us. Use the old inode instead of the one we just
                 * allocated.
                 */
-               __iget(old);
                spin_unlock(&inode_lock);
                destroy_inode(inode);
                inode = old;
@@ -791,6 +943,27 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
        return inode;
 }
 
+/*
+ * search the inode cache for a matching inode number.
+ * If we find one, then the inode number we are trying to
+ * allocate is not unique and so we should not use it.
+ *
+ * Returns 1 if the inode number is unique, 0 if it is not.
+ */
+static int test_inode_iunique(struct super_block *sb, unsigned long ino)
+{
+       struct hlist_head *b = inode_hashtable + hash(sb, ino);
+       struct hlist_node *node;
+       struct inode *inode;
+
+       hlist_for_each_entry(inode, node, b, i_hash) {
+               if (inode->i_ino == ino && inode->i_sb == sb)
+                       return 0;
+       }
+
+       return 1;
+}
+
 /**
  *     iunique - get a unique inode number
  *     @sb: superblock
@@ -812,19 +985,18 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
         * error if st_ino won't fit in target struct field. Use 32bit counter
         * here to attempt to avoid that.
         */
+       static DEFINE_SPINLOCK(iunique_lock);
        static unsigned int counter;
-       struct inode *inode;
-       struct hlist_head *head;
        ino_t res;
 
        spin_lock(&inode_lock);
+       spin_lock(&iunique_lock);
        do {
                if (counter <= max_reserved)
                        counter = max_reserved + 1;
                res = counter++;
-               head = inode_hashtable + hash(sb, res);
-               inode = find_inode_fast(sb, head, res);
-       } while (inode != NULL);
+       } while (!test_inode_iunique(sb, res));
+       spin_unlock(&iunique_lock);
        spin_unlock(&inode_lock);
 
        return res;
@@ -876,7 +1048,6 @@ static struct inode *ifind(struct super_block *sb,
        spin_lock(&inode_lock);
        inode = find_inode(sb, head, test, data);
        if (inode) {
-               __iget(inode);
                spin_unlock(&inode_lock);
                if (likely(wait))
                        wait_on_inode(inode);
@@ -909,7 +1080,6 @@ static struct inode *ifind_fast(struct super_block *sb,
        spin_lock(&inode_lock);
        inode = find_inode_fast(sb, head, ino);
        if (inode) {
-               __iget(inode);
                spin_unlock(&inode_lock);
                wait_on_inode(inode);
                return inode;
@@ -1095,7 +1265,7 @@ int insert_inode_locked(struct inode *inode)
                __iget(old);
                spin_unlock(&inode_lock);
                wait_on_inode(old);
-               if (unlikely(!hlist_unhashed(&old->i_hash))) {
+               if (unlikely(!inode_unhashed(old))) {
                        iput(old);
                        return -EBUSY;
                }
@@ -1134,7 +1304,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
                __iget(old);
                spin_unlock(&inode_lock);
                wait_on_inode(old);
-               if (unlikely(!hlist_unhashed(&old->i_hash))) {
+               if (unlikely(!inode_unhashed(old))) {
                        iput(old);
                        return -EBUSY;
                }
@@ -1143,36 +1313,6 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
 }
 EXPORT_SYMBOL(insert_inode_locked4);
 
-/**
- *     __insert_inode_hash - hash an inode
- *     @inode: unhashed inode
- *     @hashval: unsigned long value used to locate this object in the
- *             inode_hashtable.
- *
- *     Add an inode to the inode hash for this superblock.
- */
-void __insert_inode_hash(struct inode *inode, unsigned long hashval)
-{
-       struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);
-       spin_lock(&inode_lock);
-       hlist_add_head(&inode->i_hash, head);
-       spin_unlock(&inode_lock);
-}
-EXPORT_SYMBOL(__insert_inode_hash);
-
-/**
- *     remove_inode_hash - remove an inode from the hash
- *     @inode: inode to unhash
- *
- *     Remove an inode from the superblock.
- */
-void remove_inode_hash(struct inode *inode)
-{
-       spin_lock(&inode_lock);
-       hlist_del_init(&inode->i_hash);
-       spin_unlock(&inode_lock);
-}
-EXPORT_SYMBOL(remove_inode_hash);
 
 int generic_delete_inode(struct inode *inode)
 {
@@ -1187,7 +1327,7 @@ EXPORT_SYMBOL(generic_delete_inode);
  */
 int generic_drop_inode(struct inode *inode)
 {
-       return !inode->i_nlink || hlist_unhashed(&inode->i_hash);
+       return !inode->i_nlink || inode_unhashed(inode);
 }
 EXPORT_SYMBOL_GPL(generic_drop_inode);
 
@@ -1213,10 +1353,11 @@ static void iput_final(struct inode *inode)
                drop = generic_drop_inode(inode);
 
        if (!drop) {
-               if (!(inode->i_state & (I_DIRTY|I_SYNC)))
-                       list_move(&inode->i_list, &inode_unused);
-               inodes_stat.nr_unused++;
                if (sb->s_flags & MS_ACTIVE) {
+                       inode->i_state |= I_REFERENCED;
+                       if (!(inode->i_state & (I_DIRTY|I_SYNC))) {
+                               inode_lru_list_add(inode);
+                       }
                        spin_unlock(&inode_lock);
                        return;
                }
@@ -1227,19 +1368,23 @@ static void iput_final(struct inode *inode)
                spin_lock(&inode_lock);
                WARN_ON(inode->i_state & I_NEW);
                inode->i_state &= ~I_WILL_FREE;
-               inodes_stat.nr_unused--;
-               hlist_del_init(&inode->i_hash);
+               __remove_inode_hash(inode);
        }
-       list_del_init(&inode->i_list);
-       list_del_init(&inode->i_sb_list);
+
        WARN_ON(inode->i_state & I_NEW);
        inode->i_state |= I_FREEING;
-       inodes_stat.nr_inodes--;
+
+       /*
+        * Move the inode off the IO lists and LRU once I_FREEING is
+        * set so that it won't get moved back on there if it is dirty.
+        */
+       inode_lru_list_del(inode);
+       list_del_init(&inode->i_wb_list);
+
+       __inode_sb_list_del(inode);
        spin_unlock(&inode_lock);
        evict(inode);
-       spin_lock(&inode_lock);
-       hlist_del_init(&inode->i_hash);
-       spin_unlock(&inode_lock);
+       remove_inode_hash(inode);
        wake_up_inode(inode);
        BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
        destroy_inode(inode);
@@ -1503,6 +1648,8 @@ void __init inode_init(void)
                                         SLAB_MEM_SPREAD),
                                         init_once);
        register_shrinker(&icache_shrinker);
+       percpu_counter_init(&nr_inodes, 0);
+       percpu_counter_init(&nr_inodes_unused, 0);
 
        /* Hash may have been set up in inode_init_early */
        if (!hashdist)
index a6910e91cee8799196e991c7cab98ad11206cf01..ebad3b90752dae0b37838734293ee36864af2c02 100644 (file)
@@ -101,3 +101,10 @@ extern void put_super(struct super_block *sb);
 struct nameidata;
 extern struct file *nameidata_to_filp(struct nameidata *);
 extern void release_open_intent(struct nameidata *);
+
+/*
+ * inode.c
+ */
+extern int get_nr_dirty_inodes(void);
+extern int evict_inodes(struct super_block *);
+extern int invalidate_inodes(struct super_block *);
index 09ff41a752a092431068b991b9e323bbe5276fbd..60c2b944d76267bbd40358f7384dfe3fc9240bd3 100644 (file)
@@ -962,25 +962,23 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
  * or getblk() if they are not.  Returns the number of blocks inserted
  * (-ve == error.)
  */
-int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
+int isofs_get_blocks(struct inode *inode, sector_t iblock,
                     struct buffer_head **bh, unsigned long nblocks)
 {
-       unsigned long b_off;
+       unsigned long b_off = iblock;
        unsigned offset, sect_size;
        unsigned int firstext;
        unsigned long nextblk, nextoff;
-       long iblock = (long)iblock_s;
        int section, rv, error;
        struct iso_inode_info *ei = ISOFS_I(inode);
 
        error = -EIO;
        rv = 0;
-       if (iblock < 0 || iblock != iblock_s) {
+       if (iblock != b_off) {
                printk(KERN_DEBUG "%s: block number too large\n", __func__);
                goto abort;
        }
 
-       b_off = iblock;
 
        offset = 0;
        firstext = ei->i_first_extent;
@@ -998,8 +996,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                 * I/O errors.
                 */
                if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
-                       printk(KERN_DEBUG "%s: block >= EOF (%ld, %ld)\n",
-                               __func__, iblock, (unsigned long) inode->i_size);
+                       printk(KERN_DEBUG "%s: block >= EOF (%lu, %llu)\n",
+                               __func__, b_off,
+                               (unsigned long long)inode->i_size);
                        goto abort;
                }
 
@@ -1025,9 +1024,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                        if (++section > 100) {
                                printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
                                        " aborting...\n", __func__);
-                               printk(KERN_DEBUG "%s: block=%ld firstext=%u sect_size=%u "
+                               printk(KERN_DEBUG "%s: block=%lu firstext=%u sect_size=%u "
                                        "nextblk=%lu nextoff=%lu\n", __func__,
-                                       iblock, firstext, (unsigned) sect_size,
+                                       b_off, firstext, (unsigned) sect_size,
                                        nextblk, nextoff);
                                goto abort;
                        }
index ed78a3cf3cb047046d8ea385af9554e63214aac8..79121aa5858b8a4aa02861ba57cf17d9a8dfe13b 100644 (file)
@@ -289,7 +289,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
                mutex_unlock(&f->sem);
                d_instantiate(dentry, old_dentry->d_inode);
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
-               atomic_inc(&old_dentry->d_inode->i_count);
+               ihold(old_dentry->d_inode);
        }
        return ret;
 }
@@ -864,7 +864,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
                /* Might as well let the VFS know */
                d_instantiate(new_dentry, old_dentry->d_inode);
-               atomic_inc(&old_dentry->d_inode->i_count);
+               ihold(old_dentry->d_inode);
                new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
                return ret;
        }
index f8332dc8eeb2111430d2a16ae716b6d1925fde99..3a09423b6c22c6bf0d1635ddd572ef4620c146b2 100644 (file)
@@ -497,7 +497,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
         * appear hashed, but do not put on any lists.  hlist_del()
         * will work fine and require no locking.
         */
-       ip->i_hash.pprev = &ip->i_hash.next;
+       hlist_add_fake(&ip->i_hash);
 
        return (ip);
 }
index d945ea76b445249de68fece3be7dea631cf2b6b1..9466957ec84173f56707bd591e97b007c7bba57c 100644 (file)
@@ -1279,7 +1279,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
         * lazy commit thread finishes processing
         */
        if (tblk->xflag & COMMIT_DELETE) {
-               atomic_inc(&tblk->u.ip->i_count);
+               ihold(tblk->u.ip);
                /*
                 * Avoid a rare deadlock
                 *
index a9cf8e8675be8713dc5f9311faa20fefcac85156..231ca4af9bce4f27d2c12d71e9c0a237616e512d 100644 (file)
@@ -839,7 +839,7 @@ static int jfs_link(struct dentry *old_dentry,
        ip->i_ctime = CURRENT_TIME;
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(dir);
-       atomic_inc(&ip->i_count);
+       ihold(ip);
 
        iplist[0] = ip;
        iplist[1] = dir;
index 62baa0387d6e03869e726b89ffaddccce4fc090c..304a5132ca270d018799d3003170bd813c23dd9b 100644 (file)
@@ -255,7 +255,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
 
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        inc_nlink(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        dget(dentry);
        d_instantiate(dentry, inode);
        return 0;
@@ -892,10 +892,6 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent);
  */
 int generic_file_fsync(struct file *file, int datasync)
 {
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 0, /* metadata-only; caller takes care of data */
-       };
        struct inode *inode = file->f_mapping->host;
        int err;
        int ret;
@@ -906,7 +902,7 @@ int generic_file_fsync(struct file *file, int datasync)
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
                return ret;
 
-       err = sync_inode(inode, &wbc);
+       err = sync_inode_metadata(inode, 1);
        if (ret == 0)
                ret = err;
        return ret;
index 64fd427c993cce81eb5246ba9717a975575c0017..d5bb86866e6c19f85a359373742a37e24ad39ad7 100644 (file)
@@ -42,6 +42,7 @@ struct nlm_wait {
 };
 
 static LIST_HEAD(nlm_blocked);
+static DEFINE_SPINLOCK(nlm_blocked_lock);
 
 /**
  * nlmclnt_init - Set up per-NFS mount point lockd data structures
@@ -97,7 +98,10 @@ struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *
                block->b_lock = fl;
                init_waitqueue_head(&block->b_wait);
                block->b_status = nlm_lck_blocked;
+
+               spin_lock(&nlm_blocked_lock);
                list_add(&block->b_list, &nlm_blocked);
+               spin_unlock(&nlm_blocked_lock);
        }
        return block;
 }
@@ -106,7 +110,9 @@ void nlmclnt_finish_block(struct nlm_wait *block)
 {
        if (block == NULL)
                return;
+       spin_lock(&nlm_blocked_lock);
        list_del(&block->b_list);
+       spin_unlock(&nlm_blocked_lock);
        kfree(block);
 }
 
@@ -154,6 +160,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
         * Look up blocked request based on arguments. 
         * Warning: must not use cookie to match it!
         */
+       spin_lock(&nlm_blocked_lock);
        list_for_each_entry(block, &nlm_blocked, b_list) {
                struct file_lock *fl_blocked = block->b_lock;
 
@@ -178,6 +185,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
                wake_up(&block->b_wait);
                res = nlm_granted;
        }
+       spin_unlock(&nlm_blocked_lock);
        return res;
 }
 
@@ -216,10 +224,6 @@ reclaimer(void *ptr)
        allow_signal(SIGKILL);
 
        down_write(&host->h_rwsem);
-
-       /* This one ensures that our parent doesn't terminate while the
-        * reclaim is in progress */
-       lock_kernel();
        lockd_up();     /* note: this cannot fail as lockd is already running */
 
        dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
@@ -260,16 +264,17 @@ restart:
        dprintk("NLM: done reclaiming locks for host %s\n", host->h_name);
 
        /* Now, wake up all processes that sleep on a blocked lock */
+       spin_lock(&nlm_blocked_lock);
        list_for_each_entry(block, &nlm_blocked, b_list) {
                if (block->b_host == host) {
                        block->b_status = nlm_lck_denied_grace_period;
                        wake_up(&block->b_wait);
                }
        }
+       spin_unlock(&nlm_blocked_lock);
 
        /* Release host handle after use */
        nlm_release_host(host);
        lockd_down();
-       unlock_kernel();
        return 0;
 }
index 7932c399fab41421095fbb0f98f0b21819e96514..47ea1e1925b8c4fded4b156ea7cef916322377bf 100644 (file)
@@ -166,7 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
        /* Set up the argument struct */
        nlmclnt_setlockargs(call, fl);
 
-       lock_kernel();
        if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
                if (fl->fl_type != F_UNLCK) {
                        call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
@@ -177,10 +176,8 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
                status = nlmclnt_test(call, fl);
        else
                status = -EINVAL;
-
        fl->fl_ops->fl_release_private(fl);
        fl->fl_ops = NULL;
-       unlock_kernel();
 
        dprintk("lockd: clnt proc returns %d\n", status);
        return status;
@@ -226,9 +223,7 @@ void nlm_release_call(struct nlm_rqst *call)
 
 static void nlmclnt_rpc_release(void *data)
 {
-       lock_kernel();
        nlm_release_call(data);
-       unlock_kernel();
 }
 
 static int nlm_wait_on_grace(wait_queue_head_t *queue)
@@ -448,14 +443,18 @@ out:
 
 static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
+       spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock);
        new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
        new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
        list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
+       spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock);
 }
 
 static void nlmclnt_locks_release_private(struct file_lock *fl)
 {
+       spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock);
        list_del(&fl->fl_u.nfs_fl.list);
+       spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock);
        nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
 }
 
@@ -721,9 +720,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
 die:
        return;
  retry_rebind:
-       lock_kernel();
        nlm_rebind_host(req->a_host);
-       unlock_kernel();
  retry_unlock:
        rpc_restart_call(task);
 }
@@ -801,9 +798,7 @@ retry_cancel:
        /* Don't ever retry more than 3 times */
        if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
                goto die;
-       lock_kernel();
        nlm_rebind_host(req->a_host);
-       unlock_kernel();
        rpc_restart_call(task);
        rpc_delay(task, 30 * HZ);
 }
index bb464d12104c44dd67b0eee1496c49a8df138ac7..25e21e4023b22a3f51ceb9d1c1869c2b7518f6d0 100644 (file)
@@ -353,6 +353,7 @@ nlm_bind_host(struct nlm_host *host)
                        .to_retries     = 5U,
                };
                struct rpc_create_args args = {
+                       .net            = &init_net,
                        .protocol       = host->h_proto,
                        .address        = nlm_addr(host),
                        .addrsize       = host->h_addrlen,
index e3015464fbab8ac1a9a48f0ea5465080923731bb..e0c91894964446231135d7ad2317b7135fa6265e 100644 (file)
@@ -69,6 +69,7 @@ static struct rpc_clnt *nsm_create(void)
                .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
        };
        struct rpc_create_args args = {
+               .net                    = &init_net,
                .protocol               = XPRT_TRANSPORT_UDP,
                .address                = (struct sockaddr *)&sin,
                .addrsize               = sizeof(sin),
index f1bacf1a03912bb52939e5d0595b9c71f70ff8d6..abfff9d7979dc60b57646b6129cdb7dd279c6041 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/in.h>
 #include <linux/uio.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
@@ -130,15 +129,6 @@ lockd(void *vrqstp)
 
        dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
 
-       /*
-        * FIXME: it would be nice if lockd didn't spend its entire life
-        * running under the BKL. At the very least, it would be good to
-        * have someone clarify what it's intended to protect here. I've
-        * seen some handwavy posts about posix locking needing to be
-        * done under the BKL, but it's far from clear.
-        */
-       lock_kernel();
-
        if (!nlm_timeout)
                nlm_timeout = LOCKD_DFLT_TIMEO;
        nlmsvc_timeout = nlm_timeout * HZ;
@@ -195,7 +185,6 @@ lockd(void *vrqstp)
        if (nlmsvc_ops)
                nlmsvc_invalidate_all();
        nlm_shutdown_hosts();
-       unlock_kernel();
        return 0;
 }
 
@@ -206,7 +195,7 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
 
        xprt = svc_find_xprt(serv, name, family, 0);
        if (xprt == NULL)
-               return svc_create_xprt(serv, name, family, port,
+               return svc_create_xprt(serv, name, &init_net, family, port,
                                                SVC_SOCK_DEFAULTS);
        svc_xprt_put(xprt);
        return 0;
index 031c6569a134aa7efcfc776d1cab5ef03bc742b8..a336e832475db7ffd5516a4cbe7e32daff49fd7c 100644 (file)
@@ -230,9 +230,7 @@ static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
 
 static void nlm4svc_callback_release(void *data)
 {
-       lock_kernel();
        nlm_release_call(data);
-       unlock_kernel();
 }
 
 static const struct rpc_call_ops nlm4svc_callback_ops = {
index 84055d31bfc5e427a87c2412eea17f6ea59e2fc4..c462d346acbda920a78ef03c153dc088b70ef7f4 100644 (file)
@@ -52,12 +52,13 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
  * The list of blocked locks to retry
  */
 static LIST_HEAD(nlm_blocked);
+static DEFINE_SPINLOCK(nlm_blocked_lock);
 
 /*
  * Insert a blocked lock into the global list
  */
 static void
-nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
+nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
 {
        struct nlm_block *b;
        struct list_head *pos;
@@ -87,6 +88,13 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
        block->b_when = when;
 }
 
+static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
+{
+       spin_lock(&nlm_blocked_lock);
+       nlmsvc_insert_block_locked(block, when);
+       spin_unlock(&nlm_blocked_lock);
+}
+
 /*
  * Remove a block from the global list
  */
@@ -94,7 +102,9 @@ static inline void
 nlmsvc_remove_block(struct nlm_block *block)
 {
        if (!list_empty(&block->b_list)) {
+               spin_lock(&nlm_blocked_lock);
                list_del_init(&block->b_list);
+               spin_unlock(&nlm_blocked_lock);
                nlmsvc_release_block(block);
        }
 }
@@ -651,7 +661,7 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
        struct nlm_block *block;
        int rc = -ENOENT;
 
-       lock_kernel();
+       spin_lock(&nlm_blocked_lock);
        list_for_each_entry(block, &nlm_blocked, b_list) {
                if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
                        dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
@@ -665,13 +675,13 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
                        } else if (result == 0)
                                block->b_granted = 1;
 
-                       nlmsvc_insert_block(block, 0);
+                       nlmsvc_insert_block_locked(block, 0);
                        svc_wake_up(block->b_daemon);
                        rc = 0;
                        break;
                }
        }
-       unlock_kernel();
+       spin_unlock(&nlm_blocked_lock);
        if (rc == -ENOENT)
                printk(KERN_WARNING "lockd: grant for unknown block\n");
        return rc;
@@ -690,14 +700,16 @@ nlmsvc_notify_blocked(struct file_lock *fl)
        struct nlm_block        *block;
 
        dprintk("lockd: VFS unblock notification for block %p\n", fl);
+       spin_lock(&nlm_blocked_lock);
        list_for_each_entry(block, &nlm_blocked, b_list) {
                if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
-                       nlmsvc_insert_block(block, 0);
+                       nlmsvc_insert_block_locked(block, 0);
+                       spin_unlock(&nlm_blocked_lock);
                        svc_wake_up(block->b_daemon);
                        return;
                }
        }
-
+       spin_unlock(&nlm_blocked_lock);
        printk(KERN_WARNING "lockd: notification for unknown block!\n");
 }
 
@@ -803,7 +815,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
 
        dprintk("lockd: GRANT_MSG RPC callback\n");
 
-       lock_kernel();
+       spin_lock(&nlm_blocked_lock);
        /* if the block is not on a list at this point then it has
         * been invalidated. Don't try to requeue it.
         *
@@ -825,19 +837,20 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
                /* Call was successful, now wait for client callback */
                timeout = 60 * HZ;
        }
-       nlmsvc_insert_block(block, timeout);
+       nlmsvc_insert_block_locked(block, timeout);
        svc_wake_up(block->b_daemon);
 out:
-       unlock_kernel();
+       spin_unlock(&nlm_blocked_lock);
 }
 
+/*
+ * FIXME: nlmsvc_release_block() grabs a mutex.  This is not allowed for an
+ * .rpc_release rpc_call_op
+ */
 static void nlmsvc_grant_release(void *data)
 {
        struct nlm_rqst         *call = data;
-
-       lock_kernel();
        nlmsvc_release_block(call->a_block);
-       unlock_kernel();
 }
 
 static const struct rpc_call_ops nlmsvc_grant_ops = {
index 0f2ab741ae7c8205edeed842e7bbf6f89d6d482f..c3069f38d60220e82726d5c318d0942e125ddb03 100644 (file)
@@ -260,9 +260,7 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
 
 static void nlmsvc_callback_release(void *data)
 {
-       lock_kernel();
        nlm_release_call(data);
-       unlock_kernel();
 }
 
 static const struct rpc_call_ops nlmsvc_callback_ops = {
index d0ef94cfb3da4d218b66a0a4046d96ab30506f3b..1ca0679c80bfcca842d277f7597d96dbe8792c35 100644 (file)
@@ -170,6 +170,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
 
 again:
        file->f_locks = 0;
+       lock_flocks(); /* protects i_flock list */
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
                if (fl->fl_lmops != &nlmsvc_lock_operations)
                        continue;
@@ -181,6 +182,7 @@ again:
                if (match(lockhost, host)) {
                        struct file_lock lock = *fl;
 
+                       unlock_flocks();
                        lock.fl_type  = F_UNLCK;
                        lock.fl_start = 0;
                        lock.fl_end   = OFFSET_MAX;
@@ -192,6 +194,7 @@ again:
                        goto again;
                }
        }
+       unlock_flocks();
 
        return 0;
 }
@@ -226,10 +229,14 @@ nlm_file_inuse(struct nlm_file *file)
        if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
                return 1;
 
+       lock_flocks();
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
-               if (fl->fl_lmops == &nlmsvc_lock_operations)
+               if (fl->fl_lmops == &nlmsvc_lock_operations) {
+                       unlock_flocks();
                        return 1;
+               }
        }
+       unlock_flocks();
        file->f_locks = 0;
        return 0;
 }
index 8b2b6ad56a090b0bd1cb58ef839fd9ecedf536cf..50ec15927aab3164a456875e6c11b1f4fa2f8bef 100644 (file)
@@ -142,6 +142,7 @@ int lease_break_time = 45;
 
 static LIST_HEAD(file_lock_list);
 static LIST_HEAD(blocked_list);
+static DEFINE_SPINLOCK(file_lock_lock);
 
 /*
  * Protects the two list heads above, plus the inode->i_flock list
@@ -149,23 +150,24 @@ static LIST_HEAD(blocked_list);
  */
 void lock_flocks(void)
 {
-       lock_kernel();
+       spin_lock(&file_lock_lock);
 }
 EXPORT_SYMBOL_GPL(lock_flocks);
 
 void unlock_flocks(void)
 {
-       unlock_kernel();
+       spin_unlock(&file_lock_lock);
 }
 EXPORT_SYMBOL_GPL(unlock_flocks);
 
 static struct kmem_cache *filelock_cache __read_mostly;
 
 /* Allocate an empty lock structure. */
-static struct file_lock *locks_alloc_lock(void)
+struct file_lock *locks_alloc_lock(void)
 {
        return kmem_cache_alloc(filelock_cache, GFP_KERNEL);
 }
+EXPORT_SYMBOL_GPL(locks_alloc_lock);
 
 void locks_release_private(struct file_lock *fl)
 {
@@ -1365,7 +1367,6 @@ int fcntl_getlease(struct file *filp)
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
-       struct file_lock *new_fl = NULL;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        int error, rdlease_count = 0, wrlease_count = 0;
@@ -1385,11 +1386,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        lease = *flp;
 
        if (arg != F_UNLCK) {
-               error = -ENOMEM;
-               new_fl = locks_alloc_lock();
-               if (new_fl == NULL)
-                       goto out;
-
                error = -EAGAIN;
                if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
                        goto out;
@@ -1434,7 +1430,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
                goto out;
        }
 
-       error = 0;
        if (arg == F_UNLCK)
                goto out;
 
@@ -1442,15 +1437,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        if (!leases_enable)
                goto out;
 
-       locks_copy_lock(new_fl, lease);
-       locks_insert_lock(before, new_fl);
-
-       *flp = new_fl;
+       locks_insert_lock(before, lease);
        return 0;
 
 out:
-       if (new_fl != NULL)
-               locks_free_lock(new_fl);
+       locks_free_lock(lease);
        return error;
 }
 EXPORT_SYMBOL(generic_setlease);
@@ -1514,26 +1505,38 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
  */
 int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 {
-       struct file_lock fl, *flp = &fl;
+       struct file_lock *fl;
+       struct fasync_struct *new;
        struct inode *inode = filp->f_path.dentry->d_inode;
        int error;
 
-       locks_init_lock(&fl);
-       error = lease_init(filp, arg, &fl);
-       if (error)
-               return error;
+       fl = lease_alloc(filp, arg);
+       if (IS_ERR(fl))
+               return PTR_ERR(fl);
 
+       new = fasync_alloc();
+       if (!new) {
+               locks_free_lock(fl);
+               return -ENOMEM;
+       }
        lock_flocks();
-
-       error = __vfs_setlease(filp, arg, &flp);
+       error = __vfs_setlease(filp, arg, &fl);
        if (error || arg == F_UNLCK)
                goto out_unlock;
 
-       error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
+       /*
+        * fasync_insert_entry() returns the old entry if any.
+        * If there was no old entry, then it used 'new' and
+        * inserted it into the fasync list. Clear new so that
+        * we don't release it here.
+        */
+       if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new))
+               new = NULL;
+
        if (error < 0) {
                /* remove lease just inserted by setlease */
-               flp->fl_type = F_UNLCK | F_INPROGRESS;
-               flp->fl_break_time = jiffies - 10;
+               fl->fl_type = F_UNLCK | F_INPROGRESS;
+               fl->fl_break_time = jiffies - 10;
                time_out_leases(inode);
                goto out_unlock;
        }
@@ -1541,6 +1544,8 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
 out_unlock:
        unlock_flocks();
+       if (new)
+               fasync_free(new);
        return error;
 }
 
@@ -2109,7 +2114,7 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock);
 #include <linux/seq_file.h>
 
 static void lock_get_status(struct seq_file *f, struct file_lock *fl,
-                                                       int id, char *pfx)
+                           loff_t id, char *pfx)
 {
        struct inode *inode = NULL;
        unsigned int fl_pid;
@@ -2122,7 +2127,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
        if (fl->fl_file != NULL)
                inode = fl->fl_file->f_path.dentry->d_inode;
 
-       seq_printf(f, "%d:%s ", id, pfx);
+       seq_printf(f, "%lld:%s ", id, pfx);
        if (IS_POSIX(fl)) {
                seq_printf(f, "%6s %s ",
                             (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
@@ -2185,24 +2190,27 @@ static int locks_show(struct seq_file *f, void *v)
 
        fl = list_entry(v, struct file_lock, fl_link);
 
-       lock_get_status(f, fl, (long)f->private, "");
+       lock_get_status(f, fl, *((loff_t *)f->private), "");
 
        list_for_each_entry(bfl, &fl->fl_block, fl_block)
-               lock_get_status(f, bfl, (long)f->private, " ->");
+               lock_get_status(f, bfl, *((loff_t *)f->private), " ->");
 
-       f->private++;
        return 0;
 }
 
 static void *locks_start(struct seq_file *f, loff_t *pos)
 {
+       loff_t *p = f->private;
+
        lock_flocks();
-       f->private = (void *)1;
+       *p = (*pos + 1);
        return seq_list_start(&file_lock_list, *pos);
 }
 
 static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
 {
+       loff_t *p = f->private;
+       ++*p;
        return seq_list_next(v, &file_lock_list, pos);
 }
 
@@ -2220,14 +2228,14 @@ static const struct seq_operations locks_seq_operations = {
 
 static int locks_open(struct inode *inode, struct file *filp)
 {
-       return seq_open(filp, &locks_seq_operations);
+       return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t));
 }
 
 static const struct file_operations proc_locks_operations = {
        .open           = locks_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = seq_release,
+       .release        = seq_release_private,
 };
 
 static int __init proc_locks_init(void)
index 1eb4e89e045b082d9f02d6d005edd3f61e5c48c8..409dfd65e9a1764029edf55071069e61f447d29d 100644 (file)
@@ -569,7 +569,7 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir,
                return -EMLINK;
 
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        inode->i_nlink++;
        mark_inode_dirty_sync(inode);
 
index f3f3578393a417085812ba1ad7e0b7c1e4e5c981..c0d35a3accef98dd5ed7619214146e0f0f5d3260 100644 (file)
@@ -101,7 +101,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        return add_nondir(dentry, inode);
 }
 
index 24896e8335658c9c0ce2c81c117cb664b964da70..f7dbc06857abfe6e1959654f7fd66b393dd161d0 100644 (file)
@@ -1121,11 +1121,13 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
 static struct dentry *__lookup_hash(struct qstr *name,
                struct dentry *base, struct nameidata *nd)
 {
+       struct inode *inode = base->d_inode;
        struct dentry *dentry;
-       struct inode *inode;
        int err;
 
-       inode = base->d_inode;
+       err = exec_permission(inode);
+       if (err)
+               return ERR_PTR(err);
 
        /*
         * See if the low-level filesystem might want
@@ -1161,11 +1163,6 @@ out:
  */
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
-       int err;
-
-       err = exec_permission(nd->path.dentry->d_inode);
-       if (err)
-               return ERR_PTR(err);
        return __lookup_hash(&nd->last, nd->path.dentry, nd);
 }
 
@@ -1213,9 +1210,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
        if (err)
                return ERR_PTR(err);
 
-       err = exec_permission(base->d_inode);
-       if (err)
-               return ERR_PTR(err);
        return __lookup_hash(&this, base, NULL);
 }
 
@@ -2291,7 +2285,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
                        goto slashes;
                inode = dentry->d_inode;
                if (inode)
-                       atomic_inc(&inode->i_count);
+                       ihold(inode);
                error = mnt_want_write(nd.path.mnt);
                if (error)
                        goto exit2;
index 7ca5182c0bedd547e21531e777175d2058ea2982..8a415c9c5e552efd945cdb85af6f74af4b2b6de6 100644 (file)
@@ -595,7 +595,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
                                goto out_free;
                }
 
-               mnt->mnt_flags = old->mnt_flags;
+               mnt->mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD;
                atomic_inc(&sb->s_active);
                mnt->mnt_sb = sb;
                mnt->mnt_root = dget(root);
index b950415d7c4340b0bb30da28cbb6e96c1a011826..ba306658a6db16441843d7c4244a8c0158625acd 100644 (file)
@@ -1,7 +1,6 @@
 config NFS_FS
        tristate "NFS client support"
        depends on INET && FILE_LOCKING
-       depends on BKL # fix as soon as lockd is done
        select LOCKD
        select SUNRPC
        select NFS_ACL_SUPPORT if NFS_V3_ACL
@@ -77,13 +76,17 @@ config NFS_V4
 
 config NFS_V4_1
        bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
-       depends on NFS_V4 && EXPERIMENTAL
+       depends on NFS_FS && NFS_V4 && EXPERIMENTAL
+       select PNFS_FILE_LAYOUT
        help
          This option enables support for minor version 1 of the NFSv4 protocol
-         (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client.
+         (RFC 5661) in the kernel's NFS client.
 
          If unsure, say N.
 
+config PNFS_FILE_LAYOUT
+       tristate
+
 config ROOT_NFS
        bool "Root file system on NFS"
        depends on NFS_FS=y && IP_PNP
@@ -118,3 +121,14 @@ config NFS_USE_KERNEL_DNS
        select DNS_RESOLVER
        select KEYS
        default y
+
+config NFS_USE_NEW_IDMAPPER
+       bool "Use the new idmapper upcall routine"
+       depends on NFS_V4 && KEYS
+       help
+         Say Y here if you want NFS to use the new idmapper upcall functions.
+         You will need /sbin/request-key (usually provided by the keyutils
+         package).  For details, read
+         <file:Documentation/filesystems/nfs/idmapper.txt>.
+
+         If you are unsure, say N.
index da7fda639eac6445d3a34193610ca10f8f302e01..4776ff9e38143d5f3c01744d8cd7261c2a62553c 100644 (file)
@@ -15,5 +15,9 @@ nfs-$(CONFIG_NFS_V4)  += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
                           delegation.o idmap.o \
                           callback.o callback_xdr.o callback_proc.o \
                           nfs4namespace.o
+nfs-$(CONFIG_NFS_V4_1) += pnfs.o
 nfs-$(CONFIG_SYSCTL) += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
+
+obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
+nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
index e17b49e2eabd8dcb887819bbf2d8c714e4e2085f..aeec017fe814acbdf17947a68553765a335359ae 100644 (file)
@@ -109,7 +109,7 @@ nfs4_callback_up(struct svc_serv *serv)
 {
        int ret;
 
-       ret = svc_create_xprt(serv, "tcp", PF_INET,
+       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret <= 0)
                goto out_err;
@@ -117,7 +117,7 @@ nfs4_callback_up(struct svc_serv *serv)
        dprintk("NFS: Callback listener port = %u (af %u)\n",
                        nfs_callback_tcpport, PF_INET);
 
-       ret = svc_create_xprt(serv, "tcp", PF_INET6,
+       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret > 0) {
                nfs_callback_tcpport6 = ret;
index 930d10fecdaff8632dc35869c3695fc8397e8d7a..2950fca0c61b22cd0997d7c136cde40b90a0ae71 100644 (file)
@@ -118,11 +118,11 @@ int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const n
        if (delegation == NULL)
                return 0;
 
-       /* seqid is 4-bytes long */
-       if (((u32 *) &stateid->data)[0] != 0)
+       if (stateid->stateid.seqid != 0)
                return 0;
-       if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
-                  sizeof(stateid->data)-4))
+       if (memcmp(&delegation->stateid.stateid.other,
+                  &stateid->stateid.other,
+                  NFS4_STATEID_OTHER_SIZE))
                return 0;
 
        return 1;
index e7340729af896e2bce1097fe4f8521618680173e..0870d0d4efc0b15d1a72b212e5acc693d6a90725 100644 (file)
@@ -48,6 +48,7 @@
 #include "iostat.h"
 #include "internal.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
@@ -155,7 +156,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        cred = rpc_lookup_machine_cred();
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
-
+#if defined(CONFIG_NFS_V4_1)
+       INIT_LIST_HEAD(&clp->cl_layouts);
+#endif
        nfs_fscache_get_client_cookie(clp);
 
        return clp;
@@ -252,6 +255,7 @@ void nfs_put_client(struct nfs_client *clp)
                nfs_free_client(clp);
        }
 }
+EXPORT_SYMBOL_GPL(nfs_put_client);
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 /*
@@ -601,6 +605,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
 {
        struct rpc_clnt         *clnt = NULL;
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = clp->cl_proto,
                .address        = (struct sockaddr *)&clp->cl_addr,
                .addrsize       = clp->cl_addrlen,
@@ -635,7 +640,8 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
  */
 static void nfs_destroy_server(struct nfs_server *server)
 {
-       if (!(server->flags & NFS_MOUNT_NONLM))
+       if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
+                       !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
                nlmclnt_done(server->nlm_host);
 }
 
@@ -657,7 +663,8 @@ static int nfs_start_lockd(struct nfs_server *server)
 
        if (nlm_init.nfs_version > 3)
                return 0;
-       if (server->flags & NFS_MOUNT_NONLM)
+       if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
+                       (server->flags & NFS_MOUNT_LOCAL_FCNTL))
                return 0;
 
        switch (clp->cl_proto) {
@@ -898,11 +905,13 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
        if (server->wsize > NFS_MAX_FILE_IO_SIZE)
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       set_pnfs_layoutdriver(server, fsinfo->layouttype);
+
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
        server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
-       if (server->dtsize > PAGE_CACHE_SIZE)
-               server->dtsize = PAGE_CACHE_SIZE;
+       if (server->dtsize > PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES)
+               server->dtsize = PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES;
        if (server->dtsize > server->rsize)
                server->dtsize = server->rsize;
 
@@ -913,6 +922,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
 
        server->maxfilesize = fsinfo->maxfilesize;
 
+       server->time_delta = fsinfo->time_delta;
+
        /* We're airborne Set socket buffersize */
        rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 }
@@ -935,6 +946,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
        }
 
        fsinfo.fattr = fattr;
+       fsinfo.layouttype = 0;
        error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
        if (error < 0)
                goto out_error;
@@ -1017,6 +1029,7 @@ void nfs_free_server(struct nfs_server *server)
 {
        dprintk("--> nfs_free_server()\n");
 
+       unset_pnfs_layoutdriver(server);
        spin_lock(&nfs_client_lock);
        list_del(&server->client_link);
        list_del(&server->master_link);
@@ -1356,8 +1369,9 @@ static int nfs4_init_server(struct nfs_server *server,
 
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
-       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
-               NFS_CAP_POSIX_LOCK;
+       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
+       if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+                       server->caps |= NFS_CAP_READDIRPLUS;
        server->options = data->options;
 
        /* Get a client record */
index e257172d438c08afe374c99fe0e7c80af51efe6c..07ac3847e562b54c26efd30c9a9eabab468c309d 100644 (file)
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
-#include "nfs4_fs.h"
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 /* #define NFS_DEBUG_VERBOSE 1 */
 
@@ -55,6 +56,7 @@ static int nfs_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
 static int nfs_fsync_dir(struct file *, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
+static int nfs_readdir_clear_array(struct page*, gfp_t);
 
 const struct file_operations nfs_dir_operations = {
        .llseek         = nfs_llseek_dir,
@@ -80,6 +82,10 @@ const struct inode_operations nfs_dir_inode_operations = {
        .setattr        = nfs_setattr,
 };
 
+const struct address_space_operations nfs_dir_addr_space_ops = {
+       .releasepage = nfs_readdir_clear_array,
+};
+
 #ifdef CONFIG_NFS_V3
 const struct inode_operations nfs3_dir_inode_operations = {
        .create         = nfs_create,
@@ -104,8 +110,9 @@ const struct inode_operations nfs3_dir_inode_operations = {
 #ifdef CONFIG_NFS_V4
 
 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
+static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd);
 const struct inode_operations nfs4_dir_inode_operations = {
-       .create         = nfs_create,
+       .create         = nfs_open_create,
        .lookup         = nfs_atomic_lookup,
        .link           = nfs_link,
        .unlink         = nfs_unlink,
@@ -150,51 +157,197 @@ nfs_opendir(struct inode *inode, struct file *filp)
        return res;
 }
 
-typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
+struct nfs_cache_array_entry {
+       u64 cookie;
+       u64 ino;
+       struct qstr string;
+};
+
+struct nfs_cache_array {
+       unsigned int size;
+       int eof_index;
+       u64 last_cookie;
+       struct nfs_cache_array_entry array[0];
+};
+
+#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry))
+
+typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 typedef struct {
        struct file     *file;
        struct page     *page;
        unsigned long   page_index;
-       __be32          *ptr;
        u64             *dir_cookie;
        loff_t          current_index;
-       struct nfs_entry *entry;
        decode_dirent_t decode;
-       int             plus;
+
        unsigned long   timestamp;
        unsigned long   gencount;
-       int             timestamp_valid;
+       unsigned int    cache_entry_index;
+       unsigned int    plus:1;
+       unsigned int    eof:1;
 } nfs_readdir_descriptor_t;
 
-/* Now we cache directories properly, by stuffing the dirent
- * data directly in the page cache.
- *
- * Inode invalidation due to refresh etc. takes care of
- * _everything_, no sloppy entry flushing logic, no extraneous
- * copying, network direct to page cache, the way it was meant
- * to be.
- *
- * NOTE: Dirent information verification is done always by the
- *      page-in of the RPC reply, nowhere else, this simplies
- *      things substantially.
+/*
+ * The caller is responsible for calling nfs_readdir_release_array(page)
  */
 static
-int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
+struct nfs_cache_array *nfs_readdir_get_array(struct page *page)
+{
+       if (page == NULL)
+               return ERR_PTR(-EIO);
+       return (struct nfs_cache_array *)kmap(page);
+}
+
+static
+void nfs_readdir_release_array(struct page *page)
+{
+       kunmap(page);
+}
+
+/*
+ * we are freeing strings created by nfs_add_to_readdir_array()
+ */
+static
+int nfs_readdir_clear_array(struct page *page, gfp_t mask)
+{
+       struct nfs_cache_array *array = nfs_readdir_get_array(page);
+       int i;
+       for (i = 0; i < array->size; i++)
+               kfree(array->array[i].string.name);
+       nfs_readdir_release_array(page);
+       return 0;
+}
+
+/*
+ * the caller is responsible for freeing qstr.name
+ * when called by nfs_readdir_add_to_array, the strings will be freed in
+ * nfs_clear_readdir_array()
+ */
+static
+int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len)
+{
+       string->len = len;
+       string->name = kmemdup(name, len, GFP_KERNEL);
+       if (string->name == NULL)
+               return -ENOMEM;
+       string->hash = full_name_hash(name, len);
+       return 0;
+}
+
+static
+int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
+{
+       struct nfs_cache_array *array = nfs_readdir_get_array(page);
+       struct nfs_cache_array_entry *cache_entry;
+       int ret;
+
+       if (IS_ERR(array))
+               return PTR_ERR(array);
+       ret = -EIO;
+       if (array->size >= MAX_READDIR_ARRAY)
+               goto out;
+
+       cache_entry = &array->array[array->size];
+       cache_entry->cookie = entry->prev_cookie;
+       cache_entry->ino = entry->ino;
+       ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
+       if (ret)
+               goto out;
+       array->last_cookie = entry->cookie;
+       if (entry->eof == 1)
+               array->eof_index = array->size;
+       array->size++;
+out:
+       nfs_readdir_release_array(page);
+       return ret;
+}
+
+static
+int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
+{
+       loff_t diff = desc->file->f_pos - desc->current_index;
+       unsigned int index;
+
+       if (diff < 0)
+               goto out_eof;
+       if (diff >= array->size) {
+               if (array->eof_index > 0)
+                       goto out_eof;
+               desc->current_index += array->size;
+               return -EAGAIN;
+       }
+
+       index = (unsigned int)diff;
+       *desc->dir_cookie = array->array[index].cookie;
+       desc->cache_entry_index = index;
+       if (index == array->eof_index)
+               desc->eof = 1;
+       return 0;
+out_eof:
+       desc->eof = 1;
+       return -EBADCOOKIE;
+}
+
+static
+int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
+{
+       int i;
+       int status = -EAGAIN;
+
+       for (i = 0; i < array->size; i++) {
+               if (i == array->eof_index) {
+                       desc->eof = 1;
+                       status = -EBADCOOKIE;
+               }
+               if (array->array[i].cookie == *desc->dir_cookie) {
+                       desc->cache_entry_index = i;
+                       status = 0;
+                       break;
+               }
+       }
+
+       return status;
+}
+
+static
+int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
+{
+       struct nfs_cache_array *array;
+       int status = -EBADCOOKIE;
+
+       if (desc->dir_cookie == NULL)
+               goto out;
+
+       array = nfs_readdir_get_array(desc->page);
+       if (IS_ERR(array)) {
+               status = PTR_ERR(array);
+               goto out;
+       }
+
+       if (*desc->dir_cookie == 0)
+               status = nfs_readdir_search_for_pos(array, desc);
+       else
+               status = nfs_readdir_search_for_cookie(array, desc);
+
+       nfs_readdir_release_array(desc->page);
+out:
+       return status;
+}
+
+/* Fill a page with xdr information before transferring to the cache page */
+static
+int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
+                       struct nfs_entry *entry, struct file *file, struct inode *inode)
 {
-       struct file     *file = desc->file;
-       struct inode    *inode = file->f_path.dentry->d_inode;
        struct rpc_cred *cred = nfs_file_cred(file);
        unsigned long   timestamp, gencount;
        int             error;
 
-       dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n",
-                       __func__, (long long)desc->entry->cookie,
-                       page->index);
-
  again:
        timestamp = jiffies;
        gencount = nfs_inc_attr_generation_counter();
-       error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page,
+       error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages,
                                          NFS_SERVER(inode)->dtsize, desc->plus);
        if (error < 0) {
                /* We requested READDIRPLUS, but the server doesn't grok it */
@@ -208,190 +361,292 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        }
        desc->timestamp = timestamp;
        desc->gencount = gencount;
-       desc->timestamp_valid = 1;
-       SetPageUptodate(page);
-       /* Ensure consistent page alignment of the data.
-        * Note: assumes we have exclusive access to this mapping either
-        *       through inode->i_mutex or some other mechanism.
-        */
-       if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) {
-               /* Should never happen */
-               nfs_zap_mapping(inode, inode->i_mapping);
-       }
-       unlock_page(page);
-       return 0;
- error:
-       unlock_page(page);
-       return -EIO;
+error:
+       return error;
 }
 
-static inline
-int dir_decode(nfs_readdir_descriptor_t *desc)
+/* Fill in an entry based on the xdr code stored in desc->page */
+static
+int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream)
 {
-       __be32  *p = desc->ptr;
-       p = desc->decode(p, desc->entry, desc->plus);
+       __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus);
        if (IS_ERR(p))
                return PTR_ERR(p);
-       desc->ptr = p;
-       if (desc->timestamp_valid) {
-               desc->entry->fattr->time_start = desc->timestamp;
-               desc->entry->fattr->gencount = desc->gencount;
-       } else
-               desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
+
+       entry->fattr->time_start = desc->timestamp;
+       entry->fattr->gencount = desc->gencount;
        return 0;
 }
 
-static inline
-void dir_page_release(nfs_readdir_descriptor_t *desc)
+static
+int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
-       kunmap(desc->page);
-       page_cache_release(desc->page);
-       desc->page = NULL;
-       desc->ptr = NULL;
+       struct nfs_inode *node;
+       if (dentry->d_inode == NULL)
+               goto different;
+       node = NFS_I(dentry->d_inode);
+       if (node->fh.size != entry->fh->size)
+               goto different;
+       if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0)
+               goto different;
+       return 1;
+different:
+       return 0;
 }
 
-/*
- * Given a pointer to a buffer that has already been filled by a call
- * to readdir, find the next entry with cookie '*desc->dir_cookie'.
- *
- * If the end of the buffer has been reached, return -EAGAIN, if not,
- * return the offset within the buffer of the next entry to be
- * read.
- */
-static inline
-int find_dirent(nfs_readdir_descriptor_t *desc)
+static
+void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 {
-       struct nfs_entry *entry = desc->entry;
-       int             loop_count = 0,
-                       status;
+       struct qstr filename = {
+               .len = entry->len,
+               .name = entry->name,
+       };
+       struct dentry *dentry;
+       struct dentry *alias;
+       struct inode *dir = parent->d_inode;
+       struct inode *inode;
 
-       while((status = dir_decode(desc)) == 0) {
-               dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n",
-                               __func__, (unsigned long long)entry->cookie);
-               if (entry->prev_cookie == *desc->dir_cookie)
-                       break;
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
+       if (filename.name[0] == '.') {
+               if (filename.len == 1)
+                       return;
+               if (filename.len == 2 && filename.name[1] == '.')
+                       return;
+       }
+       filename.hash = full_name_hash(filename.name, filename.len);
+
+       dentry = d_lookup(parent, &filename);
+       if (dentry != NULL) {
+               if (nfs_same_file(dentry, entry)) {
+                       nfs_refresh_inode(dentry->d_inode, entry->fattr);
+                       goto out;
+               } else {
+                       d_drop(dentry);
+                       dput(dentry);
                }
        }
-       return status;
+
+       dentry = d_alloc(parent, &filename);
+       if (dentry == NULL)
+               return;
+
+       dentry->d_op = NFS_PROTO(dir)->dentry_ops;
+       inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
+       if (IS_ERR(inode))
+               goto out;
+
+       alias = d_materialise_unique(dentry, inode);
+       if (IS_ERR(alias))
+               goto out;
+       else if (alias) {
+               nfs_set_verifier(alias, nfs_save_change_attribute(dir));
+               dput(alias);
+       } else
+               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+
+out:
+       dput(dentry);
+}
+
+/* Perform conversion from xdr to cache array */
+static
+void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
+                               void *xdr_page, struct page *page, unsigned int buflen)
+{
+       struct xdr_stream stream;
+       struct xdr_buf buf;
+       __be32 *ptr = xdr_page;
+       int status;
+       struct nfs_cache_array *array;
+
+       buf.head->iov_base = xdr_page;
+       buf.head->iov_len = buflen;
+       buf.tail->iov_len = 0;
+       buf.page_base = 0;
+       buf.page_len = 0;
+       buf.buflen = buf.head->iov_len;
+       buf.len = buf.head->iov_len;
+
+       xdr_init_decode(&stream, &buf, ptr);
+
+
+       do {
+               status = xdr_decode(desc, entry, &stream);
+               if (status != 0)
+                       break;
+
+               if (nfs_readdir_add_to_array(entry, page) == -1)
+                       break;
+               if (desc->plus == 1)
+                       nfs_prime_dcache(desc->file->f_path.dentry, entry);
+       } while (!entry->eof);
+
+       if (status == -EBADCOOKIE && entry->eof) {
+               array = nfs_readdir_get_array(page);
+               array->eof_index = array->size - 1;
+               status = 0;
+               nfs_readdir_release_array(page);
+       }
+}
+
+static
+void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages)
+{
+       unsigned int i;
+       for (i = 0; i < npages; i++)
+               put_page(pages[i]);
+}
+
+static
+void nfs_readdir_free_large_page(void *ptr, struct page **pages,
+               unsigned int npages)
+{
+       vm_unmap_ram(ptr, npages);
+       nfs_readdir_free_pagearray(pages, npages);
 }
 
 /*
- * Given a pointer to a buffer that has already been filled by a call
- * to readdir, find the entry at offset 'desc->file->f_pos'.
- *
- * If the end of the buffer has been reached, return -EAGAIN, if not,
- * return the offset within the buffer of the next entry to be
- * read.
+ * nfs_readdir_large_page will allocate pages that must be freed with a call
+ * to nfs_readdir_free_large_page
  */
-static inline
-int find_dirent_index(nfs_readdir_descriptor_t *desc)
+static
+void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
 {
-       struct nfs_entry *entry = desc->entry;
-       int             loop_count = 0,
-                       status;
+       void *ptr;
+       unsigned int i;
+
+       for (i = 0; i < npages; i++) {
+               struct page *page = alloc_page(GFP_KERNEL);
+               if (page == NULL)
+                       goto out_freepages;
+               pages[i] = page;
+       }
 
-       for(;;) {
-               status = dir_decode(desc);
-               if (status)
-                       break;
+       ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
+       if (!IS_ERR_OR_NULL(ptr))
+               return ptr;
+out_freepages:
+       nfs_readdir_free_pagearray(pages, i);
+       return NULL;
+}
+
+static
+int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
+{
+       struct page *pages[NFS_MAX_READDIR_PAGES];
+       void *pages_ptr = NULL;
+       struct nfs_entry entry;
+       struct file     *file = desc->file;
+       struct nfs_cache_array *array;
+       int status = 0;
+       unsigned int array_size = ARRAY_SIZE(pages);
+
+       entry.prev_cookie = 0;
+       entry.cookie = *desc->dir_cookie;
+       entry.eof = 0;
+       entry.fh = nfs_alloc_fhandle();
+       entry.fattr = nfs_alloc_fattr();
+       if (entry.fh == NULL || entry.fattr == NULL)
+               goto out;
 
-               dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n",
-                               (unsigned long long)entry->cookie, desc->current_index);
+       array = nfs_readdir_get_array(page);
+       memset(array, 0, sizeof(struct nfs_cache_array));
+       array->eof_index = -1;
 
-               if (desc->file->f_pos == desc->current_index) {
-                       *desc->dir_cookie = entry->cookie;
+       pages_ptr = nfs_readdir_large_page(pages, array_size);
+       if (!pages_ptr)
+               goto out_release_array;
+       do {
+               status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
+
+               if (status < 0)
                        break;
-               }
-               desc->current_index++;
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
-               }
-       }
+               nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE);
+       } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY);
+
+       nfs_readdir_free_large_page(pages_ptr, pages, array_size);
+out_release_array:
+       nfs_readdir_release_array(page);
+out:
+       nfs_free_fattr(entry.fattr);
+       nfs_free_fhandle(entry.fh);
        return status;
 }
 
 /*
- * Find the given page, and call find_dirent() or find_dirent_index in
- * order to try to return the next entry.
+ * Now we cache directories properly, by converting xdr information
+ * to an array that can be used for lookups later.  This results in
+ * fewer cache pages, since we can store more information on each page.
+ * We only need to convert from xdr once so future lookups are much simpler
  */
-static inline
-int find_dirent_page(nfs_readdir_descriptor_t *desc)
+static
+int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
 {
        struct inode    *inode = desc->file->f_path.dentry->d_inode;
-       struct page     *page;
-       int             status;
 
-       dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n",
-                       __func__, desc->page_index,
-                       (long long) *desc->dir_cookie);
+       if (nfs_readdir_xdr_to_array(desc, page, inode) < 0)
+               goto error;
+       SetPageUptodate(page);
 
-       /* If we find the page in the page_cache, we cannot be sure
-        * how fresh the data is, so we will ignore readdir_plus attributes.
-        */
-       desc->timestamp_valid = 0;
-       page = read_cache_page(inode->i_mapping, desc->page_index,
-                              (filler_t *)nfs_readdir_filler, desc);
-       if (IS_ERR(page)) {
-               status = PTR_ERR(page);
-               goto out;
+       if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) {
+               /* Should never happen */
+               nfs_zap_mapping(inode, inode->i_mapping);
        }
+       unlock_page(page);
+       return 0;
+ error:
+       unlock_page(page);
+       return -EIO;
+}
 
-       /* NOTE: Someone else may have changed the READDIRPLUS flag */
-       desc->page = page;
-       desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
-       if (*desc->dir_cookie != 0)
-               status = find_dirent(desc);
-       else
-               status = find_dirent_index(desc);
-       if (status < 0)
-               dir_page_release(desc);
- out:
-       dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status);
-       return status;
+static
+void cache_page_release(nfs_readdir_descriptor_t *desc)
+{
+       page_cache_release(desc->page);
+       desc->page = NULL;
+}
+
+static
+struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
+{
+       struct page *page;
+       page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
+                       desc->page_index, (filler_t *)nfs_readdir_filler, desc);
+       if (IS_ERR(page))
+               desc->eof = 1;
+       return page;
 }
 
 /*
- * Recurse through the page cache pages, and return a
- * filled nfs_entry structure of the next directory entry if possible.
- *
- * The target for the search is '*desc->dir_cookie' if non-0,
- * 'desc->file->f_pos' otherwise
+ * Returns 0 if desc->dir_cookie was found on page desc->page_index
  */
+static
+int find_cache_page(nfs_readdir_descriptor_t *desc)
+{
+       int res;
+
+       desc->page = get_cache_page(desc);
+       if (IS_ERR(desc->page))
+               return PTR_ERR(desc->page);
+
+       res = nfs_readdir_search_array(desc);
+       if (res == 0)
+               return 0;
+       cache_page_release(desc);
+       return res;
+}
+
+/* Search for desc->dir_cookie from the beginning of the page cache */
 static inline
 int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
 {
-       int             loop_count = 0;
-       int             res;
-
-       /* Always search-by-index from the beginning of the cache */
-       if (*desc->dir_cookie == 0) {
-               dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n",
-                               (long long)desc->file->f_pos);
-               desc->page_index = 0;
-               desc->entry->cookie = desc->entry->prev_cookie = 0;
-               desc->entry->eof = 0;
-               desc->current_index = 0;
-       } else
-               dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n",
-                               (unsigned long long)*desc->dir_cookie);
+       int res = -EAGAIN;
 
-       for (;;) {
-               res = find_dirent_page(desc);
+       while (1) {
+               res = find_cache_page(desc);
                if (res != -EAGAIN)
                        break;
-               /* Align to beginning of next page */
-               desc->page_index ++;
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
-               }
+               desc->page_index++;
        }
-
-       dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, res);
        return res;
 }
 
@@ -400,8 +655,6 @@ static inline unsigned int dt_type(struct inode *inode)
        return (inode->i_mode >> 12) & 15;
 }
 
-static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc);
-
 /*
  * Once we've found the start of the dirent within a page: fill 'er up...
  */
@@ -410,49 +663,36 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                   filldir_t filldir)
 {
        struct file     *file = desc->file;
-       struct nfs_entry *entry = desc->entry;
-       struct dentry   *dentry = NULL;
-       u64             fileid;
-       int             loop_count = 0,
-                       res;
-
-       dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n",
-                       (unsigned long long)entry->cookie);
-
-       for(;;) {
-               unsigned d_type = DT_UNKNOWN;
-               /* Note: entry->prev_cookie contains the cookie for
-                *       retrieving the current dirent on the server */
-               fileid = entry->ino;
-
-               /* Get a dentry if we have one */
-               if (dentry != NULL)
-                       dput(dentry);
-               dentry = nfs_readdir_lookup(desc);
+       int i = 0;
+       int res = 0;
+       struct nfs_cache_array *array = NULL;
+       unsigned int d_type = DT_UNKNOWN;
+       struct dentry *dentry = NULL;
 
-               /* Use readdirplus info */
-               if (dentry != NULL && dentry->d_inode != NULL) {
-                       d_type = dt_type(dentry->d_inode);
-                       fileid = NFS_FILEID(dentry->d_inode);
-               }
+       array = nfs_readdir_get_array(desc->page);
 
-               res = filldir(dirent, entry->name, entry->len, 
-                             file->f_pos, nfs_compat_user_ino64(fileid),
-                             d_type);
+       for (i = desc->cache_entry_index; i < array->size; i++) {
+               d_type = DT_UNKNOWN;
+
+               res = filldir(dirent, array->array[i].string.name,
+                       array->array[i].string.len, file->f_pos,
+                       nfs_compat_user_ino64(array->array[i].ino), d_type);
                if (res < 0)
                        break;
                file->f_pos++;
-               *desc->dir_cookie = entry->cookie;
-               if (dir_decode(desc) != 0) {
-                       desc->page_index ++;
+               desc->cache_entry_index = i;
+               if (i < (array->size-1))
+                       *desc->dir_cookie = array->array[i+1].cookie;
+               else
+                       *desc->dir_cookie = array->last_cookie;
+               if (i == array->eof_index) {
+                       desc->eof = 1;
                        break;
                }
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
-               }
        }
-       dir_page_release(desc);
+
+       nfs_readdir_release_array(desc->page);
+       cache_page_release(desc);
        if (dentry != NULL)
                dput(dentry);
        dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
@@ -476,12 +716,9 @@ static inline
 int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                     filldir_t filldir)
 {
-       struct file     *file = desc->file;
-       struct inode    *inode = file->f_path.dentry->d_inode;
-       struct rpc_cred *cred = nfs_file_cred(file);
        struct page     *page = NULL;
        int             status;
-       unsigned long   timestamp, gencount;
+       struct inode *inode = desc->file->f_path.dentry->d_inode;
 
        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
                        (unsigned long long)*desc->dir_cookie);
@@ -491,38 +728,22 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                status = -ENOMEM;
                goto out;
        }
-       timestamp = jiffies;
-       gencount = nfs_inc_attr_generation_counter();
-       status = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred,
-                                               *desc->dir_cookie, page,
-                                               NFS_SERVER(inode)->dtsize,
-                                               desc->plus);
-       desc->page = page;
-       desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
-       if (status >= 0) {
-               desc->timestamp = timestamp;
-               desc->gencount = gencount;
-               desc->timestamp_valid = 1;
-               if ((status = dir_decode(desc)) == 0)
-                       desc->entry->prev_cookie = *desc->dir_cookie;
-       } else
+
+       if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) {
                status = -EIO;
-       if (status < 0)
                goto out_release;
+       }
 
+       desc->page_index = 0;
+       desc->page = page;
        status = nfs_do_filldir(desc, dirent, filldir);
 
-       /* Reset read descriptor so it searches the page cache from
-        * the start upon the next call to readdir_search_pagecache() */
-       desc->page_index = 0;
-       desc->entry->cookie = desc->entry->prev_cookie = 0;
-       desc->entry->eof = 0;
  out:
        dfprintk(DIRCACHE, "NFS: %s: returns %d\n",
                        __func__, status);
        return status;
  out_release:
-       dir_page_release(desc);
+       cache_page_release(desc);
        goto out;
 }
 
@@ -536,7 +757,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode    *inode = dentry->d_inode;
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
-       struct nfs_entry my_entry;
        int res = -ENOMEM;
 
        dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
@@ -557,26 +777,17 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        desc->decode = NFS_PROTO(inode)->decode_dirent;
        desc->plus = NFS_USE_READDIRPLUS(inode);
 
-       my_entry.cookie = my_entry.prev_cookie = 0;
-       my_entry.eof = 0;
-       my_entry.fh = nfs_alloc_fhandle();
-       my_entry.fattr = nfs_alloc_fattr();
-       if (my_entry.fh == NULL || my_entry.fattr == NULL)
-               goto out_alloc_failed;
-
-       desc->entry = &my_entry;
-
        nfs_block_sillyrename(dentry);
        res = nfs_revalidate_mapping(inode, filp->f_mapping);
        if (res < 0)
                goto out;
 
-       while(!desc->entry->eof) {
+       while (desc->eof != 1) {
                res = readdir_search_pagecache(desc);
 
                if (res == -EBADCOOKIE) {
                        /* This means either end of directory */
-                       if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) {
+                       if (*desc->dir_cookie && desc->eof == 0) {
                                /* Or that the server has 'lost' a cookie */
                                res = uncached_readdir(desc, dirent, filldir);
                                if (res >= 0)
@@ -588,8 +799,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                if (res == -ETOOSMALL && desc->plus) {
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        nfs_zap_caches(inode);
+                       desc->page_index = 0;
                        desc->plus = 0;
-                       desc->entry->eof = 0;
+                       desc->eof = 0;
                        continue;
                }
                if (res < 0)
@@ -605,9 +817,6 @@ out:
        nfs_unblock_sillyrename(dentry);
        if (res > 0)
                res = 0;
-out_alloc_failed:
-       nfs_free_fattr(my_entry.fattr);
-       nfs_free_fhandle(my_entry.fh);
        dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        res);
@@ -1029,10 +1238,63 @@ static int is_atomic_open(struct nameidata *nd)
        return 1;
 }
 
+static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd)
+{
+       struct path path = {
+               .mnt = nd->path.mnt,
+               .dentry = dentry,
+       };
+       struct nfs_open_context *ctx;
+       struct rpc_cred *cred;
+       fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
+
+       cred = rpc_lookup_cred();
+       if (IS_ERR(cred))
+               return ERR_CAST(cred);
+       ctx = alloc_nfs_open_context(&path, cred, fmode);
+       put_rpccred(cred);
+       if (ctx == NULL)
+               return ERR_PTR(-ENOMEM);
+       return ctx;
+}
+
+static int do_open(struct inode *inode, struct file *filp)
+{
+       nfs_fscache_set_inode_cookie(inode, filp);
+       return 0;
+}
+
+static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
+{
+       struct file *filp;
+       int ret = 0;
+
+       /* If the open_intent is for execute, we have an extra check to make */
+       if (ctx->mode & FMODE_EXEC) {
+               ret = nfs_may_open(ctx->path.dentry->d_inode,
+                               ctx->cred,
+                               nd->intent.open.flags);
+               if (ret < 0)
+                       goto out;
+       }
+       filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open);
+       if (IS_ERR(filp))
+               ret = PTR_ERR(filp);
+       else
+               nfs_file_set_open_context(filp, ctx);
+out:
+       put_nfs_open_context(ctx);
+       return ret;
+}
+
 static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
+       struct nfs_open_context *ctx;
+       struct iattr attr;
        struct dentry *res = NULL;
-       int error;
+       struct inode *inode;
+       int open_flags;
+       int err;
 
        dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1054,13 +1316,32 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
                goto out;
        }
 
+       ctx = nameidata_to_nfs_open_context(dentry, nd);
+       res = ERR_CAST(ctx);
+       if (IS_ERR(ctx))
+               goto out;
+
+       open_flags = nd->intent.open.flags;
+       if (nd->flags & LOOKUP_CREATE) {
+               attr.ia_mode = nd->intent.open.create_mode;
+               attr.ia_valid = ATTR_MODE;
+               if (!IS_POSIXACL(dir))
+                       attr.ia_mode &= ~current_umask();
+       } else {
+               open_flags &= ~(O_EXCL | O_CREAT);
+               attr.ia_valid = 0;
+       }
+
        /* Open the file on the server */
-       res = nfs4_atomic_open(dir, dentry, nd);
-       if (IS_ERR(res)) {
-               error = PTR_ERR(res);
-               switch (error) {
+       nfs_block_sillyrename(dentry->d_parent);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+       if (IS_ERR(inode)) {
+               nfs_unblock_sillyrename(dentry->d_parent);
+               put_nfs_open_context(ctx);
+               switch (PTR_ERR(inode)) {
                        /* Make a negative dentry */
                        case -ENOENT:
+                               d_add(dentry, NULL);
                                res = NULL;
                                goto out;
                        /* This turned out not to be a regular file */
@@ -1072,11 +1353,25 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
                                        goto no_open;
                        /* case -EINVAL: */
                        default:
+                               res = ERR_CAST(inode);
                                goto out;
                }
-       } else if (res != NULL)
+       }
+       res = d_add_unique(dentry, inode);
+       nfs_unblock_sillyrename(dentry->d_parent);
+       if (res != NULL) {
+               dput(ctx->path.dentry);
+               ctx->path.dentry = dget(res);
                dentry = res;
+       }
+       err = nfs_intent_set_file(nd, ctx);
+       if (err < 0) {
+               if (res != NULL)
+                       dput(res);
+               return ERR_PTR(err);
+       }
 out:
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        return res;
 no_open:
        return nfs_lookup(dir, dentry, nd);
@@ -1087,12 +1382,15 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct dentry *parent = NULL;
        struct inode *inode = dentry->d_inode;
        struct inode *dir;
+       struct nfs_open_context *ctx;
        int openflags, ret = 0;
 
        if (!is_atomic_open(nd) || d_mountpoint(dentry))
                goto no_open;
+
        parent = dget_parent(dentry);
        dir = parent->d_inode;
+
        /* We can't create new files in nfs_open_revalidate(), so we
         * optimize away revalidation of negative dentries.
         */
@@ -1112,99 +1410,96 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* We can't create new files, or truncate existing ones here */
        openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
 
+       ctx = nameidata_to_nfs_open_context(dentry, nd);
+       ret = PTR_ERR(ctx);
+       if (IS_ERR(ctx))
+               goto out;
        /*
         * Note: we're not holding inode->i_mutex and so may be racing with
         * operations that change the directory. We therefore save the
         * change attribute *before* we do the RPC call.
         */
-       ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
+               switch (ret) {
+               case -EPERM:
+               case -EACCES:
+               case -EDQUOT:
+               case -ENOSPC:
+               case -EROFS:
+                       goto out_put_ctx;
+               default:
+                       goto out_drop;
+               }
+       }
+       iput(inode);
+       if (inode != dentry->d_inode)
+               goto out_drop;
+
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+       ret = nfs_intent_set_file(nd, ctx);
+       if (ret >= 0)
+               ret = 1;
 out:
        dput(parent);
-       if (!ret)
-               d_drop(dentry);
        return ret;
+out_drop:
+       d_drop(dentry);
+       ret = 0;
+out_put_ctx:
+       put_nfs_open_context(ctx);
+       goto out;
+
 no_open_dput:
        dput(parent);
 no_open:
        return nfs_lookup_revalidate(dentry, nd);
 }
-#endif /* CONFIG_NFSV4 */
 
-static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
+static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode,
+               struct nameidata *nd)
 {
-       struct dentry *parent = desc->file->f_path.dentry;
-       struct inode *dir = parent->d_inode;
-       struct nfs_entry *entry = desc->entry;
-       struct dentry *dentry, *alias;
-       struct qstr name = {
-               .name = entry->name,
-               .len = entry->len,
-       };
-       struct inode *inode;
-       unsigned long verf = nfs_save_change_attribute(dir);
+       struct nfs_open_context *ctx = NULL;
+       struct iattr attr;
+       int error;
+       int open_flags = 0;
 
-       switch (name.len) {
-               case 2:
-                       if (name.name[0] == '.' && name.name[1] == '.')
-                               return dget_parent(parent);
-                       break;
-               case 1:
-                       if (name.name[0] == '.')
-                               return dget(parent);
-       }
+       dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
+                       dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
-       spin_lock(&dir->i_lock);
-       if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {
-               spin_unlock(&dir->i_lock);
-               return NULL;
-       }
-       spin_unlock(&dir->i_lock);
+       attr.ia_mode = mode;
+       attr.ia_valid = ATTR_MODE;
 
-       name.hash = full_name_hash(name.name, name.len);
-       dentry = d_lookup(parent, &name);
-       if (dentry != NULL) {
-               /* Is this a positive dentry that matches the readdir info? */
-               if (dentry->d_inode != NULL &&
-                               (NFS_FILEID(dentry->d_inode) == entry->ino ||
-                               d_mountpoint(dentry))) {
-                       if (!desc->plus || entry->fh->size == 0)
-                               return dentry;
-                       if (nfs_compare_fh(NFS_FH(dentry->d_inode),
-                                               entry->fh) == 0)
-                               goto out_renew;
-               }
-               /* No, so d_drop to allow one to be created */
-               d_drop(dentry);
-               dput(dentry);
-       }
-       if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR))
-               return NULL;
-       if (name.len > NFS_SERVER(dir)->namelen)
-               return NULL;
-       /* Note: caller is already holding the dir->i_mutex! */
-       dentry = d_alloc(parent, &name);
-       if (dentry == NULL)
-               return NULL;
-       dentry->d_op = NFS_PROTO(dir)->dentry_ops;
-       inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
-       if (IS_ERR(inode)) {
-               dput(dentry);
-               return NULL;
-       }
+       if ((nd->flags & LOOKUP_CREATE) != 0) {
+               open_flags = nd->intent.open.flags;
 
-       alias = d_materialise_unique(dentry, inode);
-       if (alias != NULL) {
-               dput(dentry);
-               if (IS_ERR(alias))
-                       return NULL;
-               dentry = alias;
+               ctx = nameidata_to_nfs_open_context(dentry, nd);
+               error = PTR_ERR(ctx);
+               if (IS_ERR(ctx))
+                       goto out_err_drop;
        }
 
-out_renew:
-       nfs_set_verifier(dentry, verf);
-       return dentry;
+       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
+       if (error != 0)
+               goto out_put_ctx;
+       if (ctx != NULL) {
+               error = nfs_intent_set_file(nd, ctx);
+               if (error < 0)
+                       goto out_err;
+       }
+       return 0;
+out_put_ctx:
+       if (ctx != NULL)
+               put_nfs_open_context(ctx);
+out_err_drop:
+       d_drop(dentry);
+out_err:
+       return error;
 }
 
+#endif /* CONFIG_NFSV4 */
+
 /*
  * Code common to create, mkdir, and mknod.
  */
@@ -1258,7 +1553,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
 {
        struct iattr attr;
        int error;
-       int open_flags = 0;
 
        dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1266,10 +1560,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
 
-       if ((nd->flags & LOOKUP_CREATE) != 0)
-               open_flags = nd->intent.open.flags;
-
-       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
+       error = NFS_PROTO(dir)->create(dir, dentry, &attr, 0, NULL);
        if (error != 0)
                goto out_err;
        return 0;
@@ -1351,76 +1642,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
        return error;
 }
 
-static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
-{
-       static unsigned int sillycounter;
-       const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
-       const int      countersize = sizeof(sillycounter)*2;
-       const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
-       char           silly[slen+1];
-       struct qstr    qsilly;
-       struct dentry *sdentry;
-       int            error = -EIO;
-
-       dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
-               dentry->d_parent->d_name.name, dentry->d_name.name, 
-               atomic_read(&dentry->d_count));
-       nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
-
-       /*
-        * We don't allow a dentry to be silly-renamed twice.
-        */
-       error = -EBUSY;
-       if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
-               goto out;
-
-       sprintf(silly, ".nfs%*.*Lx",
-               fileidsize, fileidsize,
-               (unsigned long long)NFS_FILEID(dentry->d_inode));
-
-       /* Return delegation in anticipation of the rename */
-       nfs_inode_return_delegation(dentry->d_inode);
-
-       sdentry = NULL;
-       do {
-               char *suffix = silly + slen - countersize;
-
-               dput(sdentry);
-               sillycounter++;
-               sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
-
-               dfprintk(VFS, "NFS: trying to rename %s to %s\n",
-                               dentry->d_name.name, silly);
-               
-               sdentry = lookup_one_len(silly, dentry->d_parent, slen);
-               /*
-                * N.B. Better to return EBUSY here ... it could be
-                * dangerous to delete the file while it's in use.
-                */
-               if (IS_ERR(sdentry))
-                       goto out;
-       } while(sdentry->d_inode != NULL); /* need negative lookup */
-
-       qsilly.name = silly;
-       qsilly.len  = strlen(silly);
-       if (dentry->d_inode) {
-               error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
-                               dir, &qsilly);
-               nfs_mark_for_revalidate(dentry->d_inode);
-       } else
-               error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
-                               dir, &qsilly);
-       if (!error) {
-               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-               d_move(dentry, sdentry);
-               error = nfs_async_unlink(dir, dentry);
-               /* If we return 0 we don't unlink */
-       }
-       dput(sdentry);
-out:
-       return error;
-}
-
 /*
  * Remove a file after making sure there are no pending writes,
  * and after checking that the file has only one user. 
@@ -1580,7 +1801,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
        d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
-               atomic_inc(&inode->i_count);
+               ihold(inode);
                d_add(dentry, inode);
        }
        return error;
@@ -1711,14 +1932,14 @@ static void nfs_access_free_list(struct list_head *head)
 int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
 {
        LIST_HEAD(head);
-       struct nfs_inode *nfsi;
+       struct nfs_inode *nfsi, *next;
        struct nfs_access_entry *cache;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
                return (nr_to_scan == 0) ? 0 : -1;
 
        spin_lock(&nfs_access_lru_lock);
-       list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
+       list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) {
                struct inode *inode;
 
                if (nr_to_scan-- == 0)
index dba50a5625db7987d1e4a757063f3a5412ff5928..a6e711ad130f9fdb456ad2a09b056214815af4f5 100644 (file)
@@ -167,7 +167,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
                return 0;
        }
        item = container_of(h, struct nfs_dns_ent, h);
-       ttl = (long)item->h.expiry_time - (long)get_seconds();
+       ttl = item->h.expiry_time - seconds_since_boot();
        if (ttl < 0)
                ttl = 0;
 
@@ -239,7 +239,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
        ttl = get_expiry(&buf);
        if (ttl == 0)
                goto out;
-       key.h.expiry_time = ttl + get_seconds();
+       key.h.expiry_time = ttl + seconds_since_boot();
 
        ret = -ENOMEM;
        item = nfs_dns_lookup(cd, &key);
@@ -301,7 +301,7 @@ static int do_cache_lookup_nowait(struct cache_detail *cd,
                goto out_err;
        ret = -ETIMEDOUT;
        if (!test_bit(CACHE_VALID, &(*item)->h.flags)
-                       || (*item)->h.expiry_time < get_seconds()
+                       || (*item)->h.expiry_time < seconds_since_boot()
                        || cd->flush_time > (*item)->h.last_refresh)
                goto out_put;
        ret = -ENOENT;
index 05bf3c0dc751d5d489b1c7be2cf594005caf1695..e756075637b005ba1937b275c2d77ed3ff8ad676 100644 (file)
@@ -36,6 +36,7 @@
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
 
@@ -386,6 +387,10 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
                file->f_path.dentry->d_name.name,
                mapping->host->i_ino, len, (long long) pos);
 
+       pnfs_update_layout(mapping->host,
+                          nfs_file_open_context(file),
+                          IOMODE_RW);
+
 start:
        /*
         * Prevent starvation issues if someone is doing a consistency
@@ -551,7 +556,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct file *filp = vma->vm_file;
        struct dentry *dentry = filp->f_path.dentry;
        unsigned pagelen;
-       int ret = -EINVAL;
+       int ret = VM_FAULT_NOPAGE;
        struct address_space *mapping;
 
        dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n",
@@ -567,21 +572,20 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (mapping != dentry->d_inode->i_mapping)
                goto out_unlock;
 
-       ret = 0;
        pagelen = nfs_page_length(page);
        if (pagelen == 0)
                goto out_unlock;
 
-       ret = nfs_flush_incompatible(filp, page);
-       if (ret != 0)
-               goto out_unlock;
+       ret = VM_FAULT_LOCKED;
+       if (nfs_flush_incompatible(filp, page) == 0 &&
+           nfs_updatepage(filp, page, 0, pagelen) == 0)
+               goto out;
 
-       ret = nfs_updatepage(filp, page, 0, pagelen);
+       ret = VM_FAULT_SIGBUS;
 out_unlock:
-       if (!ret)
-               return VM_FAULT_LOCKED;
        unlock_page(page);
-       return VM_FAULT_SIGBUS;
+out:
+       return ret;
 }
 
 static const struct vm_operations_struct nfs_file_vm_ops = {
@@ -684,7 +688,8 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
        return ret;
 }
 
-static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status = 0;
@@ -699,7 +704,7 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
        if (nfs_have_delegation(inode, FMODE_READ))
                goto out_noconflict;
 
-       if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+       if (is_local)
                goto out_noconflict;
 
        status = NFS_PROTO(inode)->lock(filp, cmd, fl);
@@ -726,7 +731,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
        return res;
 }
 
-static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status;
@@ -741,15 +747,24 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
         *      If we're signalled while cleaning up locks on process exit, we
         *      still need to complete the unlock.
         */
-       /* Use local locking if mounted with "-onolock" */
-       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+       /*
+        * Use local locking if mounted with "-onolock" or with appropriate
+        * "-olocal_lock="
+        */
+       if (!is_local)
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
        return status;
 }
 
-static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+is_time_granular(struct timespec *ts) {
+       return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
+}
+
+static int
+do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status;
@@ -762,20 +777,31 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
        if (status != 0)
                goto out;
 
-       /* Use local locking if mounted with "-onolock" */
-       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+       /*
+        * Use local locking if mounted with "-onolock" or with appropriate
+        * "-olocal_lock="
+        */
+       if (!is_local)
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
        if (status < 0)
                goto out;
+
        /*
-        * Make sure we clear the cache whenever we try to get the lock.
+        * Revalidate the cache if the server has time stamps granular
+        * enough to detect subsecond changes.  Otherwise, clear the
+        * cache to prevent missing any changes.
+        *
         * This makes locking act as a cache coherency point.
         */
        nfs_sync_mapping(filp->f_mapping);
-       if (!nfs_have_delegation(inode, FMODE_READ))
-               nfs_zap_caches(inode);
+       if (!nfs_have_delegation(inode, FMODE_READ)) {
+               if (is_time_granular(&NFS_SERVER(inode)->time_delta))
+                       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+               else
+                       nfs_zap_caches(inode);
+       }
 out:
        return status;
 }
@@ -787,6 +813,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = filp->f_mapping->host;
        int ret = -ENOLCK;
+       int is_local = 0;
 
        dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
@@ -800,6 +827,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
                goto out_err;
 
+       if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
+               is_local = 1;
+
        if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
                ret = NFS_PROTO(inode)->lock_check_bounds(fl);
                if (ret < 0)
@@ -807,11 +837,11 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        }
 
        if (IS_GETLK(cmd))
-               ret = do_getlk(filp, cmd, fl);
+               ret = do_getlk(filp, cmd, fl, is_local);
        else if (fl->fl_type == F_UNLCK)
-               ret = do_unlk(filp, cmd, fl);
+               ret = do_unlk(filp, cmd, fl, is_local);
        else
-               ret = do_setlk(filp, cmd, fl);
+               ret = do_setlk(filp, cmd, fl, is_local);
 out_err:
        return ret;
 }
@@ -821,6 +851,9 @@ out_err:
  */
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 {
+       struct inode *inode = filp->f_mapping->host;
+       int is_local = 0;
+
        dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
                        filp->f_path.dentry->d_name.name,
@@ -829,14 +862,17 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
 
+       if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
+               is_local = 1;
+
        /* We're simulating flock() locks using posix locks on the server */
        fl->fl_owner = (fl_owner_t)filp;
        fl->fl_start = 0;
        fl->fl_end = OFFSET_MAX;
 
        if (fl->fl_type == F_UNLCK)
-               return do_unlk(filp, cmd, fl);
-       return do_setlk(filp, cmd, fl);
+               return do_unlk(filp, cmd, fl, is_local);
+       return do_setlk(filp, cmd, fl, is_local);
 }
 
 /*
index a70e446e1605fa43fb1b23b96418d8296773109f..ac7b814ce1620f3e5cb0afa3334d31d1d540a52b 100644 (file)
@@ -54,8 +54,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
                        iput(inode);
                        return -ENOMEM;
                }
-               /* Circumvent igrab(): we know the inode is not being freed */
-               atomic_inc(&inode->i_count);
+               ihold(inode);
                /*
                 * Ensure that this dentry is invisible to d_find_alias().
                 * Otherwise, it may be spliced into the tree by
index 21a84d45916fc7cab0a40e20f3ae41a838f4bf17..dec47ed8b6b9aae84cd9d5071d098870a0267d44 100644 (file)
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
+
+#include <linux/slab.h>
+#include <linux/cred.h>
+#include <linux/nfs_idmap.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <linux/rcupdate.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include <keys/user-type.h>
+
+#define NFS_UINT_MAXLEN 11
+
+const struct cred *id_resolver_cache;
+
+struct key_type key_type_id_resolver = {
+       .name           = "id_resolver",
+       .instantiate    = user_instantiate,
+       .match          = user_match,
+       .revoke         = user_revoke,
+       .destroy        = user_destroy,
+       .describe       = user_describe,
+       .read           = user_read,
+};
+
+int nfs_idmap_init(void)
+{
+       struct cred *cred;
+       struct key *keyring;
+       int ret = 0;
+
+       printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
+
+       cred = prepare_kernel_cred(NULL);
+       if (!cred)
+               return -ENOMEM;
+
+       keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred,
+                            (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                            KEY_USR_VIEW | KEY_USR_READ,
+                            KEY_ALLOC_NOT_IN_QUOTA);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto failed_put_cred;
+       }
+
+       ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
+       if (ret < 0)
+               goto failed_put_key;
+
+       ret = register_key_type(&key_type_id_resolver);
+       if (ret < 0)
+               goto failed_put_key;
+
+       cred->thread_keyring = keyring;
+       cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+       id_resolver_cache = cred;
+       return 0;
+
+failed_put_key:
+       key_put(keyring);
+failed_put_cred:
+       put_cred(cred);
+       return ret;
+}
+
+void nfs_idmap_quit(void)
+{
+       key_revoke(id_resolver_cache->thread_keyring);
+       unregister_key_type(&key_type_id_resolver);
+       put_cred(id_resolver_cache);
+}
+
+/*
+ * Assemble the description to pass to request_key()
+ * This function will allocate a new string and update dest to point
+ * at it.  The caller is responsible for freeing dest.
+ *
+ * On error 0 is returned.  Otherwise, the length of dest is returned.
+ */
+static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
+                               const char *type, size_t typelen, char **desc)
+{
+       char *cp;
+       size_t desclen = typelen + namelen + 2;
+
+       *desc = kmalloc(desclen, GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+
+       cp = *desc;
+       memcpy(cp, type, typelen);
+       cp += typelen;
+       *cp++ = ':';
+
+       memcpy(cp, name, namelen);
+       cp += namelen;
+       *cp = '\0';
+       return desclen;
+}
+
+static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
+               const char *type, void *data, size_t data_size)
+{
+       const struct cred *saved_cred;
+       struct key *rkey;
+       char *desc;
+       struct user_key_payload *payload;
+       ssize_t ret;
+
+       ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
+       if (ret <= 0)
+               goto out;
+
+       saved_cred = override_creds(id_resolver_cache);
+       rkey = request_key(&key_type_id_resolver, desc, "");
+       revert_creds(saved_cred);
+       kfree(desc);
+       if (IS_ERR(rkey)) {
+               ret = PTR_ERR(rkey);
+               goto out;
+       }
+
+       rcu_read_lock();
+       rkey->perm |= KEY_USR_VIEW;
+
+       ret = key_validate(rkey);
+       if (ret < 0)
+               goto out_up;
+
+       payload = rcu_dereference(rkey->payload.data);
+       if (IS_ERR_OR_NULL(payload)) {
+               ret = PTR_ERR(payload);
+               goto out_up;
+       }
+
+       ret = payload->datalen;
+       if (ret > 0 && ret <= data_size)
+               memcpy(data, payload->data, ret);
+       else
+               ret = -EINVAL;
+
+out_up:
+       rcu_read_unlock();
+       key_put(rkey);
+out:
+       return ret;
+}
+
+
+/* ID -> Name */
+static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
+{
+       char id_str[NFS_UINT_MAXLEN];
+       int id_len;
+       ssize_t ret;
+
+       id_len = snprintf(id_str, sizeof(id_str), "%u", id);
+       ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
+       if (ret < 0)
+               return -EINVAL;
+       return ret;
+}
+
+/* Name -> ID */
+static int nfs_idmap_lookup_id(const char *name, size_t namelen,
+                               const char *type, __u32 *id)
+{
+       char id_str[NFS_UINT_MAXLEN];
+       long id_long;
+       ssize_t data_size;
+       int ret = 0;
+
+       data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
+       if (data_size <= 0) {
+               ret = -EINVAL;
+       } else {
+               ret = strict_strtol(id_str, 10, &id_long);
+               *id = (__u32)id_long;
+       }
+       return ret;
+}
+
+int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+{
+       return nfs_idmap_lookup_id(name, namelen, "uid", uid);
+}
+
+int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *gid)
+{
+       return nfs_idmap_lookup_id(name, namelen, "gid", gid);
+}
+
+int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
+{
+       return nfs_idmap_lookup_name(uid, "user", buf, buflen);
+}
+int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t buflen)
+{
+       return nfs_idmap_lookup_name(gid, "group", buf, buflen);
+}
+
+#else  /* CONFIG_NFS_USE_IDMAPPER not defined */
+
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/init.h>
@@ -503,16 +709,17 @@ int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namele
        return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
 }
 
-int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
+int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
 {
        struct idmap *idmap = clp->cl_idmap;
 
        return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
 }
-int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
+int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
 {
        struct idmap *idmap = clp->cl_idmap;
 
        return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
 }
 
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
index 7d2d6c72aa780f8f68c8b919d98963d4ba8a31fb..314f57164602eda0762c0a226db44aa19be461f5 100644 (file)
@@ -48,6 +48,7 @@
 #include "internal.h"
 #include "fscache.h"
 #include "dns_resolve.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -234,9 +235,6 @@ nfs_init_locked(struct inode *inode, void *opaque)
        return 0;
 }
 
-/* Don't use READDIRPLUS on directories that we believe are too large */
-#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
-
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
@@ -291,8 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                } else if (S_ISDIR(inode->i_mode)) {
                        inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
                        inode->i_fop = &nfs_dir_operations;
-                       if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
-                           && fattr->size <= NFS_LIMIT_READDIRPLUS)
+                       if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
                                set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
                        if ((fattr->valid & NFS_ATTR_FATTR_FSID)
@@ -623,7 +620,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
        nfs_revalidate_inode(server, inode);
 }
 
-static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred)
+struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode)
 {
        struct nfs_open_context *ctx;
 
@@ -633,11 +630,13 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
                path_get(&ctx->path);
                ctx->cred = get_rpccred(cred);
                ctx->state = NULL;
+               ctx->mode = f_mode;
                ctx->flags = 0;
                ctx->error = 0;
                ctx->dir_cookie = 0;
                nfs_init_lock_context(&ctx->lock_context);
                ctx->lock_context.open_context = ctx;
+               INIT_LIST_HEAD(&ctx->list);
        }
        return ctx;
 }
@@ -653,11 +652,15 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
 {
        struct inode *inode = ctx->path.dentry->d_inode;
 
-       if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
+       if (!list_empty(&ctx->list)) {
+               if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
+                       return;
+               list_del(&ctx->list);
+               spin_unlock(&inode->i_lock);
+       } else if (!atomic_dec_and_test(&ctx->lock_context.count))
                return;
-       list_del(&ctx->list);
-       spin_unlock(&inode->i_lock);
-       NFS_PROTO(inode)->close_context(ctx, is_sync);
+       if (inode != NULL)
+               NFS_PROTO(inode)->close_context(ctx, is_sync);
        if (ctx->cred != NULL)
                put_rpccred(ctx->cred);
        path_put(&ctx->path);
@@ -673,7 +676,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
  * Ensure that mmap has a recent RPC credential for use when writing out
  * shared pages
  */
-static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
+void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -730,11 +733,10 @@ int nfs_open(struct inode *inode, struct file *filp)
        cred = rpc_lookup_cred();
        if (IS_ERR(cred))
                return PTR_ERR(cred);
-       ctx = alloc_nfs_open_context(&filp->f_path, cred);
+       ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode);
        put_rpccred(cred);
        if (ctx == NULL)
                return -ENOMEM;
-       ctx->mode = filp->f_mode;
        nfs_file_set_open_context(filp, ctx);
        put_nfs_open_context(ctx);
        nfs_fscache_set_inode_cookie(inode, filp);
@@ -1409,6 +1411,7 @@ void nfs4_evict_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
+       pnfs_destroy_layout(NFS_I(inode));
        /* If we are holding a delegation, return it! */
        nfs_inode_return_delegation_noreclaim(inode);
        /* First call standard NFS clear_inode() code */
@@ -1446,6 +1449,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
        nfsi->delegation = NULL;
        nfsi->delegation_state = 0;
        init_rwsem(&nfsi->rwsem);
+       nfsi->layout = NULL;
 #endif
 }
 
@@ -1493,7 +1497,7 @@ static int nfsiod_start(void)
 {
        struct workqueue_struct *wq;
        dprintk("RPC:       creating workqueue nfsiod\n");
-       wq = create_singlethread_workqueue("nfsiod");
+       wq = alloc_workqueue("nfsiod", WQ_RESCUER, 0);
        if (wq == NULL)
                return -ENOMEM;
        nfsiod_workqueue = wq;
@@ -1521,6 +1525,10 @@ static int __init init_nfs_fs(void)
 {
        int err;
 
+       err = nfs_idmap_init();
+       if (err < 0)
+               goto out9;
+
        err = nfs_dns_resolver_init();
        if (err < 0)
                goto out8;
@@ -1585,6 +1593,8 @@ out6:
 out7:
        nfs_dns_resolver_destroy();
 out8:
+       nfs_idmap_quit();
+out9:
        return err;
 }
 
@@ -1597,6 +1607,7 @@ static void __exit exit_nfs_fs(void)
        nfs_destroy_nfspagecache();
        nfs_fscache_unregister();
        nfs_dns_resolver_destroy();
+       nfs_idmap_quit();
 #ifdef CONFIG_PROC_FS
        rpc_proc_unregister("nfs");
 #endif
index c961bc92c107d077b9d9df947ad215cb3071dbbe..db08ff3ff454d840baf84ea8b7ce8e5583c6cdf9 100644 (file)
@@ -62,6 +62,12 @@ struct nfs_clone_mount {
  */
 #define NFS_UNSPEC_PORT                (-1)
 
+/*
+ * Maximum number of pages that readdir can use for creating
+ * a vmapped array of pages.
+ */
+#define NFS_MAX_READDIR_PAGES 8
+
 /*
  * In-kernel mount arguments
  */
@@ -181,15 +187,15 @@ extern void nfs_destroy_directcache(void);
 /* nfs2xdr.c */
 extern int nfs_stat_to_errno(int);
 extern struct rpc_procinfo nfs_procedures[];
-extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
+extern __be32 *nfs_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 
 /* nfs3xdr.c */
 extern struct rpc_procinfo nfs3_procedures[];
-extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
+extern __be32 *nfs3_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 
 /* nfs4xdr.c */
 #ifdef CONFIG_NFS_V4
-extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 #endif
 #ifdef CONFIG_NFS_V4_1
 extern const u32 nfs41_maxread_overhead;
index 59047f8d7d72885869c748721a389307e34e7eca..eceafe74f4737ea5fbcea90b8ac19749737667b9 100644 (file)
@@ -153,6 +153,7 @@ int nfs_mount(struct nfs_mount_request *info)
                .rpc_resp       = &result,
        };
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = info->protocol,
                .address        = info->sap,
                .addrsize       = info->salen,
@@ -224,6 +225,7 @@ void nfs_umount(const struct nfs_mount_request *info)
                .to_retries = 2,
        };
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = IPPROTO_UDP,
                .address        = info->sap,
                .addrsize       = info->salen,
@@ -436,7 +438,7 @@ static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
 
        for (i = 0; i < entries; i++) {
                flavors[i] = ntohl(*p++);
-               dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
+               dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
        }
        *count = i;
 
index db8846a0e82eb686f4722b51dd5f2dbef3c6960d..e6bf45710cc7fcd0348459ed7a27cc9454ee7e88 100644 (file)
@@ -337,10 +337,10 @@ nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
 static int
 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
 {
-       p = xdr_encode_fhandle(p, args->fromfh);
-       p = xdr_encode_array(p, args->fromname, args->fromlen);
-       p = xdr_encode_fhandle(p, args->tofh);
-       p = xdr_encode_array(p, args->toname, args->tolen);
+       p = xdr_encode_fhandle(p, args->old_dir);
+       p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
+       p = xdr_encode_fhandle(p, args->new_dir);
+       p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
        return 0;
 }
@@ -423,9 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
        struct page **page;
        size_t hdrlen;
        unsigned int pglen, recvd;
-       u32 len;
        int status, nr = 0;
-       __be32 *end, *entry, *kaddr;
 
        if ((status = ntohl(*p++)))
                return nfs_stat_to_errno(status);
@@ -445,80 +443,59 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
        if (pglen > recvd)
                pglen = recvd;
        page = rcvbuf->pages;
-       kaddr = p = kmap_atomic(*page, KM_USER0);
-       end = (__be32 *)((char *)p + pglen);
-       entry = p;
-
-       /* Make sure the packet actually has a value_follows and EOF entry */
-       if ((entry + 1) > end)
-               goto short_pkt;
-
-       for (; *p++; nr++) {
-               if (p + 2 > end)
-                       goto short_pkt;
-               p++; /* fileid */
-               len = ntohl(*p++);
-               p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
-               if (len > NFS2_MAXNAMLEN) {
-                       dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
-                                               len);
-                       goto err_unmap;
-               }
-               if (p + 2 > end)
-                       goto short_pkt;
-               entry = p;
-       }
-
-       /*
-        * Apparently some server sends responses that are a valid size, but
-        * contain no entries, and have value_follows==0 and EOF==0. For
-        * those, just set the EOF marker.
-        */
-       if (!nr && entry[1] == 0) {
-               dprintk("NFS: readdir reply truncated!\n");
-               entry[1] = 1;
-       }
- out:
-       kunmap_atomic(kaddr, KM_USER0);
        return nr;
- short_pkt:
-       /*
-        * When we get a short packet there are 2 possibilities. We can
-        * return an error, or fix up the response to look like a valid
-        * response and return what we have so far. If there are no
-        * entries and the packet was short, then return -EIO. If there
-        * are valid entries in the response, return them and pretend that
-        * the call was successful, but incomplete. The caller can retry the
-        * readdir starting at the last cookie.
-        */
-       entry[0] = entry[1] = 0;
-       if (!nr)
-               nr = -errno_NFSERR_IO;
-       goto out;
-err_unmap:
-       nr = -errno_NFSERR_IO;
-       goto out;
+}
+
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
+{
+       dprintk("nfs: %s: prematurely hit end of receive buffer. "
+               "Remaining buffer length is %tu words.\n",
+               func, xdr->end - xdr->p);
 }
 
 __be32 *
-nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
 {
-       if (!*p++) {
-               if (!*p)
+       __be32 *p;
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       if (!ntohl(*p++)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               if (!ntohl(*p++))
                        return ERR_PTR(-EAGAIN);
                entry->eof = 1;
                return ERR_PTR(-EBADCOOKIE);
        }
 
+       p = xdr_inline_decode(xdr, 8);
+       if (unlikely(!p))
+               goto out_overflow;
+
        entry->ino        = ntohl(*p++);
        entry->len        = ntohl(*p++);
+
+       p = xdr_inline_decode(xdr, entry->len + 4);
+       if (unlikely(!p))
+               goto out_overflow;
        entry->name       = (const char *) p;
        p                += XDR_QUADLEN(entry->len);
        entry->prev_cookie        = entry->cookie;
        entry->cookie     = ntohl(*p++);
-       entry->eof        = !p[0] && p[1];
+
+       p = xdr_inline_peek(xdr, 8);
+       if (p != NULL)
+               entry->eof = !p[0] && p[1];
+       else
+               entry->eof = 0;
 
        return p;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return ERR_PTR(-EIO);
 }
 
 /*
@@ -596,7 +573,6 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
        struct kvec *iov = rcvbuf->head;
        size_t hdrlen;
        u32 len, recvd;
-       char    *kaddr;
        int     status;
 
        if ((status = ntohl(*p++)))
@@ -623,10 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
                return -EIO;
        }
 
-       /* NULL terminate the string we got */
-       kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
-       kaddr[len+rcvbuf->page_base] = '\0';
-       kunmap_atomic(kaddr, KM_USER0);
+       xdr_terminate_string(rcvbuf, len);
        return 0;
 }
 
index fabb4f2849a119b0d62745ad9f6aacb2e27cca1a..ce939c062a52728349c261935127960a7ca4389f 100644 (file)
@@ -313,7 +313,7 @@ static void nfs3_free_createdata(struct nfs3_createdata *data)
  */
 static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                int flags, struct nameidata *nd)
+                int flags, struct nfs_open_context *ctx)
 {
        struct nfs3_createdata *data;
        mode_t mode = sattr->ia_mode;
@@ -438,19 +438,38 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        return 1;
 }
 
+static void
+nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+       msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
+}
+
+static int
+nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+                     struct inode *new_dir)
+{
+       struct nfs_renameres *res;
+
+       if (nfs3_async_handle_jukebox(task, old_dir))
+               return 0;
+       res = task->tk_msg.rpc_resp;
+
+       nfs_post_op_update_inode(old_dir, res->old_fattr);
+       nfs_post_op_update_inode(new_dir, res->new_fattr);
+       return 1;
+}
+
 static int
 nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
                 struct inode *new_dir, struct qstr *new_name)
 {
-       struct nfs3_renameargs  arg = {
-               .fromfh         = NFS_FH(old_dir),
-               .fromname       = old_name->name,
-               .fromlen        = old_name->len,
-               .tofh           = NFS_FH(new_dir),
-               .toname         = new_name->name,
-               .tolen          = new_name->len
+       struct nfs_renameargs   arg = {
+               .old_dir        = NFS_FH(old_dir),
+               .old_name       = old_name,
+               .new_dir        = NFS_FH(new_dir),
+               .new_name       = new_name,
        };
-       struct nfs3_renameres res;
+       struct nfs_renameres res;
        struct rpc_message msg = {
                .rpc_proc       = &nfs3_procedures[NFS3PROC_RENAME],
                .rpc_argp       = &arg,
@@ -460,17 +479,17 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
 
        dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
 
-       res.fromattr = nfs_alloc_fattr();
-       res.toattr = nfs_alloc_fattr();
-       if (res.fromattr == NULL || res.toattr == NULL)
+       res.old_fattr = nfs_alloc_fattr();
+       res.new_fattr = nfs_alloc_fattr();
+       if (res.old_fattr == NULL || res.new_fattr == NULL)
                goto out;
 
        status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
-       nfs_post_op_update_inode(old_dir, res.fromattr);
-       nfs_post_op_update_inode(new_dir, res.toattr);
+       nfs_post_op_update_inode(old_dir, res.old_fattr);
+       nfs_post_op_update_inode(new_dir, res.new_fattr);
 out:
-       nfs_free_fattr(res.toattr);
-       nfs_free_fattr(res.fromattr);
+       nfs_free_fattr(res.old_fattr);
+       nfs_free_fattr(res.new_fattr);
        dprintk("NFS reply rename: %d\n", status);
        return status;
 }
@@ -611,7 +630,7 @@ out:
  */
 static int
 nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                 u64 cookie, struct page *page, unsigned int count, int plus)
+                 u64 cookie, struct page **pages, unsigned int count, int plus)
 {
        struct inode            *dir = dentry->d_inode;
        __be32                  *verf = NFS_COOKIEVERF(dir);
@@ -621,7 +640,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                .verf           = {verf[0], verf[1]},
                .plus           = plus,
                .count          = count,
-               .pages          = &page
+               .pages          = pages
        };
        struct nfs3_readdirres  res = {
                .verf           = verf,
@@ -652,7 +671,8 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 
        nfs_free_fattr(res.dir_attr);
 out:
-       dprintk("NFS reply readdir: %d\n", status);
+       dprintk("NFS reply readdir%s: %d\n",
+                       plus? "plus" : "", status);
        return status;
 }
 
@@ -722,7 +742,7 @@ nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
        dprintk("NFS call  fsstat\n");
        nfs_fattr_init(stat->fattr);
        status = rpc_call_sync(server->client, &msg, 0);
-       dprintk("NFS reply statfs: %d\n", status);
+       dprintk("NFS reply fsstat: %d\n", status);
        return status;
 }
 
@@ -844,6 +864,8 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .unlink_setup   = nfs3_proc_unlink_setup,
        .unlink_done    = nfs3_proc_unlink_done,
        .rename         = nfs3_proc_rename,
+       .rename_setup   = nfs3_proc_rename_setup,
+       .rename_done    = nfs3_proc_rename_done,
        .link           = nfs3_proc_link,
        .symlink        = nfs3_proc_symlink,
        .mkdir          = nfs3_proc_mkdir,
index 9769704f8ce626c6fa4c215c494d5dfab1adc7c1..d9a5e832c2579f9b20c0164944ae139509d8fb79 100644 (file)
@@ -100,6 +100,13 @@ static const umode_t nfs_type2fmt[] = {
        [NF3FIFO] = S_IFIFO,
 };
 
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
+{
+       dprintk("nfs: %s: prematurely hit end of receive buffer. "
+               "Remaining buffer length is %tu words.\n",
+               func, xdr->end - xdr->p);
+}
+
 /*
  * Common NFS XDR functions as inlines
  */
@@ -119,6 +126,29 @@ xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
        return NULL;
 }
 
+static inline __be32 *
+xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
+{
+       __be32 *p;
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       fh->size = ntohl(*p++);
+
+       if (fh->size <= NFS3_FHSIZE) {
+               p = xdr_inline_decode(xdr, fh->size);
+               if (unlikely(!p))
+                       goto out_overflow;
+               memcpy(fh->data, p, fh->size);
+               return p + XDR_QUADLEN(fh->size);
+       }
+       return NULL;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return ERR_PTR(-EIO);
+}
+
 /*
  * Encode/decode time.
  */
@@ -240,6 +270,26 @@ xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
        return p;
 }
 
+static inline __be32 *
+xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+{
+       __be32 *p;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       if (ntohl(*p++)) {
+               p = xdr_inline_decode(xdr, 84);
+               if (unlikely(!p))
+                       goto out_overflow;
+               p = xdr_decode_fattr(p, fattr);
+       }
+       return p;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return ERR_PTR(-EIO);
+}
+
 static inline __be32 *
 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
 {
@@ -442,12 +492,12 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
  * Encode RENAME arguments
  */
 static int
-nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
 {
-       p = xdr_encode_fhandle(p, args->fromfh);
-       p = xdr_encode_array(p, args->fromname, args->fromlen);
-       p = xdr_encode_fhandle(p, args->tofh);
-       p = xdr_encode_array(p, args->toname, args->tolen);
+       p = xdr_encode_fhandle(p, args->old_dir);
+       p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
+       p = xdr_encode_fhandle(p, args->new_dir);
+       p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
        return 0;
 }
@@ -504,9 +554,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        struct kvec *iov = rcvbuf->head;
        struct page **page;
        size_t hdrlen;
-       u32 len, recvd, pglen;
+       u32 recvd, pglen;
        int status, nr = 0;
-       __be32 *entry, *end, *kaddr;
 
        status = ntohl(*p++);
        /* Decode post_op_attrs */
@@ -536,99 +585,38 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        if (pglen > recvd)
                pglen = recvd;
        page = rcvbuf->pages;
-       kaddr = p = kmap_atomic(*page, KM_USER0);
-       end = (__be32 *)((char *)p + pglen);
-       entry = p;
-
-       /* Make sure the packet actually has a value_follows and EOF entry */
-       if ((entry + 1) > end)
-               goto short_pkt;
-
-       for (; *p++; nr++) {
-               if (p + 3 > end)
-                       goto short_pkt;
-               p += 2;                         /* inode # */
-               len = ntohl(*p++);              /* string length */
-               p += XDR_QUADLEN(len) + 2;      /* name + cookie */
-               if (len > NFS3_MAXNAMLEN) {
-                       dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
-                                               len);
-                       goto err_unmap;
-               }
 
-               if (res->plus) {
-                       /* post_op_attr */
-                       if (p + 2 > end)
-                               goto short_pkt;
-                       if (*p++) {
-                               p += 21;
-                               if (p + 1 > end)
-                                       goto short_pkt;
-                       }
-                       /* post_op_fh3 */
-                       if (*p++) {
-                               if (p + 1 > end)
-                                       goto short_pkt;
-                               len = ntohl(*p++);
-                               if (len > NFS3_FHSIZE) {
-                                       dprintk("NFS: giant filehandle in "
-                                               "readdir (len 0x%x)!\n", len);
-                                       goto err_unmap;
-                               }
-                               p += XDR_QUADLEN(len);
-                       }
-               }
-
-               if (p + 2 > end)
-                       goto short_pkt;
-               entry = p;
-       }
-
-       /*
-        * Apparently some server sends responses that are a valid size, but
-        * contain no entries, and have value_follows==0 and EOF==0. For
-        * those, just set the EOF marker.
-        */
-       if (!nr && entry[1] == 0) {
-               dprintk("NFS: readdir reply truncated!\n");
-               entry[1] = 1;
-       }
- out:
-       kunmap_atomic(kaddr, KM_USER0);
        return nr;
- short_pkt:
-       /*
-        * When we get a short packet there are 2 possibilities. We can
-        * return an error, or fix up the response to look like a valid
-        * response and return what we have so far. If there are no
-        * entries and the packet was short, then return -EIO. If there
-        * are valid entries in the response, return them and pretend that
-        * the call was successful, but incomplete. The caller can retry the
-        * readdir starting at the last cookie.
-        */
-       entry[0] = entry[1] = 0;
-       if (!nr)
-               nr = -errno_NFSERR_IO;
-       goto out;
-err_unmap:
-       nr = -errno_NFSERR_IO;
-       goto out;
 }
 
 __be32 *
-nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
 {
+       __be32 *p;
        struct nfs_entry old = *entry;
 
-       if (!*p++) {
-               if (!*p)
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       if (!ntohl(*p++)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               if (!ntohl(*p++))
                        return ERR_PTR(-EAGAIN);
                entry->eof = 1;
                return ERR_PTR(-EBADCOOKIE);
        }
 
+       p = xdr_inline_decode(xdr, 12);
+       if (unlikely(!p))
+               goto out_overflow;
        p = xdr_decode_hyper(p, &entry->ino);
        entry->len  = ntohl(*p++);
+
+       p = xdr_inline_decode(xdr, entry->len + 8);
+       if (unlikely(!p))
+               goto out_overflow;
        entry->name = (const char *) p;
        p += XDR_QUADLEN(entry->len);
        entry->prev_cookie = entry->cookie;
@@ -636,10 +624,17 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 
        if (plus) {
                entry->fattr->valid = 0;
-               p = xdr_decode_post_op_attr(p, entry->fattr);
+               p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
+               if (IS_ERR(p))
+                       goto out_overflow_exit;
                /* In fact, a post_op_fh3: */
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
                if (*p++) {
-                       p = xdr_decode_fhandle(p, entry->fh);
+                       p = xdr_decode_fhandle_stream(xdr, entry->fh);
+                       if (IS_ERR(p))
+                               goto out_overflow_exit;
                        /* Ugh -- server reply was truncated */
                        if (p == NULL) {
                                dprintk("NFS: FH truncated\n");
@@ -650,8 +645,18 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
                        memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
        }
 
-       entry->eof = !p[0] && p[1];
+       p = xdr_inline_peek(xdr, 8);
+       if (p != NULL)
+               entry->eof = !p[0] && p[1];
+       else
+               entry->eof = 0;
+
        return p;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+out_overflow_exit:
+       return ERR_PTR(-EIO);
 }
 
 /*
@@ -824,7 +829,6 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        struct kvec *iov = rcvbuf->head;
        size_t hdrlen;
        u32 len, recvd;
-       char    *kaddr;
        int     status;
 
        status = ntohl(*p++);
@@ -857,10 +861,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
                return -EIO;
        }
 
-       /* NULL terminate the string we got */
-       kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
-       kaddr[len+rcvbuf->page_base] = '\0';
-       kunmap_atomic(kaddr, KM_USER0);
+       xdr_terminate_string(rcvbuf, len);
        return 0;
 }
 
@@ -970,14 +971,14 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
  * Decode RENAME reply
  */
 static int
-nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
+nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
 {
        int     status;
 
        if ((status = ntohl(*p++)) != 0)
                status = nfs_stat_to_errno(status);
-       p = xdr_decode_wcc_data(p, res->fromattr);
-       p = xdr_decode_wcc_data(p, res->toattr);
+       p = xdr_decode_wcc_data(p, res->old_fattr);
+       p = xdr_decode_wcc_data(p, res->new_fattr);
        return status;
 }
 
@@ -1043,8 +1044,9 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
        res->wtmult = ntohl(*p++);
        res->dtpref = ntohl(*p++);
        p = xdr_decode_hyper(p, &res->maxfilesize);
+       p = xdr_decode_time3(p, &res->time_delta);
 
-       /* ignore time_delta and properties */
+       /* ignore properties */
        res->lease_time = 0;
        return 0;
 }
index 311e15cc8af0c961074714a738bc87ff4b7021d5..9fa496387fdfec9a61aa45213c2a99b93982b30b 100644 (file)
@@ -242,8 +242,6 @@ extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
 extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait);
-extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
-extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page);
@@ -333,7 +331,7 @@ extern void nfs_free_seqid(struct nfs_seqid *seqid);
 extern const nfs4_stateid zero_stateid;
 
 /* nfs4xdr.c */
-extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 extern struct rpc_procinfo nfs4_procedures[];
 
 struct nfs4_mount_data;
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
new file mode 100644 (file)
index 0000000..2e92f0d
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ *  Module for the pnfs nfs4 file layout driver.
+ *  Defines all I/O and Policy interface operations, plus code
+ *  to register itself with the pNFS client.
+ *
+ *  Copyright (c) 2002
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+#include "nfs4filelayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
+MODULE_DESCRIPTION("The NFSv4 file layout driver");
+
+static int
+filelayout_set_layoutdriver(struct nfs_server *nfss)
+{
+       int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client,
+                                               nfs4_fl_free_deviceid_callback);
+       if (status) {
+               printk(KERN_WARNING "%s: deviceid cache could not be "
+                       "initialized\n", __func__);
+               return status;
+       }
+       dprintk("%s: deviceid cache has been initialized successfully\n",
+               __func__);
+       return 0;
+}
+
+/* Clear out the layout by destroying its device list */
+static int
+filelayout_clear_layoutdriver(struct nfs_server *nfss)
+{
+       dprintk("--> %s\n", __func__);
+
+       if (nfss->nfs_client->cl_devid_cache)
+               pnfs_put_deviceid_cache(nfss->nfs_client);
+       return 0;
+}
+
+/*
+ * filelayout_check_layout()
+ *
+ * Make sure layout segment parameters are sane WRT the device.
+ * At this point no generic layer initialization of the lseg has occurred,
+ * and nothing has been added to the layout_hdr cache.
+ *
+ */
+static int
+filelayout_check_layout(struct pnfs_layout_hdr *lo,
+                       struct nfs4_filelayout_segment *fl,
+                       struct nfs4_layoutget_res *lgr,
+                       struct nfs4_deviceid *id)
+{
+       struct nfs4_file_layout_dsaddr *dsaddr;
+       int status = -EINVAL;
+       struct nfs_server *nfss = NFS_SERVER(lo->inode);
+
+       dprintk("--> %s\n", __func__);
+
+       if (fl->pattern_offset > lgr->range.offset) {
+               dprintk("%s pattern_offset %lld to large\n",
+                               __func__, fl->pattern_offset);
+               goto out;
+       }
+
+       if (fl->stripe_unit % PAGE_SIZE) {
+               dprintk("%s Stripe unit (%u) not page aligned\n",
+                       __func__, fl->stripe_unit);
+               goto out;
+       }
+
+       /* find and reference the deviceid */
+       dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id);
+       if (dsaddr == NULL) {
+               dsaddr = get_device_info(lo->inode, id);
+               if (dsaddr == NULL)
+                       goto out;
+       }
+       fl->dsaddr = dsaddr;
+
+       if (fl->first_stripe_index < 0 ||
+           fl->first_stripe_index >= dsaddr->stripe_count) {
+               dprintk("%s Bad first_stripe_index %d\n",
+                               __func__, fl->first_stripe_index);
+               goto out_put;
+       }
+
+       if ((fl->stripe_type == STRIPE_SPARSE &&
+           fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
+           (fl->stripe_type == STRIPE_DENSE &&
+           fl->num_fh != dsaddr->stripe_count)) {
+               dprintk("%s num_fh %u not valid for given packing\n",
+                       __func__, fl->num_fh);
+               goto out_put;
+       }
+
+       if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
+               dprintk("%s Stripe unit (%u) not aligned with rsize %u "
+                       "wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
+                       nfss->wsize);
+       }
+
+       status = 0;
+out:
+       dprintk("--> %s returns %d\n", __func__, status);
+       return status;
+out_put:
+       pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid);
+       goto out;
+}
+
+static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
+{
+       int i;
+
+       for (i = 0; i < fl->num_fh; i++) {
+               if (!fl->fh_array[i])
+                       break;
+               kfree(fl->fh_array[i]);
+       }
+       kfree(fl->fh_array);
+       fl->fh_array = NULL;
+}
+
+static void
+_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
+{
+       filelayout_free_fh_array(fl);
+       kfree(fl);
+}
+
+static int
+filelayout_decode_layout(struct pnfs_layout_hdr *flo,
+                        struct nfs4_filelayout_segment *fl,
+                        struct nfs4_layoutget_res *lgr,
+                        struct nfs4_deviceid *id)
+{
+       uint32_t *p = (uint32_t *)lgr->layout.buf;
+       uint32_t nfl_util;
+       int i;
+
+       dprintk("%s: set_layout_map Begin\n", __func__);
+
+       memcpy(id, p, sizeof(*id));
+       p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+       print_deviceid(id);
+
+       nfl_util = be32_to_cpup(p++);
+       if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
+               fl->commit_through_mds = 1;
+       if (nfl_util & NFL4_UFLG_DENSE)
+               fl->stripe_type = STRIPE_DENSE;
+       else
+               fl->stripe_type = STRIPE_SPARSE;
+       fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
+
+       fl->first_stripe_index = be32_to_cpup(p++);
+       p = xdr_decode_hyper(p, &fl->pattern_offset);
+       fl->num_fh = be32_to_cpup(p++);
+
+       dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
+               __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
+               fl->pattern_offset);
+
+       fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
+                              GFP_KERNEL);
+       if (!fl->fh_array)
+               return -ENOMEM;
+
+       for (i = 0; i < fl->num_fh; i++) {
+               /* Do we want to use a mempool here? */
+               fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+               if (!fl->fh_array[i]) {
+                       filelayout_free_fh_array(fl);
+                       return -ENOMEM;
+               }
+               fl->fh_array[i]->size = be32_to_cpup(p++);
+               if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
+                       printk(KERN_ERR "Too big fh %d received %d\n",
+                              i, fl->fh_array[i]->size);
+                       filelayout_free_fh_array(fl);
+                       return -EIO;
+               }
+               memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
+               p += XDR_QUADLEN(fl->fh_array[i]->size);
+               dprintk("DEBUG: %s: fh len %d\n", __func__,
+                       fl->fh_array[i]->size);
+       }
+
+       return 0;
+}
+
+static struct pnfs_layout_segment *
+filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
+                     struct nfs4_layoutget_res *lgr)
+{
+       struct nfs4_filelayout_segment *fl;
+       int rc;
+       struct nfs4_deviceid id;
+
+       dprintk("--> %s\n", __func__);
+       fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+       if (!fl)
+               return NULL;
+
+       rc = filelayout_decode_layout(layoutid, fl, lgr, &id);
+       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) {
+               _filelayout_free_lseg(fl);
+               return NULL;
+       }
+       return &fl->generic_hdr;
+}
+
+static void
+filelayout_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       struct nfs_server *nfss = NFS_SERVER(lseg->layout->inode);
+       struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
+
+       dprintk("--> %s\n", __func__);
+       pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache,
+                         &fl->dsaddr->deviceid);
+       _filelayout_free_lseg(fl);
+}
+
+static struct pnfs_layoutdriver_type filelayout_type = {
+       .id = LAYOUT_NFSV4_1_FILES,
+       .name = "LAYOUT_NFSV4_1_FILES",
+       .owner = THIS_MODULE,
+       .set_layoutdriver = filelayout_set_layoutdriver,
+       .clear_layoutdriver = filelayout_clear_layoutdriver,
+       .alloc_lseg              = filelayout_alloc_lseg,
+       .free_lseg               = filelayout_free_lseg,
+};
+
+static int __init nfs4filelayout_init(void)
+{
+       printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
+              __func__);
+       return pnfs_register_layoutdriver(&filelayout_type);
+}
+
+static void __exit nfs4filelayout_exit(void)
+{
+       printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
+              __func__);
+       pnfs_unregister_layoutdriver(&filelayout_type);
+}
+
+module_init(nfs4filelayout_init);
+module_exit(nfs4filelayout_exit);
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
new file mode 100644 (file)
index 0000000..bbf60dd
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  NFSv4 file layout driver data structures.
+ *
+ *  Copyright (c) 2002
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#ifndef FS_NFS_NFS4FILELAYOUT_H
+#define FS_NFS_NFS4FILELAYOUT_H
+
+#include "pnfs.h"
+
+/*
+ * Field testing shows we need to support upto 4096 stripe indices.
+ * We store each index as a u8 (u32 on the wire) to keep the memory footprint
+ * reasonable. This in turn means we support a maximum of 256
+ * RFC 5661 multipath_list4 structures.
+ */
+#define NFS4_PNFS_MAX_STRIPE_CNT 4096
+#define NFS4_PNFS_MAX_MULTI_CNT  256 /* 256 fit into a u8 stripe_index */
+
+enum stripetype4 {
+       STRIPE_SPARSE = 1,
+       STRIPE_DENSE = 2
+};
+
+/* Individual ip address */
+struct nfs4_pnfs_ds {
+       struct list_head        ds_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
+       u32                     ds_ip_addr;
+       u32                     ds_port;
+       struct nfs_client       *ds_clp;
+       atomic_t                ds_count;
+};
+
+struct nfs4_file_layout_dsaddr {
+       struct pnfs_deviceid_node       deviceid;
+       u32                             stripe_count;
+       u8                              *stripe_indices;
+       u32                             ds_num;
+       struct nfs4_pnfs_ds             *ds_list[1];
+};
+
+struct nfs4_filelayout_segment {
+       struct pnfs_layout_segment generic_hdr;
+       u32 stripe_type;
+       u32 commit_through_mds;
+       u32 stripe_unit;
+       u32 first_stripe_index;
+       u64 pattern_offset;
+       struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
+       unsigned int num_fh;
+       struct nfs_fh **fh_array;
+};
+
+static inline struct nfs4_filelayout_segment *
+FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
+{
+       return container_of(lseg,
+                           struct nfs4_filelayout_segment,
+                           generic_hdr);
+}
+
+extern void nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *);
+extern void print_ds(struct nfs4_pnfs_ds *ds);
+extern void print_deviceid(struct nfs4_deviceid *dev_id);
+extern struct nfs4_file_layout_dsaddr *
+nfs4_fl_find_get_deviceid(struct nfs_client *, struct nfs4_deviceid *dev_id);
+struct nfs4_file_layout_dsaddr *
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id);
+
+#endif /* FS_NFS_NFS4FILELAYOUT_H */
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
new file mode 100644 (file)
index 0000000..51fe64a
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  Device operations for the pnfs nfs4 file layout driver.
+ *
+ *  Copyright (c) 2002
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *  Garth Goodson   <Garth.Goodson@netapp.com>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#include <linux/nfs_fs.h>
+#include <linux/vmalloc.h>
+
+#include "internal.h"
+#include "nfs4filelayout.h"
+
+#define NFSDBG_FACILITY                NFSDBG_PNFS_LD
+
+/*
+ * Data server cache
+ *
+ * Data servers can be mapped to different device ids.
+ * nfs4_pnfs_ds reference counting
+ *   - set to 1 on allocation
+ *   - incremented when a device id maps a data server already in the cache.
+ *   - decremented when deviceid is removed from the cache.
+ */
+DEFINE_SPINLOCK(nfs4_ds_cache_lock);
+static LIST_HEAD(nfs4_data_server_cache);
+
+/* Debug routines */
+void
+print_ds(struct nfs4_pnfs_ds *ds)
+{
+       if (ds == NULL) {
+               printk("%s NULL device\n", __func__);
+               return;
+       }
+       printk("        ip_addr %x port %hu\n"
+               "        ref count %d\n"
+               "        client %p\n"
+               "        cl_exchange_flags %x\n",
+               ntohl(ds->ds_ip_addr), ntohs(ds->ds_port),
+               atomic_read(&ds->ds_count), ds->ds_clp,
+               ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
+}
+
+void
+print_ds_list(struct nfs4_file_layout_dsaddr *dsaddr)
+{
+       int i;
+
+       ifdebug(FACILITY) {
+               printk("%s dsaddr->ds_num %d\n", __func__,
+                      dsaddr->ds_num);
+               for (i = 0; i < dsaddr->ds_num; i++)
+                       print_ds(dsaddr->ds_list[i]);
+       }
+}
+
+void print_deviceid(struct nfs4_deviceid *id)
+{
+       u32 *p = (u32 *)id;
+
+       dprintk("%s: device id= [%x%x%x%x]\n", __func__,
+               p[0], p[1], p[2], p[3]);
+}
+
+/* nfs4_ds_cache_lock is held */
+static struct nfs4_pnfs_ds *
+_data_server_lookup_locked(u32 ip_addr, u32 port)
+{
+       struct nfs4_pnfs_ds *ds;
+
+       dprintk("_data_server_lookup: ip_addr=%x port=%hu\n",
+                       ntohl(ip_addr), ntohs(port));
+
+       list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
+               if (ds->ds_ip_addr == ip_addr &&
+                   ds->ds_port == port) {
+                       return ds;
+               }
+       }
+       return NULL;
+}
+
+static void
+destroy_ds(struct nfs4_pnfs_ds *ds)
+{
+       dprintk("--> %s\n", __func__);
+       ifdebug(FACILITY)
+               print_ds(ds);
+
+       if (ds->ds_clp)
+               nfs_put_client(ds->ds_clp);
+       kfree(ds);
+}
+
+static void
+nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
+{
+       struct nfs4_pnfs_ds *ds;
+       int i;
+
+       print_deviceid(&dsaddr->deviceid.de_id);
+
+       for (i = 0; i < dsaddr->ds_num; i++) {
+               ds = dsaddr->ds_list[i];
+               if (ds != NULL) {
+                       if (atomic_dec_and_lock(&ds->ds_count,
+                                               &nfs4_ds_cache_lock)) {
+                               list_del_init(&ds->ds_node);
+                               spin_unlock(&nfs4_ds_cache_lock);
+                               destroy_ds(ds);
+                       }
+               }
+       }
+       kfree(dsaddr->stripe_indices);
+       kfree(dsaddr);
+}
+
+void
+nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *device)
+{
+       struct nfs4_file_layout_dsaddr *dsaddr =
+               container_of(device, struct nfs4_file_layout_dsaddr, deviceid);
+
+       nfs4_fl_free_deviceid(dsaddr);
+}
+
+static struct nfs4_pnfs_ds *
+nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
+{
+       struct nfs4_pnfs_ds *tmp_ds, *ds;
+
+       ds = kzalloc(sizeof(*tmp_ds), GFP_KERNEL);
+       if (!ds)
+               goto out;
+
+       spin_lock(&nfs4_ds_cache_lock);
+       tmp_ds = _data_server_lookup_locked(ip_addr, port);
+       if (tmp_ds == NULL) {
+               ds->ds_ip_addr = ip_addr;
+               ds->ds_port = port;
+               atomic_set(&ds->ds_count, 1);
+               INIT_LIST_HEAD(&ds->ds_node);
+               ds->ds_clp = NULL;
+               list_add(&ds->ds_node, &nfs4_data_server_cache);
+               dprintk("%s add new data server ip 0x%x\n", __func__,
+                       ds->ds_ip_addr);
+       } else {
+               kfree(ds);
+               atomic_inc(&tmp_ds->ds_count);
+               dprintk("%s data server found ip 0x%x, inc'ed ds_count to %d\n",
+                       __func__, tmp_ds->ds_ip_addr,
+                       atomic_read(&tmp_ds->ds_count));
+               ds = tmp_ds;
+       }
+       spin_unlock(&nfs4_ds_cache_lock);
+out:
+       return ds;
+}
+
+/*
+ * Currently only support ipv4, and one multi-path address.
+ */
+static struct nfs4_pnfs_ds *
+decode_and_add_ds(__be32 **pp, struct inode *inode)
+{
+       struct nfs4_pnfs_ds *ds = NULL;
+       char *buf;
+       const char *ipend, *pstr;
+       u32 ip_addr, port;
+       int nlen, rlen, i;
+       int tmp[2];
+       __be32 *r_netid, *r_addr, *p = *pp;
+
+       /* r_netid */
+       nlen = be32_to_cpup(p++);
+       r_netid = p;
+       p += XDR_QUADLEN(nlen);
+
+       /* r_addr */
+       rlen = be32_to_cpup(p++);
+       r_addr = p;
+       p += XDR_QUADLEN(rlen);
+       *pp = p;
+
+       /* Check that netid is "tcp" */
+       if (nlen != 3 ||  memcmp((char *)r_netid, "tcp", 3)) {
+               dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__);
+               goto out_err;
+       }
+
+       /* ipv6 length plus port is legal */
+       if (rlen > INET6_ADDRSTRLEN + 8) {
+               dprintk("%s Invalid address, length %d\n", __func__,
+                       rlen);
+               goto out_err;
+       }
+       buf = kmalloc(rlen + 1, GFP_KERNEL);
+       buf[rlen] = '\0';
+       memcpy(buf, r_addr, rlen);
+
+       /* replace the port dots with dashes for the in4_pton() delimiter*/
+       for (i = 0; i < 2; i++) {
+               char *res = strrchr(buf, '.');
+               *res = '-';
+       }
+
+       /* Currently only support ipv4 address */
+       if (in4_pton(buf, rlen, (u8 *)&ip_addr, '-', &ipend) == 0) {
+               dprintk("%s: Only ipv4 addresses supported\n", __func__);
+               goto out_free;
+       }
+
+       /* port */
+       pstr = ipend;
+       sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]);
+       port = htons((tmp[0] << 8) | (tmp[1]));
+
+       ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
+       dprintk("%s Decoded address and port %s\n", __func__, buf);
+out_free:
+       kfree(buf);
+out_err:
+       return ds;
+}
+
+/* Decode opaque device data and return the result */
+static struct nfs4_file_layout_dsaddr*
+decode_device(struct inode *ino, struct pnfs_device *pdev)
+{
+       int i, dummy;
+       u32 cnt, num;
+       u8 *indexp;
+       __be32 *p = (__be32 *)pdev->area, *indicesp;
+       struct nfs4_file_layout_dsaddr *dsaddr;
+
+       /* Get the stripe count (number of stripe index) */
+       cnt = be32_to_cpup(p++);
+       dprintk("%s stripe count  %d\n", __func__, cnt);
+       if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
+               printk(KERN_WARNING "%s: stripe count %d greater than "
+                      "supported maximum %d\n", __func__,
+                       cnt, NFS4_PNFS_MAX_STRIPE_CNT);
+               goto out_err;
+       }
+
+       /* Check the multipath list count */
+       indicesp = p;
+       p += XDR_QUADLEN(cnt << 2);
+       num = be32_to_cpup(p++);
+       dprintk("%s ds_num %u\n", __func__, num);
+       if (num > NFS4_PNFS_MAX_MULTI_CNT) {
+               printk(KERN_WARNING "%s: multipath count %d greater than "
+                       "supported maximum %d\n", __func__,
+                       num, NFS4_PNFS_MAX_MULTI_CNT);
+               goto out_err;
+       }
+       dsaddr = kzalloc(sizeof(*dsaddr) +
+                       (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
+                       GFP_KERNEL);
+       if (!dsaddr)
+               goto out_err;
+
+       dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL);
+       if (!dsaddr->stripe_indices)
+               goto out_err_free;
+
+       dsaddr->stripe_count = cnt;
+       dsaddr->ds_num = num;
+
+       memcpy(&dsaddr->deviceid.de_id, &pdev->dev_id, sizeof(pdev->dev_id));
+
+       /* Go back an read stripe indices */
+       p = indicesp;
+       indexp = &dsaddr->stripe_indices[0];
+       for (i = 0; i < dsaddr->stripe_count; i++) {
+               *indexp = be32_to_cpup(p++);
+               if (*indexp >= num)
+                       goto out_err_free;
+               indexp++;
+       }
+       /* Skip already read multipath list count */
+       p++;
+
+       for (i = 0; i < dsaddr->ds_num; i++) {
+               int j;
+
+               dummy = be32_to_cpup(p++); /* multipath count */
+               if (dummy > 1) {
+                       printk(KERN_WARNING
+                              "%s: Multipath count %d not supported, "
+                              "skipping all greater than 1\n", __func__,
+                               dummy);
+               }
+               for (j = 0; j < dummy; j++) {
+                       if (j == 0) {
+                               dsaddr->ds_list[i] = decode_and_add_ds(&p, ino);
+                               if (dsaddr->ds_list[i] == NULL)
+                                       goto out_err_free;
+                       } else {
+                               u32 len;
+                               /* skip extra multipath */
+                               len = be32_to_cpup(p++);
+                               p += XDR_QUADLEN(len);
+                               len = be32_to_cpup(p++);
+                               p += XDR_QUADLEN(len);
+                               continue;
+                       }
+               }
+       }
+       return dsaddr;
+
+out_err_free:
+       nfs4_fl_free_deviceid(dsaddr);
+out_err:
+       dprintk("%s ERROR: returning NULL\n", __func__);
+       return NULL;
+}
+
+/*
+ * Decode the opaque device specified in 'dev'
+ * and add it to the list of available devices.
+ * If the deviceid is already cached, nfs4_add_deviceid will return
+ * a pointer to the cached struct and throw away the new.
+ */
+static struct nfs4_file_layout_dsaddr*
+decode_and_add_device(struct inode *inode, struct pnfs_device *dev)
+{
+       struct nfs4_file_layout_dsaddr *dsaddr;
+       struct pnfs_deviceid_node *d;
+
+       dsaddr = decode_device(inode, dev);
+       if (!dsaddr) {
+               printk(KERN_WARNING "%s: Could not decode or add device\n",
+                       __func__);
+               return NULL;
+       }
+
+       d = pnfs_add_deviceid(NFS_SERVER(inode)->nfs_client->cl_devid_cache,
+                             &dsaddr->deviceid);
+
+       return container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+}
+
+/*
+ * Retrieve the information for dev_id, add it to the list
+ * of available devices, and return it.
+ */
+struct nfs4_file_layout_dsaddr *
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
+{
+       struct pnfs_device *pdev = NULL;
+       u32 max_resp_sz;
+       int max_pages;
+       struct page **pages = NULL;
+       struct nfs4_file_layout_dsaddr *dsaddr = NULL;
+       int rc, i;
+       struct nfs_server *server = NFS_SERVER(inode);
+
+       /*
+        * Use the session max response size as the basis for setting
+        * GETDEVICEINFO's maxcount
+        */
+       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       max_pages = max_resp_sz >> PAGE_SHIFT;
+       dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
+               __func__, inode, max_resp_sz, max_pages);
+
+       pdev = kzalloc(sizeof(struct pnfs_device), GFP_KERNEL);
+       if (pdev == NULL)
+               return NULL;
+
+       pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL);
+       if (pages == NULL) {
+               kfree(pdev);
+               return NULL;
+       }
+       for (i = 0; i < max_pages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL);
+               if (!pages[i])
+                       goto out_free;
+       }
+
+       /* set pdev->area */
+       pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL);
+       if (!pdev->area)
+               goto out_free;
+
+       memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
+       pdev->layout_type = LAYOUT_NFSV4_1_FILES;
+       pdev->pages = pages;
+       pdev->pgbase = 0;
+       pdev->pglen = PAGE_SIZE * max_pages;
+       pdev->mincount = 0;
+
+       rc = nfs4_proc_getdeviceinfo(server, pdev);
+       dprintk("%s getdevice info returns %d\n", __func__, rc);
+       if (rc)
+               goto out_free;
+
+       /*
+        * Found new device, need to decode it and then add it to the
+        * list of known devices for this mountpoint.
+        */
+       dsaddr = decode_and_add_device(inode, pdev);
+out_free:
+       if (pdev->area != NULL)
+               vunmap(pdev->area);
+       for (i = 0; i < max_pages; i++)
+               __free_page(pages[i]);
+       kfree(pages);
+       kfree(pdev);
+       dprintk("<-- %s dsaddr %p\n", __func__, dsaddr);
+       return dsaddr;
+}
+
+struct nfs4_file_layout_dsaddr *
+nfs4_fl_find_get_deviceid(struct nfs_client *clp, struct nfs4_deviceid *id)
+{
+       struct pnfs_deviceid_node *d;
+
+       d = pnfs_find_get_deviceid(clp->cl_devid_cache, id);
+       return (d == NULL) ? NULL :
+               container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+}
index 089da5b5d20a1621b1142dbf75f415251ea4cb4b..32c8758c99fd78b6a44ea61c37f9f9fa7e57f6e3 100644 (file)
@@ -55,6 +55,7 @@
 #include "internal.h"
 #include "iostat.h"
 #include "callback.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
@@ -129,7 +130,8 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
                        | FATTR4_WORD0_MAXREAD
                        | FATTR4_WORD0_MAXWRITE
                        | FATTR4_WORD0_LEASE_TIME,
-                       0
+                       FATTR4_WORD1_TIME_DELTA
+                       | FATTR4_WORD1_FS_LAYOUT_TYPES
 };
 
 const u32 nfs4_fs_locations_bitmap[2] = {
@@ -255,9 +257,6 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                        nfs4_state_mark_reclaim_nograce(clp, state);
                        goto do_state_recovery;
                case -NFS4ERR_STALE_STATEID:
-                       if (state == NULL)
-                               break;
-                       nfs4_state_mark_reclaim_reboot(clp, state);
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
                        goto do_state_recovery;
@@ -334,10 +333,12 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
  * Must be called while holding tbl->slot_tbl_lock
  */
 static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
+nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
 {
+       int free_slotid = free_slot - tbl->slots;
        int slotid = free_slotid;
 
+       BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
        /* clear used bit in bitmap */
        __clear_bit(slotid, tbl->used_slots);
 
@@ -379,7 +380,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        struct nfs4_slot_table *tbl;
 
        tbl = &res->sr_session->fc_slot_table;
-       if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
+       if (!res->sr_slot) {
                /* just wake up the next guy waiting since
                 * we may have not consumed a slot after all */
                dprintk("%s: No slot\n", __func__);
@@ -387,17 +388,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        }
 
        spin_lock(&tbl->slot_tbl_lock);
-       nfs4_free_slot(tbl, res->sr_slotid);
+       nfs4_free_slot(tbl, res->sr_slot);
        nfs41_check_drain_session_complete(res->sr_session);
        spin_unlock(&tbl->slot_tbl_lock);
-       res->sr_slotid = NFS4_MAX_SLOT_TABLE;
+       res->sr_slot = NULL;
 }
 
 static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
        unsigned long timestamp;
-       struct nfs4_slot_table *tbl;
-       struct nfs4_slot *slot;
        struct nfs_client *clp;
 
        /*
@@ -410,17 +409,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                res->sr_status = NFS_OK;
 
        /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */
-       if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
+       if (!res->sr_slot)
                goto out;
 
-       tbl = &res->sr_session->fc_slot_table;
-       slot = tbl->slots + res->sr_slotid;
-
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
                /* Update the slot's sequence and clientid lease timer */
-               ++slot->seq_nr;
+               ++res->sr_slot->seq_nr;
                timestamp = res->sr_renewal_time;
                clp = res->sr_session->clp;
                do_renew_lease(clp, timestamp);
@@ -433,12 +429,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                 * returned NFS4ERR_DELAY as per Section 2.10.6.2
                 * of RFC5661.
                 */
-               dprintk("%s: slot=%d seq=%d: Operation in progress\n",
-                               __func__, res->sr_slotid, slot->seq_nr);
+               dprintk("%s: slot=%ld seq=%d: Operation in progress\n",
+                       __func__,
+                       res->sr_slot - res->sr_session->fc_slot_table.slots,
+                       res->sr_slot->seq_nr);
                goto out_retry;
        default:
                /* Just update the slot sequence no. */
-               ++slot->seq_nr;
+               ++res->sr_slot->seq_nr;
        }
 out:
        /* The session may be reset by one of the error handlers. */
@@ -505,10 +503,9 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
 
        dprintk("--> %s\n", __func__);
        /* slot already allocated? */
-       if (res->sr_slotid != NFS4_MAX_SLOT_TABLE)
+       if (res->sr_slot != NULL)
                return 0;
 
-       res->sr_slotid = NFS4_MAX_SLOT_TABLE;
        tbl = &session->fc_slot_table;
 
        spin_lock(&tbl->slot_tbl_lock);
@@ -550,7 +547,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
        dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
 
        res->sr_session = session;
-       res->sr_slotid = slotid;
+       res->sr_slot = slot;
        res->sr_renewal_time = jiffies;
        res->sr_status_flags = 0;
        /*
@@ -576,8 +573,9 @@ int nfs4_setup_sequence(const struct nfs_server *server,
                goto out;
        }
 
-       dprintk("--> %s clp %p session %p sr_slotid %d\n",
-               __func__, session->clp, session, res->sr_slotid);
+       dprintk("--> %s clp %p session %p sr_slot %ld\n",
+               __func__, session->clp, session, res->sr_slot ?
+                       res->sr_slot - session->fc_slot_table.slots : -1);
 
        ret = nfs41_setup_sequence(session, args, res, cache_reply,
                                   task);
@@ -650,7 +648,7 @@ static int nfs4_call_sync_sequence(struct nfs_server *server,
                .callback_data = &data
        };
 
-       res->sr_slotid = NFS4_MAX_SLOT_TABLE;
+       res->sr_slot = NULL;
        if (privileged)
                task_setup.callback_ops = &nfs41_call_priv_sync_ops;
        task = rpc_run_task(&task_setup);
@@ -735,7 +733,6 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.server = p->o_arg.server;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init(&p->dir_attr);
-       p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
 }
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
@@ -1120,6 +1117,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
        clear_bit(NFS_DELEGATED_STATE, &state->flags);
        smp_rmb();
        if (state->n_rdwr != 0) {
+               clear_bit(NFS_O_RDWR_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
                if (ret != 0)
                        return ret;
@@ -1127,6 +1125,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
                        return -ESTALE;
        }
        if (state->n_wronly != 0) {
+               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
                if (ret != 0)
                        return ret;
@@ -1134,6 +1133,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
                        return -ESTALE;
        }
        if (state->n_rdonly != 0) {
+               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
                if (ret != 0)
                        return ret;
@@ -1188,7 +1188,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        int err;
        do {
                err = _nfs4_do_open_reclaim(ctx, state);
-               if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
+               if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
@@ -1258,6 +1258,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
                                nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                       case -EKEYEXPIRED:
+                               /*
+                                * User RPCSEC_GSS context has expired.
+                                * We cannot recover this stateid now, so
+                                * skip it and allow recovery thread to
+                                * proceed.
+                                */
                        case -ENOMEM:
                                err = 0;
                                goto out;
@@ -1605,7 +1612,6 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
                        goto out;
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
-               case -EKEYEXPIRED:
                        nfs4_handle_exception(server, err, &exception);
                        err = 0;
                }
@@ -1975,7 +1981,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
-       calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        path_get(path);
        calldata->path = *path;
 
@@ -1998,120 +2003,17 @@ out:
        return status;
 }
 
-static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode)
+static struct inode *
+nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
 {
-       struct file *filp;
-       int ret;
-
-       /* If the open_intent is for execute, we have an extra check to make */
-       if (fmode & FMODE_EXEC) {
-               ret = nfs_may_open(state->inode,
-                               state->owner->so_cred,
-                               nd->intent.open.flags);
-               if (ret < 0)
-                       goto out_close;
-       }
-       filp = lookup_instantiate_filp(nd, path->dentry, NULL);
-       if (!IS_ERR(filp)) {
-               struct nfs_open_context *ctx;
-               ctx = nfs_file_open_context(filp);
-               ctx->state = state;
-               return 0;
-       }
-       ret = PTR_ERR(filp);
-out_close:
-       nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE));
-       return ret;
-}
-
-struct dentry *
-nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
-{
-       struct path path = {
-               .mnt = nd->path.mnt,
-               .dentry = dentry,
-       };
-       struct dentry *parent;
-       struct iattr attr;
-       struct rpc_cred *cred;
        struct nfs4_state *state;
-       struct dentry *res;
-       int open_flags = nd->intent.open.flags;
-       fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
-
-       if (nd->flags & LOOKUP_CREATE) {
-               attr.ia_mode = nd->intent.open.create_mode;
-               attr.ia_valid = ATTR_MODE;
-               if (!IS_POSIXACL(dir))
-                       attr.ia_mode &= ~current_umask();
-       } else {
-               open_flags &= ~O_EXCL;
-               attr.ia_valid = 0;
-               BUG_ON(open_flags & O_CREAT);
-       }
 
-       cred = rpc_lookup_cred();
-       if (IS_ERR(cred))
-               return (struct dentry *)cred;
-       parent = dentry->d_parent;
        /* Protect against concurrent sillydeletes */
-       nfs_block_sillyrename(parent);
-       state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred);
-       put_rpccred(cred);
-       if (IS_ERR(state)) {
-               if (PTR_ERR(state) == -ENOENT) {
-                       d_add(dentry, NULL);
-                       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-               }
-               nfs_unblock_sillyrename(parent);
-               return (struct dentry *)state;
-       }
-       res = d_add_unique(dentry, igrab(state->inode));
-       if (res != NULL)
-               path.dentry = res;
-       nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
-       nfs_unblock_sillyrename(parent);
-       nfs4_intent_set_file(nd, &path, state, fmode);
-       return res;
-}
-
-int
-nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
-{
-       struct path path = {
-               .mnt = nd->path.mnt,
-               .dentry = dentry,
-       };
-       struct rpc_cred *cred;
-       struct nfs4_state *state;
-       fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE);
-
-       cred = rpc_lookup_cred();
-       if (IS_ERR(cred))
-               return PTR_ERR(cred);
-       state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred);
-       put_rpccred(cred);
-       if (IS_ERR(state)) {
-               switch (PTR_ERR(state)) {
-                       case -EPERM:
-                       case -EACCES:
-                       case -EDQUOT:
-                       case -ENOSPC:
-                       case -EROFS:
-                               return PTR_ERR(state);
-                       default:
-                               goto out_drop;
-               }
-       }
-       if (state->inode == dentry->d_inode) {
-               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-               nfs4_intent_set_file(nd, &path, state, fmode);
-               return 1;
-       }
-       nfs4_close_sync(&path, state, fmode);
-out_drop:
-       d_drop(dentry);
-       return 0;
+       state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred);
+       if (IS_ERR(state))
+               return ERR_CAST(state);
+       ctx->state = state;
+       return igrab(state->inode);
 }
 
 static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
@@ -2568,36 +2470,34 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
 
 static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                 int flags, struct nameidata *nd)
+                 int flags, struct nfs_open_context *ctx)
 {
-       struct path path = {
-               .mnt = nd->path.mnt,
+       struct path my_path = {
                .dentry = dentry,
        };
+       struct path *path = &my_path;
        struct nfs4_state *state;
-       struct rpc_cred *cred;
-       fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE);
+       struct rpc_cred *cred = NULL;
+       fmode_t fmode = 0;
        int status = 0;
 
-       cred = rpc_lookup_cred();
-       if (IS_ERR(cred)) {
-               status = PTR_ERR(cred);
-               goto out;
+       if (ctx != NULL) {
+               cred = ctx->cred;
+               path = &ctx->path;
+               fmode = ctx->mode;
        }
-       state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred);
+       state = nfs4_do_open(dir, path, fmode, flags, sattr, cred);
        d_drop(dentry);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
-               goto out_putcred;
+               goto out;
        }
        d_add(dentry, igrab(state->inode));
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
-               status = nfs4_intent_set_file(nd, &path, state, fmode);
+       if (ctx != NULL)
+               ctx->state = state;
        else
-               nfs4_close_sync(&path, state, fmode);
-out_putcred:
-       put_rpccred(cred);
+               nfs4_close_sync(path, state, fmode);
 out:
        return status;
 }
@@ -2655,6 +2555,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
        args->bitmask = server->cache_consistency_bitmask;
        res->server = server;
+       res->seq_res.sr_slot = NULL;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
 }
 
@@ -2671,18 +2572,46 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        return 1;
 }
 
+static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+       struct nfs_server *server = NFS_SERVER(dir);
+       struct nfs_renameargs *arg = msg->rpc_argp;
+       struct nfs_renameres *res = msg->rpc_resp;
+
+       msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
+       arg->bitmask = server->attr_bitmask;
+       res->server = server;
+}
+
+static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+                                struct inode *new_dir)
+{
+       struct nfs_renameres *res = task->tk_msg.rpc_resp;
+
+       if (!nfs4_sequence_done(task, &res->seq_res))
+               return 0;
+       if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
+               return 0;
+
+       update_changeattr(old_dir, &res->old_cinfo);
+       nfs_post_op_update_inode(old_dir, res->old_fattr);
+       update_changeattr(new_dir, &res->new_cinfo);
+       nfs_post_op_update_inode(new_dir, res->new_fattr);
+       return 1;
+}
+
 static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
                struct inode *new_dir, struct qstr *new_name)
 {
        struct nfs_server *server = NFS_SERVER(old_dir);
-       struct nfs4_rename_arg arg = {
+       struct nfs_renameargs arg = {
                .old_dir = NFS_FH(old_dir),
                .new_dir = NFS_FH(new_dir),
                .old_name = old_name,
                .new_name = new_name,
                .bitmask = server->attr_bitmask,
        };
-       struct nfs4_rename_res res = {
+       struct nfs_renameres res = {
                .server = server,
        };
        struct rpc_message msg = {
@@ -2896,15 +2825,16 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 }
 
 static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                  u64 cookie, struct page *page, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, int plus)
 {
        struct inode            *dir = dentry->d_inode;
        struct nfs4_readdir_arg args = {
                .fh = NFS_FH(dir),
-               .pages = &page,
+               .pages = pages,
                .pgbase = 0,
                .count = count,
                .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
+               .plus = plus,
        };
        struct nfs4_readdir_res res;
        struct rpc_message msg = {
@@ -2932,14 +2862,14 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 }
 
 static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                  u64 cookie, struct page *page, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, int plus)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
                err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
                                _nfs4_proc_readdir(dentry, cred, cookie,
-                                       page, count, plus),
+                                       pages, count, plus),
                                &exception);
        } while (exception.retry);
        return err;
@@ -3490,9 +3420,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                        nfs4_state_mark_reclaim_nograce(clp, state);
                        goto do_state_recovery;
                case -NFS4ERR_STALE_STATEID:
-                       if (state == NULL)
-                               break;
-                       nfs4_state_mark_reclaim_reboot(clp, state);
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
                        goto do_state_recovery;
@@ -3626,7 +3553,6 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                        case -NFS4ERR_RESOURCE:
                                /* The IBM lawyers misread another document! */
                        case -NFS4ERR_DELAY:
-                       case -EKEYEXPIRED:
                                err = nfs4_delay(clp->cl_rpcclient, &timeout);
                }
        } while (err == 0);
@@ -3721,7 +3647,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        memcpy(&data->stateid, stateid, sizeof(data->stateid));
        data->res.fattr = &data->fattr;
        data->res.server = server;
-       data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        nfs_fattr_init(data->res.fattr);
        data->timestamp = jiffies;
        data->rpc_status = 0;
@@ -3874,7 +3799,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
        p->arg.fl = &p->fl;
        p->arg.seqid = seqid;
        p->res.seqid = seqid;
-       p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        p->arg.stateid = &lsp->ls_stateid;
        p->lsp = lsp;
        atomic_inc(&lsp->ls_count);
@@ -4054,7 +3978,6 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
        p->arg.lock_owner.id = lsp->ls_id.id;
        p->res.lock_seqid = p->arg.lock_seqid;
-       p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        p->lsp = lsp;
        p->server = server;
        atomic_inc(&lsp->ls_count);
@@ -4241,7 +4164,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
-               if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
+               if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
@@ -4266,7 +4189,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
                        goto out;
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
-               case -EKEYEXPIRED:
                        nfs4_handle_exception(server, err, &exception);
                        err = 0;
                }
@@ -4412,13 +4334,21 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                                nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
                                err = 0;
                                goto out;
+                       case -EKEYEXPIRED:
+                               /*
+                                * User RPCSEC_GSS context has expired.
+                                * We cannot recover this stateid now, so
+                                * skip it and allow recovery thread to
+                                * proceed.
+                                */
+                               err = 0;
+                               goto out;
                        case -ENOMEM:
                        case -NFS4ERR_DENIED:
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
                                err = 0;
                                goto out;
                        case -NFS4ERR_DELAY:
-                       case -EKEYEXPIRED:
                                break;
                }
                err = nfs4_handle_exception(server, err, &exception);
@@ -4647,7 +4577,6 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case -NFS4ERR_DELAY:
        case -NFS4ERR_GRACE:
-       case -EKEYEXPIRED:
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
@@ -4687,7 +4616,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        };
        int status;
 
-       res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
 
@@ -4914,49 +4842,56 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
                args->bc_attrs.max_reqs);
 }
 
-static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd)
+static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
 {
-       if (rcvd <= sent)
-               return 0;
-       printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. "
-               "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd);
-       return -EINVAL;
+       struct nfs4_channel_attrs *sent = &args->fc_attrs;
+       struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
+
+       if (rcvd->headerpadsz > sent->headerpadsz)
+               return -EINVAL;
+       if (rcvd->max_resp_sz > sent->max_resp_sz)
+               return -EINVAL;
+       /*
+        * Our requested max_ops is the minimum we need; we're not
+        * prepared to break up compounds into smaller pieces than that.
+        * So, no point even trying to continue if the server won't
+        * cooperate:
+        */
+       if (rcvd->max_ops < sent->max_ops)
+               return -EINVAL;
+       if (rcvd->max_reqs == 0)
+               return -EINVAL;
+       return 0;
 }
 
-#define _verify_fore_channel_attr(_name_) \
-       _verify_channel_attr("fore", #_name_, \
-                            args->fc_attrs._name_, \
-                            session->fc_attrs._name_)
+static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
+{
+       struct nfs4_channel_attrs *sent = &args->bc_attrs;
+       struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
 
-#define _verify_back_channel_attr(_name_) \
-       _verify_channel_attr("back", #_name_, \
-                            args->bc_attrs._name_, \
-                            session->bc_attrs._name_)
+       if (rcvd->max_rqst_sz > sent->max_rqst_sz)
+               return -EINVAL;
+       if (rcvd->max_resp_sz < sent->max_resp_sz)
+               return -EINVAL;
+       if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
+               return -EINVAL;
+       /* These would render the backchannel useless: */
+       if (rcvd->max_ops  == 0)
+               return -EINVAL;
+       if (rcvd->max_reqs == 0)
+               return -EINVAL;
+       return 0;
+}
 
-/*
- * The server is not allowed to increase the fore channel header pad size,
- * maximum response size, or maximum number of operations.
- *
- * The back channel attributes are only negotiatied down: We send what the
- * (back channel) server insists upon.
- */
 static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
                                     struct nfs4_session *session)
 {
-       int ret = 0;
-
-       ret |= _verify_fore_channel_attr(headerpadsz);
-       ret |= _verify_fore_channel_attr(max_resp_sz);
-       ret |= _verify_fore_channel_attr(max_ops);
-
-       ret |= _verify_back_channel_attr(headerpadsz);
-       ret |= _verify_back_channel_attr(max_rqst_sz);
-       ret |= _verify_back_channel_attr(max_resp_sz);
-       ret |= _verify_back_channel_attr(max_resp_sz_cached);
-       ret |= _verify_back_channel_attr(max_ops);
-       ret |= _verify_back_channel_attr(max_reqs);
+       int ret;
 
-       return ret;
+       ret = nfs4_verify_fore_channel_attrs(args, session);
+       if (ret)
+               return ret;
+       return nfs4_verify_back_channel_attrs(args, session);
 }
 
 static int _nfs4_proc_create_session(struct nfs_client *clp)
@@ -5111,7 +5046,6 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client
 {
        switch(task->tk_status) {
        case -NFS4ERR_DELAY:
-       case -EKEYEXPIRED:
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
@@ -5180,12 +5114,11 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
 
        if (!atomic_inc_not_zero(&clp->cl_count))
                return ERR_PTR(-EIO);
-       calldata = kmalloc(sizeof(*calldata), GFP_NOFS);
+       calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
        if (calldata == NULL) {
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
-       calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        msg.rpc_argp = &calldata->args;
        msg.rpc_resp = &calldata->res;
        calldata->clp = clp;
@@ -5254,7 +5187,6 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
        case -NFS4ERR_WRONG_CRED: /* What to do here? */
                break;
        case -NFS4ERR_DELAY:
-       case -EKEYEXPIRED:
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
@@ -5317,7 +5249,6 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
                goto out;
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
-       calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
 
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
@@ -5333,6 +5264,147 @@ out:
        dprintk("<-- %s status=%d\n", __func__, status);
        return status;
 }
+
+static void
+nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutget *lgp = calldata;
+       struct inode *ino = lgp->args.inode;
+       struct nfs_server *server = NFS_SERVER(ino);
+
+       dprintk("--> %s\n", __func__);
+       if (nfs4_setup_sequence(server, &lgp->args.seq_args,
+                               &lgp->res.seq_res, 0, task))
+               return;
+       rpc_call_start(task);
+}
+
+static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutget *lgp = calldata;
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+
+       dprintk("--> %s\n", __func__);
+
+       if (!nfs4_sequence_done(task, &lgp->res.seq_res))
+               return;
+
+       switch (task->tk_status) {
+       case 0:
+               break;
+       case -NFS4ERR_LAYOUTTRYLATER:
+       case -NFS4ERR_RECALLCONFLICT:
+               task->tk_status = -NFS4ERR_DELAY;
+               /* Fall through */
+       default:
+               if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
+                       rpc_restart_call_prepare(task);
+                       return;
+               }
+       }
+       lgp->status = task->tk_status;
+       dprintk("<-- %s\n", __func__);
+}
+
+static void nfs4_layoutget_release(void *calldata)
+{
+       struct nfs4_layoutget *lgp = calldata;
+
+       dprintk("--> %s\n", __func__);
+       put_layout_hdr(lgp->args.inode);
+       if (lgp->res.layout.buf != NULL)
+               free_page((unsigned long) lgp->res.layout.buf);
+       put_nfs_open_context(lgp->args.ctx);
+       kfree(calldata);
+       dprintk("<-- %s\n", __func__);
+}
+
+static const struct rpc_call_ops nfs4_layoutget_call_ops = {
+       .rpc_call_prepare = nfs4_layoutget_prepare,
+       .rpc_call_done = nfs4_layoutget_done,
+       .rpc_release = nfs4_layoutget_release,
+};
+
+int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
+{
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct rpc_task *task;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
+               .rpc_argp = &lgp->args,
+               .rpc_resp = &lgp->res,
+       };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_client = server->client,
+               .rpc_message = &msg,
+               .callback_ops = &nfs4_layoutget_call_ops,
+               .callback_data = lgp,
+               .flags = RPC_TASK_ASYNC,
+       };
+       int status = 0;
+
+       dprintk("--> %s\n", __func__);
+
+       lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS);
+       if (lgp->res.layout.buf == NULL) {
+               nfs4_layoutget_release(lgp);
+               return -ENOMEM;
+       }
+
+       lgp->res.seq_res.sr_slot = NULL;
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       status = nfs4_wait_for_completion_rpc_task(task);
+       if (status != 0)
+               goto out;
+       status = lgp->status;
+       if (status != 0)
+               goto out;
+       status = pnfs_layout_process(lgp);
+out:
+       rpc_put_task(task);
+       dprintk("<-- %s status=%d\n", __func__, status);
+       return status;
+}
+
+static int
+_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
+{
+       struct nfs4_getdeviceinfo_args args = {
+               .pdev = pdev,
+       };
+       struct nfs4_getdeviceinfo_res res = {
+               .pdev = pdev,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       dprintk("<-- %s status=%d\n", __func__, status);
+
+       return status;
+}
+
+int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
+{
+       struct nfs4_exception exception = { };
+       int err;
+
+       do {
+               err = nfs4_handle_exception(server,
+                                       _nfs4_proc_getdeviceinfo(server, pdev),
+                                       &exception);
+       } while (exception.retry);
+       return err;
+}
+EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
+
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -5443,6 +5515,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .unlink_setup   = nfs4_proc_unlink_setup,
        .unlink_done    = nfs4_proc_unlink_done,
        .rename         = nfs4_proc_rename,
+       .rename_setup   = nfs4_proc_rename_setup,
+       .rename_done    = nfs4_proc_rename_done,
        .link           = nfs4_proc_link,
        .symlink        = nfs4_proc_symlink,
        .mkdir          = nfs4_proc_mkdir,
@@ -5463,6 +5537,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .lock           = nfs4_proc_lock,
        .clear_acl_cache = nfs4_zap_acl_attr,
        .close_context  = nfs4_close_context,
+       .open_context   = nfs4_atomic_open,
 };
 
 /*
index 96524c5dca6b8bd45fc0c845546e783d318d7e4f..f575a3126737054efa695db149c9c0f08571793d 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/random.h>
+#include <linux/ratelimit.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
 
@@ -53,6 +54,7 @@
 #include "callback.h"
 #include "delegation.h"
 #include "internal.h"
+#include "pnfs.h"
 
 #define OPENOWNER_POOL_SIZE    8
 
@@ -1063,6 +1065,14 @@ restart:
                                /* Mark the file as being 'closed' */
                                state->state = 0;
                                break;
+                       case -EKEYEXPIRED:
+                               /*
+                                * User RPCSEC_GSS context has expired.
+                                * We cannot recover this stateid now, so
+                                * skip it and allow recovery thread to
+                                * proceed.
+                                */
+                               break;
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_BAD_STATEID:
@@ -1138,16 +1148,14 @@ static void nfs4_reclaim_complete(struct nfs_client *clp,
                (void)ops->reclaim_complete(clp);
 }
 
-static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
+static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
 {
        struct nfs4_state_owner *sp;
        struct rb_node *pos;
        struct nfs4_state *state;
 
        if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
-               return;
-
-       nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
+               return 0;
 
        for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
                sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
@@ -1161,6 +1169,14 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
        }
 
        nfs_delegation_reap_unclaimed(clp);
+       return 1;
+}
+
+static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
+{
+       if (!nfs4_state_clear_reclaim_reboot(clp))
+               return;
+       nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
 }
 
 static void nfs_delegation_clear_all(struct nfs_client *clp)
@@ -1175,6 +1191,14 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
 }
 
+static void nfs4_warn_keyexpired(const char *s)
+{
+       printk_ratelimited(KERN_WARNING "Error: state manager"
+                       " encountered RPCSEC_GSS session"
+                       " expired against NFSv4 server %s.\n",
+                       s);
+}
+
 static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
 {
        switch (error) {
@@ -1187,7 +1211,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_LEASE_MOVED:
                        set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
-                       nfs4_state_end_reclaim_reboot(clp);
+                       nfs4_state_clear_reclaim_reboot(clp);
                        nfs4_state_start_reclaim_reboot(clp);
                        break;
                case -NFS4ERR_EXPIRED:
@@ -1204,6 +1228,10 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                        set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
                        /* Zero session reset errors */
                        return 0;
+               case -EKEYEXPIRED:
+                       /* Nothing we can do */
+                       nfs4_warn_keyexpired(clp->cl_hostname);
+                       return 0;
        }
        return error;
 }
@@ -1414,9 +1442,10 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
                case -NFS4ERR_DELAY:
                case -NFS4ERR_CLID_INUSE:
                case -EAGAIN:
-               case -EKEYEXPIRED:
                        break;
 
+               case -EKEYEXPIRED:
+                       nfs4_warn_keyexpired(clp->cl_hostname);
                case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                         * in nfs4_exchange_id */
                default:
@@ -1447,6 +1476,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        }
                        clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
                        set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+                       pnfs_destroy_all_layouts(clp);
                }
 
                if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
index 08ef912911324d550285299d112164b11f45689b..f313c4cce7e4d1d087b8a1b47b55f769edf40a21 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/nfs_idmap.h>
 #include "nfs4_fs.h"
 #include "internal.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
 
@@ -310,6 +311,19 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
 #define encode_reclaim_complete_maxsz  (op_encode_hdr_maxsz + 4)
 #define decode_reclaim_complete_maxsz  (op_decode_hdr_maxsz + 4)
+#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
+                               XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
+#define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
+                               1 /* layout type */ + \
+                               1 /* opaque devaddr4 length */ + \
+                                 /* devaddr4 payload is read into page */ \
+                               1 /* notification bitmap length */ + \
+                               1 /* notification bitmap */)
+#define encode_layoutget_maxsz (op_encode_hdr_maxsz + 10 + \
+                               encode_stateid_maxsz)
+#define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \
+                               decode_stateid_maxsz + \
+                               XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE))
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -699,6 +713,20 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_reclaim_complete_sz   (compound_decode_hdr_maxsz + \
                                         decode_sequence_maxsz + \
                                         decode_reclaim_complete_maxsz)
+#define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz +    \
+                               encode_sequence_maxsz +\
+                               encode_getdeviceinfo_maxsz)
+#define NFS4_dec_getdeviceinfo_sz (compound_decode_hdr_maxsz +    \
+                               decode_sequence_maxsz + \
+                               decode_getdeviceinfo_maxsz)
+#define NFS4_enc_layoutget_sz  (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz +        \
+                               encode_layoutget_maxsz)
+#define NFS4_dec_layoutget_sz  (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz +        \
+                               decode_layoutget_maxsz)
 
 const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                      compound_encode_hdr_maxsz +
@@ -816,7 +844,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
        if (iap->ia_valid & ATTR_MODE)
                len += 4;
        if (iap->ia_valid & ATTR_UID) {
-               owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
+               owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name, IDMAP_NAMESZ);
                if (owner_namelen < 0) {
                        dprintk("nfs: couldn't resolve uid %d to string\n",
                                        iap->ia_uid);
@@ -828,7 +856,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
                len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
        }
        if (iap->ia_valid & ATTR_GID) {
-               owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
+               owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group, IDMAP_NAMESZ);
                if (owner_grouplen < 0) {
                        dprintk("nfs: couldn't resolve gid %d to string\n",
                                        iap->ia_gid);
@@ -1385,24 +1413,35 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-       uint32_t attrs[2] = {
-               FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
-               FATTR4_WORD1_MOUNTED_ON_FILEID,
-       };
+       uint32_t attrs[2] = {0, 0};
+       uint32_t dircount = readdir->count >> 1;
        __be32 *p;
 
+       if (readdir->plus) {
+               attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
+                       FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
+               attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
+                       FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
+                       FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
+                       FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+               dircount >>= 1;
+       }
+       attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
+       attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+       /* Switch to mounted_on_fileid if the server supports it */
+       if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
+               attrs[0] &= ~FATTR4_WORD0_FILEID;
+       else
+               attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+
        p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
        *p++ = cpu_to_be32(OP_READDIR);
        p = xdr_encode_hyper(p, readdir->cookie);
        p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
-       *p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
+       *p++ = cpu_to_be32(dircount);
        *p++ = cpu_to_be32(readdir->count);
        *p++ = cpu_to_be32(2);
-       /* Switch to mounted_on_fileid if the server supports it */
-       if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
-               attrs[0] &= ~FATTR4_WORD0_FILEID;
-       else
-               attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+
        *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
        *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
        hdr->nops++;
@@ -1726,6 +1765,58 @@ static void encode_sequence(struct xdr_stream *xdr,
 #endif /* CONFIG_NFS_V4_1 */
 }
 
+#ifdef CONFIG_NFS_V4_1
+static void
+encode_getdeviceinfo(struct xdr_stream *xdr,
+                    const struct nfs4_getdeviceinfo_args *args,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
+       *p++ = cpu_to_be32(OP_GETDEVICEINFO);
+       p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
+                                   NFS4_DEVICEID4_SIZE);
+       *p++ = cpu_to_be32(args->pdev->layout_type);
+       *p++ = cpu_to_be32(args->pdev->pglen);          /* gdia_maxcount */
+       *p++ = cpu_to_be32(0);                          /* bitmap length 0 */
+       hdr->nops++;
+       hdr->replen += decode_getdeviceinfo_maxsz;
+}
+
+static void
+encode_layoutget(struct xdr_stream *xdr,
+                     const struct nfs4_layoutget_args *args,
+                     struct compound_hdr *hdr)
+{
+       nfs4_stateid stateid;
+       __be32 *p;
+
+       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
+       *p++ = cpu_to_be32(OP_LAYOUTGET);
+       *p++ = cpu_to_be32(0);     /* Signal layout available */
+       *p++ = cpu_to_be32(args->type);
+       *p++ = cpu_to_be32(args->range.iomode);
+       p = xdr_encode_hyper(p, args->range.offset);
+       p = xdr_encode_hyper(p, args->range.length);
+       p = xdr_encode_hyper(p, args->minlength);
+       pnfs_get_layout_stateid(&stateid, NFS_I(args->inode)->layout,
+                               args->ctx->state);
+       p = xdr_encode_opaque_fixed(p, &stateid.data, NFS4_STATEID_SIZE);
+       *p = cpu_to_be32(args->maxcount);
+
+       dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
+               __func__,
+               args->type,
+               args->range.iomode,
+               (unsigned long)args->range.offset,
+               (unsigned long)args->range.length,
+               args->maxcount);
+       hdr->nops++;
+       hdr->replen += decode_layoutget_maxsz;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
 /*
  * END OF "GENERIC" ENCODE ROUTINES.
  */
@@ -1823,7 +1914,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
 /*
  * Encode RENAME request
  */
-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs_renameargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -2543,6 +2634,51 @@ static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
        return 0;
 }
 
+/*
+ * Encode GETDEVICEINFO request
+ */
+static int nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req, uint32_t *p,
+                                     struct nfs4_getdeviceinfo_args *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, req, &hdr);
+       encode_sequence(&xdr, &args->seq_args, &hdr);
+       encode_getdeviceinfo(&xdr, args, &hdr);
+
+       /* set up reply kvec. Subtract notification bitmap max size (2)
+        * so that notification bitmap is put in xdr_buf tail */
+       xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2,
+                        args->pdev->pages, args->pdev->pgbase,
+                        args->pdev->pglen);
+
+       encode_nops(&hdr);
+       return 0;
+}
+
+/*
+ *  Encode LAYOUTGET request
+ */
+static int nfs4_xdr_enc_layoutget(struct rpc_rqst *req, uint32_t *p,
+                                 struct nfs4_layoutget_args *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, req, &hdr);
+       encode_sequence(&xdr, &args->seq_args, &hdr);
+       encode_putfh(&xdr, NFS_FH(args->inode), &hdr);
+       encode_layoutget(&xdr, args, &hdr);
+       encode_nops(&hdr);
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
@@ -2676,7 +2812,10 @@ out_overflow:
 static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
 {
        if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
-               decode_attr_bitmap(xdr, bitmask);
+               int ret;
+               ret = decode_attr_bitmap(xdr, bitmask);
+               if (unlikely(ret < 0))
+                       return ret;
                bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
        } else
                bitmask[0] = bitmask[1] = 0;
@@ -2848,6 +2987,56 @@ out_overflow:
        return -EIO;
 }
 
+static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap)
+{
+       __be32 *p;
+
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
+       }
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
+static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
+{
+       __be32 *p;
+       int len;
+
+       if (fh != NULL)
+               memset(fh, 0, sizeof(*fh));
+
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               len = be32_to_cpup(p);
+               if (len > NFS4_FHSIZE)
+                       return -EIO;
+               p = xdr_inline_decode(xdr, len);
+               if (unlikely(!p))
+                       goto out_overflow;
+               if (fh != NULL) {
+                       memcpy(fh->data, p, len);
+                       fh->size = len;
+               }
+               bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE;
+       }
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
        __be32 *p;
@@ -3521,6 +3710,24 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
        return status;
 }
 
+static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
+                                 struct timespec *time)
+{
+       int status = 0;
+
+       time->tv_sec = 0;
+       time->tv_nsec = 0;
+       if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U)))
+               return -EIO;
+       if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) {
+               status = decode_attr_time(xdr, time);
+               bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
+       }
+       dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
+               (long)time->tv_nsec);
+       return status;
+}
+
 static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
 {
        int status = 0;
@@ -3744,29 +3951,14 @@ xdr_error:
        return status;
 }
 
-static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
+               struct nfs_fattr *fattr, struct nfs_fh *fh,
                const struct nfs_server *server, int may_sleep)
 {
-       __be32 *savep;
-       uint32_t attrlen,
-                bitmap[2] = {0},
-                type;
        int status;
        umode_t fmode = 0;
        uint64_t fileid;
-
-       status = decode_op_hdr(xdr, OP_GETATTR);
-       if (status < 0)
-               goto xdr_error;
-
-       status = decode_attr_bitmap(xdr, bitmap);
-       if (status < 0)
-               goto xdr_error;
-
-       status = decode_attr_length(xdr, &attrlen, &savep);
-       if (status < 0)
-               goto xdr_error;
-
+       uint32_t type;
 
        status = decode_attr_type(xdr, bitmap, &type);
        if (status < 0)
@@ -3792,6 +3984,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
                goto xdr_error;
        fattr->valid |= status;
 
+       status = decode_attr_error(xdr, bitmap);
+       if (status < 0)
+               goto xdr_error;
+
+       status = decode_attr_filehandle(xdr, bitmap, fh);
+       if (status < 0)
+               goto xdr_error;
+
        status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
        if (status < 0)
                goto xdr_error;
@@ -3862,12 +4062,101 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
                fattr->valid |= status;
        }
 
+xdr_error:
+       dprintk("%s: xdr returned %d\n", __func__, -status);
+       return status;
+}
+
+static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+               struct nfs_fh *fh, const struct nfs_server *server, int may_sleep)
+{
+       __be32 *savep;
+       uint32_t attrlen,
+                bitmap[2] = {0};
+       int status;
+
+       status = decode_op_hdr(xdr, OP_GETATTR);
+       if (status < 0)
+               goto xdr_error;
+
+       status = decode_attr_bitmap(xdr, bitmap);
+       if (status < 0)
+               goto xdr_error;
+
+       status = decode_attr_length(xdr, &attrlen, &savep);
+       if (status < 0)
+               goto xdr_error;
+
+       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep);
+       if (status < 0)
+               goto xdr_error;
+
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
        return status;
 }
 
+static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+               const struct nfs_server *server, int may_sleep)
+{
+       return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep);
+}
+
+/*
+ * Decode potentially multiple layout types. Currently we only support
+ * one layout driver per file system.
+ */
+static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
+                                        uint32_t *layouttype)
+{
+       uint32_t *p;
+       int num;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       num = be32_to_cpup(p);
+
+       /* pNFS is not supported by the underlying file system */
+       if (num == 0) {
+               *layouttype = 0;
+               return 0;
+       }
+       if (num > 1)
+               printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
+                       "per filesystem not supported\n", __func__);
+
+       /* Decode and set first layout type, move xdr->p past unused types */
+       p = xdr_inline_decode(xdr, num * 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       *layouttype = be32_to_cpup(p);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
+/*
+ * The type of file system exported.
+ * Note we must ensure that layouttype is set in any non-error case.
+ */
+static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
+                               uint32_t *layouttype)
+{
+       int status = 0;
+
+       dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
+       if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
+               return -EIO;
+       if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
+               status = decode_first_pnfs_layout_type(xdr, layouttype);
+               bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
+       } else
+               *layouttype = 0;
+       return status;
+}
 
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
@@ -3894,6 +4183,12 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
        if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
                goto xdr_error;
        fsinfo->wtpref = fsinfo->wtmax;
+       status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
+       if (status != 0)
+               goto xdr_error;
+       status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
+       if (status != 0)
+               goto xdr_error;
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
@@ -3950,13 +4245,13 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
        __be32 *p;
        uint32_t namelen, type;
 
-       p = xdr_inline_decode(xdr, 32);
+       p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
        if (unlikely(!p))
                goto out_overflow;
-       p = xdr_decode_hyper(p, &offset);
+       p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
        p = xdr_decode_hyper(p, &length);
-       type = be32_to_cpup(p++);
-       if (fl != NULL) {
+       type = be32_to_cpup(p++); /* 4 byte read */
+       if (fl != NULL) { /* manipulate file lock */
                fl->fl_start = (loff_t)offset;
                fl->fl_end = fl->fl_start + (loff_t)length - 1;
                if (length == ~(uint64_t)0)
@@ -3966,9 +4261,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
                        fl->fl_type = F_RDLCK;
                fl->fl_pid = 0;
        }
-       p = xdr_decode_hyper(p, &clientid);
-       namelen = be32_to_cpup(p);
-       p = xdr_inline_decode(xdr, namelen);
+       p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
+       namelen = be32_to_cpup(p); /* read 4 bytes */  /* have read all 32 bytes now */
+       p = xdr_inline_decode(xdr, namelen); /* variable size field */
        if (likely(p))
                return -NFS4ERR_DENIED;
 out_overflow:
@@ -4200,12 +4495,9 @@ out_overflow:
 static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
 {
        struct xdr_buf  *rcvbuf = &req->rq_rcv_buf;
-       struct page     *page = *rcvbuf->pages;
        struct kvec     *iov = rcvbuf->head;
        size_t          hdrlen;
        u32             recvd, pglen = rcvbuf->page_len;
-       __be32          *end, *entry, *p, *kaddr;
-       unsigned int    nr = 0;
        int             status;
 
        status = decode_op_hdr(xdr, OP_READDIR);
@@ -4225,71 +4517,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
                pglen = recvd;
        xdr_read_pages(xdr, pglen);
 
-       BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
-       kaddr = p = kmap_atomic(page, KM_USER0);
-       end = p + ((pglen + readdir->pgbase) >> 2);
-       entry = p;
-
-       /* Make sure the packet actually has a value_follows and EOF entry */
-       if ((entry + 1) > end)
-               goto short_pkt;
-
-       for (; *p++; nr++) {
-               u32 len, attrlen, xlen;
-               if (end - p < 3)
-                       goto short_pkt;
-               dprintk("cookie = %Lu, ", *((unsigned long long *)p));
-               p += 2;                 /* cookie */
-               len = ntohl(*p++);      /* filename length */
-               if (len > NFS4_MAXNAMLEN) {
-                       dprintk("NFS: giant filename in readdir (len 0x%x)\n",
-                                       len);
-                       goto err_unmap;
-               }
-               xlen = XDR_QUADLEN(len);
-               if (end - p < xlen + 1)
-                       goto short_pkt;
-               dprintk("filename = %*s\n", len, (char *)p);
-               p += xlen;
-               len = ntohl(*p++);      /* bitmap length */
-               if (end - p < len + 1)
-                       goto short_pkt;
-               p += len;
-               attrlen = XDR_QUADLEN(ntohl(*p++));
-               if (end - p < attrlen + 2)
-                       goto short_pkt;
-               p += attrlen;           /* attributes */
-               entry = p;
-       }
-       /*
-        * Apparently some server sends responses that are a valid size, but
-        * contain no entries, and have value_follows==0 and EOF==0. For
-        * those, just set the EOF marker.
-        */
-       if (!nr && entry[1] == 0) {
-               dprintk("NFS: readdir reply truncated!\n");
-               entry[1] = 1;
-       }
-out:
-       kunmap_atomic(kaddr, KM_USER0);
+
        return 0;
-short_pkt:
-       /*
-        * When we get a short packet there are 2 possibilities. We can
-        * return an error, or fix up the response to look like a valid
-        * response and return what we have so far. If there are no
-        * entries and the packet was short, then return -EIO. If there
-        * are valid entries in the response, return them and pretend that
-        * the call was successful, but incomplete. The caller can retry the
-        * readdir starting at the last cookie.
-        */
-       dprintk("%s: short packet at entry %d\n", __func__, nr);
-       entry[0] = entry[1] = 0;
-       if (nr)
-               goto out;
-err_unmap:
-       kunmap_atomic(kaddr, KM_USER0);
-       return -errno_NFSERR_IO;
 }
 
 static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
@@ -4299,7 +4528,6 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
        size_t hdrlen;
        u32 len, recvd;
        __be32 *p;
-       char *kaddr;
        int status;
 
        status = decode_op_hdr(xdr, OP_READLINK);
@@ -4330,9 +4558,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
         * and and null-terminate the text (the VFS expects
         * null-termination).
         */
-       kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
-       kaddr[len+rcvbuf->page_base] = '\0';
-       kunmap_atomic(kaddr, KM_USER0);
+       xdr_terminate_string(rcvbuf, len);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -4668,7 +4894,6 @@ static int decode_sequence(struct xdr_stream *xdr,
                           struct rpc_rqst *rqstp)
 {
 #if defined(CONFIG_NFS_V4_1)
-       struct nfs4_slot *slot;
        struct nfs4_sessionid id;
        u32 dummy;
        int status;
@@ -4700,15 +4925,14 @@ static int decode_sequence(struct xdr_stream *xdr,
                goto out_overflow;
 
        /* seqid */
-       slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
        dummy = be32_to_cpup(p++);
-       if (dummy != slot->seq_nr) {
+       if (dummy != res->sr_slot->seq_nr) {
                dprintk("%s Invalid sequence number\n", __func__);
                goto out_err;
        }
        /* slot id */
        dummy = be32_to_cpup(p++);
-       if (dummy != res->sr_slotid) {
+       if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) {
                dprintk("%s Invalid slot id\n", __func__);
                goto out_err;
        }
@@ -4731,6 +4955,134 @@ out_overflow:
 #endif /* CONFIG_NFS_V4_1 */
 }
 
+#if defined(CONFIG_NFS_V4_1)
+
+static int decode_getdeviceinfo(struct xdr_stream *xdr,
+                               struct pnfs_device *pdev)
+{
+       __be32 *p;
+       uint32_t len, type;
+       int status;
+
+       status = decode_op_hdr(xdr, OP_GETDEVICEINFO);
+       if (status) {
+               if (status == -ETOOSMALL) {
+                       p = xdr_inline_decode(xdr, 4);
+                       if (unlikely(!p))
+                               goto out_overflow;
+                       pdev->mincount = be32_to_cpup(p);
+                       dprintk("%s: Min count too small. mincnt = %u\n",
+                               __func__, pdev->mincount);
+               }
+               return status;
+       }
+
+       p = xdr_inline_decode(xdr, 8);
+       if (unlikely(!p))
+               goto out_overflow;
+       type = be32_to_cpup(p++);
+       if (type != pdev->layout_type) {
+               dprintk("%s: layout mismatch req: %u pdev: %u\n",
+                       __func__, pdev->layout_type, type);
+               return -EINVAL;
+       }
+       /*
+        * Get the length of the opaque device_addr4. xdr_read_pages places
+        * the opaque device_addr4 in the xdr_buf->pages (pnfs_device->pages)
+        * and places the remaining xdr data in xdr_buf->tail
+        */
+       pdev->mincount = be32_to_cpup(p);
+       xdr_read_pages(xdr, pdev->mincount); /* include space for the length */
+
+       /* Parse notification bitmap, verifying that it is zero. */
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       len = be32_to_cpup(p);
+       if (len) {
+               int i;
+
+               p = xdr_inline_decode(xdr, 4 * len);
+               if (unlikely(!p))
+                       goto out_overflow;
+               for (i = 0; i < len; i++, p++) {
+                       if (be32_to_cpup(p)) {
+                               dprintk("%s: notifications not supported\n",
+                                       __func__);
+                               return -EIO;
+                       }
+               }
+       }
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
+static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
+                           struct nfs4_layoutget_res *res)
+{
+       __be32 *p;
+       int status;
+       u32 layout_count;
+
+       status = decode_op_hdr(xdr, OP_LAYOUTGET);
+       if (status)
+               return status;
+       p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->return_on_close = be32_to_cpup(p++);
+       p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
+       layout_count = be32_to_cpup(p);
+       if (!layout_count) {
+               dprintk("%s: server responded with empty layout array\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       p = xdr_inline_decode(xdr, 24);
+       if (unlikely(!p))
+               goto out_overflow;
+       p = xdr_decode_hyper(p, &res->range.offset);
+       p = xdr_decode_hyper(p, &res->range.length);
+       res->range.iomode = be32_to_cpup(p++);
+       res->type = be32_to_cpup(p++);
+
+       status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p);
+       if (unlikely(status))
+               return status;
+
+       dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
+               __func__,
+               (unsigned long)res->range.offset,
+               (unsigned long)res->range.length,
+               res->range.iomode,
+               res->type,
+               res->layout.len);
+
+       /* nfs4_proc_layoutget allocated a single page */
+       if (res->layout.len > PAGE_SIZE)
+               return -ENOMEM;
+       memcpy(res->layout.buf, p, res->layout.len);
+
+       if (layout_count > 1) {
+               /* We only handle a length one array at the moment.  Any
+                * further entries are just ignored.  Note that this means
+                * the client may see a response that is less than the
+                * minimum it requested.
+                */
+               dprintk("%s: server responded with %d layouts, dropping tail\n",
+                       __func__, layout_count);
+       }
+
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
 /*
  * END OF "GENERIC" DECODE ROUTINES.
  */
@@ -4873,7 +5225,7 @@ out:
 /*
  * Decode RENAME response
  */
-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs_renameres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -5758,25 +6110,84 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
                status = decode_reclaim_complete(&xdr, (void *)NULL);
        return status;
 }
+
+/*
+ * Decode GETDEVINFO response
+ */
+static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp, uint32_t *p,
+                                     struct nfs4_getdeviceinfo_res *res)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+       status = decode_compound_hdr(&xdr, &hdr);
+       if (status != 0)
+               goto out;
+       status = decode_sequence(&xdr, &res->seq_res, rqstp);
+       if (status != 0)
+               goto out;
+       status = decode_getdeviceinfo(&xdr, res->pdev);
+out:
+       return status;
+}
+
+/*
+ * Decode LAYOUTGET response
+ */
+static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, uint32_t *p,
+                                 struct nfs4_layoutget_res *res)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+       status = decode_compound_hdr(&xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(&xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(&xdr);
+       if (status)
+               goto out;
+       status = decode_layoutget(&xdr, rqstp, res);
+out:
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
-__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
+                          struct nfs_server *server, int plus)
 {
        uint32_t bitmap[2] = {0};
        uint32_t len;
-
-       if (!*p++) {
-               if (!*p)
+       __be32 *p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       if (!ntohl(*p++)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               if (!ntohl(*p++))
                        return ERR_PTR(-EAGAIN);
                entry->eof = 1;
                return ERR_PTR(-EBADCOOKIE);
        }
 
+       p = xdr_inline_decode(xdr, 12);
+       if (unlikely(!p))
+               goto out_overflow;
        entry->prev_cookie = entry->cookie;
        p = xdr_decode_hyper(p, &entry->cookie);
        entry->len = ntohl(*p++);
+
+       p = xdr_inline_decode(xdr, entry->len);
+       if (unlikely(!p))
+               goto out_overflow;
        entry->name = (const char *) p;
-       p += XDR_QUADLEN(entry->len);
 
        /*
         * In case the server doesn't return an inode number,
@@ -5784,32 +6195,33 @@ __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
         * since glibc seems to choke on it...)
         */
        entry->ino = 1;
+       entry->fattr->valid = 0;
 
-       len = ntohl(*p++);              /* bitmap length */
-       if (len-- > 0) {
-               bitmap[0] = ntohl(*p++);
-               if (len-- > 0) {
-                       bitmap[1] = ntohl(*p++);
-                       p += len;
-               }
-       }
-       len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
-       if (len > 0) {
-               if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
-                       bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
-                       /* Ignore the return value of rdattr_error for now */
-                       p++;
-                       len--;
-               }
-               if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
-                       xdr_decode_hyper(p, &entry->ino);
-               else if (bitmap[0] == FATTR4_WORD0_FILEID)
-                       xdr_decode_hyper(p, &entry->ino);
-               p += len;
-       }
+       if (decode_attr_bitmap(xdr, bitmap) < 0)
+               goto out_overflow;
+
+       if (decode_attr_length(xdr, &len, &p) < 0)
+               goto out_overflow;
+
+       if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0)
+               goto out_overflow;
+       if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
+               entry->ino = entry->fattr->fileid;
+
+       if (verify_attr_len(xdr, p, len) < 0)
+               goto out_overflow;
+
+       p = xdr_inline_peek(xdr, 8);
+       if (p != NULL)
+               entry->eof = !p[0] && p[1];
+       else
+               entry->eof = 0;
 
-       entry->eof = !p[0] && p[1];
        return p;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return ERR_PTR(-EIO);
 }
 
 /*
@@ -5936,6 +6348,8 @@ struct rpc_procinfo       nfs4_procedures[] = {
   PROC(SEQUENCE,       enc_sequence,   dec_sequence),
   PROC(GET_LEASE_TIME, enc_get_lease_time,     dec_get_lease_time),
   PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
+  PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
+  PROC(LAYOUTGET,  enc_layoutget,     dec_layoutget),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index df101d9f546ae294a4e370b77fa63c06bf5ab277..903908a20023bf83b08d7fc6c808cbd4f20e0aa2 100644 (file)
@@ -3,9 +3,10 @@
  *
  *  Allow an NFS filesystem to be mounted as root. The way this works is:
  *     (1) Use the IP autoconfig mechanism to set local IP addresses and routes.
- *     (2) Handle RPC negotiation with the system which replied to RARP or
- *         was reported as a boot server by BOOTP or manually.
- *     (3) The actual mounting is done later, when init() is running.
+ *     (2) Construct the device string and the options string using DHCP
+ *         option 17 and/or kernel command line options.
+ *     (3) When mount_root() sets up the root file system, pass these strings
+ *         to the NFS client's regular mount interface via sys_mount().
  *
  *
  *     Changes:
  *     Hua Qin         :       Support for mounting root file system via
  *                             NFS over TCP.
  *     Fabian Frederick:       Option parser rebuilt (using parser lib)
-*/
+ *     Chuck Lever     :       Use super.c's text-based mount option parsing
+ *     Chuck Lever     :       Add "nfsrootdebug".
+ */
 
 #include <linux/types.h>
 #include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/xprtsock.h>
 #include <linux/nfs.h>
 #include <linux/nfs_fs.h>
-#include <linux/nfs_mount.h>
-#include <linux/in.h>
-#include <linux/major.h>
 #include <linux/utsname.h>
-#include <linux/inet.h>
 #include <linux/root_dev.h>
 #include <net/ipconfig.h>
-#include <linux/parser.h>
 
 #include "internal.h"
 
-/* Define this to allow debugging output */
-#undef NFSROOT_DEBUG
 #define NFSDBG_FACILITY NFSDBG_ROOT
 
-/* Default port to use if server is not running a portmapper */
-#define NFS_MNT_PORT   627
-
 /* Default path we try to mount. "%s" gets replaced by our IP address */
 #define NFS_ROOT               "/tftpboot/%s"
 
 /* Parameters passed from the kernel command line */
-static char nfs_root_name[256] __initdata = "";
+static char nfs_root_parms[256] __initdata = "";
+
+/* Text-based mount options passed to super.c */
+static char nfs_root_options[256] __initdata = "";
 
 /* Address of NFS server */
-static __be32 servaddr __initdata = 0;
+static __be32 servaddr __initdata = htonl(INADDR_NONE);
 
 /* Name of directory to mount */
-static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, };
-
-/* NFS-related data */
-static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
-static int nfs_port __initdata = 0;            /* Port to connect to for NFS */
-static int mount_port __initdata = 0;          /* Mount daemon port number */
-
-
-/***************************************************************************
-
-                            Parsing of options
-
- ***************************************************************************/
-
-enum {
-       /* Options that take integer arguments */
-       Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin,
-       Opt_acregmax, Opt_acdirmin, Opt_acdirmax,
-       /* Options that take no arguments */
-       Opt_soft, Opt_hard, Opt_intr,
-       Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, 
-       Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
-       Opt_acl, Opt_noacl,
-       /* Error token */
-       Opt_err
-};
-
-static const match_table_t tokens __initconst = {
-       {Opt_port, "port=%u"},
-       {Opt_rsize, "rsize=%u"},
-       {Opt_wsize, "wsize=%u"},
-       {Opt_timeo, "timeo=%u"},
-       {Opt_retrans, "retrans=%u"},
-       {Opt_acregmin, "acregmin=%u"},
-       {Opt_acregmax, "acregmax=%u"},
-       {Opt_acdirmin, "acdirmin=%u"},
-       {Opt_acdirmax, "acdirmax=%u"},
-       {Opt_soft, "soft"},
-       {Opt_hard, "hard"},
-       {Opt_intr, "intr"},
-       {Opt_nointr, "nointr"},
-       {Opt_posix, "posix"},
-       {Opt_noposix, "noposix"},
-       {Opt_cto, "cto"},
-       {Opt_nocto, "nocto"},
-       {Opt_ac, "ac"},
-       {Opt_noac, "noac"},
-       {Opt_lock, "lock"},
-       {Opt_nolock, "nolock"},
-       {Opt_v2, "nfsvers=2"},
-       {Opt_v2, "v2"},
-       {Opt_v3, "nfsvers=3"},
-       {Opt_v3, "v3"},
-       {Opt_udp, "proto=udp"},
-       {Opt_udp, "udp"},
-       {Opt_tcp, "proto=tcp"},
-       {Opt_tcp, "tcp"},
-       {Opt_acl, "acl"},
-       {Opt_noacl, "noacl"},
-       {Opt_err, NULL}
-       
-};
+static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = "";
 
+/* server:export path string passed to super.c */
+static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
+
+#ifdef RPC_DEBUG
 /*
- *  Parse option string.
+ * When the "nfsrootdebug" kernel command line option is specified,
+ * enable debugging messages for NFSROOT.
  */
-
-static int __init root_nfs_parse(char *name, char *buf)
+static int __init nfs_root_debug(char *__unused)
 {
-
-       char *p;
-       substring_t args[MAX_OPT_ARGS];
-       int option;
-
-       if (!name)
-               return 1;
-
-       /* Set the NFS remote path */
-       p = strsep(&name, ",");
-       if (p[0] != '\0' && strcmp(p, "default") != 0)
-               strlcpy(buf, p, NFS_MAXPATHLEN);
-
-       while ((p = strsep (&name, ",")) != NULL) {
-               int token; 
-               if (!*p)
-                       continue;
-               token = match_token(p, tokens, args);
-
-               /* %u tokens only. Beware if you add new tokens! */
-               if (token < Opt_soft && match_int(&args[0], &option))
-                       return 0;
-               switch (token) {
-                       case Opt_port:
-                               nfs_port = option;
-                               break;
-                       case Opt_rsize:
-                               nfs_data.rsize = option;
-                               break;
-                       case Opt_wsize:
-                               nfs_data.wsize = option;
-                               break;
-                       case Opt_timeo:
-                               nfs_data.timeo = option;
-                               break;
-                       case Opt_retrans:
-                               nfs_data.retrans = option;
-                               break;
-                       case Opt_acregmin:
-                               nfs_data.acregmin = option;
-                               break;
-                       case Opt_acregmax:
-                               nfs_data.acregmax = option;
-                               break;
-                       case Opt_acdirmin:
-                               nfs_data.acdirmin = option;
-                               break;
-                       case Opt_acdirmax:
-                               nfs_data.acdirmax = option;
-                               break;
-                       case Opt_soft:
-                               nfs_data.flags |= NFS_MOUNT_SOFT;
-                               break;
-                       case Opt_hard:
-                               nfs_data.flags &= ~NFS_MOUNT_SOFT;
-                               break;
-                       case Opt_intr:
-                       case Opt_nointr:
-                               break;
-                       case Opt_posix:
-                               nfs_data.flags |= NFS_MOUNT_POSIX;
-                               break;
-                       case Opt_noposix:
-                               nfs_data.flags &= ~NFS_MOUNT_POSIX;
-                               break;
-                       case Opt_cto:
-                               nfs_data.flags &= ~NFS_MOUNT_NOCTO;
-                               break;
-                       case Opt_nocto:
-                               nfs_data.flags |= NFS_MOUNT_NOCTO;
-                               break;
-                       case Opt_ac:
-                               nfs_data.flags &= ~NFS_MOUNT_NOAC;
-                               break;
-                       case Opt_noac:
-                               nfs_data.flags |= NFS_MOUNT_NOAC;
-                               break;
-                       case Opt_lock:
-                               nfs_data.flags &= ~NFS_MOUNT_NONLM;
-                               break;
-                       case Opt_nolock:
-                               nfs_data.flags |= NFS_MOUNT_NONLM;
-                               break;
-                       case Opt_v2:
-                               nfs_data.flags &= ~NFS_MOUNT_VER3;
-                               break;
-                       case Opt_v3:
-                               nfs_data.flags |= NFS_MOUNT_VER3;
-                               break;
-                       case Opt_udp:
-                               nfs_data.flags &= ~NFS_MOUNT_TCP;
-                               break;
-                       case Opt_tcp:
-                               nfs_data.flags |= NFS_MOUNT_TCP;
-                               break;
-                       case Opt_acl:
-                               nfs_data.flags &= ~NFS_MOUNT_NOACL;
-                               break;
-                       case Opt_noacl:
-                               nfs_data.flags |= NFS_MOUNT_NOACL;
-                               break;
-                       default:
-                               printk(KERN_WARNING "Root-NFS: unknown "
-                                       "option: %s\n", p);
-                               return 0;
-               }
-       }
-
+       nfs_debug |= NFSDBG_ROOT | NFSDBG_MOUNT;
        return 1;
 }
 
+__setup("nfsrootdebug", nfs_root_debug);
+#endif
+
 /*
- *  Prepare the NFS data structure and parse all options.
+ *  Parse NFS server and directory information passed on the kernel
+ *  command line.
+ *
+ *  nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
+ *
+ *  If there is a "%s" token in the <root-dir> string, it is replaced
+ *  by the ASCII-representation of the client's IP address.
  */
-static int __init root_nfs_name(char *name)
+static int __init nfs_root_setup(char *line)
 {
-       static char buf[NFS_MAXPATHLEN] __initdata;
-       char *cp;
-
-       /* Set some default values */
-       memset(&nfs_data, 0, sizeof(nfs_data));
-       nfs_port          = -1;
-       nfs_data.version  = NFS_MOUNT_VERSION;
-       nfs_data.flags    = NFS_MOUNT_NONLM;    /* No lockd in nfs root yet */
-       nfs_data.rsize    = NFS_DEF_FILE_IO_SIZE;
-       nfs_data.wsize    = NFS_DEF_FILE_IO_SIZE;
-       nfs_data.acregmin = NFS_DEF_ACREGMIN;
-       nfs_data.acregmax = NFS_DEF_ACREGMAX;
-       nfs_data.acdirmin = NFS_DEF_ACDIRMIN;
-       nfs_data.acdirmax = NFS_DEF_ACDIRMAX;
-       strcpy(buf, NFS_ROOT);
-
-       /* Process options received from the remote server */
-       root_nfs_parse(root_server_path, buf);
-
-       /* Override them by options set on kernel command-line */
-       root_nfs_parse(name, buf);
-
-       cp = utsname()->nodename;
-       if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
-               printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
-               return -1;
+       ROOT_DEV = Root_NFS;
+
+       if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
+               strlcpy(nfs_root_parms, line, sizeof(nfs_root_parms));
+       } else {
+               size_t n = strlen(line) + sizeof(NFS_ROOT) - 1;
+               if (n >= sizeof(nfs_root_parms))
+                       line[sizeof(nfs_root_parms) - sizeof(NFS_ROOT) - 2] = '\0';
+               sprintf(nfs_root_parms, NFS_ROOT, line);
        }
-       sprintf(nfs_export_path, buf, cp);
+
+       /*
+        * Extract the IP address of the NFS server containing our
+        * root file system, if one was specified.
+        *
+        * Note: root_nfs_parse_addr() removes the server-ip from
+        *       nfs_root_parms, if it exists.
+        */
+       root_server_addr = root_nfs_parse_addr(nfs_root_parms);
 
        return 1;
 }
 
+__setup("nfsroot=", nfs_root_setup);
 
-/*
- *  Get NFS server address.
- */
-static int __init root_nfs_addr(void)
+static int __init root_nfs_copy(char *dest, const char *src,
+                                    const size_t destlen)
 {
-       if ((servaddr = root_server_addr) == htonl(INADDR_NONE)) {
-               printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n");
+       if (strlcpy(dest, src, destlen) > destlen)
                return -1;
-       }
+       return 0;
+}
 
-       snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
-                "%pI4", &servaddr);
+static int __init root_nfs_cat(char *dest, const char *src,
+                                 const size_t destlen)
+{
+       if (strlcat(dest, src, destlen) > destlen)
+               return -1;
        return 0;
 }
 
 /*
- *  Tell the user what's going on.
+ * Parse out root export path and mount options from
+ * passed-in string @incoming.
+ *
+ * Copy the export path into @exppath.
  */
-#ifdef NFSROOT_DEBUG
-static void __init root_nfs_print(void)
+static int __init root_nfs_parse_options(char *incoming, char *exppath,
+                                        const size_t exppathlen)
 {
-       printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
-               nfs_export_path, nfs_data.hostname);
-       printk(KERN_NOTICE "Root-NFS:     rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
-               nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans);
-       printk(KERN_NOTICE "Root-NFS:     acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
-               nfs_data.acregmin, nfs_data.acregmax,
-               nfs_data.acdirmin, nfs_data.acdirmax);
-       printk(KERN_NOTICE "Root-NFS:     nfsd port = %d, mountd port = %d, flags = %08x\n",
-               nfs_port, mount_port, nfs_data.flags);
-}
-#endif
-
+       char *p;
 
-static int __init root_nfs_init(void)
-{
-#ifdef NFSROOT_DEBUG
-       nfs_debug |= NFSDBG_ROOT;
-#endif
+       /*
+        * Set the NFS remote path
+        */
+       p = strsep(&incoming, ",");
+       if (*p != '\0' && strcmp(p, "default") != 0)
+               if (root_nfs_copy(exppath, p, exppathlen))
+                       return -1;
 
        /*
-        * Decode the root directory path name and NFS options from
-        * the kernel command line. This has to go here in order to
-        * be able to use the client IP address for the remote root
-        * directory (necessary for pure RARP booting).
+        * @incoming now points to the rest of the string; if it
+        * contains something, append it to our root options buffer
         */
-       if (root_nfs_name(nfs_root_name) < 0 ||
-           root_nfs_addr() < 0)
-               return -1;
+       if (incoming != NULL && *incoming != '\0')
+               if (root_nfs_cat(nfs_root_options, incoming,
+                                               sizeof(nfs_root_options)))
+                       return -1;
 
-#ifdef NFSROOT_DEBUG
-       root_nfs_print();
-#endif
+       /*
+        * Possibly prepare for more options to be appended
+        */
+       if (nfs_root_options[0] != '\0' &&
+           nfs_root_options[strlen(nfs_root_options)] != ',')
+               if (root_nfs_cat(nfs_root_options, ",",
+                                               sizeof(nfs_root_options)))
+                       return -1;
 
        return 0;
 }
 
-
 /*
- *  Parse NFS server and directory information passed on the kernel
- *  command line.
+ *  Decode the export directory path name and NFS options from
+ *  the kernel command line.  This has to be done late in order to
+ *  use a dynamically acquired client IP address for the remote
+ *  root directory path.
+ *
+ *  Returns zero if successful; otherwise -1 is returned.
  */
-static int __init nfs_root_setup(char *line)
+static int __init root_nfs_data(char *cmdline)
 {
-       ROOT_DEV = Root_NFS;
-       if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
-               strlcpy(nfs_root_name, line, sizeof(nfs_root_name));
-       } else {
-               int n = strlen(line) + sizeof(NFS_ROOT) - 1;
-               if (n >= sizeof(nfs_root_name))
-                       line[sizeof(nfs_root_name) - sizeof(NFS_ROOT) - 2] = '\0';
-               sprintf(nfs_root_name, NFS_ROOT, line);
+       char addr_option[sizeof("nolock,addr=") + INET_ADDRSTRLEN + 1];
+       int len, retval = -1;
+       char *tmp = NULL;
+       const size_t tmplen = sizeof(nfs_export_path);
+
+       tmp = kzalloc(tmplen, GFP_KERNEL);
+       if (tmp == NULL)
+               goto out_nomem;
+       strcpy(tmp, NFS_ROOT);
+
+       if (root_server_path[0] != '\0') {
+               dprintk("Root-NFS: DHCPv4 option 17: %s\n",
+                       root_server_path);
+               if (root_nfs_parse_options(root_server_path, tmp, tmplen))
+                       goto out_optionstoolong;
        }
-       root_server_addr = root_nfs_parse_addr(nfs_root_name);
-       return 1;
-}
-
-__setup("nfsroot=", nfs_root_setup);
-
-/***************************************************************************
 
-              Routines to actually mount the root directory
+       if (cmdline[0] != '\0') {
+               dprintk("Root-NFS: nfsroot=%s\n", cmdline);
+               if (root_nfs_parse_options(cmdline, tmp, tmplen))
+                       goto out_optionstoolong;
+       }
 
- ***************************************************************************/
+       /*
+        * Append mandatory options for nfsroot so they override
+        * what has come before
+        */
+       snprintf(addr_option, sizeof(addr_option), "nolock,addr=%pI4",
+                       &servaddr);
+       if (root_nfs_cat(nfs_root_options, addr_option,
+                                               sizeof(nfs_root_options)))
+               goto out_optionstoolong;
 
-/*
- *  Construct sockaddr_in from address and port number.
- */
-static inline void
-set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
-{
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = addr;
-       sin->sin_port = port;
-}
+       /*
+        * Set up nfs_root_device.  For NFS mounts, this looks like
+        *
+        *      server:/path
+        *
+        * At this point, utsname()->nodename contains our local
+        * IP address or hostname, set by ipconfig.  If "%s" exists
+        * in tmp, substitute the nodename, then shovel the whole
+        * mess into nfs_root_device.
+        */
+       len = snprintf(nfs_export_path, sizeof(nfs_export_path),
+                               tmp, utsname()->nodename);
+       if (len > (int)sizeof(nfs_export_path))
+               goto out_devnametoolong;
+       len = snprintf(nfs_root_device, sizeof(nfs_root_device),
+                               "%pI4:%s", &servaddr, nfs_export_path);
+       if (len > (int)sizeof(nfs_root_device))
+               goto out_devnametoolong;
 
-/*
- *  Query server portmapper for the port of a daemon program.
- */
-static int __init root_nfs_getport(int program, int version, int proto)
-{
-       struct sockaddr_in sin;
+       retval = 0;
 
-       printk(KERN_NOTICE "Looking up port of RPC %d/%d on %pI4\n",
-               program, version, &servaddr);
-       set_sockaddr(&sin, servaddr, 0);
-       return rpcb_getport_sync(&sin, program, version, proto);
+out:
+       kfree(tmp);
+       return retval;
+out_nomem:
+       printk(KERN_ERR "Root-NFS: could not allocate memory\n");
+       goto out;
+out_optionstoolong:
+       printk(KERN_ERR "Root-NFS: mount options string too long\n");
+       goto out;
+out_devnametoolong:
+       printk(KERN_ERR "Root-NFS: root device name too long.\n");
+       goto out;
 }
 
-
-/*
- *  Use portmapper to find mountd and nfsd port numbers if not overriden
- *  by the user. Use defaults if portmapper is not available.
- *  XXX: Is there any nfs server with no portmapper?
+/**
+ * nfs_root_data - Return prepared 'data' for NFSROOT mount
+ * @root_device: OUT: address of string containing NFSROOT device
+ * @root_data: OUT: address of string containing NFSROOT mount options
+ *
+ * Returns zero and sets @root_device and @root_data if successful,
+ * otherwise -1 is returned.
  */
-static int __init root_nfs_ports(void)
+int __init nfs_root_data(char **root_device, char **root_data)
 {
-       int port;
-       int nfsd_ver, mountd_ver;
-       int nfsd_port, mountd_port;
-       int proto;
-
-       if (nfs_data.flags & NFS_MOUNT_VER3) {
-               nfsd_ver = NFS3_VERSION;
-               mountd_ver = NFS_MNT3_VERSION;
-               nfsd_port = NFS_PORT;
-               mountd_port = NFS_MNT_PORT;
-       } else {
-               nfsd_ver = NFS2_VERSION;
-               mountd_ver = NFS_MNT_VERSION;
-               nfsd_port = NFS_PORT;
-               mountd_port = NFS_MNT_PORT;
-       }
-
-       proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
-       if (nfs_port < 0) {
-               if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
-                       printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
-                                       "number from server, using default\n");
-                       port = nfsd_port;
-               }
-               nfs_port = port;
-               dprintk("Root-NFS: Portmapper on server returned %d "
-                       "as nfsd port\n", port);
+       servaddr = root_server_addr;
+       if (servaddr == htonl(INADDR_NONE)) {
+               printk(KERN_ERR "Root-NFS: no NFS server address\n");
+               return -1;
        }
 
-       if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) {
-               printk(KERN_ERR "Root-NFS: Unable to get mountd port "
-                               "number from server, using default\n");
-               port = mountd_port;
-       }
-       mount_port = port;
-       dprintk("Root-NFS: mountd port is %d\n", port);
+       if (root_nfs_data(nfs_root_parms) < 0)
+               return -1;
 
+       *root_device = nfs_root_device;
+       *root_data = nfs_root_options;
        return 0;
 }
-
-
-/*
- *  Get a file handle from the server for the directory which is to be
- *  mounted.
- */
-static int __init root_nfs_get_handle(void)
-{
-       struct sockaddr_in sin;
-       unsigned int auth_flav_len = 0;
-       struct nfs_mount_request request = {
-               .sap            = (struct sockaddr *)&sin,
-               .salen          = sizeof(sin),
-               .dirpath        = nfs_export_path,
-               .version        = (nfs_data.flags & NFS_MOUNT_VER3) ?
-                                       NFS_MNT3_VERSION : NFS_MNT_VERSION,
-               .protocol       = (nfs_data.flags & NFS_MOUNT_TCP) ?
-                                       XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
-               .auth_flav_len  = &auth_flav_len,
-       };
-       int status = -ENOMEM;
-
-       request.fh = nfs_alloc_fhandle();
-       if (!request.fh)
-               goto out;
-       set_sockaddr(&sin, servaddr, htons(mount_port));
-       status = nfs_mount(&request);
-       if (status < 0)
-               printk(KERN_ERR "Root-NFS: Server returned error %d "
-                               "while mounting %s\n", status, nfs_export_path);
-       else {
-               nfs_data.root.size = request.fh->size;
-               memcpy(&nfs_data.root.data, request.fh->data, request.fh->size);
-       }
-       nfs_free_fhandle(request.fh);
-out:
-       return status;
-}
-
-/*
- *  Get the NFS port numbers and file handle, and return the prepared 'data'
- *  argument for mount() if everything went OK. Return NULL otherwise.
- */
-void * __init nfs_root_data(void)
-{
-       if (root_nfs_init() < 0
-        || root_nfs_ports() < 0
-        || root_nfs_get_handle() < 0)
-               return NULL;
-       set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, htons(nfs_port));
-       return (void*)&nfs_data;
-}
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
new file mode 100644 (file)
index 0000000..db77342
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ *  pNFS functions to call and manage layout drivers.
+ *
+ *  Copyright (c) 2002 [year of first publication]
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#include <linux/nfs_fs.h>
+#include "internal.h"
+#include "pnfs.h"
+
+#define NFSDBG_FACILITY                NFSDBG_PNFS
+
+/* Locking:
+ *
+ * pnfs_spinlock:
+ *      protects pnfs_modules_tbl.
+ */
+static DEFINE_SPINLOCK(pnfs_spinlock);
+
+/*
+ * pnfs_modules_tbl holds all pnfs modules
+ */
+static LIST_HEAD(pnfs_modules_tbl);
+
+/* Return the registered pnfs layout driver module matching given id */
+static struct pnfs_layoutdriver_type *
+find_pnfs_driver_locked(u32 id)
+{
+       struct pnfs_layoutdriver_type *local;
+
+       list_for_each_entry(local, &pnfs_modules_tbl, pnfs_tblid)
+               if (local->id == id)
+                       goto out;
+       local = NULL;
+out:
+       dprintk("%s: Searching for id %u, found %p\n", __func__, id, local);
+       return local;
+}
+
+static struct pnfs_layoutdriver_type *
+find_pnfs_driver(u32 id)
+{
+       struct pnfs_layoutdriver_type *local;
+
+       spin_lock(&pnfs_spinlock);
+       local = find_pnfs_driver_locked(id);
+       spin_unlock(&pnfs_spinlock);
+       return local;
+}
+
+void
+unset_pnfs_layoutdriver(struct nfs_server *nfss)
+{
+       if (nfss->pnfs_curr_ld) {
+               nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
+               module_put(nfss->pnfs_curr_ld->owner);
+       }
+       nfss->pnfs_curr_ld = NULL;
+}
+
+/*
+ * Try to set the server's pnfs module to the pnfs layout type specified by id.
+ * Currently only one pNFS layout driver per filesystem is supported.
+ *
+ * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
+ */
+void
+set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
+{
+       struct pnfs_layoutdriver_type *ld_type = NULL;
+
+       if (id == 0)
+               goto out_no_driver;
+       if (!(server->nfs_client->cl_exchange_flags &
+                (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
+               printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
+                      id, server->nfs_client->cl_exchange_flags);
+               goto out_no_driver;
+       }
+       ld_type = find_pnfs_driver(id);
+       if (!ld_type) {
+               request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
+               ld_type = find_pnfs_driver(id);
+               if (!ld_type) {
+                       dprintk("%s: No pNFS module found for %u.\n",
+                               __func__, id);
+                       goto out_no_driver;
+               }
+       }
+       if (!try_module_get(ld_type->owner)) {
+               dprintk("%s: Could not grab reference on module\n", __func__);
+               goto out_no_driver;
+       }
+       server->pnfs_curr_ld = ld_type;
+       if (ld_type->set_layoutdriver(server)) {
+               printk(KERN_ERR
+                      "%s: Error initializing mount point for layout driver %u.\n",
+                      __func__, id);
+               module_put(ld_type->owner);
+               goto out_no_driver;
+       }
+       dprintk("%s: pNFS module for %u set\n", __func__, id);
+       return;
+
+out_no_driver:
+       dprintk("%s: Using NFSv4 I/O\n", __func__);
+       server->pnfs_curr_ld = NULL;
+}
+
+int
+pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
+{
+       int status = -EINVAL;
+       struct pnfs_layoutdriver_type *tmp;
+
+       if (ld_type->id == 0) {
+               printk(KERN_ERR "%s id 0 is reserved\n", __func__);
+               return status;
+       }
+       if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
+               printk(KERN_ERR "%s Layout driver must provide "
+                      "alloc_lseg and free_lseg.\n", __func__);
+               return status;
+       }
+
+       spin_lock(&pnfs_spinlock);
+       tmp = find_pnfs_driver_locked(ld_type->id);
+       if (!tmp) {
+               list_add(&ld_type->pnfs_tblid, &pnfs_modules_tbl);
+               status = 0;
+               dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
+                       ld_type->name);
+       } else {
+               printk(KERN_ERR "%s Module with id %d already loaded!\n",
+                       __func__, ld_type->id);
+       }
+       spin_unlock(&pnfs_spinlock);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(pnfs_register_layoutdriver);
+
+void
+pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
+{
+       dprintk("%s Deregistering id:%u\n", __func__, ld_type->id);
+       spin_lock(&pnfs_spinlock);
+       list_del(&ld_type->pnfs_tblid);
+       spin_unlock(&pnfs_spinlock);
+}
+EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
+
+/*
+ * pNFS client layout cache
+ */
+
+static void
+get_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+{
+       assert_spin_locked(&lo->inode->i_lock);
+       lo->refcount++;
+}
+
+static void
+put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+{
+       assert_spin_locked(&lo->inode->i_lock);
+       BUG_ON(lo->refcount == 0);
+
+       lo->refcount--;
+       if (!lo->refcount) {
+               dprintk("%s: freeing layout cache %p\n", __func__, lo);
+               BUG_ON(!list_empty(&lo->layouts));
+               NFS_I(lo->inode)->layout = NULL;
+               kfree(lo);
+       }
+}
+
+void
+put_layout_hdr(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       put_layout_hdr_locked(NFS_I(inode)->layout);
+       spin_unlock(&inode->i_lock);
+}
+
+static void
+init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
+{
+       INIT_LIST_HEAD(&lseg->fi_list);
+       kref_init(&lseg->kref);
+       lseg->layout = lo;
+}
+
+/* Called without i_lock held, as the free_lseg call may sleep */
+static void
+destroy_lseg(struct kref *kref)
+{
+       struct pnfs_layout_segment *lseg =
+               container_of(kref, struct pnfs_layout_segment, kref);
+       struct inode *ino = lseg->layout->inode;
+
+       dprintk("--> %s\n", __func__);
+       NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
+       /* Matched by get_layout_hdr_locked in pnfs_insert_layout */
+       put_layout_hdr(ino);
+}
+
+static void
+put_lseg(struct pnfs_layout_segment *lseg)
+{
+       if (!lseg)
+               return;
+
+       dprintk("%s: lseg %p ref %d\n", __func__, lseg,
+               atomic_read(&lseg->kref.refcount));
+       kref_put(&lseg->kref, destroy_lseg);
+}
+
+static void
+pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list)
+{
+       struct pnfs_layout_segment *lseg, *next;
+       struct nfs_client *clp;
+
+       dprintk("%s:Begin lo %p\n", __func__, lo);
+
+       assert_spin_locked(&lo->inode->i_lock);
+       list_for_each_entry_safe(lseg, next, &lo->segs, fi_list) {
+               dprintk("%s: freeing lseg %p\n", __func__, lseg);
+               list_move(&lseg->fi_list, tmp_list);
+       }
+       clp = NFS_SERVER(lo->inode)->nfs_client;
+       spin_lock(&clp->cl_lock);
+       /* List does not take a reference, so no need for put here */
+       list_del_init(&lo->layouts);
+       spin_unlock(&clp->cl_lock);
+       write_seqlock(&lo->seqlock);
+       clear_bit(NFS_LAYOUT_STATEID_SET, &lo->state);
+       write_sequnlock(&lo->seqlock);
+
+       dprintk("%s:Return\n", __func__);
+}
+
+static void
+pnfs_free_lseg_list(struct list_head *tmp_list)
+{
+       struct pnfs_layout_segment *lseg;
+
+       while (!list_empty(tmp_list)) {
+               lseg = list_entry(tmp_list->next, struct pnfs_layout_segment,
+                               fi_list);
+               dprintk("%s calling put_lseg on %p\n", __func__, lseg);
+               list_del(&lseg->fi_list);
+               put_lseg(lseg);
+       }
+}
+
+void
+pnfs_destroy_layout(struct nfs_inode *nfsi)
+{
+       struct pnfs_layout_hdr *lo;
+       LIST_HEAD(tmp_list);
+
+       spin_lock(&nfsi->vfs_inode.i_lock);
+       lo = nfsi->layout;
+       if (lo) {
+               pnfs_clear_lseg_list(lo, &tmp_list);
+               /* Matched by refcount set to 1 in alloc_init_layout_hdr */
+               put_layout_hdr_locked(lo);
+       }
+       spin_unlock(&nfsi->vfs_inode.i_lock);
+       pnfs_free_lseg_list(&tmp_list);
+}
+
+/*
+ * Called by the state manger to remove all layouts established under an
+ * expired lease.
+ */
+void
+pnfs_destroy_all_layouts(struct nfs_client *clp)
+{
+       struct pnfs_layout_hdr *lo;
+       LIST_HEAD(tmp_list);
+
+       spin_lock(&clp->cl_lock);
+       list_splice_init(&clp->cl_layouts, &tmp_list);
+       spin_unlock(&clp->cl_lock);
+
+       while (!list_empty(&tmp_list)) {
+               lo = list_entry(tmp_list.next, struct pnfs_layout_hdr,
+                               layouts);
+               dprintk("%s freeing layout for inode %lu\n", __func__,
+                       lo->inode->i_ino);
+               pnfs_destroy_layout(NFS_I(lo->inode));
+       }
+}
+
+/* update lo->stateid with new if is more recent
+ *
+ * lo->stateid could be the open stateid, in which case we just use what given.
+ */
+static void
+pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
+                       const nfs4_stateid *new)
+{
+       nfs4_stateid *old = &lo->stateid;
+       bool overwrite = false;
+
+       write_seqlock(&lo->seqlock);
+       if (!test_bit(NFS_LAYOUT_STATEID_SET, &lo->state) ||
+           memcmp(old->stateid.other, new->stateid.other, sizeof(new->stateid.other)))
+               overwrite = true;
+       else {
+               u32 oldseq, newseq;
+
+               oldseq = be32_to_cpu(old->stateid.seqid);
+               newseq = be32_to_cpu(new->stateid.seqid);
+               if ((int)(newseq - oldseq) > 0)
+                       overwrite = true;
+       }
+       if (overwrite)
+               memcpy(&old->stateid, &new->stateid, sizeof(new->stateid));
+       write_sequnlock(&lo->seqlock);
+}
+
+static void
+pnfs_layout_from_open_stateid(struct pnfs_layout_hdr *lo,
+                             struct nfs4_state *state)
+{
+       int seq;
+
+       dprintk("--> %s\n", __func__);
+       write_seqlock(&lo->seqlock);
+       do {
+               seq = read_seqbegin(&state->seqlock);
+               memcpy(lo->stateid.data, state->stateid.data,
+                      sizeof(state->stateid.data));
+       } while (read_seqretry(&state->seqlock, seq));
+       set_bit(NFS_LAYOUT_STATEID_SET, &lo->state);
+       write_sequnlock(&lo->seqlock);
+       dprintk("<-- %s\n", __func__);
+}
+
+void
+pnfs_get_layout_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
+                       struct nfs4_state *open_state)
+{
+       int seq;
+
+       dprintk("--> %s\n", __func__);
+       do {
+               seq = read_seqbegin(&lo->seqlock);
+               if (!test_bit(NFS_LAYOUT_STATEID_SET, &lo->state)) {
+                       /* This will trigger retry of the read */
+                       pnfs_layout_from_open_stateid(lo, open_state);
+               } else
+                       memcpy(dst->data, lo->stateid.data,
+                              sizeof(lo->stateid.data));
+       } while (read_seqretry(&lo->seqlock, seq));
+       dprintk("<-- %s\n", __func__);
+}
+
+/*
+* Get layout from server.
+*    for now, assume that whole file layouts are requested.
+*    arg->offset: 0
+*    arg->length: all ones
+*/
+static struct pnfs_layout_segment *
+send_layoutget(struct pnfs_layout_hdr *lo,
+          struct nfs_open_context *ctx,
+          u32 iomode)
+{
+       struct inode *ino = lo->inode;
+       struct nfs_server *server = NFS_SERVER(ino);
+       struct nfs4_layoutget *lgp;
+       struct pnfs_layout_segment *lseg = NULL;
+
+       dprintk("--> %s\n", __func__);
+
+       BUG_ON(ctx == NULL);
+       lgp = kzalloc(sizeof(*lgp), GFP_KERNEL);
+       if (lgp == NULL) {
+               put_layout_hdr(lo->inode);
+               return NULL;
+       }
+       lgp->args.minlength = NFS4_MAX_UINT64;
+       lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
+       lgp->args.range.iomode = iomode;
+       lgp->args.range.offset = 0;
+       lgp->args.range.length = NFS4_MAX_UINT64;
+       lgp->args.type = server->pnfs_curr_ld->id;
+       lgp->args.inode = ino;
+       lgp->args.ctx = get_nfs_open_context(ctx);
+       lgp->lsegpp = &lseg;
+
+       /* Synchronously retrieve layout information from server and
+        * store in lseg.
+        */
+       nfs4_proc_layoutget(lgp);
+       if (!lseg) {
+               /* remember that LAYOUTGET failed and suspend trying */
+               set_bit(lo_fail_bit(iomode), &lo->state);
+       }
+       return lseg;
+}
+
+/*
+ * Compare two layout segments for sorting into layout cache.
+ * We want to preferentially return RW over RO layouts, so ensure those
+ * are seen first.
+ */
+static s64
+cmp_layout(u32 iomode1, u32 iomode2)
+{
+       /* read > read/write */
+       return (int)(iomode2 == IOMODE_READ) - (int)(iomode1 == IOMODE_READ);
+}
+
+static void
+pnfs_insert_layout(struct pnfs_layout_hdr *lo,
+                  struct pnfs_layout_segment *lseg)
+{
+       struct pnfs_layout_segment *lp;
+       int found = 0;
+
+       dprintk("%s:Begin\n", __func__);
+
+       assert_spin_locked(&lo->inode->i_lock);
+       if (list_empty(&lo->segs)) {
+               struct nfs_client *clp = NFS_SERVER(lo->inode)->nfs_client;
+
+               spin_lock(&clp->cl_lock);
+               BUG_ON(!list_empty(&lo->layouts));
+               list_add_tail(&lo->layouts, &clp->cl_layouts);
+               spin_unlock(&clp->cl_lock);
+       }
+       list_for_each_entry(lp, &lo->segs, fi_list) {
+               if (cmp_layout(lp->range.iomode, lseg->range.iomode) > 0)
+                       continue;
+               list_add_tail(&lseg->fi_list, &lp->fi_list);
+               dprintk("%s: inserted lseg %p "
+                       "iomode %d offset %llu length %llu before "
+                       "lp %p iomode %d offset %llu length %llu\n",
+                       __func__, lseg, lseg->range.iomode,
+                       lseg->range.offset, lseg->range.length,
+                       lp, lp->range.iomode, lp->range.offset,
+                       lp->range.length);
+               found = 1;
+               break;
+       }
+       if (!found) {
+               list_add_tail(&lseg->fi_list, &lo->segs);
+               dprintk("%s: inserted lseg %p "
+                       "iomode %d offset %llu length %llu at tail\n",
+                       __func__, lseg, lseg->range.iomode,
+                       lseg->range.offset, lseg->range.length);
+       }
+       get_layout_hdr_locked(lo);
+
+       dprintk("%s:Return\n", __func__);
+}
+
+static struct pnfs_layout_hdr *
+alloc_init_layout_hdr(struct inode *ino)
+{
+       struct pnfs_layout_hdr *lo;
+
+       lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
+       if (!lo)
+               return NULL;
+       lo->refcount = 1;
+       INIT_LIST_HEAD(&lo->layouts);
+       INIT_LIST_HEAD(&lo->segs);
+       seqlock_init(&lo->seqlock);
+       lo->inode = ino;
+       return lo;
+}
+
+static struct pnfs_layout_hdr *
+pnfs_find_alloc_layout(struct inode *ino)
+{
+       struct nfs_inode *nfsi = NFS_I(ino);
+       struct pnfs_layout_hdr *new = NULL;
+
+       dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
+
+       assert_spin_locked(&ino->i_lock);
+       if (nfsi->layout)
+               return nfsi->layout;
+
+       spin_unlock(&ino->i_lock);
+       new = alloc_init_layout_hdr(ino);
+       spin_lock(&ino->i_lock);
+
+       if (likely(nfsi->layout == NULL))       /* Won the race? */
+               nfsi->layout = new;
+       else
+               kfree(new);
+       return nfsi->layout;
+}
+
+/*
+ * iomode matching rules:
+ * iomode      lseg    match
+ * -----       -----   -----
+ * ANY         READ    true
+ * ANY         RW      true
+ * RW          READ    false
+ * RW          RW      true
+ * READ                READ    true
+ * READ                RW      true
+ */
+static int
+is_matching_lseg(struct pnfs_layout_segment *lseg, u32 iomode)
+{
+       return (iomode != IOMODE_RW || lseg->range.iomode == IOMODE_RW);
+}
+
+/*
+ * lookup range in layout
+ */
+static struct pnfs_layout_segment *
+pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)
+{
+       struct pnfs_layout_segment *lseg, *ret = NULL;
+
+       dprintk("%s:Begin\n", __func__);
+
+       assert_spin_locked(&lo->inode->i_lock);
+       list_for_each_entry(lseg, &lo->segs, fi_list) {
+               if (is_matching_lseg(lseg, iomode)) {
+                       ret = lseg;
+                       break;
+               }
+               if (cmp_layout(iomode, lseg->range.iomode) > 0)
+                       break;
+       }
+
+       dprintk("%s:Return lseg %p ref %d\n",
+               __func__, ret, ret ? atomic_read(&ret->kref.refcount) : 0);
+       return ret;
+}
+
+/*
+ * Layout segment is retreived from the server if not cached.
+ * The appropriate layout segment is referenced and returned to the caller.
+ */
+struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino,
+                  struct nfs_open_context *ctx,
+                  enum pnfs_iomode iomode)
+{
+       struct nfs_inode *nfsi = NFS_I(ino);
+       struct pnfs_layout_hdr *lo;
+       struct pnfs_layout_segment *lseg = NULL;
+
+       if (!pnfs_enabled_sb(NFS_SERVER(ino)))
+               return NULL;
+       spin_lock(&ino->i_lock);
+       lo = pnfs_find_alloc_layout(ino);
+       if (lo == NULL) {
+               dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
+               goto out_unlock;
+       }
+
+       /* Check to see if the layout for the given range already exists */
+       lseg = pnfs_has_layout(lo, iomode);
+       if (lseg) {
+               dprintk("%s: Using cached lseg %p for iomode %d)\n",
+                       __func__, lseg, iomode);
+               goto out_unlock;
+       }
+
+       /* if LAYOUTGET already failed once we don't try again */
+       if (test_bit(lo_fail_bit(iomode), &nfsi->layout->state))
+               goto out_unlock;
+
+       get_layout_hdr_locked(lo); /* Matched in nfs4_layoutget_release */
+       spin_unlock(&ino->i_lock);
+
+       lseg = send_layoutget(lo, ctx, iomode);
+out:
+       dprintk("%s end, state 0x%lx lseg %p\n", __func__,
+               nfsi->layout->state, lseg);
+       return lseg;
+out_unlock:
+       spin_unlock(&ino->i_lock);
+       goto out;
+}
+
+int
+pnfs_layout_process(struct nfs4_layoutget *lgp)
+{
+       struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout;
+       struct nfs4_layoutget_res *res = &lgp->res;
+       struct pnfs_layout_segment *lseg;
+       struct inode *ino = lo->inode;
+       int status = 0;
+
+       /* Inject layout blob into I/O device driver */
+       lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res);
+       if (!lseg || IS_ERR(lseg)) {
+               if (!lseg)
+                       status = -ENOMEM;
+               else
+                       status = PTR_ERR(lseg);
+               dprintk("%s: Could not allocate layout: error %d\n",
+                      __func__, status);
+               goto out;
+       }
+
+       spin_lock(&ino->i_lock);
+       init_lseg(lo, lseg);
+       lseg->range = res->range;
+       *lgp->lsegpp = lseg;
+       pnfs_insert_layout(lo, lseg);
+
+       /* Done processing layoutget. Set the layout stateid */
+       pnfs_set_layout_stateid(lo, &res->stateid);
+       spin_unlock(&ino->i_lock);
+out:
+       return status;
+}
+
+/*
+ * Device ID cache. Currently supports one layout type per struct nfs_client.
+ * Add layout type to the lookup key to expand to support multiple types.
+ */
+int
+pnfs_alloc_init_deviceid_cache(struct nfs_client *clp,
+                        void (*free_callback)(struct pnfs_deviceid_node *))
+{
+       struct pnfs_deviceid_cache *c;
+
+       c = kzalloc(sizeof(struct pnfs_deviceid_cache), GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;
+       spin_lock(&clp->cl_lock);
+       if (clp->cl_devid_cache != NULL) {
+               atomic_inc(&clp->cl_devid_cache->dc_ref);
+               dprintk("%s [kref [%d]]\n", __func__,
+                       atomic_read(&clp->cl_devid_cache->dc_ref));
+               kfree(c);
+       } else {
+               /* kzalloc initializes hlists */
+               spin_lock_init(&c->dc_lock);
+               atomic_set(&c->dc_ref, 1);
+               c->dc_free_callback = free_callback;
+               clp->cl_devid_cache = c;
+               dprintk("%s [new]\n", __func__);
+       }
+       spin_unlock(&clp->cl_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pnfs_alloc_init_deviceid_cache);
+
+/*
+ * Called from pnfs_layoutdriver_type->free_lseg
+ * last layout segment reference frees deviceid
+ */
+void
+pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
+                 struct pnfs_deviceid_node *devid)
+{
+       struct nfs4_deviceid *id = &devid->de_id;
+       struct pnfs_deviceid_node *d;
+       struct hlist_node *n;
+       long h = nfs4_deviceid_hash(id);
+
+       dprintk("%s [%d]\n", __func__, atomic_read(&devid->de_ref));
+       if (!atomic_dec_and_lock(&devid->de_ref, &c->dc_lock))
+               return;
+
+       hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[h], de_node)
+               if (!memcmp(&d->de_id, id, sizeof(*id))) {
+                       hlist_del_rcu(&d->de_node);
+                       spin_unlock(&c->dc_lock);
+                       synchronize_rcu();
+                       c->dc_free_callback(devid);
+                       return;
+               }
+       spin_unlock(&c->dc_lock);
+       /* Why wasn't it found in  the list? */
+       BUG();
+}
+EXPORT_SYMBOL_GPL(pnfs_put_deviceid);
+
+/* Find and reference a deviceid */
+struct pnfs_deviceid_node *
+pnfs_find_get_deviceid(struct pnfs_deviceid_cache *c, struct nfs4_deviceid *id)
+{
+       struct pnfs_deviceid_node *d;
+       struct hlist_node *n;
+       long hash = nfs4_deviceid_hash(id);
+
+       dprintk("--> %s hash %ld\n", __func__, hash);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) {
+               if (!memcmp(&d->de_id, id, sizeof(*id))) {
+                       if (!atomic_inc_not_zero(&d->de_ref)) {
+                               goto fail;
+                       } else {
+                               rcu_read_unlock();
+                               return d;
+                       }
+               }
+       }
+fail:
+       rcu_read_unlock();
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(pnfs_find_get_deviceid);
+
+/*
+ * Add a deviceid to the cache.
+ * GETDEVICEINFOs for same deviceid can race. If deviceid is found, discard new
+ */
+struct pnfs_deviceid_node *
+pnfs_add_deviceid(struct pnfs_deviceid_cache *c, struct pnfs_deviceid_node *new)
+{
+       struct pnfs_deviceid_node *d;
+       long hash = nfs4_deviceid_hash(&new->de_id);
+
+       dprintk("--> %s hash %ld\n", __func__, hash);
+       spin_lock(&c->dc_lock);
+       d = pnfs_find_get_deviceid(c, &new->de_id);
+       if (d) {
+               spin_unlock(&c->dc_lock);
+               dprintk("%s [discard]\n", __func__);
+               c->dc_free_callback(new);
+               return d;
+       }
+       INIT_HLIST_NODE(&new->de_node);
+       atomic_set(&new->de_ref, 1);
+       hlist_add_head_rcu(&new->de_node, &c->dc_deviceids[hash]);
+       spin_unlock(&c->dc_lock);
+       dprintk("%s [new]\n", __func__);
+       return new;
+}
+EXPORT_SYMBOL_GPL(pnfs_add_deviceid);
+
+void
+pnfs_put_deviceid_cache(struct nfs_client *clp)
+{
+       struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
+
+       dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache);
+       if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
+               int i;
+               /* Verify cache is empty */
+               for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++)
+                       BUG_ON(!hlist_empty(&local->dc_deviceids[i]));
+               clp->cl_devid_cache = NULL;
+               spin_unlock(&clp->cl_lock);
+               kfree(local);
+       }
+}
+EXPORT_SYMBOL_GPL(pnfs_put_deviceid_cache);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
new file mode 100644 (file)
index 0000000..e12367d
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  pNFS client data structures.
+ *
+ *  Copyright (c) 2002
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#ifndef FS_NFS_PNFS_H
+#define FS_NFS_PNFS_H
+
+struct pnfs_layout_segment {
+       struct list_head fi_list;
+       struct pnfs_layout_range range;
+       struct kref kref;
+       struct pnfs_layout_hdr *layout;
+};
+
+#ifdef CONFIG_NFS_V4_1
+
+#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
+
+enum {
+       NFS_LAYOUT_RO_FAILED = 0,       /* get ro layout failed stop trying */
+       NFS_LAYOUT_RW_FAILED,           /* get rw layout failed stop trying */
+       NFS_LAYOUT_STATEID_SET,         /* have a valid layout stateid */
+};
+
+/* Per-layout driver specific registration structure */
+struct pnfs_layoutdriver_type {
+       struct list_head pnfs_tblid;
+       const u32 id;
+       const char *name;
+       struct module *owner;
+       int (*set_layoutdriver) (struct nfs_server *);
+       int (*clear_layoutdriver) (struct nfs_server *);
+       struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr);
+       void (*free_lseg) (struct pnfs_layout_segment *lseg);
+};
+
+struct pnfs_layout_hdr {
+       unsigned long           refcount;
+       struct list_head        layouts;   /* other client layouts */
+       struct list_head        segs;      /* layout segments list */
+       seqlock_t               seqlock;   /* Protects the stateid */
+       nfs4_stateid            stateid;
+       unsigned long           state;
+       struct inode            *inode;
+};
+
+struct pnfs_device {
+       struct nfs4_deviceid dev_id;
+       unsigned int  layout_type;
+       unsigned int  mincount;
+       struct page **pages;
+       void          *area;
+       unsigned int  pgbase;
+       unsigned int  pglen;
+};
+
+/*
+ * Device ID RCU cache. A device ID is unique per client ID and layout type.
+ */
+#define NFS4_DEVICE_ID_HASH_BITS       5
+#define NFS4_DEVICE_ID_HASH_SIZE       (1 << NFS4_DEVICE_ID_HASH_BITS)
+#define NFS4_DEVICE_ID_HASH_MASK       (NFS4_DEVICE_ID_HASH_SIZE - 1)
+
+static inline u32
+nfs4_deviceid_hash(struct nfs4_deviceid *id)
+{
+       unsigned char *cptr = (unsigned char *)id->data;
+       unsigned int nbytes = NFS4_DEVICEID4_SIZE;
+       u32 x = 0;
+
+       while (nbytes--) {
+               x *= 37;
+               x += *cptr++;
+       }
+       return x & NFS4_DEVICE_ID_HASH_MASK;
+}
+
+struct pnfs_deviceid_node {
+       struct hlist_node       de_node;
+       struct nfs4_deviceid    de_id;
+       atomic_t                de_ref;
+};
+
+struct pnfs_deviceid_cache {
+       spinlock_t              dc_lock;
+       atomic_t                dc_ref;
+       void                    (*dc_free_callback)(struct pnfs_deviceid_node *);
+       struct hlist_head       dc_deviceids[NFS4_DEVICE_ID_HASH_SIZE];
+};
+
+extern int pnfs_alloc_init_deviceid_cache(struct nfs_client *,
+                       void (*free_callback)(struct pnfs_deviceid_node *));
+extern void pnfs_put_deviceid_cache(struct nfs_client *);
+extern struct pnfs_deviceid_node *pnfs_find_get_deviceid(
+                               struct pnfs_deviceid_cache *,
+                               struct nfs4_deviceid *);
+extern struct pnfs_deviceid_node *pnfs_add_deviceid(
+                               struct pnfs_deviceid_cache *,
+                               struct pnfs_deviceid_node *);
+extern void pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
+                             struct pnfs_deviceid_node *devid);
+
+extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
+extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
+
+/* nfs4proc.c */
+extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
+                                  struct pnfs_device *dev);
+extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
+
+/* pnfs.c */
+struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
+                  enum pnfs_iomode access_type);
+void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
+void unset_pnfs_layoutdriver(struct nfs_server *);
+int pnfs_layout_process(struct nfs4_layoutget *lgp);
+void pnfs_destroy_layout(struct nfs_inode *);
+void pnfs_destroy_all_layouts(struct nfs_client *);
+void put_layout_hdr(struct inode *inode);
+void pnfs_get_layout_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
+                            struct nfs4_state *open_state);
+
+
+static inline int lo_fail_bit(u32 iomode)
+{
+       return iomode == IOMODE_RW ?
+                        NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
+}
+
+/* Return true if a layout driver is being used for this mountpoint */
+static inline int pnfs_enabled_sb(struct nfs_server *nfss)
+{
+       return nfss->pnfs_curr_ld != NULL;
+}
+
+#else  /* CONFIG_NFS_V4_1 */
+
+static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
+{
+}
+
+static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
+{
+}
+
+static inline struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
+                  enum pnfs_iomode access_type)
+{
+       return NULL;
+}
+
+static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id)
+{
+}
+
+static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
+{
+}
+
+#endif /* CONFIG_NFS_V4_1 */
+
+#endif /* FS_NFS_PNFS_H */
index 611bec22f552e62b9ab0c63bf660e2e773fe81b0..58e7f84fc1fd0128bf0f5fe60db17961bbf20d11 100644 (file)
@@ -258,7 +258,7 @@ static void nfs_free_createdata(const struct nfs_createdata *data)
 
 static int
 nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-               int flags, struct nameidata *nd)
+               int flags, struct nfs_open_context *ctx)
 {
        struct nfs_createdata *data;
        struct rpc_message msg = {
@@ -365,17 +365,32 @@ static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        return 1;
 }
 
+static void
+nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+       msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
+}
+
+static int
+nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+                    struct inode *new_dir)
+{
+       if (nfs_async_handle_expired_key(task))
+               return 0;
+       nfs_mark_for_revalidate(old_dir);
+       nfs_mark_for_revalidate(new_dir);
+       return 1;
+}
+
 static int
 nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
                struct inode *new_dir, struct qstr *new_name)
 {
        struct nfs_renameargs   arg = {
-               .fromfh         = NFS_FH(old_dir),
-               .fromname       = old_name->name,
-               .fromlen        = old_name->len,
-               .tofh           = NFS_FH(new_dir),
-               .toname         = new_name->name,
-               .tolen          = new_name->len
+               .old_dir        = NFS_FH(old_dir),
+               .old_name       = old_name,
+               .new_dir        = NFS_FH(new_dir),
+               .new_name       = new_name,
        };
        struct rpc_message msg = {
                .rpc_proc       = &nfs_procedures[NFSPROC_RENAME],
@@ -519,14 +534,14 @@ nfs_proc_rmdir(struct inode *dir, struct qstr *name)
  */
 static int
 nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                u64 cookie, struct page *page, unsigned int count, int plus)
+                u64 cookie, struct page **pages, unsigned int count, int plus)
 {
        struct inode            *dir = dentry->d_inode;
        struct nfs_readdirargs  arg = {
                .fh             = NFS_FH(dir),
                .cookie         = cookie,
                .count          = count,
-               .pages          = &page,
+               .pages          = pages,
        };
        struct rpc_message      msg = {
                .rpc_proc       = &nfs_procedures[NFSPROC_READDIR],
@@ -705,6 +720,8 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .unlink_setup   = nfs_proc_unlink_setup,
        .unlink_done    = nfs_proc_unlink_done,
        .rename         = nfs_proc_rename,
+       .rename_setup   = nfs_proc_rename_setup,
+       .rename_done    = nfs_proc_rename_done,
        .link           = nfs_proc_link,
        .symlink        = nfs_proc_symlink,
        .mkdir          = nfs_proc_mkdir,
index 87adc2744246a59aafe6339f16599517c6e3c03b..e4b62c6f5a6e9eb721eda53d836c41055ab2e1b7 100644 (file)
@@ -25,6 +25,7 @@
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
@@ -46,7 +47,6 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
                p->npages = pagecount;
-               p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
                if (pagecount <= ARRAY_SIZE(p->page_array))
                        p->pagevec = p->page_array;
                else {
@@ -121,6 +121,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        len = nfs_page_length(page);
        if (len == 0)
                return nfs_return_empty_page(page);
+       pnfs_update_layout(inode, ctx, IOMODE_READ);
        new = nfs_create_request(ctx, inode, page, 0, len);
        if (IS_ERR(new)) {
                unlock_page(page);
@@ -625,6 +626,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
+       pnfs_update_layout(inode, desc.ctx, IOMODE_READ);
        if (rsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
        else
index f4cbf0c306c64d6583cbfffaa14cfbc7a467dfaa..3600ec700d583356d7e765db1c3a7035d3b2355c 100644 (file)
@@ -100,6 +100,7 @@ enum {
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
        Opt_lookupcache,
        Opt_fscache_uniq,
+       Opt_local_lock,
 
        /* Special mount options */
        Opt_userspace, Opt_deprecated, Opt_sloppy,
@@ -171,6 +172,7 @@ static const match_table_t nfs_mount_option_tokens = {
 
        { Opt_lookupcache, "lookupcache=%s" },
        { Opt_fscache_uniq, "fsc=%s" },
+       { Opt_local_lock, "local_lock=%s" },
 
        { Opt_err, NULL }
 };
@@ -236,6 +238,22 @@ static match_table_t nfs_lookupcache_tokens = {
        { Opt_lookupcache_err, NULL }
 };
 
+enum {
+       Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
+       Opt_local_lock_none,
+
+       Opt_local_lock_err
+};
+
+static match_table_t nfs_local_lock_tokens = {
+       { Opt_local_lock_all, "all" },
+       { Opt_local_lock_flock, "flock" },
+       { Opt_local_lock_posix, "posix" },
+       { Opt_local_lock_none, "none" },
+
+       { Opt_local_lock_err, NULL }
+};
+
 
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct dentry *, struct kstatfs *);
@@ -622,6 +640,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        const struct proc_nfs_info *nfs_infop;
        struct nfs_client *clp = nfss->nfs_client;
        u32 version = clp->rpc_ops->version;
+       int local_flock, local_fcntl;
 
        seq_printf(m, ",vers=%u", version);
        seq_printf(m, ",rsize=%u", nfss->rsize);
@@ -670,6 +689,18 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                else
                        seq_printf(m, ",lookupcache=pos");
        }
+
+       local_flock = nfss->flags & NFS_MOUNT_LOCAL_FLOCK;
+       local_fcntl = nfss->flags & NFS_MOUNT_LOCAL_FCNTL;
+
+       if (!local_flock && !local_fcntl)
+               seq_printf(m, ",local_lock=none");
+       else if (local_flock && local_fcntl)
+               seq_printf(m, ",local_lock=all");
+       else if (local_flock)
+               seq_printf(m, ",local_lock=flock");
+       else
+               seq_printf(m, ",local_lock=posix");
 }
 
 /*
@@ -1017,9 +1048,13 @@ static int nfs_parse_mount_options(char *raw,
                        break;
                case Opt_lock:
                        mnt->flags &= ~NFS_MOUNT_NONLM;
+                       mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+                                       NFS_MOUNT_LOCAL_FCNTL);
                        break;
                case Opt_nolock:
                        mnt->flags |= NFS_MOUNT_NONLM;
+                       mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+                                      NFS_MOUNT_LOCAL_FCNTL);
                        break;
                case Opt_v2:
                        mnt->flags &= ~NFS_MOUNT_VER3;
@@ -1420,6 +1455,34 @@ static int nfs_parse_mount_options(char *raw,
                        mnt->fscache_uniq = string;
                        mnt->options |= NFS_OPTION_FSCACHE;
                        break;
+               case Opt_local_lock:
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       token = match_token(string, nfs_local_lock_tokens,
+                                       args);
+                       kfree(string);
+                       switch (token) {
+                       case Opt_local_lock_all:
+                               mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+                                              NFS_MOUNT_LOCAL_FCNTL);
+                               break;
+                       case Opt_local_lock_flock:
+                               mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+                               break;
+                       case Opt_local_lock_posix:
+                               mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+                               break;
+                       case Opt_local_lock_none:
+                               mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+                                               NFS_MOUNT_LOCAL_FCNTL);
+                               break;
+                       default:
+                               dfprintk(MOUNT, "NFS:   invalid "
+                                               "local_lock argument\n");
+                               return 0;
+                       };
+                       break;
 
                /*
                 * Special options
@@ -1825,6 +1888,12 @@ static int nfs_validate_mount_data(void *options,
                if (!args->nfs_server.hostname)
                        goto out_nomem;
 
+               if (!(data->flags & NFS_MOUNT_NONLM))
+                       args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+                                        NFS_MOUNT_LOCAL_FCNTL);
+               else
+                       args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+                                       NFS_MOUNT_LOCAL_FCNTL);
                /*
                 * The legacy version 6 binary mount data from userspace has a
                 * field used only to transport selinux information into the
@@ -2441,7 +2510,8 @@ static void nfs4_fill_super(struct super_block *sb)
 
 static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
 {
-       args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
+       args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+                        NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
 }
 
 static int nfs4_validate_text_mount_data(void *options,
index ad4d2e787b2041d17eaacc4a1ce8097f0cc13aca..978aaeb8a0936617ed19cde6c5995e247b77af4c 100644 (file)
@@ -32,6 +32,7 @@ static ctl_table nfs_cb_sysctls[] = {
                .extra1 = (int *)&nfs_set_port_min,
                .extra2 = (int *)&nfs_set_port_max,
        },
+#ifndef CONFIG_NFS_USE_NEW_IDMAPPER
        {
                .procname = "idmap_cache_timeout",
                .data = &nfs_idmap_cache_timeout,
@@ -39,6 +40,7 @@ static ctl_table nfs_cb_sysctls[] = {
                .mode = 0644,
                .proc_handler = proc_dointvec_jiffies,
        },
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 #endif
        {
                .procname       = "nfs_mountpoint_timeout",
index 2f84adaad42784a8a07e6130884a827f3466134d..9a16bad5d2eaf4dad7d99e8b89d83576a3f163a1 100644 (file)
 #include <linux/nfs_fs.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/namei.h>
 
 #include "internal.h"
 #include "nfs4_fs.h"
+#include "iostat.h"
+#include "delegation.h"
 
 struct nfs_unlinkdata {
        struct hlist_node list;
@@ -244,7 +247,7 @@ void nfs_unblock_sillyrename(struct dentry *dentry)
  * @dir: parent directory of dentry
  * @dentry: dentry to unlink
  */
-int
+static int
 nfs_async_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct nfs_unlinkdata *data;
@@ -259,7 +262,6 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
                status = PTR_ERR(data->cred);
                goto out_free;
        }
-       data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        data->res.dir_attr = &data->dir_attr;
 
        status = -EBUSY;
@@ -303,3 +305,256 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
        if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
                nfs_free_unlinkdata(data);
 }
+
+/* Cancel a queued async unlink. Called when a sillyrename run fails. */
+static void
+nfs_cancel_async_unlink(struct dentry *dentry)
+{
+       spin_lock(&dentry->d_lock);
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+               struct nfs_unlinkdata *data = dentry->d_fsdata;
+
+               dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+               spin_unlock(&dentry->d_lock);
+               nfs_free_unlinkdata(data);
+               return;
+       }
+       spin_unlock(&dentry->d_lock);
+}
+
+struct nfs_renamedata {
+       struct nfs_renameargs   args;
+       struct nfs_renameres    res;
+       struct rpc_cred         *cred;
+       struct inode            *old_dir;
+       struct dentry           *old_dentry;
+       struct nfs_fattr        old_fattr;
+       struct inode            *new_dir;
+       struct dentry           *new_dentry;
+       struct nfs_fattr        new_fattr;
+};
+
+/**
+ * nfs_async_rename_done - Sillyrename post-processing
+ * @task: rpc_task of the sillyrename
+ * @calldata: nfs_renamedata for the sillyrename
+ *
+ * Do the directory attribute updates and the d_move
+ */
+static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs_renamedata *data = calldata;
+       struct inode *old_dir = data->old_dir;
+       struct inode *new_dir = data->new_dir;
+
+       if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
+               nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client);
+               return;
+       }
+
+       if (task->tk_status != 0) {
+               nfs_cancel_async_unlink(data->old_dentry);
+               return;
+       }
+
+       nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir));
+       d_move(data->old_dentry, data->new_dentry);
+}
+
+/**
+ * nfs_async_rename_release - Release the sillyrename data.
+ * @calldata: the struct nfs_renamedata to be released
+ */
+static void nfs_async_rename_release(void *calldata)
+{
+       struct nfs_renamedata   *data = calldata;
+       struct super_block *sb = data->old_dir->i_sb;
+
+       if (data->old_dentry->d_inode)
+               nfs_mark_for_revalidate(data->old_dentry->d_inode);
+
+       dput(data->old_dentry);
+       dput(data->new_dentry);
+       iput(data->old_dir);
+       iput(data->new_dir);
+       nfs_sb_deactive(sb);
+       put_rpccred(data->cred);
+       kfree(data);
+}
+
+#if defined(CONFIG_NFS_V4_1)
+static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs_renamedata *data = calldata;
+       struct nfs_server *server = NFS_SERVER(data->old_dir);
+
+       if (nfs4_setup_sequence(server, &data->args.seq_args,
+                               &data->res.seq_res, 1, task))
+               return;
+       rpc_call_start(task);
+}
+#endif /* CONFIG_NFS_V4_1 */
+
+static const struct rpc_call_ops nfs_rename_ops = {
+       .rpc_call_done = nfs_async_rename_done,
+       .rpc_release = nfs_async_rename_release,
+#if defined(CONFIG_NFS_V4_1)
+       .rpc_call_prepare = nfs_rename_prepare,
+#endif /* CONFIG_NFS_V4_1 */
+};
+
+/**
+ * nfs_async_rename - perform an asynchronous rename operation
+ * @old_dir: directory that currently holds the dentry to be renamed
+ * @new_dir: target directory for the rename
+ * @old_dentry: original dentry to be renamed
+ * @new_dentry: dentry to which the old_dentry should be renamed
+ *
+ * It's expected that valid references to the dentries and inodes are held
+ */
+static struct rpc_task *
+nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
+                struct dentry *old_dentry, struct dentry *new_dentry)
+{
+       struct nfs_renamedata *data;
+       struct rpc_message msg = { };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_message = &msg,
+               .callback_ops = &nfs_rename_ops,
+               .workqueue = nfsiod_workqueue,
+               .rpc_client = NFS_CLIENT(old_dir),
+               .flags = RPC_TASK_ASYNC,
+       };
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return ERR_PTR(-ENOMEM);
+       task_setup_data.callback_data = data,
+
+       data->cred = rpc_lookup_cred();
+       if (IS_ERR(data->cred)) {
+               struct rpc_task *task = ERR_CAST(data->cred);
+               kfree(data);
+               return task;
+       }
+
+       msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
+       msg.rpc_cred = data->cred;
+
+       /* set up nfs_renamedata */
+       data->old_dir = old_dir;
+       atomic_inc(&old_dir->i_count);
+       data->new_dir = new_dir;
+       atomic_inc(&new_dir->i_count);
+       data->old_dentry = dget(old_dentry);
+       data->new_dentry = dget(new_dentry);
+       nfs_fattr_init(&data->old_fattr);
+       nfs_fattr_init(&data->new_fattr);
+
+       /* set up nfs_renameargs */
+       data->args.old_dir = NFS_FH(old_dir);
+       data->args.old_name = &old_dentry->d_name;
+       data->args.new_dir = NFS_FH(new_dir);
+       data->args.new_name = &new_dentry->d_name;
+
+       /* set up nfs_renameres */
+       data->res.old_fattr = &data->old_fattr;
+       data->res.new_fattr = &data->new_fattr;
+
+       nfs_sb_active(old_dir->i_sb);
+
+       NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dir);
+
+       return rpc_run_task(&task_setup_data);
+}
+
+/**
+ * nfs_sillyrename - Perform a silly-rename of a dentry
+ * @dir: inode of directory that contains dentry
+ * @dentry: dentry to be sillyrenamed
+ *
+ * NFSv2/3 is stateless and the server doesn't know when the client is
+ * holding a file open. To prevent application problems when a file is
+ * unlinked while it's still open, the client performs a "silly-rename".
+ * That is, it renames the file to a hidden file in the same directory,
+ * and only performs the unlink once the last reference to it is put.
+ *
+ * The final cleanup is done during dentry_iput.
+ */
+int
+nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+{
+       static unsigned int sillycounter;
+       const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
+       const int      countersize = sizeof(sillycounter)*2;
+       const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
+       char           silly[slen+1];
+       struct dentry *sdentry;
+       struct rpc_task *task;
+       int            error = -EIO;
+
+       dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
+               dentry->d_parent->d_name.name, dentry->d_name.name,
+               atomic_read(&dentry->d_count));
+       nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
+
+       /*
+        * We don't allow a dentry to be silly-renamed twice.
+        */
+       error = -EBUSY;
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+               goto out;
+
+       sprintf(silly, ".nfs%*.*Lx",
+               fileidsize, fileidsize,
+               (unsigned long long)NFS_FILEID(dentry->d_inode));
+
+       /* Return delegation in anticipation of the rename */
+       nfs_inode_return_delegation(dentry->d_inode);
+
+       sdentry = NULL;
+       do {
+               char *suffix = silly + slen - countersize;
+
+               dput(sdentry);
+               sillycounter++;
+               sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
+
+               dfprintk(VFS, "NFS: trying to rename %s to %s\n",
+                               dentry->d_name.name, silly);
+
+               sdentry = lookup_one_len(silly, dentry->d_parent, slen);
+               /*
+                * N.B. Better to return EBUSY here ... it could be
+                * dangerous to delete the file while it's in use.
+                */
+               if (IS_ERR(sdentry))
+                       goto out;
+       } while (sdentry->d_inode != NULL); /* need negative lookup */
+
+       /* queue unlink first. Can't do this from rpc_release as it
+        * has to allocate memory
+        */
+       error = nfs_async_unlink(dir, dentry);
+       if (error)
+               goto out_dput;
+
+       /* run the rename task, undo unlink if it fails */
+       task = nfs_async_rename(dir, dir, dentry, sdentry);
+       if (IS_ERR(task)) {
+               error = -EBUSY;
+               nfs_cancel_async_unlink(dentry);
+               goto out_dput;
+       }
+
+       /* wait for the RPC task to complete, unless a SIGKILL intervenes */
+       error = rpc_wait_for_completion_task(task);
+       if (error == 0)
+               error = task->tk_status;
+       rpc_put_task(task);
+out_dput:
+       dput(sdentry);
+out:
+       return error;
+}
index 874972d9427c15d94e7ee7c9182fd5f4a3eb5968..4c14c17a5276a410bb383e3650f106ab56cf47d6 100644 (file)
@@ -55,7 +55,6 @@ struct nfs_write_data *nfs_commitdata_alloc(void)
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
-               p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        }
        return p;
 }
@@ -75,7 +74,6 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
                p->npages = pagecount;
-               p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
                if (pagecount <= ARRAY_SIZE(p->page_array))
                        p->pagevec = p->page_array;
                else {
@@ -292,9 +290,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, st
        nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
        nfs_pageio_cond_complete(pgio, page->index);
-       ret = nfs_page_async_flush(pgio, page,
-                       wbc->sync_mode == WB_SYNC_NONE ||
-                       wbc->nonblocking != 0);
+       ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
        if (ret == -EAGAIN) {
                redirty_page_for_writepage(wbc, page);
                ret = 0;
@@ -1433,15 +1429,17 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
        int flags = FLUSH_SYNC;
        int ret = 0;
 
-       /* Don't commit yet if this is a non-blocking flush and there are
-        * lots of outstanding writes for this mapping.
-        */
-       if (wbc->sync_mode == WB_SYNC_NONE &&
-           nfsi->ncommit <= (nfsi->npages >> 1))
-               goto out_mark_dirty;
+       if (wbc->sync_mode == WB_SYNC_NONE) {
+               /* Don't commit yet if this is a non-blocking flush and there
+                * are a lot of outstanding writes for this mapping.
+                */
+               if (nfsi->ncommit <= (nfsi->npages >> 1))
+                       goto out_mark_dirty;
 
-       if (wbc->nonblocking || wbc->for_background)
+               /* don't wait for the COMMIT response */
                flags = 0;
+       }
+
        ret = nfs_commit_inode(inode, flags);
        if (ret >= 0) {
                if (wbc->sync_mode == WB_SYNC_NONE) {
index 7cf4ddafb4abc3b0ae4f511bb0d264eab0f563d4..18b3e8975fe05c2364dd507d50b364b4c13b0dfd 100644 (file)
@@ -2,7 +2,6 @@ config NFSD
        tristate "NFS server support"
        depends on INET
        depends on FILE_LOCKING
-       depends on BKL # fix as soon as lockd is done
        select LOCKD
        select SUNRPC
        select EXPORTFS
@@ -29,6 +28,18 @@ config NFSD
 
          If unsure, say N.
 
+config NFSD_DEPRECATED
+       bool "Include support for deprecated syscall interface to NFSD"
+       depends on NFSD
+       default y
+       help
+         The syscall interface to nfsd was obsoleted in 2.6.0 by a new
+         filesystem based interface.  The old interface is due for removal
+         in 2.6.40.  If you wish to remove the interface before then
+         say N.
+
+         In unsure, say Y.
+
 config NFSD_V2_ACL
        bool
        depends on NFSD
index c2a4f71d87dd507a99d20564cff85ff15bd91646..c0fcb7ab7f6db42b9793dd2b59f853f92728db35 100644 (file)
@@ -28,9 +28,6 @@
 typedef struct auth_domain     svc_client;
 typedef struct svc_export      svc_export;
 
-static void            exp_do_unexport(svc_export *unexp);
-static int             exp_verify_string(char *cp, int max);
-
 /*
  * We have two caches.
  * One maps client+vfsmnt+dentry to export options - the export map
@@ -802,6 +799,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
        return ek;
 }
 
+#ifdef CONFIG_NFSD_DEPRECATED
 static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
                       struct svc_export *exp)
 {
@@ -852,6 +850,7 @@ exp_get_fsid_key(svc_client *clp, int fsid)
 
        return exp_find_key(clp, FSID_NUM, fsidv, NULL);
 }
+#endif
 
 static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
                                     struct cache_req *reqp)
@@ -893,6 +892,7 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path)
        return exp;
 }
 
+#ifdef CONFIG_NFSD_DEPRECATED
 /*
  * Hashtable locking. Write locks are placed only by user processes
  * wanting to modify export information.
@@ -925,6 +925,19 @@ exp_writeunlock(void)
 {
        up_write(&hash_sem);
 }
+#else
+
+/* hash_sem not needed once deprecated interface is removed */
+void exp_readlock(void) {}
+static inline void exp_writelock(void){}
+void exp_readunlock(void) {}
+static inline void exp_writeunlock(void){}
+
+#endif
+
+#ifdef CONFIG_NFSD_DEPRECATED
+static void            exp_do_unexport(svc_export *unexp);
+static int             exp_verify_string(char *cp, int max);
 
 static void exp_fsid_unhash(struct svc_export *exp)
 {
@@ -935,10 +948,9 @@ static void exp_fsid_unhash(struct svc_export *exp)
 
        ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
        if (!IS_ERR(ek)) {
-               ek->h.expiry_time = get_seconds()-1;
+               sunrpc_invalidate(&ek->h, &svc_expkey_cache);
                cache_put(&ek->h, &svc_expkey_cache);
        }
-       svc_expkey_cache.nextcheck = get_seconds();
 }
 
 static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
@@ -973,10 +985,9 @@ static void exp_unhash(struct svc_export *exp)
 
        ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
        if (!IS_ERR(ek)) {
-               ek->h.expiry_time = get_seconds()-1;
+               sunrpc_invalidate(&ek->h, &svc_expkey_cache);
                cache_put(&ek->h, &svc_expkey_cache);
        }
-       svc_expkey_cache.nextcheck = get_seconds();
 }
        
 /*
@@ -1097,8 +1108,7 @@ out:
 static void
 exp_do_unexport(svc_export *unexp)
 {
-       unexp->h.expiry_time = get_seconds()-1;
-       svc_export_cache.nextcheck = get_seconds();
+       sunrpc_invalidate(&unexp->h, &svc_export_cache);
        exp_unhash(unexp);
        exp_fsid_unhash(unexp);
 }
@@ -1150,6 +1160,7 @@ out_unlock:
        exp_writeunlock();
        return err;
 }
+#endif /* CONFIG_NFSD_DEPRECATED */
 
 /*
  * Obtain the root fh on behalf of a client.
@@ -1459,25 +1470,43 @@ static void show_secinfo_flags(struct seq_file *m, int flags)
        show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
 }
 
+static bool secinfo_flags_equal(int f, int g)
+{
+       f &= NFSEXP_SECINFO_FLAGS;
+       g &= NFSEXP_SECINFO_FLAGS;
+       return f == g;
+}
+
+static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
+{
+       int flags;
+
+       flags = (*fp)->flags;
+       seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
+       (*fp)++;
+       while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
+               seq_printf(m, ":%d", (*fp)->pseudoflavor);
+               (*fp)++;
+       }
+       return flags;
+}
+
 static void show_secinfo(struct seq_file *m, struct svc_export *exp)
 {
        struct exp_flavor_info *f;
        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
-       int lastflags = 0, first = 0;
+       int flags;
 
        if (exp->ex_nflavors == 0)
                return;
-       for (f = exp->ex_flavors; f < end; f++) {
-               if (first || f->flags != lastflags) {
-                       if (!first)
-                               show_secinfo_flags(m, lastflags);
-                       seq_printf(m, ",sec=%d", f->pseudoflavor);
-                       lastflags = f->flags;
-               } else {
-                       seq_printf(m, ":%d", f->pseudoflavor);
-               }
+       f = exp->ex_flavors;
+       flags = show_secinfo_run(m, &f, end);
+       if (!secinfo_flags_equal(flags, exp->ex_flags))
+               show_secinfo_flags(m, flags);
+       while (f != end) {
+               flags = show_secinfo_run(m, &f, end);
+               show_secinfo_flags(m, flags);
        }
-       show_secinfo_flags(m, lastflags);
 }
 
 static void exp_flags(struct seq_file *m, int flag, int fsid,
@@ -1532,6 +1561,7 @@ const struct seq_operations nfs_exports_op = {
        .show   = e_show,
 };
 
+#ifdef CONFIG_NFSD_DEPRECATED
 /*
  * Add or modify a client.
  * Change requests may involve the list of host addresses. The list of
@@ -1563,7 +1593,7 @@ exp_addclient(struct nfsctl_client *ncp)
        /* Insert client into hashtable. */
        for (i = 0; i < ncp->cl_naddr; i++) {
                ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
-               auth_unix_add_addr(&addr6, dom);
+               auth_unix_add_addr(&init_net, &addr6, dom);
        }
        auth_unix_forget_old(dom);
        auth_domain_put(dom);
@@ -1621,6 +1651,7 @@ exp_verify_string(char *cp, int max)
        printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
        return 0;
 }
+#endif /* CONFIG_NFSD_DEPRECATED */
 
 /*
  * Initialize the exports module.
index 988cbb3a19b6785378a5dcaab1118e4b3d78b14b..143da2eecd7b73a1d3181627c9b03e4c16f3e0c1 100644 (file)
@@ -41,7 +41,6 @@
 
 #define NFSPROC4_CB_NULL 0
 #define NFSPROC4_CB_COMPOUND 1
-#define NFS4_STATEID_SIZE 16
 
 /* Index of predefined Linux callback client operations */
 
@@ -248,10 +247,11 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
 }
 
 static void
-encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args,
+encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb,
                   struct nfs4_cb_compound_hdr *hdr)
 {
        __be32 *p;
+       struct nfsd4_session *ses = cb->cb_clp->cl_cb_session;
 
        if (hdr->minorversion == 0)
                return;
@@ -259,8 +259,8 @@ encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args,
        RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20);
 
        WRITE32(OP_CB_SEQUENCE);
-       WRITEMEM(args->cbs_clp->cl_sessionid.data, NFS4_MAX_SESSIONID_LEN);
-       WRITE32(args->cbs_clp->cl_cb_seq_nr);
+       WRITEMEM(ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN);
+       WRITE32(ses->se_cb_seq_nr);
        WRITE32(0);             /* slotid, always 0 */
        WRITE32(0);             /* highest slotid always 0 */
        WRITE32(0);             /* cachethis always 0 */
@@ -280,18 +280,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
 
 static int
 nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
-               struct nfs4_rpc_args *rpc_args)
+               struct nfsd4_callback *cb)
 {
        struct xdr_stream xdr;
-       struct nfs4_delegation *args = rpc_args->args_op;
+       struct nfs4_delegation *args = cb->cb_op;
        struct nfs4_cb_compound_hdr hdr = {
-               .ident = args->dl_ident,
-               .minorversion = rpc_args->args_seq.cbs_minorversion,
+               .ident = cb->cb_clp->cl_cb_ident,
+               .minorversion = cb->cb_minorversion,
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
        encode_cb_compound_hdr(&xdr, &hdr);
-       encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr);
+       encode_cb_sequence(&xdr, cb, &hdr);
        encode_cb_recall(&xdr, args, &hdr);
        encode_cb_nops(&hdr);
        return 0;
@@ -339,15 +339,16 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
  * with a single slot.
  */
 static int
-decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res,
+decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb,
                   struct rpc_rqst *rqstp)
 {
+       struct nfsd4_session *ses = cb->cb_clp->cl_cb_session;
        struct nfs4_sessionid id;
        int status;
        u32 dummy;
        __be32 *p;
 
-       if (res->cbs_minorversion == 0)
+       if (cb->cb_minorversion == 0)
                return 0;
 
        status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE);
@@ -363,13 +364,12 @@ decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res,
        READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
        memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
        p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
-       if (memcmp(id.data, res->cbs_clp->cl_sessionid.data,
-                  NFS4_MAX_SESSIONID_LEN)) {
+       if (memcmp(id.data, ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN)) {
                dprintk("%s Invalid session id\n", __func__);
                goto out;
        }
        READ32(dummy);
-       if (dummy != res->cbs_clp->cl_cb_seq_nr) {
+       if (dummy != ses->se_cb_seq_nr) {
                dprintk("%s Invalid sequence number\n", __func__);
                goto out;
        }
@@ -393,7 +393,7 @@ nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
 
 static int
 nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
-               struct nfsd4_cb_sequence *seq)
+               struct nfsd4_callback *cb)
 {
        struct xdr_stream xdr;
        struct nfs4_cb_compound_hdr hdr;
@@ -403,8 +403,8 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
        status = decode_cb_compound_hdr(&xdr, &hdr);
        if (status)
                goto out;
-       if (seq) {
-               status = decode_cb_sequence(&xdr, seq, rqstp);
+       if (cb) {
+               status = decode_cb_sequence(&xdr, cb, rqstp);
                if (status)
                        goto out;
        }
@@ -473,30 +473,34 @@ static int max_cb_time(void)
 /* Reference counting, callback cleanup, etc., all look racy as heck.
  * And why is cl_cb_set an atomic? */
 
-int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
+int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
 {
        struct rpc_timeout      timeparms = {
                .to_initval     = max_cb_time(),
                .to_retries     = 0,
        };
        struct rpc_create_args args = {
-               .protocol       = XPRT_TRANSPORT_TCP,
-               .address        = (struct sockaddr *) &cb->cb_addr,
-               .addrsize       = cb->cb_addrlen,
+               .net            = &init_net,
+               .address        = (struct sockaddr *) &conn->cb_addr,
+               .addrsize       = conn->cb_addrlen,
                .timeout        = &timeparms,
                .program        = &cb_program,
-               .prognumber     = cb->cb_prog,
                .version        = 0,
                .authflavor     = clp->cl_flavor,
                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
-               .client_name    = clp->cl_principal,
        };
        struct rpc_clnt *client;
 
-       if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
-               return -EINVAL;
-       if (cb->cb_minorversion) {
-               args.bc_xprt = cb->cb_xprt;
+       if (clp->cl_minorversion == 0) {
+               if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
+                       return -EINVAL;
+               args.client_name = clp->cl_principal;
+               args.prognumber = conn->cb_prog,
+               args.protocol = XPRT_TRANSPORT_TCP;
+               clp->cl_cb_ident = conn->cb_ident;
+       } else {
+               args.bc_xprt = conn->cb_xprt;
+               args.prognumber = clp->cl_cb_session->se_cb_prog;
                args.protocol = XPRT_TRANSPORT_BC_TCP;
        }
        /* Create RPC client */
@@ -506,7 +510,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
                        PTR_ERR(client));
                return PTR_ERR(client);
        }
-       nfsd4_set_callback_client(clp, client);
+       clp->cl_cb_client = client;
        return 0;
 
 }
@@ -519,7 +523,7 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
 
 static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs4_client *clp = calldata;
+       struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
 
        if (task->tk_status)
                warn_no_callback_path(clp, task->tk_status);
@@ -528,6 +532,8 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
 }
 
 static const struct rpc_call_ops nfsd4_cb_probe_ops = {
+       /* XXX: release method to ensure we set the cb channel down if
+        * necessary on early failure? */
        .rpc_call_done = nfsd4_cb_probe_done,
 };
 
@@ -543,38 +549,42 @@ int set_callback_cred(void)
        return 0;
 }
 
+static struct workqueue_struct *callback_wq;
 
-void do_probe_callback(struct nfs4_client *clp)
+static void do_probe_callback(struct nfs4_client *clp)
 {
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
-               .rpc_argp       = clp,
-               .rpc_cred       = callback_cred
-       };
-       int status;
+       struct nfsd4_callback *cb = &clp->cl_cb_null;
 
-       status = rpc_call_async(clp->cl_cb_client, &msg,
-                               RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
-                               &nfsd4_cb_probe_ops, (void *)clp);
-       if (status)
-               warn_no_callback_path(clp, status);
+       cb->cb_op = NULL;
+       cb->cb_clp = clp;
+
+       cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
+       cb->cb_msg.rpc_argp = NULL;
+       cb->cb_msg.rpc_resp = NULL;
+       cb->cb_msg.rpc_cred = callback_cred;
+
+       cb->cb_ops = &nfsd4_cb_probe_ops;
+
+       queue_work(callback_wq, &cb->cb_work);
 }
 
 /*
- * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
+ * Poke the callback thread to process any updates to the callback
+ * parameters, and send a null probe.
  */
-void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
+void nfsd4_probe_callback(struct nfs4_client *clp)
 {
-       int status;
+       set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+       do_probe_callback(clp);
+}
 
+void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+{
        BUG_ON(atomic_read(&clp->cl_cb_set));
 
-       status = setup_callback_client(clp, cb);
-       if (status) {
-               warn_no_callback_path(clp, status);
-               return;
-       }
-       do_probe_callback(clp);
+       spin_lock(&clp->cl_lock);
+       memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
+       spin_unlock(&clp->cl_lock);
 }
 
 /*
@@ -585,8 +595,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
 static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
                struct rpc_task *task)
 {
-       struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
-       u32 *ptr = (u32 *)clp->cl_sessionid.data;
+       u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
        int status = 0;
 
        dprintk("%s: %u:%u:%u:%u\n", __func__,
@@ -598,14 +607,6 @@ static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
                status = -EAGAIN;
                goto out;
        }
-
-       /*
-        * We'll need the clp during XDR encoding and decoding,
-        * and the sequence during decoding to verify the reply
-        */
-       args->args_seq.cbs_clp = clp;
-       task->tk_msg.rpc_resp = &args->args_seq;
-
 out:
        dprintk("%s status=%d\n", __func__, status);
        return status;
@@ -617,13 +618,13 @@ out:
  */
 static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
 {
-       struct nfs4_delegation *dp = calldata;
+       struct nfsd4_callback *cb = calldata;
+       struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
        struct nfs4_client *clp = dp->dl_client;
-       struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
-       u32 minorversion = clp->cl_cb_conn.cb_minorversion;
+       u32 minorversion = clp->cl_minorversion;
        int status = 0;
 
-       args->args_seq.cbs_minorversion = minorversion;
+       cb->cb_minorversion = minorversion;
        if (minorversion) {
                status = nfsd41_cb_setup_sequence(clp, task);
                if (status) {
@@ -640,19 +641,20 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
 
 static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs4_delegation *dp = calldata;
+       struct nfsd4_callback *cb = calldata;
+       struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
        struct nfs4_client *clp = dp->dl_client;
 
        dprintk("%s: minorversion=%d\n", __func__,
-               clp->cl_cb_conn.cb_minorversion);
+               clp->cl_minorversion);
 
-       if (clp->cl_cb_conn.cb_minorversion) {
+       if (clp->cl_minorversion) {
                /* No need for lock, access serialized in nfsd4_cb_prepare */
-               ++clp->cl_cb_seq_nr;
+               ++clp->cl_cb_session->se_cb_seq_nr;
                clear_bit(0, &clp->cl_cb_slot_busy);
                rpc_wake_up_next(&clp->cl_cb_waitq);
                dprintk("%s: freed slot, new seqid=%d\n", __func__,
-                       clp->cl_cb_seq_nr);
+                       clp->cl_cb_session->se_cb_seq_nr);
 
                /* We're done looking into the sequence information */
                task->tk_msg.rpc_resp = NULL;
@@ -662,7 +664,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
 
 static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs4_delegation *dp = calldata;
+       struct nfsd4_callback *cb = calldata;
+       struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
        struct nfs4_client *clp = dp->dl_client;
        struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
 
@@ -707,7 +710,8 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
 
 static void nfsd4_cb_recall_release(void *calldata)
 {
-       struct nfs4_delegation *dp = calldata;
+       struct nfsd4_callback *cb = calldata;
+       struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
 
        nfs4_put_delegation(dp);
 }
@@ -718,8 +722,6 @@ static const struct rpc_call_ops nfsd4_cb_recall_ops = {
        .rpc_release = nfsd4_cb_recall_release,
 };
 
-static struct workqueue_struct *callback_wq;
-
 int nfsd4_create_callback_queue(void)
 {
        callback_wq = create_singlethread_workqueue("nfsd4_callbacks");
@@ -734,57 +736,88 @@ void nfsd4_destroy_callback_queue(void)
 }
 
 /* must be called under the state lock */
-void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt *new)
+void nfsd4_shutdown_callback(struct nfs4_client *clp)
 {
-       struct rpc_clnt *old = clp->cl_cb_client;
-
-       clp->cl_cb_client = new;
+       set_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags);
        /*
-        * After this, any work that saw the old value of cl_cb_client will
-        * be gone:
+        * Note this won't actually result in a null callback;
+        * instead, nfsd4_do_callback_rpc() will detect the killed
+        * client, destroy the rpc client, and stop:
         */
+       do_probe_callback(clp);
        flush_workqueue(callback_wq);
-       /* So we can safely shut it down: */
-       if (old)
-               rpc_shutdown_client(old);
 }
 
-/*
- * called with dp->dl_count inc'ed.
- */
-static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
+void nfsd4_release_cb(struct nfsd4_callback *cb)
 {
-       struct nfs4_client *clp = dp->dl_client;
-       struct rpc_clnt *clnt = clp->cl_cb_client;
-       struct nfs4_rpc_args *args = &dp->dl_recall.cb_args;
-       struct rpc_message msg = {
-               .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
-               .rpc_cred = callback_cred
-       };
+       if (cb->cb_ops->rpc_release)
+               cb->cb_ops->rpc_release(cb);
+}
 
-       if (clnt == NULL) {
-               nfs4_put_delegation(dp);
-               return; /* Client is shutting down; give up. */
+void nfsd4_process_cb_update(struct nfsd4_callback *cb)
+{
+       struct nfs4_cb_conn conn;
+       struct nfs4_client *clp = cb->cb_clp;
+       int err;
+
+       /*
+        * This is either an update, or the client dying; in either case,
+        * kill the old client:
+        */
+       if (clp->cl_cb_client) {
+               rpc_shutdown_client(clp->cl_cb_client);
+               clp->cl_cb_client = NULL;
        }
+       if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
+               return;
+       spin_lock(&clp->cl_lock);
+       /*
+        * Only serialized callback code is allowed to clear these
+        * flags; main nfsd code can only set them:
+        */
+       BUG_ON(!clp->cl_cb_flags);
+       clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+       memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
+       spin_unlock(&clp->cl_lock);
 
-       args->args_op = dp;
-       msg.rpc_argp = args;
-       dp->dl_retries = 1;
-       rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
+       err = setup_callback_client(clp, &conn);
+       if (err)
+               warn_no_callback_path(clp, err);
 }
 
 void nfsd4_do_callback_rpc(struct work_struct *w)
 {
-       /* XXX: for now, just send off delegation recall. */
-       /* In future, generalize to handle any sort of callback. */
-       struct nfsd4_callback *c = container_of(w, struct nfsd4_callback, cb_work);
-       struct nfs4_delegation *dp = container_of(c, struct nfs4_delegation, dl_recall);
+       struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
+       struct nfs4_client *clp = cb->cb_clp;
+       struct rpc_clnt *clnt;
 
-       _nfsd4_cb_recall(dp);
-}
+       if (clp->cl_cb_flags)
+               nfsd4_process_cb_update(cb);
 
+       clnt = clp->cl_cb_client;
+       if (!clnt) {
+               /* Callback channel broken, or client killed; give up: */
+               nfsd4_release_cb(cb);
+               return;
+       }
+       rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
+                       cb->cb_ops, cb);
+}
 
 void nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
+       struct nfsd4_callback *cb = &dp->dl_recall;
+
+       dp->dl_retries = 1;
+       cb->cb_op = dp;
+       cb->cb_clp = dp->dl_client;
+       cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
+       cb->cb_msg.rpc_argp = cb;
+       cb->cb_msg.rpc_resp = cb;
+       cb->cb_msg.rpc_cred = callback_cred;
+
+       cb->cb_ops = &nfsd4_cb_recall_ops;
+       dp->dl_retries = 1;
+
        queue_work(callback_wq, &dp->dl_recall.cb_work);
 }
index c78dbf4934247e101d6fee19dd1e3ee150957e80..f0695e815f0ec9e53a2e9934392ac820d36e442e 100644 (file)
@@ -482,109 +482,26 @@ nfsd_idmap_shutdown(void)
        cache_unregister(&nametoid_cache);
 }
 
-/*
- * Deferred request handling
- */
-
-struct idmap_defer_req {
-       struct cache_req                req;
-       struct cache_deferred_req deferred_req;
-       wait_queue_head_t       waitq;
-       atomic_t                        count;
-};
-
-static inline void
-put_mdr(struct idmap_defer_req *mdr)
-{
-       if (atomic_dec_and_test(&mdr->count))
-               kfree(mdr);
-}
-
-static inline void
-get_mdr(struct idmap_defer_req *mdr)
-{
-       atomic_inc(&mdr->count);
-}
-
-static void
-idmap_revisit(struct cache_deferred_req *dreq, int toomany)
-{
-       struct idmap_defer_req *mdr =
-               container_of(dreq, struct idmap_defer_req, deferred_req);
-
-       wake_up(&mdr->waitq);
-       put_mdr(mdr);
-}
-
-static struct cache_deferred_req *
-idmap_defer(struct cache_req *req)
-{
-       struct idmap_defer_req *mdr =
-               container_of(req, struct idmap_defer_req, req);
-
-       mdr->deferred_req.revisit = idmap_revisit;
-       get_mdr(mdr);
-       return (&mdr->deferred_req);
-}
-
-static inline int
-do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key,
-               struct cache_detail *detail, struct ent **item,
-               struct idmap_defer_req *mdr)
-{
-       *item = lookup_fn(key);
-       if (!*item)
-               return -ENOMEM;
-       return cache_check(detail, &(*item)->h, &mdr->req);
-}
-
-static inline int
-do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
-                       struct ent *key, struct cache_detail *detail,
-                       struct ent **item)
-{
-       int ret = -ENOMEM;
-
-       *item = lookup_fn(key);
-       if (!*item)
-               goto out_err;
-       ret = -ETIMEDOUT;
-       if (!test_bit(CACHE_VALID, &(*item)->h.flags)
-                       || (*item)->h.expiry_time < get_seconds()
-                       || detail->flush_time > (*item)->h.last_refresh)
-               goto out_put;
-       ret = -ENOENT;
-       if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
-               goto out_put;
-       return 0;
-out_put:
-       cache_put(&(*item)->h, detail);
-out_err:
-       *item = NULL;
-       return ret;
-}
-
 static int
 idmap_lookup(struct svc_rqst *rqstp,
                struct ent *(*lookup_fn)(struct ent *), struct ent *key,
                struct cache_detail *detail, struct ent **item)
 {
-       struct idmap_defer_req *mdr;
        int ret;
 
-       mdr = kzalloc(sizeof(*mdr), GFP_KERNEL);
-       if (!mdr)
+       *item = lookup_fn(key);
+       if (!*item)
                return -ENOMEM;
-       atomic_set(&mdr->count, 1);
-       init_waitqueue_head(&mdr->waitq);
-       mdr->req.defer = idmap_defer;
-       ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr);
-       if (ret == -EAGAIN) {
-               wait_event_interruptible_timeout(mdr->waitq,
-                       test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ);
-               ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item);
+ retry:
+       ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle);
+
+       if (ret == -ETIMEDOUT) {
+               struct ent *prev_item = *item;
+               *item = lookup_fn(key);
+               if (*item != prev_item)
+                       goto retry;
+               cache_put(&(*item)->h, detail);
        }
-       put_mdr(mdr);
        return ret;
 }
 
index 59ec449b0c7fd8b61040703ee98fa51e7c40e280..0cdfd022bb7b307d344989f493b9873b903dd22d 100644 (file)
@@ -1031,8 +1031,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
        resp->cstate.session = NULL;
        fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
        fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
-       /* Use the deferral mechanism only for NFSv4.0 compounds */
-       rqstp->rq_usedeferral = (args->minorversion == 0);
+       /*
+        * Don't use the deferral mechanism for NFSv4; compounds make it
+        * too hard to avoid non-idempotency problems.
+        */
+       rqstp->rq_usedeferral = 0;
 
        /*
         * According to RFC3010, this takes precedence over all other errors.
index a7292fcf7718e0d1471ddcfd2dab4e3957f17e18..56347e0ac88da33f1fd655809a90c1509f0cb389 100644 (file)
@@ -207,7 +207,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
 {
        struct nfs4_delegation *dp;
        struct nfs4_file *fp = stp->st_file;
-       struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
 
        dprintk("NFSD alloc_init_deleg\n");
        /*
@@ -234,7 +233,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        nfs4_file_get_access(fp, O_RDONLY);
        dp->dl_flock = NULL;
        dp->dl_type = type;
-       dp->dl_ident = cb->cb_ident;
        dp->dl_stateid.si_boot = boot_time;
        dp->dl_stateid.si_stateownerid = current_delegid++;
        dp->dl_stateid.si_fileid = 0;
@@ -535,171 +533,258 @@ gen_sessionid(struct nfsd4_session *ses)
  */
 #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
 
+static void
+free_session_slots(struct nfsd4_session *ses)
+{
+       int i;
+
+       for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+               kfree(ses->se_slots[i]);
+}
+
 /*
- * Give the client the number of ca_maxresponsesize_cached slots it
- * requests, of size bounded by NFSD_SLOT_CACHE_SIZE,
- * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more
- * than NFSD_MAX_SLOTS_PER_SESSION.
- *
- * If we run out of reserved DRC memory we should (up to a point)
+ * We don't actually need to cache the rpc and session headers, so we
+ * can allocate a little less for each slot:
+ */
+static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+{
+       return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+}
+
+static int nfsd4_sanitize_slot_size(u32 size)
+{
+       size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
+       size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
+
+       return size;
+}
+
+/*
+ * XXX: If we run out of reserved DRC memory we could (up to a point)
  * re-negotiate active sessions and reduce their slot usage to make
  * rooom for new connections. For now we just fail the create session.
  */
-static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
+static int nfsd4_get_drc_mem(int slotsize, u32 num)
 {
-       int mem, size = fchan->maxresp_cached;
+       int avail;
 
-       if (fchan->maxreqs < 1)
-               return nfserr_inval;
+       num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
 
-       if (size < NFSD_MIN_HDR_SEQ_SZ)
-               size = NFSD_MIN_HDR_SEQ_SZ;
-       size -= NFSD_MIN_HDR_SEQ_SZ;
-       if (size > NFSD_SLOT_CACHE_SIZE)
-               size = NFSD_SLOT_CACHE_SIZE;
-
-       /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */
-       mem = fchan->maxreqs * size;
-       if (mem > NFSD_MAX_MEM_PER_SESSION) {
-               fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size;
-               if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
-                       fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
-               mem = fchan->maxreqs * size;
-       }
+       spin_lock(&nfsd_drc_lock);
+       avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
+                       nfsd_drc_max_mem - nfsd_drc_mem_used);
+       num = min_t(int, num, avail / slotsize);
+       nfsd_drc_mem_used += num * slotsize;
+       spin_unlock(&nfsd_drc_lock);
 
+       return num;
+}
+
+static void nfsd4_put_drc_mem(int slotsize, int num)
+{
        spin_lock(&nfsd_drc_lock);
-       /* bound the total session drc memory ussage */
-       if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) {
-               fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size;
-               mem = fchan->maxreqs * size;
-       }
-       nfsd_drc_mem_used += mem;
+       nfsd_drc_mem_used -= slotsize * num;
        spin_unlock(&nfsd_drc_lock);
+}
 
-       if (fchan->maxreqs == 0)
-               return nfserr_jukebox;
+static struct nfsd4_session *alloc_session(int slotsize, int numslots)
+{
+       struct nfsd4_session *new;
+       int mem, i;
 
-       fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
-       return 0;
+       BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
+                       + sizeof(struct nfsd4_session) > PAGE_SIZE);
+       mem = numslots * sizeof(struct nfsd4_slot *);
+
+       new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
+       if (!new)
+               return NULL;
+       /* allocate each struct nfsd4_slot and data cache in one piece */
+       for (i = 0; i < numslots; i++) {
+               mem = sizeof(struct nfsd4_slot) + slotsize;
+               new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
+               if (!new->se_slots[i])
+                       goto out_free;
+       }
+       return new;
+out_free:
+       while (i--)
+               kfree(new->se_slots[i]);
+       kfree(new);
+       return NULL;
 }
 
-/*
- * fchan holds the client values on input, and the server values on output
- * sv_max_mesg is the maximum payload plus one page for overhead.
- */
-static int init_forechannel_attrs(struct svc_rqst *rqstp,
-                                 struct nfsd4_channel_attrs *session_fchan,
-                                 struct nfsd4_channel_attrs *fchan)
+static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
 {
-       int status = 0;
-       __u32   maxcount = nfsd_serv->sv_max_mesg;
+       u32 maxrpc = nfsd_serv->sv_max_mesg;
 
-       /* headerpadsz set to zero in encode routine */
+       new->maxreqs = numslots;
+       new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
+       new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
+       new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
+       new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
+}
 
-       /* Use the client's max request and max response size if possible */
-       if (fchan->maxreq_sz > maxcount)
-               fchan->maxreq_sz = maxcount;
-       session_fchan->maxreq_sz = fchan->maxreq_sz;
+static void free_conn(struct nfsd4_conn *c)
+{
+       svc_xprt_put(c->cn_xprt);
+       kfree(c);
+}
 
-       if (fchan->maxresp_sz > maxcount)
-               fchan->maxresp_sz = maxcount;
-       session_fchan->maxresp_sz = fchan->maxresp_sz;
+static void nfsd4_conn_lost(struct svc_xpt_user *u)
+{
+       struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
+       struct nfs4_client *clp = c->cn_session->se_client;
 
-       /* Use the client's maxops if possible */
-       if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND)
-               fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
-       session_fchan->maxops = fchan->maxops;
+       spin_lock(&clp->cl_lock);
+       if (!list_empty(&c->cn_persession)) {
+               list_del(&c->cn_persession);
+               free_conn(c);
+       }
+       spin_unlock(&clp->cl_lock);
+}
 
-       /* FIXME: Error means no more DRC pages so the server should
-        * recover pages from existing sessions. For now fail session
-        * creation.
-        */
-       status = set_forechannel_drc_size(fchan);
+static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
+{
+       struct nfsd4_conn *conn;
 
-       session_fchan->maxresp_cached = fchan->maxresp_cached;
-       session_fchan->maxreqs = fchan->maxreqs;
+       conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
+       if (!conn)
+               return NULL;
+       svc_xprt_get(rqstp->rq_xprt);
+       conn->cn_xprt = rqstp->rq_xprt;
+       conn->cn_flags = flags;
+       INIT_LIST_HEAD(&conn->cn_xpt_user.list);
+       return conn;
+}
 
-       dprintk("%s status %d\n", __func__, status);
-       return status;
+static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
+{
+       conn->cn_session = ses;
+       list_add(&conn->cn_persession, &ses->se_conns);
 }
 
-static void
-free_session_slots(struct nfsd4_session *ses)
+static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
 {
-       int i;
+       struct nfs4_client *clp = ses->se_client;
 
-       for (i = 0; i < ses->se_fchannel.maxreqs; i++)
-               kfree(ses->se_slots[i]);
+       spin_lock(&clp->cl_lock);
+       __nfsd4_hash_conn(conn, ses);
+       spin_unlock(&clp->cl_lock);
 }
 
-/*
- * We don't actually need to cache the rpc and session headers, so we
- * can allocate a little less for each slot:
- */
-static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+static void nfsd4_register_conn(struct nfsd4_conn *conn)
 {
-       return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+       conn->cn_xpt_user.callback = nfsd4_conn_lost;
+       register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
 }
 
-static int
-alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
-                  struct nfsd4_create_session *cses)
+static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
 {
-       struct nfsd4_session *new, tmp;
-       struct nfsd4_slot *sp;
-       int idx, slotsize, cachesize, i;
-       int status;
+       struct nfsd4_conn *conn;
+       u32 flags = NFS4_CDFC4_FORE;
 
-       memset(&tmp, 0, sizeof(tmp));
+       if (ses->se_flags & SESSION4_BACK_CHAN)
+               flags |= NFS4_CDFC4_BACK;
+       conn = alloc_conn(rqstp, flags);
+       if (!conn)
+               return nfserr_jukebox;
+       nfsd4_hash_conn(conn, ses);
+       nfsd4_register_conn(conn);
+       return nfs_ok;
+}
 
-       /* FIXME: For now, we just accept the client back channel attributes. */
-       tmp.se_bchannel = cses->back_channel;
-       status = init_forechannel_attrs(rqstp, &tmp.se_fchannel,
-                                       &cses->fore_channel);
-       if (status)
-               goto out;
+static void nfsd4_del_conns(struct nfsd4_session *s)
+{
+       struct nfs4_client *clp = s->se_client;
+       struct nfsd4_conn *c;
 
-       BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
-                    + sizeof(struct nfsd4_session) > PAGE_SIZE);
+       spin_lock(&clp->cl_lock);
+       while (!list_empty(&s->se_conns)) {
+               c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
+               list_del_init(&c->cn_persession);
+               spin_unlock(&clp->cl_lock);
 
-       status = nfserr_jukebox;
-       /* allocate struct nfsd4_session and slot table pointers in one piece */
-       slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
-       new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
-       if (!new)
-               goto out;
+               unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
+               free_conn(c);
 
-       memcpy(new, &tmp, sizeof(*new));
+               spin_lock(&clp->cl_lock);
+       }
+       spin_unlock(&clp->cl_lock);
+}
 
-       /* allocate each struct nfsd4_slot and data cache in one piece */
-       cachesize = slot_bytes(&new->se_fchannel);
-       for (i = 0; i < new->se_fchannel.maxreqs; i++) {
-               sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL);
-               if (!sp)
-                       goto out_free;
-               new->se_slots[i] = sp;
+void free_session(struct kref *kref)
+{
+       struct nfsd4_session *ses;
+       int mem;
+
+       ses = container_of(kref, struct nfsd4_session, se_ref);
+       nfsd4_del_conns(ses);
+       spin_lock(&nfsd_drc_lock);
+       mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
+       nfsd_drc_mem_used -= mem;
+       spin_unlock(&nfsd_drc_lock);
+       free_session_slots(ses);
+       kfree(ses);
+}
+
+static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
+{
+       struct nfsd4_session *new;
+       struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
+       int numslots, slotsize;
+       int status;
+       int idx;
+
+       /*
+        * Note decreasing slot size below client's request may
+        * make it difficult for client to function correctly, whereas
+        * decreasing the number of slots will (just?) affect
+        * performance.  When short on memory we therefore prefer to
+        * decrease number of slots instead of their size.
+        */
+       slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
+       numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
+
+       new = alloc_session(slotsize, numslots);
+       if (!new) {
+               nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
+               return NULL;
        }
+       init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
 
        new->se_client = clp;
        gen_sessionid(new);
-       idx = hash_sessionid(&new->se_sessionid);
-       memcpy(clp->cl_sessionid.data, new->se_sessionid.data,
-              NFS4_MAX_SESSIONID_LEN);
 
+       INIT_LIST_HEAD(&new->se_conns);
+
+       new->se_cb_seq_nr = 1;
        new->se_flags = cses->flags;
+       new->se_cb_prog = cses->callback_prog;
        kref_init(&new->se_ref);
+       idx = hash_sessionid(&new->se_sessionid);
        spin_lock(&client_lock);
        list_add(&new->se_hash, &sessionid_hashtbl[idx]);
        list_add(&new->se_perclnt, &clp->cl_sessions);
        spin_unlock(&client_lock);
 
-       status = nfs_ok;
-out:
-       return status;
-out_free:
-       free_session_slots(new);
-       kfree(new);
-       goto out;
+       status = nfsd4_new_conn(rqstp, new);
+       /* whoops: benny points out, status is ignored! (err, or bogus) */
+       if (status) {
+               free_session(&new->se_ref);
+               return NULL;
+       }
+       if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+               struct sockaddr *sa = svc_addr(rqstp);
+
+               clp->cl_cb_session = new;
+               clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
+               svc_xprt_get(rqstp->rq_xprt);
+               rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
+               clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
+               nfsd4_probe_callback(clp);
+       }
+       return new;
 }
 
 /* caller must hold client_lock */
@@ -731,21 +816,6 @@ unhash_session(struct nfsd4_session *ses)
        list_del(&ses->se_perclnt);
 }
 
-void
-free_session(struct kref *kref)
-{
-       struct nfsd4_session *ses;
-       int mem;
-
-       ses = container_of(kref, struct nfsd4_session, se_ref);
-       spin_lock(&nfsd_drc_lock);
-       mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
-       nfsd_drc_mem_used -= mem;
-       spin_unlock(&nfsd_drc_lock);
-       free_session_slots(ses);
-       kfree(ses);
-}
-
 /* must be called under the client_lock */
 static inline void
 renew_client_locked(struct nfs4_client *clp)
@@ -812,6 +882,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 static inline void
 free_client(struct nfs4_client *clp)
 {
+       while (!list_empty(&clp->cl_sessions)) {
+               struct nfsd4_session *ses;
+               ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
+                               se_perclnt);
+               list_del(&ses->se_perclnt);
+               nfsd4_put_session(ses);
+       }
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
        kfree(clp->cl_principal);
@@ -838,15 +915,12 @@ release_session_client(struct nfsd4_session *session)
 static inline void
 unhash_client_locked(struct nfs4_client *clp)
 {
+       struct nfsd4_session *ses;
+
        mark_client_expired(clp);
        list_del(&clp->cl_lru);
-       while (!list_empty(&clp->cl_sessions)) {
-               struct nfsd4_session  *ses;
-               ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
-                                se_perclnt);
-               unhash_session(ses);
-               nfsd4_put_session(ses);
-       }
+       list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
+               list_del_init(&ses->se_hash);
 }
 
 static void
@@ -875,7 +949,7 @@ expire_client(struct nfs4_client *clp)
                sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
                release_openowner(sop);
        }
-       nfsd4_set_callback_client(clp, NULL);
+       nfsd4_shutdown_callback(clp);
        if (clp->cl_cb_conn.cb_xprt)
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
        list_del(&clp->cl_idhash);
@@ -960,6 +1034,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        if (clp == NULL)
                return NULL;
 
+       INIT_LIST_HEAD(&clp->cl_sessions);
+
        princ = svc_gss_principal(rqstp);
        if (princ) {
                clp->cl_principal = kstrdup(princ, GFP_KERNEL);
@@ -976,8 +1052,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        INIT_LIST_HEAD(&clp->cl_strhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
-       INIT_LIST_HEAD(&clp->cl_sessions);
        INIT_LIST_HEAD(&clp->cl_lru);
+       spin_lock_init(&clp->cl_lock);
+       INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
        clp->cl_time = get_seconds();
        clear_bit(0, &clp->cl_cb_slot_busy);
        rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
@@ -986,7 +1063,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        clp->cl_flavor = rqstp->rq_flavor;
        copy_cred(&clp->cl_cred, &rqstp->rq_cred);
        gen_confirm(clp);
-
+       clp->cl_cb_session = NULL;
        return clp;
 }
 
@@ -1098,7 +1175,7 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
 static void
 gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
 {
-       struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
+       struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
        unsigned short expected_family;
 
        /* Currently, we only support tcp and tcp6 for the callback channel */
@@ -1111,24 +1188,23 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
        else
                goto out_err;
 
-       cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
+       conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
                                            se->se_callback_addr_len,
-                                           (struct sockaddr *) &cb->cb_addr,
-                                           sizeof(cb->cb_addr));
+                                           (struct sockaddr *)&conn->cb_addr,
+                                           sizeof(conn->cb_addr));
 
-       if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family)
+       if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
                goto out_err;
 
-       if (cb->cb_addr.ss_family == AF_INET6)
-               ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid;
+       if (conn->cb_addr.ss_family == AF_INET6)
+               ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
 
-       cb->cb_minorversion = 0;
-       cb->cb_prog = se->se_callback_prog;
-       cb->cb_ident = se->se_callback_ident;
+       conn->cb_prog = se->se_callback_prog;
+       conn->cb_ident = se->se_callback_ident;
        return;
 out_err:
-       cb->cb_addr.ss_family = AF_UNSPEC;
-       cb->cb_addrlen = 0;
+       conn->cb_addr.ss_family = AF_UNSPEC;
+       conn->cb_addrlen = 0;
        dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
                "will not receive delegations\n",
                clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
@@ -1415,7 +1491,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 {
        struct sockaddr *sa = svc_addr(rqstp);
        struct nfs4_client *conf, *unconf;
+       struct nfsd4_session *new;
        struct nfsd4_clid_slot *cs_slot = NULL;
+       bool confirm_me = false;
        int status = 0;
 
        nfs4_lock_state();
@@ -1438,7 +1516,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                                cs_slot->sl_seqid, cr_ses->seqid);
                        goto out;
                }
-               cs_slot->sl_seqid++;
        } else if (unconf) {
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
                    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
@@ -1451,48 +1528,41 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                if (status) {
                        /* an unconfirmed replay returns misordered */
                        status = nfserr_seq_misordered;
-                       goto out_cache;
+                       goto out;
                }
 
-               cs_slot->sl_seqid++; /* from 0 to 1 */
-               move_to_confirmed(unconf);
-
-               if (cr_ses->flags & SESSION4_BACK_CHAN) {
-                       unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
-                       svc_xprt_get(rqstp->rq_xprt);
-                       rpc_copy_addr(
-                               (struct sockaddr *)&unconf->cl_cb_conn.cb_addr,
-                               sa);
-                       unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
-                       unconf->cl_cb_conn.cb_minorversion =
-                               cstate->minorversion;
-                       unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
-                       unconf->cl_cb_seq_nr = 1;
-                       nfsd4_probe_callback(unconf, &unconf->cl_cb_conn);
-               }
+               confirm_me = true;
                conf = unconf;
        } else {
                status = nfserr_stale_clientid;
                goto out;
        }
 
+       /*
+        * XXX: we should probably set this at creation time, and check
+        * for consistent minorversion use throughout:
+        */
+       conf->cl_minorversion = 1;
        /*
         * We do not support RDMA or persistent sessions
         */
        cr_ses->flags &= ~SESSION4_PERSIST;
        cr_ses->flags &= ~SESSION4_RDMA;
 
-       status = alloc_init_session(rqstp, conf, cr_ses);
-       if (status)
+       status = nfserr_jukebox;
+       new = alloc_init_session(rqstp, conf, cr_ses);
+       if (!new)
                goto out;
-
-       memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data,
+       status = nfs_ok;
+       memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
               NFS4_MAX_SESSIONID_LEN);
+       cs_slot->sl_seqid++;
        cr_ses->seqid = cs_slot->sl_seqid;
 
-out_cache:
        /* cache solo and embedded create sessions under the state lock */
        nfsd4_cache_create_session(cr_ses, cs_slot, status);
+       if (confirm_me)
+               move_to_confirmed(conf);
 out:
        nfs4_unlock_state();
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1546,8 +1616,11 @@ nfsd4_destroy_session(struct svc_rqst *r,
 
        nfs4_lock_state();
        /* wait for callbacks */
-       nfsd4_set_callback_client(ses->se_client, NULL);
+       nfsd4_shutdown_callback(ses->se_client);
        nfs4_unlock_state();
+
+       nfsd4_del_conns(ses);
+
        nfsd4_put_session(ses);
        status = nfs_ok;
 out:
@@ -1555,6 +1628,36 @@ out:
        return status;
 }
 
+static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
+{
+       struct nfsd4_conn *c;
+
+       list_for_each_entry(c, &s->se_conns, cn_persession) {
+               if (c->cn_xprt == xpt) {
+                       return c;
+               }
+       }
+       return NULL;
+}
+
+static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
+{
+       struct nfs4_client *clp = ses->se_client;
+       struct nfsd4_conn *c;
+
+       spin_lock(&clp->cl_lock);
+       c = __nfsd4_find_conn(new->cn_xprt, ses);
+       if (c) {
+               spin_unlock(&clp->cl_lock);
+               free_conn(new);
+               return;
+       }
+       __nfsd4_hash_conn(new, ses);
+       spin_unlock(&clp->cl_lock);
+       nfsd4_register_conn(new);
+       return;
+}
+
 __be32
 nfsd4_sequence(struct svc_rqst *rqstp,
               struct nfsd4_compound_state *cstate,
@@ -1563,11 +1666,20 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct nfsd4_session *session;
        struct nfsd4_slot *slot;
+       struct nfsd4_conn *conn;
        int status;
 
        if (resp->opcnt != 1)
                return nfserr_sequence_pos;
 
+       /*
+        * Will be either used or freed by nfsd4_sequence_check_conn
+        * below.
+        */
+       conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
+       if (!conn)
+               return nfserr_jukebox;
+
        spin_lock(&client_lock);
        status = nfserr_badsession;
        session = find_in_sessionid_hashtbl(&seq->sessionid);
@@ -1599,6 +1711,9 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        if (status)
                goto out;
 
+       nfsd4_sequence_check_conn(conn, session);
+       conn = NULL;
+
        /* Success! bump slot seqid */
        slot->sl_inuse = true;
        slot->sl_seqid = seq->seqid;
@@ -1613,6 +1728,7 @@ out:
                nfsd4_get_session(cstate->session);
                atomic_inc(&session->se_client->cl_refcount);
        }
+       kfree(conn);
        spin_unlock(&client_lock);
        dprintk("%s: return %d\n", __func__, ntohl(status));
        return status;
@@ -1747,6 +1863,11 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                gen_clid(new);
        }
+       /*
+        * XXX: we should probably set this at creation time, and check
+        * for consistent minorversion use throughout:
+        */
+       new->cl_minorversion = 0;
        gen_callback(new, setclid, rpc_get_scope_id(sa));
        add_to_unconfirmed(new, strhashval);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
@@ -1807,7 +1928,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfserr_clid_inuse;
                else {
                        atomic_set(&conf->cl_cb_set, 0);
-                       nfsd4_probe_callback(conf, &unconf->cl_cb_conn);
+                       nfsd4_change_callback(conf, &unconf->cl_cb_conn);
+                       nfsd4_probe_callback(conf);
                        expire_client(unconf);
                        status = nfs_ok;
 
@@ -1841,7 +1963,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        }
                        move_to_confirmed(unconf);
                        conf = unconf;
-                       nfsd4_probe_callback(conf, &conf->cl_cb_conn);
+                       nfsd4_probe_callback(conf);
                        status = nfs_ok;
                }
        } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
@@ -2492,7 +2614,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        struct nfs4_delegation *dp;
        struct nfs4_stateowner *sop = stp->st_stateowner;
        int cb_up = atomic_read(&sop->so_client->cl_cb_set);
-       struct file_lock fl, *flp = &fl;
+       struct file_lock *fl;
        int status, flag = 0;
 
        flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2526,20 +2648,24 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
                flag = NFS4_OPEN_DELEGATE_NONE;
                goto out;
        }
-       locks_init_lock(&fl);
-       fl.fl_lmops = &nfsd_lease_mng_ops;
-       fl.fl_flags = FL_LEASE;
-       fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
-       fl.fl_end = OFFSET_MAX;
-       fl.fl_owner =  (fl_owner_t)dp;
-       fl.fl_file = find_readable_file(stp->st_file);
-       BUG_ON(!fl.fl_file);
-       fl.fl_pid = current->tgid;
+       status = -ENOMEM;
+       fl = locks_alloc_lock();
+       if (!fl)
+               goto out;
+       locks_init_lock(fl);
+       fl->fl_lmops = &nfsd_lease_mng_ops;
+       fl->fl_flags = FL_LEASE;
+       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
+       fl->fl_end = OFFSET_MAX;
+       fl->fl_owner =  (fl_owner_t)dp;
+       fl->fl_file = find_readable_file(stp->st_file);
+       BUG_ON(!fl->fl_file);
+       fl->fl_pid = current->tgid;
 
        /* vfs_setlease checks to see if delegation should be handed out.
         * the lock_manager callbacks fl_mylease and fl_change are used
         */
-       if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
+       if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                unhash_delegation(dp);
                flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2944,7 +3070,11 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
        if (STALE_STATEID(stateid)) 
                goto out;
 
-       status = nfserr_bad_stateid;
+       /*
+        * We assume that any stateid that has the current boot time,
+        * but that we can't find, is expired:
+        */
+       status = nfserr_expired;
        if (is_delegation_stateid(stateid)) {
                dp = find_delegation_stateid(ino, stateid);
                if (!dp)
@@ -2964,6 +3094,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                stp = find_stateid(stateid, flags);
                if (!stp)
                        goto out;
+               status = nfserr_bad_stateid;
                if (nfs4_check_fh(current_fh, stp))
                        goto out;
                if (!stp->st_stateowner->so_confirmed)
@@ -3038,8 +3169,9 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
                 * a replayed close:
                 */
                sop = search_close_lru(stateid->si_stateownerid, flags);
+               /* It's not stale; let's assume it's expired: */
                if (sop == NULL)
-                       return nfserr_bad_stateid;
+                       return nfserr_expired;
                *sopp = sop;
                goto check_replay;
        }
@@ -3304,6 +3436,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        status = nfserr_bad_stateid;
        if (!is_delegation_stateid(stateid))
                goto out;
+       status = nfserr_expired;
        dp = find_delegation_stateid(inode, stateid);
        if (!dp)
                goto out;
index 1a468bbd330f48410f62a74272c1f4c431755169..f35a94a0402677d36193c9fcb57992edcc061e9d 100644 (file)
@@ -1805,19 +1805,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                                goto out_nfserr;
                }
        }
-       if ((buflen -= 16) < 0)
-               goto out_resource;
 
-       if (unlikely(bmval2)) {
+       if (bmval2) {
+               if ((buflen -= 16) < 0)
+                       goto out_resource;
                WRITE32(3);
                WRITE32(bmval0);
                WRITE32(bmval1);
                WRITE32(bmval2);
-       } else if (likely(bmval1)) {
+       } else if (bmval1) {
+               if ((buflen -= 12) < 0)
+                       goto out_resource;
                WRITE32(2);
                WRITE32(bmval0);
                WRITE32(bmval1);
        } else {
+               if ((buflen -= 8) < 0)
+                       goto out_resource;
                WRITE32(1);
                WRITE32(bmval0);
        }
@@ -1828,15 +1832,17 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                u32 word1 = nfsd_suppattrs1(minorversion);
                u32 word2 = nfsd_suppattrs2(minorversion);
 
-               if ((buflen -= 12) < 0)
-                       goto out_resource;
                if (!aclsupport)
                        word0 &= ~FATTR4_WORD0_ACL;
                if (!word2) {
+                       if ((buflen -= 12) < 0)
+                               goto out_resource;
                        WRITE32(2);
                        WRITE32(word0);
                        WRITE32(word1);
                } else {
+                       if ((buflen -= 16) < 0)
+                               goto out_resource;
                        WRITE32(3);
                        WRITE32(word0);
                        WRITE32(word1);
index 06fa87e52e8243cc46a41d5f861aa91388581d7b..d6dc3f61f8bafdd77e3a592b26a543e42ae7d1a9 100644 (file)
@@ -22,6 +22,7 @@
  */
 enum {
        NFSD_Root = 1,
+#ifdef CONFIG_NFSD_DEPRECATED
        NFSD_Svc,
        NFSD_Add,
        NFSD_Del,
@@ -29,6 +30,7 @@ enum {
        NFSD_Unexport,
        NFSD_Getfd,
        NFSD_Getfs,
+#endif
        NFSD_List,
        NFSD_Export_features,
        NFSD_Fh,
@@ -54,6 +56,7 @@ enum {
 /*
  * write() for these nodes.
  */
+#ifdef CONFIG_NFSD_DEPRECATED
 static ssize_t write_svc(struct file *file, char *buf, size_t size);
 static ssize_t write_add(struct file *file, char *buf, size_t size);
 static ssize_t write_del(struct file *file, char *buf, size_t size);
@@ -61,6 +64,7 @@ static ssize_t write_export(struct file *file, char *buf, size_t size);
 static ssize_t write_unexport(struct file *file, char *buf, size_t size);
 static ssize_t write_getfd(struct file *file, char *buf, size_t size);
 static ssize_t write_getfs(struct file *file, char *buf, size_t size);
+#endif
 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
@@ -76,6 +80,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
 #endif
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
+#ifdef CONFIG_NFSD_DEPRECATED
        [NFSD_Svc] = write_svc,
        [NFSD_Add] = write_add,
        [NFSD_Del] = write_del,
@@ -83,6 +88,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Unexport] = write_unexport,
        [NFSD_Getfd] = write_getfd,
        [NFSD_Getfs] = write_getfs,
+#endif
        [NFSD_Fh] = write_filehandle,
        [NFSD_FO_UnlockIP] = write_unlock_ip,
        [NFSD_FO_UnlockFS] = write_unlock_fs,
@@ -121,6 +127,14 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
 
 static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
 {
+       static int warned;
+       if (file->f_dentry->d_name.name[0] == '.' && !warned) {
+               printk(KERN_INFO
+                      "Warning: \"%s\" uses deprecated NFSD interface: %s."
+                      "  This will be removed in 2.6.40\n",
+                      current->comm, file->f_dentry->d_name.name);
+               warned = 1;
+       }
        if (! file->private_data) {
                /* An attempt to read a transaction file without writing
                 * causes a 0-byte write so that the file can return
@@ -187,6 +201,7 @@ static const struct file_operations pool_stats_operations = {
  * payload - write methods
  */
 
+#ifdef CONFIG_NFSD_DEPRECATED
 /**
  * write_svc - Start kernel's NFSD server
  *
@@ -402,7 +417,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
 
        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
 
-       clp = auth_unix_lookup(&in6);
+       clp = auth_unix_lookup(&init_net, &in6);
        if (!clp)
                err = -EPERM;
        else {
@@ -465,7 +480,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
 
        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
 
-       clp = auth_unix_lookup(&in6);
+       clp = auth_unix_lookup(&init_net, &in6);
        if (!clp)
                err = -EPERM;
        else {
@@ -482,6 +497,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
  out:
        return err;
 }
+#endif /* CONFIG_NFSD_DEPRECATED */
 
 /**
  * write_unlock_ip - Release all locks used by a client
@@ -1000,12 +1016,12 @@ static ssize_t __write_ports_addxprt(char *buf)
        if (err != 0)
                return err;
 
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET, port, SVC_SOCK_ANONYMOUS);
        if (err < 0)
                goto out_err;
 
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
@@ -1356,6 +1372,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
 static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
 {
        static struct tree_descr nfsd_files[] = {
+#ifdef CONFIG_NFSD_DEPRECATED
                [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
                [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
                [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
@@ -1363,6 +1380,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
                [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
+#endif
                [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
                [NFSD_Export_features] = {"export_features",
                                        &export_features_operations, S_IRUGO},
index b76ac3a82e39f14438f2b3c5c886fe466b84a45d..6b641cf2c19ac59a6f65326c40038e2549c6df83 100644 (file)
@@ -249,7 +249,7 @@ extern time_t nfsd4_grace;
 #define        COMPOUND_SLACK_SPACE            140    /* OP_GETFH */
 #define COMPOUND_ERR_SLACK_SPACE       12     /* OP_SETATTR */
 
-#define NFSD_LAUNDROMAT_MINTIMEOUT      10   /* seconds */
+#define NFSD_LAUNDROMAT_MINTIMEOUT      1   /* seconds */
 
 /*
  * The following attributes are currently not supported by the NFSv4 server:
index e2c43464f23764405fef5e525e3829777be1a1a7..2bae1d86f5f241b8d62a61bf9ed8b5a0bcfc9c8e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/nfsacl.h>
 #include <linux/seq_file.h>
+#include <net/net_namespace.h>
 #include "nfsd.h"
 #include "cache.h"
 #include "vfs.h"
@@ -186,12 +187,12 @@ static int nfsd_init_socks(int port)
        if (!list_empty(&nfsd_serv->sv_permsocks))
                return 0;
 
-       error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
+       error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
 
-       error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
+       error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
index 322518c88e4b09eee40473ed8efaece99e02410b..39adc27b06853c37a40a1e951ff5027625a15b52 100644 (file)
@@ -35,6 +35,7 @@
 #ifndef _NFSD4_STATE_H
 #define _NFSD4_STATE_H
 
+#include <linux/sunrpc/svc_xprt.h>
 #include <linux/nfsd/nfsfh.h>
 #include "nfsfh.h"
 
@@ -64,19 +65,12 @@ typedef struct {
        (s)->si_fileid, \
        (s)->si_generation
 
-struct nfsd4_cb_sequence {
-       /* args/res */
-       u32                     cbs_minorversion;
-       struct nfs4_client      *cbs_clp;
-};
-
-struct nfs4_rpc_args {
-       void                            *args_op;
-       struct nfsd4_cb_sequence        args_seq;
-};
-
 struct nfsd4_callback {
-       struct nfs4_rpc_args cb_args;
+       void *cb_op;
+       struct nfs4_client *cb_clp;
+       u32 cb_minorversion;
+       struct rpc_message cb_msg;
+       const struct rpc_call_ops *cb_ops;
        struct work_struct cb_work;
 };
 
@@ -91,7 +85,6 @@ struct nfs4_delegation {
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
-       u32                     dl_ident;
        stateid_t               dl_stateid;
        struct knfsd_fh         dl_fh;
        int                     dl_retries;
@@ -103,8 +96,8 @@ struct nfs4_cb_conn {
        /* SETCLIENTID info */
        struct sockaddr_storage cb_addr;
        size_t                  cb_addrlen;
-       u32                     cb_prog;
-       u32                     cb_minorversion;
+       u32                     cb_prog; /* used only in 4.0 case;
+                                           per-session otherwise */
        u32                     cb_ident;       /* minorversion 0 only */
        struct svc_xprt         *cb_xprt;       /* minorversion 1 only */
 };
@@ -160,6 +153,15 @@ struct nfsd4_clid_slot {
        struct nfsd4_create_session     sl_cr_ses;
 };
 
+struct nfsd4_conn {
+       struct list_head cn_persession;
+       struct svc_xprt *cn_xprt;
+       struct svc_xpt_user cn_xpt_user;
+       struct nfsd4_session *cn_session;
+/* CDFC4_FORE, CDFC4_BACK: */
+       unsigned char cn_flags;
+};
+
 struct nfsd4_session {
        struct kref             se_ref;
        struct list_head        se_hash;        /* hash by sessionid */
@@ -169,6 +171,9 @@ struct nfsd4_session {
        struct nfs4_sessionid   se_sessionid;
        struct nfsd4_channel_attrs se_fchannel;
        struct nfsd4_channel_attrs se_bchannel;
+       struct list_head        se_conns;
+       u32                     se_cb_prog;
+       u32                     se_cb_seq_nr;
        struct nfsd4_slot       *se_slots[];    /* forward channel slots */
 };
 
@@ -221,24 +226,32 @@ struct nfs4_client {
        clientid_t              cl_clientid;    /* generated by server */
        nfs4_verifier           cl_confirm;     /* generated by server */
        u32                     cl_firststate;  /* recovery dir creation */
+       u32                     cl_minorversion;
 
        /* for v4.0 and v4.1 callbacks: */
        struct nfs4_cb_conn     cl_cb_conn;
+#define NFSD4_CLIENT_CB_UPDATE 1
+#define NFSD4_CLIENT_KILL      2
+       unsigned long           cl_cb_flags;
        struct rpc_clnt         *cl_cb_client;
+       u32                     cl_cb_ident;
        atomic_t                cl_cb_set;
+       struct nfsd4_callback   cl_cb_null;
+       struct nfsd4_session    *cl_cb_session;
+
+       /* for all client information that callback code might need: */
+       spinlock_t              cl_lock;
 
        /* for nfs41 */
        struct list_head        cl_sessions;
        struct nfsd4_clid_slot  cl_cs_slot;     /* create_session slot */
        u32                     cl_exchange_flags;
-       struct nfs4_sessionid   cl_sessionid;
        /* number of rpc's in progress over an associated session: */
        atomic_t                cl_refcount;
 
        /* for nfs41 callbacks */
        /* We currently support a single back channel with a single slot */
        unsigned long           cl_cb_slot_busy;
-       u32                     cl_cb_seq_nr;
        struct rpc_wait_queue   cl_cb_waitq;    /* backchannel callers may */
                                                /* wait here for slots */
 };
@@ -440,12 +453,13 @@ extern int nfs4_in_grace(void);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
 extern void nfs4_free_stateowner(struct kref *kref);
 extern int set_callback_cred(void);
-extern void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
+extern void nfsd4_probe_callback(struct nfs4_client *clp);
+extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
 extern void nfsd4_do_callback_rpc(struct work_struct *);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 extern int nfsd4_create_callback_queue(void);
 extern void nfsd4_destroy_callback_queue(void);
-extern void nfsd4_set_callback_client(struct nfs4_client *, struct rpc_clnt *);
+extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
 extern void nfsd4_init_recdir(char *recdir_name);
index 661a6cf8e8265eaeca988e2aabc0ba1ede767717..184938fcff04d5dff712b8bee01f5d7e41bb20ad 100644 (file)
@@ -281,23 +281,13 @@ commit_metadata(struct svc_fh *fhp)
 {
        struct inode *inode = fhp->fh_dentry->d_inode;
        const struct export_operations *export_ops = inode->i_sb->s_export_op;
-       int error = 0;
 
        if (!EX_ISSYNC(fhp->fh_export))
                return 0;
 
-       if (export_ops->commit_metadata) {
-               error = export_ops->commit_metadata(inode);
-       } else {
-               struct writeback_control wbc = {
-                       .sync_mode = WB_SYNC_ALL,
-                       .nr_to_write = 0, /* metadata only */
-               };
-
-               error = sync_inode(inode, &wbc);
-       }
-
-       return error;
+       if (export_ops->commit_metadata)
+               return export_ops->commit_metadata(inode);
+       return sync_inode_metadata(inode, 1);
 }
 
 /*
index 185d1607cb00c2f6c0b1e224ea148af0fb17e224..6e9557ecf161fd664a0715d9a3b8e0f3e34501dd 100644 (file)
@@ -207,7 +207,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
 
        inode->i_ctime = CURRENT_TIME;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        err = nilfs_add_nondir(dentry, inode);
        if (!err)
index d926af626177d9ca3fd275cf1be57d8fe105a0d2..687d090cea341fea2f0cf88ac9b4b41e36dcf957 100644 (file)
@@ -1609,7 +1609,7 @@ nilfs_copy_replace_page_buffers(struct page *page, struct list_head *out)
        kunmap_atomic(kaddr, KM_USER0);
 
        if (!TestSetPageWriteback(clone_page))
-               inc_zone_page_state(clone_page, NR_WRITEBACK);
+               account_page_writeback(clone_page);
        unlock_page(clone_page);
 
        return 0;
index 36802420d69a94024eefde05f1eab9f6a9932241..4498a208df940b92117323dcad6cb355969fd164 100644 (file)
@@ -88,8 +88,6 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
 {
        struct dentry *parent;
        struct inode *p_inode;
-       bool send = false;
-       bool should_update_children = false;
 
        if (!dentry)
                dentry = path->dentry;
@@ -97,29 +95,12 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
        if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
                return;
 
-       spin_lock(&dentry->d_lock);
-       parent = dentry->d_parent;
+       parent = dget_parent(dentry);
        p_inode = parent->d_inode;
 
-       if (fsnotify_inode_watches_children(p_inode)) {
-               if (p_inode->i_fsnotify_mask & mask) {
-                       dget(parent);
-                       send = true;
-               }
-       } else {
-               /*
-                * The parent doesn't care about events on it's children but
-                * at least one child thought it did.  We need to run all the
-                * children and update their d_flags to let them know p_inode
-                * doesn't care about them any more.
-                */
-               dget(parent);
-               should_update_children = true;
-       }
-
-       spin_unlock(&dentry->d_lock);
-
-       if (send) {
+       if (unlikely(!fsnotify_inode_watches_children(p_inode)))
+               __fsnotify_update_child_dentry_flags(p_inode);
+       else if (p_inode->i_fsnotify_mask & mask) {
                /* we are notifying a parent so come up with the new mask which
                 * specifies these are events which came from a child. */
                mask |= FS_EVENT_ON_CHILD;
@@ -130,13 +111,9 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
                else
                        fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
                                 dentry->d_name.name, 0);
-               dput(parent);
        }
 
-       if (unlikely(should_update_children)) {
-               __fsnotify_update_child_dentry_flags(p_inode);
-               dput(parent);
-       }
+       dput(parent);
 }
 EXPORT_SYMBOL_GPL(__fsnotify_parent);
 
index 33297c00506050afb6bbe6227f8d47e4eb9cdd11..21ed10660b80770c34eb136a311254330568fac2 100644 (file)
@@ -240,6 +240,7 @@ void fsnotify_unmount_inodes(struct list_head *list)
 {
        struct inode *inode, *next_i, *need_iput = NULL;
 
+       spin_lock(&inode_lock);
        list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
                struct inode *need_iput_tmp;
 
@@ -297,4 +298,5 @@ void fsnotify_unmount_inodes(struct list_head *list)
 
                spin_lock(&inode_lock);
        }
+       spin_unlock(&inode_lock);
 }
index 19c5180f8a28c063b9a8cf5fefc58a6c61512455..d3fbe5730bfc1bb1c1264e9e3923c9425321fea0 100644 (file)
@@ -2911,8 +2911,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
                goto unl_upcase_iput_tmp_ino_err_out_now;
        }
        if ((sb->s_root = d_alloc_root(vol->root_ino))) {
-               /* We increment i_count simulating an ntfs_iget(). */
-               atomic_inc(&vol->root_ino->i_count);
+               /* We grab a reference, simulating an ntfs_iget(). */
+               ihold(vol->root_ino);
                ntfs_debug("Exiting, status successful.");
                /* Release the default upcase if it has no users. */
                mutex_lock(&ntfs_lock);
@@ -3021,21 +3021,6 @@ iput_tmp_ino_err_out_now:
        if (vol->mft_ino && vol->mft_ino != tmp_ino)
                iput(vol->mft_ino);
        vol->mft_ino = NULL;
-       /*
-        * This is needed to get ntfs_clear_extent_inode() called for each
-        * inode we have ever called ntfs_iget()/iput() on, otherwise we A)
-        * leak resources and B) a subsequent mount fails automatically due to
-        * ntfs_iget() never calling down into our ntfs_read_locked_inode()
-        * method again... FIXME: Do we need to do this twice now because of
-        * attribute inodes? I think not, so leave as is for now... (AIA)
-        */
-       if (invalidate_inodes(sb)) {
-               ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
-                               "driver bug.");
-               /* Copied from fs/super.c. I just love this message. (-; */
-               printk("NTFS: Busy inodes after umount. Self-destruct in 5 "
-                               "seconds.  Have a nice day...\n");
-       }
        /* Errors at this stage are irrelevant. */
 err_out_now:
        sb->s_fs_info = NULL;
index 5cfeee11815881b04a3250d42a72838e40289200..f1e962cb3b73084699a182933b7760926c36880e 100644 (file)
@@ -165,7 +165,7 @@ int ocfs2_get_block(struct inode *inode, sector_t iblock,
         * ocfs2 never allocates in this function - the only time we
         * need to use BH_New is when we're extending i_size on a file
         * system which doesn't support holes, in which case BH_New
-        * allows block_prepare_write() to zero.
+        * allows __block_write_begin() to zero.
         *
         * If we see this on a sparse file system, then a truncate has
         * raced us and removed the cluster. In this case, we clear
@@ -407,21 +407,6 @@ static int ocfs2_writepage(struct page *page, struct writeback_control *wbc)
        return ret;
 }
 
-/*
- * This is called from ocfs2_write_zero_page() which has handled it's
- * own cluster locking and has ensured allocation exists for those
- * blocks to be written.
- */
-int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
-                              unsigned from, unsigned to)
-{
-       int ret;
-
-       ret = block_prepare_write(page, from, to, ocfs2_get_block);
-
-       return ret;
-}
-
 /* Taken from ext3. We don't necessarily need the full blown
  * functionality yet, but IMHO it's better to cut and paste the whole
  * thing so we can avoid introducing our own bugs (and easily pick up
@@ -732,7 +717,7 @@ static int ocfs2_should_read_blk(struct inode *inode, struct page *page,
 }
 
 /*
- * Some of this taken from block_prepare_write(). We already have our
+ * Some of this taken from __block_write_begin(). We already have our
  * mapping by now though, and the entire write will be allocating or
  * it won't, so not much need to use BH_New.
  *
index 7606f663da6d1e1181dac172736ed9dfbbb3fd84..76bfdfda691a03b1790ac9670a8bb79d042e7584 100644 (file)
@@ -22,9 +22,6 @@
 #ifndef OCFS2_AOPS_H
 #define OCFS2_AOPS_H
 
-int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
-                              unsigned from, unsigned to);
-
 handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
                                                         struct page *page,
                                                         unsigned from,
index a7ebd9d42dc8853e89dd381af65afeab3e5df8fe..75e115f1bd730d2b12d4e1d924d203a5864d5150 100644 (file)
@@ -400,6 +400,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
        if (inode) {
                ip = DLMFS_I(inode);
 
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = current_fsuid();
                inode->i_gid = current_fsgid();
@@ -425,6 +426,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
        if (!inode)
                return NULL;
 
+       inode->i_ino = get_next_ino();
        inode->i_mode = mode;
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
index 1ca6867935bbc62e4f733f703951d9f39c7bab93..77b4c04a2809831e7209d1be3f8e860a0ba7edc8 100644 (file)
@@ -796,13 +796,12 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
                block_end = block_start + (1 << inode->i_blkbits);
 
                /*
-                * block_start is block-aligned.  Bump it by one to
-                * force ocfs2_{prepare,commit}_write() to zero the
+                * block_start is block-aligned.  Bump it by one to force
+                * __block_write_begin and block_commit_write to zero the
                 * whole block.
                 */
-               ret = ocfs2_prepare_write_nolock(inode, page,
-                                                block_start + 1,
-                                                block_start + 1);
+               ret = __block_write_begin(page, block_start + 1, 0,
+                                         ocfs2_get_block);
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out_unlock;
index e7bde21149aee4f4e1dfed501069358927a064d7..ff5744e1e36fcb9200158eb419abc3ebdf33ec5b 100644 (file)
@@ -742,7 +742,7 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto out_commit;
        }
 
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        dentry->d_op = &ocfs2_dentry_ops;
        d_instantiate(dentry, inode);
 
index b81bfc016a0549a0c5bc1c4be725cf3c4b30352d..0a8b0ad0c7e25c803ca57a9a814934620ad80039 100644 (file)
@@ -365,25 +365,17 @@ struct device_type part_type = {
 static void delete_partition_rcu_cb(struct rcu_head *head)
 {
        struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
-       struct gendisk *disk = part_to_disk(part);
-       struct request_queue *q = disk->queue;
-       unsigned long flags;
 
        part->start_sect = 0;
        part->nr_sects = 0;
        part_stat_set_all(part, 0);
        put_device(part_to_dev(part));
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       elv_quiesce_end(q);
-       spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
 void delete_partition(struct gendisk *disk, int partno)
 {
        struct disk_part_tbl *ptbl = disk->part_tbl;
        struct hd_struct *part;
-       struct request_queue *q = disk->queue;
 
        if (partno >= ptbl->len)
                return;
@@ -398,10 +390,6 @@ void delete_partition(struct gendisk *disk, int partno)
        kobject_put(part->holder_dir);
        device_del(part_to_dev(part));
 
-       spin_lock_irq(q->queue_lock);
-       elv_quiesce_start(q);
-       spin_unlock_irq(q->queue_lock);
-
        call_rcu(&part->rcu_head, delete_partition_rcu_cb);
 }
 
index 37eb1ebeaa906ea068f940e6298f8cd632feacb4..d2d7566ce68e5cb4fc9713e531670d8f05d52d02 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -954,6 +954,8 @@ static struct inode * get_pipe_inode(void)
        if (!inode)
                goto fail_inode;
 
+       inode->i_ino = get_next_ino();
+
        pipe = alloc_pipe_info(inode);
        if (!pipe)
                goto fail_iput;
index 50f8f0600f0657d47de7081883f7dfe0fa460b69..6a0068841d96c00ef3b1bbc38182bf1db9b54f17 100644 (file)
@@ -33,8 +33,8 @@ config PROC_KCORE
        depends on PROC_FS && MMU
 
 config PROC_VMCORE
-        bool "/proc/vmcore support (EXPERIMENTAL)"
-        depends on PROC_FS && CRASH_DUMP
+       bool "/proc/vmcore support"
+       depends on PROC_FS && CRASH_DUMP
        default y
         help
         Exports the dump image of crashed kernel in ELF format.
index dc5d5f51f3fe4dc564a19e06cb330d09abc9b6a4..9b094c1c846542160ff6c265171467d5ef0050ff 100644 (file)
@@ -771,6 +771,8 @@ static const struct file_operations proc_single_file_operations = {
 static int mem_open(struct inode* inode, struct file* file)
 {
        file->private_data = (void*)((long)current->self_exec_id);
+       /* OK to pass negative loff_t, we can catch out-of-range */
+       file->f_mode |= FMODE_UNSIGNED_OFFSET;
        return 0;
 }
 
@@ -1023,28 +1025,47 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
-       if (copy_from_user(buffer, buf, count))
-               return -EFAULT;
+       if (copy_from_user(buffer, buf, count)) {
+               err = -EFAULT;
+               goto out;
+       }
 
        err = strict_strtol(strstrip(buffer), 0, &oom_adjust);
        if (err)
-               return -EINVAL;
+               goto out;
        if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
-            oom_adjust != OOM_DISABLE)
-               return -EINVAL;
+            oom_adjust != OOM_DISABLE) {
+               err = -EINVAL;
+               goto out;
+       }
 
        task = get_proc_task(file->f_path.dentry->d_inode);
-       if (!task)
-               return -ESRCH;
+       if (!task) {
+               err = -ESRCH;
+               goto out;
+       }
+
+       task_lock(task);
+       if (!task->mm) {
+               err = -EINVAL;
+               goto err_task_lock;
+       }
+
        if (!lock_task_sighand(task, &flags)) {
-               put_task_struct(task);
-               return -ESRCH;
+               err = -ESRCH;
+               goto err_task_lock;
        }
 
        if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) {
-               unlock_task_sighand(task, &flags);
-               put_task_struct(task);
-               return -EACCES;
+               err = -EACCES;
+               goto err_sighand;
+       }
+
+       if (oom_adjust != task->signal->oom_adj) {
+               if (oom_adjust == OOM_DISABLE)
+                       atomic_inc(&task->mm->oom_disable_count);
+               if (task->signal->oom_adj == OOM_DISABLE)
+                       atomic_dec(&task->mm->oom_disable_count);
        }
 
        /*
@@ -1065,10 +1086,13 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        else
                task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
                                                                -OOM_DISABLE;
+err_sighand:
        unlock_task_sighand(task, &flags);
+err_task_lock:
+       task_unlock(task);
        put_task_struct(task);
-
-       return count;
+out:
+       return err < 0 ? err : count;
 }
 
 static const struct file_operations proc_oom_adjust_operations = {
@@ -1109,30 +1133,49 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
-       if (copy_from_user(buffer, buf, count))
-               return -EFAULT;
+       if (copy_from_user(buffer, buf, count)) {
+               err = -EFAULT;
+               goto out;
+       }
 
        err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
        if (err)
-               return -EINVAL;
+               goto out;
        if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
-                       oom_score_adj > OOM_SCORE_ADJ_MAX)
-               return -EINVAL;
+                       oom_score_adj > OOM_SCORE_ADJ_MAX) {
+               err = -EINVAL;
+               goto out;
+       }
 
        task = get_proc_task(file->f_path.dentry->d_inode);
-       if (!task)
-               return -ESRCH;
+       if (!task) {
+               err = -ESRCH;
+               goto out;
+       }
+
+       task_lock(task);
+       if (!task->mm) {
+               err = -EINVAL;
+               goto err_task_lock;
+       }
+
        if (!lock_task_sighand(task, &flags)) {
-               put_task_struct(task);
-               return -ESRCH;
+               err = -ESRCH;
+               goto err_task_lock;
        }
+
        if (oom_score_adj < task->signal->oom_score_adj &&
                        !capable(CAP_SYS_RESOURCE)) {
-               unlock_task_sighand(task, &flags);
-               put_task_struct(task);
-               return -EACCES;
+               err = -EACCES;
+               goto err_sighand;
        }
 
+       if (oom_score_adj != task->signal->oom_score_adj) {
+               if (oom_score_adj == OOM_SCORE_ADJ_MIN)
+                       atomic_inc(&task->mm->oom_disable_count);
+               if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+                       atomic_dec(&task->mm->oom_disable_count);
+       }
        task->signal->oom_score_adj = oom_score_adj;
        /*
         * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
@@ -1143,9 +1186,13 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
        else
                task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
                                                        OOM_SCORE_ADJ_MAX;
+err_sighand:
        unlock_task_sighand(task, &flags);
+err_task_lock:
+       task_unlock(task);
        put_task_struct(task);
-       return count;
+out:
+       return err < 0 ? err : count;
 }
 
 static const struct file_operations proc_oom_score_adj_operations = {
@@ -1601,6 +1648,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
 
        /* Common stuff */
        ei = PROC_I(inode);
+       inode->i_ino = get_next_ino();
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_op = &proc_def_inode_operations;
 
@@ -2547,6 +2595,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
 
        /* Initialize the inode */
        ei = PROC_I(inode);
+       inode->i_ino = get_next_ino();
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 
        /*
index 2fc52552271d91cf904213ee98576e20237ec1da..b652cb00906b02927c7f4afa048d6bd83615936d 100644 (file)
@@ -23,6 +23,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
        if (!inode)
                goto out;
 
+       inode->i_ino = get_next_ino();
+
        sysctl_head_get(head);
        ei = PROC_I(inode);
        ei->sysctl = head;
index a5ebae70dc6d4c90213770630f185d56ec6d6009..67fadb1ad2c11a6428480aad801ee616d90eebac 100644 (file)
@@ -58,6 +58,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
        struct inode * inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode_init_owner(inode, dir, mode);
                inode->i_mapping->a_ops = &ramfs_aops;
                inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
index e757ef26e4cecb6d47fd628b32f204e90c4b8497..9cd9d148105d287b55c9f60af4034f300cc6d1af 100644 (file)
@@ -31,6 +31,20 @@ const struct file_operations generic_ro_fops = {
 
 EXPORT_SYMBOL(generic_ro_fops);
 
+static int
+__negative_fpos_check(struct file *file, loff_t pos, size_t count)
+{
+       /*
+        * pos or pos+count is negative here, check overflow.
+        * too big "count" will be caught in rw_verify_area().
+        */
+       if ((pos < 0) && (pos + count < pos))
+               return -EOVERFLOW;
+       if (file->f_mode & FMODE_UNSIGNED_OFFSET)
+               return 0;
+       return -EINVAL;
+}
+
 /**
  * generic_file_llseek_unlocked - lockless generic llseek implementation
  * @file:      file structure to seek on
@@ -62,7 +76,9 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
                break;
        }
 
-       if (offset < 0 || offset > inode->i_sb->s_maxbytes)
+       if (offset < 0 && __negative_fpos_check(file, offset, 0))
+               return -EINVAL;
+       if (offset > inode->i_sb->s_maxbytes)
                return -EINVAL;
 
        /* Special lock needed here? */
@@ -137,7 +153,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
                        offset += file->f_pos;
        }
        retval = -EINVAL;
-       if (offset >= 0) {
+       if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) {
                if (offset != file->f_pos) {
                        file->f_pos = offset;
                        file->f_version = 0;
@@ -221,6 +237,7 @@ bad:
 }
 #endif
 
+
 /*
  * rw_verify_area doesn't like huge counts. We limit
  * them to something that fits in "int" so that others
@@ -238,8 +255,11 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
        if (unlikely((ssize_t) count < 0))
                return retval;
        pos = *ppos;
-       if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
-               return retval;
+       if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) {
+               retval = __negative_fpos_check(file, pos, count);
+               if (retval)
+                       return retval;
+       }
 
        if (unlikely(inode->i_flock && mandatory_lock(inode))) {
                retval = locks_mandatory_area(
index caa758377d66b8ba5530d029635d8cdfa98048ba..41656d40dc5c87fc8bcfd9ec5aea4bc635ebc092 100644 (file)
@@ -22,8 +22,6 @@
 
 int reiserfs_commit_write(struct file *f, struct page *page,
                          unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
-                          unsigned from, unsigned to);
 
 void reiserfs_evict_inode(struct inode *inode)
 {
@@ -165,7 +163,7 @@ inline void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
 ** but tail is still sitting in a direct item, and we can't write to
 ** it.  So, look through this page, and check all the mapped buffers
 ** to make sure they have valid block numbers.  Any that don't need
-** to be unmapped, so that block_prepare_write will correctly call
+** to be unmapped, so that __block_write_begin will correctly call
 ** reiserfs_get_block to convert the tail into an unformatted node
 */
 static inline void fix_tail_page_for_writing(struct page *page)
@@ -439,13 +437,13 @@ static int reiserfs_bmap(struct inode *inode, sector_t block,
 }
 
 /* special version of get_block that is only used by grab_tail_page right
-** now.  It is sent to block_prepare_write, and when you try to get a
+** now.  It is sent to __block_write_begin, and when you try to get a
 ** block past the end of the file (or a block from a hole) it returns
-** -ENOENT instead of a valid buffer.  block_prepare_write expects to
+** -ENOENT instead of a valid buffer.  __block_write_begin expects to
 ** be able to do i/o on the buffers returned, unless an error value
 ** is also returned.
 **
-** So, this allows block_prepare_write to be used for reading a single block
+** So, this allows __block_write_begin to be used for reading a single block
 ** in a page.  Where it does not produce a valid page for holes, or past the
 ** end of the file.  This turns out to be exactly what we need for reading
 ** tails for conversion.
@@ -558,11 +556,12 @@ static int convert_tail_for_hole(struct inode *inode,
         **
         ** We must fix the tail page for writing because it might have buffers
         ** that are mapped, but have a block number of 0.  This indicates tail
-        ** data that has been read directly into the page, and block_prepare_write
-        ** won't trigger a get_block in this case.
+        ** data that has been read directly into the page, and
+        ** __block_write_begin won't trigger a get_block in this case.
         */
        fix_tail_page_for_writing(tail_page);
-       retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end);
+       retval = __reiserfs_write_begin(tail_page, tail_start,
+                                     tail_end - tail_start);
        if (retval)
                goto unlock;
 
@@ -2033,7 +2032,7 @@ static int grab_tail_page(struct inode *inode,
        /* start within the page of the last block in the file */
        start = (offset / blocksize) * blocksize;
 
-       error = block_prepare_write(page, start, offset,
+       error = __block_write_begin(page, start, offset - start,
                                    reiserfs_get_block_create_0);
        if (error)
                goto unlock;
@@ -2438,7 +2437,7 @@ static int reiserfs_write_full_page(struct page *page,
                /* from this point on, we know the buffer is mapped to a
                 * real block and not a direct item
                 */
-               if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+               if (wbc->sync_mode != WB_SYNC_NONE) {
                        lock_buffer(bh);
                } else {
                        if (!trylock_buffer(bh)) {
@@ -2628,8 +2627,7 @@ static int reiserfs_write_begin(struct file *file,
        return ret;
 }
 
-int reiserfs_prepare_write(struct file *f, struct page *page,
-                          unsigned from, unsigned to)
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len)
 {
        struct inode *inode = page->mapping->host;
        int ret;
@@ -2650,7 +2648,7 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
                th->t_refcount++;
        }
 
-       ret = block_prepare_write(page, from, to, reiserfs_get_block);
+       ret = __block_write_begin(page, from, len, reiserfs_get_block);
        if (ret && reiserfs_transaction_running(inode->i_sb)) {
                struct reiserfs_transaction_handle *th = current->journal_info;
                /* this gets a little ugly.  If reiserfs_get_block returned an
index 5cbb81e134aca031b21e3c88661400ff1c1b174f..adf22b485ceac01e0f5ed7b0a8d1593956a7b81f 100644 (file)
@@ -160,8 +160,6 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
 
 int reiserfs_commit_write(struct file *f, struct page *page,
                          unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
-                          unsigned from, unsigned to);
 /*
 ** reiserfs_unpack
 ** Function try to convert tail from direct item into indirect.
@@ -200,7 +198,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp)
        }
 
        /* we unpack by finding the page with the tail, and calling
-        ** reiserfs_prepare_write on that page.  This will force a
+        ** __reiserfs_write_begin on that page.  This will force a
         ** reiserfs_get_block to unpack the tail for us.
         */
        index = inode->i_size >> PAGE_CACHE_SHIFT;
@@ -210,7 +208,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp)
        if (!page) {
                goto out;
        }
-       retval = reiserfs_prepare_write(NULL, page, write_from, write_from);
+       retval = __reiserfs_write_begin(page, write_from, 0);
        if (retval)
                goto out_unlock;
 
index ee78d4a0086a983609749a72ec0fb840615255fd..ba5f51ec345829499982f17196fc61ac444429a0 100644 (file)
@@ -1156,7 +1156,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
        inode->i_ctime = CURRENT_TIME_SEC;
        reiserfs_update_sd(&th, inode);
 
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(dentry, inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
        reiserfs_write_unlock(dir->i_sb);
index 8c4cf273c672185fe7cb4c5d0a6e30ddc85e5bf3..5d04a7828e7a4ee05d27446cbc8ee7fdfb433ad9 100644 (file)
@@ -418,13 +418,11 @@ static inline __u32 xattr_hash(const char *msg, int len)
 
 int reiserfs_commit_write(struct file *f, struct page *page,
                          unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
-                          unsigned from, unsigned to);
 
 static void update_ctime(struct inode *inode)
 {
        struct timespec now = current_fs_time(inode->i_sb);
-       if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink ||
+       if (inode_unhashed(inode) || !inode->i_nlink ||
            timespec_equal(&inode->i_ctime, &now))
                return;
 
@@ -532,8 +530,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
                        rxh->h_hash = cpu_to_le32(xahash);
                }
 
-               err = reiserfs_prepare_write(NULL, page, page_offset,
-                                           page_offset + chunk + skip);
+               err = __reiserfs_write_begin(page, page_offset, chunk + skip);
                if (!err) {
                        if (buffer)
                                memcpy(data + skip, buffer + buffer_pos, chunk);
index 0e7cb1395a94cfb2c98aad791672576315b88526..05d6b0e78c959a341137c97fbb2ea2fa89b25197 100644 (file)
@@ -462,9 +462,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
        if (size) {
                char *p;
 
-               spin_lock(&dcache_lock);
                p = __d_path(path, root, buf, size);
-               spin_unlock(&dcache_lock);
                res = PTR_ERR(p);
                if (!IS_ERR(p)) {
                        char *end = mangle_path(buf, p, esc);
index 74047304b01a4300bf7f781ad4d2838dc3bc316b..492465b451ddd34f6f60214fb48224687649faa9 100644 (file)
@@ -98,6 +98,16 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr);
 #ifdef __ARCH_SI_TRAPNO
                err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
+#endif
+#ifdef BUS_MCEERR_AO
+               /* 
+                * Other callers might not initialize the si_lsb field,
+                * so check explicitly for the right codes here.
+                */
+               if (kinfo->si_code == BUS_MCEERR_AR ||
+                   kinfo->si_code == BUS_MCEERR_AO)
+                       err |= __put_user((short) kinfo->si_addr_lsb,
+                                         &uinfo->ssi_addr_lsb);
 #endif
                break;
        case __SI_CHLD:
index 00a70cab1f36ea7fc7bd96317d4bccdd8486a736..f678d421e54166917f7c8ca7cf3a51632cbd1d52 100644 (file)
@@ -406,21 +406,15 @@ void
 smb_renew_times(struct dentry * dentry)
 {
        dget(dentry);
-       spin_lock(&dentry->d_lock);
-       for (;;) {
-               struct dentry *parent;
+       dentry->d_time = jiffies;
 
-               dentry->d_time = jiffies;
-               if (IS_ROOT(dentry))
-                       break;
-               parent = dentry->d_parent;
-               dget(parent);
-               spin_unlock(&dentry->d_lock);
+       while (!IS_ROOT(dentry)) {
+               struct dentry *parent = dget_parent(dentry);
                dput(dentry);
                dentry = parent;
-               spin_lock(&dentry->d_lock);
+
+               dentry->d_time = jiffies;
        }
-       spin_unlock(&dentry->d_lock);
        dput(dentry);
 }
 
index 8fc5e50e142fad71ad05aa38f726ae0d6d4ca566..f6e9ee59757ec29c11be43e6fcab2713bab2562e 100644 (file)
@@ -229,7 +229,6 @@ smb_invalidate_inodes(struct smb_sb_info *server)
 {
        VERBOSE("\n");
        shrink_dcache_sb(SB_of(server));
-       invalidate_inodes(SB_of(server));
 }
 
 /*
index 71c29b6670b402719f8475ed34b39a306bda807d..3dcf638d4d3a0ff836fd9aba946361edd894b630 100644 (file)
@@ -332,16 +332,15 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
         * and store it in reversed order [see reverse_string()]
         */
        dget(entry);
-       spin_lock(&entry->d_lock);
        while (!IS_ROOT(entry)) {
                struct dentry *parent;
 
                if (maxlen < (3<<unicode)) {
-                       spin_unlock(&entry->d_lock);
                        dput(entry);
                        return -ENAMETOOLONG;
                }
 
+               spin_lock(&entry->d_lock);
                len = server->ops->convert(path, maxlen-2, 
                                      entry->d_name.name, entry->d_name.len,
                                      server->local_nls, server->remote_nls);
@@ -359,15 +358,12 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
                }
                *path++ = '\\';
                maxlen -= len+1;
-
-               parent = entry->d_parent;
-               dget(parent);
                spin_unlock(&entry->d_lock);
+
+               parent = dget_parent(entry);
                dput(entry);
                entry = parent;
-               spin_lock(&entry->d_lock);
        }
-       spin_unlock(&entry->d_lock);
        dput(entry);
        reverse_string(buf, path-buf);
 
index 8819e3a7ff203fb521b537672d16d5e2d4cea80d..b9c9869165db359d018134e99e0a39e2738e6dba 100644 (file)
@@ -273,14 +273,14 @@ void generic_shutdown_super(struct super_block *sb)
                get_fs_excl();
                sb->s_flags &= ~MS_ACTIVE;
 
-               /* bad name - it should be evict_inodes() */
-               invalidate_inodes(sb);
+               fsnotify_unmount_inodes(&sb->s_inodes);
+
+               evict_inodes(sb);
 
                if (sop->put_super)
                        sop->put_super(sb);
 
-               /* Forget any remaining inodes */
-               if (invalidate_inodes(sb)) {
+               if (!list_empty(&sb->s_inodes)) {
                        printk("VFS: Busy inodes after unmount of %s. "
                           "Self-destruct in 5 seconds.  Have a nice day...\n",
                           sb->s_id);
index 33e047b59b8d659975d6c325835f0d11a2df27d4..11e7f7d11cd06fe85bf694397d3608b805db1fe3 100644 (file)
@@ -126,7 +126,7 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        return add_nondir(dentry, inode);
 }
index 87ebcce72213e2889f66127125908190a4ef213d..14f64b689d7f58edef4be03d58a8712c442f62ef 100644 (file)
@@ -550,7 +550,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 
        lock_2_inodes(dir, inode);
        inc_nlink(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        inode->i_ctime = ubifs_current_time(inode);
        dir->i_size += sz_change;
        dir_ui->ui_size = dir->i_size;
index bf5fc674193c8bba9e5e31589ba883d49f106270..6d8dc02baebb57e05e5839464b24e8f443263546 100644 (file)
@@ -1101,7 +1101,7 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        inc_nlink(inode);
        inode->i_ctime = current_fs_time(inode->i_sb);
        mark_inode_dirty(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(dentry, inode);
        unlock_kernel();
 
index b056f02b1fb306c810f4b429ae99417a8f6238e5..12f39b9e4437db73784cd77b8e7f898457d157db 100644 (file)
@@ -180,7 +180,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
 
        error = ufs_add_nondir(dentry, inode);
        unlock_kernel();
index b552f816de15942095f82ad0302b8656f7db09ae..c9af48fffcd77fc559f73d5d97317e22ec4d3413 100644 (file)
@@ -1139,8 +1139,7 @@ xfs_vm_writepage(
                                type = IO_DELAY;
                                flags = BMAPI_ALLOCATE;
 
-                               if (wbc->sync_mode == WB_SYNC_NONE &&
-                                   wbc->nonblocking)
+                               if (wbc->sync_mode == WB_SYNC_NONE)
                                        flags |= BMAPI_TRYLOCK;
                        }
 
index ba5312802aa99dfe266148b90d9dfa8e3f54e19d..63fd2c07cb57d861837bf463d9ad7b3aa5392088 100644 (file)
@@ -1580,6 +1580,7 @@ xfs_mapping_buftarg(
                        XFS_BUFTARG_NAME(btp));
                return ENOMEM;
        }
+       inode->i_ino = get_next_ino();
        inode->i_mode = S_IFBLK;
        inode->i_bdev = bdev;
        inode->i_rdev = bdev->bd_dev;
index ec858e09d546bf3bf34ca1dcbe0f7b74cb52ffa9..96107efc0c61908c3f1a94a646604836fc2131e1 100644 (file)
@@ -317,7 +317,7 @@ xfs_vn_link(
        if (unlikely(error))
                return -error;
 
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(dentry, inode);
        return 0;
 }
@@ -760,7 +760,9 @@ xfs_setup_inode(
 
        inode->i_ino = ip->i_ino;
        inode->i_state = I_NEW;
-       inode_add_to_lists(ip->i_mount->m_super, inode);
+
+       inode_sb_list_add(inode);
+       insert_inode_hash(inode);
 
        inode->i_mode   = ip->i_d.di_mode;
        inode->i_nlink  = ip->i_d.di_nlink;
index ab31ce5aeaf9cde4c5c008e1492c7a42f5399863..cf808782c0650d86e967e149a8fac2baf80dd093 100644 (file)
@@ -576,7 +576,7 @@ xfs_max_file_offset(
 
        /* Figure out maximum filesize, on Linux this can depend on
         * the filesystem blocksize (on 32 bit platforms).
-        * __block_prepare_write does this in an [unsigned] long...
+        * __block_write_begin does this in an [unsigned] long...
         *      page->index << (PAGE_CACHE_SHIFT - bbits)
         * So, for page sized blocks (4K on 32 bit platforms),
         * this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is
index fac52290de90c050b6ab0c9ea5d208541cd4c839..fb2ca2e4cdc935c112d1504a85aca3130f511179 100644 (file)
@@ -500,7 +500,7 @@ void                xfs_mark_inode_dirty_sync(xfs_inode_t *);
 #define IHOLD(ip) \
 do { \
        ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
-       atomic_inc(&(VFS_I(ip)->i_count)); \
+       ihold(VFS_I(ip)); \
        trace_xfs_ihold(ip, _THIS_IP_); \
 } while (0)
 
index 4de84ce3a927123f118861df950202a8dba1a536..359ef11725a65da5bf6d07d8fc0cccee33be803f 100644 (file)
@@ -184,7 +184,7 @@ struct acpi_device_pnp {
 
 #define acpi_device_bid(d)     ((d)->pnp.bus_id)
 #define acpi_device_adr(d)     ((d)->pnp.bus_address)
-char *acpi_device_hid(struct acpi_device *device);
+const char *acpi_device_hid(struct acpi_device *device);
 #define acpi_device_name(d)    ((d)->pnp.device_name)
 #define acpi_device_class(d)   ((d)->pnp.device_class)
 
@@ -389,21 +389,25 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
 int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
 int acpi_pm_device_sleep_state(struct device *, int *);
-int acpi_pm_device_sleep_wake(struct device *, bool);
-#else /* !CONFIG_PM_SLEEP */
+#else
 static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
 {
        if (p)
                *p = ACPI_STATE_D0;
        return ACPI_STATE_D3;
 }
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+int acpi_pm_device_sleep_wake(struct device *, bool);
+#else
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
        return -ENODEV;
 }
-#endif /* !CONFIG_PM_SLEEP */
+#endif
 
 #endif                         /* CONFIG_ACPI */
 
index 23d78b4d088b70eeb95f5ab9737fded3044ec910..3090471b2a5ef6069927b82c9bbea9bec8b2590e 100644 (file)
@@ -115,8 +115,6 @@ void pci_acpi_crs_quirks(void);
 #define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01
 #define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02
 
-int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
-
 /*--------------------------------------------------------------------------
                                   Dock Station
   -------------------------------------------------------------------------- */
index 29bf945143e8358e4fd46ed8d98bf2f007c0e227..65b3f5888f42749510f4d51f7d9a0bed43e770bf 100644 (file)
@@ -98,8 +98,6 @@ acpi_os_table_override(struct acpi_table_header *existing_table,
 /*
  * Spinlock primitives
  */
-acpi_status acpi_os_create_lock(acpi_spinlock * out_handle);
-
 void acpi_os_delete_lock(acpi_spinlock handle);
 
 acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock handle);
@@ -223,25 +221,15 @@ acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width);
  */
 acpi_status
 acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id,
-                              u32 reg, u32 *value, u32 width);
+                              u32 reg, u64 *value, u32 width);
 
 acpi_status
 acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id,
                                u32 reg, u64 value, u32 width);
 
-/*
- * Interim function needed for PCI IRQ routing
- */
-void
-acpi_os_derive_pci_id(acpi_handle device,
-                     acpi_handle region, struct acpi_pci_id **pci_id);
-
 /*
  * Miscellaneous
  */
-acpi_status acpi_os_validate_interface(char *interface);
-acpi_status acpi_osi_invalidate(char* interface);
-
 acpi_status
 acpi_os_validate_address(u8 space_id, acpi_physical_address address,
                         acpi_size length, char *name);
index 984cdc62e30bc52da4cef907f3dd5094aa5ffd71..53b7cfd924a300ec924ca0cea5ed9dde18ba8e40 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20100702
+#define ACPI_CA_VERSION                 0x20101013
 
 #include "actypes.h"
 #include "actbl.h"
@@ -72,6 +72,7 @@ extern u8 acpi_gbl_truncate_io_addresses;
 
 extern u32 acpi_current_gpe_count;
 extern struct acpi_table_fadt acpi_gbl_FADT;
+extern u8 acpi_gbl_system_awake_and_running;
 
 extern u32 acpi_rsdt_forced;
 /*
@@ -105,6 +106,10 @@ const char *acpi_format_exception(acpi_status exception);
 
 acpi_status acpi_purge_cached_objects(void);
 
+acpi_status acpi_install_interface(acpi_string interface_name);
+
+acpi_status acpi_remove_interface(acpi_string interface_name);
+
 /*
  * ACPI Memory management
  */
@@ -263,6 +268,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 acpi_status acpi_install_exception_handler(acpi_exception_handler handler);
 #endif
 
+acpi_status acpi_install_interface_handler(acpi_interface_handler handler);
+
 /*
  * Event interfaces
  */
@@ -308,6 +315,8 @@ acpi_install_gpe_block(acpi_handle gpe_device,
 
 acpi_status acpi_remove_gpe_block(acpi_handle gpe_device);
 
+acpi_status acpi_update_gpes(void);
+
 /*
  * Resource interfaces
  */
index 5db8f472fec992205455a4924f7bc0e484743293..2b134b691e349dbbab0f87966e96e3d70185e4f5 100644 (file)
  *
  * ACPI_SIZE        16/32/64-bit unsigned value
  * ACPI_NATIVE_INT  16/32/64-bit signed value
- *
  */
 
 /*******************************************************************************
@@ -132,6 +131,16 @@ typedef COMPILER_DEPENDENT_INT64 INT64;
 
 /*! [End] no source code translation !*/
 
+/*
+ * Value returned by acpi_os_get_thread_id. There is no standard "thread_id"
+ * across operating systems or even the various UNIX systems. Since ACPICA
+ * only needs the thread ID as a unique thread identifier, we use a u64
+ * as the only common data type - it will accommodate any type of pointer or
+ * any type of integer. It is up to the host-dependent OSL to cast the
+ * native thread ID type to a u64 (in acpi_os_get_thread_id).
+ */
+#define acpi_thread_id                  u64
+
 /*******************************************************************************
  *
  * Types specific to 64-bit targets
@@ -211,12 +220,6 @@ typedef u32 acpi_physical_address;
  *
  ******************************************************************************/
 
-/* Value returned by acpi_os_get_thread_id */
-
-#ifndef acpi_thread_id
-#define acpi_thread_id                 acpi_size
-#endif
-
 /* Flags for acpi_os_acquire_lock/acpi_os_release_lock */
 
 #ifndef acpi_cpu_flags
@@ -375,16 +378,6 @@ typedef void *acpi_handle; /* Actually a ptr to a NS Node */
 typedef u8 acpi_owner_id;
 #define ACPI_OWNER_ID_MAX               0xFF
 
-struct uint64_struct {
-       u32 lo;
-       u32 hi;
-};
-
-union uint64_overlay {
-       u64 full;
-       struct uint64_struct part;
-};
-
 #define ACPI_INTEGER_BIT_SIZE           64
 #define ACPI_MAX_DECIMAL_DIGITS         20     /* 2^64 = 18,446,744,073,709,551,616 */
 
@@ -950,6 +943,9 @@ acpi_status(*acpi_walk_callback) (acpi_handle object,
                                  u32 nesting_level,
                                  void *context, void **return_value);
 
+typedef
+u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported);
+
 /* Interrupt handler return values */
 
 #define ACPI_INTERRUPT_NOT_HANDLED      0x00
index c05aeba9e8f0e42a3441a66c75b02b0a973a046d..a3e334ab11191aeb596b93cfc28a7c4dcef85d4d 100644 (file)
 #define ACPI_MUTEX_TYPE             ACPI_BINARY_SEMAPHORE
 #endif
 
+/* "inline" keywords - configurable since inline is not standardized */
+
+#ifndef ACPI_INLINE
+#define ACPI_INLINE
+#endif
+
 /*
  * Debugger threading model
  * Use single threaded if the entire subsystem is contained in an application
index 0cd53e3cd1a37789bb54edf99ec843df82c3b025..5dcb9537343c7a91d82317dd4e50aa7d385149f5 100644 (file)
@@ -44,6 +44,8 @@
 #ifndef __ACGCC_H__
 #define __ACGCC_H__
 
+#define ACPI_INLINE             __inline__
+
 /* Function name is used for debug output. Non-ANSI, compiler-dependent */
 
 #define ACPI_GET_FUNCTION_NAME          __func__
index 103f08aca764e23ffe81d9ee6da4fd6206e3de7b..572189e37133d697db734ff2d8e10c1707917463 100644 (file)
@@ -75,7 +75,6 @@
 #define acpi_cache_t                        struct kmem_cache
 #define acpi_spinlock                       spinlock_t *
 #define acpi_cpu_flags                      unsigned long
-#define acpi_thread_id                      struct task_struct *
 
 #else /* !__KERNEL__ */
 
@@ -88,7 +87,7 @@
 /* Host-dependent types and defines for user-space ACPICA */
 
 #define ACPI_FLUSH_CPU_CACHE()
-#define acpi_thread_id                      pthread_t
+#define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread))
 
 #if defined(__ia64__) || defined(__x86_64__)
 #define ACPI_MACHINE_WIDTH          64
 
 
 #ifdef __KERNEL__
+#include <acpi/actypes.h>
 /*
  * Overrides for in-kernel ACPICA
  */
 static inline acpi_thread_id acpi_os_get_thread_id(void)
 {
-       return current;
+       return (acpi_thread_id)(unsigned long)current;
 }
 
 /*
@@ -127,7 +127,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
  * However, boot has  (system_state != SYSTEM_RUNNING)
  * to quiet __might_sleep() in kmalloc() and resume does not.
  */
-#include <acpi/actypes.h>
 static inline void *acpi_os_allocate(acpi_size size)
 {
        return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
index f4d4120e5128a8fe76580286151017ddb68c497b..6f3c6ae4fe03381755264f7d58b9b5ba57fc286f 100644 (file)
@@ -108,7 +108,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
 #endif
 
 #ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY
-#define page_clear_dirty(page)         do { } while (0)
+#define page_clear_dirty(page, mapped) do { } while (0)
 #endif
 
 #ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
index f4229fb315e1d7d81caddb7557cbcb6c65072fed..2c0fc10956baf2123f5f24ed203572874369e206 100644 (file)
 #define DATA_DATA                                                      \
        *(.data)                                                        \
        *(.ref.data)                                                    \
+       *(.data..shared_aligned) /* percpu related */                   \
        DEV_KEEP(init.data)                                             \
        DEV_KEEP(exit.data)                                             \
        CPU_KEEP(init.data)                                             \
 
 #ifdef CONFIG_BLK_DEV_INITRD
 #define INIT_RAM_FS                                                    \
-       . = ALIGN(PAGE_SIZE);                                           \
+       . = ALIGN(4);                                                   \
        VMLINUX_SYMBOL(__initramfs_start) = .;                          \
        *(.init.ramfs)                                                  \
        VMLINUX_SYMBOL(__initramfs_end) = .;
index 4c9461a4f9e67b4b3e67c5bb73192aed44695079..274eaaa15c36a86ee48a6b743f6c9d7cfb36b010 100644 (file)
@@ -699,13 +699,8 @@ struct drm_driver {
        int (*suspend) (struct drm_device *, pm_message_t state);
        int (*resume) (struct drm_device *);
        int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
-       void (*dma_ready) (struct drm_device *);
        int (*dma_quiescent) (struct drm_device *);
-       int (*context_ctor) (struct drm_device *dev, int context);
        int (*context_dtor) (struct drm_device *dev, int context);
-       int (*kernel_context_switch) (struct drm_device *dev, int old,
-                                     int new);
-       void (*kernel_context_switch_unlock) (struct drm_device *dev);
 
        /**
         * get_vblank_counter - get raw hardware vblank counter
@@ -777,8 +772,6 @@ struct drm_driver {
                                        struct drm_file *file_priv);
        void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
                                            struct drm_file *file_priv);
-       resource_size_t (*get_map_ofs) (struct drm_local_map * map);
-       resource_size_t (*get_reg_ofs) (struct drm_device *dev);
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
@@ -795,8 +788,6 @@ struct drm_driver {
        void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv,
                            bool from_release);
 
-       int (*proc_init)(struct drm_minor *minor);
-       void (*proc_cleanup)(struct drm_minor *minor);
        int (*debugfs_init)(struct drm_minor *minor);
        void (*debugfs_cleanup)(struct drm_minor *minor);
 
@@ -972,7 +963,6 @@ struct drm_device {
        __volatile__ long context_flag; /**< Context swapping flag */
        __volatile__ long interrupt_flag; /**< Interruption handler flag */
        __volatile__ long dma_flag;     /**< DMA dispatch flag */
-       struct timer_list timer;        /**< Timer for delaying ctx switch */
        wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */
        int last_checked;               /**< Last context checked for DMA */
        int last_context;               /**< Last current context */
@@ -1045,25 +1035,12 @@ struct drm_device {
        struct drm_minor *control;              /**< Control node for card */
        struct drm_minor *primary;              /**< render type primary screen head */
 
-       /** \name Drawable information */
-       /*@{ */
-       spinlock_t drw_lock;
-       struct idr drw_idr;
-       /*@} */
-
         struct drm_mode_config mode_config;    /**< Current mode config */
 
        /** \name GEM information */
        /*@{ */
        spinlock_t object_name_lock;
        struct idr object_name_idr;
-       atomic_t object_count;
-       atomic_t object_memory;
-       atomic_t pin_count;
-       atomic_t pin_memory;
-       atomic_t gtt_count;
-       atomic_t gtt_memory;
-       uint32_t gtt_total;
        uint32_t invalidate_domains;    /* domains pending invalidation */
        uint32_t flush_domains;         /* domains pending flush */
        /*@} */
@@ -1175,8 +1152,6 @@ 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 void drm_vm_close_locked(struct vm_area_struct *vma);
-extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map);
-extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
                                /* Memory management support (drm_memory.h) */
@@ -1186,8 +1161,7 @@ extern int drm_mem_info(char *buf, char **start, off_t offset,
                        int request, int *eof, void *data);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
 
-extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
-extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
+extern void drm_free_agp(DRM_AGP_MEM * handle, int pages);
 extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
 extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
                                       struct page **pages,
@@ -1239,17 +1213,6 @@ extern int drm_setsareactx(struct drm_device *dev, void *data,
 extern int drm_getsareactx(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);
 
-                               /* Drawable IOCTL support (drm_drawable.h) */
-extern int drm_adddraw(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
-extern int drm_rmdraw(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv);
-extern int drm_update_drawable_info(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
-                                                 drm_drawable_t id);
-extern void drm_drawable_free_all(struct drm_device *dev);
-
                                /* Authentication IOCTL support (drm_auth.h) */
 extern int drm_getmagic(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
@@ -1264,7 +1227,6 @@ extern int drm_lock(struct drm_device *dev, void *data,
                    struct drm_file *file_priv);
 extern int drm_unlock(struct drm_device *dev, void *data,
                      struct drm_file *file_priv);
-extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
 extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
 extern void drm_idlelock_take(struct drm_lock_data *lock_data);
 extern void drm_idlelock_release(struct drm_lock_data *lock_data);
@@ -1359,10 +1321,6 @@ extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
 extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
 extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
-extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
-extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
-extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
-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) */
@@ -1414,7 +1372,6 @@ extern int drm_bufs_info(struct seq_file *m, void *data);
 extern int drm_vblank_info(struct seq_file *m, void *data);
 extern int drm_clients_info(struct seq_file *m, void* data);
 extern int drm_gem_name_info(struct seq_file *m, void *data);
-extern int drm_gem_object_info(struct seq_file *m, void* data);
 
 #if DRM_DEBUG_CODE
 extern int drm_vma_info(struct seq_file *m, void *data);
index 3e5a51af757c76ba07f514d00265a5e7300b6627..029aa688e787c4673c12f38919999982a926e5f6 100644 (file)
@@ -221,7 +221,8 @@ struct drm_framebuffer_funcs {
         * the semantics and arguments have a one to one mapping
         * on this function.
         */
-       int (*dirty)(struct drm_framebuffer *framebuffer, unsigned flags,
+       int (*dirty)(struct drm_framebuffer *framebuffer,
+                    struct drm_file *file_priv, unsigned flags,
                     unsigned color, struct drm_clip_rect *clips,
                     unsigned num_clips);
 };
@@ -762,6 +763,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
 extern bool drm_detect_hdmi_monitor(struct edid *edid);
+extern bool drm_detect_monitor_audio(struct edid *edid);
 extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
 extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
index 59b7073b13fe334815fc3dd290b49e73c4e162d4..73b071203dcc8bf61d65a75bac74524ba579fbcb 100644 (file)
 
 #include <linux/fb.h>
 
+enum mode_set_atomic {
+       LEAVE_ATOMIC_MODE_SET,
+       ENTER_ATOMIC_MODE_SET,
+};
+
 struct drm_crtc_helper_funcs {
        /*
         * Control power levels on the CRTC.  If the mode passed in is
@@ -61,7 +66,8 @@ struct drm_crtc_helper_funcs {
        int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
                             struct drm_framebuffer *old_fb);
        int (*mode_set_base_atomic)(struct drm_crtc *crtc,
-                                   struct drm_framebuffer *fb, int x, int y);
+                                   struct drm_framebuffer *fb, int x, int y,
+                                   enum mode_set_atomic);
 
        /* reload the current crtc LUT */
        void (*load_lut)(struct drm_crtc *crtc);
index a49e791db0b0308f284a17408a7051559102ca1d..83a389e44543f19911efe7726ad48d4dd602f967 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef _DRM_DP_HELPER_H_
 #define _DRM_DP_HELPER_H_
 
+#include <linux/types.h>
+#include <linux/i2c.h>
+
 /* From the VESA DisplayPort spec */
 
 #define AUX_NATIVE_WRITE       0x8
index e41c74facb6a3e41e84e3c66df6395d1a94add76..8c641bed9bbd36526870b6741fdd16f780e3b0ec 100644 (file)
@@ -286,6 +286,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_PAGEFLIPPING     8
 #define I915_PARAM_HAS_EXECBUF2          9
 #define I915_PARAM_HAS_BSD              10
+#define I915_PARAM_HAS_BLT              11
 
 typedef struct drm_i915_getparam {
        int param;
@@ -627,8 +628,11 @@ struct drm_i915_gem_execbuffer2 {
        __u32 num_cliprects;
        /** This is a struct drm_clip_rect *cliprects */
        __u64 cliprects_ptr;
+#define I915_EXEC_RING_MASK              (7<<0)
+#define I915_EXEC_DEFAULT                (0<<0)
 #define I915_EXEC_RENDER                 (1<<0)
-#define I915_EXEC_BSD                    (1<<1)
+#define I915_EXEC_BSD                    (2<<0)
+#define I915_EXEC_BLT                    (3<<0)
        __u64 flags;
        __u64 rsvd1;
        __u64 rsvd2;
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
new file mode 100644 (file)
index 0000000..d3c8194
--- /dev/null
@@ -0,0 +1,18 @@
+/* Common header for intel-gtt.ko and i915.ko */
+
+#ifndef _DRM_INTEL_GTT_H
+#define        _DRM_INTEL_GTT_H
+struct intel_gtt {
+       /* Number of stolen gtt entries at the beginning. */
+       unsigned int gtt_stolen_entries;
+       /* Total number of gtt entries. */
+       unsigned int gtt_total_entries;
+       /* Part of the gtt that is mappable by the cpu, for those chips where
+        * this is not the full gtt. */
+       unsigned int gtt_mappable_entries;
+};
+
+struct intel_gtt *intel_gtt_get(void);
+
+#endif
+
index 2040e6c4f1729a7de3001d5077277b8521427fb9..5afa5b52063e6d385926de88ec49faf1324a185a 100644 (file)
@@ -102,7 +102,8 @@ struct ttm_bus_placement {
  */
 
 struct ttm_mem_reg {
-       struct drm_mm_node *mm_node;
+       void *mm_node;
+       unsigned long start;
        unsigned long size;
        unsigned long num_pages;
        uint32_t page_alignment;
index b87504235f183f45c01d527ae585cbbafbd197ab..d01b4ddbdc56acb88fd1064b0e4580f82aa03b76 100644 (file)
@@ -203,7 +203,22 @@ struct ttm_tt {
  * It's set up by the ttm_bo_driver::init_mem_type method.
  */
 
+struct ttm_mem_type_manager;
+
+struct ttm_mem_type_manager_func {
+       int  (*init)(struct ttm_mem_type_manager *man, unsigned long p_size);
+       int  (*takedown)(struct ttm_mem_type_manager *man);
+       int  (*get_node)(struct ttm_mem_type_manager *man,
+                        struct ttm_buffer_object *bo,
+                        struct ttm_placement *placement,
+                        struct ttm_mem_reg *mem);
+       void (*put_node)(struct ttm_mem_type_manager *man,
+                        struct ttm_mem_reg *mem);
+       void (*debug)(struct ttm_mem_type_manager *man, const char *prefix);
+};
+
 struct ttm_mem_type_manager {
+       struct ttm_bo_device *bdev;
 
        /*
         * No protection. Constant from start.
@@ -222,8 +237,8 @@ struct ttm_mem_type_manager {
         * TODO: Consider one lru_lock per ttm_mem_type_manager.
         * Plays ill with list removal, though.
         */
-
-       struct drm_mm manager;
+       const struct ttm_mem_type_manager_func *func;
+       void *priv;
        struct list_head lru;
 };
 
@@ -649,6 +664,12 @@ extern int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                                struct ttm_mem_reg *mem,
                                bool interruptible,
                                bool no_wait_reserve, bool no_wait_gpu);
+
+extern void ttm_bo_mem_put(struct ttm_buffer_object *bo,
+                          struct ttm_mem_reg *mem);
+extern void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo,
+                                 struct ttm_mem_reg *mem);
+
 /**
  * ttm_bo_wait_for_cpu
  *
@@ -891,6 +912,8 @@ extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
  */
 extern pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp);
 
+extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;
+
 #if (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
 #define TTM_HAS_AGP
 #include <linux/agp_backend.h>
index 4d0842391edc666f8985329fed245b989e3a0c2d..650e6bf6f69f101999d0294497458c3d5100e55f 100644 (file)
@@ -72,6 +72,7 @@
 #define DRM_VMW_PARAM_FIFO_OFFSET      3
 #define DRM_VMW_PARAM_HW_CAPS          4
 #define DRM_VMW_PARAM_FIFO_CAPS        5
+#define DRM_VMW_PARAM_MAX_FB_SIZE      6
 
 /**
  * struct drm_vmw_getparam_arg
index c227757feb06b4c22eb15ca3faf82c1dfa9f107e..050a7bccb8365ef117f365ebe3d3a8d337efc390 100644 (file)
@@ -245,8 +245,6 @@ int acpi_check_resource_conflict(const struct resource *res);
 
 int acpi_check_region(resource_size_t start, resource_size_t n,
                      const char *name);
-int acpi_check_mem_region(resource_size_t start, resource_size_t n,
-                     const char *name);
 
 int acpi_resources_are_enforced(void);
 
@@ -308,6 +306,9 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
                                             u32 *mask, u32 req);
 extern void acpi_early_init(void);
 
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
 #else  /* !CONFIG_ACPI */
 
 #define acpi_disabled 1
@@ -344,12 +345,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
        return 0;
 }
 
-static inline int acpi_check_mem_region(resource_size_t start,
-                                       resource_size_t n, const char *name)
-{
-       return 0;
-}
-
 struct acpi_table_header;
 static inline int acpi_table_parse(char *id,
                                int (*handler)(struct acpi_table_header *))
index 35b00746c712fc11776e78345edf786b98f9063b..4ce34fa937d4910cf8d7546e54de1e888fb0abb2 100644 (file)
@@ -111,6 +111,7 @@ void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi);
 
 extern spinlock_t bdi_lock;
 extern struct list_head bdi_list;
+extern struct list_head bdi_pending_list;
 
 static inline int wb_has_dirty_io(struct bdi_writeback *wb)
 {
@@ -285,7 +286,7 @@ enum {
 void clear_bdi_congested(struct backing_dev_info *bdi, int sync);
 void set_bdi_congested(struct backing_dev_info *bdi, int sync);
 long congestion_wait(int sync, long timeout);
-
+long wait_iff_congested(struct zone *zone, int sync, long timeout);
 
 static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
 {
diff --git a/include/linux/bfin_mac.h b/include/linux/bfin_mac.h
new file mode 100644 (file)
index 0000000..904dec7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Blackfin On-Chip MAC Driver
+ *
+ * Copyright 2004-2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _LINUX_BFIN_MAC_H_
+#define _LINUX_BFIN_MAC_H_
+
+#include <linux/phy.h>
+
+struct bfin_phydev_platform_data {
+       unsigned short addr;
+       int irq;
+};
+
+struct bfin_mii_bus_platform_data {
+       int phydev_number;
+       struct bfin_phydev_platform_data *phydev_data;
+       const unsigned short *mac_peripherals;
+       int phy_mode;
+       unsigned int phy_mask;
+};
+
+#endif
index 009b80e49f5361bb119e346e184c796d698dfc42..646b462d04df6819e542113f94695d0d716cf721 100644 (file)
@@ -115,7 +115,6 @@ struct request {
        void *elevator_private3;
 
        struct gendisk *rq_disk;
-       struct hd_struct *part;
        unsigned long start_time;
 #ifdef CONFIG_BLK_CGROUP
        unsigned long long start_time_ns;
index dd1b25b2641c6474925537ced10bd45831912754..68d1fe7b877c82e2d302fb31f3702836bc6d6843 100644 (file)
@@ -212,7 +212,6 @@ int generic_write_end(struct file *, struct address_space *,
                                loff_t, unsigned, unsigned,
                                struct page *, void *);
 void page_zero_new_buffers(struct page *page, unsigned from, unsigned to);
-int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 int cont_write_begin(struct file *, struct address_space *, loff_t,
                        unsigned, unsigned, struct page **, void **,
                        get_block_t *, loff_t *);
index b3ef0c461578c834c1266dc10b0390c51658aae6..e35071b1de0e26a3d8f5e1ee27c1da3d3667a4ad 100644 (file)
 
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
 #include <linux/coda.h>
 
 /*
  * coda fs inode data
+ * c_lock protects accesses to c_flags, c_mapcount, c_cached_epoch, c_uid and
+ * c_cached_perm.
+ * vfs_inode is set only when the inode is created and never changes.
+ * c_fid is set when the inode is created and should be considered immutable.
  */
 struct coda_inode_info {
-        struct CodaFid    c_fid;       /* Coda identifier */
-        u_short                   c_flags;     /* flags (see below) */
-       struct list_head   c_cilist;    /* list of all coda inodes */
+       struct CodaFid     c_fid;       /* Coda identifier */
+       u_short            c_flags;     /* flags (see below) */
        unsigned int       c_mapcount;  /* nr of times this inode is mapped */
        unsigned int       c_cached_epoch; /* epoch for cached permissions */
        vuid_t             c_uid;       /* fsuid for cached permissions */
-        unsigned int       c_cached_perm; /* cached access permissions */
+       unsigned int       c_cached_perm; /* cached access permissions */
+       spinlock_t         c_lock;
        struct inode       vfs_inode;
 };
 
index dcc228aa335ae43b77febde77dbecf4d031773b4..2e914d0771b9022ccf42bf50afd7d0e4445510d9 100644 (file)
@@ -89,7 +89,11 @@ static __inline__ char *coda_i2s(struct inode *inode)
 /* this will not zap the inode away */
 static __inline__ void coda_flag_inode(struct inode *inode, int flag)
 {
-       ITOC(inode)->c_flags |= flag;
+       struct coda_inode_info *cii = ITOC(inode);
+
+       spin_lock(&cii->c_lock);
+       cii->c_flags |= flag;
+       spin_unlock(&cii->c_lock);
 }              
 
 #endif
index 284b520934a0aee94534965645d6171f41eb787c..72f2d2f0af91efec0793a3fa202483d2383e82ac 100644 (file)
@@ -8,6 +8,7 @@
 
 #ifdef __KERNEL__
 #include <linux/backing-dev.h>
+#include <linux/mutex.h>
 
 struct kstatfs;
 
@@ -20,6 +21,7 @@ struct venus_comm {
        int                 vc_inuse;
        struct super_block *vc_sb;
        struct backing_dev_info bdi;
+       struct mutex        vc_mutex;
 };
 
 
@@ -63,7 +65,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
                 unsigned int cmd, struct PioctlData *data);
-int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out);
 int venus_fsync(struct super_block *sb, struct CodaFid *fid);
 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
 
index 51e3145196f6f77e852cca9b5f141155bbf10685..36d57f74cd01c6c126ee2f7c2ea2c98f66868b2f 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/wait.h>
 
-/**
+/*
  * struct completion - structure used to maintain state for a "completion"
  *
  * This is the opaque structure used to maintain the state for a "completion".
@@ -34,7 +34,7 @@ struct completion {
        ({ init_completion(&work); work; })
 
 /**
- * DECLARE_COMPLETION: - declare and initialize a completion structure
+ * DECLARE_COMPLETION - declare and initialize a completion structure
  * @work:  identifier for the completion structure
  *
  * This macro declares and initializes a completion structure. Generally used
@@ -50,7 +50,7 @@ struct completion {
  * are on the kernel stack:
  */
 /**
- * DECLARE_COMPLETION_ONSTACK: - declare and initialize a completion structure
+ * DECLARE_COMPLETION_ONSTACK - declare and initialize a completion structure
  * @work:  identifier for the completion structure
  *
  * This macro declares and initializes a completion structure on the kernel
@@ -64,7 +64,7 @@ struct completion {
 #endif
 
 /**
- * init_completion: - Initialize a dynamically allocated completion
+ * init_completion - Initialize a dynamically allocated completion
  * @x:  completion structure that is to be initialized
  *
  * This inline function will initialize a dynamically created completion
@@ -92,7 +92,7 @@ extern void complete(struct completion *);
 extern void complete_all(struct completion *);
 
 /**
- * INIT_COMPLETION: - reinitialize a completion structure
+ * INIT_COMPLETION - reinitialize a completion structure
  * @x:  completion structure to be reinitialized
  *
  * This macro should be used to reinitialize a completion structure so it can
index 7c930dba477ca2da1d748ac66bc157f5d0887052..5dd428532f794c387533633cba57e6e12957cb01 100644 (file)
 #include <linux/if_ether.h>
 #include <linux/memory.h>
 
+struct mdio_platform_data {
+       unsigned long           bus_freq;
+};
+
 struct emac_platform_data {
        char mac_addr[ETH_ALEN];
        u32 ctrl_reg_offset;
        u32 ctrl_mod_reg_offset;
        u32 ctrl_ram_offset;
        u32 hw_ram_addr;
-       u32 mdio_reg_offset;
        u32 ctrl_ram_size;
-       u32 phy_mask;
-       u32 mdio_max_freq;
+
+       /*
+        * phy_id can be one of the following:
+        *   - NULL             : use the first phy on the bus,
+        *   - ""               : force to 100/full, no mdio control
+        *   - "<bus>:<addr>"   : use the specified bus and phy
+        */
+       const char *phy_id;
+
        u8 rmii_en;
        u8 version;
        void (*interrupt_enable) (void);
index 80a0ece8f7e47e8479c6d8fadb6cc2dae7de05e1..4fd978e7eb83ef8d689d0d313b5441b0631ea275 100644 (file)
@@ -122,8 +122,6 @@ extern void elv_completed_request(struct request_queue *, struct request *);
 extern int elv_set_request(struct request_queue *, struct request *, gfp_t);
 extern void elv_put_request(struct request_queue *, struct request *);
 extern void elv_drain_elevator(struct request_queue *);
-extern void elv_quiesce_start(struct request_queue *);
-extern void elv_quiesce_end(struct request_queue *);
 
 /*
  * io scheduler registration
index 4f34ff6e55585b365db2c419c878e46c67d6d9b0..b2a6009cba10f6e018093dd50fec8d913e7d5817 100644 (file)
@@ -34,9 +34,9 @@
 
 /* And dynamically-tunable limits and defaults: */
 struct files_stat_struct {
-       int nr_files;           /* read only */
-       int nr_free_files;      /* read only */
-       int max_files;          /* tunable */
+       unsigned long nr_files;         /* read only */
+       unsigned long nr_free_files;    /* read only */
+       unsigned long max_files;                /* tunable */
 };
 
 struct inodes_stat_t {
@@ -92,6 +92,9 @@ struct inodes_stat_t {
 /* Expect random access pattern */
 #define FMODE_RANDOM           ((__force fmode_t)0x1000)
 
+/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
+#define FMODE_UNSIGNED_OFFSET  ((__force fmode_t)0x2000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
 
@@ -231,6 +234,7 @@ struct inodes_stat_t {
 #define S_NOCMTIME     128     /* Do not update file c/mtime */
 #define S_SWAPFILE     256     /* Do not truncate: swapon got its bmaps */
 #define S_PRIVATE      512     /* Inode is fs-internal */
+#define S_IMA          1024    /* Inode has an associated IMA struct */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -265,6 +269,7 @@ struct inodes_stat_t {
 #define IS_NOCMTIME(inode)     ((inode)->i_flags & S_NOCMTIME)
 #define IS_SWAPFILE(inode)     ((inode)->i_flags & S_SWAPFILE)
 #define IS_PRIVATE(inode)      ((inode)->i_flags & S_PRIVATE)
+#define IS_IMA(inode)          ((inode)->i_flags & S_IMA)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -400,7 +405,7 @@ extern void __init inode_init_early(void);
 extern void __init files_init(unsigned long);
 
 extern struct files_stat_struct files_stat;
-extern int get_max_files(void);
+extern unsigned long get_max_files(void);
 extern int sysctl_nr_open;
 extern struct inodes_stat_t inodes_stat;
 extern int leases_enable, lease_break_time;
@@ -720,7 +725,8 @@ struct posix_acl;
 
 struct inode {
        struct hlist_node       i_hash;
-       struct list_head        i_list;         /* backing dev IO list */
+       struct list_head        i_wb_list;      /* backing dev IO list */
+       struct list_head        i_lru;          /* inode LRU list */
        struct list_head        i_sb_list;
        struct list_head        i_dentry;
        unsigned long           i_ino;
@@ -772,6 +778,10 @@ struct inode {
 
        unsigned int            i_flags;
 
+#ifdef CONFIG_IMA
+       /* protected by i_lock */
+       unsigned int            i_readcount; /* struct files open RO */
+#endif
        atomic_t                i_writecount;
 #ifdef CONFIG_SECURITY
        void                    *i_security;
@@ -783,6 +793,11 @@ struct inode {
        void                    *i_private; /* fs or device private pointer */
 };
 
+static inline int inode_unhashed(struct inode *inode)
+{
+       return hlist_unhashed(&inode->i_hash);
+}
+
 /*
  * inode->i_mutex nesting subclasses for the lock validator:
  *
@@ -1107,6 +1122,7 @@ extern int fcntl_getlease(struct file *filp);
 
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
+extern struct file_lock * locks_alloc_lock(void);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
@@ -1295,6 +1311,11 @@ struct fasync_struct {
 
 /* SMP safe fasync helpers: */
 extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+extern struct fasync_struct *fasync_insert_entry(int, struct file *, struct fasync_struct **, struct fasync_struct *);
+extern int fasync_remove_entry(struct file *, struct fasync_struct **);
+extern struct fasync_struct *fasync_alloc(void);
+extern void fasync_free(struct fasync_struct *);
+
 /* can be called from interrupts */
 extern void kill_fasync(struct fasync_struct **, int, int);
 
@@ -1633,16 +1654,17 @@ struct super_operations {
  *
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  */
-#define I_DIRTY_SYNC           1
-#define I_DIRTY_DATASYNC       2
-#define I_DIRTY_PAGES          4
+#define I_DIRTY_SYNC           (1 << 0)
+#define I_DIRTY_DATASYNC       (1 << 1)
+#define I_DIRTY_PAGES          (1 << 2)
 #define __I_NEW                        3
 #define I_NEW                  (1 << __I_NEW)
-#define I_WILL_FREE            16
-#define I_FREEING              32
-#define I_CLEAR                        64
+#define I_WILL_FREE            (1 << 4)
+#define I_FREEING              (1 << 5)
+#define I_CLEAR                        (1 << 6)
 #define __I_SYNC               7
 #define I_SYNC                 (1 << __I_SYNC)
+#define I_REFERENCED           (1 << 8)
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1734,6 +1756,7 @@ static inline void file_accessed(struct file *file)
 }
 
 int sync_inode(struct inode *inode, struct writeback_control *wbc);
+int sync_inode_metadata(struct inode *inode, int wait);
 
 struct file_system_type {
        const char *name;
@@ -2078,7 +2101,6 @@ extern int check_disk_change(struct block_device *);
 extern int __invalidate_device(struct block_device *);
 extern int invalidate_partition(struct gendisk *, int);
 #endif
-extern int invalidate_inodes(struct super_block *);
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
                                        pgoff_t start, pgoff_t end);
 
@@ -2162,7 +2184,7 @@ extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin);
 
 extern int inode_init_always(struct super_block *, struct inode *);
 extern void inode_init_once(struct inode *);
-extern void inode_add_to_lists(struct super_block *, struct inode *);
+extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
@@ -2182,11 +2204,11 @@ extern struct inode * iget_locked(struct super_block *, unsigned long);
 extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
 extern int insert_inode_locked(struct inode *);
 extern void unlock_new_inode(struct inode *);
+extern unsigned int get_next_ino(void);
 
 extern void __iget(struct inode * inode);
 extern void iget_failed(struct inode *);
 extern void end_writeback(struct inode *);
-extern void destroy_inode(struct inode *);
 extern void __destroy_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
 extern int should_remove_suid(struct dentry *);
@@ -2194,9 +2216,11 @@ extern int file_remove_suid(struct file *);
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 extern void remove_inode_hash(struct inode *);
-static inline void insert_inode_hash(struct inode *inode) {
+static inline void insert_inode_hash(struct inode *inode)
+{
        __insert_inode_hash(inode, inode->i_ino);
 }
+extern void inode_sb_list_add(struct inode *inode);
 
 #ifdef CONFIG_BLOCK
 extern void submit_bio(int, struct bio *);
@@ -2479,7 +2503,10 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
 struct ctl_table;
 int proc_nr_files(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
-
+int proc_nr_dentry(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos);
+int proc_nr_inodes(struct ctl_table *table, int write,
+                  void __user *buffer, size_t *lenp, loff_t *ppos);
 int __init get_filesystem_list(char *buf);
 
 #define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
index 361d1cc288d03cc690fbac6638d1e865df289556..b65a6f472775db8cc542f1e515bce9ffec2b1a9c 100644 (file)
@@ -53,9 +53,7 @@ struct gameport {
 #define to_gameport_port(d)    container_of(d, struct gameport, dev)
 
 struct gameport_driver {
-
-       void *private;
-       char *description;
+       const char *description;
 
        int (*connect)(struct gameport *, struct gameport_driver *drv);
        int (*reconnect)(struct gameport *);
index 557c3927e70f5637c3bef45a019e9f6fc257c3a4..7a7b9c1644e4f26de810d54fd00a12302d56c927 100644 (file)
@@ -140,7 +140,6 @@ struct disk_part_tbl {
        struct rcu_head rcu_head;
        int len;
        struct hd_struct __rcu *last_lookup;
-       struct gendisk *disk;
        struct hd_struct __rcu *part[];
 };
 
index 975609cb8548504f20fd09e91476197a39dfbef1..e8713d55360ab90d85af0daca3b36bdfbcd430d1 100644 (file)
@@ -9,6 +9,32 @@
 
 struct vm_area_struct;
 
+/* Plain integer GFP bitmasks. Do not use this directly. */
+#define ___GFP_DMA             0x01u
+#define ___GFP_HIGHMEM         0x02u
+#define ___GFP_DMA32           0x04u
+#define ___GFP_MOVABLE         0x08u
+#define ___GFP_WAIT            0x10u
+#define ___GFP_HIGH            0x20u
+#define ___GFP_IO              0x40u
+#define ___GFP_FS              0x80u
+#define ___GFP_COLD            0x100u
+#define ___GFP_NOWARN          0x200u
+#define ___GFP_REPEAT          0x400u
+#define ___GFP_NOFAIL          0x800u
+#define ___GFP_NORETRY         0x1000u
+#define ___GFP_COMP            0x4000u
+#define ___GFP_ZERO            0x8000u
+#define ___GFP_NOMEMALLOC      0x10000u
+#define ___GFP_HARDWALL                0x20000u
+#define ___GFP_THISNODE                0x40000u
+#define ___GFP_RECLAIMABLE     0x80000u
+#ifdef CONFIG_KMEMCHECK
+#define ___GFP_NOTRACK         0x200000u
+#else
+#define ___GFP_NOTRACK         0
+#endif
+
 /*
  * GFP bitmasks..
  *
@@ -18,10 +44,10 @@ struct vm_area_struct;
  * without the underscores and use them consistently. The definitions here may
  * be used in bit comparisons.
  */
-#define __GFP_DMA      ((__force gfp_t)0x01u)
-#define __GFP_HIGHMEM  ((__force gfp_t)0x02u)
-#define __GFP_DMA32    ((__force gfp_t)0x04u)
-#define __GFP_MOVABLE  ((__force gfp_t)0x08u)  /* Page is movable */
+#define __GFP_DMA      ((__force gfp_t)___GFP_DMA)
+#define __GFP_HIGHMEM  ((__force gfp_t)___GFP_HIGHMEM)
+#define __GFP_DMA32    ((__force gfp_t)___GFP_DMA32)
+#define __GFP_MOVABLE  ((__force gfp_t)___GFP_MOVABLE)  /* Page is movable */
 #define GFP_ZONEMASK   (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
 /*
  * Action modifiers - doesn't change the zoning
@@ -38,27 +64,22 @@ struct vm_area_struct;
  * __GFP_MOVABLE: Flag that this page will be movable by the page migration
  * mechanism or reclaimed
  */
-#define __GFP_WAIT     ((__force gfp_t)0x10u)  /* Can wait and reschedule? */
-#define __GFP_HIGH     ((__force gfp_t)0x20u)  /* Should access emergency pools? */
-#define __GFP_IO       ((__force gfp_t)0x40u)  /* Can start physical IO? */
-#define __GFP_FS       ((__force gfp_t)0x80u)  /* Can call down to low-level FS? */
-#define __GFP_COLD     ((__force gfp_t)0x100u) /* Cache-cold page required */
-#define __GFP_NOWARN   ((__force gfp_t)0x200u) /* Suppress page allocation failure warning */
-#define __GFP_REPEAT   ((__force gfp_t)0x400u) /* See above */
-#define __GFP_NOFAIL   ((__force gfp_t)0x800u) /* See above */
-#define __GFP_NORETRY  ((__force gfp_t)0x1000u)/* See above */
-#define __GFP_COMP     ((__force gfp_t)0x4000u)/* Add compound page metadata */
-#define __GFP_ZERO     ((__force gfp_t)0x8000u)/* Return zeroed page on success */
-#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
-#define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
-#define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
-#define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */
-
-#ifdef CONFIG_KMEMCHECK
-#define __GFP_NOTRACK  ((__force gfp_t)0x200000u)  /* Don't track with kmemcheck */
-#else
-#define __GFP_NOTRACK  ((__force gfp_t)0)
-#endif
+#define __GFP_WAIT     ((__force gfp_t)___GFP_WAIT)    /* Can wait and reschedule? */
+#define __GFP_HIGH     ((__force gfp_t)___GFP_HIGH)    /* Should access emergency pools? */
+#define __GFP_IO       ((__force gfp_t)___GFP_IO)      /* Can start physical IO? */
+#define __GFP_FS       ((__force gfp_t)___GFP_FS)      /* Can call down to low-level FS? */
+#define __GFP_COLD     ((__force gfp_t)___GFP_COLD)    /* Cache-cold page required */
+#define __GFP_NOWARN   ((__force gfp_t)___GFP_NOWARN)  /* Suppress page allocation failure warning */
+#define __GFP_REPEAT   ((__force gfp_t)___GFP_REPEAT)  /* See above */
+#define __GFP_NOFAIL   ((__force gfp_t)___GFP_NOFAIL)  /* See above */
+#define __GFP_NORETRY  ((__force gfp_t)___GFP_NORETRY) /* See above */
+#define __GFP_COMP     ((__force gfp_t)___GFP_COMP)    /* Add compound page metadata */
+#define __GFP_ZERO     ((__force gfp_t)___GFP_ZERO)    /* Return zeroed page on success */
+#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC) /* Don't use emergency reserves */
+#define __GFP_HARDWALL   ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */
+#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */
+#define __GFP_NOTRACK  ((__force gfp_t)___GFP_NOTRACK)  /* Don't track with kmemcheck */
 
 /*
  * This may seem redundant, but it's a way of annotating false positives vs.
@@ -186,14 +207,14 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
 #endif
 
 #define GFP_ZONE_TABLE ( \
-       (ZONE_NORMAL << 0 * ZONES_SHIFT)                                \
-       | (OPT_ZONE_DMA << __GFP_DMA * ZONES_SHIFT)                     \
-       | (OPT_ZONE_HIGHMEM << __GFP_HIGHMEM * ZONES_SHIFT)             \
-       | (OPT_ZONE_DMA32 << __GFP_DMA32 * ZONES_SHIFT)                 \
-       | (ZONE_NORMAL << __GFP_MOVABLE * ZONES_SHIFT)                  \
-       | (OPT_ZONE_DMA << (__GFP_MOVABLE | __GFP_DMA) * ZONES_SHIFT)   \
-       | (ZONE_MOVABLE << (__GFP_MOVABLE | __GFP_HIGHMEM) * ZONES_SHIFT)\
-       | (OPT_ZONE_DMA32 << (__GFP_MOVABLE | __GFP_DMA32) * ZONES_SHIFT)\
+       (ZONE_NORMAL << 0 * ZONES_SHIFT)                                      \
+       | (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT)                          \
+       | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT)                  \
+       | (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT)                      \
+       | (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT)                       \
+       | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT)       \
+       | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT)   \
+       | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT)   \
 )
 
 /*
@@ -203,20 +224,20 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
  * allowed.
  */
 #define GFP_ZONE_BAD ( \
-       1 << (__GFP_DMA | __GFP_HIGHMEM)                                \
-       | 1 << (__GFP_DMA | __GFP_DMA32)                                \
-       | 1 << (__GFP_DMA32 | __GFP_HIGHMEM)                            \
-       | 1 << (__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM)                \
-       | 1 << (__GFP_MOVABLE | __GFP_HIGHMEM | __GFP_DMA)              \
-       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA)                \
-       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_HIGHMEM)            \
-       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA | __GFP_HIGHMEM)\
+       1 << (___GFP_DMA | ___GFP_HIGHMEM)                                    \
+       | 1 << (___GFP_DMA | ___GFP_DMA32)                                    \
+       | 1 << (___GFP_DMA32 | ___GFP_HIGHMEM)                                \
+       | 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM)                   \
+       | 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA)                 \
+       | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA)                   \
+       | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM)               \
+       | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM)  \
 )
 
 static inline enum zone_type gfp_zone(gfp_t flags)
 {
        enum zone_type z;
-       int bit = flags & GFP_ZONEMASK;
+       int bit = (__force int) (flags & GFP_ZONEMASK);
 
        z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
                                         ((1 << ZONES_SHIFT) - 1);
diff --git a/include/linux/gpio-fan.h b/include/linux/gpio-fan.h
new file mode 100644 (file)
index 0000000..0966591
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * include/linux/gpio-fan.h
+ *
+ * Platform data structure for GPIO fan driver
+ *
+ * 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 __LINUX_GPIO_FAN_H
+#define __LINUX_GPIO_FAN_H
+
+struct gpio_fan_alarm {
+       unsigned        gpio;
+       unsigned        active_low;
+};
+
+struct gpio_fan_speed {
+       int rpm;
+       int ctrl_val;
+};
+
+struct gpio_fan_platform_data {
+       int                     num_ctrl;
+       unsigned                *ctrl;  /* fan control GPIOs. */
+       struct gpio_fan_alarm   *alarm; /* fan alarm GPIO. */
+       /*
+        * Speed conversion array: rpm from/to GPIO bit field.
+        * This array _must_ be sorted in ascending rpm order.
+        */
+       int                     num_speed;
+       struct gpio_fan_speed   *speed;
+};
+
+#endif /* __LINUX_GPIO_FAN_H */
index e3060ef85b6dead79e7922faaaffd1351f209e95..8a85ec109a3a57f1dbc8bd5a01a90fb6ad093bb3 100644 (file)
@@ -28,18 +28,6 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
 
 #include <asm/kmap_types.h>
 
-#ifdef CONFIG_DEBUG_HIGHMEM
-
-void debug_kmap_atomic(enum km_type type);
-
-#else
-
-static inline void debug_kmap_atomic(enum km_type type)
-{
-}
-
-#endif
-
 #ifdef CONFIG_HIGHMEM
 #include <asm/highmem.h>
 
@@ -49,6 +37,27 @@ extern unsigned long totalhigh_pages;
 
 void kmap_flush_unused(void);
 
+DECLARE_PER_CPU(int, __kmap_atomic_idx);
+
+static inline int kmap_atomic_idx_push(void)
+{
+       int idx = __get_cpu_var(__kmap_atomic_idx)++;
+#ifdef CONFIG_DEBUG_HIGHMEM
+       WARN_ON_ONCE(in_irq() && !irqs_disabled());
+       BUG_ON(idx > KM_TYPE_NR);
+#endif
+       return idx;
+}
+
+static inline int kmap_atomic_idx_pop(void)
+{
+       int idx = --__get_cpu_var(__kmap_atomic_idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       BUG_ON(idx < 0);
+#endif
+       return idx;
+}
+
 #else /* CONFIG_HIGHMEM */
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -66,19 +75,19 @@ static inline void kunmap(struct page *page)
 {
 }
 
-static inline void *kmap_atomic(struct page *page, enum km_type idx)
+static inline void *__kmap_atomic(struct page *page)
 {
        pagefault_disable();
        return page_address(page);
 }
-#define kmap_atomic_prot(page, idx, prot)      kmap_atomic(page, idx)
+#define kmap_atomic_prot(page, prot)   __kmap_atomic(page)
 
-static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
+static inline void __kunmap_atomic(void *addr)
 {
        pagefault_enable();
 }
 
-#define kmap_atomic_pfn(pfn, idx)      kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_pfn(pfn)   kmap_atomic(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
 
 #define kmap_flush_unused()    do {} while(0)
@@ -86,12 +95,20 @@ static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
 
 #endif /* CONFIG_HIGHMEM */
 
-/* Prevent people trying to call kunmap_atomic() as if it were kunmap() */
-/* kunmap_atomic() should get the return value of kmap_atomic, not the page. */
-#define kunmap_atomic(addr, idx) do { \
-               BUILD_BUG_ON(__same_type((addr), struct page *)); \
-               kunmap_atomic_notypecheck((addr), (idx)); \
-       } while (0)
+/*
+ * Make both: kmap_atomic(page, idx) and kmap_atomic(page) work.
+ */
+#define kmap_atomic(page, args...) __kmap_atomic(page)
+
+/*
+ * Prevent people trying to call kunmap_atomic() as if it were kunmap()
+ * kunmap_atomic() should get the return value of kmap_atomic, not the page.
+ */
+#define kunmap_atomic(addr, args...)                           \
+do {                                                           \
+       BUILD_BUG_ON(__same_type((addr), struct page *));       \
+       __kunmap_atomic(addr);                                  \
+} while (0)
 
 /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
 #ifndef clear_user_highpage
@@ -201,8 +218,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from,
        vfrom = kmap_atomic(from, KM_USER0);
        vto = kmap_atomic(to, KM_USER1);
        copy_user_page(vto, vfrom, vaddr, to);
-       kunmap_atomic(vfrom, KM_USER0);
        kunmap_atomic(vto, KM_USER1);
+       kunmap_atomic(vfrom, KM_USER0);
 }
 
 #endif
@@ -214,8 +231,8 @@ static inline void copy_highpage(struct page *to, struct page *from)
        vfrom = kmap_atomic(from, KM_USER0);
        vto = kmap_atomic(to, KM_USER1);
        copy_page(vto, vfrom);
-       kunmap_atomic(vfrom, KM_USER0);
        kunmap_atomic(vto, KM_USER1);
+       kunmap_atomic(vfrom, KM_USER0);
 }
 
 #endif /* _LINUX_HIGHMEM_H */
index f479700df61b186118d607a0db86b1e47ffa8294..943c76b3d4bb94d9536ecf8e324bea8ffda853e4 100644 (file)
@@ -43,7 +43,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to,
                                                struct vm_area_struct *vma,
                                                int acctflags);
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
-void __isolate_hwpoisoned_huge_page(struct page *page);
+int dequeue_hwpoisoned_huge_page(struct page *page);
+void copy_huge_page(struct page *dst, struct page *src);
 
 extern unsigned long hugepages_treat_as_movable;
 extern const unsigned long hugetlb_zero, hugetlb_infinity;
@@ -101,7 +102,10 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
 #define hugetlb_fault(mm, vma, addr, flags)    ({ BUG(); 0; })
 #define huge_pte_offset(mm, address)   0
-#define __isolate_hwpoisoned_huge_page(page)   0
+#define dequeue_hwpoisoned_huge_page(page)     0
+static inline void copy_huge_page(struct page *dst, struct page *src)
+{
+}
 
 #define hugetlb_change_protection(vma, address, end, newprot)
 
@@ -228,6 +232,8 @@ struct huge_bootmem_page {
        struct hstate *hstate;
 };
 
+struct page *alloc_huge_page_node(struct hstate *h, int nid);
+
 /* arch callback */
 int __init alloc_bootmem_huge_page(struct hstate *h);
 
@@ -301,8 +307,14 @@ static inline struct hstate *page_hstate(struct page *page)
        return size_to_hstate(PAGE_SIZE << compound_order(page));
 }
 
+static inline unsigned hstate_index_to_shift(unsigned index)
+{
+       return hstates[index].order + PAGE_SHIFT;
+}
+
 #else
 struct hstate {};
+#define alloc_huge_page_node(h, nid) NULL
 #define alloc_bootmem_huge_page(h) NULL
 #define hstate_file(f) NULL
 #define hstate_vma(v) NULL
@@ -317,6 +329,7 @@ static inline unsigned int pages_per_huge_page(struct hstate *h)
 {
        return 1;
 }
+#define hstate_index_to_shift(index) 0
 #endif
 
 #endif /* _LINUX_HUGETLB_H */
diff --git a/include/linux/i2c/apds990x.h b/include/linux/i2c/apds990x.h
new file mode 100644 (file)
index 0000000..d186fcc
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the APDS990x sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __APDS990X_H__
+#define __APDS990X_H__
+
+
+#define APDS_IRLED_CURR_12mA   0x3
+#define APDS_IRLED_CURR_25mA   0x2
+#define APDS_IRLED_CURR_50mA   0x1
+#define APDS_IRLED_CURR_100mA  0x0
+
+/**
+ * struct apds990x_chip_factors - defines effect of the cover window
+ * @ga: Total glass attenuation
+ * @cf1: clear channel factor 1 for raw to lux conversion
+ * @irf1: IR channel factor 1 for raw to lux conversion
+ * @cf2: clear channel factor 2 for raw to lux conversion
+ * @irf2: IR channel factor 2 for raw to lux conversion
+ * @df: device factor for conversion formulas
+ *
+ * Structure for tuning ALS calculation to match with environment.
+ * Values depend on the material above the sensor and the sensor
+ * itself. If the GA is zero, driver will use uncovered sensor default values
+ * format: decimal value * APDS_PARAM_SCALE except df which is plain integer.
+ */
+#define APDS_PARAM_SCALE 4096
+struct apds990x_chip_factors {
+       int ga;
+       int cf1;
+       int irf1;
+       int cf2;
+       int irf2;
+       int df;
+};
+
+/**
+ * struct apds990x_platform_data - platform data for apsd990x.c driver
+ * @cf: chip factor data
+ * @pddrive: IR-led driving current
+ * @ppcount: number of IR pulses used for proximity estimation
+ * @setup_resources: interrupt line setup call back function
+ * @release_resources: interrupt line release call back function
+ *
+ * Proximity detection result depends heavily on correct ppcount, pdrive
+ * and cover window.
+ *
+ */
+
+struct apds990x_platform_data {
+       struct apds990x_chip_factors cf;
+       u8     pdrive;
+       u8     ppcount;
+       int    (*setup_resources)(void);
+       int    (*release_resources)(void);
+};
+
+#endif
diff --git a/include/linux/i2c/bh1770glc.h b/include/linux/i2c/bh1770glc.h
new file mode 100644 (file)
index 0000000..8b5e2df
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __BH1770_H__
+#define __BH1770_H__
+
+/**
+ * struct bh1770_platform_data - platform data for bh1770glc driver
+ * @led_def_curr: IR led driving current.
+ * @glass_attenuation: Attenuation factor for covering window.
+ * @setup_resources: Call back for interrupt line setup function
+ * @release_resources: Call back for interrupte line release function
+ *
+ * Example of glass attenuation: 16384 * 385 / 100 means attenuation factor
+ * of 3.85. i.e. light_above_sensor = light_above_cover_window / 3.85
+ */
+
+struct bh1770_platform_data {
+#define BH1770_LED_5mA 0
+#define BH1770_LED_10mA        1
+#define BH1770_LED_20mA        2
+#define BH1770_LED_50mA        3
+#define BH1770_LED_100mA 4
+#define BH1770_LED_150mA 5
+#define BH1770_LED_200mA 6
+       __u8 led_def_curr;
+#define BH1770_NEUTRAL_GA 16384 /* 16384 / 16384 = 1 */
+       __u32 glass_attenuation;
+       int (*setup_resources)(void);
+       int (*release_resources)(void);
+};
+#endif
index 6de90bfc6acde5a2728cb4d95091ab2dd7115822..4793d8a7f48086e58bac27204e8245dcc40c558d 100644 (file)
@@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 
 struct twl4030_codec_audio_data {
-       unsigned int    audio_mclk;
+       unsigned int audio_mclk; /* not used, will be removed */
+       unsigned int digimic_delay; /* in ms */
        unsigned int ramp_delay_value;
+       unsigned int offset_cncl_path;
+       unsigned int check_defaults:1;
+       unsigned int reset_registers:1;
        unsigned int hs_extmute:1;
        void (*set_hs_extmute)(int mute);
 };
index 928ae712709faa041160a1a4a2f45ad5dcf1baf3..13a801f3d028225533f2ce701349b2b0657ca734 100644 (file)
@@ -81,6 +81,7 @@ struct idr {
 #define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC)
 
 /**
+ * DOC: idr sync
  * idr synchronization (stolen from radix-tree.h)
  *
  * idr_find() is able to be called locklessly, using RCU. The caller must
index d6ae1761be97fae4cbbc66602d19d9bdd60f3bdd..51af441f3a21268fe40f8b78810d801cdc5b6416 100644 (file)
@@ -34,7 +34,7 @@ struct input_event {
  * Protocol version.
  */
 
-#define EV_VERSION             0x010000
+#define EV_VERSION             0x010001
 
 /*
  * IOCTLs (0x00 - 0x7f)
@@ -56,25 +56,50 @@ struct input_absinfo {
        __s32 resolution;
 };
 
+/**
+ * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
+ * @scancode: scancode represented in machine-endian form.
+ * @len: length of the scancode that resides in @scancode buffer.
+ * @index: index in the keymap, may be used instead of scancode
+ * @flags: allows to specify how kernel should handle the request. For
+ *     example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
+ *     should perform lookup in keymap by @index instead of @scancode
+ * @keycode: key code assigned to this scancode
+ *
+ * The structure is used to retrieve and modify keymap data. Users have
+ * option of performing lookup either by @scancode itself or by @index
+ * in keymap entry. EVIOCGKEYCODE will also return scancode or index
+ * (depending on which element was used to perform lookup).
+ */
+struct input_keymap_entry {
+#define INPUT_KEYMAP_BY_INDEX  (1 << 0)
+       __u8  flags;
+       __u8  len;
+       __u16 index;
+       __u32 keycode;
+       __u8  scancode[32];
+};
+
 #define EVIOCGVERSION          _IOR('E', 0x01, int)                    /* get driver version */
 #define EVIOCGID               _IOR('E', 0x02, struct input_id)        /* get device ID */
 #define EVIOCGREP              _IOR('E', 0x03, unsigned int[2])        /* get repeat settings */
 #define EVIOCSREP              _IOW('E', 0x03, unsigned int[2])        /* set repeat settings */
-#define EVIOCGKEYCODE          _IOR('E', 0x04, unsigned int[2])        /* get keycode */
-#define EVIOCSKEYCODE          _IOW('E', 0x04, unsigned int[2])        /* set keycode */
+
+#define EVIOCGKEYCODE          _IOR('E', 0x04, struct input_keymap_entry)      /* get keycode */
+#define EVIOCSKEYCODE          _IOW('E', 0x04, struct input_keymap_entry)      /* set keycode */
 
 #define EVIOCGNAME(len)                _IOC(_IOC_READ, 'E', 0x06, len)         /* get device name */
 #define EVIOCGPHYS(len)                _IOC(_IOC_READ, 'E', 0x07, len)         /* get physical location */
 #define EVIOCGUNIQ(len)                _IOC(_IOC_READ, 'E', 0x08, len)         /* get unique identifier */
 
-#define EVIOCGKEY(len)         _IOC(_IOC_READ, 'E', 0x18, len)         /* get global keystate */
+#define EVIOCGKEY(len)         _IOC(_IOC_READ, 'E', 0x18, len)         /* get global key state */
 #define EVIOCGLED(len)         _IOC(_IOC_READ, 'E', 0x19, len)         /* get all LEDs */
 #define EVIOCGSND(len)         _IOC(_IOC_READ, 'E', 0x1a, len)         /* get all sounds status */
 #define EVIOCGSW(len)          _IOC(_IOC_READ, 'E', 0x1b, len)         /* get all switch states */
 
 #define EVIOCGBIT(ev,len)      _IOC(_IOC_READ, 'E', 0x20 + ev, len)    /* get event bits */
-#define EVIOCGABS(abs)         _IOR('E', 0x40 + abs, struct input_absinfo)             /* get abs value/limits */
-#define EVIOCSABS(abs)         _IOW('E', 0xc0 + abs, struct input_absinfo)             /* set abs value/limits */
+#define EVIOCGABS(abs)         _IOR('E', 0x40 + abs, struct input_absinfo)     /* get abs value/limits */
+#define EVIOCSABS(abs)         _IOW('E', 0xc0 + abs, struct input_absinfo)     /* set abs value/limits */
 
 #define EVIOCSFF               _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))   /* send a force effect to a force feedback device */
 #define EVIOCRMFF              _IOW('E', 0x81, int)                    /* Erase a force effect */
@@ -1088,13 +1113,13 @@ struct input_mt_slot {
  * @keycodemax: size of keycode table
  * @keycodesize: size of elements in keycode table
  * @keycode: map of scancodes to keycodes for this device
+ * @getkeycode: optional legacy method to retrieve current keymap.
  * @setkeycode: optional method to alter current keymap, used to implement
  *     sparse keymaps. If not supplied default mechanism will be used.
  *     The method is being called while holding event_lock and thus must
  *     not sleep
- * @getkeycode: optional method to retrieve current keymap. If not supplied
- *     default mechanism will be used. The method is being called while
- *     holding event_lock and thus must not sleep
+ * @getkeycode_new: transition method
+ * @setkeycode_new: transition method
  * @ff: force feedback structure associated with the device if device
  *     supports force feedback effects
  * @repeat_key: stores key code of the last key pressed; used to implement
@@ -1168,10 +1193,16 @@ struct input_dev {
        unsigned int keycodemax;
        unsigned int keycodesize;
        void *keycode;
+
        int (*setkeycode)(struct input_dev *dev,
                          unsigned int scancode, unsigned int keycode);
        int (*getkeycode)(struct input_dev *dev,
                          unsigned int scancode, unsigned int *keycode);
+       int (*setkeycode_new)(struct input_dev *dev,
+                             const struct input_keymap_entry *ke,
+                             unsigned int *old_keycode);
+       int (*getkeycode_new)(struct input_dev *dev,
+                             struct input_keymap_entry *ke);
 
        struct ff_device *ff;
 
@@ -1478,10 +1509,12 @@ INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz)
 INPUT_GENERATE_ABS_ACCESSORS(flat, flat)
 INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
 
-int input_get_keycode(struct input_dev *dev,
-                     unsigned int scancode, unsigned int *keycode);
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+                            unsigned int *scancode);
+
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke);
 int input_set_keycode(struct input_dev *dev,
-                     unsigned int scancode, unsigned int keycode);
+                     const struct input_keymap_entry *ke);
 
 extern struct class input_class;
 
diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h
new file mode 100644 (file)
index 0000000..e470d38
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#ifndef _BU21013_H
+#define _BU21013_H
+
+/**
+ * struct bu21013_platform_device - Handle the platform data
+ * @cs_en:     pointer to the cs enable function
+ * @cs_dis:    pointer to the cs disable function
+ * @irq_read_val:    pointer to read the pen irq value function
+ * @x_max_res: xmax resolution
+ * @y_max_res: ymax resolution
+ * @touch_x_max: touch x max
+ * @touch_y_max: touch y max
+ * @cs_pin: chip select pin
+ * @irq: irq pin
+ * @ext_clk: external clock flag
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @wakeup: wakeup flag
+ *
+ * This is used to handle the platform data
+ */
+struct bu21013_platform_device {
+       int (*cs_en)(int reset_pin);
+       int (*cs_dis)(int reset_pin);
+       int (*irq_read_val)(void);
+       int x_max_res;
+       int y_max_res;
+       int touch_x_max;
+       int touch_y_max;
+       unsigned int cs_pin;
+       unsigned int irq;
+       bool ext_clk;
+       bool x_flip;
+       bool y_flip;
+       bool wakeup;
+};
+
+#endif
index 7fb59279373823339f6fdda86158952e3e6fac45..8cdcc2a199ad1641c3ca652263922fbdcddf6f6a 100644 (file)
@@ -81,8 +81,7 @@ io_mapping_free(struct io_mapping *mapping)
 /* Atomic map/unmap */
 static inline void __iomem *
 io_mapping_map_atomic_wc(struct io_mapping *mapping,
-                        unsigned long offset,
-                        int slot)
+                        unsigned long offset)
 {
        resource_size_t phys_addr;
        unsigned long pfn;
@@ -90,13 +89,13 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping,
        BUG_ON(offset >= mapping->size);
        phys_addr = mapping->base + offset;
        pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
-       return iomap_atomic_prot_pfn(pfn, slot, mapping->prot);
+       return iomap_atomic_prot_pfn(pfn, mapping->prot);
 }
 
 static inline void
-io_mapping_unmap_atomic(void __iomem *vaddr, int slot)
+io_mapping_unmap_atomic(void __iomem *vaddr)
 {
-       iounmap_atomic(vaddr, slot);
+       iounmap_atomic(vaddr);
 }
 
 static inline void __iomem *
@@ -137,14 +136,13 @@ io_mapping_free(struct io_mapping *mapping)
 /* Atomic map/unmap */
 static inline void __iomem *
 io_mapping_map_atomic_wc(struct io_mapping *mapping,
-                        unsigned long offset,
-                        int slot)
+                        unsigned long offset)
 {
        return ((char __force __iomem *) mapping) + offset;
 }
 
 static inline void
-io_mapping_unmap_atomic(void __iomem *vaddr, int slot)
+io_mapping_unmap_atomic(void __iomem *vaddr)
 {
 }
 
index edef168a04064b61161cff70e9e8d803aa2ed1a4..450092c1e35f459f6db7dba29dbb94ec1a2c683c 100644 (file)
@@ -173,6 +173,11 @@ extern int _cond_resched(void);
                (__x < 0) ? -__x : __x;         \
        })
 
+#define abs64(x) ({                            \
+               s64 __x = (x);                  \
+               (__x < 0) ? -__x : __x;         \
+       })
+
 #ifdef CONFIG_PROVE_LOCKING
 void might_fault(void);
 #else
@@ -203,10 +208,10 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
 extern long long simple_strtoll(const char *,char **,unsigned int);
-extern int strict_strtoul(const char *, unsigned int, unsigned long *);
-extern int strict_strtol(const char *, unsigned int, long *);
-extern int strict_strtoull(const char *, unsigned int, unsigned long long *);
-extern int strict_strtoll(const char *, unsigned int, long long *);
+extern int __must_check strict_strtoul(const char *, unsigned int, unsigned long *);
+extern int __must_check strict_strtol(const char *, unsigned int, long *);
+extern int __must_check strict_strtoull(const char *, unsigned int, unsigned long long *);
+extern int __must_check strict_strtoll(const char *, unsigned int, long long *);
 extern int sprintf(char * buf, const char * fmt, ...)
        __attribute__ ((format (printf, 2, 3)));
 extern int vsprintf(char *buf, const char *, va_list)
@@ -277,6 +282,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 asmlinkage int printk(const char * fmt, ...)
        __attribute__ ((format (printf, 1, 2))) __cold;
 
+/*
+ * Please don't use printk_ratelimit(), because it shares ratelimiting state
+ * with all other unrelated printk_ratelimit() callsites.  Instead use
+ * printk_ratelimited() or plain old __ratelimit().
+ */
 extern int __printk_ratelimit(const char *func);
 #define printk_ratelimit() __printk_ratelimit(__func__)
 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
@@ -651,6 +661,24 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
        (void) (&_max1 == &_max2);              \
        _max1 > _max2 ? _max1 : _max2; })
 
+#define min3(x, y, z) ({                       \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       typeof(z) _min3 = (z);                  \
+       (void) (&_min1 == &_min2);              \
+       (void) (&_min1 == &_min3);              \
+       _min1 < _min2 ? (_min1 < _min3 ? _min1 : _min3) : \
+               (_min2 < _min3 ? _min2 : _min3); })
+
+#define max3(x, y, z) ({                       \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       typeof(z) _max3 = (z);                  \
+       (void) (&_max1 == &_max2);              \
+       (void) (&_max1 == &_max3);              \
+       _max1 > _max2 ? (_max1 > _max3 ? _max1 : _max3) : \
+               (_max2 > _max3 ? _max2 : _max3); })
+
 /**
  * min_not_zero - return the minimum that is _not_ zero, unless both are zero
  * @x: value1
index 62dbee554f608c91fe7b2b3bf01f390260821c52..c238ad2f82eae4f149e70fc7138fdd5beaa40b13 100644 (file)
@@ -171,11 +171,8 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
        }
 
 
-static inline unsigned int __must_check
-__kfifo_must_check_helper(unsigned int val)
-{
-       return val;
-}
+/* __kfifo_must_check_helper() is temporarily disabled because it was faulty */
+#define __kfifo_must_check_helper(x) (x)
 
 /**
  * kfifo_initialized - Check if the fifo is initialized
index 0e8a346424bb6d4d1ec162ff26fb933f4fce92ef..d4292c8431e069a52e62431bfb47ecb8b39f84f1 100644 (file)
@@ -1,6 +1,52 @@
 #ifndef __LIS3LV02D_H_
 #define __LIS3LV02D_H_
 
+/**
+ * struct lis3lv02d_platform_data - lis3 chip family platform data
+ * @click_flags:       Click detection unit configuration
+ * @click_thresh_x:    Click detection unit x axis threshold
+ * @click_thresh_y:    Click detection unit y axis threshold
+ * @click_thresh_z:    Click detection unit z axis threshold
+ * @click_time_limit:  Click detection unit time parameter
+ * @click_latency:     Click detection unit latency parameter
+ * @click_window:      Click detection unit window parameter
+ * @irq_cfg:           On chip irq source and type configuration (click /
+ *                     data available / wake up, open drain, polarity)
+ * @irq_flags1:                Additional irq triggering flags for irq channel 0
+ * @irq_flags2:                Additional irq triggering flags for irq channel 1
+ * @duration1:         Wake up unit 1 duration parameter
+ * @duration2:         Wake up unit 2 duration parameter
+ * @wakeup_flags:      Wake up unit 1 flags
+ * @wakeup_thresh:     Wake up unit 1 threshold value
+ * @wakeup_flags2:     Wake up unit 2 flags
+ * @wakeup_thresh2:    Wake up unit 2 threshold value
+ * @hipass_ctrl:       High pass filter control (enable / disable, cut off
+ *                     frequency)
+ * @axis_x:            Sensor orientation remapping for x-axis
+ * @axis_y:            Sensor orientation remapping for y-axis
+ * @axis_z:            Sensor orientation remapping for z-axis
+ * @driver_features:   Enable bits for different features. Disabled by default
+ * @default_rate:      Default sampling rate. 0 means reset default
+ * @setup_resources:   Interrupt line setup call back function
+ * @release_resources: Interrupt line release call back function
+ * @st_min_limits[3]:  Selftest acceptance minimum values
+ * @st_max_limits[3]:  Selftest acceptance maximum values
+ * @irq2:              Irq line 2 number
+ *
+ * Platform data is used to setup the sensor chip. Meaning of the different
+ * chip features can be found from the data sheet. It is publicly available
+ * at www.st.com web pages. Currently the platform data is used
+ * only for the 8 bit device. The 8 bit device has two wake up / free fall
+ * detection units and click detection unit. There are plenty of ways to
+ * configure the chip which makes is quite hard to explain deeper meaning of
+ * the fields here. Behaviour of the detection blocks varies heavily depending
+ * on the configuration. For example, interrupt detection block can use high
+ * pass filtered data which makes it react to the changes in the acceleration.
+ * Irq_flags can be used to enable interrupt detection on the both edges.
+ * With proper chip configuration this produces interrupt when some trigger
+ * starts and when it goes away.
+ */
+
 struct lis3lv02d_platform_data {
        /* please note: the 'click' feature is only supported for
         * LIS[32]02DL variants of the chip and will be ignored for
@@ -36,7 +82,10 @@ struct lis3lv02d_platform_data {
 #define LIS3_IRQ_OPEN_DRAIN    (1 << 6)
 #define LIS3_IRQ_ACTIVE_LOW    (1 << 7)
        unsigned char irq_cfg;
-
+       unsigned char irq_flags1; /* Additional irq edge / level flags */
+       unsigned char irq_flags2; /* Additional irq edge / level flags */
+       unsigned char duration1;
+       unsigned char duration2;
 #define LIS3_WAKEUP_X_LO       (1 << 0)
 #define LIS3_WAKEUP_X_HI       (1 << 1)
 #define LIS3_WAKEUP_Y_LO       (1 << 2)
@@ -64,6 +113,10 @@ struct lis3lv02d_platform_data {
        s8 axis_x;
        s8 axis_y;
        s8 axis_z;
+#define LIS3_USE_REGULATOR_CTRL 0x01
+#define LIS3_USE_BLOCK_READ    0x02
+       u16 driver_features;
+       int default_rate;
        int (*setup_resources)(void);
        int (*release_resources)(void);
        /* Limits for selftest are specified in chip data sheet */
index 88a000617d775fb74333a5f54aceac8460cb5008..9a5f8a71810c55f231565422f8912bea5bbe2d7b 100644 (file)
@@ -636,6 +636,12 @@ static inline void hlist_add_after(struct hlist_node *n,
                next->next->pprev  = &next->next;
 }
 
+/* after that we'll appear to be on some hlist and hlist_del will work */
+static inline void hlist_add_fake(struct hlist_node *n)
+{
+       n->pprev = &n->next;
+}
+
 /*
  * Move a list from one list head to another. Fixup the pprev
  * reference of the first entry if it exists.
index c87f1528703a68c2dd024d612a203ae4517b5cea..23fcdfcba81b33ef0d5e2957c591f8baeb1f1836 100644 (file)
@@ -35,6 +35,14 @@ static inline u64 div64_u64(u64 dividend, u64 divisor)
        return dividend / divisor;
 }
 
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ */
+static inline s64 div64_s64(s64 dividend, s64 divisor)
+{
+       return dividend / divisor;
+}
+
 #elif BITS_PER_LONG == 32
 
 #ifndef div_u64_rem
@@ -53,6 +61,10 @@ extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
 extern u64 div64_u64(u64 dividend, u64 divisor);
 #endif
 
+#ifndef div64_s64
+extern s64 div64_s64(s64 dividend, s64 divisor);
+#endif
+
 #endif /* BITS_PER_LONG */
 
 /**
index 864035fb8f8a83e547efbdd161093117bac94bc2..4307231bd22fb23ad9732295f472bc4b8564e200 100644 (file)
@@ -70,6 +70,10 @@ extern void online_page(struct page *page);
 extern int online_pages(unsigned long, unsigned long);
 extern void __offline_isolated_pages(unsigned long, unsigned long);
 
+#ifdef CONFIG_MEMORY_HOTREMOVE
+extern bool is_pageblock_removable_nolock(struct page *page);
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+
 /* reasonably generic interface to expand the physical pages in a zone  */
 extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
        unsigned long nr_pages);
index 7238231b8dd40194e980dad7683c854fd88a6047..085527fb82610065e3b8566372780cd6910c2cf3 100644 (file)
@@ -14,6 +14,8 @@ extern int migrate_page(struct address_space *,
                        struct page *, struct page *);
 extern int migrate_pages(struct list_head *l, new_page_t x,
                        unsigned long private, int offlining);
+extern int migrate_huge_pages(struct list_head *l, new_page_t x,
+                       unsigned long private, int offlining);
 
 extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
@@ -23,12 +25,17 @@ extern int migrate_prep_local(void);
 extern int migrate_vmas(struct mm_struct *mm,
                const nodemask_t *from, const nodemask_t *to,
                unsigned long flags);
+extern void migrate_page_copy(struct page *newpage, struct page *page);
+extern int migrate_huge_page_move_mapping(struct address_space *mapping,
+                                 struct page *newpage, struct page *page);
 #else
 #define PAGE_MIGRATION 0
 
 static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, int offlining) { return -ENOSYS; }
+static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
+               unsigned long private, int offlining) { return -ENOSYS; }
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 static inline int migrate_prep_local(void) { return -ENOSYS; }
@@ -40,6 +47,15 @@ static inline int migrate_vmas(struct mm_struct *mm,
        return -ENOSYS;
 }
 
+static inline void migrate_page_copy(struct page *newpage,
+                                    struct page *page) {}
+
+static inline int migrate_huge_page_move_mapping(struct address_space *mapping,
+                                 struct page *newpage, struct page *page)
+{
+       return -ENOSYS;
+}
+
 /* Possible settings for the migrate_page() method in address_operations */
 #define migrate_page NULL
 #define fail_migrate_page NULL
index 78a1b96717523ba47b84867fc875aacef4f51e20..9a18667c13cc02a0709e648d339b0c72278887d0 100644 (file)
@@ -58,6 +58,7 @@ enum {
        MLX4_CMD_SENSE_PORT      = 0x4d,
        MLX4_CMD_HW_HEALTH_CHECK = 0x50,
        MLX4_CMD_SET_PORT        = 0xc,
+       MLX4_CMD_SET_NODE        = 0x5a,
        MLX4_CMD_ACCESS_DDR      = 0x2e,
        MLX4_CMD_MAP_ICM         = 0xffa,
        MLX4_CMD_UNMAP_ICM       = 0xff9,
@@ -141,6 +142,7 @@ enum {
        MLX4_SET_PORT_MAC_TABLE = 0x2,
        MLX4_SET_PORT_VLAN_TABLE = 0x3,
        MLX4_SET_PORT_PRIO_MAP  = 0x4,
+       MLX4_SET_PORT_GID_TABLE = 0x5,
 };
 
 struct mlx4_dev;
index 7338654c02b4de5402cbba6c80a3f96106e3b717..a7b15bc7648e27744fea2fee5de8cefb83f99340 100644 (file)
@@ -67,7 +67,8 @@ enum {
        MLX4_DEV_CAP_FLAG_ATOMIC        = 1 << 18,
        MLX4_DEV_CAP_FLAG_RAW_MCAST     = 1 << 19,
        MLX4_DEV_CAP_FLAG_UD_AV_PORT    = 1 << 20,
-       MLX4_DEV_CAP_FLAG_UD_MCAST      = 1 << 21
+       MLX4_DEV_CAP_FLAG_UD_MCAST      = 1 << 21,
+       MLX4_DEV_CAP_FLAG_IBOE          = 1 << 30
 };
 
 enum {
@@ -171,6 +172,10 @@ enum {
        MLX4_NUM_FEXCH          = 64 * 1024,
 };
 
+enum {
+       MLX4_MAX_FAST_REG_PAGES = 511,
+};
+
 static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor)
 {
        return (major << 32) | (minor << 16) | subminor;
@@ -379,6 +384,27 @@ struct mlx4_av {
        u8                      dgid[16];
 };
 
+struct mlx4_eth_av {
+       __be32          port_pd;
+       u8              reserved1;
+       u8              smac_idx;
+       u16             reserved2;
+       u8              reserved3;
+       u8              gid_index;
+       u8              stat_rate;
+       u8              hop_limit;
+       __be32          sl_tclass_flowlabel;
+       u8              dgid[16];
+       u32             reserved4[2];
+       __be16          vlan;
+       u8              mac[6];
+};
+
+union mlx4_ext_av {
+       struct mlx4_av          ib;
+       struct mlx4_eth_av      eth;
+};
+
 struct mlx4_dev {
        struct pci_dev         *pdev;
        unsigned long           flags;
@@ -407,6 +433,12 @@ struct mlx4_init_port_param {
                if (((type) == MLX4_PORT_TYPE_IB ? (dev)->caps.port_mask : \
                     ~(dev)->caps.port_mask) & 1 << ((port) - 1))
 
+#define mlx4_foreach_ib_transport_port(port, dev)                      \
+       for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++)     \
+               if (((dev)->caps.port_mask & 1 << ((port) - 1)) ||      \
+                   ((dev)->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
+
+
 int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
                   struct mlx4_buf *buf);
 void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
@@ -474,6 +506,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]);
 int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index);
 void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index);
 
+int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
 int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
 void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
 
index 53c5fdb6eac48cae01caa030700d3817538de7f0..f407cd4bfb341d7a2ac0a6f624130fa8430f6d51 100644 (file)
@@ -44,15 +44,24 @@ enum mlx4_dev_event {
        MLX4_DEV_EVENT_PORT_REINIT,
 };
 
+enum mlx4_protocol {
+       MLX4_PROTOCOL_IB,
+       MLX4_PROTOCOL_EN,
+};
+
 struct mlx4_interface {
        void *                  (*add)   (struct mlx4_dev *dev);
        void                    (*remove)(struct mlx4_dev *dev, void *context);
        void                    (*event) (struct mlx4_dev *dev, void *context,
                                          enum mlx4_dev_event event, int port);
+       void *                  (*get_dev)(struct mlx4_dev *dev, void *context, u8 port);
        struct list_head        list;
+       enum mlx4_protocol      protocol;
 };
 
 int mlx4_register_interface(struct mlx4_interface *intf);
 void mlx4_unregister_interface(struct mlx4_interface *intf);
 
+void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port);
+
 #endif /* MLX4_DRIVER_H */
index 7abe64326f7233bef36c31d3379ff9e8919d5dcb..0eeb2a1a867c97159f5a57c378dad3ad92c226d7 100644 (file)
@@ -109,10 +109,11 @@ struct mlx4_qp_path {
        __be32                  tclass_flowlabel;
        u8                      rgid[16];
        u8                      sched_queue;
-       u8                      snooper_flags;
+       u8                      vlan_index;
        u8                      reserved3[2];
        u8                      counter_index;
-       u8                      reserved4[7];
+       u8                      reserved4;
+       u8                      dmac[6];
 };
 
 struct mlx4_qp_context {
@@ -166,6 +167,7 @@ enum {
        MLX4_WQE_CTRL_TCP_UDP_CSUM      = 1 << 5,
        MLX4_WQE_CTRL_INS_VLAN          = 1 << 6,
        MLX4_WQE_CTRL_STRONG_ORDER      = 1 << 7,
+       MLX4_WQE_CTRL_FORCE_LOOPBACK    = 1 << 0,
 };
 
 struct mlx4_wqe_ctrl_seg {
@@ -219,7 +221,8 @@ struct mlx4_wqe_datagram_seg {
        __be32                  av[8];
        __be32                  dqpn;
        __be32                  qkey;
-       __be32                  reservd[2];
+       __be16                  vlan;
+       u8                      mac[6];
 };
 
 struct mlx4_wqe_lso_seg {
index 7687228dd3b7d16530cf28087ea71f07155ee3ba..721f451c3029bb756324458f93eccf107778d746 100644 (file)
@@ -144,6 +144,7 @@ extern pgprot_t protection_map[16];
 #define FAULT_FLAG_WRITE       0x01    /* Fault was a write access */
 #define FAULT_FLAG_NONLINEAR   0x02    /* Fault was via a nonlinear mapping */
 #define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
+#define FAULT_FLAG_ALLOW_RETRY 0x08    /* Retry fault if blocking */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -497,8 +498,8 @@ static inline void set_compound_order(struct page *page, unsigned long order)
 #define NODES_PGSHIFT          (NODES_PGOFF * (NODES_WIDTH != 0))
 #define ZONES_PGSHIFT          (ZONES_PGOFF * (ZONES_WIDTH != 0))
 
-/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allcator */
-#ifdef NODE_NOT_IN_PAGEFLAGS
+/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */
+#ifdef NODE_NOT_IN_PAGE_FLAGS
 #define ZONEID_SHIFT           (SECTIONS_SHIFT + ZONES_SHIFT)
 #define ZONEID_PGOFF           ((SECTIONS_PGOFF < ZONES_PGOFF)? \
                                                SECTIONS_PGOFF : ZONES_PGOFF)
@@ -718,12 +719,21 @@ static inline int page_mapped(struct page *page)
 #define VM_FAULT_SIGBUS        0x0002
 #define VM_FAULT_MAJOR 0x0004
 #define VM_FAULT_WRITE 0x0008  /* Special case for get_user_pages */
-#define VM_FAULT_HWPOISON 0x0010       /* Hit poisoned page */
+#define VM_FAULT_HWPOISON 0x0010       /* Hit poisoned small page */
+#define VM_FAULT_HWPOISON_LARGE 0x0020  /* Hit poisoned large page. Index encoded in upper bits */
 
 #define VM_FAULT_NOPAGE        0x0100  /* ->fault installed the pte, not return page */
 #define VM_FAULT_LOCKED        0x0200  /* ->fault locked the returned page */
+#define VM_FAULT_RETRY 0x0400  /* ->fault blocked, must retry */
+
+#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
+
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
+                        VM_FAULT_HWPOISON_LARGE)
 
-#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)
+/* Encode hstate index for a hwpoisoned large page */
+#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
+#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0xf)
 
 /*
  * Can be called by the pagefault handler when it gets a VM_FAULT_OOM.
@@ -860,6 +870,7 @@ int __set_page_dirty_no_writeback(struct page *page);
 int redirty_page_for_writepage(struct writeback_control *wbc,
                                struct page *page);
 void account_page_dirtied(struct page *page, struct address_space *mapping);
+void account_page_writeback(struct page *page);
 int set_page_dirty(struct page *page);
 int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
@@ -1023,7 +1034,15 @@ extern void unregister_shrinker(struct shrinker *);
 
 int vma_wants_writenotify(struct vm_area_struct *vma);
 
-extern pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl);
+extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
+                              spinlock_t **ptl);
+static inline pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+                                   spinlock_t **ptl)
+{
+       pte_t *ptep;
+       __cond_lock(*ptl, ptep = __get_locked_pte(mm, addr, ptl));
+       return ptep;
+}
 
 #ifdef __PAGETABLE_PUD_FOLDED
 static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd,
index cb57d657ce4d2643c58e21eb23b2b1434f0f7a2f..bb7288a782fde2ff1d19978a7b9cb387476575ba 100644 (file)
@@ -310,6 +310,8 @@ struct mm_struct {
 #ifdef CONFIG_MMU_NOTIFIER
        struct mmu_notifier_mm *mmu_notifier_mm;
 #endif
+       /* How many tasks sharing this mm are OOM_DISABLE */
+       atomic_t oom_disable_count;
 };
 
 /* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
index 3984c4eb41fdc9c85759dbffe308df5a806391f4..39c24ebe9cfd4e75b8841deec06aa6d78c91c2ad 100644 (file)
@@ -104,6 +104,8 @@ enum zone_stat_item {
        NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
        NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
        NR_SHMEM,               /* shmem pages (included tmpfs/GEM pages) */
+       NR_DIRTIED,             /* page dirtyings since bootup */
+       NR_WRITTEN,             /* page writings since bootup */
 #ifdef CONFIG_NUMA
        NUMA_HIT,               /* allocated in intended node */
        NUMA_MISS,              /* allocated in non intended node */
@@ -421,6 +423,9 @@ struct zone {
 typedef enum {
        ZONE_RECLAIM_LOCKED,            /* prevents concurrent reclaim */
        ZONE_OOM_LOCKED,                /* zone is in OOM killer zonelist */
+       ZONE_CONGESTED,                 /* zone has many dirty pages backed by
+                                        * a congested BDI
+                                        */
 } zone_flags_t;
 
 static inline void zone_set_flag(struct zone *zone, zone_flags_t flag)
@@ -438,6 +443,11 @@ static inline void zone_clear_flag(struct zone *zone, zone_flags_t flag)
        clear_bit(flag, &zone->flags);
 }
 
+static inline int zone_is_reclaim_congested(const struct zone *zone)
+{
+       return test_bit(ZONE_CONGESTED, &zone->flags);
+}
+
 static inline int zone_is_reclaim_locked(const struct zone *zone)
 {
        return test_bit(ZONE_RECLAIM_LOCKED, &zone->flags);
index 9d2f1837b3d8615e64395157c06f993dff16468e..112adf8bd47dd2c1d13800577f340d6cfa9c0b46 100644 (file)
@@ -21,8 +21,8 @@
 #define __module_cat(a,b) ___module_cat(a,b)
 #define __MODULE_INFO(tag, name, info)                                   \
 static const char __module_cat(name,__LINE__)[]                                  \
-  __used                                                                 \
-  __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info
+  __used __attribute__((section(".modinfo"), unused, aligned(1)))        \
+  = __stringify(tag) "=" info
 #else  /* !MODULE */
 #define __MODULE_INFO(tag, name, info)
 #endif
index dee0b11a87590b31750706fec2bfe93bfec7d2bf..16faa130088c298fe8540b7fa29d365d0ea579b7 100644 (file)
@@ -229,6 +229,8 @@ enum {
 extern int          sock_wake_async(struct socket *sk, int how, int band);
 extern int          sock_register(const struct net_proto_family *fam);
 extern void         sock_unregister(int family);
+extern int          __sock_create(struct net *net, int family, int type, int proto,
+                                struct socket **res, int kern);
 extern int          sock_create(int family, int type, int proto,
                                 struct socket **res);
 extern int          sock_create_kern(int family, int type, int proto,
index 07e40c62597211c58d50ce4d61fca14a8021c34f..4925b22219d25cfa654aa9d515950acc36d977f4 100644 (file)
@@ -17,7 +17,9 @@
 
 #define NFS4_BITMAP_SIZE       2
 #define NFS4_VERIFIER_SIZE     8
-#define NFS4_STATEID_SIZE      16
+#define NFS4_STATEID_SEQID_SIZE 4
+#define NFS4_STATEID_OTHER_SIZE 12
+#define NFS4_STATEID_SIZE      (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SIZE)
 #define NFS4_FHSIZE            128
 #define NFS4_MAXPATHLEN                PATH_MAX
 #define NFS4_MAXNAMLEN         NAME_MAX
@@ -61,6 +63,9 @@
 #define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL       0x10000
 #define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED         0x20000
 
+#define NFS4_CDFC4_FORE        0x1
+#define NFS4_CDFC4_BACK 0x2
+
 #define NFS4_SET_TO_SERVER_TIME        0
 #define NFS4_SET_TO_CLIENT_TIME        1
 
@@ -167,7 +172,16 @@ struct nfs4_acl {
 };
 
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
-typedef struct { char data[NFS4_STATEID_SIZE]; } nfs4_stateid;
+
+struct nfs41_stateid {
+       __be32 seqid;
+       char other[NFS4_STATEID_OTHER_SIZE];
+} __attribute__ ((packed));
+
+typedef union {
+       char data[NFS4_STATEID_SIZE];
+       struct nfs41_stateid stateid;
+} nfs4_stateid;
 
 enum nfs_opnum4 {
        OP_ACCESS = 3,
@@ -471,6 +485,8 @@ enum lock_type4 {
 #define FATTR4_WORD1_TIME_MODIFY        (1UL << 21)
 #define FATTR4_WORD1_TIME_MODIFY_SET    (1UL << 22)
 #define FATTR4_WORD1_MOUNTED_ON_FILEID  (1UL << 23)
+#define FATTR4_WORD1_FS_LAYOUT_TYPES    (1UL << 30)
+#define FATTR4_WORD2_LAYOUT_BLKSIZE     (1UL << 1)
 
 #define NFSPROC4_NULL 0
 #define NFSPROC4_COMPOUND 1
@@ -532,6 +548,8 @@ enum {
        NFSPROC4_CLNT_SEQUENCE,
        NFSPROC4_CLNT_GET_LEASE_TIME,
        NFSPROC4_CLNT_RECLAIM_COMPLETE,
+       NFSPROC4_CLNT_LAYOUTGET,
+       NFSPROC4_CLNT_GETDEVICEINFO,
 };
 
 /* nfs41 types */
@@ -550,6 +568,49 @@ enum state_protect_how4 {
        SP4_SSV         = 2
 };
 
+enum pnfs_layouttype {
+       LAYOUT_NFSV4_1_FILES  = 1,
+       LAYOUT_OSD2_OBJECTS = 2,
+       LAYOUT_BLOCK_VOLUME = 3,
+};
+
+/* used for both layout return and recall */
+enum pnfs_layoutreturn_type {
+       RETURN_FILE = 1,
+       RETURN_FSID = 2,
+       RETURN_ALL  = 3
+};
+
+enum pnfs_iomode {
+       IOMODE_READ = 1,
+       IOMODE_RW = 2,
+       IOMODE_ANY = 3,
+};
+
+enum pnfs_notify_deviceid_type4 {
+       NOTIFY_DEVICEID4_CHANGE = 1 << 1,
+       NOTIFY_DEVICEID4_DELETE = 1 << 2,
+};
+
+#define NFL4_UFLG_MASK                 0x0000003F
+#define NFL4_UFLG_DENSE                        0x00000001
+#define NFL4_UFLG_COMMIT_THRU_MDS      0x00000002
+#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK        0xFFFFFFC0
+
+/* Encoded in the loh_body field of type layouthint4 */
+enum filelayout_hint_care4 {
+       NFLH4_CARE_DENSE                = NFL4_UFLG_DENSE,
+       NFLH4_CARE_COMMIT_THRU_MDS      = NFL4_UFLG_COMMIT_THRU_MDS,
+       NFLH4_CARE_STRIPE_UNIT_SIZE     = 0x00000040,
+       NFLH4_CARE_STRIPE_COUNT         = 0x00000080
+};
+
+#define NFS4_DEVICEID4_SIZE 16
+
+struct nfs4_deviceid {
+       char data[NFS4_DEVICEID4_SIZE];
+};
+
 #endif
 #endif
 
index d0edf7d823ae3ef60ec2ba6c6daa3ff0b34643cd..bba26684acdc5e0e9364419db9cc3fb7802c1109 100644 (file)
@@ -188,6 +188,9 @@ struct nfs_inode {
        struct nfs_delegation __rcu *delegation;
        fmode_t                  delegation_state;
        struct rw_semaphore     rwsem;
+
+       /* pNFS layout information */
+       struct pnfs_layout_hdr *layout;
 #endif /* CONFIG_NFS_V4*/
 #ifdef CONFIG_NFS_FSCACHE
        struct fscache_cookie   *fscache;
@@ -360,10 +363,13 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
 extern void put_nfs_open_context(struct nfs_open_context *ctx);
 extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
+extern struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode);
+extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
 extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx);
 extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
 extern u64 nfs_compat_user_ino64(u64 fileid);
 extern void nfs_fattr_init(struct nfs_fattr *fattr);
+extern unsigned long nfs_inc_attr_generation_counter(void);
 
 extern struct nfs_fattr *nfs_alloc_fattr(void);
 
@@ -379,9 +385,12 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh)
        kfree(fh);
 }
 
+/*
+ * linux/fs/nfs/nfsroot.c
+ */
+extern int  nfs_root_data(char **root_device, char **root_data); /*__init*/
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
 extern __be32 root_nfs_parse_addr(char *name); /*__init*/
-extern unsigned long nfs_inc_attr_generation_counter(void);
 
 /*
  * linux/fs/nfs/file.c
@@ -479,10 +488,10 @@ extern void nfs_release_automount_timer(void);
 /*
  * linux/fs/nfs/unlink.c
  */
-extern int  nfs_async_unlink(struct inode *dir, struct dentry *dentry);
 extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
 extern void nfs_block_sillyrename(struct dentry *dentry);
 extern void nfs_unblock_sillyrename(struct dentry *dentry);
+extern int  nfs_sillyrename(struct inode *dir, struct dentry *dentry);
 
 /*
  * linux/fs/nfs/write.c
@@ -584,10 +593,6 @@ nfs_fileid_to_ino_t(u64 fileid)
        return ino;
 }
 
-/* NFS root */
-
-extern void * nfs_root_data(void);
-
 #define nfs_wait_event(clnt, wq, condition)                            \
 ({                                                                     \
        int __retval = wait_event_killable(wq, condition);              \
@@ -613,6 +618,8 @@ extern void * nfs_root_data(void);
 #define NFSDBG_CLIENT          0x0200
 #define NFSDBG_MOUNT           0x0400
 #define NFSDBG_FSCACHE         0x0800
+#define NFSDBG_PNFS            0x1000
+#define NFSDBG_PNFS_LD         0x2000
 #define NFSDBG_ALL             0xFFFF
 
 #ifdef __KERNEL__
index c82ee7cd6288573186a664d12b16bdd2a3ea07f1..452d96436d266d6ea6cef73f2e3e1dd74a1f76b2 100644 (file)
@@ -82,6 +82,8 @@ struct nfs_client {
        /* The flags used for obtaining the clientid during EXCHANGE_ID */
        u32                     cl_exchange_flags;
        struct nfs4_session     *cl_session;    /* sharred session */
+       struct list_head        cl_layouts;
+       struct pnfs_deviceid_cache *cl_devid_cache; /* pNFS deviceid cache */
 #endif /* CONFIG_NFS_V4_1 */
 
 #ifdef CONFIG_NFS_FSCACHE
@@ -124,6 +126,7 @@ struct nfs_server {
 
        struct nfs_fsid         fsid;
        __u64                   maxfilesize;    /* maximum file size */
+       struct timespec         time_delta;     /* smallest time granularity */
        unsigned long           mount_time;     /* when this fs was mounted */
        dev_t                   s_dev;          /* superblock dev numbers */
 
@@ -144,6 +147,7 @@ struct nfs_server {
        u32                     acl_bitmask;    /* V4 bitmask representing the ACEs
                                                   that are supported on this
                                                   filesystem */
+       struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
 #endif
        void (*destroy)(struct nfs_server *);
 
index 91a1c24e0cbffdeb97e28d072cd657510d22faab..e8352dc5afb5921d0adb5e7e882a7adf87e3f250 100644 (file)
@@ -66,13 +66,40 @@ struct idmap_msg {
 /* Forward declaration to make this header independent of others */
 struct nfs_client;
 
+#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
+
+int nfs_idmap_init(void);
+void nfs_idmap_quit(void);
+
+static inline int nfs_idmap_new(struct nfs_client *clp)
+{
+       return 0;
+}
+
+static inline void nfs_idmap_delete(struct nfs_client *clp)
+{
+}
+
+#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
+
+static inline int nfs_idmap_init(void)
+{
+       return 0;
+}
+
+static inline void nfs_idmap_quit(void)
+{
+}
+
 int nfs_idmap_new(struct nfs_client *);
 void nfs_idmap_delete(struct nfs_client *);
 
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
+
 int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *);
 int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *);
-int nfs_map_uid_to_name(struct nfs_client *, __u32, char *);
-int nfs_map_gid_to_group(struct nfs_client *, __u32, char *);
+int nfs_map_uid_to_name(struct nfs_client *, __u32, char *, size_t);
+int nfs_map_gid_to_group(struct nfs_client *, __u32, char *, size_t);
 
 extern unsigned int nfs_idmap_cache_timeout;
 #endif /* __KERNEL__ */
index 5d59ae861aa6a1c55b0672d1a58d9d3890121871..576bddd72e0402b6020208da922c2837b321bb49 100644 (file)
@@ -71,4 +71,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_NORESVPORT           0x40000
 #define NFS_MOUNT_LEGACY_INTERFACE     0x80000
 
+#define NFS_MOUNT_LOCAL_FLOCK  0x100000
+#define NFS_MOUNT_LOCAL_FCNTL  0x200000
+
 #endif
index fc461926c412e58d91d717aa7a9cbd48d407ea01..ba6cc8f223c94190a13a2e1ef2316f993c205010 100644 (file)
@@ -112,7 +112,9 @@ struct nfs_fsinfo {
        __u32                   wtmult; /* writes should be multiple of this */
        __u32                   dtpref; /* pref. readdir transfer size */
        __u64                   maxfilesize;
+       struct timespec         time_delta; /* server time granularity */
        __u32                   lease_time; /* in seconds */
+       __u32                   layouttype; /* supported pnfs layout driver */
 };
 
 struct nfs_fsstat {
@@ -170,7 +172,7 @@ struct nfs4_sequence_args {
 
 struct nfs4_sequence_res {
        struct nfs4_session     *sr_session;
-       u8                      sr_slotid;      /* slot used to send request */
+       struct nfs4_slot        *sr_slot;       /* slot used to send request */
        int                     sr_status;      /* sequence operation status */
        unsigned long           sr_renewal_time;
        u32                     sr_status_flags;
@@ -185,6 +187,55 @@ struct nfs4_get_lease_time_res {
        struct nfs4_sequence_res        lr_seq_res;
 };
 
+#define PNFS_LAYOUT_MAXSIZE 4096
+
+struct nfs4_layoutdriver_data {
+       __u32 len;
+       void *buf;
+};
+
+struct pnfs_layout_range {
+       u32 iomode;
+       u64 offset;
+       u64 length;
+};
+
+struct nfs4_layoutget_args {
+       __u32 type;
+       struct pnfs_layout_range range;
+       __u64 minlength;
+       __u32 maxcount;
+       struct inode *inode;
+       struct nfs_open_context *ctx;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_layoutget_res {
+       __u32 return_on_close;
+       struct pnfs_layout_range range;
+       __u32 type;
+       nfs4_stateid stateid;
+       struct nfs4_layoutdriver_data layout;
+       struct nfs4_sequence_res seq_res;
+};
+
+struct nfs4_layoutget {
+       struct nfs4_layoutget_args args;
+       struct nfs4_layoutget_res res;
+       struct pnfs_layout_segment **lsegpp;
+       int status;
+};
+
+struct nfs4_getdeviceinfo_args {
+       struct pnfs_device *pdev;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_getdeviceinfo_res {
+       struct pnfs_device *pdev;
+       struct nfs4_sequence_res seq_res;
+};
+
 /*
  * Arguments to the open call.
  */
@@ -399,6 +450,27 @@ struct nfs_removeres {
        struct nfs4_sequence_res        seq_res;
 };
 
+/*
+ * Common arguments to the rename call
+ */
+struct nfs_renameargs {
+       const struct nfs_fh             *old_dir;
+       const struct nfs_fh             *new_dir;
+       const struct qstr               *old_name;
+       const struct qstr               *new_name;
+       const u32                       *bitmask;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs_renameres {
+       const struct nfs_server         *server;
+       struct nfs4_change_info         old_cinfo;
+       struct nfs_fattr                *old_fattr;
+       struct nfs4_change_info         new_cinfo;
+       struct nfs_fattr                *new_fattr;
+       struct nfs4_sequence_res        seq_res;
+};
+
 /*
  * Argument struct for decode_entry function
  */
@@ -434,15 +506,6 @@ struct nfs_createargs {
        struct iattr *          sattr;
 };
 
-struct nfs_renameargs {
-       struct nfs_fh *         fromfh;
-       const char *            fromname;
-       unsigned int            fromlen;
-       struct nfs_fh *         tofh;
-       const char *            toname;
-       unsigned int            tolen;
-};
-
 struct nfs_setattrargs {
        struct nfs_fh *                 fh;
        nfs4_stateid                    stateid;
@@ -586,15 +649,6 @@ struct nfs3_mknodargs {
        dev_t                   rdev;
 };
 
-struct nfs3_renameargs {
-       struct nfs_fh *         fromfh;
-       const char *            fromname;
-       unsigned int            fromlen;
-       struct nfs_fh *         tofh;
-       const char *            toname;
-       unsigned int            tolen;
-};
-
 struct nfs3_linkargs {
        struct nfs_fh *         fromfh;
        struct nfs_fh *         tofh;
@@ -629,11 +683,6 @@ struct nfs3_readlinkargs {
        struct page **          pages;
 };
 
-struct nfs3_renameres {
-       struct nfs_fattr *      fromattr;
-       struct nfs_fattr *      toattr;
-};
-
 struct nfs3_linkres {
        struct nfs_fattr *      dir_attr;
        struct nfs_fattr *      fattr;
@@ -780,6 +829,7 @@ struct nfs4_readdir_arg {
        struct page **                  pages;  /* zero-copy data */
        unsigned int                    pgbase; /* zero-copy data */
        const u32 *                     bitmask;
+       int                             plus;
        struct nfs4_sequence_args       seq_args;
 };
 
@@ -801,24 +851,6 @@ struct nfs4_readlink_res {
        struct nfs4_sequence_res        seq_res;
 };
 
-struct nfs4_rename_arg {
-       const struct nfs_fh *           old_dir;
-       const struct nfs_fh *           new_dir;
-       const struct qstr *             old_name;
-       const struct qstr *             new_name;
-       const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
-};
-
-struct nfs4_rename_res {
-       const struct nfs_server *       server;
-       struct nfs4_change_info         old_cinfo;
-       struct nfs_fattr *              old_fattr;
-       struct nfs4_change_info         new_cinfo;
-       struct nfs_fattr *              new_fattr;
-       struct nfs4_sequence_res        seq_res;
-};
-
 #define NFS4_SETCLIENTID_NAMELEN       (127)
 struct nfs4_setclientid {
        const nfs4_verifier *           sc_verifier;
@@ -1032,19 +1064,21 @@ struct nfs_rpc_ops {
        int     (*readlink)(struct inode *, struct page *, unsigned int,
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
-                           struct iattr *, int, struct nameidata *);
+                           struct iattr *, int, struct nfs_open_context *);
        int     (*remove)  (struct inode *, struct qstr *);
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
        int     (*rename)  (struct inode *, struct qstr *,
                            struct inode *, struct qstr *);
+       void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
+       int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
        int     (*link)    (struct inode *, struct inode *, struct qstr *);
        int     (*symlink) (struct inode *, struct dentry *, struct page *,
                            unsigned int, struct iattr *);
        int     (*mkdir)   (struct inode *, struct dentry *, struct iattr *);
        int     (*rmdir)   (struct inode *, struct qstr *);
        int     (*readdir) (struct dentry *, struct rpc_cred *,
-                           u64, struct page *, unsigned int, int);
+                           u64, struct page **, unsigned int, int);
        int     (*mknod)   (struct inode *, struct dentry *, struct iattr *,
                            dev_t);
        int     (*statfs)  (struct nfs_server *, struct nfs_fh *,
@@ -1054,7 +1088,7 @@ struct nfs_rpc_ops {
        int     (*pathconf) (struct nfs_server *, struct nfs_fh *,
                             struct nfs_pathconf *);
        int     (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
-       __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus);
+       __be32 *(*decode_dirent)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int plus);
        void    (*read_setup)   (struct nfs_read_data *, struct rpc_message *);
        int     (*read_done)  (struct rpc_task *, struct nfs_read_data *);
        void    (*write_setup)  (struct nfs_write_data *, struct rpc_message *);
@@ -1065,6 +1099,10 @@ struct nfs_rpc_ops {
        int     (*lock_check_bounds)(const struct file_lock *);
        void    (*clear_acl_cache)(struct inode *);
        void    (*close_context)(struct nfs_open_context *ctx, int);
+       struct inode * (*open_context) (struct inode *dir,
+                               struct nfs_open_context *ctx,
+                               int open_flags,
+                               struct iattr *iattr);
 };
 
 /*
index 835f85ecd2de3eb1331a82a4de24222d5dd98fe1..975d347079d95ee7015e976a95888951c348a538 100644 (file)
@@ -27,20 +27,19 @@ static inline int of_driver_match_device(const struct device *dev,
 extern struct platform_device *of_dev_get(struct platform_device *dev);
 extern void of_dev_put(struct platform_device *dev);
 
+extern int of_device_add(struct platform_device *pdev);
 extern int of_device_register(struct platform_device *ofdev);
 extern void of_device_unregister(struct platform_device *ofdev);
-extern void of_release_dev(struct device *dev);
-
-static inline void of_device_free(struct platform_device *dev)
-{
-       of_release_dev(&dev->dev);
-}
 
 extern ssize_t of_device_get_modalias(struct device *dev,
                                        char *str, ssize_t len);
 
 extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 
+static inline void of_device_node_put(struct device *dev)
+{
+       of_node_put(dev->of_node);
+}
 
 #else /* CONFIG_OF_DEVICE */
 
@@ -56,6 +55,8 @@ static inline int of_device_uevent(struct device *dev,
        return -ENODEV;
 }
 
+static inline void of_device_node_put(struct device *dev) { }
+
 #endif /* CONFIG_OF_DEVICE */
 
 #endif /* _LINUX_OF_DEVICE_H */
index 71e1a916d3fa9d6fbd6876a7aacc695711123a40..7bbf5b32843897a4b09c700a430221a6f6002897 100644 (file)
@@ -72,7 +72,7 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
                                 unsigned long *size);
 extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
 extern unsigned long of_get_flat_dt_root(void);
-extern void early_init_dt_scan_chosen_arch(unsigned long node);
+
 extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data);
 extern void early_init_dt_check_for_initrd(unsigned long node);
index 5929781c104df9443ab56bb9c5b07d682a0b2f6a..109e013b177295c927d133f525ff847ee6f8d985 100644 (file)
@@ -5,6 +5,7 @@
 struct of_irq;
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/irq.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
 
@@ -64,6 +65,9 @@ extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          unsigned int intsize);
 extern int of_irq_to_resource(struct device_node *dev, int index,
                              struct resource *r);
+extern int of_irq_count(struct device_node *dev);
+extern int of_irq_to_resource_table(struct device_node *dev,
+               struct resource *res, int nr_irqs);
 
 #endif /* CONFIG_OF_IRQ */
 #endif /* CONFIG_OF */
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h
new file mode 100644 (file)
index 0000000..c65a18a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Definitions for building a device tree by calling into the
+ * Open Firmware PROM.
+ *
+ * Copyright (C) 2010  Andres Salomon <dilinger@queued.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.
+ */
+
+#ifndef _LINUX_OF_PDT_H
+#define _LINUX_OF_PDT_H
+
+/* overridable operations for calling into the PROM */
+struct of_pdt_ops {
+       /*
+        * buf should be 32 bytes; return 0 on success.
+        * If prev is NULL, the first property will be returned.
+        */
+       int (*nextprop)(phandle node, char *prev, char *buf);
+
+       /* for both functions, return proplen on success; -1 on error */
+       int (*getproplen)(phandle node, const char *prop);
+       int (*getproperty)(phandle node, const char *prop, char *buf,
+                       int bufsize);
+
+       /* phandles are 0 if no child or sibling exists */
+       phandle (*getchild)(phandle parent);
+       phandle (*getsibling)(phandle node);
+
+       /* return 0 on success; fill in 'len' with number of bytes in path */
+       int (*pkg2path)(phandle node, char *buf, const int buflen, int *len);
+};
+
+extern void *prom_early_alloc(unsigned long size);
+
+/* for building the device tree */
+extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
+
+extern void (*of_pdt_build_more)(struct device_node *dp,
+               struct device_node ***nextp);
+
+#endif /* _LINUX_OF_PDT_H */
index 6fa317801e1c72be3e6977b538f49da988be49ee..5f38c460367e41c1d9c7f9dab04fb2af993f52dc 100644 (file)
@@ -310,7 +310,7 @@ static inline void SetPageUptodate(struct page *page)
 {
 #ifdef CONFIG_S390
        if (!test_and_set_bit(PG_uptodate, &page->flags))
-               page_clear_dirty(page);
+               page_clear_dirty(page, 0);
 #else
        /*
         * Memory barrier must be issued before setting the PG_uptodate bit,
index e8c06122be36058f88cb6e291360eb2c0ebe09a0..19ef95d293aecbc9f23e48b0235ef47625e70536 100644 (file)
@@ -67,7 +67,8 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
 
 #define get_pageblock_flags(page) \
                        get_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
-#define set_pageblock_flags(page) \
-                       set_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
+#define set_pageblock_flags(page, flags) \
+                       set_pageblock_flags_group(page, flags,  \
+                                                 0, NR_PAGEBLOCK_BITS-1)
 
 #endif /* PAGEBLOCK_FLAGS_H */
index e12cdc6d79ee79e80ddbcf6709e97a403a4746f7..2d1ffe3cf1ee6ae4d8f443ed5db16044244c413e 100644 (file)
@@ -299,6 +299,8 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
 extern void __lock_page(struct page *page);
 extern int __lock_page_killable(struct page *page);
 extern void __lock_page_nosync(struct page *page);
+extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
+                               unsigned int flags);
 extern void unlock_page(struct page *page);
 
 static inline void __set_page_locked(struct page *page)
@@ -350,6 +352,17 @@ static inline void lock_page_nosync(struct page *page)
                __lock_page_nosync(page);
 }
        
+/*
+ * lock_page_or_retry - Lock the page, unless this would block and the
+ * caller indicated that it can handle a retry.
+ */
+static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm,
+                                    unsigned int flags)
+{
+       might_sleep();
+       return trylock_page(page) || __lock_page_or_retry(page, mm, flags);
+}
+
 /*
  * This is exported only for wait_on_page_locked/wait_on_page_writeback.
  * Never use this directly!
index d278dd9cb76510aeedb248d0be2ff071de4e98f0..b4c3d1b500370bc7d96f4ac7ed9ec092f5f608a9 100644 (file)
 
 #define PCI_VENDOR_ID_SILAN            0x1904
 
+#define PCI_VENDOR_ID_RENESAS          0x1912
+#define PCI_DEVICE_ID_RENESAS_SH7781   0x0001
+#define PCI_DEVICE_ID_RENESAS_SH7780   0x0002
+#define PCI_DEVICE_ID_RENESAS_SH7763   0x0004
+#define PCI_DEVICE_ID_RENESAS_SH7785   0x0007
+#define PCI_DEVICE_ID_RENESAS_SH7786   0x0010
+
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
index 30083a896f3628418fa42114a582dc18396c66e9..7d7325685c421a8b7da8746ea47583396bb61b8c 100644 (file)
@@ -89,6 +89,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_CURRENT_MAX,
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CURRENT_AVG,
        POWER_SUPPLY_PROP_POWER_NOW,
@@ -125,7 +126,10 @@ enum power_supply_type {
        POWER_SUPPLY_TYPE_BATTERY = 0,
        POWER_SUPPLY_TYPE_UPS,
        POWER_SUPPLY_TYPE_MAINS,
-       POWER_SUPPLY_TYPE_USB,
+       POWER_SUPPLY_TYPE_USB,          /* Standard Downstream Port */
+       POWER_SUPPLY_TYPE_USB_DCP,      /* Dedicated Charging Port */
+       POWER_SUPPLY_TYPE_USB_CDP,      /* Charging Downstream Port */
+       POWER_SUPPLY_TYPE_USB_ACA,      /* Accessory Charger Adapters */
 };
 
 union power_supply_propval {
index 8f69d09a41a50265977c4e89c2ad13672d98a816..03ff67b0cdf5403deab6f69924c3f9a419e644db 100644 (file)
@@ -36,6 +36,8 @@ static inline void ratelimit_state_init(struct ratelimit_state *rs,
        rs->begin = 0;
 }
 
+extern struct ratelimit_state printk_ratelimit_state;
+
 extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
 #define __ratelimit(state) ___ratelimit(state, __func__)
 
index 91a4177e60ce3779e21c7a3fd8bfbc08858d43f3..5ca47e59b7278ffbb0dd4fc624d9e4cf1697d0ae 100644 (file)
@@ -2072,6 +2072,8 @@ void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
 void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
 int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
 
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
+
 /* namei.c */
 void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
 int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
index 31b2fd75dcbae59d3ed633253c1f5cd3850c201a..bb83c0da207197122c9ef3988cf0b3d843404cd3 100644 (file)
@@ -25,8 +25,8 @@
  * pointing to this anon_vma once its vma list is empty.
  */
 struct anon_vma {
-       spinlock_t lock;        /* Serialize access to vma list */
        struct anon_vma *root;  /* Root of this anon_vma tree */
+       spinlock_t lock;        /* Serialize access to vma list */
 #if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
 
        /*
@@ -205,9 +205,20 @@ int try_to_unmap_one(struct page *, struct vm_area_struct *,
 /*
  * Called from mm/filemap_xip.c to unmap empty zero page
  */
-pte_t *page_check_address(struct page *, struct mm_struct *,
+pte_t *__page_check_address(struct page *, struct mm_struct *,
                                unsigned long, spinlock_t **, int);
 
+static inline pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+                                       unsigned long address,
+                                       spinlock_t **ptlp, int sync)
+{
+       pte_t *ptep;
+
+       __cond_lock(*ptlp, ptep = __page_check_address(page, mm, address,
+                                                      ptlp, sync));
+       return ptep;
+}
+
 /*
  * Used by swapoff to help locate where page is expected in vma.
  */
@@ -230,7 +241,20 @@ int try_to_munlock(struct page *);
 /*
  * Called by memory-failure.c to kill processes.
  */
-struct anon_vma *page_lock_anon_vma(struct page *page);
+struct anon_vma *__page_lock_anon_vma(struct page *page);
+
+static inline struct anon_vma *page_lock_anon_vma(struct page *page)
+{
+       struct anon_vma *anon_vma;
+
+       __cond_lock(RCU, anon_vma = __page_lock_anon_vma(page));
+
+       /* (void) is needed to make gcc happy */
+       (void) __cond_lock(&anon_vma->root->lock, anon_vma);
+
+       return anon_vma;
+}
+
 void page_unlock_anon_vma(struct anon_vma *anon_vma);
 int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
 
index 56154bbb8da9cf012f990d31448f741538201bcb..393ce94e54b77155227f5df48cf7e81e6b9ec09f 100644 (file)
@@ -1706,7 +1706,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_DUMPCORE    0x00000200      /* dumped core */
 #define PF_SIGNALED    0x00000400      /* killed by a signal */
 #define PF_MEMALLOC    0x00000800      /* Allocating memory */
-#define PF_FLUSHER     0x00001000      /* responsible for disk writeback */
 #define PF_USED_MATH   0x00002000      /* if unset the fpu must be initialized before use */
 #define PF_FREEZING    0x00004000      /* freeze in progress. do not account to load */
 #define PF_NOFREEZE    0x00008000      /* this thread should not be frozen */
index 99e5994e6f84ec106dbd5760e4966243cbb91f70..212eb4c67797ba9b5e27fb9258d583d68d7a85d5 100644 (file)
 /* High Speed UART for Medfield */
 #define PORT_MFD       95
 
+/* TI OMAP-UART */
+#define PORT_OMAP      96
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index b5552568178d9c459412bac9f10671b822ca2af4..e26f4788845fcef5f6b0ed2181cfd36163cb4327 100644 (file)
@@ -41,7 +41,9 @@ struct serio {
        int (*start)(struct serio *);
        void (*stop)(struct serio *);
 
-       struct serio *parent, *child;
+       struct serio *parent;
+       struct list_head child_node;    /* Entry in parent->children list */
+       struct list_head children;
        unsigned int depth;             /* level of nesting in serio hierarchy */
 
        struct serio_driver *drv;       /* accessed from interrupt, must be protected by serio->lock and serio->sem */
@@ -54,10 +56,9 @@ struct serio {
 #define to_serio_port(d)       container_of(d, struct serio, dev)
 
 struct serio_driver {
-       void *private;
-       char *description;
+       const char *description;
 
-       struct serio_device_id *id_table;
+       const struct serio_device_id *id_table;
        bool manual_bind;
 
        void (*write_wakeup)(struct serio *);
@@ -197,5 +198,6 @@ static inline void serio_continue_rx(struct serio *serio)
 #define SERIO_W8001    0x39
 #define SERIO_DYNAPRO  0x3a
 #define SERIO_HAMPSHIRE        0x3b
+#define SERIO_PS2MULT  0x3c
 
 #endif
index 0299b4ce63dbd4b96faf4265043a75ccfacc6183..7f770c638e99d670840ed99856dce0b07a660f8b 100644 (file)
@@ -70,9 +70,6 @@
 #define SFI_SIG_APIC           "APIC"
 #define SFI_SIG_XSDT           "XSDT"
 #define SFI_SIG_WAKE           "WAKE"
-#define SFI_SIG_SPIB           "SPIB"
-#define SFI_SIG_I2CB           "I2CB"
-#define SFI_SIG_GPEM           "GPEM"
 #define SFI_SIG_DEVS           "DEVS"
 #define SFI_SIG_GPIO           "GPIO"
 
@@ -168,27 +165,6 @@ struct sfi_gpio_table_entry {
        char    pin_name[16];
 } __packed;
 
-struct sfi_spi_table_entry {
-       u16     host_num;       /* attached to host 0, 1...*/
-       u16     cs;             /* chip select */
-       u16     irq_info;
-       char    name[16];
-       u8      dev_info[10];
-} __packed;
-
-struct sfi_i2c_table_entry {
-       u16     host_num;
-       u16     addr;           /* slave addr */
-       u16     irq_info;
-       char    name[16];
-       u8      dev_info[10];
-} __packed;
-
-struct sfi_gpe_table_entry {
-       u16     logical_id;     /* logical id */
-       u16     phys_id;        /* physical GPE id */
-} __packed;
-
 typedef int (*sfi_table_handler) (struct sfi_table_header *table);
 
 #ifdef CONFIG_SFI
index 875ce50719a952d3f42e69badf9ede21f2743ac0..4dca992f3093771993ac9d98d1233df5e2f33cfa 100644 (file)
@@ -4,11 +4,20 @@
 #include <linux/list.h>
 #include <linux/seq_file.h>
 #include <linux/cpufreq.h>
+#include <linux/types.h>
+#include <linux/kref.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 
 struct clk;
 
+struct clk_mapping {
+       phys_addr_t             phys;
+       void __iomem            *base;
+       unsigned long           len;
+       struct kref             ref;
+};
+
 struct clk_ops {
        void (*init)(struct clk *clk);
        int (*enable)(struct clk *clk);
@@ -21,9 +30,6 @@ struct clk_ops {
 
 struct clk {
        struct list_head        node;
-       const char              *name;
-       int                     id;
-
        struct clk              *parent;
        struct clk              **parent_table; /* list of parents to */
        unsigned short          parent_num;     /* choose between */
@@ -45,7 +51,9 @@ struct clk {
        unsigned long           arch_flags;
        void                    *priv;
        struct dentry           *dentry;
+       struct clk_mapping      *mapping;
        struct cpufreq_frequency_table *freq_table;
+       unsigned int            nr_freqs;
 };
 
 #define CLK_ENABLE_ON_INIT     (1 << 0)
@@ -111,6 +119,9 @@ int clk_rate_table_find(struct clk *clk,
                        struct cpufreq_frequency_table *freq_table,
                        unsigned long rate);
 
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+                             unsigned int div_max, unsigned long rate);
+
 #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
 {                                                                      \
        .parent         = _parent,                                      \
index 0d6cd38e673ddb2486711517047a3c7fd544ad14..b4f183a31f130c6d183c60043964dc0caf74737c 100644 (file)
@@ -20,6 +20,12 @@ struct intc_group {
 
 #define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
 
+struct intc_subgroup {
+       unsigned long reg, reg_width;
+       intc_enum parent_id;
+       intc_enum enum_ids[32];
+};
+
 struct intc_mask_reg {
        unsigned long set_reg, clr_reg, reg_width;
        intc_enum enum_ids[32];
@@ -69,9 +75,12 @@ struct intc_hw_desc {
        unsigned int nr_sense_regs;
        struct intc_mask_reg *ack_regs;
        unsigned int nr_ack_regs;
+       struct intc_subgroup *subgroups;
+       unsigned int nr_subgroups;
 };
 
-#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
+
 #define INTC_HW_DESC(vectors, groups, mask_regs,       \
                     prio_regs, sense_regs, ack_regs)   \
 {                                                      \
@@ -105,8 +114,11 @@ struct intc_desc symbol __initdata = {                                     \
                           prio_regs, sense_regs, ack_regs),            \
 }
 
-int __init register_intc_controller(struct intc_desc *desc);
+int register_intc_controller(struct intc_desc *desc);
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
 int intc_set_priority(unsigned int irq, unsigned int prio);
+int intc_irq_lookup(const char *chipname, intc_enum enum_id);
+void intc_finalize(void);
 
 #ifdef CONFIG_INTC_USERIMASK
 int register_intc_userimask(unsigned long addr);
index 07c08af9f8f6ab418eab61bb960b84cad805e81c..30cae70874f4a1f10dd564aee7f65858091a10c3 100644 (file)
@@ -92,5 +92,6 @@ struct pinmux_info {
 };
 
 int register_pinmux(struct pinmux_info *pip);
+int unregister_pinmux(struct pinmux_info *pip);
 
 #endif /* __SH_PFC_H */
index b363b916c90961a9d61877f26d900d9111aeacb7..3ff4961da9b514992cf0edabf07c1b08d2121027 100644 (file)
@@ -33,6 +33,7 @@ struct signalfd_siginfo {
        __u64 ssi_utime;
        __u64 ssi_stime;
        __u64 ssi_addr;
+       __u16 ssi_addr_lsb;
 
        /*
         * Pad strcture to 128 bytes. Remember to update the
@@ -43,7 +44,7 @@ struct signalfd_siginfo {
         * comes out of a read(2) and we really don't want to have
         * a compat on read(2).
         */
-       __u8 __pad[48];
+       __u8 __pad[46];
 };
 
 
index 5bbc447175dce88239097002e403a7957d4e42a2..b2024757edd5a7ca2d15d5bb4e149ebe8205f7eb 100644 (file)
@@ -122,8 +122,8 @@ extern const struct rpc_authops     authnull_ops;
 int __init             rpc_init_authunix(void);
 int __init             rpc_init_generic_auth(void);
 int __init             rpcauth_init_module(void);
-void __exit            rpcauth_remove_module(void);
-void __exit            rpc_destroy_generic_auth(void);
+void                   rpcauth_remove_module(void);
+void                   rpc_destroy_generic_auth(void);
 void                   rpc_destroy_authunix(void);
 
 struct rpc_cred *      rpc_lookup_cred(void);
index 7bf3e84b92f43c1e331040b735bf3faff67fd697..6950c981882dfa4c30247e75fa93758145d0d2a9 100644 (file)
@@ -125,12 +125,15 @@ struct cache_detail {
  */
 struct cache_req {
        struct cache_deferred_req *(*defer)(struct cache_req *req);
+       int thread_wait;  /* How long (jiffies) we can block the
+                          * current thread to wait for updates.
+                          */
 };
 /* this must be embedded in a deferred_request that is being
  * delayed awaiting cache-fill
  */
 struct cache_deferred_req {
-       struct list_head        hash;   /* on hash chain */
+       struct hlist_node       hash;   /* on hash chain */
        struct list_head        recent; /* on fifo */
        struct cache_head       *item;  /* cache item we wait on */
        void                    *owner; /* we might need to discard all defered requests
@@ -194,7 +197,9 @@ extern void cache_purge(struct cache_detail *detail);
 #define NEVER (0x7FFFFFFF)
 extern void __init cache_initialize(void);
 extern int cache_register(struct cache_detail *cd);
+extern int cache_register_net(struct cache_detail *cd, struct net *net);
 extern void cache_unregister(struct cache_detail *cd);
+extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
 
 extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
                                        mode_t, struct cache_detail *);
@@ -218,14 +223,42 @@ static inline int get_int(char **bpp, int *anint)
        return 0;
 }
 
+/*
+ * timestamps kept in the cache are expressed in seconds
+ * since boot.  This is the best for measuring differences in
+ * real time.
+ */
+static inline time_t seconds_since_boot(void)
+{
+       struct timespec boot;
+       getboottime(&boot);
+       return get_seconds() - boot.tv_sec;
+}
+
+static inline time_t convert_to_wallclock(time_t sinceboot)
+{
+       struct timespec boot;
+       getboottime(&boot);
+       return boot.tv_sec + sinceboot;
+}
+
 static inline time_t get_expiry(char **bpp)
 {
        int rv;
+       struct timespec boot;
+
        if (get_int(bpp, &rv))
                return 0;
        if (rv < 0)
                return 0;
-       return rv;
+       getboottime(&boot);
+       return rv - boot.tv_sec;
 }
 
+static inline void sunrpc_invalidate(struct cache_head *h,
+                                    struct cache_detail *detail)
+{
+       h->expiry_time = seconds_since_boot() - 1;
+       detail->nextcheck = seconds_since_boot();
+}
 #endif /*  _LINUX_SUNRPC_CACHE_H_ */
index 85f38a63f098a2c55989f1e5d4e070595e525a99..a5a55f284b7da5de0fdc38fe7b9dac53feb53672 100644 (file)
@@ -102,6 +102,7 @@ struct rpc_procinfo {
 #ifdef __KERNEL__
 
 struct rpc_create_args {
+       struct net              *net;
        int                     protocol;
        struct sockaddr         *address;
        size_t                  addrsize;
@@ -137,7 +138,6 @@ int         rpcb_register(u32, u32, int, unsigned short);
 int            rpcb_v4_register(const u32 program, const u32 version,
                                 const struct sockaddr *address,
                                 const char *netid);
-int            rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
 void           rpcb_getport_async(struct rpc_task *);
 
 void           rpc_call_start(struct rpc_task *);
diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h
deleted file mode 100644 (file)
index e3e6a34..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *  linux/include/linux/sunrpc/gss_spkm3.h
- *
- *  Copyright (c) 2000 The Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  Andy Adamson   <andros@umich.edu>
- */
-
-#include <linux/sunrpc/auth_gss.h>
-#include <linux/sunrpc/gss_err.h>
-#include <linux/sunrpc/gss_asn1.h>
-
-struct spkm3_ctx {
-       struct xdr_netobj       ctx_id;  /* per message context id */
-       int                     endtime; /* endtime of the context */
-       struct xdr_netobj       mech_used;
-       unsigned int            ret_flags ;
-       struct xdr_netobj       conf_alg;
-       struct xdr_netobj       derived_conf_key;
-       struct xdr_netobj       intg_alg;
-       struct xdr_netobj       derived_integ_key;
-};
-
-/* OIDs declarations for K-ALG, I-ALG, C-ALG, and OWF-ALG */
-extern const struct xdr_netobj hmac_md5_oid;
-extern const struct xdr_netobj cast5_cbc_oid;
-
-/* SPKM InnerContext Token types */
-
-#define SPKM_ERROR_TOK 3
-#define SPKM_MIC_TOK   4
-#define SPKM_WRAP_TOK  5
-#define SPKM_DEL_TOK   6
-
-u32 spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_netobj * token, int toktype);
-
-u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype);
-
-#define CKSUMTYPE_RSA_MD5            0x0007
-#define CKSUMTYPE_HMAC_MD5           0x0008
-
-s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
-               unsigned int hdrlen, struct xdr_buf *body,
-               unsigned int body_offset, struct xdr_netobj *cksum);
-void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
-int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
-                   int explen);
-void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, 
-                   unsigned char *ctxhdr, int elen, int zbit);
-void spkm3_make_mic_token(unsigned  char **tokp, int toklen, 
-                   struct xdr_netobj *mic_hdr,
-                   struct xdr_netobj *md5cksum, int md5elen, int md5zbit);
-u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, 
-                   unsigned char **cksum);
index 5fa0f20843078a94c8822ef1a1ace6cc5d0ae2c0..680471d1f28a4300700883489c3b8b78335c07da 100644 (file)
@@ -38,8 +38,21 @@ struct svc_stat {
                                rpcbadclnt;
 };
 
-void                   rpc_proc_init(void);
-void                   rpc_proc_exit(void);
+struct net;
+#ifdef CONFIG_PROC_FS
+int                    rpc_proc_init(struct net *);
+void                   rpc_proc_exit(struct net *);
+#else
+static inline int rpc_proc_init(struct net *net)
+{
+       return 0;
+}
+
+static inline void rpc_proc_exit(struct net *net)
+{
+}
+#endif
+
 #ifdef MODULE
 void                   rpc_modcount(struct inode *, int);
 #endif
@@ -54,9 +67,6 @@ void                  svc_proc_unregister(const char *);
 
 void                   svc_seq_show(struct seq_file *,
                                     const struct svc_stat *);
-
-extern struct proc_dir_entry   *proc_net_rpc;
-
 #else
 
 static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
@@ -69,9 +79,6 @@ static inline void svc_proc_unregister(const char *p) {}
 
 static inline void svc_seq_show(struct seq_file *seq,
                                const struct svc_stat *st) {}
-
-#define proc_net_rpc NULL
-
 #endif
 
 #endif /* _LINUX_SUNRPC_STATS_H */
index 5f4e18b3ce73d3b5000b46d633d2eaa7af38c13d..bbdb680ffbe9d46f31de3f88d82d48869543920f 100644 (file)
@@ -12,6 +12,7 @@
 
 struct svc_xprt_ops {
        struct svc_xprt *(*xpo_create)(struct svc_serv *,
+                                      struct net *net,
                                       struct sockaddr *, int,
                                       int);
        struct svc_xprt *(*xpo_accept)(struct svc_xprt *);
@@ -32,6 +33,16 @@ struct svc_xprt_class {
        u32                     xcl_max_payload;
 };
 
+/*
+ * This is embedded in an object that wants a callback before deleting
+ * an xprt; intended for use by NFSv4.1, which needs to know when a
+ * client's tcp connection (and hence possibly a backchannel) goes away.
+ */
+struct svc_xpt_user {
+       struct list_head list;
+       void (*callback)(struct svc_xpt_user *);
+};
+
 struct svc_xprt {
        struct svc_xprt_class   *xpt_class;
        struct svc_xprt_ops     *xpt_ops;
@@ -66,14 +77,31 @@ struct svc_xprt {
        struct sockaddr_storage xpt_remote;     /* remote peer's address */
        size_t                  xpt_remotelen;  /* length of address */
        struct rpc_wait_queue   xpt_bc_pending; /* backchannel wait queue */
+       struct list_head        xpt_users;      /* callbacks on free */
+
+       struct net              *xpt_net;
 };
 
+static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+{
+       spin_lock(&xpt->xpt_lock);
+       list_add(&u->list, &xpt->xpt_users);
+       spin_unlock(&xpt->xpt_lock);
+}
+
+static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+{
+       spin_lock(&xpt->xpt_lock);
+       list_del_init(&u->list);
+       spin_unlock(&xpt->xpt_lock);
+}
+
 int    svc_reg_xprt_class(struct svc_xprt_class *);
 void   svc_unreg_xprt_class(struct svc_xprt_class *);
 void   svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
                      struct svc_serv *);
-int    svc_create_xprt(struct svc_serv *, const char *, const int,
-                       const unsigned short, int);
+int    svc_create_xprt(struct svc_serv *, const char *, struct net *,
+                       const int, const unsigned short, int);
 void   svc_xprt_enqueue(struct svc_xprt *xprt);
 void   svc_xprt_received(struct svc_xprt *);
 void   svc_xprt_put(struct svc_xprt *xprt);
index d39dbdc7b10f383332caf249c1872458c35562cd..25d333c1b5717f3ee9f659168d805865ab420bd5 100644 (file)
@@ -108,10 +108,15 @@ struct auth_ops {
 #define        SVC_NEGATIVE    4
 #define        SVC_OK          5
 #define        SVC_DROP        6
-#define        SVC_DENIED      7
-#define        SVC_PENDING     8
-#define        SVC_COMPLETE    9
+#define        SVC_CLOSE       7       /* Like SVC_DROP, but request is definitely
+                                * lost so if there is a tcp connection, it
+                                * should be closed
+                                */
+#define        SVC_DENIED      8
+#define        SVC_PENDING     9
+#define        SVC_COMPLETE    10
 
+struct svc_xprt;
 
 extern int     svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
 extern int     svc_authorise(struct svc_rqst *rqstp);
@@ -121,13 +126,13 @@ extern void       svc_auth_unregister(rpc_authflavor_t flavor);
 
 extern struct auth_domain *unix_domain_find(char *name);
 extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom);
 extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
 extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
+extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
 extern void svcauth_unix_purge(void);
-extern void svcauth_unix_info_release(void *);
+extern void svcauth_unix_info_release(struct svc_xprt *xpt);
 extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
 
 static inline unsigned long hash_str(char *name, int bits)
index 35cf2e8cd7c6212fc690eba566f97411a90849bd..498ab93a81e4d6afb8233e0925671556571c20b2 100644 (file)
@@ -108,6 +108,7 @@ void        xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
                         unsigned int);
 void   xdr_inline_pages(struct xdr_buf *, unsigned int,
                         struct page **, unsigned int, unsigned int);
+void   xdr_terminate_string(struct xdr_buf *, const u32);
 
 static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
 {
@@ -131,6 +132,13 @@ xdr_decode_hyper(__be32 *p, __u64 *valp)
        return p + 2;
 }
 
+static inline __be32 *
+xdr_decode_opaque_fixed(__be32 *p, void *ptr, unsigned int len)
+{
+       memcpy(ptr, p, len);
+       return p + XDR_QUADLEN(len);
+}
+
 /*
  * Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
  */
@@ -200,6 +208,7 @@ extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
                unsigned int base, unsigned int len);
 extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
 extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
index ff5a77b28c50c61044e150591d2148c76414cdf3..89d10d279a203d611bbc3f40760ab490c8eea098 100644 (file)
@@ -224,6 +224,7 @@ struct rpc_xprt {
                                        bklog_u;        /* backlog queue utilization */
        } stat;
 
+       struct net              *xprt_net;
        const char              *address_strings[RPC_DISPLAY_MAX];
 };
 
@@ -249,6 +250,7 @@ static inline int bc_prealloc(struct rpc_rqst *req)
 
 struct xprt_create {
        int                     ident;          /* XPRT_TRANSPORT identifier */
+       struct net *            net;
        struct sockaddr *       srcaddr;        /* optional local address */
        struct sockaddr *       dstaddr;        /* remote peer address */
        size_t                  addrlen;
@@ -280,6 +282,8 @@ void                        xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release(struct rpc_task *task);
 struct rpc_xprt *      xprt_get(struct rpc_xprt *xprt);
 void                   xprt_put(struct rpc_xprt *xprt);
+struct rpc_xprt *      xprt_alloc(struct net *net, int size, int max_req);
+void                   xprt_free(struct rpc_xprt *);
 
 static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
 {
index 7cdd63366f883a164a7f5d5b74ff8882c62b4f8c..eba53e71d2ccfa5f678cc8063dd55c0d56ef1dec 100644 (file)
@@ -271,8 +271,18 @@ extern void scan_mapping_unevictable_pages(struct address_space *);
 extern unsigned long scan_unevictable_pages;
 extern int scan_unevictable_handler(struct ctl_table *, int,
                                        void __user *, size_t *, loff_t *);
+#ifdef CONFIG_NUMA
 extern int scan_unevictable_register_node(struct node *node);
 extern void scan_unevictable_unregister_node(struct node *node);
+#else
+static inline int scan_unevictable_register_node(struct node *node)
+{
+       return 0;
+}
+static inline void scan_unevictable_unregister_node(struct node *node)
+{
+}
+#endif
 
 extern int kswapd_run(int nid);
 extern void kswapd_stop(int nid);
index 357dbc19606f8920f0b060ad04fb1d4fb2dfca00..c2a9eb44f2fa974cc7ac15a35ae9c184c1e6773f 100644 (file)
@@ -121,15 +121,7 @@ typedef            __u64           u_int64_t;
 typedef                __s64           int64_t;
 #endif
 
-/*
- * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
- * common 32/64-bit compat problems.
- * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
- * architectures) and to 8-byte boundaries on 64-bit architetures.  The new
- * aligned_64 type enforces 8-byte alignment so that structs containing
- * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
- * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
- */
+/* this is a special 64bit data type that is 8-byte aligned */
 #define aligned_u64 __u64 __attribute__((aligned(8)))
 #define aligned_be64 __be64 __attribute__((aligned(8)))
 #define aligned_le64 __le64 __attribute__((aligned(8)))
@@ -186,7 +178,15 @@ typedef __u64 __bitwise __be64;
 typedef __u16 __bitwise __sum16;
 typedef __u32 __bitwise __wsum;
 
-/* this is a special 64bit data type that is 8-byte aligned */
+/*
+ * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
+ * common 32/64-bit compat problems.
+ * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
+ * architectures) and to 8-byte boundaries on 64-bit architetures.  The new
+ * aligned_64 type enforces 8-byte alignment so that structs containing
+ * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
+ * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
+ */
 #define __aligned_u64 __u64 __attribute__((aligned(8)))
 #define __aligned_be64 __be64 __attribute__((aligned(8)))
 #define __aligned_le64 __le64 __attribute__((aligned(8)))
index 63a4fe6d51bd68277634943cb062dc4ea62fced1..a03dcf62ca9d591d00290ced4394f7873b81329e 100644 (file)
@@ -53,8 +53,10 @@ static inline void vmalloc_init(void)
 #endif
 
 extern void *vmalloc(unsigned long size);
+extern void *vzalloc(unsigned long size);
 extern void *vmalloc_user(unsigned long size);
 extern void *vmalloc_node(unsigned long size, int node);
+extern void *vzalloc_node(unsigned long size, int node);
 extern void *vmalloc_exec(unsigned long size);
 extern void *vmalloc_32(unsigned long size);
 extern void *vmalloc_32_user(unsigned long size);
diff --git a/include/linux/wlp.h b/include/linux/wlp.h
deleted file mode 100644 (file)
index c76fe23..0000000
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * - Does not (yet) include support for WLP control frames
- *   WLP Draft 0.99 [6.5].
- *
- *   A visual representation of the data structures.
- *
- *                              wssidB      wssidB
- *                               ^           ^
- *                               |           |
- *                              wssidA      wssidA
- *   wlp interface {             ^           ^
- *       ...                     |           |
- *       ...               ...  wssid      wssid ...
- *       wlp --- ...             |           |
- *   };          neighbors --> neighbA --> neighbB
- *               ...
- *               wss
- *               ...
- *               eda cache  --> neighborA --> neighborB --> neighborC ...
- */
-
-#ifndef __LINUX__WLP_H_
-#define __LINUX__WLP_H_
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/uwb.h>
-
-/**
- * WLP Protocol ID
- * WLP Draft 0.99 [6.2]
- *
- * The MUX header for all WLP frames
- */
-#define WLP_PROTOCOL_ID 0x0100
-
-/**
- * WLP Version
- * WLP version placed in the association frames (WLP 0.99 [6.6])
- */
-#define WLP_VERSION 0x10
-
-/**
- * Bytes needed to print UUID as string
- */
-#define WLP_WSS_UUID_STRSIZE 48
-
-/**
- * Bytes needed to print nonce as string
- */
-#define WLP_WSS_NONCE_STRSIZE 48
-
-
-/**
- * Size used for WLP name size
- *
- * The WSS name is set to 65 bytes, 1 byte larger than the maximum
- * allowed by the WLP spec. This is to have a null terminated string
- * for display to the user. A maximum of 64 bytes will still be used
- * when placing the WSS name field in association frames.
- */
-#define WLP_WSS_NAME_SIZE 65
-
-/**
- * Number of bytes added by WLP to data frame
- *
- * A data frame transmitted from a host will be placed in a Standard or
- * Abbreviated WLP frame. These have an extra 4 bytes of header (struct
- * wlp_frame_std_abbrv_hdr).
- * When the stack sends this data frame for transmission it needs to ensure
- * there is enough headroom for this header.
- */
-#define WLP_DATA_HLEN 4
-
-/**
- * State of device regarding WLP Service Set
- *
- * WLP_WSS_STATE_NONE: the host does not participate in any WSS
- * WLP_WSS_STATE_PART_ENROLLED: used as part of the enrollment sequence
- *                            ("Partial Enroll"). This state is used to
- *                            indicate the first part of enrollment that is
- *                            unsecure. If the WSS is unsecure then the
- *                            state will promptly go to WLP_WSS_STATE_ENROLLED,
- *                            if the WSS is not secure then the enrollment
- *                            procedure is a few more steps before we are
- *                            enrolled.
- * WLP_WSS_STATE_ENROLLED: the host is enrolled in a WSS
- * WLP_WSS_STATE_ACTIVE: WSS is activated
- * WLP_WSS_STATE_CONNECTED: host is connected to neighbor in WSS
- *
- */
-enum wlp_wss_state {
-       WLP_WSS_STATE_NONE = 0,
-       WLP_WSS_STATE_PART_ENROLLED,
-       WLP_WSS_STATE_ENROLLED,
-       WLP_WSS_STATE_ACTIVE,
-       WLP_WSS_STATE_CONNECTED,
-};
-
-/**
- * WSS Secure status
- * WLP 0.99 Table 6
- *
- * Set to one if the WSS is secure, zero if it is not secure
- */
-enum wlp_wss_sec_status {
-       WLP_WSS_UNSECURE = 0,
-       WLP_WSS_SECURE,
-};
-
-/**
- * WLP frame type
- * WLP Draft 0.99 [6.2 Table 1]
- */
-enum wlp_frame_type {
-       WLP_FRAME_STANDARD = 0,
-       WLP_FRAME_ABBREVIATED,
-       WLP_FRAME_CONTROL,
-       WLP_FRAME_ASSOCIATION,
-};
-
-/**
- * WLP Association Message Type
- * WLP Draft 0.99 [6.6.1.2 Table 8]
- */
-enum wlp_assoc_type {
-       WLP_ASSOC_D1 = 2,
-       WLP_ASSOC_D2 = 3,
-       WLP_ASSOC_M1 = 4,
-       WLP_ASSOC_M2 = 5,
-       WLP_ASSOC_M3 = 7,
-       WLP_ASSOC_M4 = 8,
-       WLP_ASSOC_M5 = 9,
-       WLP_ASSOC_M6 = 10,
-       WLP_ASSOC_M7 = 11,
-       WLP_ASSOC_M8 = 12,
-       WLP_ASSOC_F0 = 14,
-       WLP_ASSOC_E1 = 32,
-       WLP_ASSOC_E2 = 33,
-       WLP_ASSOC_C1 = 34,
-       WLP_ASSOC_C2 = 35,
-       WLP_ASSOC_C3 = 36,
-       WLP_ASSOC_C4 = 37,
-};
-
-/**
- * WLP Attribute Type
- * WLP Draft 0.99 [6.6.1 Table 6]
- */
-enum wlp_attr_type {
-       WLP_ATTR_AUTH           = 0x1005, /* Authenticator */
-       WLP_ATTR_DEV_NAME       = 0x1011, /* Device Name */
-       WLP_ATTR_DEV_PWD_ID     = 0x1012, /* Device Password ID */
-       WLP_ATTR_E_HASH1        = 0x1014, /* E-Hash1 */
-       WLP_ATTR_E_HASH2        = 0x1015, /* E-Hash2 */
-       WLP_ATTR_E_SNONCE1      = 0x1016, /* E-SNonce1 */
-       WLP_ATTR_E_SNONCE2      = 0x1017, /* E-SNonce2 */
-       WLP_ATTR_ENCR_SET       = 0x1018, /* Encrypted Settings */
-       WLP_ATTR_ENRL_NONCE     = 0x101A, /* Enrollee Nonce */
-       WLP_ATTR_KEYWRAP_AUTH   = 0x101E, /* Key Wrap Authenticator */
-       WLP_ATTR_MANUF          = 0x1021, /* Manufacturer */
-       WLP_ATTR_MSG_TYPE       = 0x1022, /* Message Type */
-       WLP_ATTR_MODEL_NAME     = 0x1023, /* Model Name */
-       WLP_ATTR_MODEL_NR       = 0x1024, /* Model Number */
-       WLP_ATTR_PUB_KEY        = 0x1032, /* Public Key */
-       WLP_ATTR_REG_NONCE      = 0x1039, /* Registrar Nonce */
-       WLP_ATTR_R_HASH1        = 0x103D, /* R-Hash1 */
-       WLP_ATTR_R_HASH2        = 0x103E, /* R-Hash2 */
-       WLP_ATTR_R_SNONCE1      = 0x103F, /* R-SNonce1 */
-       WLP_ATTR_R_SNONCE2      = 0x1040, /* R-SNonce2 */
-       WLP_ATTR_SERIAL         = 0x1042, /* Serial number */
-       WLP_ATTR_UUID_E         = 0x1047, /* UUID-E */
-       WLP_ATTR_UUID_R         = 0x1048, /* UUID-R */
-       WLP_ATTR_PRI_DEV_TYPE   = 0x1054, /* Primary Device Type */
-       WLP_ATTR_SEC_DEV_TYPE   = 0x1055, /* Secondary Device Type */
-       WLP_ATTR_PORT_DEV       = 0x1056, /* Portable Device */
-       WLP_ATTR_APP_EXT        = 0x1058, /* Application Extension */
-       WLP_ATTR_WLP_VER        = 0x2000, /* WLP Version */
-       WLP_ATTR_WSSID          = 0x2001, /* WSSID */
-       WLP_ATTR_WSS_NAME       = 0x2002, /* WSS Name */
-       WLP_ATTR_WSS_SEC_STAT   = 0x2003, /* WSS Secure Status */
-       WLP_ATTR_WSS_BCAST      = 0x2004, /* WSS Broadcast Address */
-       WLP_ATTR_WSS_M_KEY      = 0x2005, /* WSS Master Key */
-       WLP_ATTR_ACC_ENRL       = 0x2006, /* Accepting Enrollment */
-       WLP_ATTR_WSS_INFO       = 0x2007, /* WSS Information */
-       WLP_ATTR_WSS_SEL_MTHD   = 0x2008, /* WSS Selection Method */
-       WLP_ATTR_ASSC_MTHD_LIST = 0x2009, /* Association Methods List */
-       WLP_ATTR_SEL_ASSC_MTHD  = 0x200A, /* Selected Association Method */
-       WLP_ATTR_ENRL_HASH_COMM = 0x200B, /* Enrollee Hash Commitment */
-       WLP_ATTR_WSS_TAG        = 0x200C, /* WSS Tag */
-       WLP_ATTR_WSS_VIRT       = 0x200D, /* WSS Virtual EUI-48 */
-       WLP_ATTR_WLP_ASSC_ERR   = 0x200E, /* WLP Association Error */
-       WLP_ATTR_VNDR_EXT       = 0x200F, /* Vendor Extension */
-};
-
-/**
- * WLP Category ID of primary/secondary device
- * WLP Draft 0.99 [6.6.1.8 Table 12]
- */
-enum wlp_dev_category_id {
-       WLP_DEV_CAT_COMPUTER = 1,
-       WLP_DEV_CAT_INPUT,
-       WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER,
-       WLP_DEV_CAT_CAMERA,
-       WLP_DEV_CAT_STORAGE,
-       WLP_DEV_CAT_INFRASTRUCTURE,
-       WLP_DEV_CAT_DISPLAY,
-       WLP_DEV_CAT_MULTIM,
-       WLP_DEV_CAT_GAMING,
-       WLP_DEV_CAT_TELEPHONE,
-       WLP_DEV_CAT_OTHER = 65535,
-};
-
-/**
- * WLP WSS selection method
- * WLP Draft 0.99 [6.6.1.6 Table 10]
- */
-enum wlp_wss_sel_mthd {
-       WLP_WSS_ENRL_SELECT = 1,        /* Enrollee selects */
-       WLP_WSS_REG_SELECT,             /* Registrar selects */
-};
-
-/**
- * WLP association error values
- * WLP Draft 0.99 [6.6.1.5 Table 9]
- */
-enum wlp_assc_error {
-       WLP_ASSOC_ERROR_NONE,
-       WLP_ASSOC_ERROR_AUTH,           /* Authenticator Failure */
-       WLP_ASSOC_ERROR_ROGUE,          /* Rogue activity suspected */
-       WLP_ASSOC_ERROR_BUSY,           /* Device busy */
-       WLP_ASSOC_ERROR_LOCK,           /* Setup Locked */
-       WLP_ASSOC_ERROR_NOT_READY,      /* Registrar not ready */
-       WLP_ASSOC_ERROR_INV,            /* Invalid WSS selection */
-       WLP_ASSOC_ERROR_MSG_TIME,       /* Message timeout */
-       WLP_ASSOC_ERROR_ENR_TIME,       /* Enrollment session timeout */
-       WLP_ASSOC_ERROR_PW,             /* Device password invalid */
-       WLP_ASSOC_ERROR_VER,            /* Unsupported version */
-       WLP_ASSOC_ERROR_INT,            /* Internal error */
-       WLP_ASSOC_ERROR_UNDEF,          /* Undefined error */
-       WLP_ASSOC_ERROR_NUM,            /* Numeric comparison failure */
-       WLP_ASSOC_ERROR_WAIT,           /* Waiting for user input */
-};
-
-/**
- * WLP Parameters
- * WLP 0.99 [7.7]
- */
-enum wlp_parameters {
-       WLP_PER_MSG_TIMEOUT = 15,       /* Seconds to wait for response to
-                                          association message. */
-};
-
-/**
- * WLP IE
- *
- * The WLP IE should be included in beacons by all devices.
- *
- * The driver can set only a few of the fields in this information element,
- * most fields are managed by the device self. When the driver needs to set
- * a field it will only provide values for the fields of interest, the rest
- * will be filled with zeroes. The fields of interest are:
- *
- * Element ID
- * Length
- * Capabilities (only to include WSSID Hash list length)
- * WSSID Hash List fields
- *
- * WLP 0.99 [6.7]
- *
- * Only the fields that will be used are detailed in this structure, rest
- * are not detailed or marked as "notused".
- */
-struct wlp_ie {
-       struct uwb_ie_hdr hdr;
-       __le16 capabilities;
-       __le16 cycle_param;
-       __le16 acw_anchor_addr;
-       u8 wssid_hash_list[];
-} __packed;
-
-static inline int wlp_ie_hash_length(struct wlp_ie *ie)
-{
-       return (le16_to_cpu(ie->capabilities) >> 12) & 0xf;
-}
-
-static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length)
-{
-       u16 caps = le16_to_cpu(ie->capabilities);
-       caps = (caps & ~(0xf << 12)) | (hash_length << 12);
-       ie->capabilities = cpu_to_le16(caps);
-}
-
-/**
- * WLP nonce
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * A 128-bit random number often used (E-SNonce1, E-SNonce2, Enrollee
- * Nonce, Registrar Nonce, R-SNonce1, R-SNonce2). It is passed to HW so
- * it is packed.
- */
-struct wlp_nonce {
-       u8 data[16];
-} __packed;
-
-/**
- * WLP UUID
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * Universally Unique Identifier (UUID) encoded as an octet string in the
- * order the octets are shown in string representation in RFC4122. A UUID
- * is often used (UUID-E, UUID-R, WSSID). It is passed to HW so it is packed.
- */
-struct wlp_uuid {
-       u8 data[16];
-} __packed;
-
-
-/**
- * Primary and secondary device type attributes
- * WLP Draft 0.99 [6.6.1.8]
- */
-struct wlp_dev_type {
-       enum wlp_dev_category_id category:16;
-       u8 OUI[3];
-       u8 OUIsubdiv;
-       __le16 subID;
-} __packed;
-
-/**
- * WLP frame header
- * WLP Draft 0.99 [6.2]
- */
-struct wlp_frame_hdr {
-       __le16 mux_hdr;                 /* WLP_PROTOCOL_ID */
-       enum wlp_frame_type type:8;
-} __packed;
-
-/**
- * WLP attribute field header
- * WLP Draft 0.99 [6.6.1]
- *
- * Header of each attribute found in an association frame
- */
-struct wlp_attr_hdr {
-       __le16 type;
-       __le16 length;
-} __packed;
-
-/**
- * Device information commonly used together
- *
- * Each of these device information elements has a specified range in which it
- * should fit (WLP 0.99 [Table 6]). This range provided in the spec does not
- * include the termination null '\0' character (when used in the
- * association protocol the attribute fields are accompanied
- * with a "length" field so the full range from the spec can be used for
- * the value). We thus allocate an extra byte to be able to store a string
- * of max length with a terminating '\0'.
- */
-struct wlp_device_info {
-       char name[33];
-       char model_name[33];
-       char manufacturer[65];
-       char model_nr[33];
-       char serial[33];
-       struct wlp_dev_type prim_dev_type;
-};
-
-/**
- * Macros for the WLP attributes
- *
- * There are quite a few attributes (total is 43). The attribute layout can be
- * in one of three categories: one value, an array, an enum forced to 8 bits.
- * These macros help with their definitions.
- */
-#define wlp_attr(type, name)                                           \
-struct wlp_attr_##name {                                               \
-       struct wlp_attr_hdr hdr;                                        \
-       type name;                                                      \
-} __packed;
-
-#define wlp_attr_array(type, name)                                     \
-struct wlp_attr_##name {                                               \
-       struct wlp_attr_hdr hdr;                                        \
-       type name[];                                                    \
-} __packed;
-
-/**
- * WLP association attribute fields
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * Attributes appear in same order as the Table in the spec
- * FIXME Does not define all attributes yet
- */
-
-/* Device name: Friendly name of sending device */
-wlp_attr_array(u8, dev_name)
-
-/* Enrollee Nonce: Random number generated by enrollee for an enrollment
- * session */
-wlp_attr(struct wlp_nonce, enonce)
-
-/* Manufacturer name: Name of manufacturer of the sending device */
-wlp_attr_array(u8, manufacturer)
-
-/* WLP Message Type */
-wlp_attr(u8, msg_type)
-
-/* WLP Model name: Model name of sending device */
-wlp_attr_array(u8, model_name)
-
-/* WLP Model number: Model number of sending device */
-wlp_attr_array(u8, model_nr)
-
-/* Registrar Nonce: Random number generated by registrar for an enrollment
- * session */
-wlp_attr(struct wlp_nonce, rnonce)
-
-/* Serial number of device */
-wlp_attr_array(u8, serial)
-
-/* UUID of enrollee */
-wlp_attr(struct wlp_uuid, uuid_e)
-
-/* UUID of registrar */
-wlp_attr(struct wlp_uuid, uuid_r)
-
-/* WLP Primary device type */
-wlp_attr(struct wlp_dev_type, prim_dev_type)
-
-/* WLP Secondary device type */
-wlp_attr(struct wlp_dev_type, sec_dev_type)
-
-/* WLP protocol version */
-wlp_attr(u8, version)
-
-/* WLP service set identifier */
-wlp_attr(struct wlp_uuid, wssid)
-
-/* WLP WSS name */
-wlp_attr_array(u8, wss_name)
-
-/* WLP WSS Secure Status */
-wlp_attr(u8, wss_sec_status)
-
-/* WSS Broadcast Address */
-wlp_attr(struct uwb_mac_addr, wss_bcast)
-
-/* WLP Accepting Enrollment */
-wlp_attr(u8, accept_enrl)
-
-/**
- * WSS information attributes
- * WLP Draft 0.99 [6.6.3 Table 15]
- */
-struct wlp_wss_info {
-       struct wlp_attr_wssid wssid;
-       struct wlp_attr_wss_name name;
-       struct wlp_attr_accept_enrl accept;
-       struct wlp_attr_wss_sec_status sec_stat;
-       struct wlp_attr_wss_bcast bcast;
-} __packed;
-
-/* WLP WSS Information */
-wlp_attr_array(struct wlp_wss_info, wss_info)
-
-/* WLP WSS Selection method */
-wlp_attr(u8, wss_sel_mthd)
-
-/* WLP WSS tag */
-wlp_attr(u8, wss_tag)
-
-/* WSS Virtual Address */
-wlp_attr(struct uwb_mac_addr, wss_virt)
-
-/* WLP association error */
-wlp_attr(u8, wlp_assc_err)
-
-/**
- * WLP standard and abbreviated frames
- *
- * WLP Draft 0.99 [6.3] and [6.4]
- *
- * The difference between the WLP standard frame and the WLP
- * abbreviated frame is that the standard frame includes the src
- * and dest addresses from the Ethernet header, the abbreviated frame does
- * not.
- * The src/dest (as well as the type/length and client data) are already
- * defined as part of the Ethernet header, we do not do this here.
- * From this perspective the standard and abbreviated frames appear the
- * same - they will be treated differently though.
- *
- * The size of this header is also captured in WLP_DATA_HLEN to enable
- * interfaces to prepare their headroom.
- */
-struct wlp_frame_std_abbrv_hdr {
-       struct wlp_frame_hdr hdr;
-       u8 tag;
-} __packed;
-
-/**
- * WLP association frames
- *
- * WLP Draft 0.99 [6.6]
- */
-struct wlp_frame_assoc {
-       struct wlp_frame_hdr hdr;
-       enum wlp_assoc_type type:8;
-       struct wlp_attr_version version;
-       struct wlp_attr_msg_type msg_type;
-       u8 attr[];
-} __packed;
-
-/* Ethernet to dev address mapping */
-struct wlp_eda {
-       spinlock_t lock;
-       struct list_head cache; /* Eth<->Dev Addr cache */
-};
-
-/**
- * WSS information temporary storage
- *
- * This information is only stored temporarily during discovery. It should
- * not be stored unless the device is enrolled in the advertised WSS. This
- * is done mainly because we follow the letter of the spec in this regard.
- * See WLP 0.99 [7.2.3].
- * When the device does become enrolled in a WSS the WSS information will
- * be stored as part of the more comprehensive struct wlp_wss.
- */
-struct wlp_wss_tmp_info {
-       char name[WLP_WSS_NAME_SIZE];
-       u8 accept_enroll;
-       u8 sec_status;
-       struct uwb_mac_addr bcast;
-};
-
-struct wlp_wssid_e {
-       struct list_head node;
-       struct wlp_uuid wssid;
-       struct wlp_wss_tmp_info *info;
-};
-
-/**
- * A cache entry of WLP neighborhood
- *
- * @node: head of list is wlp->neighbors
- * @wssid: list of wssids of this neighbor, element is wlp_wssid_e
- * @info:  temporary storage for information learned during discovery. This
- *         storage is used together with the wssid_e temporary storage
- *         during discovery.
- */
-struct wlp_neighbor_e {
-       struct list_head node;
-       struct wlp_uuid uuid;
-       struct uwb_dev *uwb_dev;
-       struct list_head wssid; /* Elements are wlp_wssid_e */
-       struct wlp_device_info *info;
-};
-
-struct wlp;
-/**
- * Information for an association session in progress.
- *
- * @exp_message: The type of the expected message. Both this message and a
- *               F0 message (which can be sent in response to any
- *               association frame) will be accepted as a valid message for
- *               this session.
- * @cb:          The function that will be called upon receipt of this
- *               message.
- * @cb_priv:     Private data of callback
- * @data:        Data used in association process (always a sk_buff?)
- * @neighbor:    Address of neighbor with which association session is in
- *               progress.
- */
-struct wlp_session {
-       enum wlp_assoc_type exp_message;
-       void (*cb)(struct wlp *);
-       void *cb_priv;
-       void *data;
-       struct uwb_dev_addr neighbor_addr;
-};
-
-/**
- * WLP Service Set
- *
- * @mutex: used to protect entire WSS structure.
- *
- * @name: The WSS name is set to 65 bytes, 1 byte larger than the maximum
- *        allowed by the WLP spec. This is to have a null terminated string
- *        for display to the user. A maximum of 64 bytes will still be used
- *        when placing the WSS name field in association frames.
- *
- * @accept_enroll: Accepting enrollment: Set to one if registrar is
- *                 accepting enrollment in WSS, or zero otherwise.
- *
- * Global and local information for each WSS in which we are enrolled.
- * WLP 0.99 Section 7.2.1 and Section 7.2.2
- */
-struct wlp_wss {
-       struct mutex mutex;
-       struct kobject kobj;
-       /* Global properties. */
-       struct wlp_uuid wssid;
-       u8 hash;
-       char name[WLP_WSS_NAME_SIZE];
-       struct uwb_mac_addr bcast;
-       u8 secure_status:1;
-       u8 master_key[16];
-       /* Local properties. */
-       u8 tag;
-       struct uwb_mac_addr virtual_addr;
-       /* Extra */
-       u8 accept_enroll:1;
-       enum wlp_wss_state state;
-};
-
-/**
- * WLP main structure
- * @mutex: protect changes to WLP structure. We only allow changes to the
- *         uuid, so currently this mutex only protects this field.
- */
-struct wlp {
-       struct mutex mutex;
-       struct uwb_rc *rc;              /* UWB radio controller */
-       struct net_device *ndev;
-       struct uwb_pal pal;
-       struct wlp_eda eda;
-       struct wlp_uuid uuid;
-       struct wlp_session *session;
-       struct wlp_wss wss;
-       struct mutex nbmutex; /* Neighbor mutex protects neighbors list */
-       struct list_head neighbors; /* Elements are wlp_neighbor_e */
-       struct uwb_notifs_handler uwb_notifs_handler;
-       struct wlp_device_info *dev_info;
-       void (*fill_device_info)(struct wlp *wlp, struct wlp_device_info *info);
-       int (*xmit_frame)(struct wlp *, struct sk_buff *,
-                         struct uwb_dev_addr *);
-       void (*stop_queue)(struct wlp *);
-       void (*start_queue)(struct wlp *);
-};
-
-/* sysfs */
-
-
-struct wlp_wss_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct wlp_wss *wss, char *buf);
-       ssize_t (*store)(struct wlp_wss *wss, const char *buf, size_t count);
-};
-
-#define WSS_ATTR(_name, _mode, _show, _store) \
-static struct wlp_wss_attribute wss_attr_##_name = __ATTR(_name, _mode,        \
-                                                         _show, _store)
-
-extern int wlp_setup(struct wlp *, struct uwb_rc *, struct net_device *ndev);
-extern void wlp_remove(struct wlp *);
-extern ssize_t wlp_neighborhood_show(struct wlp *, char *);
-extern int wlp_wss_setup(struct net_device *, struct wlp_wss *);
-extern void wlp_wss_remove(struct wlp_wss *);
-extern ssize_t wlp_wss_activate_show(struct wlp_wss *, char *);
-extern ssize_t wlp_wss_activate_store(struct wlp_wss *, const char *, size_t);
-extern ssize_t wlp_eda_show(struct wlp *, char *);
-extern ssize_t wlp_eda_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_uuid_show(struct wlp *, char *);
-extern ssize_t wlp_uuid_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_name_show(struct wlp *, char *);
-extern ssize_t wlp_dev_name_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_manufacturer_show(struct wlp *, char *);
-extern ssize_t wlp_dev_manufacturer_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_model_name_show(struct wlp *, char *);
-extern ssize_t wlp_dev_model_name_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_model_nr_show(struct wlp *, char *);
-extern ssize_t wlp_dev_model_nr_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_serial_show(struct wlp *, char *);
-extern ssize_t wlp_dev_serial_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_prim_category_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_category_store(struct wlp *, const char *,
-                                          size_t);
-extern ssize_t wlp_dev_prim_OUI_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_OUI_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *, const char *,
-                                         size_t);
-extern ssize_t wlp_dev_prim_subcat_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_subcat_store(struct wlp *, const char *,
-                                        size_t);
-extern int wlp_receive_frame(struct device *, struct wlp *, struct sk_buff *,
-                            struct uwb_dev_addr *);
-extern int wlp_prepare_tx_frame(struct device *, struct wlp *,
-                              struct sk_buff *, struct uwb_dev_addr *);
-void wlp_reset_all(struct wlp *wlp);
-
-/**
- * Initialize WSS
- */
-static inline
-void wlp_wss_init(struct wlp_wss *wss)
-{
-       mutex_init(&wss->mutex);
-}
-
-static inline
-void wlp_init(struct wlp *wlp)
-{
-       INIT_LIST_HEAD(&wlp->neighbors);
-       mutex_init(&wlp->mutex);
-       mutex_init(&wlp->nbmutex);
-       wlp_wss_init(&wlp->wss);
-}
-
-
-#endif /* #ifndef __LINUX__WLP_H_ */
index 070bb7a8893646418b8b4ddcfbe9a3436e514711..0c0771f06bfa745e8e4e5add4ec4823cf52eb813 100644 (file)
@@ -190,7 +190,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
                __INIT_WORK((_work), (_func), 0);               \
        } while (0)
 
-#define INIT_WORK_ON_STACK(_work, _func)                       \
+#define INIT_WORK_ONSTACK(_work, _func)                                \
        do {                                                    \
                __INIT_WORK((_work), (_func), 1);               \
        } while (0)
@@ -201,9 +201,9 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
                init_timer(&(_work)->timer);                    \
        } while (0)
 
-#define INIT_DELAYED_WORK_ON_STACK(_work, _func)               \
+#define INIT_DELAYED_WORK_ONSTACK(_work, _func)                        \
        do {                                                    \
-               INIT_WORK_ON_STACK(&(_work)->work, (_func));    \
+               INIT_WORK_ONSTACK(&(_work)->work, (_func));     \
                init_timer_on_stack(&(_work)->timer);           \
        } while (0)
 
index 72a5d647a5f26d9eb3c798894443d4eb7849c0dd..d5c7aaadda59a926032794a4d3a27a46f01bab3c 100644 (file)
@@ -10,8 +10,6 @@
 struct backing_dev_info;
 
 extern spinlock_t inode_lock;
-extern struct list_head inode_in_use;
-extern struct list_head inode_unused;
 
 /*
  * fs/fs-writeback.c
@@ -149,6 +147,8 @@ int write_cache_pages(struct address_space *mapping,
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 void set_page_dirty_balance(struct page *page, int page_mkwrite);
 void writeback_set_ratelimit(void);
+void tag_pages_for_writeback(struct address_space *mapping,
+                            pgoff_t start, pgoff_t end);
 
 /* pdflush.c */
 extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
index a9c041d49662592e022d409e4b60de9f07e43300..9b201ec8dc7f1e2abb79b7b5205292c8755e4f0f 100644 (file)
@@ -35,7 +35,7 @@ struct ir_scancode_table {
        unsigned int            len;    /* Used number of entries */
        unsigned int            alloc;  /* Size of *scan in bytes */
        u64                     ir_type;
-       char                    *name;
+       const char              *name;
        spinlock_t              lock;
 };
 
index fa0d52b8e622cd55c0cc1f8f58e0e9e53231c969..b5fc9f39122b65ab7a7fbd4911dd9e4ab6c98d8e 100644 (file)
@@ -39,7 +39,9 @@
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/socket.h>
+#include <linux/if_vlan.h>
 #include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
 
 struct rdma_addr_client {
        atomic_t refcount;
@@ -63,6 +65,7 @@ struct rdma_dev_addr {
        unsigned char broadcast[MAX_ADDR_LEN];
        unsigned short dev_type;
        int bound_dev_if;
+       enum rdma_transport_type transport;
 };
 
 /**
@@ -127,9 +130,51 @@ static inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr)
        return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0;
 }
 
+static inline void iboe_mac_vlan_to_ll(union ib_gid *gid, u8 *mac, u16 vid)
+{
+       memset(gid->raw, 0, 16);
+       *((__be32 *) gid->raw) = cpu_to_be32(0xfe800000);
+       if (vid < 0x1000) {
+               gid->raw[12] = vid & 0xff;
+               gid->raw[11] = vid >> 8;
+       } else {
+               gid->raw[12] = 0xfe;
+               gid->raw[11] = 0xff;
+       }
+       memcpy(gid->raw + 13, mac + 3, 3);
+       memcpy(gid->raw + 8, mac, 3);
+       gid->raw[8] ^= 2;
+}
+
+static inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev)
+{
+       return dev->priv_flags & IFF_802_1Q_VLAN ?
+               vlan_dev_vlan_id(dev) : 0xffff;
+}
+
+static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr,
+                                     union ib_gid *gid)
+{
+       struct net_device *dev;
+       u16 vid = 0xffff;
+
+       dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+       if (dev) {
+               vid = rdma_vlan_dev_vlan_id(dev);
+               dev_put(dev);
+       }
+
+       iboe_mac_vlan_to_ll(gid, dev_addr->src_dev_addr, vid);
+}
+
 static inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
 {
-       memcpy(gid, dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid);
+       if (dev_addr->transport == RDMA_TRANSPORT_IB &&
+           dev_addr->dev_type != ARPHRD_INFINIBAND)
+               iboe_addr_get_sgid(dev_addr, gid);
+       else
+               memcpy(gid, dev_addr->src_dev_addr +
+                      rdma_addr_gid_offset(dev_addr), sizeof *gid);
 }
 
 static inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
@@ -147,4 +192,91 @@ static inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_g
        memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid);
 }
 
+static inline enum ib_mtu iboe_get_mtu(int mtu)
+{
+       /*
+        * reduce IB headers from effective IBoE MTU. 28 stands for
+        * atomic header which is the biggest possible header after BTH
+        */
+       mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28;
+
+       if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096))
+               return IB_MTU_4096;
+       else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048))
+               return IB_MTU_2048;
+       else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024))
+               return IB_MTU_1024;
+       else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512))
+               return IB_MTU_512;
+       else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256))
+               return IB_MTU_256;
+       else
+               return 0;
+}
+
+static inline int iboe_get_rate(struct net_device *dev)
+{
+       struct ethtool_cmd cmd;
+
+       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings ||
+           dev->ethtool_ops->get_settings(dev, &cmd))
+               return IB_RATE_PORT_CURRENT;
+
+       if (cmd.speed >= 40000)
+               return IB_RATE_40_GBPS;
+       else if (cmd.speed >= 30000)
+               return IB_RATE_30_GBPS;
+       else if (cmd.speed >= 20000)
+               return IB_RATE_20_GBPS;
+       else if (cmd.speed >= 10000)
+               return IB_RATE_10_GBPS;
+       else
+               return IB_RATE_PORT_CURRENT;
+}
+
+static inline int rdma_link_local_addr(struct in6_addr *addr)
+{
+       if (addr->s6_addr32[0] == htonl(0xfe800000) &&
+           addr->s6_addr32[1] == 0)
+               return 1;
+
+       return 0;
+}
+
+static inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac)
+{
+       memcpy(mac, &addr->s6_addr[8], 3);
+       memcpy(mac + 3, &addr->s6_addr[13], 3);
+       mac[0] ^= 2;
+}
+
+static inline int rdma_is_multicast_addr(struct in6_addr *addr)
+{
+       return addr->s6_addr[0] == 0xff;
+}
+
+static inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac)
+{
+       int i;
+
+       mac[0] = 0x33;
+       mac[1] = 0x33;
+       for (i = 2; i < 6; ++i)
+               mac[i] = addr->s6_addr[i + 10];
+}
+
+static inline u16 rdma_get_vlan_id(union ib_gid *dgid)
+{
+       u16 vid;
+
+       vid = dgid->raw[11] << 8 | dgid->raw[12];
+       return vid < 0x1000 ? vid : 0xffff;
+}
+
+static inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev)
+{
+       return dev->priv_flags & IFF_802_1Q_VLAN ?
+               vlan_dev_real_dev(dev) : 0;
+}
+
 #endif /* IB_ADDR_H */
index cbb50f4da3dd92df64f7af53ebca0e0a79f6e174..b37fe3b10a9da4f397d272a54b6c036045f019c7 100644 (file)
@@ -37,6 +37,8 @@
 
 enum {
        IB_LRH_BYTES  = 8,
+       IB_ETH_BYTES  = 14,
+       IB_VLAN_BYTES = 4,
        IB_GRH_BYTES  = 40,
        IB_BTH_BYTES  = 12,
        IB_DETH_BYTES = 8
@@ -210,14 +212,32 @@ struct ib_unpacked_deth {
        __be32       source_qpn;
 };
 
+struct ib_unpacked_eth {
+       u8      dmac_h[4];
+       u8      dmac_l[2];
+       u8      smac_h[2];
+       u8      smac_l[4];
+       __be16  type;
+};
+
+struct ib_unpacked_vlan {
+       __be16  tag;
+       __be16  type;
+};
+
 struct ib_ud_header {
+       int                     lrh_present;
        struct ib_unpacked_lrh  lrh;
-       int                     grh_present;
-       struct ib_unpacked_grh  grh;
-       struct ib_unpacked_bth  bth;
+       int                     eth_present;
+       struct ib_unpacked_eth  eth;
+       int                     vlan_present;
+       struct ib_unpacked_vlan vlan;
+       int                     grh_present;
+       struct ib_unpacked_grh  grh;
+       struct ib_unpacked_bth  bth;
        struct ib_unpacked_deth deth;
-       int                     immediate_present;
-       __be32                  immediate_data;
+       int                     immediate_present;
+       __be32                  immediate_data;
 };
 
 void ib_pack(const struct ib_field        *desc,
@@ -230,9 +250,12 @@ void ib_unpack(const struct ib_field        *desc,
               void                         *buf,
               void                         *structure);
 
-void ib_ud_header_init(int                        payload_bytes,
-                      int                 grh_present,
-                      int                 immediate_present,
+void ib_ud_header_init(int                 payload_bytes,
+                      int                  lrh_present,
+                      int                  eth_present,
+                      int                  vlan_present,
+                      int                  grh_present,
+                      int                  immediate_present,
                       struct ib_ud_header *header);
 
 int ib_ud_header_pack(struct ib_ud_header *header,
index a17f77106149bb8ee63f02a8bdddf79f72a2c928..fe5b05177a2cb4fe9195cb2b95e4f1aca0242759 100644 (file)
@@ -205,7 +205,8 @@ struct ib_uverbs_query_port_resp {
        __u8  active_width;
        __u8  active_speed;
        __u8  phys_state;
-       __u8  reserved[3];
+       __u8  link_layer;
+       __u8  reserved[2];
 };
 
 struct ib_uverbs_alloc_pd {
index 857b3b9cf120a4bcac7a19607f8b26ce14f23cae..e04c4888d1fdca554edf5dcb6d37f16b15e47d02 100644 (file)
@@ -75,6 +75,12 @@ enum rdma_transport_type {
 enum rdma_transport_type
 rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__;
 
+enum rdma_link_layer {
+       IB_LINK_LAYER_UNSPECIFIED,
+       IB_LINK_LAYER_INFINIBAND,
+       IB_LINK_LAYER_ETHERNET,
+};
+
 enum ib_device_cap_flags {
        IB_DEVICE_RESIZE_MAX_WR         = 1,
        IB_DEVICE_BAD_PKEY_CNTR         = (1<<1),
@@ -1010,6 +1016,8 @@ struct ib_device {
        int                        (*query_port)(struct ib_device *device,
                                                 u8 port_num,
                                                 struct ib_port_attr *port_attr);
+       enum rdma_link_layer       (*get_link_layer)(struct ib_device *device,
+                                                    u8 port_num);
        int                        (*query_gid)(struct ib_device *device,
                                                u8 port_num, int index,
                                                union ib_gid *gid);
@@ -1222,6 +1230,9 @@ int ib_query_device(struct ib_device *device,
 int ib_query_port(struct ib_device *device,
                  u8 port_num, struct ib_port_attr *port_attr);
 
+enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device,
+                                              u8 port_num);
+
 int ib_query_gid(struct ib_device *device,
                 u8 port_num, int index, union ib_gid *gid);
 
index ad178fa78f665a69fba3b4d26e66c9aee9443d75..1ae84db4c9fb6525b4937276e42f220dbe41d5e7 100644 (file)
@@ -239,4 +239,42 @@ struct srp_rsp {
        u8      data[0];
 } __attribute__((packed));
 
+struct srp_cred_req {
+       u8      opcode;
+       u8      sol_not;
+       u8      reserved[2];
+       __be32  req_lim_delta;
+       u64     tag;
+};
+
+struct srp_cred_rsp {
+       u8      opcode;
+       u8      reserved[7];
+       u64     tag;
+};
+
+/*
+ * The SRP spec defines the fixed portion of the AER_REQ structure to be
+ * 36 bytes, so it needs to be packed to avoid having it padded to 40 bytes
+ * on 64-bit architectures.
+ */
+struct srp_aer_req {
+       u8      opcode;
+       u8      sol_not;
+       u8      reserved[2];
+       __be32  req_lim_delta;
+       u64     tag;
+       u32     reserved2;
+       __be64  lun;
+       __be32  sense_data_len;
+       u32     reserved3;
+       u8      sense_data[0];
+} __attribute__((packed));
+
+struct srp_aer_rsp {
+       u8      opcode;
+       u8      reserved[7];
+       u64     tag;
+};
+
 #endif /* SCSI_SRP_H */
index df26ebbfa9c697584ec95b429300a5b0d407ccb0..1fa2407c966fdc5240d9853395fd22af6f435724 100644 (file)
@@ -177,7 +177,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
 #define snd_power_lock(card)           do { (void)(card); } while (0)
 #define snd_power_unlock(card)         do { (void)(card); } while (0)
 static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card)      SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card)      ({ (void)(card); SNDRV_CTL_POWER_D0; })
 #define snd_power_change_state(card, state)    do { (void)(card); } while (0)
 
 #endif /* CONFIG_PM */
index 7dc97d12253c1bdc494b939e5e856b1b1fa6fc2c..4f865df42f0f9daf2e078b6a26c1b108638454ba 100644 (file)
 #define CCCA_CURRADDR_MASK     0x00ffffff      /* Current address of the selected channel              */
 #define CCCA_CURRADDR          0x18000008
 
+/* undefine CCR to avoid conflict with the definition for SH */
+#undef CCR
 #define CCR                    0x09            /* Cache control register                               */
 #define CCR_CACHEINVALIDSIZE   0x07190009
 #define CCR_CACHEINVALIDSIZE_MASK      0xfe000000      /* Number of invalid samples cache for this channel     */
index d90b9fa327074b9e38ad2c3b84063a3d24effd2f..c140fc7cbd3f276470a949c2701c9989e4f9a2f8 100644 (file)
@@ -47,6 +47,9 @@ enum snd_jack_types {
        SND_JACK_BTN_0          = 0x4000,
        SND_JACK_BTN_1          = 0x2000,
        SND_JACK_BTN_2          = 0x1000,
+       SND_JACK_BTN_3          = 0x0800,
+       SND_JACK_BTN_4          = 0x0400,
+       SND_JACK_BTN_5          = 0x0200,
 };
 
 struct snd_jack {
@@ -55,7 +58,7 @@ struct snd_jack {
        int type;
        const char *id;
        char name[100];
-       unsigned int key[3];   /* Keep in sync with definitions above */
+       unsigned int key[6];   /* Keep in sync with definitions above */
        void *private_data;
        void (*private_free)(struct snd_jack *);
 };
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644 (file)
index 0000000..c3ba823
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the 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 __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+       u16 band3[5];
+       u16 band4[5];
+       u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+       /* Equalizers for DAI1 and DAI2 */
+       struct max98088_eq_cfg *eq_cfg;
+       unsigned int eq_cfgcnt;
+
+       /* Receiver output can be configured as power amplifier or LINE out */
+       /* Set receiver_mode to:
+        * 0 = amplifier output, or
+        * 1 = LINE level output
+        */
+       unsigned int receiver_mode:1;
+
+       /* Analog/digital microphone configuration:
+        * 0 = analog microphone input (normal setting)
+        * 1 = digital microphone input
+        */
+       unsigned int digmic_left_mode:1;
+       unsigned int digmic_right_mode:1;
+
+};
+
+#endif
index 85f1c6bf8566944eaa85d6b8742ebef2a06e6ce9..dfd9b76b185306a40fff57df94ad53ab83d2f966 100644 (file)
@@ -278,6 +278,7 @@ struct snd_pcm_runtime {
        snd_pcm_uframes_t hw_ptr_base;  /* Position at buffer restart */
        snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
        unsigned long hw_ptr_jiffies;   /* Time when hw_ptr is updated */
+       unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
        snd_pcm_sframes_t delay;        /* extra delay; typically FIFO size */
 
        /* -- HW params -- */
index 9d51d6f358930c68d7c8264e4e0e047a1b15343b..fa60cbda90a4553f69b9b1ce94e51fd7df9fa880 100644 (file)
@@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
        int (*set_rate)(int is_porta, int rate); /* for master mode */
 };
 
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
 #endif /* __SOUND_FSI_H */
index 377693a143855fe24a827aaaa035f1c55cccfe61..e7b680248006524012531c0e78d165e01e09ea4b 100644 (file)
@@ -91,15 +91,17 @@ struct snd_pcm_substream;
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_BE)
 
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
 /* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
 
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 /* Digital Audio Interface mute */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
 
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
 struct snd_soc_dai_ops {
        /*
         * DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
 };
 
 /*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
  *
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
  */
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
        /* DAI description */
-       char *name;
+       const char *name;
        unsigned int id;
        int ac97_control;
 
-       struct device *dev;
-       void *ac97_pdata;       /* platform_data for the ac97 codec */
-
-       /* DAI callbacks */
-       int (*probe)(struct platform_device *pdev,
-                    struct snd_soc_dai *dai);
-       void (*remove)(struct platform_device *pdev,
-                      struct snd_soc_dai *dai);
+       /* DAI driver callbacks */
+       int (*probe)(struct snd_soc_dai *dai);
+       int (*remove)(struct snd_soc_dai *dai);
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
 
@@ -219,26 +211,51 @@ struct snd_soc_dai {
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
        unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+       const char *name;
+       int id;
+       struct device *dev;
+       void *ac97_pdata;       /* platform_data for the ac97 codec */
+
+       /* driver ops */
+       struct snd_soc_dai_driver *driver;
 
        /* DAI runtime info */
-       struct snd_soc_codec *codec;
+       unsigned int capture_active:1;          /* stream is in use */
+       unsigned int playback_active:1;         /* stream is in use */
+       unsigned int symmetric_rates:1;
+       struct snd_pcm_runtime *runtime;
        unsigned int active;
        unsigned char pop_wait:1;
+       unsigned char probed:1;
 
-       /* DAI private data */
-       void *private_data;
+       /* DAI DMA data */
+       void *playback_dma_data;
+       void *capture_dma_data;
 
-       /* parent platform */
-       struct snd_soc_platform *platform;
+       /* parent platform/codec */
+       union {
+               struct snd_soc_platform *platform;
+               struct snd_soc_codec *codec;
+       };
+       struct snd_soc_card *card;
 
        struct list_head list;
+       struct list_head card_list;
 };
 
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
                                             const struct snd_pcm_substream *ss)
 {
        return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-               dai->playback.dma_data : dai->capture.dma_data;
+               dai->playback_dma_data : dai->capture_dma_data;
 }
 
 static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
                                            void *data)
 {
        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dai->playback.dma_data = data;
+               dai->playback_dma_data = data;
        else
-               dai->capture.dma_data = data;
+               dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+               void *data)
+{
+       dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+       return dev_get_drvdata(dai->dev);
 }
 
 #endif
index c5d9987bc897adc5ec87a06ec57cadf2fd627471..8fd3b41b763f6a90ca60446cfd6cca97a36664aa 100644 (file)
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
        .reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+                             wevent, wflags)                           \
+{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+       .reg = wreg, .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
        .reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+                            wevent, wflags)                            \
+{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+       .reg = wreg, .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
                            const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
-       int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event);
+void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
deleted file mode 100644 (file)
index a064e19..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-                             void *codec_data, struct snd_soc_dai *dai,
-                             struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-                                struct device_node *node,
-                                struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */
index 65e9d03ed4f5e0c34ca833d6e6570de05fc78125..5c3bce83f28ad1be248a35c89d190dcb1504c36e 100644 (file)
  * @OFF:     Power Off. No restrictions on transition times.
  */
 enum snd_soc_bias_level {
-       SND_SOC_BIAS_ON,
-       SND_SOC_BIAS_PREPARE,
-       SND_SOC_BIAS_STANDBY,
        SND_SOC_BIAS_OFF,
+       SND_SOC_BIAS_STANDBY,
+       SND_SOC_BIAS_PREPARE,
+       SND_SOC_BIAS_ON,
 };
 
 struct snd_jack;
@@ -228,13 +228,17 @@ struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
+struct snd_soc_dai_driver;
 struct snd_soc_platform;
 struct snd_soc_dai_link;
+struct snd_soc_platform_driver;
 struct snd_soc_codec;
+struct snd_soc_codec_driver;
 struct soc_enum;
 struct snd_soc_ac97_ops;
 struct snd_soc_jack;
 struct snd_soc_jack_pin;
+
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
 #endif
@@ -249,19 +253,18 @@ enum snd_soc_control_type {
        SND_SOC_SPI,
 };
 
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_register_platform(struct device *dev,
+               struct snd_soc_platform_driver *platform_drv);
+void snd_soc_unregister_platform(struct device *dev);
+int snd_soc_register_codec(struct device *dev,
+               struct snd_soc_codec_driver *codec_drv,
+               struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                               int addr_bits, int data_bits,
                               enum snd_soc_control_type control);
 
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
        const struct snd_pcm_hardware *hw);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
        int invert;
        int debounce_time;
        struct snd_soc_jack *jack;
-       struct work_struct work;
+       struct delayed_work work;
 
        int (*jack_status_check)(void);
 };
@@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
 
 struct snd_soc_jack {
        struct snd_jack *jack;
-       struct snd_soc_card *card;
+       struct snd_soc_codec *codec;
        struct list_head pins;
        int status;
        struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@ struct snd_soc_jack {
 
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
-       char *stream_name;
+       const char *stream_name;
        u64 formats;                    /* SNDRV_PCM_FMTBIT_* */
        unsigned int rates;             /* SNDRV_PCM_RATE_* */
        unsigned int rate_min;          /* min rate */
        unsigned int rate_max;          /* max rate */
        unsigned int channels_min;      /* min channels */
        unsigned int channels_max;      /* max channels */
-       unsigned int active;            /* stream is in use */
-       void *dma_data;                 /* used by platform code */
 };
 
 /* SoC audio ops */
@@ -419,44 +420,36 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
 struct snd_soc_codec {
-       char *name;
-       struct module *owner;
-       struct mutex mutex;
+       const char *name;
+       int id;
        struct device *dev;
-       struct snd_soc_device *socdev;
+       struct snd_soc_codec_driver *driver;
 
+       struct mutex mutex;
+       struct snd_soc_card *card;
        struct list_head list;
-
-       /* callbacks */
-       int (*set_bias_level)(struct snd_soc_codec *,
-                             enum snd_soc_bias_level level);
+       struct list_head card_list;
+       int num_dai;
 
        /* runtime */
-       struct snd_card *card;
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
        unsigned int active;
-       unsigned int pcm_devs;
-       void *drvdata;
+       unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+       unsigned int cache_only:1;  /* Suppress writes to hardware */
+       unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+       unsigned int suspended:1; /* Codec is in suspend PM state */
+       unsigned int probed:1; /* Codec has been probed */
+       unsigned int ac97_registered:1; /* Codec has been AC97 registered */
+       unsigned int ac97_created:1; /* Codec has been created by SoC */
+       unsigned int sysfs_registered:1; /* codec has been sysfs registered */
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
-       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
-       int (*display_register)(struct snd_soc_codec *, char *,
-                               size_t, unsigned int);
-       int (*volatile_register)(unsigned int);
-       int (*readable_register)(unsigned int);
        hw_write_t hw_write;
        unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
        void *reg_cache;
-       short reg_cache_size;
-       short reg_cache_step;
-
-       unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-       unsigned int cache_only:1;  /* Suppress writes to hardware */
-       unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
 
        /* dapm */
        u32 pop_time;
@@ -466,10 +459,6 @@ struct snd_soc_codec {
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
 
-       /* codec DAI's */
-       struct snd_soc_dai *dai;
-       unsigned int num_dai;
-
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_codec_root;
        struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@ struct snd_soc_codec {
 #endif
 };
 
-/* codec device */
-struct snd_soc_codec_device {
-       int (*probe)(struct platform_device *pdev);
-       int (*remove)(struct platform_device *pdev);
-       int (*suspend)(struct platform_device *pdev, pm_message_t state);
-       int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+       /* driver ops */
+       int (*probe)(struct snd_soc_codec *);
+       int (*remove)(struct snd_soc_codec *);
+       int (*suspend)(struct snd_soc_codec *,
+                       pm_message_t state);
+       int (*resume)(struct snd_soc_codec *);
+
+       /* codec IO */
+       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+       int (*display_register)(struct snd_soc_codec *, char *,
+                               size_t, unsigned int);
+       int (*volatile_register)(unsigned int);
+       int (*readable_register)(unsigned int);
+       short reg_cache_size;
+       short reg_cache_step;
+       short reg_word_size;
+       const void *reg_cache_default;
+
+       /* codec bias level */
+       int (*set_bias_level)(struct snd_soc_codec *,
+                             enum snd_soc_bias_level level);
 };
 
 /* SoC platform interface */
-struct snd_soc_platform {
-       char *name;
-       struct list_head list;
+struct snd_soc_platform_driver {
 
-       int (*probe)(struct platform_device *pdev);
-       int (*remove)(struct platform_device *pdev);
-       int (*suspend)(struct snd_soc_dai_link *dai_link);
-       int (*resume)(struct snd_soc_dai_link *dai_link);
+       int (*probe)(struct snd_soc_platform *);
+       int (*remove)(struct snd_soc_platform *);
+       int (*suspend)(struct snd_soc_dai *dai);
+       int (*resume)(struct snd_soc_dai *dai);
 
        /* pcm creation and destruction */
        int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@ struct snd_soc_platform {
                struct snd_soc_dai *);
 
        /* platform stream ops */
-       struct snd_pcm_ops *pcm_ops;
+       struct snd_pcm_ops *ops;
 };
 
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link  {
-       char *name;                     /* Codec name */
-       char *stream_name;              /* Stream name */
+struct snd_soc_platform {
+       const char *name;
+       int id;
+       struct device *dev;
+       struct snd_soc_platform_driver *driver;
 
-       /* DAI */
-       struct snd_soc_dai *codec_dai;
-       struct snd_soc_dai *cpu_dai;
+       unsigned int suspended:1; /* platform is suspended */
+       unsigned int probed:1;
 
-       /* machine stream operations */
-       struct snd_soc_ops *ops;
+       struct snd_soc_card *card;
+       struct list_head list;
+       struct list_head card_list;
+};
 
-       /* codec/machine specific init - e.g. add machine controls */
-       int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+       /* config - must be set by machine driver */
+       const char *name;                       /* Codec name */
+       const char *stream_name;                /* Stream name */
+       const char *codec_name;         /* for multi-codec */
+       const char *platform_name;      /* for multi-platform */
+       const char *cpu_dai_name;
+       const char *codec_dai_name;
 
        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@ struct snd_soc_dai_link  {
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 
-       /* Symmetry data - only valid if symmetry is being enforced */
-       unsigned int rate;
+       /* codec/machine specific init - e.g. add machine controls */
+       int (*init)(struct snd_soc_pcm_runtime *rtd);
 
-       /* DAI pcm */
-       struct snd_pcm *pcm;
+       /* machine stream operations */
+       struct snd_soc_ops *ops;
 };
 
 /* SoC card */
 struct snd_soc_card {
-       char *name;
+       const char *name;
        struct device *dev;
+       struct snd_card *snd_card;
+       struct module *owner;
 
        struct list_head list;
+       struct mutex mutex;
 
-       int instantiated;
+       bool instantiated;
 
        int (*probe)(struct platform_device *pdev);
        int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@ struct snd_soc_card {
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
        int num_links;
+       struct snd_soc_pcm_runtime *rtd;
+       int num_rtd;
 
-       struct snd_soc_device *socdev;
-
-       struct snd_soc_codec *codec;
-
-       struct snd_soc_platform *platform;
-       struct delayed_work delayed_work;
        struct work_struct deferred_resume_work;
+
+       /* lists of probed devices belonging to this card */
+       struct list_head codec_dev_list;
+       struct list_head platform_dev_list;
+       struct list_head dai_dev_list;
 };
 
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
-       struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime  {
+       struct device dev;
        struct snd_soc_card *card;
-       struct snd_soc_codec_device *codec_dev;
-       void *codec_data;
-};
+       struct snd_soc_dai_link *dai_link;
+
+       unsigned int complete:1;
+       unsigned int dev_registered:1;
+
+       /* Symmetry data - only valid if symmetry is being enforced */
+       unsigned int rate;
+       long pmdown_time;
 
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
-       struct snd_soc_dai_link *dai;
-       struct snd_soc_device *socdev;
+       /* runtime devices */
+       struct snd_pcm *pcm;
+       struct snd_soc_codec *codec;
+       struct snd_soc_platform *platform;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
+
+       struct delayed_work delayed_work;
 };
 
 /* mixer control */
@@ -615,24 +642,48 @@ struct soc_enum {
 static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
                                        unsigned int reg)
 {
-       return codec->read(codec, reg);
+       return codec->driver->read(codec, reg);
 }
 
 static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
                                         unsigned int reg, unsigned int val)
 {
-       return codec->write(codec, reg, val);
+       return codec->driver->write(codec, reg, val);
 }
 
+/* device driver data */
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
-                                            void *data)
+               void *data)
 {
-       codec->drvdata = data;
+       dev_set_drvdata(codec->dev, data);
 }
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
-       return codec->drvdata;
+       return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+               void *data)
+{
+       dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+       return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+               void *data)
+{
+       dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+       return dev_get_drvdata(&rtd->dev);
 }
 
 #include <sound/soc-dai.h>
index 9fd5b19ccf5c05a7002440588041e49b3e9a8e18..7067e2dfb0b992abc09840c1c58c23a4d4d7e351 100644 (file)
 #define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
 #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with mute */
 
+#define TLV_DB_SCALE_MASK      0xffff
+#define TLV_DB_SCALE_MUTE      0x10000
 #define TLV_DB_SCALE_ITEM(min, step, mute)                     \
        SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int),      \
-       (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
+       (min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
        unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
 
index b1a5f34e5cfad9917cb48ecd3872152eeae6944b..99e0308bf2c2416d3e0864fd1063b53f3f2656c3 100644 (file)
 #ifndef __TLV320AIC3x_H__
 #define __TLV320AIC3x_H__
 
+/* GPIO API */
+enum {
+       AIC3X_GPIO1_FUNC_DISABLED               = 0,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
+       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
+       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
+       AIC3X_GPIO1_FUNC_INPUT                  = 8,
+       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
+       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
+       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
+       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
+};
+
+enum {
+       AIC3X_GPIO2_FUNC_DISABLED               = 0,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
+       AIC3X_GPIO2_FUNC_INPUT                  = 3,
+       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
+       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
+       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
+       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
+       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
+};
+
+struct aic3x_setup_data {
+       unsigned int gpio_func[2];
+};
+
 struct aic3x_pdata {
        int gpio_reset; /* < 0 if not used */
+       struct aic3x_setup_data *setup;
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
new file mode 100644 (file)
index 0000000..2b5306c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * wm8962.h  --  WM8962 Soc Audio driver platform data
+ *
+ * This program is free software; you can 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 _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+       int gpio_base;
+       u32 gpio_init[WM8962_MAX_GPIO];
+
+       /* Setup for microphone detection, raw value to be written to
+        * R48(0x30) - only microphone related bits will be updated.
+        * Detection may be enabled here for use with signals brought
+        * out on the GPIOs. */
+       u32 mic_cfg;
+
+       bool irq_active_low;
+
+       bool spk_mono;   /* Speaker outputs tied together as mono */
+};
+
+#endif
index 01e9e0076a92c68682fa513e1f4a862e291fb9ae..6bcb00645de47ffb9262c1c366fa14e82291e887 100644 (file)
@@ -242,18 +242,20 @@ TRACE_EVENT(ext4_da_writepages,
                __entry->pages_skipped  = wbc->pages_skipped;
                __entry->range_start    = wbc->range_start;
                __entry->range_end      = wbc->range_end;
-               __entry->nonblocking    = wbc->nonblocking;
                __entry->for_kupdate    = wbc->for_kupdate;
                __entry->for_reclaim    = wbc->for_reclaim;
                __entry->range_cyclic   = wbc->range_cyclic;
                __entry->writeback_index = inode->i_mapping->writeback_index;
        ),
 
-       TP_printk("dev %s ino %lu nr_to_write %ld pages_skipped %ld range_start %llu range_end %llu nonblocking %d for_kupdate %d for_reclaim %d range_cyclic %d writeback_index %lu",
+       TP_printk("dev %s ino %lu nr_to_write %ld pages_skipped %ld "
+                 "range_start %llu range_end %llu "
+                 "for_kupdate %d for_reclaim %d "
+                 "range_cyclic %d writeback_index %lu",
                  jbd2_dev_to_name(__entry->dev),
                  (unsigned long) __entry->ino, __entry->nr_to_write,
                  __entry->pages_skipped, __entry->range_start,
-                 __entry->range_end, __entry->nonblocking,
+                 __entry->range_end,
                  __entry->for_kupdate, __entry->for_reclaim,
                  __entry->range_cyclic,
                  (unsigned long) __entry->writeback_index)
index 370aa5a87322fa686f3f6b59474e67bf9cf94567..c255fcc587bfe7d3acca8e6bf8d7642bc5f7ce24 100644 (file)
@@ -10,6 +10,7 @@
 
 #define RECLAIM_WB_ANON                0x0001u
 #define RECLAIM_WB_FILE                0x0002u
+#define RECLAIM_WB_MIXED       0x0010u
 #define RECLAIM_WB_SYNC                0x0004u
 #define RECLAIM_WB_ASYNC       0x0008u
 
        (flags) ? __print_flags(flags, "|",                     \
                {RECLAIM_WB_ANON,       "RECLAIM_WB_ANON"},     \
                {RECLAIM_WB_FILE,       "RECLAIM_WB_FILE"},     \
+               {RECLAIM_WB_MIXED,      "RECLAIM_WB_MIXED"},    \
                {RECLAIM_WB_SYNC,       "RECLAIM_WB_SYNC"},     \
                {RECLAIM_WB_ASYNC,      "RECLAIM_WB_ASYNC"}     \
                ) : "RECLAIM_WB_NONE"
 
 #define trace_reclaim_flags(page, sync) ( \
        (page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
-       (sync == PAGEOUT_IO_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC)   \
+       (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC)   \
+       )
+
+#define trace_shrink_flags(file, sync) ( \
+       (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_MIXED : \
+                       (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON)) |  \
+       (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
        )
 
 TRACE_EVENT(mm_vmscan_kswapd_sleep,
@@ -269,6 +277,40 @@ TRACE_EVENT(mm_vmscan_writepage,
                show_reclaim_flags(__entry->reclaim_flags))
 );
 
+TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
+
+       TP_PROTO(int nid, int zid,
+                       unsigned long nr_scanned, unsigned long nr_reclaimed,
+                       int priority, int reclaim_flags),
+
+       TP_ARGS(nid, zid, nr_scanned, nr_reclaimed, priority, reclaim_flags),
+
+       TP_STRUCT__entry(
+               __field(int, nid)
+               __field(int, zid)
+               __field(unsigned long, nr_scanned)
+               __field(unsigned long, nr_reclaimed)
+               __field(int, priority)
+               __field(int, reclaim_flags)
+       ),
+
+       TP_fast_assign(
+               __entry->nid = nid;
+               __entry->zid = zid;
+               __entry->nr_scanned = nr_scanned;
+               __entry->nr_reclaimed = nr_reclaimed;
+               __entry->priority = priority;
+               __entry->reclaim_flags = reclaim_flags;
+       ),
+
+       TP_printk("nid=%d zid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
+               __entry->nid, __entry->zid,
+               __entry->nr_scanned, __entry->nr_reclaimed,
+               __entry->priority,
+               show_reclaim_flags(__entry->reclaim_flags))
+);
+
+
 #endif /* _TRACE_VMSCAN_H */
 
 /* This part must be outside protection */
index f345f66ae9d100d755c4e4a1afb3f4b2310148da..89a2b2db43751686129d90f8d58fd3c08787726b 100644 (file)
@@ -96,8 +96,6 @@ DECLARE_EVENT_CLASS(wbc_class,
                __field(long, nr_to_write)
                __field(long, pages_skipped)
                __field(int, sync_mode)
-               __field(int, nonblocking)
-               __field(int, encountered_congestion)
                __field(int, for_kupdate)
                __field(int, for_background)
                __field(int, for_reclaim)
@@ -153,6 +151,41 @@ DEFINE_WBC_EVENT(wbc_balance_dirty_written);
 DEFINE_WBC_EVENT(wbc_balance_dirty_wait);
 DEFINE_WBC_EVENT(wbc_writepage);
 
+DECLARE_EVENT_CLASS(writeback_congest_waited_template,
+
+       TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+       TP_ARGS(usec_timeout, usec_delayed),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   usec_timeout    )
+               __field(        unsigned int,   usec_delayed    )
+       ),
+
+       TP_fast_assign(
+               __entry->usec_timeout   = usec_timeout;
+               __entry->usec_delayed   = usec_delayed;
+       ),
+
+       TP_printk("usec_timeout=%u usec_delayed=%u",
+                       __entry->usec_timeout,
+                       __entry->usec_delayed)
+);
+
+DEFINE_EVENT(writeback_congest_waited_template, writeback_congestion_wait,
+
+       TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+       TP_ARGS(usec_timeout, usec_delayed)
+);
+
+DEFINE_EVENT(writeback_congest_waited_template, writeback_wait_iff_congested,
+
+       TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+       TP_ARGS(usec_timeout, usec_delayed)
+);
+
 #endif /* _TRACE_WRITEBACK_H */
 
 /* This part must be outside protection */
index 577cf18cce8961ec8a1075b150cb985f0ee63997..1e1aa54ab2e45bad0c1d6841572ba84ff0e912a3 100644 (file)
 struct sh_mobile_lcdc_chan_cfg;
 struct device;
 
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK      (0xF << 0)
+#define HDMI_SND_SRC_I2S       (0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF     (1 << 0)
+#define HDMI_SND_SRC_DSD       (2 << 0)
+#define HDMI_SND_SRC_HBR       (3 << 0)
+
 struct sh_mobile_hdmi_info {
        struct sh_mobile_lcdc_chan_cfg  *lcd_chan;
        struct device                   *lcd_dev;
+       unsigned int                     flags;
 };
 
 #endif
index 4e65c16a445b06f573afc055e92c7d4b9280d907..84ad8f02fee5e5904c31c21915db049de7c3b2b3 100644 (file)
@@ -1 +1,2 @@
 header-y += evtchn.h
+header-y += privcmd.h
index d3938d3e71f822c01956cdb6fbe93bc90cfb1363..d7a6c13bde69cf505bef40027bcd555a4463d57f 100644 (file)
@@ -186,6 +186,35 @@ struct xen_translate_gpfn_list {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
 
+/*
+ * Returns the pseudo-physical memory map as it was when the domain
+ * was started (specified by XENMEM_set_memory_map).
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_memory_map           9
+struct xen_memory_map {
+    /*
+     * On call the number of entries which can be stored in buffer. On
+     * return the number of entries which have been stored in
+     * buffer.
+     */
+    unsigned int nr_entries;
+
+    /*
+     * Entries in the buffer are in the same format as returned by the
+     * BIOS INT 0x15 EAX=0xE820 call.
+     */
+    GUEST_HANDLE(void) buffer;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
+
+/*
+ * Returns the real physical memory map. Passes the same structure as
+ * XENMEM_memory_map.
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_machine_memory_map   10
+
 
 /*
  * Prevent the balloon driver from changing the memory reservation
diff --git a/include/xen/privcmd.h b/include/xen/privcmd.h
new file mode 100644 (file)
index 0000000..b42cdfd
--- /dev/null
@@ -0,0 +1,80 @@
+/******************************************************************************
+ * privcmd.h
+ *
+ * Interface to /proc/xen/privcmd.
+ *
+ * Copyright (c) 2003-2005, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 __LINUX_PUBLIC_PRIVCMD_H__
+#define __LINUX_PUBLIC_PRIVCMD_H__
+
+#include <linux/types.h>
+
+typedef unsigned long xen_pfn_t;
+
+#ifndef __user
+#define __user
+#endif
+
+struct privcmd_hypercall {
+       __u64 op;
+       __u64 arg[5];
+};
+
+struct privcmd_mmap_entry {
+       __u64 va;
+       __u64 mfn;
+       __u64 npages;
+};
+
+struct privcmd_mmap {
+       int num;
+       domid_t dom; /* target domain */
+       struct privcmd_mmap_entry __user *entry;
+};
+
+struct privcmd_mmapbatch {
+       int num;     /* number of pages to populate */
+       domid_t dom; /* target domain */
+       __u64 addr;  /* virtual address */
+       xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
+};
+
+/*
+ * @cmd: IOCTL_PRIVCMD_HYPERCALL
+ * @arg: &privcmd_hypercall_t
+ * Return: Value returned from execution of the specified hypercall.
+ */
+#define IOCTL_PRIVCMD_HYPERCALL                                        \
+       _IOC(_IOC_NONE, 'P', 0, sizeof(struct privcmd_hypercall))
+#define IOCTL_PRIVCMD_MMAP                                     \
+       _IOC(_IOC_NONE, 'P', 2, sizeof(struct privcmd_mmap))
+#define IOCTL_PRIVCMD_MMAPBATCH                                        \
+       _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
+
+#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
index 351f4051f6d856d455d5f3d60b75bf3570209d9a..98b92154a2645407808c74ba9326e735f84b75af 100644 (file)
@@ -23,4 +23,9 @@ int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
 
 void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
 
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+                              unsigned long addr,
+                              unsigned long mfn, int nr,
+                              pgprot_t prot, unsigned domid);
+
 #endif /* INCLUDE_XEN_OPS_H */
index 42db0551c3aaf4892986e34673b40ddf30f4b724..830aaec9c7d5e0cb8df39af760791b5335772768 100644 (file)
@@ -291,7 +291,7 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
        if (err)
                return err;
 
-       sys_chdir("/root");
+       sys_chdir((const char __user __force *)"/root");
        ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
        printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
               current->fs->pwd.mnt->mnt_sb->s_type->name,
@@ -361,13 +361,13 @@ out:
 #ifdef CONFIG_ROOT_NFS
 static int __init mount_nfs_root(void)
 {
-       void *data = nfs_root_data();
+       char *root_dev, *root_data;
 
-       create_dev("/dev/root", ROOT_DEV);
-       if (data &&
-           do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0)
-               return 1;
-       return 0;
+       if (nfs_root_data(&root_dev, &root_data) != 0)
+               return 0;
+       if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0)
+               return 0;
+       return 1;
 }
 #endif
 
@@ -488,5 +488,5 @@ void __init prepare_namespace(void)
 out:
        devtmpfs_mount("dev");
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
-       sys_chroot(".");
+       sys_chroot((const char __user __force *)".");
 }
index 69aebbf8fd2dbf4ebeb301cf1fa590d3c864b9c9..32c4799b8c91bb483f418cd6a39e1e11eda0cd7a 100644 (file)
@@ -283,7 +283,7 @@ static void __init autodetect_raid(void)
 
        wait_for_device_probe();
 
-       fd = sys_open("/dev/md0", 0, 0);
+       fd = sys_open((const char __user __force *) "/dev/md0", 0, 0);
        if (fd >= 0) {
                sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
                sys_close(fd);
index bf3ef667bf3669d4332fbaa5fdd65784823c0f54..6e1ee6987c78dbca4cb3f01aaa031e4b3a42708f 100644 (file)
@@ -168,7 +168,7 @@ int __init rd_load_image(char *from)
        char rotator[4] = { '|' , '/' , '-' , '\\' };
 #endif
 
-       out_fd = sys_open("/dev/ram", O_RDWR, 0);
+       out_fd = sys_open((const char __user __force *) "/dev/ram", O_RDWR, 0);
        if (out_fd < 0)
                goto out;
 
@@ -267,7 +267,7 @@ noclose_input:
        sys_close(out_fd);
 out:
        kfree(buf);
-       sys_unlink("/dev/ram");
+       sys_unlink((const char __user __force *) "/dev/ram");
        return res;
 }
 
index 4b9c20205092e1f7de716633c0d51bd8746e74af..d9c6e782ff5333012ba0b527a084b1d14a35e624 100644 (file)
@@ -528,7 +528,7 @@ static void __init clean_rootfs(void)
        struct linux_dirent64 *dirp;
        int num;
 
-       fd = sys_open("/", O_RDONLY, 0);
+       fd = sys_open((const char __user __force *) "/", O_RDONLY, 0);
        WARN_ON(fd < 0);
        if (fd < 0)
                return;
@@ -590,7 +590,8 @@ static int __init populate_rootfs(void)
                }
                printk(KERN_INFO "rootfs image is not initramfs (%s)"
                                "; looks like an initrd\n", err);
-               fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
+               fd = sys_open((const char __user __force *) "/initrd.image",
+                             O_WRONLY|O_CREAT, 0700);
                if (fd >= 0) {
                        sys_write(fd, (char *)initrd_start,
                                        initrd_end - initrd_start);
index f4c1a3a1b8c52bd06dbdcadf6833b5328693b0e3..267739d851791b0a3e4526a3be5fb4944d8b507e 100644 (file)
@@ -29,17 +29,17 @@ static int __init default_rootfs(void)
 {
        int err;
 
-       err = sys_mkdir("/dev", 0755);
+       err = sys_mkdir((const char __user __force *) "/dev", 0755);
        if (err < 0)
                goto out;
 
-       err = sys_mknod((const char __user *) "/dev/console",
+       err = sys_mknod((const char __user __force *) "/dev/console",
                        S_IFCHR | S_IRUSR | S_IWUSR,
                        new_encode_dev(MKDEV(5, 1)));
        if (err < 0)
                goto out;
 
-       err = sys_mkdir("/root", 0700);
+       err = sys_mkdir((const char __user __force *) "/root", 0700);
        if (err < 0)
                goto out;
 
index e1e7b9635f5da7c986dfd18426bce94c177d6630..3a61ffefe88472af269e0bc218d6f8eb2959a1c9 100644 (file)
@@ -116,6 +116,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
 
        inode = new_inode(sb);
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = current_fsuid();
                inode->i_gid = current_fsgid();
@@ -769,7 +770,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
 
        inode = dentry->d_inode;
        if (inode)
-               atomic_inc(&inode->i_count);
+               ihold(inode);
        err = mnt_want_write(ipc_ns->mq_mnt);
        if (err)
                goto out_err;
index 7b69b8d0313d63a92bd4efaf4d07676456fe71fc..9270d532ec3c7c6a5be2cf3d1eca21788036b81f 100644 (file)
@@ -777,6 +777,7 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
        struct inode *inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_uid = current_fsuid();
                inode->i_gid = current_fsgid();
index e2bdf37f9fdea71a15acb3523ec20b63a6aa42d3..894179a32ec163fe3347f8614626ddf7a9946cb7 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/perf_event.h>
 #include <trace/events/sched.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/oom.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -687,6 +688,8 @@ static void exit_mm(struct task_struct * tsk)
        enter_lazy_tlb(mm, current);
        /* We don't want this task to be frozen prematurely */
        clear_freeze_flag(tsk);
+       if (tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+               atomic_dec(&mm->oom_disable_count);
        task_unlock(tsk);
        mm_update_next_owner(mm);
        mmput(mm);
index c445f8cc408d777dd7a94aec3fa78c07e1d98b98..e87aaaaf5131de2bb924c963d618a52f5de01127 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/perf_event.h>
 #include <linux/posix-timers.h>
 #include <linux/user-return-notifier.h>
+#include <linux/oom.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -488,6 +489,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
        mm->cached_hole_size = ~0UL;
        mm_init_aio(mm);
        mm_init_owner(mm, p);
+       atomic_set(&mm->oom_disable_count, 0);
 
        if (likely(!mm_alloc_pgd(mm))) {
                mm->def_flags = 0;
@@ -741,6 +743,8 @@ good_mm:
        /* Initializing for Swap token stuff */
        mm->token_priority = 0;
        mm->last_interval = 0;
+       if (tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+               atomic_inc(&mm->oom_disable_count);
 
        tsk->mm = mm;
        tsk->active_mm = mm;
@@ -1299,8 +1303,13 @@ bad_fork_cleanup_io:
 bad_fork_cleanup_namespaces:
        exit_task_namespaces(p);
 bad_fork_cleanup_mm:
-       if (p->mm)
+       if (p->mm) {
+               task_lock(p);
+               if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+                       atomic_dec(&p->mm->oom_disable_count);
+               task_unlock(p);
                mmput(p->mm);
+       }
 bad_fork_cleanup_signal:
        if (!(clone_flags & CLONE_THREAD))
                free_signal_struct(p->signal);
@@ -1693,6 +1702,10 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
                        active_mm = current->active_mm;
                        current->mm = new_mm;
                        current->active_mm = new_mm;
+                       if (current->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+                               atomic_dec(&mm->oom_disable_count);
+                               atomic_inc(&new_mm->oom_disable_count);
+                       }
                        activate_mm(active_mm, new_mm);
                        new_mm = mm;
                }
index a118bf160e0b05a4b24404beda19d07adead5161..6c683b37f2ce25291a5a0c8f490a16c08c84d674 100644 (file)
@@ -169,7 +169,7 @@ static void get_futex_key_refs(union futex_key *key)
 
        switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
        case FUT_OFF_INODE:
-               atomic_inc(&key->shared.inode->i_count);
+               ihold(key->shared.inode);
                break;
        case FUT_OFF_MMSHARED:
                atomic_inc(&key->private.mm->mm_count);
index c0613f7d673064b7bbe1afcf7477dd569310989c..b55045bc7563186a84ee04267c41011bc0f59cd2 100644 (file)
@@ -816,7 +816,7 @@ static int kimage_load_normal_segment(struct kimage *image,
 
                ptr = kmap(page);
                /* Start with a clear page */
-               memset(ptr, 0, PAGE_SIZE);
+               clear_page(ptr);
                ptr += maddr & ~PAGE_MASK;
                mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
                if (mchunk > mbytes)
index ac7eb109f19635d11930a9cef03ed4cd352cc235..0dac75ea4456f040b14ae18e3dbbe5ce8332a108 100644 (file)
@@ -984,8 +984,8 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
                src = kmap_atomic(s_page, KM_USER0);
                dst = kmap_atomic(d_page, KM_USER1);
                do_copy_page(dst, src);
-               kunmap_atomic(src, KM_USER0);
                kunmap_atomic(dst, KM_USER1);
+               kunmap_atomic(src, KM_USER0);
        } else {
                if (PageHighMem(d_page)) {
                        /* Page pointed to by src may contain some kernel
@@ -993,7 +993,7 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
                         */
                        safe_copy_page(buffer, s_page);
                        dst = kmap_atomic(d_page, KM_USER0);
-                       memcpy(dst, buffer, PAGE_SIZE);
+                       copy_page(dst, buffer);
                        kunmap_atomic(dst, KM_USER0);
                } else {
                        safe_copy_page(page_address(d_page), s_page);
@@ -1687,7 +1687,7 @@ int snapshot_read_next(struct snapshot_handle *handle)
                memory_bm_position_reset(&orig_bm);
                memory_bm_position_reset(&copy_bm);
        } else if (handle->cur <= nr_meta_pages) {
-               memset(buffer, 0, PAGE_SIZE);
+               clear_page(buffer);
                pack_pfns(buffer, &orig_bm);
        } else {
                struct page *page;
@@ -1701,7 +1701,7 @@ int snapshot_read_next(struct snapshot_handle *handle)
                        void *kaddr;
 
                        kaddr = kmap_atomic(page, KM_USER0);
-                       memcpy(buffer, kaddr, PAGE_SIZE);
+                       copy_page(buffer, kaddr);
                        kunmap_atomic(kaddr, KM_USER0);
                        handle->buffer = buffer;
                } else {
@@ -1984,7 +1984,7 @@ static void copy_last_highmem_page(void)
                void *dst;
 
                dst = kmap_atomic(last_highmem_page, KM_USER0);
-               memcpy(dst, buffer, PAGE_SIZE);
+               copy_page(dst, buffer);
                kunmap_atomic(dst, KM_USER0);
                last_highmem_page = NULL;
        }
@@ -2270,11 +2270,11 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf)
 
        kaddr1 = kmap_atomic(p1, KM_USER0);
        kaddr2 = kmap_atomic(p2, KM_USER1);
-       memcpy(buf, kaddr1, PAGE_SIZE);
-       memcpy(kaddr1, kaddr2, PAGE_SIZE);
-       memcpy(kaddr2, buf, PAGE_SIZE);
-       kunmap_atomic(kaddr1, KM_USER0);
+       copy_page(buf, kaddr1);
+       copy_page(kaddr1, kaddr2);
+       copy_page(kaddr2, buf);
        kunmap_atomic(kaddr2, KM_USER1);
+       kunmap_atomic(kaddr1, KM_USER0);
 }
 
 /**
index 916eaa79039968ff8412128858e9b8aeda951ac6..a0e4a86ccf94887a6f64ae985db131608def8952 100644 (file)
@@ -251,7 +251,7 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
        if (bio_chain) {
                src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
                if (src) {
-                       memcpy(src, buf, PAGE_SIZE);
+                       copy_page(src, buf);
                } else {
                        WARN_ON_ONCE(1);
                        bio_chain = NULL;       /* Go synchronous */
@@ -325,7 +325,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
                error = write_page(handle->cur, handle->cur_swap, NULL);
                if (error)
                        goto out;
-               memset(handle->cur, 0, PAGE_SIZE);
+               clear_page(handle->cur);
                handle->cur_swap = offset;
                handle->k = 0;
        }
@@ -910,7 +910,7 @@ int swsusp_check(void)
        hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
        if (!IS_ERR(hib_resume_bdev)) {
                set_blocksize(hib_resume_bdev, PAGE_SIZE);
-               memset(swsusp_header, 0, PAGE_SIZE);
+               clear_page(swsusp_header);
                error = hib_bio_read_page(swsusp_resume_block,
                                        swsusp_header, NULL);
                if (error)
index 2531017795f63e7d9c60d1db976e2b227c98ffda..b2ebaee8c377d2aa92c073e772748242b5ce5c90 100644 (file)
@@ -210,7 +210,7 @@ __setup("log_buf_len=", log_buf_len_setup);
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
 
-static unsigned int boot_delay; /* msecs delay after each printk during bootup */
+static int boot_delay; /* msecs delay after each printk during bootup */
 static unsigned long long loops_per_msec;      /* based on boot_delay */
 
 static int __init boot_delay_setup(char *str)
@@ -647,6 +647,7 @@ static inline int can_use_console(unsigned int cpu)
  * released but interrupts still disabled.
  */
 static int acquire_console_semaphore_for_printk(unsigned int cpu)
+       __releases(&logbuf_lock)
 {
        int retval = 0;
 
@@ -1511,7 +1512,7 @@ int kmsg_dump_unregister(struct kmsg_dumper *dumper)
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
 
-static const char const *kmsg_reasons[] = {
+static const char * const kmsg_reasons[] = {
        [KMSG_DUMP_OOPS]        = "oops",
        [KMSG_DUMP_PANIC]       = "panic",
        [KMSG_DUMP_KEXEC]       = "kexec",
index 090c28812ce101fbd055821fe12806265bd1ed9b..2df820b03beb17499afccd6c3acc59e08bfd0194 100644 (file)
@@ -262,7 +262,7 @@ repeat:
                cpu_stop_fn_t fn = work->fn;
                void *arg = work->arg;
                struct cpu_stop_done *done = work->done;
-               char ksym_buf[KSYM_NAME_LEN];
+               char ksym_buf[KSYM_NAME_LEN] __maybe_unused;
 
                __set_current_state(TASK_RUNNING);
 
@@ -304,7 +304,7 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
                p = kthread_create(cpu_stopper_thread, stopper, "migration/%d",
                                   cpu);
                if (IS_ERR(p))
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(PTR_ERR(p));
                get_task_struct(p);
                kthread_bind(p, cpu);
                sched_set_stop_task(cpu, p);
@@ -372,7 +372,7 @@ static int __init cpu_stop_init(void)
        /* start one for the boot cpu */
        err = cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_UP_PREPARE,
                                    bcpu);
-       BUG_ON(err == NOTIFY_BAD);
+       BUG_ON(err != NOTIFY_OK);
        cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_ONLINE, bcpu);
        register_cpu_notifier(&cpu_stop_cpu_notifier);
 
index 3a45c224770fb82fa4bd76f9c7d4f2f989ee5aa9..c33a1edb799fda6db2e16fdf9d1d0401a9f78278 100644 (file)
@@ -161,8 +161,6 @@ extern int no_unaligned_warning;
 extern int unaligned_dump_stack;
 #endif
 
-extern struct ratelimit_state printk_ratelimit_state;
-
 #ifdef CONFIG_PROC_SYSCTL
 static int proc_do_cad_pid(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -1340,28 +1338,28 @@ static struct ctl_table fs_table[] = {
                .data           = &inodes_stat,
                .maxlen         = 2*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_nr_inodes,
        },
        {
                .procname       = "inode-state",
                .data           = &inodes_stat,
                .maxlen         = 7*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_nr_inodes,
        },
        {
                .procname       = "file-nr",
                .data           = &files_stat,
-               .maxlen         = 3*sizeof(int),
+               .maxlen         = sizeof(files_stat),
                .mode           = 0444,
                .proc_handler   = proc_nr_files,
        },
        {
                .procname       = "file-max",
                .data           = &files_stat.max_files,
-               .maxlen         = sizeof(int),
+               .maxlen         = sizeof(files_stat.max_files),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
                .procname       = "nr_open",
@@ -1377,7 +1375,7 @@ static struct ctl_table fs_table[] = {
                .data           = &dentry_stat,
                .maxlen         = 6*sizeof(int),
                .mode           = 0444,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_nr_dentry,
        },
        {
                .procname       = "overflowuid",
index 7e72614b736d82dd108d99ab79daefa55e6cdfe3..2c7d8d5914b188be65c36a686a81fba7eed07d8c 100644 (file)
@@ -91,6 +91,7 @@ static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
  * upon function exit.
  */
 static void free_user(struct user_struct *up, unsigned long flags)
+       __releases(&uidhash_lock)
 {
        uid_hash_remove(up);
        spin_unlock_irqrestore(&uidhash_lock, flags);
index c4bd3d825f35c8c8dd7ed4831cd5fee5fe6a6b9a..b0310eb6cc1e85433a502e7c93c62651e216f47a 100644 (file)
@@ -92,7 +92,7 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
 }
 EXPORT_SYMBOL(prepare_to_wait_exclusive);
 
-/*
+/**
  * finish_wait - clean up after waiting in a queue
  * @q: waitqueue waited on
  * @wait: wait descriptor
@@ -127,11 +127,11 @@ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
 }
 EXPORT_SYMBOL(finish_wait);
 
-/*
+/**
  * abort_exclusive_wait - abort exclusive waiting in a queue
  * @q: waitqueue waited on
  * @wait: wait descriptor
- * @state: runstate of the waiter to be woken
+ * @mode: runstate of the waiter to be woken
  * @key: key to identify a wait bit queue or %NULL
  *
  * Sets current thread back to running state and removes
index 30acdb74cc23bfb21d1dcc0a14433003c9e085b7..90db1bd1a97852e4c547c43d840b2ca624c9a773 100644 (file)
@@ -2064,7 +2064,7 @@ static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
         * checks and call back into the fixup functions where we
         * might deadlock.
         */
-       INIT_WORK_ON_STACK(&barr->work, wq_barrier_func);
+       INIT_WORK_ONSTACK(&barr->work, wq_barrier_func);
        __set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work));
        init_completion(&barr->done);
 
@@ -2791,7 +2791,9 @@ static int alloc_cwqs(struct workqueue_struct *wq)
                }
        }
 
-       /* just in case, make sure it's actually aligned */
+       /* just in case, make sure it's actually aligned
+        * - this is affected by PERCPU() alignment in vmlinux.lds.S
+        */
        BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align));
        return wq->cpu_wq.v ? 0 : -ENOMEM;
 }
index 69a32664c289692576677a48d5daacca69212752..995840664a5f388b1248bb5b5b363daa1e89948e 100644 (file)
@@ -317,6 +317,14 @@ config DEBUG_OBJECTS_RCU_HEAD
        help
          Enable this to turn on debugging of RCU list heads (call_rcu() usage).
 
+config DEBUG_OBJECTS_PERCPU_COUNTER
+       bool "Debug percpu counter objects"
+       depends on DEBUG_OBJECTS
+       help
+         If you say Y here, additional code will be inserted into the
+         percpu counter routines to track the life time of percpu counter
+         objects and validate the percpu counter operations.
+
 config DEBUG_OBJECTS_ENABLE_DEFAULT
        int "debug_objects bootup default value (0-1)"
         range 0 1
@@ -366,7 +374,7 @@ config SLUB_STATS
 config DEBUG_KMEMLEAK
        bool "Kernel memory leak detector"
        depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
-               (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE)
+               (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
 
        select DEBUG_FS if SYSFS
        select STACKTRACE if STACKTRACE_SUPPORT
@@ -740,6 +748,15 @@ config DEBUG_LIST
 
          If unsure, say N.
 
+config TEST_LIST_SORT
+       bool "Linked list sorting test"
+       depends on DEBUG_KERNEL
+       help
+         Enable this to turn on 'list_sort()' function test. This test is
+         executed only once during system boot, so affects only boot time.
+
+         If unsure, say N.
+
 config DEBUG_SG
        bool "Debug SG table operations"
        depends on DEBUG_KERNEL
index ffb78c916ccdf85ffb0d8ec7d0f3f1e4f41ab3ef..741fae905ae3ba8d81c0a4cbe9564cdd4e0d4ce7 100644 (file)
@@ -359,7 +359,6 @@ EXPORT_SYMBOL(bitmap_find_next_zero_area);
 
 #define CHUNKSZ                                32
 #define nbits_to_hold_value(val)       fls(val)
-#define unhex(c)                       (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
 #define BASEDEC 10             /* fancier cpuset lists input in decimal */
 
 /**
@@ -466,7 +465,7 @@ int __bitmap_parse(const char *buf, unsigned int buflen,
                        if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
                                return -EOVERFLOW;
 
-                       chunk = (chunk << 4) | unhex(c);
+                       chunk = (chunk << 4) | hex_to_bin(c);
                        ndigits++; totaldigits++;
                }
                if (ndigits == 0)
index a111eb8de9cfeefb2bc82011ef580f970091bfcd..5b4919191778bb4f2224e798037f23e9dd5ea2ad 100644 (file)
@@ -77,26 +77,58 @@ s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
 EXPORT_SYMBOL(div_s64_rem);
 #endif
 
-/* 64bit divisor, dividend and result. dynamic precision */
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ *
+ * This implementation is a modified version of the algorithm proposed
+ * by the book 'Hacker's Delight'.  The original source and full proof
+ * can be found here and is available for use without restriction.
+ *
+ * 'http://www.hackersdelight.org/HDcode/newCode/divDouble.c'
+ */
 #ifndef div64_u64
 u64 div64_u64(u64 dividend, u64 divisor)
 {
-       u32 high, d;
+       u32 high = divisor >> 32;
+       u64 quot;
 
-       high = divisor >> 32;
-       if (high) {
-               unsigned int shift = fls(high);
+       if (high == 0) {
+               quot = div_u64(dividend, divisor);
+       } else {
+               int n = 1 + fls(high);
+               quot = div_u64(dividend >> n, divisor >> n);
 
-               d = divisor >> shift;
-               dividend >>= shift;
-       } else
-               d = divisor;
+               if (quot != 0)
+                       quot--;
+               if ((dividend - quot * divisor) >= divisor)
+                       quot++;
+       }
 
-       return div_u64(dividend, d);
+       return quot;
 }
 EXPORT_SYMBOL(div64_u64);
 #endif
 
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ */
+#ifndef div64_s64
+s64 div64_s64(s64 dividend, s64 divisor)
+{
+       s64 quot, t;
+
+       quot = div64_u64(abs64(dividend), abs64(divisor));
+       t = (dividend ^ divisor) >> 63;
+
+       return (quot ^ t) - t;
+}
+EXPORT_SYMBOL(div64_s64);
+#endif
+
 #endif /* BITS_PER_LONG == 32 */
 
 /*
index 5e0966be0f7ceead8beee37f0ed5da7b0c63c775..e15502e8b21e5bbb47addef5c8fea61b57118508 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -106,16 +106,17 @@ static void idr_mark_full(struct idr_layer **pa, int id)
 }
 
 /**
- * idr_pre_get - reserver resources for idr allocation
+ * idr_pre_get - reserve resources for idr allocation
  * @idp:       idr handle
  * @gfp_mask:  memory allocation flags
  *
- * This function should be called prior to locking and calling the
- * idr_get_new* functions. It preallocates enough memory to satisfy
- * the worst possible allocation.
+ * This function should be called prior to calling the idr_get_new* functions.
+ * It preallocates enough memory to satisfy the worst possible allocation. The
+ * caller should pass in GFP_KERNEL if possible.  This of course requires that
+ * no spinning locks be held.
  *
- * If the system is REALLY out of memory this function returns 0,
- * otherwise 1.
+ * If the system is REALLY out of memory this function returns %0,
+ * otherwise %1.
  */
 int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
 {
@@ -290,11 +291,13 @@ static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
  * This is the allocate id function.  It should be called with any
  * required locks.
  *
- * If memory is required, it will return -EAGAIN, you should unlock
- * and go back to the idr_pre_get() call.  If the idr is full, it will
- * return -ENOSPC.
+ * If allocation from IDR's private freelist fails, idr_get_new_above() will
+ * return %-EAGAIN.  The caller should retry the idr_pre_get() call to refill
+ * IDR's preallocation and then retry the idr_get_new_above() call.
  *
- * @id returns a value in the range @starting_id ... 0x7fffffff
+ * If the idr is full idr_get_new_above() will return %-ENOSPC.
+ *
+ * @id returns a value in the range @starting_id ... %0x7fffffff
  */
 int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
 {
@@ -318,14 +321,13 @@ EXPORT_SYMBOL(idr_get_new_above);
  * @ptr: pointer you want associated with the id
  * @id: pointer to the allocated handle
  *
- * This is the allocate id function.  It should be called with any
- * required locks.
+ * If allocation from IDR's private freelist fails, idr_get_new_above() will
+ * return %-EAGAIN.  The caller should retry the idr_pre_get() call to refill
+ * IDR's preallocation and then retry the idr_get_new_above() call.
  *
- * If memory is required, it will return -EAGAIN, you should unlock
- * and go back to the idr_pre_get() call.  If the idr is full, it will
- * return -ENOSPC.
+ * If the idr is full idr_get_new_above() will return %-ENOSPC.
  *
- * @id returns a value in the range 0 ... 0x7fffffff
+ * @id returns a value in the range %0 ... %0x7fffffff
  */
 int idr_get_new(struct idr *idp, void *ptr, int *id)
 {
@@ -388,7 +390,7 @@ static void sub_remove(struct idr *idp, int shift, int id)
 }
 
 /**
- * idr_remove - remove the given id and free it's slot
+ * idr_remove - remove the given id and free its slot
  * @idp: idr handle
  * @id: unique key
  */
@@ -437,7 +439,7 @@ EXPORT_SYMBOL(idr_remove);
  * function will remove all id mappings and leave all idp_layers
  * unused.
  *
- * A typical clean-up sequence for objects stored in an idr tree, will
+ * A typical clean-up sequence for objects stored in an idr tree will
  * use idr_for_each() to free all objects, if necessay, then
  * idr_remove_all() to remove all ids, and idr_destroy() to free
  * up the cached idr_layers.
@@ -542,7 +544,7 @@ EXPORT_SYMBOL(idr_find);
  * not allowed.
  *
  * We check the return of @fn each time. If it returns anything other
- * than 0, we break out and return that value.
+ * than %0, we break out and return that value.
  *
  * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove().
  */
@@ -637,8 +639,8 @@ EXPORT_SYMBOL(idr_get_next);
  * @id: lookup key
  *
  * Replace the pointer registered with an id and return the old value.
- * A -ENOENT return indicates that @id was not found.
- * A -EINVAL return indicates that @id was not within valid constraints.
+ * A %-ENOENT return indicates that @id was not found.
+ * A %-EINVAL return indicates that @id was not within valid constraints.
  *
  * The caller must serialize with writers.
  */
@@ -696,10 +698,11 @@ void idr_init(struct idr *idp)
 EXPORT_SYMBOL(idr_init);
 
 
-/*
+/**
+ * DOC: IDA description
  * IDA - IDR based ID allocator
  *
- * this is id allocator without id -> pointer translation.  Memory
+ * This is id allocator without id -> pointer translation.  Memory
  * usage is much lower than full blown idr because each id only
  * occupies a bit.  ida uses a custom leaf node which contains
  * IDA_BITMAP_BITS slots.
@@ -732,8 +735,8 @@ static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap)
  * following function.  It preallocates enough memory to satisfy the
  * worst possible allocation.
  *
- * If the system is REALLY out of memory this function returns 0,
- * otherwise 1.
+ * If the system is REALLY out of memory this function returns %0,
+ * otherwise %1.
  */
 int ida_pre_get(struct ida *ida, gfp_t gfp_mask)
 {
@@ -765,11 +768,11 @@ EXPORT_SYMBOL(ida_pre_get);
  * Allocate new ID above or equal to @ida.  It should be called with
  * any required locks.
  *
- * If memory is required, it will return -EAGAIN, you should unlock
+ * If memory is required, it will return %-EAGAIN, you should unlock
  * and go back to the ida_pre_get() call.  If the ida is full, it will
- * return -ENOSPC.
+ * return %-ENOSPC.
  *
- * @p_id returns a value in the range @starting_id ... 0x7fffffff.
+ * @p_id returns a value in the range @starting_id ... %0x7fffffff.
  */
 int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
 {
@@ -851,11 +854,11 @@ EXPORT_SYMBOL(ida_get_new_above);
  *
  * Allocate new ID.  It should be called with any required locks.
  *
- * If memory is required, it will return -EAGAIN, you should unlock
+ * If memory is required, it will return %-EAGAIN, you should unlock
  * and go back to the idr_pre_get() call.  If the idr is full, it will
- * return -ENOSPC.
+ * return %-ENOSPC.
  *
- * @id returns a value in the range 0 ... 0x7fffffff.
+ * @id returns a value in the range %0 ... %0x7fffffff.
  */
 int ida_get_new(struct ida *ida, int *p_id)
 {
index a7616fa3162e844f5b3c7090c1911543c826147e..d7325c6b103f0be078ff3672c35c468ed35738f1 100644 (file)
@@ -141,77 +141,151 @@ void list_sort(void *priv, struct list_head *head,
 }
 EXPORT_SYMBOL(list_sort);
 
-#ifdef DEBUG_LIST_SORT
+#ifdef CONFIG_TEST_LIST_SORT
+
+#include <linux/random.h>
+
+/*
+ * The pattern of set bits in the list length determines which cases
+ * are hit in list_sort().
+ */
+#define TEST_LIST_LEN (512+128+2) /* not including head */
+
+#define TEST_POISON1 0xDEADBEEF
+#define TEST_POISON2 0xA324354C
+
 struct debug_el {
-       struct list_head l_h;
+       unsigned int poison1;
+       struct list_head list;
+       unsigned int poison2;
        int value;
        unsigned serial;
 };
 
-static int cmp(void *priv, struct list_head *a, struct list_head *b)
+/* Array, containing pointers to all elements in the test list */
+static struct debug_el **elts __initdata;
+
+static int __init check(struct debug_el *ela, struct debug_el *elb)
 {
-       return container_of(a, struct debug_el, l_h)->value
-            - container_of(b, struct debug_el, l_h)->value;
+       if (ela->serial >= TEST_LIST_LEN) {
+               printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
+                               ela->serial);
+               return -EINVAL;
+       }
+       if (elb->serial >= TEST_LIST_LEN) {
+               printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
+                               elb->serial);
+               return -EINVAL;
+       }
+       if (elts[ela->serial] != ela || elts[elb->serial] != elb) {
+               printk(KERN_ERR "list_sort_test: error: phantom element\n");
+               return -EINVAL;
+       }
+       if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) {
+               printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
+                               ela->poison1, ela->poison2);
+               return -EINVAL;
+       }
+       if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) {
+               printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
+                               elb->poison1, elb->poison2);
+               return -EINVAL;
+       }
+       return 0;
 }
 
-/*
- * The pattern of set bits in the list length determines which cases
- * are hit in list_sort().
- */
-#define LIST_SORT_TEST_LENGTH (512+128+2) /* not including head */
+static int __init cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+       struct debug_el *ela, *elb;
+
+       ela = container_of(a, struct debug_el, list);
+       elb = container_of(b, struct debug_el, list);
+
+       check(ela, elb);
+       return ela->value - elb->value;
+}
 
 static int __init list_sort_test(void)
 {
-       int i, r = 1, count;
-       struct list_head *head = kmalloc(sizeof(*head), GFP_KERNEL);
-       struct list_head *cur;
+       int i, count = 1, err = -EINVAL;
+       struct debug_el *el;
+       struct list_head *cur, *tmp;
+       LIST_HEAD(head);
+
+       printk(KERN_DEBUG "list_sort_test: start testing list_sort()\n");
 
-       printk(KERN_WARNING "testing list_sort()\n");
+       elts = kmalloc(sizeof(void *) * TEST_LIST_LEN, GFP_KERNEL);
+       if (!elts) {
+               printk(KERN_ERR "list_sort_test: error: cannot allocate "
+                               "memory\n");
+               goto exit;
+       }
 
-       cur = head;
-       for (i = 0; i < LIST_SORT_TEST_LENGTH; i++) {
-               struct debug_el *el = kmalloc(sizeof(*el), GFP_KERNEL);
-               BUG_ON(!el);
+       for (i = 0; i < TEST_LIST_LEN; i++) {
+               el = kmalloc(sizeof(*el), GFP_KERNEL);
+               if (!el) {
+                       printk(KERN_ERR "list_sort_test: error: cannot "
+                                       "allocate memory\n");
+                       goto exit;
+               }
                 /* force some equivalencies */
-               el->value = (r = (r * 725861) % 6599) % (LIST_SORT_TEST_LENGTH/3);
+               el->value = random32() % (TEST_LIST_LEN/3);
                el->serial = i;
-
-               el->l_h.prev = cur;
-               cur->next = &el->l_h;
-               cur = cur->next;
+               el->poison1 = TEST_POISON1;
+               el->poison2 = TEST_POISON2;
+               elts[i] = el;
+               list_add_tail(&el->list, &head);
        }
-       head->prev = cur;
 
-       list_sort(NULL, head, cmp);
+       list_sort(NULL, &head, cmp);
+
+       for (cur = head.next; cur->next != &head; cur = cur->next) {
+               struct debug_el *el1;
+               int cmp_result;
 
-       count = 1;
-       for (cur = head->next; cur->next != head; cur = cur->next) {
-               struct debug_el *el = container_of(cur, struct debug_el, l_h);
-               int cmp_result = cmp(NULL, cur, cur->next);
                if (cur->next->prev != cur) {
-                       printk(KERN_EMERG "list_sort() returned "
-                                               "a corrupted list!\n");
-                       return 1;
-               } else if (cmp_result > 0) {
-                       printk(KERN_EMERG "list_sort() failed to sort!\n");
-                       return 1;
-               } else if (cmp_result == 0 &&
-                               el->serial >= container_of(cur->next,
-                                       struct debug_el, l_h)->serial) {
-                       printk(KERN_EMERG "list_sort() failed to preserve order"
-                                                " of equivalent elements!\n");
-                       return 1;
+                       printk(KERN_ERR "list_sort_test: error: list is "
+                                       "corrupted\n");
+                       goto exit;
+               }
+
+               cmp_result = cmp(NULL, cur, cur->next);
+               if (cmp_result > 0) {
+                       printk(KERN_ERR "list_sort_test: error: list is not "
+                                       "sorted\n");
+                       goto exit;
+               }
+
+               el = container_of(cur, struct debug_el, list);
+               el1 = container_of(cur->next, struct debug_el, list);
+               if (cmp_result == 0 && el->serial >= el1->serial) {
+                       printk(KERN_ERR "list_sort_test: error: order of "
+                                       "equivalent elements not preserved\n");
+                       goto exit;
+               }
+
+               if (check(el, el1)) {
+                       printk(KERN_ERR "list_sort_test: error: element check "
+                                       "failed\n");
+                       goto exit;
                }
-               kfree(cur->prev);
                count++;
        }
-       kfree(cur);
-       if (count != LIST_SORT_TEST_LENGTH) {
-               printk(KERN_EMERG "list_sort() returned list of"
-                                               "different length!\n");
-               return 1;
+
+       if (count != TEST_LIST_LEN) {
+               printk(KERN_ERR "list_sort_test: error: bad list length %d",
+                               count);
+               goto exit;
        }
-       return 0;
+
+       err = 0;
+exit:
+       kfree(elts);
+       list_for_each_safe(cur, tmp, &head) {
+               list_del(cur);
+               kfree(container_of(cur, struct debug_el, list));
+       }
+       return err;
 }
 module_init(list_sort_test);
-#endif
+#endif /* CONFIG_TEST_LIST_SORT */
index fb34977246bb052923d5fad6341c2ba80315fdfe..6e89eca5cca00b6fb059bae5135b0ee381a5d5d5 100644 (file)
@@ -128,12 +128,13 @@ static int match_number(substring_t *s, int *result, int base)
        char *endp;
        char *buf;
        int ret;
+       size_t len = s->to - s->from;
 
-       buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+       buf = kmalloc(len + 1, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
-       memcpy(buf, s->from, s->to - s->from);
-       buf[s->to - s->from] = '\0';
+       memcpy(buf, s->from, len);
+       buf[len] = '\0';
        *result = simple_strtol(buf, &endp, base);
        ret = 0;
        if (endp == buf)
index ec9048e74f448ce3a79522aef9ac5f4c4b350737..604678d7d06d9b101feafb31da72654d5f618500 100644 (file)
@@ -8,10 +8,53 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
+#include <linux/debugobjects.h>
 
 static LIST_HEAD(percpu_counters);
 static DEFINE_MUTEX(percpu_counters_lock);
 
+#ifdef CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER
+
+static struct debug_obj_descr percpu_counter_debug_descr;
+
+static int percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
+{
+       struct percpu_counter *fbc = addr;
+
+       switch (state) {
+       case ODEBUG_STATE_ACTIVE:
+               percpu_counter_destroy(fbc);
+               debug_object_free(fbc, &percpu_counter_debug_descr);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static struct debug_obj_descr percpu_counter_debug_descr = {
+       .name           = "percpu_counter",
+       .fixup_free     = percpu_counter_fixup_free,
+};
+
+static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
+{
+       debug_object_init(fbc, &percpu_counter_debug_descr);
+       debug_object_activate(fbc, &percpu_counter_debug_descr);
+}
+
+static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
+{
+       debug_object_deactivate(fbc, &percpu_counter_debug_descr);
+       debug_object_free(fbc, &percpu_counter_debug_descr);
+}
+
+#else  /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
+static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
+{ }
+static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
+{ }
+#endif /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
+
 void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
 {
        int cpu;
@@ -30,9 +73,9 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
 {
        s64 count;
        s32 *pcount;
-       int cpu = get_cpu();
 
-       pcount = per_cpu_ptr(fbc->counters, cpu);
+       preempt_disable();
+       pcount = this_cpu_ptr(fbc->counters);
        count = *pcount + amount;
        if (count >= batch || count <= -batch) {
                spin_lock(&fbc->lock);
@@ -42,7 +85,7 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
        } else {
                *pcount = count;
        }
-       put_cpu();
+       preempt_enable();
 }
 EXPORT_SYMBOL(__percpu_counter_add);
 
@@ -75,7 +118,11 @@ int __percpu_counter_init(struct percpu_counter *fbc, s64 amount,
        fbc->counters = alloc_percpu(s32);
        if (!fbc->counters)
                return -ENOMEM;
+
+       debug_percpu_counter_activate(fbc);
+
 #ifdef CONFIG_HOTPLUG_CPU
+       INIT_LIST_HEAD(&fbc->list);
        mutex_lock(&percpu_counters_lock);
        list_add(&fbc->list, &percpu_counters);
        mutex_unlock(&percpu_counters_lock);
@@ -89,6 +136,8 @@ void percpu_counter_destroy(struct percpu_counter *fbc)
        if (!fbc->counters)
                return;
 
+       debug_percpu_counter_deactivate(fbc);
+
 #ifdef CONFIG_HOTPLUG_CPU
        mutex_lock(&percpu_counters_lock);
        list_del(&fbc->list);
index 7af9d841c43beea318540340739ac3432b87ed12..c150d3dafff4a4152f085ff1ae33ae0f122f25f6 100644 (file)
@@ -988,8 +988,15 @@ static noinline_for_stack
 char *pointer(const char *fmt, char *buf, char *end, void *ptr,
              struct printf_spec spec)
 {
-       if (!ptr)
+       if (!ptr) {
+               /*
+                * Print (null) with the same width as a pointer so it makes
+                * tabular output look nice.
+                */
+               if (spec.field_width == -1)
+                       spec.field_width = 2 * sizeof(void *);
                return string(buf, end, "(null)", spec);
+       }
 
        switch (*fmt) {
        case 'F':
@@ -1031,7 +1038,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
-               spec.field_width = 2*sizeof(void *);
+               spec.field_width = 2 * sizeof(void *);
                spec.flags |= ZEROPAD;
        }
        spec.base = 16;
@@ -1497,7 +1504,7 @@ EXPORT_SYMBOL(snprintf);
  * @...: Arguments for the format string
  *
  * The return value is the number of characters written into @buf not including
- * the trailing '\0'. If @size is <= 0 the function returns 0.
+ * the trailing '\0'. If @size is == 0 the function returns 0.
  */
 
 int scnprintf(char *buf, size_t size, const char *fmt, ...)
@@ -1509,7 +1516,11 @@ int scnprintf(char *buf, size_t size, const char *fmt, ...)
        i = vsnprintf(buf, size, fmt, args);
        va_end(args);
 
-       return (i >= size) ? (size - 1) : i;
+       if (likely(i < size))
+               return i;
+       if (size != 0)
+               return size - 1;
+       return 0;
 }
 EXPORT_SYMBOL(scnprintf);
 
index 65d420499a615bf68a3be8313c3b0d8b1b330178..027100d30227fead0a4010d1feb0e2791a98fcaa 100644 (file)
@@ -74,11 +74,11 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
 
        nr_wb = nr_dirty = nr_io = nr_more_io = 0;
        spin_lock(&inode_lock);
-       list_for_each_entry(inode, &wb->b_dirty, i_list)
+       list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
                nr_dirty++;
-       list_for_each_entry(inode, &wb->b_io, i_list)
+       list_for_each_entry(inode, &wb->b_io, i_wb_list)
                nr_io++;
-       list_for_each_entry(inode, &wb->b_more_io, i_list)
+       list_for_each_entry(inode, &wb->b_more_io, i_wb_list)
                nr_more_io++;
        spin_unlock(&inode_lock);
 
@@ -362,7 +362,7 @@ static int bdi_forker_thread(void *ptr)
 {
        struct bdi_writeback *me = ptr;
 
-       current->flags |= PF_FLUSHER | PF_SWAPWRITE;
+       current->flags |= PF_SWAPWRITE;
        set_freezable();
 
        /*
@@ -729,6 +729,7 @@ static wait_queue_head_t congestion_wqh[2] = {
                __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
                __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
        };
+static atomic_t nr_bdi_congested[2];
 
 void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
 {
@@ -736,7 +737,8 @@ void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
        wait_queue_head_t *wqh = &congestion_wqh[sync];
 
        bit = sync ? BDI_sync_congested : BDI_async_congested;
-       clear_bit(bit, &bdi->state);
+       if (test_and_clear_bit(bit, &bdi->state))
+               atomic_dec(&nr_bdi_congested[sync]);
        smp_mb__after_clear_bit();
        if (waitqueue_active(wqh))
                wake_up(wqh);
@@ -748,7 +750,8 @@ void set_bdi_congested(struct backing_dev_info *bdi, int sync)
        enum bdi_state bit;
 
        bit = sync ? BDI_sync_congested : BDI_async_congested;
-       set_bit(bit, &bdi->state);
+       if (!test_and_set_bit(bit, &bdi->state))
+               atomic_inc(&nr_bdi_congested[sync]);
 }
 EXPORT_SYMBOL(set_bdi_congested);
 
@@ -764,13 +767,72 @@ EXPORT_SYMBOL(set_bdi_congested);
 long congestion_wait(int sync, long timeout)
 {
        long ret;
+       unsigned long start = jiffies;
        DEFINE_WAIT(wait);
        wait_queue_head_t *wqh = &congestion_wqh[sync];
 
        prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
        ret = io_schedule_timeout(timeout);
        finish_wait(wqh, &wait);
+
+       trace_writeback_congestion_wait(jiffies_to_usecs(timeout),
+                                       jiffies_to_usecs(jiffies - start));
+
        return ret;
 }
 EXPORT_SYMBOL(congestion_wait);
 
+/**
+ * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a zone to complete writes
+ * @zone: A zone to check if it is heavily congested
+ * @sync: SYNC or ASYNC IO
+ * @timeout: timeout in jiffies
+ *
+ * In the event of a congested backing_dev (any backing_dev) and the given
+ * @zone has experienced recent congestion, this waits for up to @timeout
+ * jiffies for either a BDI to exit congestion of the given @sync queue
+ * or a write to complete.
+ *
+ * In the absense of zone congestion, cond_resched() is called to yield
+ * the processor if necessary but otherwise does not sleep.
+ *
+ * The return value is 0 if the sleep is for the full timeout. Otherwise,
+ * it is the number of jiffies that were still remaining when the function
+ * returned. return_value == timeout implies the function did not sleep.
+ */
+long wait_iff_congested(struct zone *zone, int sync, long timeout)
+{
+       long ret;
+       unsigned long start = jiffies;
+       DEFINE_WAIT(wait);
+       wait_queue_head_t *wqh = &congestion_wqh[sync];
+
+       /*
+        * If there is no congestion, or heavy congestion is not being
+        * encountered in the current zone, yield if necessary instead
+        * of sleeping on the congestion queue
+        */
+       if (atomic_read(&nr_bdi_congested[sync]) == 0 ||
+                       !zone_is_reclaim_congested(zone)) {
+               cond_resched();
+
+               /* In case we scheduled, work out time remaining */
+               ret = timeout - (jiffies - start);
+               if (ret < 0)
+                       ret = 0;
+
+               goto out;
+       }
+
+       /* Sleep until uncongested or a write happens */
+       prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
+       ret = io_schedule_timeout(timeout);
+       finish_wait(wqh, &wait);
+
+out:
+       trace_writeback_wait_iff_congested(jiffies_to_usecs(timeout),
+                                       jiffies_to_usecs(jiffies - start));
+
+       return ret;
+}
+EXPORT_SYMBOL(wait_iff_congested);
index 3df063706f53e6d579ec0acabace3503a471ba29..4df2de77e06956cf68551192d4aa14578bd6ca44 100644 (file)
@@ -311,6 +311,8 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
        size_t offset;
        void *retval;
 
+       might_sleep_if(mem_flags & __GFP_WAIT);
+
        spin_lock_irqsave(&pool->lock, flags);
  restart:
        list_for_each_entry(page, &pool->page_list, page_list) {
index 3d4df44e4221d25bb041995813823e00903161e5..75572b5f23746a4b47a42920980a22e6a5251fe7 100644 (file)
@@ -612,6 +612,19 @@ void __lock_page_nosync(struct page *page)
                                                        TASK_UNINTERRUPTIBLE);
 }
 
+int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
+                        unsigned int flags)
+{
+       if (!(flags & FAULT_FLAG_ALLOW_RETRY)) {
+               __lock_page(page);
+               return 1;
+       } else {
+               up_read(&mm->mmap_sem);
+               wait_on_page_locked(page);
+               return 0;
+       }
+}
+
 /**
  * find_get_page - find and get a page reference
  * @mapping: the address_space to search
@@ -1539,25 +1552,28 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 * waiting for the lock.
                 */
                do_async_mmap_readahead(vma, ra, file, page, offset);
-               lock_page(page);
-
-               /* Did it get truncated? */
-               if (unlikely(page->mapping != mapping)) {
-                       unlock_page(page);
-                       put_page(page);
-                       goto no_cached_page;
-               }
        } else {
                /* No page in the page cache at all */
                do_sync_mmap_readahead(vma, ra, file, offset);
                count_vm_event(PGMAJFAULT);
                ret = VM_FAULT_MAJOR;
 retry_find:
-               page = find_lock_page(mapping, offset);
+               page = find_get_page(mapping, offset);
                if (!page)
                        goto no_cached_page;
        }
 
+       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags))
+               return ret | VM_FAULT_RETRY;
+
+       /* Did it get truncated? */
+       if (unlikely(page->mapping != mapping)) {
+               unlock_page(page);
+               put_page(page);
+               goto retry_find;
+       }
+       VM_BUG_ON(page->index != offset);
+
        /*
         * We have a locked page in the page cache, now we need to check
         * that it's up-to-date. If not, it is going to be due to an error.
@@ -2177,12 +2193,12 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
        }
 
        if (written > 0) {
-               loff_t end = pos + written;
-               if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
-                       i_size_write(inode,  end);
+               pos += written;
+               if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
+                       i_size_write(inode, pos);
                        mark_inode_dirty(inode);
                }
-               *ppos = end;
+               *ppos = pos;
        }
 out:
        return written;
index 7a0aa1be4993521f7d55da731b3f69f8a59ea7c7..781e754a75ac973b15921a7c38c9e62f7a8bad66 100644 (file)
 unsigned long totalhigh_pages __read_mostly;
 EXPORT_SYMBOL(totalhigh_pages);
 
+
+DEFINE_PER_CPU(int, __kmap_atomic_idx);
+EXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx);
+
 unsigned int nr_free_highpages (void)
 {
        pg_data_t *pgdat;
@@ -422,61 +426,3 @@ void __init page_address_init(void)
 }
 
 #endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
-
-#ifdef CONFIG_DEBUG_HIGHMEM
-
-void debug_kmap_atomic(enum km_type type)
-{
-       static int warn_count = 10;
-
-       if (unlikely(warn_count < 0))
-               return;
-
-       if (unlikely(in_interrupt())) {
-               if (in_nmi()) {
-                       if (type != KM_NMI && type != KM_NMI_PTE) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               } else if (in_irq()) {
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
-                           type != KM_BOUNCE_READ && type != KM_IRQ_PTE) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               } else if (!irqs_disabled()) {  /* softirq */
-                       if (type != KM_IRQ0 && type != KM_IRQ1 &&
-                           type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
-                           type != KM_SKB_SUNRPC_DATA &&
-                           type != KM_SKB_DATA_SOFTIRQ &&
-                           type != KM_BOUNCE_READ) {
-                               WARN_ON(1);
-                               warn_count--;
-                       }
-               }
-       }
-
-       if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
-                       type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ ||
-                       type == KM_IRQ_PTE || type == KM_NMI ||
-                       type == KM_NMI_PTE ) {
-               if (!irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
-               if (irq_count() == 0 && !irqs_disabled()) {
-                       WARN_ON(1);
-                       warn_count--;
-               }
-       }
-#ifdef CONFIG_KGDB_KDB
-       if (unlikely(type == KM_KDB && atomic_read(&kgdb_active) == -1)) {
-               WARN_ON(1);
-               warn_count--;
-       }
-#endif /* CONFIG_KGDB_KDB */
-}
-
-#endif
index c03273807182dde1d9dd2e905c0db11a6dfe2441..c4a3558589ab15de3ac9abb135ee499d17544142 100644 (file)
@@ -423,14 +423,14 @@ static void clear_huge_page(struct page *page,
        }
 }
 
-static void copy_gigantic_page(struct page *dst, struct page *src,
+static void copy_user_gigantic_page(struct page *dst, struct page *src,
                           unsigned long addr, struct vm_area_struct *vma)
 {
        int i;
        struct hstate *h = hstate_vma(vma);
        struct page *dst_base = dst;
        struct page *src_base = src;
-       might_sleep();
+
        for (i = 0; i < pages_per_huge_page(h); ) {
                cond_resched();
                copy_user_highpage(dst, src, addr + i*PAGE_SIZE, vma);
@@ -440,14 +440,15 @@ static void copy_gigantic_page(struct page *dst, struct page *src,
                src = mem_map_next(src, src_base, i);
        }
 }
-static void copy_huge_page(struct page *dst, struct page *src,
+
+static void copy_user_huge_page(struct page *dst, struct page *src,
                           unsigned long addr, struct vm_area_struct *vma)
 {
        int i;
        struct hstate *h = hstate_vma(vma);
 
        if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
-               copy_gigantic_page(dst, src, addr, vma);
+               copy_user_gigantic_page(dst, src, addr, vma);
                return;
        }
 
@@ -458,6 +459,40 @@ static void copy_huge_page(struct page *dst, struct page *src,
        }
 }
 
+static void copy_gigantic_page(struct page *dst, struct page *src)
+{
+       int i;
+       struct hstate *h = page_hstate(src);
+       struct page *dst_base = dst;
+       struct page *src_base = src;
+
+       for (i = 0; i < pages_per_huge_page(h); ) {
+               cond_resched();
+               copy_highpage(dst, src);
+
+               i++;
+               dst = mem_map_next(dst, dst_base, i);
+               src = mem_map_next(src, src_base, i);
+       }
+}
+
+void copy_huge_page(struct page *dst, struct page *src)
+{
+       int i;
+       struct hstate *h = page_hstate(src);
+
+       if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
+               copy_gigantic_page(dst, src);
+               return;
+       }
+
+       might_sleep();
+       for (i = 0; i < pages_per_huge_page(h); i++) {
+               cond_resched();
+               copy_highpage(dst + i, src + i);
+       }
+}
+
 static void enqueue_huge_page(struct hstate *h, struct page *page)
 {
        int nid = page_to_nid(page);
@@ -466,11 +501,24 @@ static void enqueue_huge_page(struct hstate *h, struct page *page)
        h->free_huge_pages_node[nid]++;
 }
 
+static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
+{
+       struct page *page;
+
+       if (list_empty(&h->hugepage_freelists[nid]))
+               return NULL;
+       page = list_entry(h->hugepage_freelists[nid].next, struct page, lru);
+       list_del(&page->lru);
+       set_page_refcounted(page);
+       h->free_huge_pages--;
+       h->free_huge_pages_node[nid]--;
+       return page;
+}
+
 static struct page *dequeue_huge_page_vma(struct hstate *h,
                                struct vm_area_struct *vma,
                                unsigned long address, int avoid_reserve)
 {
-       int nid;
        struct page *page = NULL;
        struct mempolicy *mpol;
        nodemask_t *nodemask;
@@ -496,19 +544,13 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                                MAX_NR_ZONES - 1, nodemask) {
-               nid = zone_to_nid(zone);
-               if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask) &&
-                   !list_empty(&h->hugepage_freelists[nid])) {
-                       page = list_entry(h->hugepage_freelists[nid].next,
-                                         struct page, lru);
-                       list_del(&page->lru);
-                       h->free_huge_pages--;
-                       h->free_huge_pages_node[nid]--;
-
-                       if (!avoid_reserve)
-                               decrement_hugepage_resv_vma(h, vma);
-
-                       break;
+               if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask)) {
+                       page = dequeue_huge_page_node(h, zone_to_nid(zone));
+                       if (page) {
+                               if (!avoid_reserve)
+                                       decrement_hugepage_resv_vma(h, vma);
+                               break;
+                       }
                }
        }
 err:
@@ -770,11 +812,10 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
        return ret;
 }
 
-static struct page *alloc_buddy_huge_page(struct hstate *h,
-                       struct vm_area_struct *vma, unsigned long address)
+static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
 {
        struct page *page;
-       unsigned int nid;
+       unsigned int r_nid;
 
        if (h->order >= MAX_ORDER)
                return NULL;
@@ -812,9 +853,14 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
        }
        spin_unlock(&hugetlb_lock);
 
-       page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
-                                       __GFP_REPEAT|__GFP_NOWARN,
-                                       huge_page_order(h));
+       if (nid == NUMA_NO_NODE)
+               page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
+                                  __GFP_REPEAT|__GFP_NOWARN,
+                                  huge_page_order(h));
+       else
+               page = alloc_pages_exact_node(nid,
+                       htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
+                       __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h));
 
        if (page && arch_prepare_hugepage(page)) {
                __free_pages(page, huge_page_order(h));
@@ -823,19 +869,13 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
 
        spin_lock(&hugetlb_lock);
        if (page) {
-               /*
-                * This page is now managed by the hugetlb allocator and has
-                * no users -- drop the buddy allocator's reference.
-                */
-               put_page_testzero(page);
-               VM_BUG_ON(page_count(page));
-               nid = page_to_nid(page);
+               r_nid = page_to_nid(page);
                set_compound_page_dtor(page, free_huge_page);
                /*
                 * We incremented the global counters already
                 */
-               h->nr_huge_pages_node[nid]++;
-               h->surplus_huge_pages_node[nid]++;
+               h->nr_huge_pages_node[r_nid]++;
+               h->surplus_huge_pages_node[r_nid]++;
                __count_vm_event(HTLB_BUDDY_PGALLOC);
        } else {
                h->nr_huge_pages--;
@@ -847,6 +887,25 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
        return page;
 }
 
+/*
+ * This allocation function is useful in the context where vma is irrelevant.
+ * E.g. soft-offlining uses this function because it only cares physical
+ * address of error page.
+ */
+struct page *alloc_huge_page_node(struct hstate *h, int nid)
+{
+       struct page *page;
+
+       spin_lock(&hugetlb_lock);
+       page = dequeue_huge_page_node(h, nid);
+       spin_unlock(&hugetlb_lock);
+
+       if (!page)
+               page = alloc_buddy_huge_page(h, nid);
+
+       return page;
+}
+
 /*
  * Increase the hugetlb pool such that it can accomodate a reservation
  * of size 'delta'.
@@ -871,17 +930,14 @@ static int gather_surplus_pages(struct hstate *h, int delta)
 retry:
        spin_unlock(&hugetlb_lock);
        for (i = 0; i < needed; i++) {
-               page = alloc_buddy_huge_page(h, NULL, 0);
-               if (!page) {
+               page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
+               if (!page)
                        /*
                         * We were not able to allocate enough pages to
                         * satisfy the entire reservation so we free what
                         * we've allocated so far.
                         */
-                       spin_lock(&hugetlb_lock);
-                       needed = 0;
                        goto free;
-               }
 
                list_add(&page->lru, &surplus_list);
        }
@@ -908,31 +964,31 @@ retry:
        needed += allocated;
        h->resv_huge_pages += delta;
        ret = 0;
-free:
+
+       spin_unlock(&hugetlb_lock);
        /* Free the needed pages to the hugetlb pool */
        list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
                if ((--needed) < 0)
                        break;
                list_del(&page->lru);
+               /*
+                * This page is now managed by the hugetlb allocator and has
+                * no users -- drop the buddy allocator's reference.
+                */
+               put_page_testzero(page);
+               VM_BUG_ON(page_count(page));
                enqueue_huge_page(h, page);
        }
 
        /* Free unnecessary surplus pages to the buddy allocator */
+free:
        if (!list_empty(&surplus_list)) {
-               spin_unlock(&hugetlb_lock);
                list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
                        list_del(&page->lru);
-                       /*
-                        * The page has a reference count of zero already, so
-                        * call free_huge_page directly instead of using
-                        * put_page.  This must be done with hugetlb_lock
-                        * unlocked which is safe because free_huge_page takes
-                        * hugetlb_lock before deciding how to free the page.
-                        */
-                       free_huge_page(page);
+                       put_page(page);
                }
-               spin_lock(&hugetlb_lock);
        }
+       spin_lock(&hugetlb_lock);
 
        return ret;
 }
@@ -1052,14 +1108,13 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        spin_unlock(&hugetlb_lock);
 
        if (!page) {
-               page = alloc_buddy_huge_page(h, vma, addr);
+               page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
                if (!page) {
                        hugetlb_put_quota(inode->i_mapping, chg);
                        return ERR_PTR(-VM_FAULT_SIGBUS);
                }
        }
 
-       set_page_refcounted(page);
        set_page_private(page, (unsigned long) mapping);
 
        vma_commit_reservation(h, vma, addr);
@@ -2153,6 +2208,19 @@ nomem:
        return -ENOMEM;
 }
 
+static int is_hugetlb_entry_migration(pte_t pte)
+{
+       swp_entry_t swp;
+
+       if (huge_pte_none(pte) || pte_present(pte))
+               return 0;
+       swp = pte_to_swp_entry(pte);
+       if (non_swap_entry(swp) && is_migration_entry(swp)) {
+               return 1;
+       } else
+               return 0;
+}
+
 static int is_hugetlb_entry_hwpoisoned(pte_t pte)
 {
        swp_entry_t swp;
@@ -2380,10 +2448,13 @@ retry_avoidcopy:
         * When the original hugepage is shared one, it does not have
         * anon_vma prepared.
         */
-       if (unlikely(anon_vma_prepare(vma)))
+       if (unlikely(anon_vma_prepare(vma))) {
+               /* Caller expects lock to be held */
+               spin_lock(&mm->page_table_lock);
                return VM_FAULT_OOM;
+       }
 
-       copy_huge_page(new_page, old_page, address, vma);
+       copy_user_huge_page(new_page, old_page, address, vma);
        __SetPageUptodate(new_page);
 
        /*
@@ -2515,21 +2586,19 @@ retry:
                        hugepage_add_new_anon_rmap(page, vma, address);
                }
        } else {
+               /*
+                * If memory error occurs between mmap() and fault, some process
+                * don't have hwpoisoned swap entry for errored virtual address.
+                * So we need to block hugepage fault by PG_hwpoison bit check.
+                */
+               if (unlikely(PageHWPoison(page))) {
+                       ret = VM_FAULT_HWPOISON | 
+                             VM_FAULT_SET_HINDEX(h - hstates);
+                       goto backout_unlocked;
+               }
                page_dup_rmap(page);
        }
 
-       /*
-        * Since memory error handler replaces pte into hwpoison swap entry
-        * at the time of error handling, a process which reserved but not have
-        * the mapping to the error hugepage does not have hwpoison swap entry.
-        * So we need to block accesses from such a process by checking
-        * PG_hwpoison bit here.
-        */
-       if (unlikely(PageHWPoison(page))) {
-               ret = VM_FAULT_HWPOISON;
-               goto backout_unlocked;
-       }
-
        /*
         * If we are going to COW a private mapping later, we examine the
         * pending reservations for this page now. This will ensure that
@@ -2587,8 +2656,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        ptep = huge_pte_offset(mm, address);
        if (ptep) {
                entry = huge_ptep_get(ptep);
-               if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
-                       return VM_FAULT_HWPOISON;
+               if (unlikely(is_hugetlb_entry_migration(entry))) {
+                       migration_entry_wait(mm, (pmd_t *)ptep, address);
+                       return 0;
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
+                       return VM_FAULT_HWPOISON_LARGE | 
+                              VM_FAULT_SET_HINDEX(h - hstates);
        }
 
        ptep = huge_pte_alloc(mm, address, huge_page_size(h));
@@ -2878,18 +2951,41 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
        hugetlb_acct_memory(h, -(chg - freed));
 }
 
+#ifdef CONFIG_MEMORY_FAILURE
+
+/* Should be called in hugetlb_lock */
+static int is_hugepage_on_freelist(struct page *hpage)
+{
+       struct page *page;
+       struct page *tmp;
+       struct hstate *h = page_hstate(hpage);
+       int nid = page_to_nid(hpage);
+
+       list_for_each_entry_safe(page, tmp, &h->hugepage_freelists[nid], lru)
+               if (page == hpage)
+                       return 1;
+       return 0;
+}
+
 /*
  * This function is called from memory failure code.
  * Assume the caller holds page lock of the head page.
  */
-void __isolate_hwpoisoned_huge_page(struct page *hpage)
+int dequeue_hwpoisoned_huge_page(struct page *hpage)
 {
        struct hstate *h = page_hstate(hpage);
        int nid = page_to_nid(hpage);
+       int ret = -EBUSY;
 
        spin_lock(&hugetlb_lock);
-       list_del(&hpage->lru);
-       h->free_huge_pages--;
-       h->free_huge_pages_node[nid]--;
+       if (is_hugepage_on_freelist(hpage)) {
+               list_del(&hpage->lru);
+               set_page_refcounted(hpage);
+               h->free_huge_pages--;
+               h->free_huge_pages_node[nid]--;
+               ret = 0;
+       }
        spin_unlock(&hugetlb_lock);
+       return ret;
 }
+#endif
index 6a697bb97fc589fcdd71ad56a61d43f88862786b..dedb0aff673fcf9f0bbeb71dfc3f82a7ecf068ce 100644 (file)
@@ -62,7 +62,7 @@ extern bool is_free_buddy_page(struct page *page);
  */
 static inline unsigned long page_order(struct page *page)
 {
-       VM_BUG_ON(!PageBuddy(page));
+       /* PageBuddy() must be checked by the caller */
        return page_private(page);
 }
 
index 757f6b0accfe84d959b7fe5899b5916ad0ed1f14..124324134ff67b3c4a0bc06661b4f70f2406840f 100644 (file)
@@ -7,21 +7,26 @@
  * Free Software Foundation.
  *
  * High level machine check handler. Handles pages reported by the
- * hardware as being corrupted usually due to a 2bit ECC memory or cache
+ * hardware as being corrupted usually due to a multi-bit ECC memory or cache
  * failure.
+ * 
+ * In addition there is a "soft offline" entry point that allows stop using
+ * not-yet-corrupted-by-suspicious pages without killing anything.
  *
  * Handles page cache pages in various states. The tricky part
- * here is that we can access any page asynchronous to other VM
- * users, because memory failures could happen anytime and anywhere,
- * possibly violating some of their assumptions. This is why this code
- * has to be extremely careful. Generally it tries to use normal locking
- * rules, as in get the standard locks, even if that means the
- * error handling takes potentially a long time.
- *
- * The operation to map back from RMAP chains to processes has to walk
- * the complete process list and has non linear complexity with the number
- * mappings. In short it can be quite slow. But since memory corruptions
- * are rare we hope to get away with this.
+ * here is that we can access any page asynchronously in respect to 
+ * other VM users, because memory failures could happen anytime and 
+ * anywhere. This could violate some of their assumptions. This is why 
+ * this code has to be extremely careful. Generally it tries to use 
+ * normal locking rules, as in get the standard locks, even if that means 
+ * the error handling takes potentially a long time.
+ * 
+ * There are several operations here with exponential complexity because
+ * of unsuitable VM data structures. For example the operation to map back 
+ * from RMAP chains to processes has to walk the complete process list and 
+ * has non linear complexity with the number. But since memory corruptions
+ * are rare we hope to get away with this. This avoids impacting the core 
+ * VM.
  */
 
 /*
@@ -30,7 +35,6 @@
  * - kcore/oldmem/vmcore/mem/kmem check for hwpoison pages
  * - pass bad pages to kdump next kernel
  */
-#define DEBUG 1                /* remove me in 2.6.34 */
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/page-flags.h>
@@ -78,7 +82,7 @@ static int hwpoison_filter_dev(struct page *p)
                return 0;
 
        /*
-        * page_mapping() does not accept slab page
+        * page_mapping() does not accept slab pages.
         */
        if (PageSlab(p))
                return -EINVAL;
@@ -268,7 +272,7 @@ struct to_kill {
        struct list_head nd;
        struct task_struct *tsk;
        unsigned long addr;
-       unsigned addr_valid:1;
+       char addr_valid;
 };
 
 /*
@@ -309,7 +313,7 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
         * a SIGKILL because the error is not contained anymore.
         */
        if (tk->addr == -EFAULT) {
-               pr_debug("MCE: Unable to find user space address %lx in %s\n",
+               pr_info("MCE: Unable to find user space address %lx in %s\n",
                        page_to_pfn(p), tsk->comm);
                tk->addr_valid = 0;
        }
@@ -577,7 +581,7 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
                                        pfn, err);
                } else if (page_has_private(p) &&
                                !try_to_release_page(p, GFP_NOIO)) {
-                       pr_debug("MCE %#lx: failed to release buffers\n", pfn);
+                       pr_info("MCE %#lx: failed to release buffers\n", pfn);
                } else {
                        ret = RECOVERED;
                }
@@ -693,11 +697,10 @@ static int me_swapcache_clean(struct page *p, unsigned long pfn)
  * Issues:
  * - Error on hugepage is contained in hugepage unit (not in raw page unit.)
  *   To narrow down kill region to one page, we need to break up pmd.
- * - To support soft-offlining for hugepage, we need to support hugepage
- *   migration.
  */
 static int me_huge_page(struct page *p, unsigned long pfn)
 {
+       int res = 0;
        struct page *hpage = compound_head(p);
        /*
         * We can safely recover from error on free or reserved (i.e.
@@ -710,8 +713,9 @@ static int me_huge_page(struct page *p, unsigned long pfn)
         * so there is no race between isolation and mapping/unmapping.
         */
        if (!(page_mapping(hpage) || PageAnon(hpage))) {
-               __isolate_hwpoisoned_huge_page(hpage);
-               return RECOVERED;
+               res = dequeue_hwpoisoned_huge_page(hpage);
+               if (!res)
+                       return RECOVERED;
        }
        return DELAYED;
 }
@@ -836,8 +840,6 @@ static int page_action(struct page_state *ps, struct page *p,
        return (result == RECOVERED || result == DELAYED) ? 0 : -EBUSY;
 }
 
-#define N_UNMAP_TRIES 5
-
 /*
  * Do all that is necessary to remove user space mappings. Unmap
  * the pages and send SIGBUS to the processes if the data was dirty.
@@ -849,7 +851,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        struct address_space *mapping;
        LIST_HEAD(tokill);
        int ret;
-       int i;
        int kill = 1;
        struct page *hpage = compound_head(p);
 
@@ -903,17 +904,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        if (kill)
                collect_procs(hpage, &tokill);
 
-       /*
-        * try_to_unmap can fail temporarily due to races.
-        * Try a few times (RED-PEN better strategy?)
-        */
-       for (i = 0; i < N_UNMAP_TRIES; i++) {
-               ret = try_to_unmap(hpage, ttu);
-               if (ret == SWAP_SUCCESS)
-                       break;
-               pr_debug("MCE %#lx: try_to_unmap retry needed %d\n", pfn,  ret);
-       }
-
+       ret = try_to_unmap(hpage, ttu);
        if (ret != SWAP_SUCCESS)
                printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
                                pfn, page_mapcount(hpage));
@@ -981,7 +972,10 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * We need/can do nothing about count=0 pages.
         * 1) it's a free page, and therefore in safe hand:
         *    prep_new_page() will be the gate keeper.
-        * 2) it's part of a non-compound high order page.
+        * 2) it's a free hugepage, which is also safe:
+        *    an affected hugepage will be dequeued from hugepage freelist,
+        *    so there's no concern about reusing it ever after.
+        * 3) it's part of a non-compound high order page.
         *    Implies some kernel user: cannot stop them from
         *    R/W the page; let's pray that the page has been
         *    used and will be freed some time later.
@@ -993,6 +987,24 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
                if (is_free_buddy_page(p)) {
                        action_result(pfn, "free buddy", DELAYED);
                        return 0;
+               } else if (PageHuge(hpage)) {
+                       /*
+                        * Check "just unpoisoned", "filter hit", and
+                        * "race with other subpage."
+                        */
+                       lock_page_nosync(hpage);
+                       if (!PageHWPoison(hpage)
+                           || (hwpoison_filter(p) && TestClearPageHWPoison(p))
+                           || (p != hpage && TestSetPageHWPoison(hpage))) {
+                               atomic_long_sub(nr_pages, &mce_bad_pages);
+                               return 0;
+                       }
+                       set_page_hwpoison_huge_page(hpage);
+                       res = dequeue_hwpoisoned_huge_page(hpage);
+                       action_result(pfn, "free huge",
+                                     res ? IGNORED : DELAYED);
+                       unlock_page(hpage);
+                       return res;
                } else {
                        action_result(pfn, "high order kernel", IGNORED);
                        return -EBUSY;
@@ -1147,16 +1159,26 @@ int unpoison_memory(unsigned long pfn)
        page = compound_head(p);
 
        if (!PageHWPoison(p)) {
-               pr_debug("MCE: Page was already unpoisoned %#lx\n", pfn);
+               pr_info("MCE: Page was already unpoisoned %#lx\n", pfn);
                return 0;
        }
 
        nr_pages = 1 << compound_order(page);
 
        if (!get_page_unless_zero(page)) {
+               /*
+                * Since HWPoisoned hugepage should have non-zero refcount,
+                * race between memory failure and unpoison seems to happen.
+                * In such case unpoison fails and memory failure runs
+                * to the end.
+                */
+               if (PageHuge(page)) {
+                       pr_debug("MCE: Memory failure is now running on free hugepage %#lx\n", pfn);
+                       return 0;
+               }
                if (TestClearPageHWPoison(p))
                        atomic_long_sub(nr_pages, &mce_bad_pages);
-               pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);
+               pr_info("MCE: Software-unpoisoned free page %#lx\n", pfn);
                return 0;
        }
 
@@ -1168,12 +1190,12 @@ int unpoison_memory(unsigned long pfn)
         * the free buddy page pool.
         */
        if (TestClearPageHWPoison(page)) {
-               pr_debug("MCE: Software-unpoisoned page %#lx\n", pfn);
+               pr_info("MCE: Software-unpoisoned page %#lx\n", pfn);
                atomic_long_sub(nr_pages, &mce_bad_pages);
                freeit = 1;
+               if (PageHuge(page))
+                       clear_page_hwpoison_huge_page(page);
        }
-       if (PageHuge(p))
-               clear_page_hwpoison_huge_page(page);
        unlock_page(page);
 
        put_page(page);
@@ -1187,7 +1209,11 @@ EXPORT_SYMBOL(unpoison_memory);
 static struct page *new_page(struct page *p, unsigned long private, int **x)
 {
        int nid = page_to_nid(p);
-       return alloc_pages_exact_node(nid, GFP_HIGHUSER_MOVABLE, 0);
+       if (PageHuge(p))
+               return alloc_huge_page_node(page_hstate(compound_head(p)),
+                                                  nid);
+       else
+               return alloc_pages_exact_node(nid, GFP_HIGHUSER_MOVABLE, 0);
 }
 
 /*
@@ -1215,14 +1241,21 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags)
         * was free.
         */
        set_migratetype_isolate(p);
+       /*
+        * When the target page is a free hugepage, just remove it
+        * from free hugepage list.
+        */
        if (!get_page_unless_zero(compound_head(p))) {
-               if (is_free_buddy_page(p)) {
-                       pr_debug("get_any_page: %#lx free buddy page\n", pfn);
+               if (PageHuge(p)) {
+                       pr_info("get_any_page: %#lx free huge page\n", pfn);
+                       ret = dequeue_hwpoisoned_huge_page(compound_head(p));
+               } else if (is_free_buddy_page(p)) {
+                       pr_info("get_any_page: %#lx free buddy page\n", pfn);
                        /* Set hwpoison bit while page is still isolated */
                        SetPageHWPoison(p);
                        ret = 0;
                } else {
-                       pr_debug("get_any_page: %#lx: unknown zero refcount page type %lx\n",
+                       pr_info("get_any_page: %#lx: unknown zero refcount page type %lx\n",
                                pfn, p->flags);
                        ret = -EIO;
                }
@@ -1235,6 +1268,46 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags)
        return ret;
 }
 
+static int soft_offline_huge_page(struct page *page, int flags)
+{
+       int ret;
+       unsigned long pfn = page_to_pfn(page);
+       struct page *hpage = compound_head(page);
+       LIST_HEAD(pagelist);
+
+       ret = get_any_page(page, pfn, flags);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               goto done;
+
+       if (PageHWPoison(hpage)) {
+               put_page(hpage);
+               pr_debug("soft offline: %#lx hugepage already poisoned\n", pfn);
+               return -EBUSY;
+       }
+
+       /* Keep page count to indicate a given hugepage is isolated. */
+
+       list_add(&hpage->lru, &pagelist);
+       ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0);
+       if (ret) {
+                       putback_lru_pages(&pagelist);
+               pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
+                        pfn, ret, page->flags);
+               if (ret > 0)
+                       ret = -EIO;
+               return ret;
+       }
+done:
+       if (!PageHWPoison(hpage))
+               atomic_long_add(1 << compound_order(hpage), &mce_bad_pages);
+       set_page_hwpoison_huge_page(hpage);
+       dequeue_hwpoisoned_huge_page(hpage);
+       /* keep elevated page count for bad page */
+       return ret;
+}
+
 /**
  * soft_offline_page - Soft offline a page.
  * @page: page to offline
@@ -1262,6 +1335,9 @@ int soft_offline_page(struct page *page, int flags)
        int ret;
        unsigned long pfn = page_to_pfn(page);
 
+       if (PageHuge(page))
+               return soft_offline_huge_page(page, flags);
+
        ret = get_any_page(page, pfn, flags);
        if (ret < 0)
                return ret;
@@ -1288,7 +1364,7 @@ int soft_offline_page(struct page *page, int flags)
                        goto done;
        }
        if (!PageLRU(page)) {
-               pr_debug("soft_offline: %#lx: unknown non LRU page type %lx\n",
+               pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
                                pfn, page->flags);
                return -EIO;
        }
@@ -1302,7 +1378,7 @@ int soft_offline_page(struct page *page, int flags)
        if (PageHWPoison(page)) {
                unlock_page(page);
                put_page(page);
-               pr_debug("soft offline: %#lx page already poisoned\n", pfn);
+               pr_info("soft offline: %#lx page already poisoned\n", pfn);
                return -EBUSY;
        }
 
@@ -1323,7 +1399,7 @@ int soft_offline_page(struct page *page, int flags)
        put_page(page);
        if (ret == 1) {
                ret = 0;
-               pr_debug("soft_offline: %#lx: invalidated\n", pfn);
+               pr_info("soft_offline: %#lx: invalidated\n", pfn);
                goto done;
        }
 
@@ -1339,13 +1415,13 @@ int soft_offline_page(struct page *page, int flags)
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0);
                if (ret) {
-                       pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
+                       pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
                                pfn, ret, page->flags);
                        if (ret > 0)
                                ret = -EIO;
                }
        } else {
-               pr_debug("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
+               pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
                                pfn, ret, page_count(page), page->flags);
        }
        if (ret)
index 98b58fecedeffc236a9c7285689fe4720409bd30..02e48aa0ed136ff8e4d808d954a20d0b46e6d23d 100644 (file)
@@ -736,7 +736,7 @@ again:
        dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
        if (!dst_pte)
                return -ENOMEM;
-       src_pte = pte_offset_map_nested(src_pmd, addr);
+       src_pte = pte_offset_map(src_pmd, addr);
        src_ptl = pte_lockptr(src_mm, src_pmd);
        spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
        orig_src_pte = src_pte;
@@ -767,7 +767,7 @@ again:
 
        arch_leave_lazy_mmu_mode();
        spin_unlock(src_ptl);
-       pte_unmap_nested(orig_src_pte);
+       pte_unmap(orig_src_pte);
        add_mm_rss_vec(dst_mm, rss);
        pte_unmap_unlock(orig_dst_pte, dst_ptl);
        cond_resched();
@@ -1450,7 +1450,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                        if (ret & VM_FAULT_OOM)
                                                return i ? i : -ENOMEM;
                                        if (ret &
-                                           (VM_FAULT_HWPOISON|VM_FAULT_SIGBUS))
+                                           (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE|
+                                            VM_FAULT_SIGBUS))
                                                return i ? i : -EFAULT;
                                        BUG();
                                }
@@ -1590,7 +1591,7 @@ struct page *get_dump_page(unsigned long addr)
 }
 #endif /* CONFIG_ELF_CORE */
 
-pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
                        spinlock_t **ptl)
 {
        pgd_t * pgd = pgd_offset(mm, addr);
@@ -2079,7 +2080,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
                 * zeroes.
                 */
                if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
-                       memset(kaddr, 0, PAGE_SIZE);
+                       clear_page(kaddr);
                kunmap_atomic(kaddr, KM_USER0);
                flush_dcache_page(dst);
        } else
@@ -2107,6 +2108,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
 static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pte_t *page_table, pmd_t *pmd,
                spinlock_t *ptl, pte_t orig_pte)
+       __releases(ptl)
 {
        struct page *old_page, *new_page;
        pte_t entry;
@@ -2626,6 +2628,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        struct page *page, *swapcache = NULL;
        swp_entry_t entry;
        pte_t pte;
+       int locked;
        struct mem_cgroup *ptr = NULL;
        int exclusive = 0;
        int ret = 0;
@@ -2676,8 +2679,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out_release;
        }
 
-       lock_page(page);
+       locked = lock_page_or_retry(page, mm, flags);
        delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
+       if (!locked) {
+               ret |= VM_FAULT_RETRY;
+               goto out_release;
+       }
 
        /*
         * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
@@ -2926,7 +2933,8 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        vmf.page = NULL;
 
        ret = vma->vm_ops->fault(vma, &vmf);
-       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE |
+                           VM_FAULT_RETRY)))
                return ret;
 
        if (unlikely(PageHWPoison(vmf.page))) {
@@ -3343,7 +3351,7 @@ int in_gate_area_no_task(unsigned long addr)
 
 #endif /* __HAVE_ARCH_GATE_AREA */
 
-static int follow_pte(struct mm_struct *mm, unsigned long address,
+static int __follow_pte(struct mm_struct *mm, unsigned long address,
                pte_t **ptepp, spinlock_t **ptlp)
 {
        pgd_t *pgd;
@@ -3380,6 +3388,17 @@ out:
        return -EINVAL;
 }
 
+static inline int follow_pte(struct mm_struct *mm, unsigned long address,
+                            pte_t **ptepp, spinlock_t **ptlp)
+{
+       int res;
+
+       /* (void) is needed to make gcc happy */
+       (void) __cond_lock(*ptlp,
+                          !(res = __follow_pte(mm, address, ptepp, ptlp)));
+       return res;
+}
+
 /**
  * follow_pfn - look up PFN at a user virtual address
  * @vma: memory mapping
index d4e940a26945cde1f8251b39b37fde3144639d5b..9260314a221e0720d5cc3ecf5f00325c7ec3fba6 100644 (file)
@@ -602,27 +602,14 @@ static struct page *next_active_pageblock(struct page *page)
 /* Checks if this range of memory is likely to be hot-removable. */
 int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
 {
-       int type;
        struct page *page = pfn_to_page(start_pfn);
        struct page *end_page = page + nr_pages;
 
        /* Check the starting page of each pageblock within the range */
        for (; page < end_page; page = next_active_pageblock(page)) {
-               type = get_pageblock_migratetype(page);
-
-               /*
-                * A pageblock containing MOVABLE or free pages is considered
-                * removable
-                */
-               if (type != MIGRATE_MOVABLE && !pageblock_free(page))
-                       return 0;
-
-               /*
-                * A pageblock starting with a PageReserved page is not
-                * considered removable.
-                */
-               if (PageReserved(page))
+               if (!is_pageblock_removable_nolock(page))
                        return 0;
+               cond_resched();
        }
 
        /* All pageblocks in the memory block are likely to be hot-removable */
@@ -659,7 +646,7 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
  * Scanning pfn is much easier than scanning lru list.
  * Scan pfn from start to end and Find LRU page.
  */
-int scan_lru_pages(unsigned long start, unsigned long end)
+static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
 {
        unsigned long pfn;
        struct page *page;
@@ -709,29 +696,30 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                                            page_is_file_cache(page));
 
                } else {
-                       /* Becasue we don't have big zone->lock. we should
-                          check this again here. */
-                       if (page_count(page))
-                               not_managed++;
 #ifdef CONFIG_DEBUG_VM
                        printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
                               pfn);
                        dump_page(page);
 #endif
+                       /* Becasue we don't have big zone->lock. we should
+                          check this again here. */
+                       if (page_count(page)) {
+                               not_managed++;
+                               ret = -EBUSY;
+                               break;
+                       }
                }
        }
-       ret = -EBUSY;
-       if (not_managed) {
-               if (!list_empty(&source))
+       if (!list_empty(&source)) {
+               if (not_managed) {
+                       putback_lru_pages(&source);
+                       goto out;
+               }
+               /* this function returns # of failed pages */
+               ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1);
+               if (ret)
                        putback_lru_pages(&source);
-               goto out;
        }
-       ret = 0;
-       if (list_empty(&source))
-               goto out;
-       /* this function returns # of failed pages */
-       ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1);
-
 out:
        return ret;
 }
index f969da5dd8a2136b92aab7e7c1a6ecc9083d6cb9..81a127643aea889675e9570ebee5653833e55e95 100644 (file)
@@ -924,15 +924,21 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
        nodemask_t nmask;
        LIST_HEAD(pagelist);
        int err = 0;
+       struct vm_area_struct *vma;
 
        nodes_clear(nmask);
        node_set(source, nmask);
 
-       check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
+       vma = check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
                        flags | MPOL_MF_DISCONTIG_OK, &pagelist);
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
 
-       if (!list_empty(&pagelist))
+       if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_node_page, dest, 0);
+               if (err)
+                       putback_lru_pages(&pagelist);
+       }
 
        return err;
 }
@@ -1147,9 +1153,12 @@ static long do_mbind(unsigned long start, unsigned long len,
 
                err = mbind_range(mm, start, end, new);
 
-               if (!list_empty(&pagelist))
+               if (!list_empty(&pagelist)) {
                        nr_failed = migrate_pages(&pagelist, new_vma_page,
                                                (unsigned long)vma, 0);
+                       if (nr_failed)
+                               putback_lru_pages(&pagelist);
+               }
 
                if (!err && nr_failed && (flags & MPOL_MF_STRICT))
                        err = -EIO;
index 38e7cad782f4b008a85f03e6635332f46ba0932b..fe5a3c6a54260f2ae9999fbaabe03082a818982f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/security.h>
 #include <linux/memcontrol.h>
 #include <linux/syscalls.h>
+#include <linux/hugetlb.h>
 #include <linux/gfp.h>
 
 #include "internal.h"
@@ -95,26 +96,34 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
        pte_t *ptep, pte;
        spinlock_t *ptl;
 
-       pgd = pgd_offset(mm, addr);
-       if (!pgd_present(*pgd))
-               goto out;
+       if (unlikely(PageHuge(new))) {
+               ptep = huge_pte_offset(mm, addr);
+               if (!ptep)
+                       goto out;
+               ptl = &mm->page_table_lock;
+       } else {
+               pgd = pgd_offset(mm, addr);
+               if (!pgd_present(*pgd))
+                       goto out;
 
-       pud = pud_offset(pgd, addr);
-       if (!pud_present(*pud))
-               goto out;
+               pud = pud_offset(pgd, addr);
+               if (!pud_present(*pud))
+                       goto out;
 
-       pmd = pmd_offset(pud, addr);
-       if (!pmd_present(*pmd))
-               goto out;
+               pmd = pmd_offset(pud, addr);
+               if (!pmd_present(*pmd))
+                       goto out;
 
-       ptep = pte_offset_map(pmd, addr);
+               ptep = pte_offset_map(pmd, addr);
 
-       if (!is_swap_pte(*ptep)) {
-               pte_unmap(ptep);
-               goto out;
-       }
+               if (!is_swap_pte(*ptep)) {
+                       pte_unmap(ptep);
+                       goto out;
+               }
+
+               ptl = pte_lockptr(mm, pmd);
+       }
 
-       ptl = pte_lockptr(mm, pmd);
        spin_lock(ptl);
        pte = *ptep;
        if (!is_swap_pte(pte))
@@ -130,10 +139,19 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
        pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
        if (is_write_migration_entry(entry))
                pte = pte_mkwrite(pte);
+#ifdef CONFIG_HUGETLB_PAGE
+       if (PageHuge(new))
+               pte = pte_mkhuge(pte);
+#endif
        flush_cache_page(vma, addr, pte_pfn(pte));
        set_pte_at(mm, addr, ptep, pte);
 
-       if (PageAnon(new))
+       if (PageHuge(new)) {
+               if (PageAnon(new))
+                       hugepage_add_anon_rmap(new, vma, addr);
+               else
+                       page_dup_rmap(new);
+       } else if (PageAnon(new))
                page_add_anon_rmap(new, vma, addr);
        else
                page_add_file_rmap(new);
@@ -275,12 +293,60 @@ static int migrate_page_move_mapping(struct address_space *mapping,
        return 0;
 }
 
+/*
+ * The expected number of remaining references is the same as that
+ * of migrate_page_move_mapping().
+ */
+int migrate_huge_page_move_mapping(struct address_space *mapping,
+                                  struct page *newpage, struct page *page)
+{
+       int expected_count;
+       void **pslot;
+
+       if (!mapping) {
+               if (page_count(page) != 1)
+                       return -EAGAIN;
+               return 0;
+       }
+
+       spin_lock_irq(&mapping->tree_lock);
+
+       pslot = radix_tree_lookup_slot(&mapping->page_tree,
+                                       page_index(page));
+
+       expected_count = 2 + page_has_private(page);
+       if (page_count(page) != expected_count ||
+           (struct page *)radix_tree_deref_slot(pslot) != page) {
+               spin_unlock_irq(&mapping->tree_lock);
+               return -EAGAIN;
+       }
+
+       if (!page_freeze_refs(page, expected_count)) {
+               spin_unlock_irq(&mapping->tree_lock);
+               return -EAGAIN;
+       }
+
+       get_page(newpage);
+
+       radix_tree_replace_slot(pslot, newpage);
+
+       page_unfreeze_refs(page, expected_count);
+
+       __put_page(page);
+
+       spin_unlock_irq(&mapping->tree_lock);
+       return 0;
+}
+
 /*
  * Copy the page to its new location
  */
-static void migrate_page_copy(struct page *newpage, struct page *page)
+void migrate_page_copy(struct page *newpage, struct page *page)
 {
-       copy_highpage(newpage, page);
+       if (PageHuge(page))
+               copy_huge_page(newpage, page);
+       else
+               copy_highpage(newpage, page);
 
        if (PageError(page))
                SetPageError(newpage);
@@ -431,7 +497,6 @@ static int writeout(struct address_space *mapping, struct page *page)
                .nr_to_write = 1,
                .range_start = 0,
                .range_end = LLONG_MAX,
-               .nonblocking = 1,
                .for_reclaim = 1
        };
        int rc;
@@ -723,6 +788,92 @@ move_newpage:
        return rc;
 }
 
+/*
+ * Counterpart of unmap_and_move_page() for hugepage migration.
+ *
+ * This function doesn't wait the completion of hugepage I/O
+ * because there is no race between I/O and migration for hugepage.
+ * Note that currently hugepage I/O occurs only in direct I/O
+ * where no lock is held and PG_writeback is irrelevant,
+ * and writeback status of all subpages are counted in the reference
+ * count of the head page (i.e. if all subpages of a 2MB hugepage are
+ * under direct I/O, the reference of the head page is 512 and a bit more.)
+ * This means that when we try to migrate hugepage whose subpages are
+ * doing direct I/O, some references remain after try_to_unmap() and
+ * hugepage migration fails without data corruption.
+ *
+ * There is also no race when direct I/O is issued on the page under migration,
+ * because then pte is replaced with migration swap entry and direct I/O code
+ * will wait in the page fault for migration to complete.
+ */
+static int unmap_and_move_huge_page(new_page_t get_new_page,
+                               unsigned long private, struct page *hpage,
+                               int force, int offlining)
+{
+       int rc = 0;
+       int *result = NULL;
+       struct page *new_hpage = get_new_page(hpage, private, &result);
+       int rcu_locked = 0;
+       struct anon_vma *anon_vma = NULL;
+
+       if (!new_hpage)
+               return -ENOMEM;
+
+       rc = -EAGAIN;
+
+       if (!trylock_page(hpage)) {
+               if (!force)
+                       goto out;
+               lock_page(hpage);
+       }
+
+       if (PageAnon(hpage)) {
+               rcu_read_lock();
+               rcu_locked = 1;
+
+               if (page_mapped(hpage)) {
+                       anon_vma = page_anon_vma(hpage);
+                       atomic_inc(&anon_vma->external_refcount);
+               }
+       }
+
+       try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+
+       if (!page_mapped(hpage))
+               rc = move_to_new_page(new_hpage, hpage, 1);
+
+       if (rc)
+               remove_migration_ptes(hpage, hpage);
+
+       if (anon_vma && atomic_dec_and_lock(&anon_vma->external_refcount,
+                                           &anon_vma->lock)) {
+               int empty = list_empty(&anon_vma->head);
+               spin_unlock(&anon_vma->lock);
+               if (empty)
+                       anon_vma_free(anon_vma);
+       }
+
+       if (rcu_locked)
+               rcu_read_unlock();
+out:
+       unlock_page(hpage);
+
+       if (rc != -EAGAIN) {
+               list_del(&hpage->lru);
+               put_page(hpage);
+       }
+
+       put_page(new_hpage);
+
+       if (result) {
+               if (rc)
+                       *result = rc;
+               else
+                       *result = page_to_nid(new_hpage);
+       }
+       return rc;
+}
+
 /*
  * migrate_pages
  *
@@ -732,8 +883,9 @@ move_newpage:
  *
  * The function returns after 10 attempts or if no pages
  * are movable anymore because to has become empty
- * or no retryable pages exist anymore. All pages will be
- * returned to the LRU or freed.
+ * or no retryable pages exist anymore.
+ * Caller should call putback_lru_pages to return pages to the LRU
+ * or free list.
  *
  * Return: Number of pages not migrated or error code.
  */
@@ -780,7 +932,51 @@ out:
        if (!swapwrite)
                current->flags &= ~PF_SWAPWRITE;
 
-       putback_lru_pages(from);
+       if (rc)
+               return rc;
+
+       return nr_failed + retry;
+}
+
+int migrate_huge_pages(struct list_head *from,
+               new_page_t get_new_page, unsigned long private, int offlining)
+{
+       int retry = 1;
+       int nr_failed = 0;
+       int pass = 0;
+       struct page *page;
+       struct page *page2;
+       int rc;
+
+       for (pass = 0; pass < 10 && retry; pass++) {
+               retry = 0;
+
+               list_for_each_entry_safe(page, page2, from, lru) {
+                       cond_resched();
+
+                       rc = unmap_and_move_huge_page(get_new_page,
+                                       private, page, pass > 2, offlining);
+
+                       switch(rc) {
+                       case -ENOMEM:
+                               goto out;
+                       case -EAGAIN:
+                               retry++;
+                               break;
+                       case 0:
+                               break;
+                       default:
+                               /* Permanent failure */
+                               nr_failed++;
+                               break;
+                       }
+               }
+       }
+       rc = 0;
+out:
+
+       list_for_each_entry_safe(page, page2, from, lru)
+               put_page(page);
 
        if (rc)
                return rc;
@@ -841,7 +1037,7 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
 
                err = -EFAULT;
                vma = find_vma(mm, pp->addr);
-               if (!vma || !vma_migratable(vma))
+               if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma))
                        goto set_status;
 
                page = follow_page(vma, pp->addr, FOLL_GET);
@@ -890,9 +1086,12 @@ set_status:
        }
 
        err = 0;
-       if (!list_empty(&pagelist))
+       if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_page_node,
                                (unsigned long)pm, 0);
+               if (err)
+                       putback_lru_pages(&pagelist);
+       }
 
        up_read(&mm->mmap_sem);
        return err;
@@ -1005,7 +1204,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
                int err = -EFAULT;
 
                vma = find_vma(mm, addr);
-               if (!vma)
+               if (!vma || addr < vma->vm_start)
                        goto set_status;
 
                page = follow_page(vma, addr, 0);
index cde56ee51ef7a6b10e18f860bd7be08df07f2407..563fbdd6293ae3f0139450d6b7d848f862c1f8dc 100644 (file)
@@ -101,7 +101,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
         * pte locks because exclusive mmap_sem prevents deadlock.
         */
        old_pte = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
-       new_pte = pte_offset_map_nested(new_pmd, new_addr);
+       new_pte = pte_offset_map(new_pmd, new_addr);
        new_ptl = pte_lockptr(mm, new_pmd);
        if (new_ptl != old_ptl)
                spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
@@ -119,7 +119,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
        arch_leave_lazy_mmu_mode();
        if (new_ptl != old_ptl)
                spin_unlock(new_ptl);
-       pte_unmap_nested(new_pte - 1);
+       pte_unmap(new_pte - 1);
        pte_unmap_unlock(old_pte - 1, old_ptl);
        if (mapping)
                spin_unlock(&mapping->i_mmap_lock);
index 88ff091eb07a23dcaee1e8e6d0cc70927183b89b..30b5c20eec15e6761bad5dd4815e69ebae1d7dc2 100644 (file)
@@ -293,11 +293,58 @@ void *vmalloc(unsigned long size)
 }
 EXPORT_SYMBOL(vmalloc);
 
+/*
+ *     vzalloc - allocate virtually continguos memory with zero fill
+ *
+ *     @size:          allocation size
+ *
+ *     Allocate enough pages to cover @size from the page level
+ *     allocator and map them into continguos kernel virtual space.
+ *     The memory allocated is set to zero.
+ *
+ *     For tight control over page level allocator and protection flags
+ *     use __vmalloc() instead.
+ */
+void *vzalloc(unsigned long size)
+{
+       return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                       PAGE_KERNEL);
+}
+EXPORT_SYMBOL(vzalloc);
+
+/**
+ * vmalloc_node - allocate memory on a specific node
+ * @size:      allocation size
+ * @node:      numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
 void *vmalloc_node(unsigned long size, int node)
 {
        return vmalloc(size);
 }
-EXPORT_SYMBOL(vmalloc_node);
+
+/**
+ * vzalloc_node - allocate memory on a specific node with zero fill
+ * @size:      allocation size
+ * @node:      numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+void *vzalloc_node(unsigned long size, int node)
+{
+       return vzalloc(size);
+}
+EXPORT_SYMBOL(vzalloc_node);
 
 #ifndef PAGE_KERNEL_EXEC
 # define PAGE_KERNEL_EXEC PAGE_KERNEL
index 4029583a10241aaa84e3937ee216740e0a88a363..7dcca55ede7ca1493df615af994f6ba23c1bb129 100644 (file)
@@ -162,10 +162,11 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
                return 0;
 
        /*
-        * Shortcut check for OOM_SCORE_ADJ_MIN so the entire heuristic doesn't
-        * need to be executed for something that cannot be killed.
+        * Shortcut check for a thread sharing p->mm that is OOM_SCORE_ADJ_MIN
+        * so the entire heuristic doesn't need to be executed for something
+        * that cannot be killed.
         */
-       if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+       if (atomic_read(&p->mm->oom_disable_count)) {
                task_unlock(p);
                return 0;
        }
@@ -403,16 +404,40 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
 #define K(x) ((x) << (PAGE_SHIFT-10))
 static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
 {
+       struct task_struct *q;
+       struct mm_struct *mm;
+
        p = find_lock_task_mm(p);
        if (!p)
                return 1;
 
+       /* mm cannot be safely dereferenced after task_unlock(p) */
+       mm = p->mm;
+
        pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
                task_pid_nr(p), p->comm, K(p->mm->total_vm),
                K(get_mm_counter(p->mm, MM_ANONPAGES)),
                K(get_mm_counter(p->mm, MM_FILEPAGES)));
        task_unlock(p);
 
+       /*
+        * Kill all processes sharing p->mm in other thread groups, if any.
+        * They don't get access to memory reserves or a higher scheduler
+        * priority, though, to avoid depletion of all memory or task
+        * starvation.  This prevents mm->mmap_sem livelock when an oom killed
+        * task cannot exit because it requires the semaphore and its contended
+        * by another thread trying to allocate memory itself.  That thread will
+        * now get access to memory reserves since it has a pending fatal
+        * signal.
+        */
+       for_each_process(q)
+               if (q->mm == mm && !same_thread_group(q, p)) {
+                       task_lock(q);   /* Protect ->comm from prctl() */
+                       pr_err("Kill process %d (%s) sharing same memory\n",
+                               task_pid_nr(q), q->comm);
+                       task_unlock(q);
+                       force_sig(SIGKILL, q);
+               }
 
        set_tsk_thread_flag(p, TIF_MEMDIE);
        force_sig(SIGKILL, p);
@@ -680,7 +705,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
        read_lock(&tasklist_lock);
        if (sysctl_oom_kill_allocating_task &&
            !oom_unkillable_task(current, NULL, nodemask) &&
-           (current->signal->oom_adj != OOM_DISABLE)) {
+           current->mm && !atomic_read(&current->mm->oom_disable_count)) {
                /*
                 * oom_kill_process() needs tasklist_lock held.  If it returns
                 * non-zero, current could not be killed so we must fallback to
index e3bccac1f0255bb78373e6268aab787a370ee520..b840afa89761ce0d83690ff963385399246fa6d8 100644 (file)
@@ -415,14 +415,8 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
 
        if (vm_dirty_bytes)
                dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
-       else {
-               int dirty_ratio;
-
-               dirty_ratio = vm_dirty_ratio;
-               if (dirty_ratio < 5)
-                       dirty_ratio = 5;
-               dirty = (dirty_ratio * available_memory) / 100;
-       }
+       else
+               dirty = (vm_dirty_ratio * available_memory) / 100;
 
        if (dirty_background_bytes)
                background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
@@ -510,7 +504,7 @@ static void balance_dirty_pages(struct address_space *mapping,
                 * catch-up. This avoids (excessively) small writeouts
                 * when the bdi limits are ramping up.
                 */
-               if (nr_reclaimable + nr_writeback <
+               if (nr_reclaimable + nr_writeback <=
                                (background_thresh + dirty_thresh) / 2)
                        break;
 
@@ -542,8 +536,8 @@ static void balance_dirty_pages(struct address_space *mapping,
                 * the last resort safeguard.
                 */
                dirty_exceeded =
-                       (bdi_nr_reclaimable + bdi_nr_writeback >= bdi_thresh)
-                       || (nr_reclaimable + nr_writeback >= dirty_thresh);
+                       (bdi_nr_reclaimable + bdi_nr_writeback > bdi_thresh)
+                       || (nr_reclaimable + nr_writeback > dirty_thresh);
 
                if (!dirty_exceeded)
                        break;
@@ -1121,6 +1115,7 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
 {
        if (mapping_cap_account_dirty(mapping)) {
                __inc_zone_page_state(page, NR_FILE_DIRTY);
+               __inc_zone_page_state(page, NR_DIRTIED);
                __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
                task_dirty_inc(current);
                task_io_account_write(PAGE_CACHE_SIZE);
@@ -1128,6 +1123,18 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
 }
 EXPORT_SYMBOL(account_page_dirtied);
 
+/*
+ * Helper function for set_page_writeback family.
+ * NOTE: Unlike account_page_dirtied this does not rely on being atomic
+ * wrt interrupts.
+ */
+void account_page_writeback(struct page *page)
+{
+       inc_zone_page_state(page, NR_WRITEBACK);
+       inc_zone_page_state(page, NR_WRITTEN);
+}
+EXPORT_SYMBOL(account_page_writeback);
+
 /*
  * For address_spaces which do not use buffers.  Just tag the page as dirty in
  * its radix tree.
@@ -1366,7 +1373,7 @@ int test_set_page_writeback(struct page *page)
                ret = TestSetPageWriteback(page);
        }
        if (!ret)
-               inc_zone_page_state(page, NR_WRITEBACK);
+               account_page_writeback(page);
        return ret;
 
 }
index 2a362c52fdf482144eac24111059f56b5147bd42..07a654486f75cfdfe13035f7bf501e2d2dbf0a4a 100644 (file)
@@ -531,7 +531,7 @@ static inline void __free_one_page(struct page *page,
         * so it's less likely to be used soon and more likely to be merged
         * as a higher order page
         */
-       if ((order < MAX_ORDER-1) && pfn_valid_within(page_to_pfn(buddy))) {
+       if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) {
                struct page *higher_page, *higher_buddy;
                combined_idx = __find_combined_index(page_idx, order);
                higher_page = page + combined_idx - page_idx;
@@ -1907,7 +1907,7 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
                        preferred_zone, migratetype);
 
                if (!page && gfp_mask & __GFP_NOFAIL)
-                       congestion_wait(BLK_RW_ASYNC, HZ/50);
+                       wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
        } while (!page && (gfp_mask & __GFP_NOFAIL));
 
        return page;
@@ -1932,7 +1932,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
        const gfp_t wait = gfp_mask & __GFP_WAIT;
 
        /* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */
-       BUILD_BUG_ON(__GFP_HIGH != ALLOC_HIGH);
+       BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH);
 
        /*
         * The caller may dip into page reserves a bit more if the caller
@@ -1940,7 +1940,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
         * policy or is asking for __GFP_HIGH memory.  GFP_ATOMIC requests will
         * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
         */
-       alloc_flags |= (gfp_mask & __GFP_HIGH);
+       alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH);
 
        if (!wait) {
                alloc_flags |= ALLOC_HARDER;
@@ -2095,7 +2095,7 @@ rebalance:
        pages_reclaimed += did_some_progress;
        if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
                /* Wait for some write requests to complete then retry */
-               congestion_wait(BLK_RW_ASYNC, HZ/50);
+               wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
                goto rebalance;
        }
 
@@ -5297,12 +5297,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
  * page allocater never alloc memory from ISOLATE block.
  */
 
+static int
+__count_immobile_pages(struct zone *zone, struct page *page, int count)
+{
+       unsigned long pfn, iter, found;
+       /*
+        * For avoiding noise data, lru_add_drain_all() should be called
+        * If ZONE_MOVABLE, the zone never contains immobile pages
+        */
+       if (zone_idx(zone) == ZONE_MOVABLE)
+               return true;
+
+       if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE)
+               return true;
+
+       pfn = page_to_pfn(page);
+       for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
+               unsigned long check = pfn + iter;
+
+               if (!pfn_valid_within(check)) {
+                       iter++;
+                       continue;
+               }
+               page = pfn_to_page(check);
+               if (!page_count(page)) {
+                       if (PageBuddy(page))
+                               iter += (1 << page_order(page)) - 1;
+                       continue;
+               }
+               if (!PageLRU(page))
+                       found++;
+               /*
+                * If there are RECLAIMABLE pages, we need to check it.
+                * But now, memory offline itself doesn't call shrink_slab()
+                * and it still to be fixed.
+                */
+               /*
+                * If the page is not RAM, page_count()should be 0.
+                * we don't need more check. This is an _used_ not-movable page.
+                *
+                * The problematic thing here is PG_reserved pages. PG_reserved
+                * is set to both of a memory hole page and a _used_ kernel
+                * page at boot.
+                */
+               if (found > count)
+                       return false;
+       }
+       return true;
+}
+
+bool is_pageblock_removable_nolock(struct page *page)
+{
+       struct zone *zone = page_zone(page);
+       return __count_immobile_pages(zone, page, 0);
+}
+
 int set_migratetype_isolate(struct page *page)
 {
        struct zone *zone;
-       struct page *curr_page;
-       unsigned long flags, pfn, iter;
-       unsigned long immobile = 0;
+       unsigned long flags, pfn;
        struct memory_isolate_notify arg;
        int notifier_ret;
        int ret = -EBUSY;
@@ -5312,11 +5365,6 @@ int set_migratetype_isolate(struct page *page)
        zone_idx = zone_idx(zone);
 
        spin_lock_irqsave(&zone->lock, flags);
-       if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
-           zone_idx == ZONE_MOVABLE) {
-               ret = 0;
-               goto out;
-       }
 
        pfn = page_to_pfn(page);
        arg.start_pfn = pfn;
@@ -5336,23 +5384,20 @@ int set_migratetype_isolate(struct page *page)
         */
        notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg);
        notifier_ret = notifier_to_errno(notifier_ret);
-       if (notifier_ret || !arg.pages_found)
+       if (notifier_ret)
                goto out;
-
-       for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
-               if (!pfn_valid_within(pfn))
-                       continue;
-
-               curr_page = pfn_to_page(iter);
-               if (!page_count(curr_page) || PageLRU(curr_page))
-                       continue;
-
-               immobile++;
-       }
-
-       if (arg.pages_found == immobile)
+       /*
+        * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
+        * We just check MOVABLE pages.
+        */
+       if (__count_immobile_pages(zone, page, arg.pages_found))
                ret = 0;
 
+       /*
+        * immobile means "not-on-lru" paes. If immobile is larger than
+        * removable-by-driver pages reported by notifier, we'll fail.
+        */
+
 out:
        if (!ret) {
                set_pageblock_migratetype(page, MIGRATE_ISOLATE);
index 5e0ffd967452083c8209dfa0a1334416ded99f68..4ae42bb4089241d146d8a62429cebc600fd7d14e 100644 (file)
@@ -86,7 +86,7 @@ undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
  * all pages in [start_pfn...end_pfn) must be in the same zone.
  * zone->lock must be held before call this.
  *
- * Returns 0 if all pages in the range is isolated.
+ * Returns 1 if all pages in the range is isolated.
  */
 static int
 __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
@@ -119,7 +119,6 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        struct zone *zone;
        int ret;
 
-       pfn = start_pfn;
        /*
         * Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page
         * is not aligned to pageblock_nr_pages.
index 92e6757f196ed4e3b3598c1f8b7214616a4cbe39..1a8bf76bfd038a7fe84fdd6b9443c4673c8ddd9f 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -80,7 +80,7 @@ static inline struct anon_vma_chain *anon_vma_chain_alloc(void)
        return kmem_cache_alloc(anon_vma_chain_cachep, GFP_KERNEL);
 }
 
-void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain)
+static void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain)
 {
        kmem_cache_free(anon_vma_chain_cachep, anon_vma_chain);
 }
@@ -314,7 +314,7 @@ void __init anon_vma_init(void)
  * Getting a lock on a stable anon_vma from a page off the LRU is
  * tricky: page_lock_anon_vma rely on RCU to guard against the races.
  */
-struct anon_vma *page_lock_anon_vma(struct page *page)
+struct anon_vma *__page_lock_anon_vma(struct page *page)
 {
        struct anon_vma *anon_vma, *root_anon_vma;
        unsigned long anon_mapping;
@@ -348,6 +348,8 @@ out:
 }
 
 void page_unlock_anon_vma(struct anon_vma *anon_vma)
+       __releases(&anon_vma->root->lock)
+       __releases(RCU)
 {
        anon_vma_unlock(anon_vma);
        rcu_read_unlock();
@@ -407,7 +409,7 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
  *
  * On success returns with pte mapped and locked.
  */
-pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
                          unsigned long address, spinlock_t **ptlp, int sync)
 {
        pgd_t *pgd;
@@ -745,7 +747,7 @@ int page_mkclean(struct page *page)
                if (mapping) {
                        ret = page_mkclean_file(mapping, page);
                        if (page_test_dirty(page)) {
-                               page_clear_dirty(page);
+                               page_clear_dirty(page, 1);
                                ret = 1;
                        }
                }
@@ -780,10 +782,10 @@ void page_move_anon_rmap(struct page *page,
 }
 
 /**
- * __page_set_anon_rmap - setup new anonymous rmap
- * @page:      the page to add the mapping to
- * @vma:       the vm area in which the mapping is added
- * @address:   the user virtual address mapped
+ * __page_set_anon_rmap - set up new anonymous rmap
+ * @page:      Page to add to rmap     
+ * @vma:       VM area to add page to.
+ * @address:   User virtual address of the mapping     
  * @exclusive: the page is exclusively owned by the current process
  */
 static void __page_set_anon_rmap(struct page *page,
@@ -793,25 +795,16 @@ static void __page_set_anon_rmap(struct page *page,
 
        BUG_ON(!anon_vma);
 
+       if (PageAnon(page))
+               return;
+
        /*
         * If the page isn't exclusively mapped into this vma,
         * we must use the _oldest_ possible anon_vma for the
         * page mapping!
         */
-       if (!exclusive) {
-               if (PageAnon(page))
-                       return;
+       if (!exclusive)
                anon_vma = anon_vma->root;
-       } else {
-               /*
-                * In this case, swapped-out-but-not-discarded swap-cache
-                * is remapped. So, no need to update page->mapping here.
-                * We convice anon_vma poitned by page->mapping is not obsolete
-                * because vma->anon_vma is necessary to be a family of it.
-                */
-               if (PageAnon(page))
-                       return;
-       }
 
        anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
        page->mapping = (struct address_space *) anon_vma;
@@ -942,7 +935,7 @@ void page_remove_rmap(struct page *page)
         * containing the swap entry, but page not yet written to swap.
         */
        if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) {
-               page_clear_dirty(page);
+               page_clear_dirty(page, 1);
                set_page_dirty(page);
        }
        /*
index 080b09a57a8fab1a4565757d13bb7a4fdb74b74a..f6d350e8adc56da67313a782569e81c34af27286 100644 (file)
@@ -1586,6 +1586,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 
        inode = new_inode(sb);
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode_init_owner(inode, dir, mode);
                inode->i_blocks = 0;
                inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
@@ -1903,7 +1904,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr
        dir->i_size += BOGO_DIRENT_SIZE;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        inc_nlink(inode);
-       atomic_inc(&inode->i_count);    /* New dentry reference */
+       ihold(inode);   /* New dentry reference */
        dget(dentry);           /* Extra pinning count for the created dentry */
        d_instantiate(dentry, inode);
 out:
@@ -2146,7 +2147,7 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
        if (*len < 3)
                return 255;
 
-       if (hlist_unhashed(&inode->i_hash)) {
+       if (inode_unhashed(inode)) {
                /* Unfortunately insert_inode_hash is not idempotent,
                 * so as we hash inodes here rather than at creation
                 * time, we need a lock to ensure we only try
@@ -2154,7 +2155,7 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
                 */
                static DEFINE_SPINLOCK(lock);
                spin_lock(&lock);
-               if (hlist_unhashed(&inode->i_hash))
+               if (inode_unhashed(inode))
                        __insert_inode_hash(inode,
                                            inode->i_ino + inode->i_generation);
                spin_unlock(&lock);
index fcae9815d3b35ce951669e8a404fb71b7a40d34f..b1e40dafbab3cc6326a6913acf17155cbcd8e7f0 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -901,7 +901,7 @@ static int transfer_objects(struct array_cache *to,
                struct array_cache *from, unsigned int max)
 {
        /* Figure out how many entries to transfer */
-       int nr = min(min(from->avail, max), to->limit - to->avail);
+       int nr = min3(from->avail, max, to->limit - to->avail);
 
        if (!nr)
                return 0;
index 9fc7bac7db0c3b3478b49cbcf33a7f906c170b4c..67ddaaf98c744d9e7febe38b0cbdd9cabb55c5b1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/capability.h>
 #include <linux/syscalls.h>
 #include <linux/memcontrol.h>
+#include <linux/poll.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -58,6 +59,10 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
 
 static DEFINE_MUTEX(swapon_mutex);
 
+static DECLARE_WAIT_QUEUE_HEAD(proc_poll_wait);
+/* Activity counter to indicate that a swapon or swapoff has occurred */
+static atomic_t proc_poll_event = ATOMIC_INIT(0);
+
 static inline unsigned char swap_count(unsigned char ent)
 {
        return ent & ~SWAP_HAS_CACHE;   /* may include SWAP_HAS_CONT flag */
@@ -1680,6 +1685,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        }
        filp_close(swap_file, NULL);
        err = 0;
+       atomic_inc(&proc_poll_event);
+       wake_up_interruptible(&proc_poll_wait);
 
 out_dput:
        filp_close(victim, NULL);
@@ -1688,6 +1695,25 @@ out:
 }
 
 #ifdef CONFIG_PROC_FS
+struct proc_swaps {
+       struct seq_file seq;
+       int event;
+};
+
+static unsigned swaps_poll(struct file *file, poll_table *wait)
+{
+       struct proc_swaps *s = file->private_data;
+
+       poll_wait(file, &proc_poll_wait, wait);
+
+       if (s->event != atomic_read(&proc_poll_event)) {
+               s->event = atomic_read(&proc_poll_event);
+               return POLLIN | POLLRDNORM | POLLERR | POLLPRI;
+       }
+
+       return POLLIN | POLLRDNORM;
+}
+
 /* iterator */
 static void *swap_start(struct seq_file *swap, loff_t *pos)
 {
@@ -1771,7 +1797,24 @@ static const struct seq_operations swaps_op = {
 
 static int swaps_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &swaps_op);
+       struct proc_swaps *s;
+       int ret;
+
+       s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       file->private_data = s;
+
+       ret = seq_open(file, &swaps_op);
+       if (ret) {
+               kfree(s);
+               return ret;
+       }
+
+       s->seq.private = s;
+       s->event = atomic_read(&proc_poll_event);
+       return ret;
 }
 
 static const struct file_operations proc_swaps_operations = {
@@ -1779,6 +1822,7 @@ static const struct file_operations proc_swaps_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
+       .poll           = swaps_poll,
 };
 
 static int __init procswaps_init(void)
@@ -2084,6 +2128,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                swap_info[prev]->next = type;
        spin_unlock(&swap_lock);
        mutex_unlock(&swapon_mutex);
+       atomic_inc(&proc_poll_event);
+       wake_up_interruptible(&proc_poll_wait);
+
        error = 0;
        goto out;
 bad_swap:
index 9f909622a25eb9f5ac3f5489465d18c02d961c24..a3d66b3dc5cb0c9136b13764958d6aedf5b10526 100644 (file)
@@ -293,13 +293,13 @@ static void __insert_vmap_area(struct vmap_area *va)
        struct rb_node *tmp;
 
        while (*p) {
-               struct vmap_area *tmp;
+               struct vmap_area *tmp_va;
 
                parent = *p;
-               tmp = rb_entry(parent, struct vmap_area, rb_node);
-               if (va->va_start < tmp->va_end)
+               tmp_va = rb_entry(parent, struct vmap_area, rb_node);
+               if (va->va_start < tmp_va->va_end)
                        p = &(*p)->rb_left;
-               else if (va->va_end > tmp->va_start)
+               else if (va->va_end > tmp_va->va_start)
                        p = &(*p)->rb_right;
                else
                        BUG();
@@ -1596,6 +1596,13 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
 }
 EXPORT_SYMBOL(__vmalloc);
 
+static inline void *__vmalloc_node_flags(unsigned long size,
+                                       int node, gfp_t flags)
+{
+       return __vmalloc_node(size, 1, flags, PAGE_KERNEL,
+                                       node, __builtin_return_address(0));
+}
+
 /**
  *     vmalloc  -  allocate virtually contiguous memory
  *     @size:          allocation size
@@ -1607,11 +1614,27 @@ EXPORT_SYMBOL(__vmalloc);
  */
 void *vmalloc(unsigned long size)
 {
-       return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
-                                       -1, __builtin_return_address(0));
+       return __vmalloc_node_flags(size, -1, GFP_KERNEL | __GFP_HIGHMEM);
 }
 EXPORT_SYMBOL(vmalloc);
 
+/**
+ *     vzalloc - allocate virtually contiguous memory with zero fill
+ *     @size:  allocation size
+ *     Allocate enough pages to cover @size from the page level
+ *     allocator and map them into contiguous kernel virtual space.
+ *     The memory allocated is set to zero.
+ *
+ *     For tight control over page level allocator and protection flags
+ *     use __vmalloc() instead.
+ */
+void *vzalloc(unsigned long size)
+{
+       return __vmalloc_node_flags(size, -1,
+                               GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+}
+EXPORT_SYMBOL(vzalloc);
+
 /**
  * vmalloc_user - allocate zeroed virtually contiguous memory for userspace
  * @size: allocation size
@@ -1653,6 +1676,25 @@ void *vmalloc_node(unsigned long size, int node)
 }
 EXPORT_SYMBOL(vmalloc_node);
 
+/**
+ * vzalloc_node - allocate memory on a specific node with zero fill
+ * @size:      allocation size
+ * @node:      numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc_node() instead.
+ */
+void *vzalloc_node(unsigned long size, int node)
+{
+       return __vmalloc_node_flags(size, node,
+                        GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+}
+EXPORT_SYMBOL(vzalloc_node);
+
 #ifndef PAGE_KERNEL_EXEC
 # define PAGE_KERNEL_EXEC PAGE_KERNEL
 #endif
@@ -2350,6 +2392,7 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
 
 #ifdef CONFIG_PROC_FS
 static void *s_start(struct seq_file *m, loff_t *pos)
+       __acquires(&vmlist_lock)
 {
        loff_t n = *pos;
        struct vm_struct *v;
@@ -2376,6 +2419,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 }
 
 static void s_stop(struct seq_file *m, void *p)
+       __releases(&vmlist_lock)
 {
        read_unlock(&vmlist_lock);
 }
index b94c9464f2620b4e06e4219899114c2274749735..b8a6fdc2131258db15321021375117cae27cec0d 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/vmscan.h>
 
+enum lumpy_mode {
+       LUMPY_MODE_NONE,
+       LUMPY_MODE_ASYNC,
+       LUMPY_MODE_SYNC,
+};
+
 struct scan_control {
        /* Incremented by the number of inactive pages that were scanned */
        unsigned long nr_scanned;
@@ -82,7 +88,7 @@ struct scan_control {
         * Intend to reclaim enough continuous memory rather than reclaim
         * enough amount of memory. i.e, mode for high order allocation.
         */
-       bool lumpy_reclaim_mode;
+       enum lumpy_mode lumpy_reclaim_mode;
 
        /* Which cgroup do we reclaim from */
        struct mem_cgroup *mem_cgroup;
@@ -265,6 +271,36 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
        return ret;
 }
 
+static void set_lumpy_reclaim_mode(int priority, struct scan_control *sc,
+                                  bool sync)
+{
+       enum lumpy_mode mode = sync ? LUMPY_MODE_SYNC : LUMPY_MODE_ASYNC;
+
+       /*
+        * Some reclaim have alredy been failed. No worth to try synchronous
+        * lumpy reclaim.
+        */
+       if (sync && sc->lumpy_reclaim_mode == LUMPY_MODE_NONE)
+               return;
+
+       /*
+        * If we need a large contiguous chunk of memory, or have
+        * trouble getting a small set of contiguous pages, we
+        * will reclaim both active and inactive pages.
+        */
+       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+               sc->lumpy_reclaim_mode = mode;
+       else if (sc->order && priority < DEF_PRIORITY - 2)
+               sc->lumpy_reclaim_mode = mode;
+       else
+               sc->lumpy_reclaim_mode = LUMPY_MODE_NONE;
+}
+
+static void disable_lumpy_reclaim_mode(struct scan_control *sc)
+{
+       sc->lumpy_reclaim_mode = LUMPY_MODE_NONE;
+}
+
 static inline int is_page_cache_freeable(struct page *page)
 {
        /*
@@ -275,7 +311,8 @@ static inline int is_page_cache_freeable(struct page *page)
        return page_count(page) - page_has_private(page) == 2;
 }
 
-static int may_write_to_queue(struct backing_dev_info *bdi)
+static int may_write_to_queue(struct backing_dev_info *bdi,
+                             struct scan_control *sc)
 {
        if (current->flags & PF_SWAPWRITE)
                return 1;
@@ -283,6 +320,10 @@ static int may_write_to_queue(struct backing_dev_info *bdi)
                return 1;
        if (bdi == current->backing_dev_info)
                return 1;
+
+       /* lumpy reclaim for hugepage often need a lot of write */
+       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+               return 1;
        return 0;
 }
 
@@ -307,12 +348,6 @@ static void handle_write_error(struct address_space *mapping,
        unlock_page(page);
 }
 
-/* Request for sync pageout. */
-enum pageout_io {
-       PAGEOUT_IO_ASYNC,
-       PAGEOUT_IO_SYNC,
-};
-
 /* possible outcome of pageout() */
 typedef enum {
        /* failed to write page out, page is locked */
@@ -330,7 +365,7 @@ typedef enum {
  * Calls ->writepage().
  */
 static pageout_t pageout(struct page *page, struct address_space *mapping,
-                                               enum pageout_io sync_writeback)
+                        struct scan_control *sc)
 {
        /*
         * If the page is dirty, only perform writeback if that write
@@ -366,7 +401,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
        }
        if (mapping->a_ops->writepage == NULL)
                return PAGE_ACTIVATE;
-       if (!may_write_to_queue(mapping->backing_dev_info))
+       if (!may_write_to_queue(mapping->backing_dev_info, sc))
                return PAGE_KEEP;
 
        if (clear_page_dirty_for_io(page)) {
@@ -376,7 +411,6 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                        .nr_to_write = SWAP_CLUSTER_MAX,
                        .range_start = 0,
                        .range_end = LLONG_MAX,
-                       .nonblocking = 1,
                        .for_reclaim = 1,
                };
 
@@ -394,7 +428,8 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                 * direct reclaiming a large contiguous area and the
                 * first attempt to free a range of pages fails.
                 */
-               if (PageWriteback(page) && sync_writeback == PAGEOUT_IO_SYNC)
+               if (PageWriteback(page) &&
+                   sc->lumpy_reclaim_mode == LUMPY_MODE_SYNC)
                        wait_on_page_writeback(page);
 
                if (!PageWriteback(page)) {
@@ -402,7 +437,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                        ClearPageReclaim(page);
                }
                trace_mm_vmscan_writepage(page,
-                       trace_reclaim_flags(page, sync_writeback));
+                       trace_reclaim_flags(page, sc->lumpy_reclaim_mode));
                inc_zone_page_state(page, NR_VMSCAN_WRITE);
                return PAGE_SUCCESS;
        }
@@ -580,7 +615,7 @@ static enum page_references page_check_references(struct page *page,
        referenced_page = TestClearPageReferenced(page);
 
        /* Lumpy reclaim - ignore references */
-       if (sc->lumpy_reclaim_mode)
+       if (sc->lumpy_reclaim_mode != LUMPY_MODE_NONE)
                return PAGEREF_RECLAIM;
 
        /*
@@ -616,7 +651,7 @@ static enum page_references page_check_references(struct page *page,
        }
 
        /* Reclaim if clean, defer dirty pages to writeback */
-       if (referenced_page)
+       if (referenced_page && !PageSwapBacked(page))
                return PAGEREF_RECLAIM_CLEAN;
 
        return PAGEREF_RECLAIM;
@@ -644,12 +679,14 @@ static noinline_for_stack void free_page_list(struct list_head *free_pages)
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-                                       struct scan_control *sc,
-                                       enum pageout_io sync_writeback)
+                                     struct zone *zone,
+                                     struct scan_control *sc)
 {
        LIST_HEAD(ret_pages);
        LIST_HEAD(free_pages);
        int pgactivate = 0;
+       unsigned long nr_dirty = 0;
+       unsigned long nr_congested = 0;
        unsigned long nr_reclaimed = 0;
 
        cond_resched();
@@ -669,6 +706,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        goto keep;
 
                VM_BUG_ON(PageActive(page));
+               VM_BUG_ON(page_zone(page) != zone);
 
                sc->nr_scanned++;
 
@@ -694,10 +732,13 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                         * for any page for which writeback has already
                         * started.
                         */
-                       if (sync_writeback == PAGEOUT_IO_SYNC && may_enter_fs)
+                       if (sc->lumpy_reclaim_mode == LUMPY_MODE_SYNC &&
+                           may_enter_fs)
                                wait_on_page_writeback(page);
-                       else
-                               goto keep_locked;
+                       else {
+                               unlock_page(page);
+                               goto keep_lumpy;
+                       }
                }
 
                references = page_check_references(page, sc);
@@ -743,6 +784,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                }
 
                if (PageDirty(page)) {
+                       nr_dirty++;
+
                        if (references == PAGEREF_RECLAIM_CLEAN)
                                goto keep_locked;
                        if (!may_enter_fs)
@@ -751,14 +794,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                goto keep_locked;
 
                        /* Page is dirty, try to write it out here */
-                       switch (pageout(page, mapping, sync_writeback)) {
+                       switch (pageout(page, mapping, sc)) {
                        case PAGE_KEEP:
+                               nr_congested++;
                                goto keep_locked;
                        case PAGE_ACTIVATE:
                                goto activate_locked;
                        case PAGE_SUCCESS:
-                               if (PageWriteback(page) || PageDirty(page))
+                               if (PageWriteback(page))
+                                       goto keep_lumpy;
+                               if (PageDirty(page))
                                        goto keep;
+
                                /*
                                 * A synchronous write - probably a ramdisk.  Go
                                 * ahead and try to reclaim the page.
@@ -841,6 +888,7 @@ cull_mlocked:
                        try_to_free_swap(page);
                unlock_page(page);
                putback_lru_page(page);
+               disable_lumpy_reclaim_mode(sc);
                continue;
 
 activate_locked:
@@ -853,10 +901,21 @@ activate_locked:
 keep_locked:
                unlock_page(page);
 keep:
+               disable_lumpy_reclaim_mode(sc);
+keep_lumpy:
                list_add(&page->lru, &ret_pages);
                VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
        }
 
+       /*
+        * Tag a zone as congested if all the dirty pages encountered were
+        * backed by a congested BDI. In this case, reclaimers should just
+        * back off and wait for congestion to clear because further reclaim
+        * will encounter the same problem
+        */
+       if (nr_dirty == nr_congested)
+               zone_set_flag(zone, ZONE_CONGESTED);
+
        free_page_list(&free_pages);
 
        list_splice(&ret_pages, page_list);
@@ -1006,7 +1065,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                        /* Check that we have not crossed a zone boundary. */
                        if (unlikely(page_zone_id(cursor_page) != zone_id))
-                               continue;
+                               break;
 
                        /*
                         * If we don't have enough swap space, reclaiming of
@@ -1014,8 +1073,8 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                         * pointless.
                         */
                        if (nr_swap_pages <= 0 && PageAnon(cursor_page) &&
-                                       !PageSwapCache(cursor_page))
-                               continue;
+                           !PageSwapCache(cursor_page))
+                               break;
 
                        if (__isolate_lru_page(cursor_page, mode, file) == 0) {
                                list_move(&cursor_page->lru, dst);
@@ -1026,11 +1085,16 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                                        nr_lumpy_dirty++;
                                scan++;
                        } else {
-                               if (mode == ISOLATE_BOTH &&
-                                               page_count(cursor_page))
-                                       nr_lumpy_failed++;
+                               /* the page is freed already. */
+                               if (!page_count(cursor_page))
+                                       continue;
+                               break;
                        }
                }
+
+               /* If we break out of the loop above, lumpy reclaim failed */
+               if (pfn < end_pfn)
+                       nr_lumpy_failed++;
        }
 
        *scanned = scan;
@@ -1253,7 +1317,7 @@ static inline bool should_reclaim_stall(unsigned long nr_taken,
                return false;
 
        /* Only stall on lumpy reclaim */
-       if (!sc->lumpy_reclaim_mode)
+       if (sc->lumpy_reclaim_mode == LUMPY_MODE_NONE)
                return false;
 
        /* If we have relaimed everything on the isolated list, no stall */
@@ -1286,7 +1350,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        unsigned long nr_scanned;
        unsigned long nr_reclaimed = 0;
        unsigned long nr_taken;
-       unsigned long nr_active;
        unsigned long nr_anon;
        unsigned long nr_file;
 
@@ -1298,15 +1361,15 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                        return SWAP_CLUSTER_MAX;
        }
 
-
+       set_lumpy_reclaim_mode(priority, sc, false);
        lru_add_drain();
        spin_lock_irq(&zone->lru_lock);
 
        if (scanning_global_lru(sc)) {
                nr_taken = isolate_pages_global(nr_to_scan,
                        &page_list, &nr_scanned, sc->order,
-                       sc->lumpy_reclaim_mode ?
-                               ISOLATE_BOTH : ISOLATE_INACTIVE,
+                       sc->lumpy_reclaim_mode == LUMPY_MODE_NONE ?
+                                       ISOLATE_INACTIVE : ISOLATE_BOTH,
                        zone, 0, file);
                zone->pages_scanned += nr_scanned;
                if (current_is_kswapd())
@@ -1318,8 +1381,8 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        } else {
                nr_taken = mem_cgroup_isolate_pages(nr_to_scan,
                        &page_list, &nr_scanned, sc->order,
-                       sc->lumpy_reclaim_mode ?
-                               ISOLATE_BOTH : ISOLATE_INACTIVE,
+                       sc->lumpy_reclaim_mode == LUMPY_MODE_NONE ?
+                                       ISOLATE_INACTIVE : ISOLATE_BOTH,
                        zone, sc->mem_cgroup,
                        0, file);
                /*
@@ -1337,20 +1400,12 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
 
        spin_unlock_irq(&zone->lru_lock);
 
-       nr_reclaimed = shrink_page_list(&page_list, sc, PAGEOUT_IO_ASYNC);
+       nr_reclaimed = shrink_page_list(&page_list, zone, sc);
 
        /* Check if we should syncronously wait for writeback */
        if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
-               congestion_wait(BLK_RW_ASYNC, HZ/10);
-
-               /*
-                * The attempt at page out may have made some
-                * of the pages active, mark them inactive again.
-                */
-               nr_active = clear_active_flags(&page_list, NULL);
-               count_vm_events(PGDEACTIVATE, nr_active);
-
-               nr_reclaimed += shrink_page_list(&page_list, sc, PAGEOUT_IO_SYNC);
+               set_lumpy_reclaim_mode(priority, sc, true);
+               nr_reclaimed += shrink_page_list(&page_list, zone, sc);
        }
 
        local_irq_disable();
@@ -1359,6 +1414,12 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        __count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
 
        putback_lru_pages(zone, sc, nr_anon, nr_file, &page_list);
+
+       trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
+               zone_idx(zone),
+               nr_scanned, nr_reclaimed,
+               priority,
+               trace_shrink_flags(file, sc->lumpy_reclaim_mode));
        return nr_reclaimed;
 }
 
@@ -1506,6 +1567,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        spin_unlock_irq(&zone->lru_lock);
 }
 
+#ifdef CONFIG_SWAP
 static int inactive_anon_is_low_global(struct zone *zone)
 {
        unsigned long active, inactive;
@@ -1531,12 +1593,26 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
 {
        int low;
 
+       /*
+        * If we don't have swap space, anonymous page deactivation
+        * is pointless.
+        */
+       if (!total_swap_pages)
+               return 0;
+
        if (scanning_global_lru(sc))
                low = inactive_anon_is_low_global(zone);
        else
                low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup);
        return low;
 }
+#else
+static inline int inactive_anon_is_low(struct zone *zone,
+                                       struct scan_control *sc)
+{
+       return 0;
+}
+#endif
 
 static int inactive_file_is_low_global(struct zone *zone)
 {
@@ -1721,21 +1797,6 @@ out:
        }
 }
 
-static void set_lumpy_reclaim_mode(int priority, struct scan_control *sc)
-{
-       /*
-        * If we need a large contiguous chunk of memory, or have
-        * trouble getting a small set of contiguous pages, we
-        * will reclaim both active and inactive pages.
-        */
-       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-               sc->lumpy_reclaim_mode = 1;
-       else if (sc->order && priority < DEF_PRIORITY - 2)
-               sc->lumpy_reclaim_mode = 1;
-       else
-               sc->lumpy_reclaim_mode = 0;
-}
-
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
@@ -1750,8 +1811,6 @@ static void shrink_zone(int priority, struct zone *zone,
 
        get_scan_count(zone, sc, nr, priority);
 
-       set_lumpy_reclaim_mode(priority, sc);
-
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
                for_each_evictable_lru(l) {
@@ -1782,7 +1841,7 @@ static void shrink_zone(int priority, struct zone *zone,
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_anon_is_low(zone, sc) && nr_swap_pages > 0)
+       if (inactive_anon_is_low(zone, sc))
                shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0);
 
        throttle_vm_writeout(sc->gfp_mask);
@@ -1937,21 +1996,16 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
 
                /* Take a nap, wait for some writeback to complete */
                if (!sc->hibernation_mode && sc->nr_scanned &&
-                   priority < DEF_PRIORITY - 2)
-                       congestion_wait(BLK_RW_ASYNC, HZ/10);
+                   priority < DEF_PRIORITY - 2) {
+                       struct zone *preferred_zone;
+
+                       first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
+                                                       NULL, &preferred_zone);
+                       wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
+               }
        }
 
 out:
-       /*
-        * Now that we've scanned all the zones at this priority level, note
-        * that level within the zone so that the next thread which performs
-        * scanning of this zone will immediately start out at this priority
-        * level.  This affects only the decision whether or not to bring
-        * mapped pages onto the inactive list.
-        */
-       if (priority < 0)
-               priority = 0;
-
        delayacct_freepages_end();
        put_mems_allowed();
 
@@ -2247,6 +2301,15 @@ loop_again:
                                if (!zone_watermark_ok(zone, order,
                                            min_wmark_pages(zone), end_zone, 0))
                                        has_under_min_watermark_zone = 1;
+                       } else {
+                               /*
+                                * If a zone reaches its high watermark,
+                                * consider it to be no longer congested. It's
+                                * possible there are dirty pages backed by
+                                * congested BDIs but as pressure is relieved,
+                                * spectulatively avoid congestion waits
+                                */
+                               zone_clear_flag(zone, ZONE_CONGESTED);
                        }
 
                }
@@ -2987,6 +3050,7 @@ int scan_unevictable_handler(struct ctl_table *table, int write,
        return 0;
 }
 
+#ifdef CONFIG_NUMA
 /*
  * per node 'scan_unevictable_pages' attribute.  On demand re-scan of
  * a specified node's per zone unevictable lists for evictable pages.
@@ -3033,4 +3097,4 @@ void scan_unevictable_unregister_node(struct node *node)
 {
        sysdev_remove_file(&node->sysdev, &attr_scan_unevictable_pages);
 }
-
+#endif
index 355a9e669aaa800d62fa31d2b83110bf76cce9d7..cd2e42be7b68f73dc60f40631f2b9f87708d3b47 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/vmstat.h>
 #include <linux/sched.h>
 #include <linux/math64.h>
+#include <linux/writeback.h>
+#include <linux/compaction.h>
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
 DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -394,6 +396,7 @@ void zone_statistics(struct zone *preferred_zone, struct zone *z)
 #endif
 
 #ifdef CONFIG_COMPACTION
+
 struct contig_page_info {
        unsigned long free_pages;
        unsigned long free_blocks_total;
@@ -745,6 +748,11 @@ static const char * const vmstat_text[] = {
        "nr_isolated_anon",
        "nr_isolated_file",
        "nr_shmem",
+       "nr_dirtied",
+       "nr_written",
+       "nr_dirty_threshold",
+       "nr_dirty_background_threshold",
+
 #ifdef CONFIG_NUMA
        "numa_hit",
        "numa_miss",
@@ -904,36 +912,44 @@ static const struct file_operations proc_zoneinfo_file_operations = {
        .release        = seq_release,
 };
 
+enum writeback_stat_item {
+       NR_DIRTY_THRESHOLD,
+       NR_DIRTY_BG_THRESHOLD,
+       NR_VM_WRITEBACK_STAT_ITEMS,
+};
+
 static void *vmstat_start(struct seq_file *m, loff_t *pos)
 {
        unsigned long *v;
-#ifdef CONFIG_VM_EVENT_COUNTERS
-       unsigned long *e;
-#endif
-       int i;
+       int i, stat_items_size;
 
        if (*pos >= ARRAY_SIZE(vmstat_text))
                return NULL;
+       stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
+                         NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
-       v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
-                       + sizeof(struct vm_event_state), GFP_KERNEL);
-#else
-       v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
-                       GFP_KERNEL);
+       stat_items_size += sizeof(struct vm_event_state);
 #endif
+
+       v = kmalloc(stat_items_size, GFP_KERNEL);
        m->private = v;
        if (!v)
                return ERR_PTR(-ENOMEM);
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
                v[i] = global_page_state(i);
+       v += NR_VM_ZONE_STAT_ITEMS;
+
+       global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
+                           v + NR_DIRTY_THRESHOLD);
+       v += NR_VM_WRITEBACK_STAT_ITEMS;
+
 #ifdef CONFIG_VM_EVENT_COUNTERS
-       e = v + NR_VM_ZONE_STAT_ITEMS;
-       all_vm_events(e);
-       e[PGPGIN] /= 2;         /* sectors -> kbytes */
-       e[PGPGOUT] /= 2;
+       all_vm_events(v);
+       v[PGPGIN] /= 2;         /* sectors -> kbytes */
+       v[PGPGOUT] /= 2;
 #endif
-       return v + *pos;
+       return m->private + *pos;
 }
 
 static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
index 499c045d69102aa45dc3a2d1f50cb55dc55a2c8f..f7db676de77d7568b463df2b8a7db770a0f090e7 100644 (file)
@@ -1798,7 +1798,8 @@ static void iucv_work_fn(struct work_struct *work)
  * Handles external interrupts coming in from CP.
  * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
  */
-static void iucv_external_interrupt(u16 code)
+static void iucv_external_interrupt(unsigned int ext_int_code,
+                                   unsigned int param32, unsigned long param64)
 {
        struct iucv_irq_data *p;
        struct iucv_irq_list *work;
index abf3e2561521acc1ce82167b9edaf71eaf263ee9..ee3cd280c76e9cfb58024fa22f3017352f0467bc 100644 (file)
@@ -377,7 +377,7 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
                  &socket_file_ops);
        if (unlikely(!file)) {
                /* drop dentry, keep inode */
-               atomic_inc(&path.dentry->d_inode->i_count);
+               ihold(path.dentry->d_inode);
                path_put(&path);
                put_unused_fd(fd);
                return -ENFILE;
@@ -480,6 +480,7 @@ static struct socket *sock_alloc(void)
        sock = SOCKET_I(inode);
 
        kmemcheck_annotate_bitfield(sock, type);
+       inode->i_ino = get_next_ino();
        inode->i_mode = S_IFSOCK | S_IRWXUGO;
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
@@ -1145,7 +1146,7 @@ call_kill:
 }
 EXPORT_SYMBOL(sock_wake_async);
 
-static int __sock_create(struct net *net, int family, int type, int protocol,
+int __sock_create(struct net *net, int family, int type, int protocol,
                         struct socket **res, int kern)
 {
        int err;
@@ -1257,6 +1258,7 @@ out_release:
        rcu_read_unlock();
        goto out_sock_release;
 }
+EXPORT_SYMBOL(__sock_create);
 
 int sock_create(int family, int type, int protocol, struct socket **res)
 {
index 3376d7657185324adf2afef79984369bd16984ff..8873fd8ddacd261ac03bc1bb7d5b7a236579baee 100644 (file)
@@ -36,22 +36,3 @@ config RPCSEC_GSS_KRB5
          Kerberos support should be installed.
 
          If unsure, say Y.
-
-config RPCSEC_GSS_SPKM3
-       tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
-       depends on SUNRPC && EXPERIMENTAL
-       select SUNRPC_GSS
-       select CRYPTO
-       select CRYPTO_MD5
-       select CRYPTO_DES
-       select CRYPTO_CAST5
-       select CRYPTO_CBC
-       help
-         Choose Y here to enable Secure RPC using the SPKM3 public key
-         GSS-API mechanism (RFC 2025).
-
-         Secure RPC calls with SPKM3 require an auxiliary userspace
-         daemon which may be found in the Linux nfs-utils package
-         available from http://linux-nfs.org/.
-
-         If unsure, say N.
index e9eaaf7d43c18104167692f801794bdacf89b97e..afe67849269f52faaad4ee242d47d5645ad4005f 100644 (file)
@@ -595,7 +595,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
 int
 rpcauth_refreshcred(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
+       struct rpc_cred *cred;
        int err;
 
        cred = task->tk_rqstp->rq_cred;
@@ -658,7 +658,7 @@ out1:
        return err;
 }
 
-void __exit rpcauth_remove_module(void)
+void rpcauth_remove_module(void)
 {
        rpc_destroy_authunix();
        rpc_destroy_generic_auth();
index 43162bb3b78f47cb30c6054907839f92281f4c92..e010a015d99671f27a22573a31eae75ae6cda955 100644 (file)
@@ -158,7 +158,7 @@ int __init rpc_init_generic_auth(void)
        return rpcauth_init_credcache(&generic_auth);
 }
 
-void __exit rpc_destroy_generic_auth(void)
+void rpc_destroy_generic_auth(void)
 {
        rpcauth_destroy_credcache(&generic_auth);
 }
index 74a231735f6773cd5531c89cddbdef8573ebf65e..7350d86a32ee00ab254978e7237dbfe176c05638 100644 (file)
@@ -11,8 +11,3 @@ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
 
 rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
        gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o
-
-obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
-
-rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
-       gss_spkm3_token.o
index 778e5dfc5144910f83609b8bf48ca2a35011110d..f375decc024b4bbd176ee448fc72e26fc4cd020c 100644 (file)
@@ -427,7 +427,7 @@ static int
 context_derive_keys_rc4(struct krb5_ctx *ctx)
 {
        struct crypto_hash *hmac;
-       char sigkeyconstant[] = "signaturekey";
+       static const char sigkeyconstant[] = "signaturekey";
        int slen = strlen(sigkeyconstant) + 1;  /* include null terminator */
        struct hash_desc desc;
        struct scatterlist sg[1];
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
deleted file mode 100644 (file)
index adade3d..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- *  linux/net/sunrpc/gss_spkm3_mech.c
- *
- *  Copyright (c) 2003 The Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  Andy Adamson <andros@umich.edu>
- *  J. Bruce Fields <bfields@umich.edu>
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *  3. Neither the name of the University nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/sunrpc/auth.h>
-#include <linux/in.h>
-#include <linux/sunrpc/svcauth_gss.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/sunrpc/xdr.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY       RPCDBG_AUTH
-#endif
-
-static const void *
-simple_get_bytes(const void *p, const void *end, void *res, int len)
-{
-       const void *q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       memcpy(res, p, len);
-       return q;
-}
-
-static const void *
-simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
-{
-       const void *q;
-       unsigned int len;
-       p = simple_get_bytes(p, end, &len, sizeof(len));
-       if (IS_ERR(p))
-               return p;
-       res->len = len;
-       if (len == 0) {
-               res->data = NULL;
-               return p;
-       }
-       q = (const void *)((const char *)p + len);
-       if (unlikely(q > end || q < p))
-               return ERR_PTR(-EFAULT);
-       res->data = kmemdup(p, len, GFP_NOFS);
-       if (unlikely(res->data == NULL))
-               return ERR_PTR(-ENOMEM);
-       return q;
-}
-
-static int
-gss_import_sec_context_spkm3(const void *p, size_t len,
-                               struct gss_ctx *ctx_id,
-                               gfp_t gfp_mask)
-{
-       const void *end = (const void *)((const char *)p + len);
-       struct  spkm3_ctx *ctx;
-       int     version;
-
-       if (!(ctx = kzalloc(sizeof(*ctx), gfp_mask)))
-               goto out_err;
-
-       p = simple_get_bytes(p, end, &version, sizeof(version));
-       if (IS_ERR(p))
-               goto out_err_free_ctx;
-       if (version != 1) {
-               dprintk("RPC:       unknown spkm3 token format: "
-                               "obsolete nfs-utils?\n");
-               p = ERR_PTR(-EINVAL);
-               goto out_err_free_ctx;
-       }
-
-       p = simple_get_netobj(p, end, &ctx->ctx_id);
-       if (IS_ERR(p))
-               goto out_err_free_ctx;
-
-       p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
-       if (IS_ERR(p))
-               goto out_err_free_ctx_id;
-
-       p = simple_get_netobj(p, end, &ctx->mech_used);
-       if (IS_ERR(p))
-               goto out_err_free_ctx_id;
-
-       p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags));
-       if (IS_ERR(p))
-               goto out_err_free_mech;
-
-       p = simple_get_netobj(p, end, &ctx->conf_alg);
-       if (IS_ERR(p))
-               goto out_err_free_mech;
-
-       p = simple_get_netobj(p, end, &ctx->derived_conf_key);
-       if (IS_ERR(p))
-               goto out_err_free_conf_alg;
-
-       p = simple_get_netobj(p, end, &ctx->intg_alg);
-       if (IS_ERR(p))
-               goto out_err_free_conf_key;
-
-       p = simple_get_netobj(p, end, &ctx->derived_integ_key);
-       if (IS_ERR(p))
-               goto out_err_free_intg_alg;
-
-       if (p != end) {
-               p = ERR_PTR(-EFAULT);
-               goto out_err_free_intg_key;
-       }
-
-       ctx_id->internal_ctx_id = ctx;
-
-       dprintk("RPC:       Successfully imported new spkm context.\n");
-       return 0;
-
-out_err_free_intg_key:
-       kfree(ctx->derived_integ_key.data);
-out_err_free_intg_alg:
-       kfree(ctx->intg_alg.data);
-out_err_free_conf_key:
-       kfree(ctx->derived_conf_key.data);
-out_err_free_conf_alg:
-       kfree(ctx->conf_alg.data);
-out_err_free_mech:
-       kfree(ctx->mech_used.data);
-out_err_free_ctx_id:
-       kfree(ctx->ctx_id.data);
-out_err_free_ctx:
-       kfree(ctx);
-out_err:
-       return PTR_ERR(p);
-}
-
-static void
-gss_delete_sec_context_spkm3(void *internal_ctx)
-{
-       struct spkm3_ctx *sctx = internal_ctx;
-
-       kfree(sctx->derived_integ_key.data);
-       kfree(sctx->intg_alg.data);
-       kfree(sctx->derived_conf_key.data);
-       kfree(sctx->conf_alg.data);
-       kfree(sctx->mech_used.data);
-       kfree(sctx->ctx_id.data);
-       kfree(sctx);
-}
-
-static u32
-gss_verify_mic_spkm3(struct gss_ctx            *ctx,
-                       struct xdr_buf          *signbuf,
-                       struct xdr_netobj       *checksum)
-{
-       u32 maj_stat = 0;
-       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
-
-       maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK);
-
-       dprintk("RPC:       gss_verify_mic_spkm3 returning %d\n", maj_stat);
-       return maj_stat;
-}
-
-static u32
-gss_get_mic_spkm3(struct gss_ctx       *ctx,
-                    struct xdr_buf     *message_buffer,
-                    struct xdr_netobj  *message_token)
-{
-       u32 err = 0;
-       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
-
-       err = spkm3_make_token(sctx, message_buffer,
-                               message_token, SPKM_MIC_TOK);
-       dprintk("RPC:       gss_get_mic_spkm3 returning %d\n", err);
-       return err;
-}
-
-static const struct gss_api_ops gss_spkm3_ops = {
-       .gss_import_sec_context = gss_import_sec_context_spkm3,
-       .gss_get_mic            = gss_get_mic_spkm3,
-       .gss_verify_mic         = gss_verify_mic_spkm3,
-       .gss_delete_sec_context = gss_delete_sec_context_spkm3,
-};
-
-static struct pf_desc gss_spkm3_pfs[] = {
-       {RPC_AUTH_GSS_SPKM, RPC_GSS_SVC_NONE, "spkm3"},
-       {RPC_AUTH_GSS_SPKMI, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
-};
-
-static struct gss_api_mech gss_spkm3_mech = {
-       .gm_name        = "spkm3",
-       .gm_owner       = THIS_MODULE,
-       .gm_oid         = {7, "\053\006\001\005\005\001\003"},
-       .gm_ops         = &gss_spkm3_ops,
-       .gm_pf_num      = ARRAY_SIZE(gss_spkm3_pfs),
-       .gm_pfs         = gss_spkm3_pfs,
-};
-
-static int __init init_spkm3_module(void)
-{
-       int status;
-
-       status = gss_mech_register(&gss_spkm3_mech);
-       if (status)
-               printk("Failed to register spkm3 gss mechanism!\n");
-       return status;
-}
-
-static void __exit cleanup_spkm3_module(void)
-{
-       gss_mech_unregister(&gss_spkm3_mech);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_spkm3_module);
-module_exit(cleanup_spkm3_module);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
deleted file mode 100644 (file)
index 5a3a65a..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *  linux/net/sunrpc/gss_spkm3_seal.c
- *
- *  Copyright (c) 2003 The Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  Andy Adamson <andros@umich.edu>
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *  3. Neither the name of the University nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <linux/types.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/random.h>
-#include <linux/crypto.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-#include <linux/sunrpc/xdr.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY        RPCDBG_AUTH
-#endif
-
-const struct xdr_netobj hmac_md5_oid = { 8, "\x2B\x06\x01\x05\x05\x08\x01\x01"};
-const struct xdr_netobj cast5_cbc_oid = {9, "\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A"};
-
-/*
- * spkm3_make_token()
- *
- * Only SPKM_MIC_TOK with md5 intg-alg is supported
- */
-
-u32
-spkm3_make_token(struct spkm3_ctx *ctx,
-                  struct xdr_buf * text, struct xdr_netobj * token,
-                  int toktype)
-{
-       s32                     checksum_type;
-       char                    tokhdrbuf[25];
-       char                    cksumdata[16];
-       struct xdr_netobj       md5cksum = {.len = 0, .data = cksumdata};
-       struct xdr_netobj       mic_hdr = {.len = 0, .data = tokhdrbuf};
-       int                     tokenlen = 0;
-       unsigned char           *ptr;
-       s32                     now;
-       int                     ctxelen = 0, ctxzbit = 0;
-       int                     md5elen = 0, md5zbit = 0;
-
-       now = jiffies;
-
-       if (ctx->ctx_id.len != 16) {
-               dprintk("RPC:       spkm3_make_token BAD ctx_id.len %d\n",
-                               ctx->ctx_id.len);
-               goto out_err;
-       }
-
-       if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
-               dprintk("RPC:       gss_spkm3_seal: unsupported I-ALG "
-                               "algorithm.  only support hmac-md5 I-ALG.\n");
-               goto out_err;
-       } else
-               checksum_type = CKSUMTYPE_HMAC_MD5;
-
-       if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) {
-               dprintk("RPC:       gss_spkm3_seal: unsupported C-ALG "
-                               "algorithm\n");
-               goto out_err;
-       }
-
-       if (toktype == SPKM_MIC_TOK) {
-               /* Calculate checksum over the mic-header */
-               asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
-               spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
-                               ctxelen, ctxzbit);
-               if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key,
-                                       (char *)mic_hdr.data, mic_hdr.len,
-                                       text, 0, &md5cksum))
-                       goto out_err;
-
-               asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
-               tokenlen = 10 + ctxelen + 1 + md5elen + 1;
-
-               /* Create token header using generic routines */
-               token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
-
-               ptr = token->data;
-               g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
-
-               spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
-       } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
-               dprintk("RPC:       gss_spkm3_seal: SPKM_WRAP_TOK "
-                               "not supported\n");
-               goto out_err;
-       }
-
-       /* XXX need to implement sequence numbers, and ctx->expired */
-
-       return  GSS_S_COMPLETE;
-out_err:
-       token->data = NULL;
-       token->len = 0;
-       return GSS_S_FAILURE;
-}
-
-static int
-spkm3_checksummer(struct scatterlist *sg, void *data)
-{
-       struct hash_desc *desc = data;
-
-       return crypto_hash_update(desc, sg, sg->length);
-}
-
-/* checksum the plaintext data and hdrlen bytes of the token header */
-s32
-make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
-                   unsigned int hdrlen, struct xdr_buf *body,
-                   unsigned int body_offset, struct xdr_netobj *cksum)
-{
-       char                            *cksumname;
-       struct hash_desc                desc; /* XXX add to ctx? */
-       struct scatterlist              sg[1];
-       int err;
-
-       switch (cksumtype) {
-               case CKSUMTYPE_HMAC_MD5:
-                       cksumname = "hmac(md5)";
-                       break;
-               default:
-                       dprintk("RPC:       spkm3_make_checksum:"
-                                       " unsupported checksum %d", cksumtype);
-                       return GSS_S_FAILURE;
-       }
-
-       if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE;
-
-       desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(desc.tfm))
-               return GSS_S_FAILURE;
-       cksum->len = crypto_hash_digestsize(desc.tfm);
-       desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-
-       err = crypto_hash_setkey(desc.tfm, key->data, key->len);
-       if (err)
-               goto out;
-
-       err = crypto_hash_init(&desc);
-       if (err)
-               goto out;
-
-       sg_init_one(sg, header, hdrlen);
-       crypto_hash_update(&desc, sg, sg->length);
-
-       xdr_process_buf(body, body_offset, body->len - body_offset,
-                       spkm3_checksummer, &desc);
-       crypto_hash_final(&desc, cksum->data);
-
-out:
-       crypto_free_hash(desc.tfm);
-
-       return err ? GSS_S_FAILURE : 0;
-}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
deleted file mode 100644 (file)
index a99825d..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- *  linux/net/sunrpc/gss_spkm3_token.c
- *
- *  Copyright (c) 2003 The Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  Andy Adamson <andros@umich.edu>
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *  3. Neither the name of the University nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/random.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY        RPCDBG_AUTH
-#endif
-
-/*
- * asn1_bitstring_len()
- *
- * calculate the asn1 bitstring length of the xdr_netobject
- */
-void
-asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
-{
-       int i, zbit = 0,elen = in->len;
-       char *ptr;
-
-       ptr = &in->data[in->len -1];
-
-       /* count trailing 0's */
-       for(i = in->len; i > 0; i--) {
-               if (*ptr == 0) {
-                       ptr--;
-                       elen--;
-               } else
-                       break;
-       }
-
-       /* count number of 0 bits in final octet */
-       ptr = &in->data[elen - 1];
-       for(i = 0; i < 8; i++) {
-               short mask = 0x01;
-
-               if (!((mask << i) & *ptr))
-                       zbit++;
-               else
-                       break;
-       }
-       *enclen = elen;
-       *zerobits = zbit;
-}
-
-/*
- * decode_asn1_bitstring()
- *
- * decode a bitstring into a buffer of the expected length.
- * enclen = bit string length
- * explen = expected length (define in rfc)
- */
-int
-decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
-{
-       if (!(out->data = kzalloc(explen,GFP_NOFS)))
-               return 0;
-       out->len = explen;
-       memcpy(out->data, in, enclen);
-       return 1;
-}
-
-/*
- * SPKMInnerContextToken choice SPKM_MIC asn1 token layout
- *
- * contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
- *
- * tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
- *
- * pos  value
- * ----------
- * [0] a4  SPKM-MIC tag
- * [1] ??  innertoken length  (max 44)
- *
- *
- * tok_hdr piece of checksum data starts here
- *
- * the maximum mic-header len = 9 + 17 = 26
- *     mic-header
- *     ----------
- * [2] 30      SEQUENCE tag
- * [3] ??      mic-header length: (max 23) = TokenID + ContextID
- *
- *             TokenID  - all fields constant and can be hardcoded
- *             -------
- * [4]   02    Type 2
- * [5]   02    Length 2
- * [6][7] 01 01        TokenID (SPKM_MIC_TOK)
- *
- *             ContextID  - encoded length not constant, calculated
- *             ---------
- * [8] 03      Type 3
- * [9] ??      encoded length
- * [10]        ??      ctxzbit
- * [11]                contextid
- *
- * mic_header piece of checksum data ends here.
- *
- *     int-cksum - encoded length not constant, calculated
- *     ---------
- * [??]        03      Type 3
- * [??]        ??      encoded length
- * [??]        ??      md5zbit
- * [??]                int-cksum (NID_md5 = 16)
- *
- * maximum SPKM-MIC innercontext token length =
- *      10 + encoded contextid_size(17 max) + 2 + encoded
- *       cksum_size (17 maxfor NID_md5) = 46
- */
-
-/*
- * spkm3_mic_header()
- *
- * Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
- * elen: 16 byte context id asn1 bitstring encoded length
- */
-void
-spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
-{
-       char *hptr = *hdrbuf;
-       char *top = *hdrbuf;
-
-       *(u8 *)hptr++ = 0x30;
-       *(u8 *)hptr++ = elen + 7;  /* on the wire header length */
-
-       /* tokenid */
-       *(u8 *)hptr++ = 0x02;
-       *(u8 *)hptr++ = 0x02;
-       *(u8 *)hptr++ = 0x01;
-       *(u8 *)hptr++ = 0x01;
-
-       /* coniextid */
-       *(u8 *)hptr++ = 0x03;
-       *(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
-       *(u8 *)hptr++ = zbit;
-       memcpy(hptr, ctxdata, elen);
-       hptr += elen;
-       *hdrlen = hptr - top;
-}
-
-/*
- * spkm3_mic_innercontext_token()
- *
- * *tokp points to the beginning of the SPKM_MIC token  described
- * in rfc 2025, section 3.2.1:
- *
- * toklen is the inner token length
- */
-void
-spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
-{
-       unsigned char *ict = *tokp;
-
-       *(u8 *)ict++ = 0xa4;
-       *(u8 *)ict++ = toklen;
-       memcpy(ict, mic_hdr->data, mic_hdr->len);
-       ict += mic_hdr->len;
-
-       *(u8 *)ict++ = 0x03;
-       *(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
-       *(u8 *)ict++ = md5zbit;
-       memcpy(ict, md5cksum->data, md5elen);
-}
-
-u32
-spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
-{
-       struct xdr_netobj       spkm3_ctx_id = {.len =0, .data = NULL};
-       unsigned char           *ptr = *tokp;
-       int                     ctxelen;
-       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
-
-       /* spkm3 innercontext token preamble */
-       if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
-               dprintk("RPC:       BAD SPKM ictoken preamble\n");
-               goto out;
-       }
-
-       *mic_hdrlen = ptr[3];
-
-       /* token type */
-       if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
-               dprintk("RPC:       BAD asn1 SPKM3 token type\n");
-               goto out;
-       }
-
-       /* only support SPKM_MIC_TOK */
-       if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
-               dprintk("RPC:       ERROR unsupported SPKM3 token\n");
-               goto out;
-       }
-
-       /* contextid */
-       if (ptr[8] != 0x03) {
-               dprintk("RPC:       BAD SPKM3 asn1 context-id type\n");
-               goto out;
-       }
-
-       ctxelen = ptr[9];
-       if (ctxelen > 17) {  /* length includes asn1 zbit octet */
-               dprintk("RPC:       BAD SPKM3 contextid len %d\n", ctxelen);
-               goto out;
-       }
-
-       /* ignore ptr[10] */
-
-       if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
-               goto out;
-
-       /*
-       * in the current implementation: the optional int-alg is not present
-       * so the default int-alg (md5) is used the optional snd-seq field is
-       * also not present
-       */
-
-       if (*mic_hdrlen != 6 + ctxelen) {
-               dprintk("RPC:       BAD SPKM_ MIC_TOK header len %d: we only "
-                               "support default int-alg (should be absent) "
-                               "and do not support snd-seq\n", *mic_hdrlen);
-               goto out;
-       }
-       /* checksum */
-       *cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
-
-       ret = GSS_S_COMPLETE;
-out:
-       kfree(spkm3_ctx_id.data);
-       return ret;
-}
-
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
deleted file mode 100644 (file)
index cc21ee8..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *  linux/net/sunrpc/gss_spkm3_unseal.c
- *
- *  Copyright (c) 2003 The Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  Andy Adamson <andros@umich.edu>
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *  3. Neither the name of the University nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY        RPCDBG_AUTH
-#endif
-
-/*
- * spkm3_read_token()
- *
- * only SPKM_MIC_TOK with md5 intg-alg is supported
- */
-u32
-spkm3_read_token(struct spkm3_ctx *ctx,
-               struct xdr_netobj *read_token,    /* checksum */
-               struct xdr_buf *message_buffer, /* signbuf */
-               int toktype)
-{
-       s32                     checksum_type;
-       s32                     code;
-       struct xdr_netobj       wire_cksum = {.len =0, .data = NULL};
-       char                    cksumdata[16];
-       struct xdr_netobj       md5cksum = {.len = 0, .data = cksumdata};
-       unsigned char           *ptr = (unsigned char *)read_token->data;
-       unsigned char           *cksum;
-       int                     bodysize, md5elen;
-       int                     mic_hdrlen;
-       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
-
-       if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
-                                       &bodysize, &ptr, read_token->len))
-               goto out;
-
-       /* decode the token */
-
-       if (toktype != SPKM_MIC_TOK) {
-               dprintk("RPC:       BAD SPKM3 token type: %d\n", toktype);
-               goto out;
-       }
-
-       if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
-               goto out;
-
-       if (*cksum++ != 0x03) {
-               dprintk("RPC:       spkm3_read_token BAD checksum type\n");
-               goto out;
-       }
-       md5elen = *cksum++;
-       cksum++;        /* move past the zbit */
-
-       if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
-               goto out;
-
-       /* HARD CODED FOR MD5 */
-
-       /* compute the checksum of the message.
-        * ptr + 2 = start of header piece of checksum
-        * mic_hdrlen + 2 = length of header piece of checksum
-        */
-       ret = GSS_S_DEFECTIVE_TOKEN;
-       if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
-               dprintk("RPC:       gss_spkm3_seal: unsupported I-ALG "
-                               "algorithm\n");
-               goto out;
-       }
-
-       checksum_type = CKSUMTYPE_HMAC_MD5;
-
-       code = make_spkm3_checksum(checksum_type,
-               &ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2,
-               message_buffer, 0, &md5cksum);
-
-       if (code)
-               goto out;
-
-       ret = GSS_S_BAD_SIG;
-       code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
-       if (code) {
-               dprintk("RPC:       bad MIC checksum\n");
-               goto out;
-       }
-
-
-       /* XXX: need to add expiration and sequencing */
-       ret = GSS_S_COMPLETE;
-out:
-       kfree(wire_cksum.data);
-       return ret;
-}
index cc385b3a59c219741e463cd78842f8e01f7cf9c4..dec2a6fc7c1277f15485011e52a7671eb3052574 100644 (file)
@@ -964,7 +964,7 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
        if (rqstp->rq_gssclient == NULL)
                return SVC_DENIED;
        stat = svcauth_unix_set_client(rqstp);
-       if (stat == SVC_DROP)
+       if (stat == SVC_DROP || stat == SVC_CLOSE)
                return stat;
        return SVC_OK;
 }
@@ -1018,7 +1018,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
                return SVC_DENIED;
        memset(&rsikey, 0, sizeof(rsikey));
        if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
-               return SVC_DROP;
+               return SVC_CLOSE;
        *authp = rpc_autherr_badverf;
        if (svc_safe_getnetobj(argv, &tmpobj)) {
                kfree(rsikey.in_handle.data);
@@ -1026,38 +1026,35 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
        }
        if (dup_netobj(&rsikey.in_token, &tmpobj)) {
                kfree(rsikey.in_handle.data);
-               return SVC_DROP;
+               return SVC_CLOSE;
        }
 
        /* Perform upcall, or find upcall result: */
        rsip = rsi_lookup(&rsikey);
        rsi_free(&rsikey);
        if (!rsip)
-               return SVC_DROP;
-       switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
-       case -EAGAIN:
-       case -ETIMEDOUT:
-       case -ENOENT:
+               return SVC_CLOSE;
+       if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
                /* No upcall result: */
-               return SVC_DROP;
-       case 0:
-               ret = SVC_DROP;
-               /* Got an answer to the upcall; use it: */
-               if (gss_write_init_verf(rqstp, rsip))
-                       goto out;
-               if (resv->iov_len + 4 > PAGE_SIZE)
-                       goto out;
-               svc_putnl(resv, RPC_SUCCESS);
-               if (svc_safe_putnetobj(resv, &rsip->out_handle))
-                       goto out;
-               if (resv->iov_len + 3 * 4 > PAGE_SIZE)
-                       goto out;
-               svc_putnl(resv, rsip->major_status);
-               svc_putnl(resv, rsip->minor_status);
-               svc_putnl(resv, GSS_SEQ_WIN);
-               if (svc_safe_putnetobj(resv, &rsip->out_token))
-                       goto out;
-       }
+               return SVC_CLOSE;
+
+       ret = SVC_CLOSE;
+       /* Got an answer to the upcall; use it: */
+       if (gss_write_init_verf(rqstp, rsip))
+               goto out;
+       if (resv->iov_len + 4 > PAGE_SIZE)
+               goto out;
+       svc_putnl(resv, RPC_SUCCESS);
+       if (svc_safe_putnetobj(resv, &rsip->out_handle))
+               goto out;
+       if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+               goto out;
+       svc_putnl(resv, rsip->major_status);
+       svc_putnl(resv, rsip->minor_status);
+       svc_putnl(resv, GSS_SEQ_WIN);
+       if (svc_safe_putnetobj(resv, &rsip->out_token))
+               goto out;
+
        ret = SVC_COMPLETE;
 out:
        cache_put(&rsip->h, &rsi_cache);
index 7dce81a926c5e000b1444d2909fad940b93d0cf4..e433e7580e27b221eff94d8b95ceaea703440618 100644 (file)
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
+#include "netns.h"
 
 #define         RPCDBG_FACILITY RPCDBG_CACHE
 
-static int cache_defer_req(struct cache_req *req, struct cache_head *item);
+static void cache_defer_req(struct cache_req *req, struct cache_head *item);
 static void cache_revisit_request(struct cache_head *item);
 
 static void cache_init(struct cache_head *h)
 {
-       time_t now = get_seconds();
+       time_t now = seconds_since_boot();
        h->next = NULL;
        h->flags = 0;
        kref_init(&h->ref);
@@ -51,7 +52,7 @@ static void cache_init(struct cache_head *h)
 
 static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
 {
-       return  (h->expiry_time < get_seconds()) ||
+       return  (h->expiry_time < seconds_since_boot()) ||
                (detail->flush_time > h->last_refresh);
 }
 
@@ -126,7 +127,7 @@ static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
 static void cache_fresh_locked(struct cache_head *head, time_t expiry)
 {
        head->expiry_time = expiry;
-       head->last_refresh = get_seconds();
+       head->last_refresh = seconds_since_boot();
        set_bit(CACHE_VALID, &head->flags);
 }
 
@@ -237,7 +238,7 @@ int cache_check(struct cache_detail *detail,
 
        /* now see if we want to start an upcall */
        refresh_age = (h->expiry_time - h->last_refresh);
-       age = get_seconds() - h->last_refresh;
+       age = seconds_since_boot() - h->last_refresh;
 
        if (rqstp == NULL) {
                if (rv == -EAGAIN)
@@ -252,7 +253,7 @@ int cache_check(struct cache_detail *detail,
                                cache_revisit_request(h);
                                if (rv == -EAGAIN) {
                                        set_bit(CACHE_NEGATIVE, &h->flags);
-                                       cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY);
+                                       cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
                                        cache_fresh_unlocked(h, detail);
                                        rv = -ENOENT;
                                }
@@ -267,7 +268,8 @@ int cache_check(struct cache_detail *detail,
        }
 
        if (rv == -EAGAIN) {
-               if (cache_defer_req(rqstp, h) < 0) {
+               cache_defer_req(rqstp, h);
+               if (!test_bit(CACHE_PENDING, &h->flags)) {
                        /* Request is not deferred */
                        rv = cache_is_valid(detail, h);
                        if (rv == -EAGAIN)
@@ -387,11 +389,11 @@ static int cache_clean(void)
                        return -1;
                }
                current_detail = list_entry(next, struct cache_detail, others);
-               if (current_detail->nextcheck > get_seconds())
+               if (current_detail->nextcheck > seconds_since_boot())
                        current_index = current_detail->hash_size;
                else {
                        current_index = 0;
-                       current_detail->nextcheck = get_seconds()+30*60;
+                       current_detail->nextcheck = seconds_since_boot()+30*60;
                }
        }
 
@@ -476,7 +478,7 @@ EXPORT_SYMBOL_GPL(cache_flush);
 void cache_purge(struct cache_detail *detail)
 {
        detail->flush_time = LONG_MAX;
-       detail->nextcheck = get_seconds();
+       detail->nextcheck = seconds_since_boot();
        cache_flush();
        detail->flush_time = 1;
 }
@@ -505,81 +507,155 @@ EXPORT_SYMBOL_GPL(cache_purge);
 
 static DEFINE_SPINLOCK(cache_defer_lock);
 static LIST_HEAD(cache_defer_list);
-static struct list_head cache_defer_hash[DFR_HASHSIZE];
+static struct hlist_head cache_defer_hash[DFR_HASHSIZE];
 static int cache_defer_cnt;
 
-static int cache_defer_req(struct cache_req *req, struct cache_head *item)
+static void __unhash_deferred_req(struct cache_deferred_req *dreq)
+{
+       hlist_del_init(&dreq->hash);
+       if (!list_empty(&dreq->recent)) {
+               list_del_init(&dreq->recent);
+               cache_defer_cnt--;
+       }
+}
+
+static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item)
 {
-       struct cache_deferred_req *dreq, *discard;
        int hash = DFR_HASH(item);
 
-       if (cache_defer_cnt >= DFR_MAX) {
-               /* too much in the cache, randomly drop this one,
-                * or continue and drop the oldest below
-                */
-               if (net_random()&1)
-                       return -ENOMEM;
-       }
-       dreq = req->defer(req);
-       if (dreq == NULL)
-               return -ENOMEM;
+       INIT_LIST_HEAD(&dreq->recent);
+       hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);
+}
+
+static void setup_deferral(struct cache_deferred_req *dreq,
+                          struct cache_head *item,
+                          int count_me)
+{
 
        dreq->item = item;
 
        spin_lock(&cache_defer_lock);
 
-       list_add(&dreq->recent, &cache_defer_list);
-
-       if (cache_defer_hash[hash].next == NULL)
-               INIT_LIST_HEAD(&cache_defer_hash[hash]);
-       list_add(&dreq->hash, &cache_defer_hash[hash]);
+       __hash_deferred_req(dreq, item);
 
-       /* it is in, now maybe clean up */
-       discard = NULL;
-       if (++cache_defer_cnt > DFR_MAX) {
-               discard = list_entry(cache_defer_list.prev,
-                                    struct cache_deferred_req, recent);
-               list_del_init(&discard->recent);
-               list_del_init(&discard->hash);
-               cache_defer_cnt--;
+       if (count_me) {
+               cache_defer_cnt++;
+               list_add(&dreq->recent, &cache_defer_list);
        }
+
        spin_unlock(&cache_defer_lock);
 
+}
+
+struct thread_deferred_req {
+       struct cache_deferred_req handle;
+       struct completion completion;
+};
+
+static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
+{
+       struct thread_deferred_req *dr =
+               container_of(dreq, struct thread_deferred_req, handle);
+       complete(&dr->completion);
+}
+
+static void cache_wait_req(struct cache_req *req, struct cache_head *item)
+{
+       struct thread_deferred_req sleeper;
+       struct cache_deferred_req *dreq = &sleeper.handle;
+
+       sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
+       dreq->revisit = cache_restart_thread;
+
+       setup_deferral(dreq, item, 0);
+
+       if (!test_bit(CACHE_PENDING, &item->flags) ||
+           wait_for_completion_interruptible_timeout(
+                   &sleeper.completion, req->thread_wait) <= 0) {
+               /* The completion wasn't completed, so we need
+                * to clean up
+                */
+               spin_lock(&cache_defer_lock);
+               if (!hlist_unhashed(&sleeper.handle.hash)) {
+                       __unhash_deferred_req(&sleeper.handle);
+                       spin_unlock(&cache_defer_lock);
+               } else {
+                       /* cache_revisit_request already removed
+                        * this from the hash table, but hasn't
+                        * called ->revisit yet.  It will very soon
+                        * and we need to wait for it.
+                        */
+                       spin_unlock(&cache_defer_lock);
+                       wait_for_completion(&sleeper.completion);
+               }
+       }
+}
+
+static void cache_limit_defers(void)
+{
+       /* Make sure we haven't exceed the limit of allowed deferred
+        * requests.
+        */
+       struct cache_deferred_req *discard = NULL;
+
+       if (cache_defer_cnt <= DFR_MAX)
+               return;
+
+       spin_lock(&cache_defer_lock);
+
+       /* Consider removing either the first or the last */
+       if (cache_defer_cnt > DFR_MAX) {
+               if (net_random() & 1)
+                       discard = list_entry(cache_defer_list.next,
+                                            struct cache_deferred_req, recent);
+               else
+                       discard = list_entry(cache_defer_list.prev,
+                                            struct cache_deferred_req, recent);
+               __unhash_deferred_req(discard);
+       }
+       spin_unlock(&cache_defer_lock);
        if (discard)
-               /* there was one too many */
                discard->revisit(discard, 1);
+}
 
-       if (!test_bit(CACHE_PENDING, &item->flags)) {
-               /* must have just been validated... */
-               cache_revisit_request(item);
-               return -EAGAIN;
+static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+{
+       struct cache_deferred_req *dreq;
+
+       if (req->thread_wait) {
+               cache_wait_req(req, item);
+               if (!test_bit(CACHE_PENDING, &item->flags))
+                       return;
        }
-       return 0;
+       dreq = req->defer(req);
+       if (dreq == NULL)
+               return;
+       setup_deferral(dreq, item, 1);
+       if (!test_bit(CACHE_PENDING, &item->flags))
+               /* Bit could have been cleared before we managed to
+                * set up the deferral, so need to revisit just in case
+                */
+               cache_revisit_request(item);
+
+       cache_limit_defers();
 }
 
 static void cache_revisit_request(struct cache_head *item)
 {
        struct cache_deferred_req *dreq;
        struct list_head pending;
-
-       struct list_head *lp;
+       struct hlist_node *lp, *tmp;
        int hash = DFR_HASH(item);
 
        INIT_LIST_HEAD(&pending);
        spin_lock(&cache_defer_lock);
 
-       lp = cache_defer_hash[hash].next;
-       if (lp) {
-               while (lp != &cache_defer_hash[hash]) {
-                       dreq = list_entry(lp, struct cache_deferred_req, hash);
-                       lp = lp->next;
-                       if (dreq->item == item) {
-                               list_del_init(&dreq->hash);
-                               list_move(&dreq->recent, &pending);
-                               cache_defer_cnt--;
-                       }
+       hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash)
+               if (dreq->item == item) {
+                       __unhash_deferred_req(dreq);
+                       list_add(&dreq->recent, &pending);
                }
-       }
+
        spin_unlock(&cache_defer_lock);
 
        while (!list_empty(&pending)) {
@@ -600,9 +676,8 @@ void cache_clean_deferred(void *owner)
 
        list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
                if (dreq->owner == owner) {
-                       list_del_init(&dreq->hash);
-                       list_move(&dreq->recent, &pending);
-                       cache_defer_cnt--;
+                       __unhash_deferred_req(dreq);
+                       list_add(&dreq->recent, &pending);
                }
        }
        spin_unlock(&cache_defer_lock);
@@ -901,7 +976,7 @@ static int cache_release(struct inode *inode, struct file *filp,
                filp->private_data = NULL;
                kfree(rp);
 
-               cd->last_close = get_seconds();
+               cd->last_close = seconds_since_boot();
                atomic_dec(&cd->readers);
        }
        module_put(cd->owner);
@@ -1014,6 +1089,23 @@ static void warn_no_listener(struct cache_detail *detail)
        }
 }
 
+static bool cache_listeners_exist(struct cache_detail *detail)
+{
+       if (atomic_read(&detail->readers))
+               return true;
+       if (detail->last_close == 0)
+               /* This cache was never opened */
+               return false;
+       if (detail->last_close < seconds_since_boot() - 30)
+               /*
+                * We allow for the possibility that someone might
+                * restart a userspace daemon without restarting the
+                * server; but after 30 seconds, we give up.
+                */
+                return false;
+       return true;
+}
+
 /*
  * register an upcall request to user-space and queue it up for read() by the
  * upcall daemon.
@@ -1032,10 +1124,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
        char *bp;
        int len;
 
-       if (atomic_read(&detail->readers) == 0 &&
-           detail->last_close < get_seconds() - 30) {
-                       warn_no_listener(detail);
-                       return -EINVAL;
+       if (!cache_listeners_exist(detail)) {
+               warn_no_listener(detail);
+               return -EINVAL;
        }
 
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -1094,13 +1185,19 @@ int qword_get(char **bpp, char *dest, int bufsize)
        if (bp[0] == '\\' && bp[1] == 'x') {
                /* HEX STRING */
                bp += 2;
-               while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
-                       int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
-                       bp++;
-                       byte <<= 4;
-                       byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
-                       *dest++ = byte;
-                       bp++;
+               while (len < bufsize) {
+                       int h, l;
+
+                       h = hex_to_bin(bp[0]);
+                       if (h < 0)
+                               break;
+
+                       l = hex_to_bin(bp[1]);
+                       if (l < 0)
+                               break;
+
+                       *dest++ = (h << 4) | l;
+                       bp += 2;
                        len++;
                }
        } else {
@@ -1218,7 +1315,8 @@ static int c_show(struct seq_file *m, void *p)
 
        ifdebug(CACHE)
                seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
-                          cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags);
+                          convert_to_wallclock(cp->expiry_time),
+                          atomic_read(&cp->ref.refcount), cp->flags);
        cache_get(cp);
        if (cache_check(cd, cp, NULL))
                /* cache_check does a cache_put on failure */
@@ -1284,7 +1382,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
        unsigned long p = *ppos;
        size_t len;
 
-       sprintf(tbuf, "%lu\n", cd->flush_time);
+       sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time));
        len = strlen(tbuf);
        if (p >= len)
                return 0;
@@ -1302,19 +1400,20 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
                           struct cache_detail *cd)
 {
        char tbuf[20];
-       char *ep;
-       long flushtime;
+       char *bp, *ep;
+
        if (*ppos || count > sizeof(tbuf)-1)
                return -EINVAL;
        if (copy_from_user(tbuf, buf, count))
                return -EFAULT;
        tbuf[count] = 0;
-       flushtime = simple_strtoul(tbuf, &ep, 0);
+       simple_strtoul(tbuf, &ep, 0);
        if (*ep && *ep != '\n')
                return -EINVAL;
 
-       cd->flush_time = flushtime;
-       cd->nextcheck = get_seconds();
+       bp = tbuf;
+       cd->flush_time = get_expiry(&bp);
+       cd->nextcheck = seconds_since_boot();
        cache_flush();
 
        *ppos += count;
@@ -1438,8 +1537,10 @@ static const struct file_operations cache_flush_operations_procfs = {
        .llseek         = no_llseek,
 };
 
-static void remove_cache_proc_entries(struct cache_detail *cd)
+static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net)
 {
+       struct sunrpc_net *sn;
+
        if (cd->u.procfs.proc_ent == NULL)
                return;
        if (cd->u.procfs.flush_ent)
@@ -1449,15 +1550,18 @@ static void remove_cache_proc_entries(struct cache_detail *cd)
        if (cd->u.procfs.content_ent)
                remove_proc_entry("content", cd->u.procfs.proc_ent);
        cd->u.procfs.proc_ent = NULL;
-       remove_proc_entry(cd->name, proc_net_rpc);
+       sn = net_generic(net, sunrpc_net_id);
+       remove_proc_entry(cd->name, sn->proc_net_rpc);
 }
 
 #ifdef CONFIG_PROC_FS
-static int create_cache_proc_entries(struct cache_detail *cd)
+static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
 {
        struct proc_dir_entry *p;
+       struct sunrpc_net *sn;
 
-       cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+       sn = net_generic(net, sunrpc_net_id);
+       cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc);
        if (cd->u.procfs.proc_ent == NULL)
                goto out_nomem;
        cd->u.procfs.channel_ent = NULL;
@@ -1488,11 +1592,11 @@ static int create_cache_proc_entries(struct cache_detail *cd)
        }
        return 0;
 out_nomem:
-       remove_cache_proc_entries(cd);
+       remove_cache_proc_entries(cd, net);
        return -ENOMEM;
 }
 #else /* CONFIG_PROC_FS */
-static int create_cache_proc_entries(struct cache_detail *cd)
+static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
 {
        return 0;
 }
@@ -1503,23 +1607,33 @@ void __init cache_initialize(void)
        INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
 }
 
-int cache_register(struct cache_detail *cd)
+int cache_register_net(struct cache_detail *cd, struct net *net)
 {
        int ret;
 
        sunrpc_init_cache_detail(cd);
-       ret = create_cache_proc_entries(cd);
+       ret = create_cache_proc_entries(cd, net);
        if (ret)
                sunrpc_destroy_cache_detail(cd);
        return ret;
 }
+
+int cache_register(struct cache_detail *cd)
+{
+       return cache_register_net(cd, &init_net);
+}
 EXPORT_SYMBOL_GPL(cache_register);
 
-void cache_unregister(struct cache_detail *cd)
+void cache_unregister_net(struct cache_detail *cd, struct net *net)
 {
-       remove_cache_proc_entries(cd);
+       remove_cache_proc_entries(cd, net);
        sunrpc_destroy_cache_detail(cd);
 }
+
+void cache_unregister(struct cache_detail *cd)
+{
+       cache_unregister_net(cd, &init_net);
+}
 EXPORT_SYMBOL_GPL(cache_unregister);
 
 static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
index fa5549079d79ca7709d3a68bc686b77f10b08243..9dab9573be4146feafd1fb2db584faa3b61b0b0b 100644 (file)
@@ -284,6 +284,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        struct rpc_xprt *xprt;
        struct rpc_clnt *clnt;
        struct xprt_create xprtargs = {
+               .net = args->net,
                .ident = args->protocol,
                .srcaddr = args->saddress,
                .dstaddr = args->address,
@@ -1675,7 +1676,7 @@ rpc_verify_header(struct rpc_task *task)
                        rpcauth_invalcred(task);
                        /* Ensure we obtain a new XID! */
                        xprt_release(task);
-                       task->tk_action = call_refresh;
+                       task->tk_action = call_reserve;
                        goto out_retry;
                case RPC_AUTH_BADCRED:
                case RPC_AUTH_BADVERF:
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
new file mode 100644 (file)
index 0000000..d013bf2
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __SUNRPC_NETNS_H__
+#define __SUNRPC_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct cache_detail;
+
+struct sunrpc_net {
+       struct proc_dir_entry *proc_net_rpc;
+       struct cache_detail *ip_map_cache;
+};
+
+extern int sunrpc_net_id;
+
+int ip_map_cache_create(struct net *);
+void ip_map_cache_destroy(struct net *);
+
+#endif
index 52f252432144ab439c9083acf20e8d487fbbd12d..7df92d237cb8103171a892f49a98aaca1cd05e49 100644 (file)
@@ -445,6 +445,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
        struct inode *inode = new_inode(sb);
        if (!inode)
                return NULL;
+       inode->i_ino = get_next_ino();
        inode->i_mode = mode;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        switch(mode & S_IFMT) {
index dac219a56ae1a7dcf8df9ddff9a128b6caa89dac..fa6d7ca2c851fc6cc6614c26f1e8bb5b43362c66 100644 (file)
@@ -177,6 +177,7 @@ static DEFINE_MUTEX(rpcb_create_local_mutex);
 static int rpcb_create_local(void)
 {
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = XPRT_TRANSPORT_TCP,
                .address        = (struct sockaddr *)&rpcb_inaddr_loopback,
                .addrsize       = sizeof(rpcb_inaddr_loopback),
@@ -211,8 +212,9 @@ static int rpcb_create_local(void)
         */
        clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
        if (IS_ERR(clnt4)) {
-               dprintk("RPC:       failed to create local rpcbind v4 "
-                               "cleint (errno %ld).\n", PTR_ERR(clnt4));
+               dprintk("RPC:       failed to bind second program to "
+                               "rpcbind v4 client (errno %ld).\n",
+                               PTR_ERR(clnt4));
                clnt4 = NULL;
        }
 
@@ -228,6 +230,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
                                    size_t salen, int proto, u32 version)
 {
        struct rpc_create_args args = {
+               .net            = &init_net,
                .protocol       = proto,
                .address        = srvaddr,
                .addrsize       = salen,
@@ -247,7 +250,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
                ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
                break;
        default:
-               return NULL;
+               return ERR_PTR(-EAFNOSUPPORT);
        }
 
        return rpc_create(&args);
@@ -475,57 +478,6 @@ int rpcb_v4_register(const u32 program, const u32 version,
        return -EAFNOSUPPORT;
 }
 
-/**
- * rpcb_getport_sync - obtain the port for an RPC service on a given host
- * @sin: address of remote peer
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- *
- * Return value is the requested advertised port number,
- * or a negative errno value.
- *
- * Called from outside the RPC client in a synchronous task context.
- * Uses default timeout parameters specified by underlying transport.
- *
- * XXX: Needs to support IPv6
- */
-int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
-{
-       struct rpcbind_args map = {
-               .r_prog         = prog,
-               .r_vers         = vers,
-               .r_prot         = prot,
-               .r_port         = 0,
-       };
-       struct rpc_message msg = {
-               .rpc_proc       = &rpcb_procedures2[RPCBPROC_GETPORT],
-               .rpc_argp       = &map,
-               .rpc_resp       = &map,
-       };
-       struct rpc_clnt *rpcb_clnt;
-       int status;
-
-       dprintk("RPC:       %s(%pI4, %u, %u, %d)\n",
-               __func__, &sin->sin_addr.s_addr, prog, vers, prot);
-
-       rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
-                               sizeof(*sin), prot, RPCBVERS_2);
-       if (IS_ERR(rpcb_clnt))
-               return PTR_ERR(rpcb_clnt);
-
-       status = rpc_call_sync(rpcb_clnt, &msg, 0);
-       rpc_shutdown_client(rpcb_clnt);
-
-       if (status >= 0) {
-               if (map.r_port != 0)
-                       return map.r_port;
-               status = -EACCES;
-       }
-       return status;
-}
-EXPORT_SYMBOL_GPL(rpcb_getport_sync);
-
 static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc)
 {
        struct rpc_message msg = {
index aa5dbda6608cab75db59c6305ddbf38ac6cc4ade..243fc09b164e81865a902015f18bd87313413167 100644 (file)
@@ -908,7 +908,7 @@ static int rpciod_start(void)
         * Create the rpciod thread and wait for it to start.
         */
        dprintk("RPC:       creating workqueue rpciod\n");
-       wq = create_workqueue("rpciod");
+       wq = alloc_workqueue("rpciod", WQ_RESCUER, 0);
        rpciod_workqueue = wq;
        return rpciod_workqueue != NULL;
 }
index ea1046f3f9a3cac31616499559b82aa2930effba..f71a73107ae94adeae35303f95f0b3409aee9e07 100644 (file)
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/metrics.h>
-#include <net/net_namespace.h>
 
-#define RPCDBG_FACILITY        RPCDBG_MISC
+#include "netns.h"
 
-struct proc_dir_entry  *proc_net_rpc = NULL;
+#define RPCDBG_FACILITY        RPCDBG_MISC
 
 /*
  * Get RPC client stats
@@ -218,10 +217,11 @@ EXPORT_SYMBOL_GPL(rpc_print_iostats);
 static inline struct proc_dir_entry *
 do_register(const char *name, void *data, const struct file_operations *fops)
 {
-       rpc_proc_init();
-       dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
+       struct sunrpc_net *sn;
 
-       return proc_create_data(name, 0, proc_net_rpc, fops, data);
+       dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
+       sn = net_generic(&init_net, sunrpc_net_id);
+       return proc_create_data(name, 0, sn->proc_net_rpc, fops, data);
 }
 
 struct proc_dir_entry *
@@ -234,7 +234,10 @@ EXPORT_SYMBOL_GPL(rpc_proc_register);
 void
 rpc_proc_unregister(const char *name)
 {
-       remove_proc_entry(name, proc_net_rpc);
+       struct sunrpc_net *sn;
+
+       sn = net_generic(&init_net, sunrpc_net_id);
+       remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(rpc_proc_unregister);
 
@@ -248,25 +251,29 @@ EXPORT_SYMBOL_GPL(svc_proc_register);
 void
 svc_proc_unregister(const char *name)
 {
-       remove_proc_entry(name, proc_net_rpc);
+       struct sunrpc_net *sn;
+
+       sn = net_generic(&init_net, sunrpc_net_id);
+       remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(svc_proc_unregister);
 
-void
-rpc_proc_init(void)
+int rpc_proc_init(struct net *net)
 {
+       struct sunrpc_net *sn;
+
        dprintk("RPC:       registering /proc/net/rpc\n");
-       if (!proc_net_rpc)
-               proc_net_rpc = proc_mkdir("rpc", init_net.proc_net);
+       sn = net_generic(net, sunrpc_net_id);
+       sn->proc_net_rpc = proc_mkdir("rpc", net->proc_net);
+       if (sn->proc_net_rpc == NULL)
+               return -ENOMEM;
+
+       return 0;
 }
 
-void
-rpc_proc_exit(void)
+void rpc_proc_exit(struct net *net)
 {
        dprintk("RPC:       unregistering /proc/net/rpc\n");
-       if (proc_net_rpc) {
-               proc_net_rpc = NULL;
-               remove_proc_entry("rpc", init_net.proc_net);
-       }
+       remove_proc_entry("rpc", net->proc_net);
 }
 
index c0d085013a2be26f7bf3f34e195cebfc0a716039..9d0809160994a7839c283bb4902fe537a5ee3999 100644 (file)
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/xprtsock.h>
 
-extern struct cache_detail ip_map_cache, unix_gid_cache;
+#include "netns.h"
+
+int sunrpc_net_id;
+
+static __net_init int sunrpc_init_net(struct net *net)
+{
+       int err;
+
+       err = rpc_proc_init(net);
+       if (err)
+               goto err_proc;
+
+       err = ip_map_cache_create(net);
+       if (err)
+               goto err_ipmap;
+
+       return 0;
+
+err_ipmap:
+       rpc_proc_exit(net);
+err_proc:
+       return err;
+}
+
+static __net_exit void sunrpc_exit_net(struct net *net)
+{
+       ip_map_cache_destroy(net);
+       rpc_proc_exit(net);
+}
+
+static struct pernet_operations sunrpc_net_ops = {
+       .init = sunrpc_init_net,
+       .exit = sunrpc_exit_net,
+       .id = &sunrpc_net_id,
+       .size = sizeof(struct sunrpc_net),
+};
+
+extern struct cache_detail unix_gid_cache;
 
 extern void cleanup_rpcb_clnt(void);
 
@@ -38,18 +75,22 @@ init_sunrpc(void)
        err = rpcauth_init_module();
        if (err)
                goto out3;
+
+       cache_initialize();
+
+       err = register_pernet_subsys(&sunrpc_net_ops);
+       if (err)
+               goto out4;
 #ifdef RPC_DEBUG
        rpc_register_sysctl();
 #endif
-#ifdef CONFIG_PROC_FS
-       rpc_proc_init();
-#endif
-       cache_initialize();
-       cache_register(&ip_map_cache);
        cache_register(&unix_gid_cache);
        svc_init_xprt_sock();   /* svc sock transport */
        init_socket_xprt();     /* clnt sock transport */
        return 0;
+
+out4:
+       rpcauth_remove_module();
 out3:
        rpc_destroy_mempool();
 out2:
@@ -67,13 +108,10 @@ cleanup_sunrpc(void)
        svc_cleanup_xprt_sock();
        unregister_rpc_pipefs();
        rpc_destroy_mempool();
-       cache_unregister(&ip_map_cache);
        cache_unregister(&unix_gid_cache);
+       unregister_pernet_subsys(&sunrpc_net_ops);
 #ifdef RPC_DEBUG
        rpc_unregister_sysctl();
-#endif
-#ifdef CONFIG_PROC_FS
-       rpc_proc_exit();
 #endif
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
index d9017d64597e2beabb7f2edb9147018613d7c412..6359c42c49410f73fbf9e8c7c570964f1ca739b1 100644 (file)
@@ -1055,6 +1055,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                goto err_bad;
        case SVC_DENIED:
                goto err_bad_auth;
+       case SVC_CLOSE:
+               if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
+                       svc_close_xprt(rqstp->rq_xprt);
        case SVC_DROP:
                goto dropit;
        case SVC_COMPLETE:
index cbc084939dd8af2b2e009098af2875c96fbc363f..c82fe739fbdcc685fae1e59f1fdb7c9e5afd30b0 100644 (file)
@@ -100,16 +100,14 @@ EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
  */
 int svc_print_xprts(char *buf, int maxlen)
 {
-       struct list_head *le;
+       struct svc_xprt_class *xcl;
        char tmpstr[80];
        int len = 0;
        buf[0] = '\0';
 
        spin_lock(&svc_xprt_class_lock);
-       list_for_each(le, &svc_xprt_class_list) {
+       list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
                int slen;
-               struct svc_xprt_class *xcl =
-                       list_entry(le, struct svc_xprt_class, xcl_list);
 
                sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
                slen = strlen(tmpstr);
@@ -128,9 +126,9 @@ static void svc_xprt_free(struct kref *kref)
        struct svc_xprt *xprt =
                container_of(kref, struct svc_xprt, xpt_ref);
        struct module *owner = xprt->xpt_class->xcl_owner;
-       if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags) &&
-           xprt->xpt_auth_cache != NULL)
-               svcauth_unix_info_release(xprt->xpt_auth_cache);
+       if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
+               svcauth_unix_info_release(xprt);
+       put_net(xprt->xpt_net);
        xprt->xpt_ops->xpo_free(xprt);
        module_put(owner);
 }
@@ -156,15 +154,18 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
        INIT_LIST_HEAD(&xprt->xpt_list);
        INIT_LIST_HEAD(&xprt->xpt_ready);
        INIT_LIST_HEAD(&xprt->xpt_deferred);
+       INIT_LIST_HEAD(&xprt->xpt_users);
        mutex_init(&xprt->xpt_mutex);
        spin_lock_init(&xprt->xpt_lock);
        set_bit(XPT_BUSY, &xprt->xpt_flags);
        rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
+       xprt->xpt_net = get_net(&init_net);
 }
 EXPORT_SYMBOL_GPL(svc_xprt_init);
 
 static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
                                         struct svc_serv *serv,
+                                        struct net *net,
                                         const int family,
                                         const unsigned short port,
                                         int flags)
@@ -199,12 +200,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
                return ERR_PTR(-EAFNOSUPPORT);
        }
 
-       return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
+       return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
 }
 
 int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
-                   const int family, const unsigned short port,
-                   int flags)
+                   struct net *net, const int family,
+                   const unsigned short port, int flags)
 {
        struct svc_xprt_class *xcl;
 
@@ -220,7 +221,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
                        goto err;
 
                spin_unlock(&svc_xprt_class_lock);
-               newxprt = __svc_xpo_create(xcl, serv, family, port, flags);
+               newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
                if (IS_ERR(newxprt)) {
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
@@ -329,12 +330,6 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
                       "svc_xprt_enqueue: "
                       "threads and transports both waiting??\n");
 
-       if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
-               /* Don't enqueue dead transports */
-               dprintk("svc: transport %p is dead, not enqueued\n", xprt);
-               goto out_unlock;
-       }
-
        pool->sp_stats.packets++;
 
        /* Mark transport as busy. It will remain in this state until
@@ -651,6 +646,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
        if (signalled() || kthread_should_stop())
                return -EINTR;
 
+       /* Normally we will wait up to 5 seconds for any required
+        * cache information to be provided.
+        */
+       rqstp->rq_chandle.thread_wait = 5*HZ;
+
        spin_lock_bh(&pool->sp_lock);
        xprt = svc_xprt_dequeue(pool);
        if (xprt) {
@@ -658,6 +658,12 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
                svc_xprt_get(xprt);
                rqstp->rq_reserved = serv->sv_max_mesg;
                atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+
+               /* As there is a shortage of threads and this request
+                * had to be queued, don't allow the thread to wait so
+                * long for cache updates.
+                */
+               rqstp->rq_chandle.thread_wait = 1*HZ;
        } else {
                /* No data pending. Go to sleep */
                svc_thread_enqueue(pool, rqstp);
@@ -868,6 +874,19 @@ static void svc_age_temp_xprts(unsigned long closure)
        mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
 }
 
+static void call_xpt_users(struct svc_xprt *xprt)
+{
+       struct svc_xpt_user *u;
+
+       spin_lock(&xprt->xpt_lock);
+       while (!list_empty(&xprt->xpt_users)) {
+               u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list);
+               list_del(&u->list);
+               u->callback(u);
+       }
+       spin_unlock(&xprt->xpt_lock);
+}
+
 /*
  * Remove a dead transport
  */
@@ -878,7 +897,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
 
        /* Only do this once */
        if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
-               return;
+               BUG();
 
        dprintk("svc: svc_delete_xprt(%p)\n", xprt);
        xprt->xpt_ops->xpo_detach(xprt);
@@ -900,6 +919,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
        while ((dr = svc_deferred_dequeue(xprt)) != NULL)
                kfree(dr);
 
+       call_xpt_users(xprt);
        svc_xprt_put(xprt);
 }
 
@@ -910,10 +930,7 @@ void svc_close_xprt(struct svc_xprt *xprt)
                /* someone else will have to effect the close */
                return;
 
-       svc_xprt_get(xprt);
        svc_delete_xprt(xprt);
-       clear_bit(XPT_BUSY, &xprt->xpt_flags);
-       svc_xprt_put(xprt);
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
 
index 207311610988a3c3f29a2bf3ce2ea37320d237f1..560677d187f1b0fc7eb3d72c119aa848eb306145 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <linux/sunrpc/clnt.h>
 
+#include "netns.h"
+
 /*
  * AUTHUNIX and AUTHNULL credentials are both handled here.
  * AUTHNULL is treated just like AUTHUNIX except that the uid/gid
@@ -92,7 +94,6 @@ struct ip_map {
        struct unix_domain      *m_client;
        int                     m_add_change;
 };
-static struct cache_head       *ip_table[IP_HASHMAX];
 
 static void ip_map_put(struct kref *kref)
 {
@@ -178,8 +179,8 @@ static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
        return sunrpc_cache_pipe_upcall(cd, h, ip_map_request);
 }
 
-static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
-static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
+static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
                          char *mesg, int mlen)
@@ -219,10 +220,9 @@ static int ip_map_parse(struct cache_detail *cd,
        switch (address.sa.sa_family) {
        case AF_INET:
                /* Form a mapped IPv4 address in sin6 */
-               memset(&sin6, 0, sizeof(sin6));
                sin6.sin6_family = AF_INET6;
-               sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
-               sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr;
+               ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr,
+                               &sin6.sin6_addr);
                break;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case AF_INET6:
@@ -249,9 +249,9 @@ static int ip_map_parse(struct cache_detail *cd,
                dom = NULL;
 
        /* IPv6 scope IDs are ignored for now */
-       ipmp = ip_map_lookup(class, &sin6.sin6_addr);
+       ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr);
        if (ipmp) {
-               err = ip_map_update(ipmp,
+               err = __ip_map_update(cd, ipmp,
                             container_of(dom, struct unix_domain, h),
                             expiry);
        } else
@@ -294,29 +294,15 @@ static int ip_map_show(struct seq_file *m,
 }
 
 
-struct cache_detail ip_map_cache = {
-       .owner          = THIS_MODULE,
-       .hash_size      = IP_HASHMAX,
-       .hash_table     = ip_table,
-       .name           = "auth.unix.ip",
-       .cache_put      = ip_map_put,
-       .cache_upcall   = ip_map_upcall,
-       .cache_parse    = ip_map_parse,
-       .cache_show     = ip_map_show,
-       .match          = ip_map_match,
-       .init           = ip_map_init,
-       .update         = update,
-       .alloc          = ip_map_alloc,
-};
-
-static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
+static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class,
+               struct in6_addr *addr)
 {
        struct ip_map ip;
        struct cache_head *ch;
 
        strcpy(ip.m_class, class);
        ipv6_addr_copy(&ip.m_addr, addr);
-       ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
+       ch = sunrpc_cache_lookup(cd, &ip.h,
                                 hash_str(class, IP_HASHBITS) ^
                                 hash_ip6(*addr));
 
@@ -326,7 +312,17 @@ static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
                return NULL;
 }
 
-static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry)
+static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
+               struct in6_addr *addr)
+{
+       struct sunrpc_net *sn;
+
+       sn = net_generic(net, sunrpc_net_id);
+       return __ip_map_lookup(sn->ip_map_cache, class, addr);
+}
+
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
+               struct unix_domain *udom, time_t expiry)
 {
        struct ip_map ip;
        struct cache_head *ch;
@@ -344,17 +340,25 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex
                        ip.m_add_change++;
        }
        ip.h.expiry_time = expiry;
-       ch = sunrpc_cache_update(&ip_map_cache,
-                                &ip.h, &ipm->h,
+       ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
                                 hash_str(ipm->m_class, IP_HASHBITS) ^
                                 hash_ip6(ipm->m_addr));
        if (!ch)
                return -ENOMEM;
-       cache_put(ch, &ip_map_cache);
+       cache_put(ch, cd);
        return 0;
 }
 
-int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
+static inline int ip_map_update(struct net *net, struct ip_map *ipm,
+               struct unix_domain *udom, time_t expiry)
+{
+       struct sunrpc_net *sn;
+
+       sn = net_generic(net, sunrpc_net_id);
+       return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
+}
+
+int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom)
 {
        struct unix_domain *udom;
        struct ip_map *ipmp;
@@ -362,10 +366,10 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
        if (dom->flavour != &svcauth_unix)
                return -EINVAL;
        udom = container_of(dom, struct unix_domain, h);
-       ipmp = ip_map_lookup("nfsd", addr);
+       ipmp = ip_map_lookup(net, "nfsd", addr);
 
        if (ipmp)
-               return ip_map_update(ipmp, udom, NEVER);
+               return ip_map_update(net, ipmp, udom, NEVER);
        else
                return -ENOMEM;
 }
@@ -383,16 +387,18 @@ int auth_unix_forget_old(struct auth_domain *dom)
 }
 EXPORT_SYMBOL_GPL(auth_unix_forget_old);
 
-struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
+struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
 {
        struct ip_map *ipm;
        struct auth_domain *rv;
+       struct sunrpc_net *sn;
 
-       ipm = ip_map_lookup("nfsd", addr);
+       sn = net_generic(net, sunrpc_net_id);
+       ipm = ip_map_lookup(net, "nfsd", addr);
 
        if (!ipm)
                return NULL;
-       if (cache_check(&ip_map_cache, &ipm->h, NULL))
+       if (cache_check(sn->ip_map_cache, &ipm->h, NULL))
                return NULL;
 
        if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
@@ -403,22 +409,29 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
                rv = &ipm->m_client->h;
                kref_get(&rv->ref);
        }
-       cache_put(&ipm->h, &ip_map_cache);
+       cache_put(&ipm->h, sn->ip_map_cache);
        return rv;
 }
 EXPORT_SYMBOL_GPL(auth_unix_lookup);
 
 void svcauth_unix_purge(void)
 {
-       cache_purge(&ip_map_cache);
+       struct net *net;
+
+       for_each_net(net) {
+               struct sunrpc_net *sn;
+
+               sn = net_generic(net, sunrpc_net_id);
+               cache_purge(sn->ip_map_cache);
+       }
 }
 EXPORT_SYMBOL_GPL(svcauth_unix_purge);
 
 static inline struct ip_map *
-ip_map_cached_get(struct svc_rqst *rqstp)
+ip_map_cached_get(struct svc_xprt *xprt)
 {
        struct ip_map *ipm = NULL;
-       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct sunrpc_net *sn;
 
        if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
                spin_lock(&xprt->xpt_lock);
@@ -430,9 +443,10 @@ ip_map_cached_get(struct svc_rqst *rqstp)
                                 * remembered, e.g. by a second mount from the
                                 * same IP address.
                                 */
+                               sn = net_generic(xprt->xpt_net, sunrpc_net_id);
                                xprt->xpt_auth_cache = NULL;
                                spin_unlock(&xprt->xpt_lock);
-                               cache_put(&ipm->h, &ip_map_cache);
+                               cache_put(&ipm->h, sn->ip_map_cache);
                                return NULL;
                        }
                        cache_get(&ipm->h);
@@ -443,10 +457,8 @@ ip_map_cached_get(struct svc_rqst *rqstp)
 }
 
 static inline void
-ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+ip_map_cached_put(struct svc_xprt *xprt, struct ip_map *ipm)
 {
-       struct svc_xprt *xprt = rqstp->rq_xprt;
-
        if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
                spin_lock(&xprt->xpt_lock);
                if (xprt->xpt_auth_cache == NULL) {
@@ -456,15 +468,26 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
                }
                spin_unlock(&xprt->xpt_lock);
        }
-       if (ipm)
-               cache_put(&ipm->h, &ip_map_cache);
+       if (ipm) {
+               struct sunrpc_net *sn;
+
+               sn = net_generic(xprt->xpt_net, sunrpc_net_id);
+               cache_put(&ipm->h, sn->ip_map_cache);
+       }
 }
 
 void
-svcauth_unix_info_release(void *info)
+svcauth_unix_info_release(struct svc_xprt *xpt)
 {
-       struct ip_map *ipm = info;
-       cache_put(&ipm->h, &ip_map_cache);
+       struct ip_map *ipm;
+
+       ipm = xpt->xpt_auth_cache;
+       if (ipm != NULL) {
+               struct sunrpc_net *sn;
+
+               sn = net_generic(xpt->xpt_net, sunrpc_net_id);
+               cache_put(&ipm->h, sn->ip_map_cache);
+       }
 }
 
 /****************************************************************************
@@ -674,6 +697,8 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
        switch (ret) {
        case -ENOENT:
                return ERR_PTR(-ENOENT);
+       case -ETIMEDOUT:
+               return ERR_PTR(-ESHUTDOWN);
        case 0:
                gi = get_group_info(ug->gi);
                cache_put(&ug->h, &unix_gid_cache);
@@ -691,6 +716,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
        struct ip_map *ipm;
        struct group_info *gi;
        struct svc_cred *cred = &rqstp->rq_cred;
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct net *net = xprt->xpt_net;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        switch (rqstp->rq_addr.ss_family) {
        case AF_INET:
@@ -709,26 +737,27 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
        if (rqstp->rq_proc == 0)
                return SVC_OK;
 
-       ipm = ip_map_cached_get(rqstp);
+       ipm = ip_map_cached_get(xprt);
        if (ipm == NULL)
-               ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+               ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
                                    &sin6->sin6_addr);
 
        if (ipm == NULL)
                return SVC_DENIED;
 
-       switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
+       switch (cache_check(sn->ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
                default:
                        BUG();
-               case -EAGAIN:
                case -ETIMEDOUT:
+                       return SVC_CLOSE;
+               case -EAGAIN:
                        return SVC_DROP;
                case -ENOENT:
                        return SVC_DENIED;
                case 0:
                        rqstp->rq_client = &ipm->m_client->h;
                        kref_get(&rqstp->rq_client->ref);
-                       ip_map_cached_put(rqstp, ipm);
+                       ip_map_cached_put(xprt, ipm);
                        break;
        }
 
@@ -736,6 +765,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
        switch (PTR_ERR(gi)) {
        case -EAGAIN:
                return SVC_DROP;
+       case -ESHUTDOWN:
+               return SVC_CLOSE;
        case -ENOENT:
                break;
        default:
@@ -776,7 +807,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
        cred->cr_gid = (gid_t) -1;
        cred->cr_group_info = groups_alloc(0);
        if (cred->cr_group_info == NULL)
-               return SVC_DROP; /* kmalloc failure - client must retry */
+               return SVC_CLOSE; /* kmalloc failure - client must retry */
 
        /* Put NULL verifier */
        svc_putnl(resv, RPC_AUTH_NULL);
@@ -840,7 +871,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
                goto badcred;
        cred->cr_group_info = groups_alloc(slen);
        if (cred->cr_group_info == NULL)
-               return SVC_DROP;
+               return SVC_CLOSE;
        for (i = 0; i < slen; i++)
                GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
        if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
@@ -886,3 +917,56 @@ struct auth_ops svcauth_unix = {
        .set_client     = svcauth_unix_set_client,
 };
 
+int ip_map_cache_create(struct net *net)
+{
+       int err = -ENOMEM;
+       struct cache_detail *cd;
+       struct cache_head **tbl;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
+       if (cd == NULL)
+               goto err_cd;
+
+       tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL);
+       if (tbl == NULL)
+               goto err_tbl;
+
+       cd->owner = THIS_MODULE,
+       cd->hash_size = IP_HASHMAX,
+       cd->hash_table = tbl,
+       cd->name = "auth.unix.ip",
+       cd->cache_put = ip_map_put,
+       cd->cache_upcall = ip_map_upcall,
+       cd->cache_parse = ip_map_parse,
+       cd->cache_show = ip_map_show,
+       cd->match = ip_map_match,
+       cd->init = ip_map_init,
+       cd->update = update,
+       cd->alloc = ip_map_alloc,
+
+       err = cache_register_net(cd, net);
+       if (err)
+               goto err_reg;
+
+       sn->ip_map_cache = cd;
+       return 0;
+
+err_reg:
+       kfree(tbl);
+err_tbl:
+       kfree(cd);
+err_cd:
+       return err;
+}
+
+void ip_map_cache_destroy(struct net *net)
+{
+       struct sunrpc_net *sn;
+
+       sn = net_generic(net, sunrpc_net_id);
+       cache_purge(sn->ip_map_cache);
+       cache_unregister_net(sn->ip_map_cache, net);
+       kfree(sn->ip_map_cache->hash_table);
+       kfree(sn->ip_map_cache);
+}
index 7e534dd0907720073171365cc218b25e012b4c0c..07919e16be3ef3a274d7c099c2e58d2884067edf 100644 (file)
@@ -64,7 +64,8 @@ static void           svc_tcp_sock_detach(struct svc_xprt *);
 static void            svc_sock_free(struct svc_xprt *);
 
 static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
-                                         struct sockaddr *, int, int);
+                                         struct net *, struct sockaddr *,
+                                         int, int);
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key svc_key[2];
 static struct lock_class_key svc_slock_key[2];
@@ -657,10 +658,11 @@ static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
 }
 
 static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
+                                      struct net *net,
                                       struct sockaddr *sa, int salen,
                                       int flags)
 {
-       return svc_create_socket(serv, IPPROTO_UDP, sa, salen, flags);
+       return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
 }
 
 static struct svc_xprt_ops svc_udp_ops = {
@@ -1133,9 +1135,6 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
        reclen = htonl(0x80000000|((xbufp->len ) - 4));
        memcpy(xbufp->head[0].iov_base, &reclen, 4);
 
-       if (test_bit(XPT_DEAD, &rqstp->rq_xprt->xpt_flags))
-               return -ENOTCONN;
-
        sent = svc_sendto(rqstp, &rqstp->rq_res);
        if (sent != xbufp->len) {
                printk(KERN_NOTICE
@@ -1178,10 +1177,11 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
 }
 
 static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
+                                      struct net *net,
                                       struct sockaddr *sa, int salen,
                                       int flags)
 {
-       return svc_create_socket(serv, IPPROTO_TCP, sa, salen, flags);
+       return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
 }
 
 static struct svc_xprt_ops svc_tcp_ops = {
@@ -1258,19 +1258,13 @@ void svc_sock_update_bufs(struct svc_serv *serv)
         * The number of server threads has changed. Update
         * rcvbuf and sndbuf accordingly on all sockets
         */
-       struct list_head *le;
+       struct svc_sock *svsk;
 
        spin_lock_bh(&serv->sv_lock);
-       list_for_each(le, &serv->sv_permsocks) {
-               struct svc_sock *svsk =
-                       list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+       list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
                set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
-       }
-       list_for_each(le, &serv->sv_tempsocks) {
-               struct svc_sock *svsk =
-                       list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+       list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list)
                set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
-       }
        spin_unlock_bh(&serv->sv_lock);
 }
 EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
@@ -1385,6 +1379,7 @@ EXPORT_SYMBOL_GPL(svc_addsock);
  */
 static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
                                          int protocol,
+                                         struct net *net,
                                          struct sockaddr *sin, int len,
                                          int flags)
 {
@@ -1421,7 +1416,7 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
                return ERR_PTR(-EINVAL);
        }
 
-       error = sock_create_kern(family, type, protocol, &sock);
+       error = __sock_create(net, family, type, protocol, &sock, 1);
        if (error < 0)
                return ERR_PTR(error);
 
index a1f82a87d34d1fa6e4c136017735994ac558a3ed..cd9e841e7492ceecdd23859a7ec532733371293c 100644 (file)
@@ -111,6 +111,23 @@ xdr_decode_string_inplace(__be32 *p, char **sp,
 }
 EXPORT_SYMBOL_GPL(xdr_decode_string_inplace);
 
+/**
+ * xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
+ * @buf: XDR buffer where string resides
+ * @len: length of string, in bytes
+ *
+ */
+void
+xdr_terminate_string(struct xdr_buf *buf, const u32 len)
+{
+       char *kaddr;
+
+       kaddr = kmap_atomic(buf->pages[0], KM_USER0);
+       kaddr[buf->page_base + len] = '\0';
+       kunmap_atomic(kaddr, KM_USER0);
+}
+EXPORT_SYMBOL(xdr_terminate_string);
+
 void
 xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
                 unsigned int len)
@@ -395,24 +412,29 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
 {
        struct kvec *tail;
        size_t copy;
-       char *p;
        unsigned int pglen = buf->page_len;
+       unsigned int tailbuf_len;
 
        tail = buf->tail;
        BUG_ON (len > pglen);
 
+       tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len;
+
        /* Shift the tail first */
-       if (tail->iov_len != 0) {
-               p = (char *)tail->iov_base + len;
+       if (tailbuf_len != 0) {
+               unsigned int free_space = tailbuf_len - tail->iov_len;
+
+               if (len < free_space)
+                       free_space = len;
+               tail->iov_len += free_space;
+
+               copy = len;
                if (tail->iov_len > len) {
-                       copy = tail->iov_len - len;
-                       memmove(p, tail->iov_base, copy);
+                       char *p = (char *)tail->iov_base + len;
+                       memmove(p, tail->iov_base, tail->iov_len - len);
                } else
-                       buf->buflen -= len;
-               /* Copy from the inlined pages into the tail */
-               copy = len;
-               if (copy > tail->iov_len)
                        copy = tail->iov_len;
+               /* Copy from the inlined pages into the tail */
                _copy_from_pages((char *)tail->iov_base,
                                buf->pages, buf->page_base + pglen - len,
                                copy);
@@ -550,6 +572,27 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
 }
 EXPORT_SYMBOL_GPL(xdr_init_decode);
 
+/**
+ * xdr_inline_peek - Allow read-ahead in the XDR data stream
+ * @xdr: pointer to xdr_stream struct
+ * @nbytes: number of bytes of data to decode
+ *
+ * Check if the input buffer is long enough to enable us to decode
+ * 'nbytes' more bytes of data starting at the current position.
+ * If so return the current pointer without updating the current
+ * pointer position.
+ */
+__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
+{
+       __be32 *p = xdr->p;
+       __be32 *q = p + XDR_QUADLEN(nbytes);
+
+       if (unlikely(q > xdr->end || q < p))
+               return NULL;
+       return p;
+}
+EXPORT_SYMBOL_GPL(xdr_inline_peek);
+
 /**
  * xdr_inline_decode - Retrieve non-page XDR data to decode
  * @xdr: pointer to xdr_stream struct
index 970fb00f388ce532d7f0a4e3c7285f98e57af2f5..4c8f18aff7c341885764c6f1525a292688328c5d 100644 (file)
@@ -199,8 +199,6 @@ int xprt_reserve_xprt(struct rpc_task *task)
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
                if (task == xprt->snd_task)
                        return 1;
-               if (task == NULL)
-                       return 0;
                goto out_sleep;
        }
        xprt->snd_task = task;
@@ -757,13 +755,11 @@ static void xprt_connect_status(struct rpc_task *task)
  */
 struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
 {
-       struct list_head *pos;
+       struct rpc_rqst *entry;
 
-       list_for_each(pos, &xprt->recv) {
-               struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
+       list_for_each_entry(entry, &xprt->recv, rq_list)
                if (entry->rq_xid == xid)
                        return entry;
-       }
 
        dprintk("RPC:       xprt_lookup_rqst did not find xid %08x\n",
                        ntohl(xid));
@@ -962,6 +958,37 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
        spin_unlock(&xprt->reserve_lock);
 }
 
+struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
+{
+       struct rpc_xprt *xprt;
+
+       xprt = kzalloc(size, GFP_KERNEL);
+       if (xprt == NULL)
+               goto out;
+
+       xprt->max_reqs = max_req;
+       xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
+       if (xprt->slot == NULL)
+               goto out_free;
+
+       xprt->xprt_net = get_net(net);
+       return xprt;
+
+out_free:
+       kfree(xprt);
+out:
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(xprt_alloc);
+
+void xprt_free(struct rpc_xprt *xprt)
+{
+       put_net(xprt->xprt_net);
+       kfree(xprt->slot);
+       kfree(xprt);
+}
+EXPORT_SYMBOL_GPL(xprt_free);
+
 /**
  * xprt_reserve - allocate an RPC request slot
  * @task: RPC task requesting a slot allocation
index d718b8fa95253c61d0e0adedd0bccf5cd84d89ed..09af4fab1a456c32c5c7b414ab8923cb29a8ef02 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/sysctl.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/svc_rdma.h>
@@ -74,6 +75,8 @@ atomic_t rdma_stat_sq_prod;
 struct kmem_cache *svc_rdma_map_cachep;
 struct kmem_cache *svc_rdma_ctxt_cachep;
 
+struct workqueue_struct *svc_rdma_wq;
+
 /*
  * This function implements reading and resetting an atomic_t stat
  * variable through read/write to a proc file. Any write to the file
@@ -231,7 +234,7 @@ static ctl_table svcrdma_root_table[] = {
 void svc_rdma_cleanup(void)
 {
        dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
-       flush_scheduled_work();
+       destroy_workqueue(svc_rdma_wq);
        if (svcrdma_table_header) {
                unregister_sysctl_table(svcrdma_table_header);
                svcrdma_table_header = NULL;
@@ -249,6 +252,11 @@ int svc_rdma_init(void)
        dprintk("\tsq_depth         : %d\n",
                svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
        dprintk("\tmax_inline       : %d\n", svcrdma_max_req_size);
+
+       svc_rdma_wq = alloc_workqueue("svc_rdma", 0, 0);
+       if (!svc_rdma_wq)
+               return -ENOMEM;
+
        if (!svcrdma_table_header)
                svcrdma_table_header =
                        register_sysctl_table(svcrdma_root_table);
@@ -283,6 +291,7 @@ int svc_rdma_init(void)
        kmem_cache_destroy(svc_rdma_map_cachep);
  err0:
        unregister_sysctl_table(svcrdma_table_header);
+       destroy_workqueue(svc_rdma_wq);
        return -ENOMEM;
 }
 MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
index 0194de814933aea3c36d41a6c014eca68c244bd2..df67211c4bafa34449d7449cf221e354884bd39d 100644 (file)
@@ -263,9 +263,9 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
        frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
        for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
                frmr->page_list->page_list[page_no] =
-                       ib_dma_map_single(xprt->sc_cm_id->device,
-                                         page_address(rqstp->rq_arg.pages[page_no]),
-                                         PAGE_SIZE, DMA_FROM_DEVICE);
+                       ib_dma_map_page(xprt->sc_cm_id->device,
+                                       rqstp->rq_arg.pages[page_no], 0,
+                                       PAGE_SIZE, DMA_FROM_DEVICE);
                if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                         frmr->page_list->page_list[page_no]))
                        goto fatal_err;
@@ -309,17 +309,21 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
                             int count)
 {
        int i;
+       unsigned long off;
 
        ctxt->count = count;
        ctxt->direction = DMA_FROM_DEVICE;
        for (i = 0; i < count; i++) {
                ctxt->sge[i].length = 0; /* in case map fails */
                if (!frmr) {
+                       BUG_ON(0 == virt_to_page(vec[i].iov_base));
+                       off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
                        ctxt->sge[i].addr =
-                               ib_dma_map_single(xprt->sc_cm_id->device,
-                                                 vec[i].iov_base,
-                                                 vec[i].iov_len,
-                                                 DMA_FROM_DEVICE);
+                               ib_dma_map_page(xprt->sc_cm_id->device,
+                                               virt_to_page(vec[i].iov_base),
+                                               off,
+                                               vec[i].iov_len,
+                                               DMA_FROM_DEVICE);
                        if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                                 ctxt->sge[i].addr))
                                return -EINVAL;
@@ -491,6 +495,7 @@ next_sge:
                        printk(KERN_ERR "svcrdma: Error %d posting RDMA_READ\n",
                               err);
                        set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+                       svc_rdma_unmap_dma(ctxt);
                        svc_rdma_put_context(ctxt, 0);
                        goto out;
                }
index b15e1ebb2bfaca8ea39753a05d3fdd0fc630b92c..249a835b703f1f0ec46c6051ff98249227876509 100644 (file)
@@ -70,8 +70,8 @@
  * on extra page for the RPCRMDA header.
  */
 static int fast_reg_xdr(struct svcxprt_rdma *xprt,
-                struct xdr_buf *xdr,
-                struct svc_rdma_req_map *vec)
+                       struct xdr_buf *xdr,
+                       struct svc_rdma_req_map *vec)
 {
        int sge_no;
        u32 sge_bytes;
@@ -96,21 +96,25 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
        vec->count = 2;
        sge_no++;
 
-       /* Build the FRMR */
+       /* Map the XDR head */
        frmr->kva = frva;
        frmr->direction = DMA_TO_DEVICE;
        frmr->access_flags = 0;
        frmr->map_len = PAGE_SIZE;
        frmr->page_list_len = 1;
+       page_off = (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
        frmr->page_list->page_list[page_no] =
-               ib_dma_map_single(xprt->sc_cm_id->device,
-                                 (void *)xdr->head[0].iov_base,
-                                 PAGE_SIZE, DMA_TO_DEVICE);
+               ib_dma_map_page(xprt->sc_cm_id->device,
+                               virt_to_page(xdr->head[0].iov_base),
+                               page_off,
+                               PAGE_SIZE - page_off,
+                               DMA_TO_DEVICE);
        if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                 frmr->page_list->page_list[page_no]))
                goto fatal_err;
        atomic_inc(&xprt->sc_dma_used);
 
+       /* Map the XDR page list */
        page_off = xdr->page_base;
        page_bytes = xdr->page_len + page_off;
        if (!page_bytes)
@@ -128,9 +132,9 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
                page_bytes -= sge_bytes;
 
                frmr->page_list->page_list[page_no] =
-                       ib_dma_map_single(xprt->sc_cm_id->device,
-                                         page_address(page),
-                                         PAGE_SIZE, DMA_TO_DEVICE);
+                       ib_dma_map_page(xprt->sc_cm_id->device,
+                                       page, page_off,
+                                       sge_bytes, DMA_TO_DEVICE);
                if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                         frmr->page_list->page_list[page_no]))
                        goto fatal_err;
@@ -166,8 +170,10 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
                vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
 
                frmr->page_list->page_list[page_no] =
-                       ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
-                                         DMA_TO_DEVICE);
+                   ib_dma_map_page(xprt->sc_cm_id->device, virt_to_page(va),
+                                   page_off,
+                                   PAGE_SIZE,
+                                   DMA_TO_DEVICE);
                if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                         frmr->page_list->page_list[page_no]))
                        goto fatal_err;
@@ -245,6 +251,35 @@ static int map_xdr(struct svcxprt_rdma *xprt,
        return 0;
 }
 
+static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
+                             struct xdr_buf *xdr,
+                             u32 xdr_off, size_t len, int dir)
+{
+       struct page *page;
+       dma_addr_t dma_addr;
+       if (xdr_off < xdr->head[0].iov_len) {
+               /* This offset is in the head */
+               xdr_off += (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
+               page = virt_to_page(xdr->head[0].iov_base);
+       } else {
+               xdr_off -= xdr->head[0].iov_len;
+               if (xdr_off < xdr->page_len) {
+                       /* This offset is in the page list */
+                       page = xdr->pages[xdr_off >> PAGE_SHIFT];
+                       xdr_off &= ~PAGE_MASK;
+               } else {
+                       /* This offset is in the tail */
+                       xdr_off -= xdr->page_len;
+                       xdr_off += (unsigned long)
+                               xdr->tail[0].iov_base & ~PAGE_MASK;
+                       page = virt_to_page(xdr->tail[0].iov_base);
+               }
+       }
+       dma_addr = ib_dma_map_page(xprt->sc_cm_id->device, page, xdr_off,
+                                  min_t(size_t, PAGE_SIZE, len), dir);
+       return dma_addr;
+}
+
 /* Assumptions:
  * - We are using FRMR
  *     - or -
@@ -293,10 +328,9 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
                sge[sge_no].length = sge_bytes;
                if (!vec->frmr) {
                        sge[sge_no].addr =
-                               ib_dma_map_single(xprt->sc_cm_id->device,
-                                                 (void *)
-                                                 vec->sge[xdr_sge_no].iov_base + sge_off,
-                                                 sge_bytes, DMA_TO_DEVICE);
+                               dma_map_xdr(xprt, &rqstp->rq_res, xdr_off,
+                                           sge_bytes, DMA_TO_DEVICE);
+                       xdr_off += sge_bytes;
                        if (ib_dma_mapping_error(xprt->sc_cm_id->device,
                                                 sge[sge_no].addr))
                                goto err;
@@ -333,6 +367,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
                goto err;
        return 0;
  err:
+       svc_rdma_unmap_dma(ctxt);
+       svc_rdma_put_frmr(xprt, vec->frmr);
        svc_rdma_put_context(ctxt, 0);
        /* Fatal error, close transport */
        return -EIO;
@@ -494,7 +530,8 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
  * In all three cases, this function prepares the RPCRDMA header in
  * sge[0], the 'type' parameter indicates the type to place in the
  * RPCRDMA header, and the 'byte_count' field indicates how much of
- * the XDR to include in this RDMA_SEND.
+ * the XDR to include in this RDMA_SEND. NB: The offset of the payload
+ * to send is zero in the XDR.
  */
 static int send_reply(struct svcxprt_rdma *rdma,
                      struct svc_rqst *rqstp,
@@ -536,23 +573,24 @@ static int send_reply(struct svcxprt_rdma *rdma,
        ctxt->sge[0].lkey = rdma->sc_dma_lkey;
        ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
        ctxt->sge[0].addr =
-               ib_dma_map_single(rdma->sc_cm_id->device, page_address(page),
-                                 ctxt->sge[0].length, DMA_TO_DEVICE);
+           ib_dma_map_page(rdma->sc_cm_id->device, page, 0,
+                           ctxt->sge[0].length, DMA_TO_DEVICE);
        if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
                goto err;
        atomic_inc(&rdma->sc_dma_used);
 
        ctxt->direction = DMA_TO_DEVICE;
 
-       /* Determine how many of our SGE are to be transmitted */
+       /* Map the payload indicated by 'byte_count' */
        for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
+               int xdr_off = 0;
                sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
                byte_count -= sge_bytes;
                if (!vec->frmr) {
                        ctxt->sge[sge_no].addr =
-                               ib_dma_map_single(rdma->sc_cm_id->device,
-                                                 vec->sge[sge_no].iov_base,
-                                                 sge_bytes, DMA_TO_DEVICE);
+                               dma_map_xdr(rdma, &rqstp->rq_res, xdr_off,
+                                           sge_bytes, DMA_TO_DEVICE);
+                       xdr_off += sge_bytes;
                        if (ib_dma_mapping_error(rdma->sc_cm_id->device,
                                                 ctxt->sge[sge_no].addr))
                                goto err;
index edea15a54e51d90d03b0149e6602f38017743758..9df1eadc912a837c8863bd4a69733a23dbbab134 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
 #include <linux/sunrpc/svc_rdma.h>
@@ -52,6 +53,7 @@
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
 static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+                                       struct net *net,
                                        struct sockaddr *sa, int salen,
                                        int flags);
 static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
@@ -89,6 +91,9 @@ struct svc_xprt_class svc_rdma_class = {
 /* WR context cache. Created in svc_rdma.c  */
 extern struct kmem_cache *svc_rdma_ctxt_cachep;
 
+/* Workqueue created in svc_rdma.c */
+extern struct workqueue_struct *svc_rdma_wq;
+
 struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 {
        struct svc_rdma_op_ctxt *ctxt;
@@ -120,7 +125,7 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
                 */
                if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
                        atomic_dec(&xprt->sc_dma_used);
-                       ib_dma_unmap_single(xprt->sc_cm_id->device,
+                       ib_dma_unmap_page(xprt->sc_cm_id->device,
                                            ctxt->sge[i].addr,
                                            ctxt->sge[i].length,
                                            ctxt->direction);
@@ -502,8 +507,8 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
                BUG_ON(sge_no >= xprt->sc_max_sge);
                page = svc_rdma_get_page();
                ctxt->pages[sge_no] = page;
-               pa = ib_dma_map_single(xprt->sc_cm_id->device,
-                                    page_address(page), PAGE_SIZE,
+               pa = ib_dma_map_page(xprt->sc_cm_id->device,
+                                    page, 0, PAGE_SIZE,
                                     DMA_FROM_DEVICE);
                if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
                        goto err_put_ctxt;
@@ -511,9 +516,9 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
                ctxt->sge[sge_no].addr = pa;
                ctxt->sge[sge_no].length = PAGE_SIZE;
                ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
+               ctxt->count = sge_no + 1;
                buflen += PAGE_SIZE;
        }
-       ctxt->count = sge_no;
        recv_wr.next = NULL;
        recv_wr.sg_list = &ctxt->sge[0];
        recv_wr.num_sge = ctxt->count;
@@ -529,6 +534,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
        return ret;
 
  err_put_ctxt:
+       svc_rdma_unmap_dma(ctxt);
        svc_rdma_put_context(ctxt, 1);
        return -ENOMEM;
 }
@@ -670,6 +676,7 @@ static int rdma_cma_handler(struct rdma_cm_id *cma_id,
  * Create a listening RDMA service endpoint.
  */
 static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+                                       struct net *net,
                                        struct sockaddr *sa, int salen,
                                        int flags)
 {
@@ -798,8 +805,8 @@ static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
                if (ib_dma_mapping_error(frmr->mr->device, addr))
                        continue;
                atomic_dec(&xprt->sc_dma_used);
-               ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
-                                   frmr->direction);
+               ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
+                                 frmr->direction);
        }
 }
 
@@ -1184,7 +1191,7 @@ static void svc_rdma_free(struct svc_xprt *xprt)
        struct svcxprt_rdma *rdma =
                container_of(xprt, struct svcxprt_rdma, sc_xprt);
        INIT_WORK(&rdma->sc_work, __svc_rdma_free);
-       schedule_work(&rdma->sc_work);
+       queue_work(svc_rdma_wq, &rdma->sc_work);
 }
 
 static int svc_rdma_has_wspace(struct svc_xprt *xprt)
@@ -1274,7 +1281,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
                                   atomic_read(&xprt->sc_sq_count) <
                                   xprt->sc_sq_depth);
                        if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
-                               return 0;
+                               return -ENOTCONN;
                        continue;
                }
                /* Take a transport ref for each WR posted */
@@ -1306,7 +1313,6 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
                         enum rpcrdma_errcode err)
 {
        struct ib_send_wr err_wr;
-       struct ib_sge sge;
        struct page *p;
        struct svc_rdma_op_ctxt *ctxt;
        u32 *va;
@@ -1319,26 +1325,27 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
        /* XDR encode error */
        length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
 
+       ctxt = svc_rdma_get_context(xprt);
+       ctxt->direction = DMA_FROM_DEVICE;
+       ctxt->count = 1;
+       ctxt->pages[0] = p;
+
        /* Prepare SGE for local address */
-       sge.addr = ib_dma_map_single(xprt->sc_cm_id->device,
-                                  page_address(p), PAGE_SIZE, DMA_FROM_DEVICE);
-       if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+       ctxt->sge[0].addr = ib_dma_map_page(xprt->sc_cm_id->device,
+                                           p, 0, length, DMA_FROM_DEVICE);
+       if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
                put_page(p);
                return;
        }
        atomic_inc(&xprt->sc_dma_used);
-       sge.lkey = xprt->sc_dma_lkey;
-       sge.length = length;
-
-       ctxt = svc_rdma_get_context(xprt);
-       ctxt->count = 1;
-       ctxt->pages[0] = p;
+       ctxt->sge[0].lkey = xprt->sc_dma_lkey;
+       ctxt->sge[0].length = length;
 
        /* Prepare SEND WR */
        memset(&err_wr, 0, sizeof err_wr);
        ctxt->wr_op = IB_WR_SEND;
        err_wr.wr_id = (unsigned long)ctxt;
-       err_wr.sg_list = &sge;
+       err_wr.sg_list = ctxt->sge;
        err_wr.num_sge = 1;
        err_wr.opcode = IB_WR_SEND;
        err_wr.send_flags = IB_SEND_SIGNALED;
@@ -1348,9 +1355,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
        if (ret) {
                dprintk("svcrdma: Error %d posting send for protocol error\n",
                        ret);
-               ib_dma_unmap_single(xprt->sc_cm_id->device,
-                                 sge.addr, PAGE_SIZE,
-                                 DMA_FROM_DEVICE);
+               svc_rdma_unmap_dma(ctxt);
                svc_rdma_put_context(ctxt, 1);
        }
 }
index a85e866a77f73d2abde623b3d89a264331f63999..0867070bb5ca2a9fc1e9749c6c06412cdc9c40ff 100644 (file)
@@ -237,8 +237,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
 
        dprintk("RPC:       %s: called\n", __func__);
 
-       cancel_delayed_work(&r_xprt->rdma_connect);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&r_xprt->rdma_connect);
 
        xprt_clear_connected(xprt);
 
@@ -251,9 +250,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
 
        xprt_rdma_free_addresses(xprt);
 
-       kfree(xprt->slot);
-       xprt->slot = NULL;
-       kfree(xprt);
+       xprt_free(xprt);
 
        dprintk("RPC:       %s: returning\n", __func__);
 
@@ -285,23 +282,14 @@ xprt_setup_rdma(struct xprt_create *args)
                return ERR_PTR(-EBADF);
        }
 
-       xprt = kzalloc(sizeof(struct rpcrdma_xprt), GFP_KERNEL);
+       xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt),
+                       xprt_rdma_slot_table_entries);
        if (xprt == NULL) {
                dprintk("RPC:       %s: couldn't allocate rpcrdma_xprt\n",
                        __func__);
                return ERR_PTR(-ENOMEM);
        }
 
-       xprt->max_reqs = xprt_rdma_slot_table_entries;
-       xprt->slot = kcalloc(xprt->max_reqs,
-                               sizeof(struct rpc_rqst), GFP_KERNEL);
-       if (xprt->slot == NULL) {
-               dprintk("RPC:       %s: couldn't allocate %d slots\n",
-                       __func__, xprt->max_reqs);
-               kfree(xprt);
-               return ERR_PTR(-ENOMEM);
-       }
-
        /* 60 second timeout, no retries */
        xprt->timeout = &xprt_rdma_default_timeout;
        xprt->bind_timeout = (60U * HZ);
@@ -410,8 +398,7 @@ out3:
 out2:
        rpcrdma_ia_close(&new_xprt->rx_ia);
 out1:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ERR_PTR(rc);
 }
 
@@ -460,7 +447,7 @@ xprt_rdma_connect(struct rpc_task *task)
        } else {
                schedule_delayed_work(&r_xprt->rdma_connect, 0);
                if (!RPC_IS_ASYNC(task))
-                       flush_scheduled_work();
+                       flush_delayed_work(&r_xprt->rdma_connect);
        }
 }
 
index fe9306bf10cc7f3bba4590ddf853c2ac39eadae9..dfcab5ac65af329149c637b3365751ce66999540 100644 (file)
@@ -774,8 +774,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
 
        xs_close(xprt);
        xs_free_peer_addresses(xprt);
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        module_put(THIS_MODULE);
 }
 
@@ -1516,7 +1515,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
        xs_update_peer_port(xprt);
 }
 
-static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
+static unsigned short xs_get_srcport(struct sock_xprt *transport)
 {
        unsigned short port = transport->srcport;
 
@@ -1525,7 +1524,7 @@ static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket
        return port;
 }
 
-static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
+static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
 {
        if (transport->srcport != 0)
                transport->srcport = 0;
@@ -1535,23 +1534,18 @@ static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket
                return xprt_max_resvport;
        return --port;
 }
-
-static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
+static int xs_bind(struct sock_xprt *transport, struct socket *sock)
 {
-       struct sockaddr_in myaddr = {
-               .sin_family = AF_INET,
-       };
-       struct sockaddr_in *sa;
+       struct sockaddr_storage myaddr;
        int err, nloop = 0;
-       unsigned short port = xs_get_srcport(transport, sock);
+       unsigned short port = xs_get_srcport(transport);
        unsigned short last;
 
-       sa = (struct sockaddr_in *)&transport->srcaddr;
-       myaddr.sin_addr = sa->sin_addr;
+       memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
        do {
-               myaddr.sin_port = htons(port);
-               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
-                                               sizeof(myaddr));
+               rpc_set_port((struct sockaddr *)&myaddr, port);
+               err = kernel_bind(sock, (struct sockaddr *)&myaddr,
+                               transport->xprt.addrlen);
                if (port == 0)
                        break;
                if (err == 0) {
@@ -1559,48 +1553,23 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
                        break;
                }
                last = port;
-               port = xs_next_srcport(transport, sock, port);
+               port = xs_next_srcport(transport, port);
                if (port > last)
                        nloop++;
        } while (err == -EADDRINUSE && nloop != 2);
-       dprintk("RPC:       %s %pI4:%u: %s (%d)\n",
-                       __func__, &myaddr.sin_addr,
-                       port, err ? "failed" : "ok", err);
-       return err;
-}
-
-static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
-{
-       struct sockaddr_in6 myaddr = {
-               .sin6_family = AF_INET6,
-       };
-       struct sockaddr_in6 *sa;
-       int err, nloop = 0;
-       unsigned short port = xs_get_srcport(transport, sock);
-       unsigned short last;
 
-       sa = (struct sockaddr_in6 *)&transport->srcaddr;
-       myaddr.sin6_addr = sa->sin6_addr;
-       do {
-               myaddr.sin6_port = htons(port);
-               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
-                                               sizeof(myaddr));
-               if (port == 0)
-                       break;
-               if (err == 0) {
-                       transport->srcport = port;
-                       break;
-               }
-               last = port;
-               port = xs_next_srcport(transport, sock, port);
-               if (port > last)
-                       nloop++;
-       } while (err == -EADDRINUSE && nloop != 2);
-       dprintk("RPC:       xs_bind6 %pI6:%u: %s (%d)\n",
-               &myaddr.sin6_addr, port, err ? "failed" : "ok", err);
+       if (myaddr.ss_family == AF_INET)
+               dprintk("RPC:       %s %pI4:%u: %s (%d)\n", __func__,
+                               &((struct sockaddr_in *)&myaddr)->sin_addr,
+                               port, err ? "failed" : "ok", err);
+       else
+               dprintk("RPC:       %s %pI6:%u: %s (%d)\n", __func__,
+                               &((struct sockaddr_in6 *)&myaddr)->sin6_addr,
+                               port, err ? "failed" : "ok", err);
        return err;
 }
 
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key xs_key[2];
 static struct lock_class_key xs_slock_key[2];
@@ -1622,6 +1591,18 @@ static inline void xs_reclassify_socket6(struct socket *sock)
        sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
                &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
 }
+
+static inline void xs_reclassify_socket(int family, struct socket *sock)
+{
+       switch (family) {
+       case AF_INET:
+               xs_reclassify_socket4(sock);
+               break;
+       case AF_INET6:
+               xs_reclassify_socket6(sock);
+               break;
+       }
+}
 #else
 static inline void xs_reclassify_socket4(struct socket *sock)
 {
@@ -1630,8 +1611,36 @@ static inline void xs_reclassify_socket4(struct socket *sock)
 static inline void xs_reclassify_socket6(struct socket *sock)
 {
 }
+
+static inline void xs_reclassify_socket(int family, struct socket *sock)
+{
+}
 #endif
 
+static struct socket *xs_create_sock(struct rpc_xprt *xprt,
+               struct sock_xprt *transport, int family, int type, int protocol)
+{
+       struct socket *sock;
+       int err;
+
+       err = __sock_create(xprt->xprt_net, family, type, protocol, &sock, 1);
+       if (err < 0) {
+               dprintk("RPC:       can't create %d transport socket (%d).\n",
+                               protocol, -err);
+               goto out;
+       }
+       xs_reclassify_socket(family, sock);
+
+       if (xs_bind(transport, sock)) {
+               sock_release(sock);
+               goto out;
+       }
+
+       return sock;
+out:
+       return ERR_PTR(err);
+}
+
 static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1661,82 +1670,23 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
        xs_udp_do_set_buffer_size(xprt);
 }
 
-/**
- * xs_udp_connect_worker4 - set up a UDP socket
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_udp_connect_worker4(struct work_struct *work)
+static void xs_udp_setup_socket(struct work_struct *work)
 {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
        struct rpc_xprt *xprt = &transport->xprt;
        struct socket *sock = transport->sock;
-       int err, status = -EIO;
+       int status = -EIO;
 
        if (xprt->shutdown)
                goto out;
 
        /* Start by resetting any existing state */
        xs_reset_transport(transport);
-
-       err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
+       sock = xs_create_sock(xprt, transport,
+                       xs_addr(xprt)->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+       if (IS_ERR(sock))
                goto out;
-       }
-       xs_reclassify_socket4(sock);
-
-       if (xs_bind4(transport, sock)) {
-               sock_release(sock);
-               goto out;
-       }
-
-       dprintk("RPC:       worker connecting xprt %p via %s to "
-                               "%s (port %s)\n", xprt,
-                       xprt->address_strings[RPC_DISPLAY_PROTO],
-                       xprt->address_strings[RPC_DISPLAY_ADDR],
-                       xprt->address_strings[RPC_DISPLAY_PORT]);
-
-       xs_udp_finish_connecting(xprt, sock);
-       status = 0;
-out:
-       xprt_clear_connecting(xprt);
-       xprt_wake_pending_tasks(xprt, status);
-}
-
-/**
- * xs_udp_connect_worker6 - set up a UDP socket
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_udp_connect_worker6(struct work_struct *work)
-{
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-       struct socket *sock = transport->sock;
-       int err, status = -EIO;
-
-       if (xprt->shutdown)
-               goto out;
-
-       /* Start by resetting any existing state */
-       xs_reset_transport(transport);
-
-       err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
-               goto out;
-       }
-       xs_reclassify_socket6(sock);
-
-       if (xs_bind6(transport, sock) < 0) {
-               sock_release(sock);
-               goto out;
-       }
 
        dprintk("RPC:       worker connecting xprt %p via %s to "
                                "%s (port %s)\n", xprt,
@@ -1755,12 +1705,12 @@ out:
  * We need to preserve the port number so the reply cache on the server can
  * find our cached RPC replies when we get around to reconnecting.
  */
-static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+static void xs_abort_connection(struct sock_xprt *transport)
 {
        int result;
        struct sockaddr any;
 
-       dprintk("RPC:       disconnecting xprt %p to reuse port\n", xprt);
+       dprintk("RPC:       disconnecting xprt %p to reuse port\n", transport);
 
        /*
         * Disconnect the transport socket by doing a connect operation
@@ -1770,13 +1720,13 @@ static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transpo
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
        if (!result)
-               xs_sock_mark_closed(xprt);
+               xs_sock_mark_closed(&transport->xprt);
        else
                dprintk("RPC:       AF_UNSPEC connect return code %d\n",
                                result);
 }
 
-static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+static void xs_tcp_reuse_connection(struct sock_xprt *transport)
 {
        unsigned int state = transport->inet->sk_state;
 
@@ -1799,7 +1749,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *tra
                                "sk_shutdown set to %d\n",
                                __func__, transport->inet->sk_shutdown);
        }
-       xs_abort_connection(xprt, transport);
+       xs_abort_connection(transport);
 }
 
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
@@ -1852,12 +1802,12 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
-               struct sock_xprt *transport,
-               struct socket *(*create_sock)(struct rpc_xprt *,
-                       struct sock_xprt *))
+static void xs_tcp_setup_socket(struct work_struct *work)
 {
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
        struct socket *sock = transport->sock;
+       struct rpc_xprt *xprt = &transport->xprt;
        int status = -EIO;
 
        if (xprt->shutdown)
@@ -1865,7 +1815,8 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
 
        if (!sock) {
                clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
-               sock = create_sock(xprt, transport);
+               sock = xs_create_sock(xprt, transport,
+                               xs_addr(xprt)->sa_family, SOCK_STREAM, IPPROTO_TCP);
                if (IS_ERR(sock)) {
                        status = PTR_ERR(sock);
                        goto out;
@@ -1876,7 +1827,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
                abort_and_exit = test_and_clear_bit(XPRT_CONNECTION_ABORT,
                                &xprt->state);
                /* "close" the socket, preserving the local port */
-               xs_tcp_reuse_connection(xprt, transport);
+               xs_tcp_reuse_connection(transport);
 
                if (abort_and_exit)
                        goto out_eagain;
@@ -1925,84 +1876,6 @@ out:
        xprt_wake_pending_tasks(xprt, status);
 }
 
-static struct socket *xs_create_tcp_sock4(struct rpc_xprt *xprt,
-               struct sock_xprt *transport)
-{
-       struct socket *sock;
-       int err;
-
-       /* start from scratch */
-       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create TCP transport socket (%d).\n",
-                               -err);
-               goto out_err;
-       }
-       xs_reclassify_socket4(sock);
-
-       if (xs_bind4(transport, sock) < 0) {
-               sock_release(sock);
-               goto out_err;
-       }
-       return sock;
-out_err:
-       return ERR_PTR(-EIO);
-}
-
-/**
- * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_tcp_connect_worker4(struct work_struct *work)
-{
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-
-       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock4);
-}
-
-static struct socket *xs_create_tcp_sock6(struct rpc_xprt *xprt,
-               struct sock_xprt *transport)
-{
-       struct socket *sock;
-       int err;
-
-       /* start from scratch */
-       err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock);
-       if (err < 0) {
-               dprintk("RPC:       can't create TCP transport socket (%d).\n",
-                               -err);
-               goto out_err;
-       }
-       xs_reclassify_socket6(sock);
-
-       if (xs_bind6(transport, sock) < 0) {
-               sock_release(sock);
-               goto out_err;
-       }
-       return sock;
-out_err:
-       return ERR_PTR(-EIO);
-}
-
-/**
- * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_tcp_connect_worker6(struct work_struct *work)
-{
-       struct sock_xprt *transport =
-               container_of(work, struct sock_xprt, connect_worker.work);
-       struct rpc_xprt *xprt = &transport->xprt;
-
-       xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock6);
-}
-
 /**
  * xs_connect - connect a socket to a remote endpoint
  * @task: address of RPC task that manages state of connect request
@@ -2262,6 +2135,31 @@ static struct rpc_xprt_ops bc_tcp_ops = {
        .print_stats            = xs_tcp_print_stats,
 };
 
+static int xs_init_anyaddr(const int family, struct sockaddr *sap)
+{
+       static const struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_ANY),
+       };
+       static const struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+       };
+
+       switch (family) {
+       case AF_INET:
+               memcpy(sap, &sin, sizeof(sin));
+               break;
+       case AF_INET6:
+               memcpy(sap, &sin6, sizeof(sin6));
+               break;
+       default:
+               dprintk("RPC:       %s: Bad address family\n", __func__);
+               return -EAFNOSUPPORT;
+       }
+       return 0;
+}
+
 static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
                                      unsigned int slot_table_size)
 {
@@ -2273,27 +2171,25 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
                return ERR_PTR(-EBADF);
        }
 
-       new = kzalloc(sizeof(*new), GFP_KERNEL);
-       if (new == NULL) {
+       xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size);
+       if (xprt == NULL) {
                dprintk("RPC:       xs_setup_xprt: couldn't allocate "
                                "rpc_xprt\n");
                return ERR_PTR(-ENOMEM);
        }
-       xprt = &new->xprt;
-
-       xprt->max_reqs = slot_table_size;
-       xprt->slot = kcalloc(xprt->max_reqs, sizeof(struct rpc_rqst), GFP_KERNEL);
-       if (xprt->slot == NULL) {
-               kfree(xprt);
-               dprintk("RPC:       xs_setup_xprt: couldn't allocate slot "
-                               "table\n");
-               return ERR_PTR(-ENOMEM);
-       }
 
+       new = container_of(xprt, struct sock_xprt, xprt);
        memcpy(&xprt->addr, args->dstaddr, args->addrlen);
        xprt->addrlen = args->addrlen;
        if (args->srcaddr)
                memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
+       else {
+               int err;
+               err = xs_init_anyaddr(args->dstaddr->sa_family,
+                                       (struct sockaddr *)&new->srcaddr);
+               if (err != 0)
+                       return ERR_PTR(err);
+       }
 
        return xprt;
 }
@@ -2341,7 +2237,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                        xprt_set_bound(xprt);
 
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_udp_connect_worker4);
+                                       xs_udp_setup_socket);
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
                break;
        case AF_INET6:
@@ -2349,7 +2245,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                        xprt_set_bound(xprt);
 
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_udp_connect_worker6);
+                                       xs_udp_setup_socket);
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
                break;
        default:
@@ -2371,8 +2267,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
 }
 
@@ -2416,7 +2311,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                        xprt_set_bound(xprt);
 
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_tcp_connect_worker4);
+                                       xs_tcp_setup_socket);
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
                break;
        case AF_INET6:
@@ -2424,7 +2319,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                        xprt_set_bound(xprt);
 
                INIT_DELAYED_WORK(&transport->connect_worker,
-                                       xs_tcp_connect_worker6);
+                                       xs_tcp_setup_socket);
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
                break;
        default:
@@ -2447,8 +2342,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
 }
 
@@ -2507,15 +2401,10 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                goto out_err;
        }
 
-       if (xprt_bound(xprt))
-               dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
-                               xprt->address_strings[RPC_DISPLAY_ADDR],
-                               xprt->address_strings[RPC_DISPLAY_PORT],
-                               xprt->address_strings[RPC_DISPLAY_PROTO]);
-       else
-               dprintk("RPC:       set up xprt to %s (autobind) via %s\n",
-                               xprt->address_strings[RPC_DISPLAY_ADDR],
-                               xprt->address_strings[RPC_DISPLAY_PROTO]);
+       dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
+                       xprt->address_strings[RPC_DISPLAY_ADDR],
+                       xprt->address_strings[RPC_DISPLAY_PORT],
+                       xprt->address_strings[RPC_DISPLAY_PROTO]);
 
        /*
         * Since we don't want connections for the backchannel, we set
@@ -2528,8 +2417,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       kfree(xprt->slot);
-       kfree(xprt);
+       xprt_free(xprt);
        return ret;
 }
 
index 0ebc777a66601e05d48cc8805e57cb957d9512d4..3c95304a08174f550f64f36346ce031419f6a4c8 100644 (file)
 
 static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
 static DEFINE_SPINLOCK(unix_table_lock);
-static atomic_t unix_nr_socks = ATOMIC_INIT(0);
+static atomic_long_t unix_nr_socks;
 
 #define unix_sockets_unbound   (&unix_socket_table[UNIX_HASH_SIZE])
 
@@ -360,13 +360,13 @@ static void unix_sock_destructor(struct sock *sk)
        if (u->addr)
                unix_release_addr(u->addr);
 
-       atomic_dec(&unix_nr_socks);
+       atomic_long_dec(&unix_nr_socks);
        local_bh_disable();
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        local_bh_enable();
 #ifdef UNIX_REFCNT_DEBUG
-       printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk,
-               atomic_read(&unix_nr_socks));
+       printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk,
+               atomic_long_read(&unix_nr_socks));
 #endif
 }
 
@@ -606,8 +606,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
        struct sock *sk = NULL;
        struct unix_sock *u;
 
-       atomic_inc(&unix_nr_socks);
-       if (atomic_read(&unix_nr_socks) > 2 * get_max_files())
+       atomic_long_inc(&unix_nr_socks);
+       if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files())
                goto out;
 
        sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto);
@@ -632,7 +632,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
        unix_insert_socket(unix_sockets_unbound, sk);
 out:
        if (sk == NULL)
-               atomic_dec(&unix_nr_socks);
+               atomic_long_dec(&unix_nr_socks);
        else {
                local_bh_disable();
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
index 2039acdf51222b3961b06291d6a02f4a8105a240..90b54d4697fd2de9ae1dcecc80fc25cdcab63d21 100755 (executable)
@@ -2,7 +2,7 @@
 # (c) 2001, Dave Jones. (the file handling bit)
 # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
 # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
-# (c) 2008,2009, Andy Whitcroft <apw@canonical.com>
+# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
 # Licensed under the terms of the GNU GPL License version 2
 
 use strict;
@@ -10,7 +10,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.30';
+my $V = '0.31';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -103,6 +103,8 @@ for my $key (keys %debug) {
        die "$@" if ($@);
 }
 
+my $rpt_cleaners = 0;
+
 if ($terse) {
        $emacs = 1;
        $quiet++;
@@ -150,6 +152,20 @@ our $Sparse        = qr{
 # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
 our $Attribute = qr{
                        const|
+                       __percpu|
+                       __nocast|
+                       __safe|
+                       __bitwise__|
+                       __packed__|
+                       __packed2__|
+                       __naked|
+                       __maybe_unused|
+                       __always_unused|
+                       __noreturn|
+                       __used|
+                       __cold|
+                       __noclone|
+                       __deprecated|
                        __read_mostly|
                        __kprobes|
                        __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
@@ -675,15 +691,15 @@ sub ctx_block_get {
                $blk .= $rawlines[$line];
 
                # Handle nested #if/#else.
-               if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+               if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
                        push(@stack, $level);
-               } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+               } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
                        $level = $stack[$#stack - 1];
-               } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) {
+               } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
                        $level = pop(@stack);
                }
 
-               foreach my $c (split(//, $rawlines[$line])) {
+               foreach my $c (split(//, $lines[$line])) {
                        ##print "C<$c>L<$level><$open$close>O<$off>\n";
                        if ($off > 0) {
                                $off--;
@@ -843,7 +859,12 @@ sub annotate_values {
                                $av_preprocessor = 0;
                        }
 
-               } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) {
+               } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) {
+                       print "CAST($1)\n" if ($dbg_values > 1);
+                       push(@av_paren_type, $type);
+                       $type = 'C';
+
+               } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
                        print "DECLARE($1)\n" if ($dbg_values > 1);
                        $type = 'T';
 
@@ -1308,7 +1329,11 @@ sub process {
                $here = "#$realline: " if ($file);
 
                # extract the filename as it passes
-               if ($line=~/^\+\+\+\s+(\S+)/) {
+               if ($line =~ /^diff --git.*?(\S+)$/) {
+                       $realfile = $1;
+                       $realfile =~ s@^([^/]*)/@@;
+
+               } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
                        $realfile = $1;
                        $realfile =~ s@^([^/]*)/@@;
 
@@ -1332,6 +1357,14 @@ sub process {
 
                $cnt_lines++ if ($realcnt != 0);
 
+# Check for incorrect file permissions
+               if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+                       my $permhere = $here . "FILE: $realfile\n";
+                       if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+                               ERROR("do not set execute permissions for source files\n" . $permhere);
+                       }
+               }
+
 #check the patch for a signoff:
                if ($line =~ /^\s*signed-off-by:/i) {
                        # This is a signoff, if ugly, so do not double report.
@@ -1389,21 +1422,38 @@ sub process {
                } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("trailing whitespace\n" . $herevet);
+                       $rpt_cleaners = 1;
                }
 
 # check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
                if ($realfile =~ /Kconfig/ &&
-                   $line =~ /\+?\s*(---)?help(---)?$/) {
+                   $line =~ /\+\s*(?:---)?help(?:---)?$/) {
                        my $length = 0;
-                       for (my $l = $linenr; defined($lines[$l]); $l++) {
-                               my $f = $lines[$l];
+                       my $cnt = $realcnt;
+                       my $ln = $linenr + 1;
+                       my $f;
+                       my $is_end = 0;
+                       while ($cnt > 0 && defined $lines[$ln - 1]) {
+                               $f = $lines[$ln - 1];
+                               $cnt-- if ($lines[$ln - 1] !~ /^-/);
+                               $is_end = $lines[$ln - 1] =~ /^\+/;
+                               $ln++;
+
+                               next if ($f =~ /^-/);
+                               $f =~ s/^.//;
                                $f =~ s/#.*//;
                                $f =~ s/^\s+//;
                                next if ($f =~ /^$/);
-                               last if ($f =~ /^\s*config\s/);
+                               if ($f =~ /^\s*config\s/) {
+                                       $is_end = 1;
+                                       last;
+                               }
                                $length++;
                        }
-                       WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4);
+                       WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
+                       #print "is_end<$is_end> length<$length>\n";
                }
 
 # check we are in a valid source file if not then ignore this hunk
@@ -1450,6 +1500,7 @@ sub process {
                    $rawline =~ /^\+\s*        \s*/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("code indent should use tabs where possible\n" . $herevet);
+                       $rpt_cleaners = 1;
                }
 
 # check for space before tabs.
@@ -1459,10 +1510,13 @@ sub process {
                }
 
 # check for spaces at the beginning of a line.
-               if ($rawline =~ /^\+ / && $rawline !~ /\+ +\*/)  {
+# Exceptions:
+#  1) within comments
+#  2) indented preprocessor commands
+#  3) hanging labels
+               if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/)  {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       WARN("please, no space for starting a line, \
-                               excluding comments\n" . $herevet);
+                       WARN("please, no spaces at the start of a line\n" . $herevet);
                }
 
 # check we are in a valid C source file if not then ignore this hunk
@@ -1598,7 +1652,7 @@ sub process {
 
                        if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
                                ERROR("that open brace { should be on the previous line\n" .
-                                       "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+                                       "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
                        }
                        if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
                            $ctx =~ /\)\s*\;\s*$/ &&
@@ -1607,7 +1661,7 @@ sub process {
                                my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
                                if ($nindent > $indent) {
                                        WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
-                                               "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+                                               "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
                                }
                        }
                }
@@ -1768,8 +1822,17 @@ sub process {
                    !defined $suppress_export{$realline_next} &&
                    ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
                     $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+                       # Handle definitions which produce identifiers with
+                       # a prefix:
+                       #   XXX(foo);
+                       #   EXPORT_SYMBOL(something_foo);
                        my $name = $1;
-                       if ($stat !~ /(?:
+                       if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+                           $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+                               $suppress_export{$realline_next} = 1;
+
+                       } elsif ($stat !~ /(?:
                                \n.}\s*$|
                                ^.DEFINE_$Ident\(\Q$name\E\)|
                                ^.DECLARE_$Ident\(\Q$name\E\)|
@@ -1806,6 +1869,23 @@ sub process {
                                $herecurr);
                }
 
+# check for static const char * arrays.
+               if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
+                       WARN("static const char * array should probably be static const char * const\n" .
+                               $herecurr);
+               }
+
+# check for static char foo[] = "bar" declarations.
+               if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
+                       WARN("static char array declaration should probably be static const char\n" .
+                               $herecurr);
+               }
+
+# check for declarations of struct pci_device_id
+               if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) {
+                       WARN("Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr);
+               }
+
 # check for new typedefs, only function parameters and sparse annotations
 # make sense.
                if ($line =~ /\btypedef\s/ &&
@@ -1899,6 +1979,11 @@ sub process {
                        ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
                }
 
+# missing space after union, struct or enum definition
+               if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+                   WARN("missing space after $1 definition\n" . $herecurr);
+               }
+
 # check for spacing round square brackets; allowed:
 #  1. with a type on the left -- int [] a;
 #  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
@@ -2176,21 +2261,29 @@ sub process {
                        my $value = $2;
 
                        # Flatten any parentheses
-                       $value =~ s/\)\(/\) \(/g;
+                       $value =~ s/\(/ \(/g;
+                       $value =~ s/\)/\) /g;
                        while ($value =~ s/\[[^\{\}]*\]/1/ ||
                               $value !~ /(?:$Ident|-?$Constant)\s*
                                             $Compare\s*
                                             (?:$Ident|-?$Constant)/x &&
                               $value =~ s/\([^\(\)]*\)/1/) {
                        }
-
-                       if ($value =~ /^(?:$Ident|-?$Constant)$/) {
+#print "value<$value>\n";
+                       if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
                                ERROR("return is not a function, parentheses are not required\n" . $herecurr);
 
                        } elsif ($spacing !~ /\s+/) {
                                ERROR("space required before the open parenthesis '('\n" . $herecurr);
                        }
                }
+# Return of what appears to be an errno should normally be -'ve
+               if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+                       my $name = $1;
+                       if ($name ne 'EOF' && $name ne 'ERROR') {
+                               WARN("return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+                       }
+               }
 
 # Need a space before open parenthesis after if, while etc
                if ($line=~/\b(if|while|for|switch)\(/) {
@@ -2409,8 +2502,8 @@ sub process {
                                \.$Ident\s*=\s*|
                                ^\"|\"$
                        }x;
-                       #print "REST<$rest> dstat<$dstat>\n";
-                       if ($rest ne '') {
+                       #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+                       if ($rest ne '' && $rest ne ',') {
                                if ($rest !~ /while\s*\(/ &&
                                    $dstat !~ /$exceptions/)
                                {
@@ -2839,6 +2932,15 @@ sub process {
                print "\n" if ($quiet == 0);
        }
 
+       if ($quiet == 0) {
+               # If there were whitespace errors which cleanpatch can fix
+               # then suggest that.
+               if ($rpt_cleaners) {
+                       print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+                       print "      scripts/cleanfile\n\n";
+               }
+       }
+
        if ($clean == 1 && $quiet == 0) {
                print "$vname has no obvious style problems and is ready for submission.\n"
        }
index b2281982f52f1a156f3eb5b321d3ec9a5fcaee0f..d21ec3a89603b0fa8155671587deaebaa52b6163 100755 (executable)
@@ -13,7 +13,7 @@
 use strict;
 
 my $P = $0;
-my $V = '0.24';
+my $V = '0.26-beta6';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -24,15 +24,19 @@ my $email_maintainer = 1;
 my $email_list = 1;
 my $email_subscriber_list = 0;
 my $email_git_penguin_chiefs = 0;
-my $email_git = 1;
+my $email_git = 0;
 my $email_git_all_signature_types = 0;
 my $email_git_blame = 0;
+my $email_git_blame_signatures = 1;
+my $email_git_fallback = 1;
 my $email_git_min_signatures = 1;
 my $email_git_max_maintainers = 5;
 my $email_git_min_percent = 5;
 my $email_git_since = "1-year-ago";
 my $email_hg_since = "-365";
+my $interactive = 0;
 my $email_remove_duplicates = 1;
+my $email_use_mailmap = 1;
 my $output_multiline = 1;
 my $output_separator = ", ";
 my $output_roles = 0;
@@ -49,8 +53,13 @@ my $pattern_depth = 0;
 my $version = 0;
 my $help = 0;
 
+my $vcs_used = 0;
+
 my $exit = 0;
 
+my %commit_author_hash;
+my %commit_signer_hash;
+
 my @penguin_chief = ();
 push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
 #Andrew wants in on most everything - 2009/01/14
@@ -73,7 +82,6 @@ my @signature_tags = ();
 push(@signature_tags, "Signed-off-by:");
 push(@signature_tags, "Reviewed-by:");
 push(@signature_tags, "Acked-by:");
-my $signaturePattern = "\(" . join("|", @signature_tags) . "\)";
 
 # rfc822 email address - preloaded methods go here.
 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
@@ -86,31 +94,70 @@ my %VCS_cmds;
 my %VCS_cmds_git = (
     "execute_cmd" => \&git_execute_cmd,
     "available" => '(which("git") ne "") && (-d ".git")',
-    "find_signers_cmd" => "git log --no-color --since=\$email_git_since -- \$file",
-    "find_commit_signers_cmd" => "git log --no-color -1 \$commit",
+    "find_signers_cmd" =>
+       "git log --no-color --since=\$email_git_since " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n' .
+                     '%b%n"' .
+           " -- \$file",
+    "find_commit_signers_cmd" =>
+       "git log --no-color " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n' .
+                     '%b%n"' .
+           " -1 \$commit",
+    "find_commit_author_cmd" =>
+       "git log --no-color " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n"' .
+           " -1 \$commit",
     "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
     "blame_file_cmd" => "git blame -l \$file",
-    "commit_pattern" => "^commit [0-9a-f]{40,40}",
-    "blame_commit_pattern" => "^([0-9a-f]+) "
+    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([0-9a-f]+) ",
+    "author_pattern" => "^GitAuthor: (.*)",
+    "subject_pattern" => "^GitSubject: (.*)",
 );
 
 my %VCS_cmds_hg = (
     "execute_cmd" => \&hg_execute_cmd,
     "available" => '(which("hg") ne "") && (-d ".hg")',
     "find_signers_cmd" =>
-       "hg log --date=\$email_hg_since" .
-               " --template='commit {node}\\n{desc}\\n' -- \$file",
-    "find_commit_signers_cmd" => "hg log --template='{desc}\\n' -r \$commit",
+       "hg log --date=\$email_hg_since " .
+           "--template='HgCommit: {node}\\n" .
+                       "HgAuthor: {author}\\n" .
+                       "HgSubject: {desc}\\n'" .
+           " -- \$file",
+    "find_commit_signers_cmd" =>
+       "hg log " .
+           "--template='HgSubject: {desc}\\n'" .
+           " -r \$commit",
+    "find_commit_author_cmd" =>
+       "hg log " .
+           "--template='HgCommit: {node}\\n" .
+                       "HgAuthor: {author}\\n" .
+                       "HgSubject: {desc|firstline}\\n'" .
+           " -r \$commit",
     "blame_range_cmd" => "",           # not supported
-    "blame_file_cmd" => "hg blame -c \$file",
-    "commit_pattern" => "^commit [0-9a-f]{40,40}",
-    "blame_commit_pattern" => "^([0-9a-f]+):"
+    "blame_file_cmd" => "hg blame -n \$file",
+    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([ 0-9a-f]+):",
+    "author_pattern" => "^HgAuthor: (.*)",
+    "subject_pattern" => "^HgSubject: (.*)",
 );
 
-if (-f "${lk_path}.get_maintainer.conf") {
+my $conf = which_conf(".get_maintainer.conf");
+if (-f $conf) {
     my @conf_args;
-    open(my $conffile, '<', "${lk_path}.get_maintainer.conf")
-       or warn "$P: Can't open .get_maintainer.conf: $!\n";
+    open(my $conffile, '<', "$conf")
+       or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+
     while (<$conffile>) {
        my $line = $_;
 
@@ -136,13 +183,17 @@ if (!GetOptions(
                'git!' => \$email_git,
                'git-all-signature-types!' => \$email_git_all_signature_types,
                'git-blame!' => \$email_git_blame,
+               'git-blame-signatures!' => \$email_git_blame_signatures,
+               'git-fallback!' => \$email_git_fallback,
                'git-chief-penguins!' => \$email_git_penguin_chiefs,
                'git-min-signatures=i' => \$email_git_min_signatures,
                'git-max-maintainers=i' => \$email_git_max_maintainers,
                'git-min-percent=i' => \$email_git_min_percent,
                'git-since=s' => \$email_git_since,
                'hg-since=s' => \$email_hg_since,
+               'i|interactive!' => \$interactive,
                'remove-duplicates!' => \$email_remove_duplicates,
+               'mailmap!' => \$email_use_mailmap,
                'm!' => \$email_maintainer,
                'n!' => \$email_usename,
                'l!' => \$email_list,
@@ -181,13 +232,9 @@ if (-t STDIN && !@ARGV) {
     die "$P: missing patchfile or -f file - use --help if necessary\n";
 }
 
-if ($output_separator ne ", ") {
-    $output_multiline = 0;
-}
-
-if ($output_rolestats) {
-    $output_roles = 1;
-}
+$output_multiline = 0 if ($output_separator ne ", ");
+$output_rolestats = 1 if ($interactive);
+$output_roles = 1 if ($output_rolestats);
 
 if ($sections) {
     $email = 0;
@@ -197,6 +244,7 @@ if ($sections) {
     $subsystem = 0;
     $web = 0;
     $keywords = 0;
+    $interactive = 0;
 } else {
     my $selections = $email + $scm + $status + $subsystem + $web;
     if ($selections == 0) {
@@ -215,10 +263,6 @@ if (!top_of_kernel_tree($lk_path)) {
        . "a linux kernel source tree.\n";
 }
 
-if ($email_git_all_signature_types) {
-    $signaturePattern = "(.+?)[Bb][Yy]:";
-}
-
 ## Read MAINTAINERS for type/value pairs
 
 my @typevalue = ();
@@ -253,31 +297,82 @@ while (<$maint>) {
 }
 close($maint);
 
-my %mailmap;
 
-if ($email_remove_duplicates) {
-    open(my $mailmap, '<', "${lk_path}.mailmap")
-       or warn "$P: Can't open .mailmap: $!\n";
-    while (<$mailmap>) {
-       my $line = $_;
+#
+# Read mail address map
+#
 
-       next if ($line =~ m/^\s*#/);
-       next if ($line =~ m/^\s*$/);
+my $mailmap;
 
-       my ($name, $address) = parse_email($line);
-       $line = format_email($name, $address, $email_usename);
+read_mailmap();
 
-       next if ($line =~ m/^\s*$/);
+sub read_mailmap {
+    $mailmap = {
+       names => {},
+       addresses => {}
+    };
 
-       if (exists($mailmap{$name})) {
-           my $obj = $mailmap{$name};
-           push(@$obj, $address);
-       } else {
-           my @arr = ($address);
-           $mailmap{$name} = \@arr;
+    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+
+    open(my $mailmap_file, '<', "${lk_path}.mailmap")
+       or warn "$P: Can't open .mailmap: $!\n";
+
+    while (<$mailmap_file>) {
+       s/#.*$//; #strip comments
+       s/^\s+|\s+$//g; #trim
+
+       next if (/^\s*$/); #skip empty lines
+       #entries have one of the following formats:
+       # name1 <mail1>
+       # <mail1> <mail2>
+       # name1 <mail1> <mail2>
+       # name1 <mail1> name2 <mail2>
+       # (see man git-shortlog)
+       if (/^(.+)<(.+)>$/) {
+           my $real_name = $1;
+           my $address = $2;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $address) = parse_email("$real_name <$address>");
+           $mailmap->{names}->{$address} = $real_name;
+
+       } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
+           my $real_address = $1;
+           my $wrong_address = $2;
+
+           $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+       } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
+           my $real_name = $1;
+           my $real_address = $2;
+           my $wrong_address = $3;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $real_address) =
+               parse_email("$real_name <$real_address>");
+           $mailmap->{names}->{$wrong_address} = $real_name;
+           $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+       } elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) {
+           my $real_name = $1;
+           my $real_address = $2;
+           my $wrong_name = $3;
+           my $wrong_address = $4;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $real_address) =
+               parse_email("$real_name <$real_address>");
+
+           $wrong_name =~ s/\s+$//;
+           ($wrong_name, $wrong_address) =
+               parse_email("$wrong_name <$wrong_address>");
+
+           my $wrong_email = format_email($wrong_name, $wrong_address, 1);
+           $mailmap->{names}->{$wrong_email} = $real_name;
+           $mailmap->{addresses}->{$wrong_email} = $real_address;
        }
     }
-    close($mailmap);
+    close($mailmap_file);
 }
 
 ## use the filenames on the command line or find the filenames in the patchfiles
@@ -302,7 +397,7 @@ foreach my $file (@ARGV) {
     }
     if ($from_filename) {
        push(@files, $file);
-       if (-f $file && ($keywords || $file_emails)) {
+       if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
            open(my $f, '<', $file)
                or die "$P: Can't open $file: $!\n";
            my $text = do { local($/) ; <$f> };
@@ -357,67 +452,127 @@ foreach my $file (@ARGV) {
 
 @file_emails = uniq(@file_emails);
 
+my %email_hash_name;
+my %email_hash_address;
 my @email_to = ();
+my %hash_list_to;
 my @list_to = ();
 my @scm = ();
 my @web = ();
 my @subsystem = ();
 my @status = ();
+my %deduplicate_name_hash = ();
+my %deduplicate_address_hash = ();
+my $signature_pattern;
 
-# Find responsible parties
+my @maintainers = get_maintainers();
 
-foreach my $file (@files) {
+if (@maintainers) {
+    @maintainers = merge_email(@maintainers);
+    output(@maintainers);
+}
 
-    my %hash;
-    my $tvi = find_first_section();
-    while ($tvi < @typevalue) {
-       my $start = find_starting_index($tvi);
-       my $end = find_ending_index($tvi);
-       my $exclude = 0;
-       my $i;
-
-       #Do not match excluded file patterns
-
-       for ($i = $start; $i < $end; $i++) {
-           my $line = $typevalue[$i];
-           if ($line =~ m/^(\C):\s*(.*)/) {
-               my $type = $1;
-               my $value = $2;
-               if ($type eq 'X') {
-                   if (file_match_pattern($file, $value)) {
-                       $exclude = 1;
-                       last;
-                   }
-               }
-           }
-       }
+if ($scm) {
+    @scm = uniq(@scm);
+    output(@scm);
+}
+
+if ($status) {
+    @status = uniq(@status);
+    output(@status);
+}
+
+if ($subsystem) {
+    @subsystem = uniq(@subsystem);
+    output(@subsystem);
+}
+
+if ($web) {
+    @web = uniq(@web);
+    output(@web);
+}
+
+exit($exit);
+
+sub get_maintainers {
+    %email_hash_name = ();
+    %email_hash_address = ();
+    %commit_author_hash = ();
+    %commit_signer_hash = ();
+    @email_to = ();
+    %hash_list_to = ();
+    @list_to = ();
+    @scm = ();
+    @web = ();
+    @subsystem = ();
+    @status = ();
+    %deduplicate_name_hash = ();
+    %deduplicate_address_hash = ();
+    if ($email_git_all_signature_types) {
+       $signature_pattern = "(.+?)[Bb][Yy]:";
+    } else {
+       $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+    }
+
+    # Find responsible parties
+
+    my %exact_pattern_match_hash = ();
+
+    foreach my $file (@files) {
+
+       my %hash;
+       my $tvi = find_first_section();
+       while ($tvi < @typevalue) {
+           my $start = find_starting_index($tvi);
+           my $end = find_ending_index($tvi);
+           my $exclude = 0;
+           my $i;
+
+           #Do not match excluded file patterns
 
-       if (!$exclude) {
            for ($i = $start; $i < $end; $i++) {
                my $line = $typevalue[$i];
                if ($line =~ m/^(\C):\s*(.*)/) {
                    my $type = $1;
                    my $value = $2;
-                   if ($type eq 'F') {
+                   if ($type eq 'X') {
                        if (file_match_pattern($file, $value)) {
-                           my $value_pd = ($value =~ tr@/@@);
-                           my $file_pd = ($file  =~ tr@/@@);
-                           $value_pd++ if (substr($value,-1,1) ne "/");
-                           if ($pattern_depth == 0 ||
-                               (($file_pd - $value_pd) < $pattern_depth)) {
-                               $hash{$tvi} = $value_pd;
+                           $exclude = 1;
+                           last;
+                       }
+                   }
+               }
+           }
+
+           if (!$exclude) {
+               for ($i = $start; $i < $end; $i++) {
+                   my $line = $typevalue[$i];
+                   if ($line =~ m/^(\C):\s*(.*)/) {
+                       my $type = $1;
+                       my $value = $2;
+                       if ($type eq 'F') {
+                           if (file_match_pattern($file, $value)) {
+                               my $value_pd = ($value =~ tr@/@@);
+                               my $file_pd = ($file  =~ tr@/@@);
+                               $value_pd++ if (substr($value,-1,1) ne "/");
+                               $value_pd = -1 if ($value =~ /^\.\*/);
+                               if ($value_pd >= $file_pd) {
+                                   $exact_pattern_match_hash{$file} = 1;
+                               }
+                               if ($pattern_depth == 0 ||
+                                   (($file_pd - $value_pd) < $pattern_depth)) {
+                                   $hash{$tvi} = $value_pd;
+                               }
                            }
                        }
                    }
                }
            }
+           $tvi = $end + 1;
        }
 
-       $tvi = $end + 1;
-    }
-
-    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
-       add_categories($line);
+       foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+           add_categories($line);
            if ($sections) {
                my $i;
                my $start = find_starting_index($line);
@@ -435,80 +590,71 @@ foreach my $file (@files) {
                }
                print("\n");
            }
+       }
     }
 
-    if ($email && $email_git) {
-       vcs_file_signoffs($file);
+    if ($keywords) {
+       @keyword_tvi = sort_and_uniq(@keyword_tvi);
+       foreach my $line (@keyword_tvi) {
+           add_categories($line);
+       }
     }
 
-    if ($email && $email_git_blame) {
-       vcs_file_blame($file);
+    foreach my $email (@email_to, @list_to) {
+       $email->[0] = deduplicate_email($email->[0]);
     }
-}
 
-if ($keywords) {
-    @keyword_tvi = sort_and_uniq(@keyword_tvi);
-    foreach my $line (@keyword_tvi) {
-       add_categories($line);
+    foreach my $file (@files) {
+       if ($email &&
+           ($email_git || ($email_git_fallback &&
+                           !$exact_pattern_match_hash{$file}))) {
+           vcs_file_signoffs($file);
+       }
+       if ($email && $email_git_blame) {
+           vcs_file_blame($file);
+       }
     }
-}
 
-if ($email) {
-    foreach my $chief (@penguin_chief) {
-       if ($chief =~ m/^(.*):(.*)/) {
-           my $email_address;
+    if ($email) {
+       foreach my $chief (@penguin_chief) {
+           if ($chief =~ m/^(.*):(.*)/) {
+               my $email_address;
 
-           $email_address = format_email($1, $2, $email_usename);
-           if ($email_git_penguin_chiefs) {
-               push(@email_to, [$email_address, 'chief penguin']);
-           } else {
-               @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+               $email_address = format_email($1, $2, $email_usename);
+               if ($email_git_penguin_chiefs) {
+                   push(@email_to, [$email_address, 'chief penguin']);
+               } else {
+                   @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+               }
            }
        }
-    }
 
-    foreach my $email (@file_emails) {
-       my ($name, $address) = parse_email($email);
+       foreach my $email (@file_emails) {
+           my ($name, $address) = parse_email($email);
 
-       my $tmp_email = format_email($name, $address, $email_usename);
-       push_email_address($tmp_email, '');
-       add_role($tmp_email, 'in file');
+           my $tmp_email = format_email($name, $address, $email_usename);
+           push_email_address($tmp_email, '');
+           add_role($tmp_email, 'in file');
+       }
     }
-}
 
-if ($email || $email_list) {
     my @to = ();
-    if ($email) {
-       @to = (@to, @email_to);
-    }
-    if ($email_list) {
-       @to = (@to, @list_to);
+    if ($email || $email_list) {
+       if ($email) {
+           @to = (@to, @email_to);
+       }
+       if ($email_list) {
+           @to = (@to, @list_to);
+       }
     }
-    output(merge_email(@to));
-}
-
-if ($scm) {
-    @scm = uniq(@scm);
-    output(@scm);
-}
-
-if ($status) {
-    @status = uniq(@status);
-    output(@status);
-}
 
-if ($subsystem) {
-    @subsystem = uniq(@subsystem);
-    output(@subsystem);
-}
+    if ($interactive) {
+       @to = interactive_get_maintainers(\@to);
+    }
 
-if ($web) {
-    @web = uniq(@web);
-    output(@web);
+    return @to;
 }
 
-exit($exit);
-
 sub file_match_pattern {
     my ($file, $pattern) = @_;
     if (substr($pattern, -1) eq "/") {
@@ -537,7 +683,8 @@ MAINTAINER field selection options:
   --email => print email address(es) if any
     --git => include recent git \*-by: signers
     --git-all-signature-types => include signers regardless of signature type
-        or use only ${signaturePattern} signers (default: $email_git_all_signature_types)
+        or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
+    --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
     --git-chief-penguins => include ${penguin_chiefs}
     --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
     --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
@@ -545,6 +692,7 @@ MAINTAINER field selection options:
     --git-blame => use git blame to find modified commits for patch or file
     --git-since => git history to use (default: $email_git_since)
     --hg-since => hg history to use (default: $email_hg_since)
+    --interactive => display a menu (mostly useful if used with the --git option)
     --m => include maintainer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
@@ -565,8 +713,9 @@ Output type options:
 
 Other options:
   --pattern-depth => Number of pattern directory traversals (default: 0 (all))
-  --keywords => scan patch for keywords (default: 1 (on))
-  --sections => print the entire subsystem sections with pattern matches
+  --keywords => scan patch for keywords (default: $keywords)
+  --sections => print all of the subsystem sections with pattern matches
+  --mailmap => use .mailmap file (default: $email_use_mailmap)
   --version => show version
   --help => show this help information
 
@@ -606,30 +755,30 @@ EOT
 }
 
 sub top_of_kernel_tree {
-       my ($lk_path) = @_;
+    my ($lk_path) = @_;
 
-       if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
-           $lk_path .= "/";
-       }
-       if (   (-f "${lk_path}COPYING")
-           && (-f "${lk_path}CREDITS")
-           && (-f "${lk_path}Kbuild")
-           && (-f "${lk_path}MAINTAINERS")
-           && (-f "${lk_path}Makefile")
-           && (-f "${lk_path}README")
-           && (-d "${lk_path}Documentation")
-           && (-d "${lk_path}arch")
-           && (-d "${lk_path}include")
-           && (-d "${lk_path}drivers")
-           && (-d "${lk_path}fs")
-           && (-d "${lk_path}init")
-           && (-d "${lk_path}ipc")
-           && (-d "${lk_path}kernel")
-           && (-d "${lk_path}lib")
-           && (-d "${lk_path}scripts")) {
-               return 1;
-       }
-       return 0;
+    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
+       $lk_path .= "/";
+    }
+    if (   (-f "${lk_path}COPYING")
+       && (-f "${lk_path}CREDITS")
+       && (-f "${lk_path}Kbuild")
+       && (-f "${lk_path}MAINTAINERS")
+       && (-f "${lk_path}Makefile")
+       && (-f "${lk_path}README")
+       && (-d "${lk_path}Documentation")
+       && (-d "${lk_path}arch")
+       && (-d "${lk_path}include")
+       && (-d "${lk_path}drivers")
+       && (-d "${lk_path}fs")
+       && (-d "${lk_path}init")
+       && (-d "${lk_path}ipc")
+       && (-d "${lk_path}kernel")
+       && (-d "${lk_path}lib")
+       && (-d "${lk_path}scripts")) {
+       return 1;
+    }
+    return 0;
 }
 
 sub parse_email {
@@ -821,11 +970,19 @@ sub add_categories {
                }
                if ($list_additional =~ m/subscribers-only/) {
                    if ($email_subscriber_list) {
-                       push(@list_to, [$list_address, "subscriber list${list_role}"]);
+                       if (!$hash_list_to{lc($list_address)}) {
+                           $hash_list_to{lc($list_address)} = 1;
+                           push(@list_to, [$list_address,
+                                           "subscriber list${list_role}"]);
+                       }
                    }
                } else {
                    if ($email_list) {
-                       push(@list_to, [$list_address, "open list${list_role}"]);
+                       if (!$hash_list_to{lc($list_address)}) {
+                           $hash_list_to{lc($list_address)} = 1;
+                           push(@list_to, [$list_address,
+                                           "open list${list_role}"]);
+                       }
                    }
                }
            } elsif ($ptype eq "M") {
@@ -856,15 +1013,12 @@ sub add_categories {
     }
 }
 
-my %email_hash_name;
-my %email_hash_address;
-
 sub email_inuse {
     my ($name, $address) = @_;
 
     return 1 if (($name eq "") && ($address eq ""));
-    return 1 if (($name ne "") && exists($email_hash_name{$name}));
-    return 1 if (($address ne "") && exists($email_hash_address{$address}));
+    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
+    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
 
     return 0;
 }
@@ -882,8 +1036,8 @@ sub push_email_address {
        push(@email_to, [format_email($name, $address, $email_usename), $role]);
     } elsif (!email_inuse($name, $address)) {
        push(@email_to, [format_email($name, $address, $email_usename), $role]);
-       $email_hash_name{$name}++;
-       $email_hash_address{$address}++;
+       $email_hash_name{lc($name)}++ if ($name ne "");
+       $email_hash_address{lc($address)}++;
     }
 
     return 1;
@@ -952,30 +1106,69 @@ sub which {
     return "";
 }
 
-sub mailmap {
-    my (@lines) = @_;
-    my %hash;
+sub which_conf {
+    my ($conf) = @_;
 
-    foreach my $line (@lines) {
-       my ($name, $address) = parse_email($line);
-       if (!exists($hash{$name})) {
-           $hash{$name} = $address;
-       } elsif ($address ne $hash{$name}) {
-           $address = $hash{$name};
-           $line = format_email($name, $address, $email_usename);
+    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+       if (-e "$path/$conf") {
+           return "$path/$conf";
        }
-       if (exists($mailmap{$name})) {
-           my $obj = $mailmap{$name};
-           foreach my $map_address (@$obj) {
-               if (($map_address eq $address) &&
-                   ($map_address ne $hash{$name})) {
-                   $line = format_email($name, $hash{$name}, $email_usename);
-               }
-           }
+    }
+
+    return "";
+}
+
+sub mailmap_email {
+    my ($line) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, 1);
+    my $real_name = $name;
+    my $real_address = $address;
+
+    if (exists $mailmap->{names}->{$email} ||
+       exists $mailmap->{addresses}->{$email}) {
+       if (exists $mailmap->{names}->{$email}) {
+           $real_name = $mailmap->{names}->{$email};
+       }
+       if (exists $mailmap->{addresses}->{$email}) {
+           $real_address = $mailmap->{addresses}->{$email};
+       }
+    } else {
+       if (exists $mailmap->{names}->{$address}) {
+           $real_name = $mailmap->{names}->{$address};
+       }
+       if (exists $mailmap->{addresses}->{$address}) {
+           $real_address = $mailmap->{addresses}->{$address};
        }
     }
+    return format_email($real_name, $real_address, 1);
+}
 
-    return @lines;
+sub mailmap {
+    my (@addresses) = @_;
+
+    my @mapped_emails = ();
+    foreach my $line (@addresses) {
+       push(@mapped_emails, mailmap_email($line));
+    }
+    merge_by_realname(@mapped_emails) if ($email_use_mailmap);
+    return @mapped_emails;
+}
+
+sub merge_by_realname {
+    my %address_map;
+    my (@emails) = @_;
+
+    foreach my $email (@emails) {
+       my ($name, $address) = parse_email($email);
+       if (exists $address_map{$name}) {
+           $address = $address_map{$name};
+           $email = format_email($name, $address, 1);
+       } else {
+           $address_map{$name} = $address;
+       }
+    }
 }
 
 sub git_execute_cmd {
@@ -999,10 +1192,30 @@ sub hg_execute_cmd {
     return @lines;
 }
 
+sub extract_formatted_signatures {
+    my (@signature_lines) = @_;
+
+    my @type = @signature_lines;
+
+    s/\s*(.*):.*/$1/ for (@type);
+
+    # cut -f2- -d":"
+    s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
+
+## Reformat email addresses (with names) to avoid badly written signatures
+
+    foreach my $signer (@signature_lines) {
+       $signer = deduplicate_email($signer);
+    }
+
+    return (\@type, \@signature_lines);
+}
+
 sub vcs_find_signers {
     my ($cmd) = @_;
-    my @lines = ();
     my $commits;
+    my @lines = ();
+    my @signatures = ();
 
     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
 
@@ -1010,21 +1223,48 @@ sub vcs_find_signers {
 
     $commits = grep(/$pattern/, @lines);       # of commits
 
-    @lines = grep(/^[ \t]*${signaturePattern}.*\@.*$/, @lines);
+    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
+
+    return (0, @signatures) if !@signatures;
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    if (!$email_git_penguin_chiefs) {
+       @signatures = grep(!/${penguin_chiefs}/i, @signatures);
+    }
+
+    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+
+    return ($commits, @$signers_ref);
+}
+
+sub vcs_find_author {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
     if (!$email_git_penguin_chiefs) {
        @lines = grep(!/${penguin_chiefs}/i, @lines);
     }
-    # cut -f2- -d":"
-    s/.*:\s*(.+)\s*/$1/ for (@lines);
 
-## Reformat email addresses (with names) to avoid badly written signatures
+    return @lines if !@lines;
 
+    my @authors = ();
     foreach my $line (@lines) {
-       my ($name, $address) = parse_email($line);
-       $line = format_email($name, $address, 1);
+       if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+           my $author = $1;
+           my ($name, $address) = parse_email($author);
+           $author = format_email($name, $address, 1);
+           push(@authors, $author);
+       }
     }
 
-    return ($commits, @lines);
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    return @authors;
 }
 
 sub vcs_save_commits {
@@ -1084,6 +1324,10 @@ sub vcs_blame {
        @commits = vcs_save_commits($cmd);
     }
 
+    foreach my $commit (@commits) {
+       $commit =~ s/^\^//g;
+    }
+
     return @commits;
 }
 
@@ -1092,7 +1336,7 @@ sub vcs_exists {
     %VCS_cmds = %VCS_cmds_git;
     return 1 if eval $VCS_cmds{"available"};
     %VCS_cmds = %VCS_cmds_hg;
-    return 1 if eval $VCS_cmds{"available"};
+    return 2 if eval $VCS_cmds{"available"};
     %VCS_cmds = ();
     if (!$printed_novcs) {
        warn("$P: No supported VCS found.  Add --nogit to options?\n");
@@ -1104,6 +1348,405 @@ sub vcs_exists {
     return 0;
 }
 
+sub vcs_is_git {
+    vcs_exists();
+    return $vcs_used == 1;
+}
+
+sub vcs_is_hg {
+    return $vcs_used == 2;
+}
+
+sub interactive_get_maintainers {
+    my ($list_ref) = @_;
+    my @list = @$list_ref;
+
+    vcs_exists();
+
+    my %selected;
+    my %authored;
+    my %signed;
+    my $count = 0;
+    my $maintained = 0;
+    foreach my $entry (@list) {
+       $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
+       $selected{$count} = 1;
+       $authored{$count} = 0;
+       $signed{$count} = 0;
+       $count++;
+    }
+
+    #menu loop
+    my $done = 0;
+    my $print_options = 0;
+    my $redraw = 1;
+    while (!$done) {
+       $count = 0;
+       if ($redraw) {
+           printf STDERR "\n%1s %2s %-65s",
+                         "*", "#", "email/list and role:stats";
+           if ($email_git ||
+               ($email_git_fallback && !$maintained) ||
+               $email_git_blame) {
+               print STDERR "auth sign";
+           }
+           print STDERR "\n";
+           foreach my $entry (@list) {
+               my $email = $entry->[0];
+               my $role = $entry->[1];
+               my $sel = "";
+               $sel = "*" if ($selected{$count});
+               my $commit_author = $commit_author_hash{$email};
+               my $commit_signer = $commit_signer_hash{$email};
+               my $authored = 0;
+               my $signed = 0;
+               $authored++ for (@{$commit_author});
+               $signed++ for (@{$commit_signer});
+               printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+               printf STDERR "%4d %4d", $authored, $signed
+                   if ($authored > 0 || $signed > 0);
+               printf STDERR "\n     %s\n", $role;
+               if ($authored{$count}) {
+                   my $commit_author = $commit_author_hash{$email};
+                   foreach my $ref (@{$commit_author}) {
+                       print STDERR "     Author: @{$ref}[1]\n";
+                   }
+               }
+               if ($signed{$count}) {
+                   my $commit_signer = $commit_signer_hash{$email};
+                   foreach my $ref (@{$commit_signer}) {
+                       print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
+                   }
+               }
+
+               $count++;
+           }
+       }
+       my $date_ref = \$email_git_since;
+       $date_ref = \$email_hg_since if (vcs_is_hg());
+       if ($print_options) {
+           $print_options = 0;
+           if (vcs_exists()) {
+               print STDERR <<EOT
+
+Version Control options:
+g  use git history      [$email_git]
+gf use git-fallback     [$email_git_fallback]
+b  use git blame        [$email_git_blame]
+bs use blame signatures [$email_git_blame_signatures]
+c# minimum commits      [$email_git_min_signatures]
+%# min percent          [$email_git_min_percent]
+d# history to use       [$$date_ref]
+x# max maintainers      [$email_git_max_maintainers]
+t  all signature types  [$email_git_all_signature_types]
+m  use .mailmap         [$email_use_mailmap]
+EOT
+           }
+           print STDERR <<EOT
+
+Additional options:
+0  toggle all
+tm toggle maintainers
+tg toggle git entries
+tl toggle open list entries
+ts toggle subscriber list entries
+f  emails in file       [$file_emails]
+k  keywords in file     [$keywords]
+r  remove duplicates    [$email_remove_duplicates]
+p# pattern match depth  [$pattern_depth]
+EOT
+       }
+       print STDERR
+"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+       my $input = <STDIN>;
+       chomp($input);
+
+       $redraw = 1;
+       my $rerun = 0;
+       my @wish = split(/[, ]+/, $input);
+       foreach my $nr (@wish) {
+           $nr = lc($nr);
+           my $sel = substr($nr, 0, 1);
+           my $str = substr($nr, 1);
+           my $val = 0;
+           $val = $1 if $str =~ /^(\d+)$/;
+
+           if ($sel eq "y") {
+               $interactive = 0;
+               $done = 1;
+               $output_rolestats = 0;
+               $output_roles = 0;
+               last;
+           } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
+               $selected{$nr - 1} = !$selected{$nr - 1};
+           } elsif ($sel eq "*" || $sel eq '^') {
+               my $toggle = 0;
+               $toggle = 1 if ($sel eq '*');
+               for (my $i = 0; $i < $count; $i++) {
+                   $selected{$i} = $toggle;
+               }
+           } elsif ($sel eq "0") {
+               for (my $i = 0; $i < $count; $i++) {
+                   $selected{$i} = !$selected{$i};
+               }
+           } elsif ($sel eq "t") {
+               if (lc($str) eq "m") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
+                   }
+               } elsif (lc($str) eq "g") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
+                   }
+               } elsif (lc($str) eq "l") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(open list)/i);
+                   }
+               } elsif (lc($str) eq "s") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(subscriber list)/i);
+                   }
+               }
+           } elsif ($sel eq "a") {
+               if ($val > 0 && $val <= $count) {
+                   $authored{$val - 1} = !$authored{$val - 1};
+               } elsif ($str eq '*' || $str eq '^') {
+                   my $toggle = 0;
+                   $toggle = 1 if ($str eq '*');
+                   for (my $i = 0; $i < $count; $i++) {
+                       $authored{$i} = $toggle;
+                   }
+               }
+           } elsif ($sel eq "s") {
+               if ($val > 0 && $val <= $count) {
+                   $signed{$val - 1} = !$signed{$val - 1};
+               } elsif ($str eq '*' || $str eq '^') {
+                   my $toggle = 0;
+                   $toggle = 1 if ($str eq '*');
+                   for (my $i = 0; $i < $count; $i++) {
+                       $signed{$i} = $toggle;
+                   }
+               }
+           } elsif ($sel eq "o") {
+               $print_options = 1;
+               $redraw = 1;
+           } elsif ($sel eq "g") {
+               if ($str eq "f") {
+                   bool_invert(\$email_git_fallback);
+               } else {
+                   bool_invert(\$email_git);
+               }
+               $rerun = 1;
+           } elsif ($sel eq "b") {
+               if ($str eq "s") {
+                   bool_invert(\$email_git_blame_signatures);
+               } else {
+                   bool_invert(\$email_git_blame);
+               }
+               $rerun = 1;
+           } elsif ($sel eq "c") {
+               if ($val > 0) {
+                   $email_git_min_signatures = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "x") {
+               if ($val > 0) {
+                   $email_git_max_maintainers = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "%") {
+               if ($str ne "" && $val >= 0) {
+                   $email_git_min_percent = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "d") {
+               if (vcs_is_git()) {
+                   $email_git_since = $str;
+               } elsif (vcs_is_hg()) {
+                   $email_hg_since = $str;
+               }
+               $rerun = 1;
+           } elsif ($sel eq "t") {
+               bool_invert(\$email_git_all_signature_types);
+               $rerun = 1;
+           } elsif ($sel eq "f") {
+               bool_invert(\$file_emails);
+               $rerun = 1;
+           } elsif ($sel eq "r") {
+               bool_invert(\$email_remove_duplicates);
+               $rerun = 1;
+           } elsif ($sel eq "m") {
+               bool_invert(\$email_use_mailmap);
+               read_mailmap();
+               $rerun = 1;
+           } elsif ($sel eq "k") {
+               bool_invert(\$keywords);
+               $rerun = 1;
+           } elsif ($sel eq "p") {
+               if ($str ne "" && $val >= 0) {
+                   $pattern_depth = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "h" || $sel eq "?") {
+               print STDERR <<EOT
+
+Interactive mode allows you to select the various maintainers, submitters,
+commit signers and mailing lists that could be CC'd on a patch.
+
+Any *'d entry is selected.
+
+If you have git or hg installed, you can choose to summarize the commit
+history of files in the patch.  Also, each line of the current file can
+be matched to its commit author and that commits signers with blame.
+
+Various knobs exist to control the length of time for active commit
+tracking, the maximum number of commit authors and signers to add,
+and such.
+
+Enter selections at the prompt until you are satisfied that the selected
+maintainers are appropriate.  You may enter multiple selections separated
+by either commas or spaces.
+
+EOT
+           } else {
+               print STDERR "invalid option: '$nr'\n";
+               $redraw = 0;
+           }
+       }
+       if ($rerun) {
+           print STDERR "git-blame can be very slow, please have patience..."
+               if ($email_git_blame);
+           goto &get_maintainers;
+       }
+    }
+
+    #drop not selected entries
+    $count = 0;
+    my @new_emailto = ();
+    foreach my $entry (@list) {
+       if ($selected{$count}) {
+           push(@new_emailto, $list[$count]);
+       }
+       $count++;
+    }
+    return @new_emailto;
+}
+
+sub bool_invert {
+    my ($bool_ref) = @_;
+
+    if ($$bool_ref) {
+       $$bool_ref = 0;
+    } else {
+       $$bool_ref = 1;
+    }
+}
+
+sub deduplicate_email {
+    my ($email) = @_;
+
+    my $matched = 0;
+    my ($name, $address) = parse_email($email);
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+
+    return $email if (!$email_remove_duplicates);
+
+    ($name, $address) = parse_email($email);
+
+    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
+       $name = $deduplicate_name_hash{lc($name)}->[0];
+       $address = $deduplicate_name_hash{lc($name)}->[1];
+       $matched = 1;
+    } elsif ($deduplicate_address_hash{lc($address)}) {
+       $name = $deduplicate_address_hash{lc($address)}->[0];
+       $address = $deduplicate_address_hash{lc($address)}->[1];
+       $matched = 1;
+    }
+    if (!$matched) {
+       $deduplicate_name_hash{lc($name)} = [ $name, $address ];
+       $deduplicate_address_hash{lc($address)} = [ $name, $address ];
+    }
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+    return $email;
+}
+
+sub save_commits_by_author {
+    my (@lines) = @_;
+
+    my @authors = ();
+    my @commits = ();
+    my @subjects = ();
+
+    foreach my $line (@lines) {
+       if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+           my $author = $1;
+           $author = deduplicate_email($author);
+           push(@authors, $author);
+       }
+       push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+       push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+    }
+
+    for (my $i = 0; $i < @authors; $i++) {
+       my $exists = 0;
+       foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
+           if (@{$ref}[0] eq $commits[$i] &&
+               @{$ref}[1] eq $subjects[$i]) {
+               $exists = 1;
+               last;
+           }
+       }
+       if (!$exists) {
+           push(@{$commit_author_hash{$authors[$i]}},
+                [ ($commits[$i], $subjects[$i]) ]);
+       }
+    }
+}
+
+sub save_commits_by_signer {
+    my (@lines) = @_;
+
+    my $commit = "";
+    my $subject = "";
+
+    foreach my $line (@lines) {
+       $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+       $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+       if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
+           my @signatures = ($line);
+           my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+           my @types = @$types_ref;
+           my @signers = @$signers_ref;
+
+           my $type = $types[0];
+           my $signer = $signers[0];
+
+           $signer = deduplicate_email($signer);
+
+           my $exists = 0;
+           foreach my $ref(@{$commit_signer_hash{$signer}}) {
+               if (@{$ref}[0] eq $commit &&
+                   @{$ref}[1] eq $subject &&
+                   @{$ref}[2] eq $type) {
+                   $exists = 1;
+                   last;
+               }
+           }
+           if (!$exists) {
+               push(@{$commit_signer_hash{$signer}},
+                    [ ($commit, $subject, $type) ]);
+           }
+       }
+    }
+}
+
 sub vcs_assign {
     my ($role, $divisor, @lines) = @_;
 
@@ -1117,9 +1760,9 @@ sub vcs_assign {
        $divisor = 1;
     }
 
-    if ($email_remove_duplicates) {
-       @lines = mailmap(@lines);
-    }
+    @lines = mailmap(@lines);
+
+    return if (@lines <= 0);
 
     @lines = sort(@lines);
 
@@ -1152,12 +1795,18 @@ sub vcs_file_signoffs {
     my @signers = ();
     my $commits;
 
-    return if (!vcs_exists());
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
 
     my $cmd = $VCS_cmds{"find_signers_cmd"};
     $cmd =~ s/(\$\w+)/$1/eeg;          # interpolate $cmd
 
     ($commits, @signers) = vcs_find_signers($cmd);
+
+    foreach my $signer (@signers) {
+       $signer = deduplicate_email($signer);
+    }
+
     vcs_assign("commit_signer", $commits, @signers);
 }
 
@@ -1165,29 +1814,114 @@ sub vcs_file_blame {
     my ($file) = @_;
 
     my @signers = ();
+    my @all_commits = ();
     my @commits = ();
     my $total_commits;
+    my $total_lines;
 
-    return if (!vcs_exists());
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
 
-    @commits = vcs_blame($file);
-    @commits = uniq(@commits);
+    @all_commits = vcs_blame($file);
+    @commits = uniq(@all_commits);
     $total_commits = @commits;
+    $total_lines = @all_commits;
 
-    foreach my $commit (@commits) {
-       my $commit_count;
-       my @commit_signers = ();
+    if ($email_git_blame_signatures) {
+       if (vcs_is_hg()) {
+           my $commit_count;
+           my @commit_signers = ();
+           my $commit = join(" -r ", @commits);
+           my $cmd;
+
+           $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+           $cmd =~ s/(\$\w+)/$1/eeg;   #substitute variables in $cmd
+
+           ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+           push(@signers, @commit_signers);
+       } else {
+           foreach my $commit (@commits) {
+               my $commit_count;
+               my @commit_signers = ();
+               my $cmd;
 
-       my $cmd = $VCS_cmds{"find_commit_signers_cmd"};
-       $cmd =~ s/(\$\w+)/$1/eeg;       #interpolate $cmd
+               $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+               $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
 
-       ($commit_count, @commit_signers) = vcs_find_signers($cmd);
-       push(@signers, @commit_signers);
+               ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+               push(@signers, @commit_signers);
+           }
+       }
     }
 
     if ($from_filename) {
+       if ($output_rolestats) {
+           my @blame_signers;
+           if (vcs_is_hg()) {{         # Double brace for last exit
+               my $commit_count;
+               my @commit_signers = ();
+               @commits = uniq(@commits);
+               @commits = sort(@commits);
+               my $commit = join(" -r ", @commits);
+               my $cmd;
+
+               $cmd = $VCS_cmds{"find_commit_author_cmd"};
+               $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
+
+               my @lines = ();
+
+               @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+               if (!$email_git_penguin_chiefs) {
+                   @lines = grep(!/${penguin_chiefs}/i, @lines);
+               }
+
+               last if !@lines;
+
+               my @authors = ();
+               foreach my $line (@lines) {
+                   if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+                       my $author = $1;
+                       $author = deduplicate_email($author);
+                       push(@authors, $author);
+                   }
+               }
+
+               save_commits_by_author(@lines) if ($interactive);
+               save_commits_by_signer(@lines) if ($interactive);
+
+               push(@signers, @authors);
+           }}
+           else {
+               foreach my $commit (@commits) {
+                   my $i;
+                   my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+                   $cmd =~ s/(\$\w+)/$1/eeg;   #interpolate $cmd
+                   my @author = vcs_find_author($cmd);
+                   next if !@author;
+
+                   my $formatted_author = deduplicate_email($author[0]);
+
+                   my $count = grep(/$commit/, @all_commits);
+                   for ($i = 0; $i < $count ; $i++) {
+                       push(@blame_signers, $formatted_author);
+                   }
+               }
+           }
+           if (@blame_signers) {
+               vcs_assign("authored lines", $total_lines, @blame_signers);
+           }
+       }
+       foreach my $signer (@signers) {
+           $signer = deduplicate_email($signer);
+       }
        vcs_assign("commits", $total_commits, @signers);
     } else {
+       foreach my $signer (@signers) {
+           $signer = deduplicate_email($signer);
+       }
        vcs_assign("modified commits", $total_commits, @signers);
     }
 }
index 82396050f18646ac0519352321637e930c05e367..36cc0cc39e78e135630384e6500f4a789fe7aa2a 100644 (file)
@@ -72,10 +72,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
                path_get(&root);
        }
 
-       spin_lock(&dcache_lock);
        tmp = root;
        res = __d_path(path, &tmp, buf, buflen);
-       spin_unlock(&dcache_lock);
 
        *name = res;
        /* handle error conditions - and still allow a partial path to
index 88839866cbcd029a52422b51cf163ec8167a4034..cb8f47c66a58bb7eb11c0a75319f378261393f14 100644 (file)
@@ -61,6 +61,7 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
        struct inode *inode = new_inode(sb);
 
        if (inode) {
+               inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                switch (mode & S_IFMT) {
index 3fbcd1dda0ef6e06da4a5b4b9c23a240a6378a35..ac79032bdf2356dfe7e74da640f3ff0a21efcbda 100644 (file)
@@ -70,6 +70,7 @@ int ima_init(void);
 void ima_cleanup(void);
 int ima_fs_init(void);
 void ima_fs_cleanup(void);
+int ima_inode_alloc(struct inode *inode);
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode);
 int ima_calc_hash(struct file *file, char *digest);
@@ -96,19 +97,16 @@ static inline unsigned long ima_hash_key(u8 *digest)
 }
 
 /* iint cache flags */
-#define IMA_MEASURED           1
+#define IMA_MEASURED           0x01
 
 /* integrity data associated with an inode */
 struct ima_iint_cache {
+       struct rb_node rb_node; /* rooted in ima_iint_tree */
+       struct inode *inode;    /* back pointer to inode in question */
        u64 version;            /* track inode changes */
-       unsigned long flags;
+       unsigned char flags;
        u8 digest[IMA_DIGEST_SIZE];
        struct mutex mutex;     /* protects: version, flags, digest */
-       long readcount;         /* measured files readcount */
-       long writecount;        /* measured files writecount */
-       long opencount;         /* opens reference count */
-       struct kref refcount;   /* ima_iint_cache reference count */
-       struct rcu_head rcu;
 };
 
 /* LIM API function definitions */
@@ -122,13 +120,11 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
 void ima_template_show(struct seq_file *m, void *e,
                       enum ima_show_type show);
 
-/* radix tree calls to lookup, insert, delete
+/* rbtree tree calls to lookup, insert, delete
  * integrity data associated with an inode.
  */
 struct ima_iint_cache *ima_iint_insert(struct inode *inode);
-struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
-void iint_free(struct kref *kref);
-void iint_rcu_free(struct rcu_head *rcu);
+struct ima_iint_cache *ima_iint_find(struct inode *inode);
 
 /* IMA policy related functions */
 enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
index 52015d098fdfd6d1823cf44ccfef1e754605884f..d3963de6003da423c26cc1028258fe70fd1cf1b3 100644 (file)
@@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
 {
        int must_measure;
 
-       if (iint->flags & IMA_MEASURED)
+       if (iint && iint->flags & IMA_MEASURED)
                return 1;
 
        must_measure = ima_match_policy(inode, function, mask);
index afba4aef812f699134f7c7bc66c32251d2f12c69..c442e47b67853099e776c4e5b95dd3fa321183ae 100644 (file)
  * File: ima_iint.c
  *     - implements the IMA hooks: ima_inode_alloc, ima_inode_free
  *     - cache integrity information associated with an inode
- *       using a radix tree.
+ *       using a rbtree tree.
  */
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
 #include "ima.h"
 
-RADIX_TREE(ima_iint_store, GFP_ATOMIC);
-DEFINE_SPINLOCK(ima_iint_lock);
+static struct rb_root ima_iint_tree = RB_ROOT;
+static DEFINE_SPINLOCK(ima_iint_lock);
 static struct kmem_cache *iint_cache __read_mostly;
 
 int iint_initialized = 0;
 
-/* ima_iint_find_get - return the iint associated with an inode
- *
- * ima_iint_find_get gets a reference to the iint. Caller must
- * remember to put the iint reference.
+/*
+ * __ima_iint_find - return the iint associated with an inode
  */
-struct ima_iint_cache *ima_iint_find_get(struct inode *inode)
+static struct ima_iint_cache *__ima_iint_find(struct inode *inode)
 {
        struct ima_iint_cache *iint;
+       struct rb_node *n = ima_iint_tree.rb_node;
+
+       assert_spin_locked(&ima_iint_lock);
+
+       while (n) {
+               iint = rb_entry(n, struct ima_iint_cache, rb_node);
+
+               if (inode < iint->inode)
+                       n = n->rb_left;
+               else if (inode > iint->inode)
+                       n = n->rb_right;
+               else
+                       break;
+       }
+       if (!n)
+               return NULL;
 
-       rcu_read_lock();
-       iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
-       if (!iint)
-               goto out;
-       kref_get(&iint->refcount);
-out:
-       rcu_read_unlock();
        return iint;
 }
 
-/**
- * ima_inode_alloc - allocate an iint associated with an inode
- * @inode: pointer to the inode
+/*
+ * ima_iint_find - return the iint associated with an inode
  */
-int ima_inode_alloc(struct inode *inode)
+struct ima_iint_cache *ima_iint_find(struct inode *inode)
 {
-       struct ima_iint_cache *iint = NULL;
-       int rc = 0;
-
-       iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
-       if (!iint)
-               return -ENOMEM;
+       struct ima_iint_cache *iint;
 
-       rc = radix_tree_preload(GFP_NOFS);
-       if (rc < 0)
-               goto out;
+       if (!IS_IMA(inode))
+               return NULL;
 
        spin_lock(&ima_iint_lock);
-       rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
+       iint = __ima_iint_find(inode);
        spin_unlock(&ima_iint_lock);
-       radix_tree_preload_end();
-out:
-       if (rc < 0)
-               kmem_cache_free(iint_cache, iint);
 
-       return rc;
+       return iint;
 }
 
-/* iint_free - called when the iint refcount goes to zero */
-void iint_free(struct kref *kref)
+static void iint_free(struct ima_iint_cache *iint)
 {
-       struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
-                                                  refcount);
        iint->version = 0;
        iint->flags = 0UL;
-       if (iint->readcount != 0) {
-               printk(KERN_INFO "%s: readcount: %ld\n", __func__,
-                      iint->readcount);
-               iint->readcount = 0;
-       }
-       if (iint->writecount != 0) {
-               printk(KERN_INFO "%s: writecount: %ld\n", __func__,
-                      iint->writecount);
-               iint->writecount = 0;
-       }
-       if (iint->opencount != 0) {
-               printk(KERN_INFO "%s: opencount: %ld\n", __func__,
-                      iint->opencount);
-               iint->opencount = 0;
-       }
-       kref_init(&iint->refcount);
        kmem_cache_free(iint_cache, iint);
 }
 
-void iint_rcu_free(struct rcu_head *rcu_head)
+/**
+ * ima_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ */
+int ima_inode_alloc(struct inode *inode)
 {
-       struct ima_iint_cache *iint = container_of(rcu_head,
-                                                  struct ima_iint_cache, rcu);
-       kref_put(&iint->refcount, iint_free);
+       struct rb_node **p;
+       struct rb_node *new_node, *parent = NULL;
+       struct ima_iint_cache *new_iint, *test_iint;
+       int rc;
+
+       new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
+       if (!new_iint)
+               return -ENOMEM;
+
+       new_iint->inode = inode;
+       new_node = &new_iint->rb_node;
+
+       mutex_lock(&inode->i_mutex); /* i_flags */
+       spin_lock(&ima_iint_lock);
+
+       p = &ima_iint_tree.rb_node;
+       while (*p) {
+               parent = *p;
+               test_iint = rb_entry(parent, struct ima_iint_cache, rb_node);
+
+               rc = -EEXIST;
+               if (inode < test_iint->inode)
+                       p = &(*p)->rb_left;
+               else if (inode > test_iint->inode)
+                       p = &(*p)->rb_right;
+               else
+                       goto out_err;
+       }
+
+       inode->i_flags |= S_IMA;
+       rb_link_node(new_node, parent, p);
+       rb_insert_color(new_node, &ima_iint_tree);
+
+       spin_unlock(&ima_iint_lock);
+       mutex_unlock(&inode->i_mutex); /* i_flags */
+
+       return 0;
+out_err:
+       spin_unlock(&ima_iint_lock);
+       mutex_unlock(&inode->i_mutex); /* i_flags */
+       iint_free(new_iint);
+
+       return rc;
 }
 
 /**
@@ -116,11 +137,20 @@ void ima_inode_free(struct inode *inode)
 {
        struct ima_iint_cache *iint;
 
+       if (inode->i_readcount)
+               printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount);
+
+       inode->i_readcount = 0;
+
+       if (!IS_IMA(inode))
+               return;
+
        spin_lock(&ima_iint_lock);
-       iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
+       iint = __ima_iint_find(inode);
+       rb_erase(&iint->rb_node, &ima_iint_tree);
        spin_unlock(&ima_iint_lock);
-       if (iint)
-               call_rcu(&iint->rcu, iint_rcu_free);
+
+       iint_free(iint);
 }
 
 static void init_once(void *foo)
@@ -131,10 +161,6 @@ static void init_once(void *foo)
        iint->version = 0;
        iint->flags = 0UL;
        mutex_init(&iint->mutex);
-       iint->readcount = 0;
-       iint->writecount = 0;
-       iint->opencount = 0;
-       kref_init(&iint->refcount);
 }
 
 static int __init ima_iintcache_init(void)
index e662b89d407944103dc121b9ccb37f7e68ac62e1..203de979d30565811c2da951cae458e08645d6ab 100644 (file)
@@ -85,50 +85,6 @@ out:
        return found;
 }
 
-/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
- *
- * When opening a file for read, if the file is already open for write,
- * the file could change, resulting in a file measurement error.
- *
- * Opening a file for write, if the file is already open for read, results
- * in a time of measure, time of use (ToMToU) error.
- *
- * In either case invalidate the PCR.
- */
-enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
-static void ima_read_write_check(enum iint_pcr_error error,
-                                struct ima_iint_cache *iint,
-                                struct inode *inode,
-                                const unsigned char *filename)
-{
-       switch (error) {
-       case TOMTOU:
-               if (iint->readcount > 0)
-                       ima_add_violation(inode, filename, "invalid_pcr",
-                                         "ToMToU");
-               break;
-       case OPEN_WRITERS:
-               if (iint->writecount > 0)
-                       ima_add_violation(inode, filename, "invalid_pcr",
-                                         "open_writers");
-               break;
-       }
-}
-
-/*
- * Update the counts given an fmode_t
- */
-static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
-{
-       BUG_ON(!mutex_is_locked(&iint->mutex));
-
-       iint->opencount++;
-       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
-               iint->readcount++;
-       if (mode & FMODE_WRITE)
-               iint->writecount++;
-}
-
 /*
  * ima_counts_get - increment file counts
  *
@@ -145,62 +101,101 @@ void ima_counts_get(struct file *file)
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        fmode_t mode = file->f_mode;
-       struct ima_iint_cache *iint;
        int rc;
+       bool send_tomtou = false, send_writers = false;
 
-       if (!iint_initialized || !S_ISREG(inode->i_mode))
+       if (!S_ISREG(inode->i_mode))
                return;
-       iint = ima_iint_find_get(inode);
-       if (!iint)
-               return;
-       mutex_lock(&iint->mutex);
+
+       spin_lock(&inode->i_lock);
+
        if (!ima_initialized)
                goto out;
-       rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
-       if (rc < 0)
-               goto out;
 
        if (mode & FMODE_WRITE) {
-               ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name);
+               if (inode->i_readcount && IS_IMA(inode))
+                       send_tomtou = true;
                goto out;
        }
-       ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name);
+
+       rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK);
+       if (rc < 0)
+               goto out;
+
+       if (atomic_read(&inode->i_writecount) > 0)
+               send_writers = true;
 out:
-       ima_inc_counts(iint, file->f_mode);
-       mutex_unlock(&iint->mutex);
+       /* remember the vfs deals with i_writecount */
+       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+               inode->i_readcount++;
 
-       kref_put(&iint->refcount, iint_free);
+       spin_unlock(&inode->i_lock);
+
+       if (send_tomtou)
+               ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
+                                 "ToMToU");
+       if (send_writers)
+               ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
+                                 "open_writers");
 }
 
 /*
  * Decrement ima counts
  */
-static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
-                          struct file *file)
+static void ima_dec_counts(struct inode *inode, struct file *file)
 {
        mode_t mode = file->f_mode;
-       BUG_ON(!mutex_is_locked(&iint->mutex));
 
-       iint->opencount--;
-       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
-               iint->readcount--;
-       if (mode & FMODE_WRITE) {
-               iint->writecount--;
-               if (iint->writecount == 0) {
-                       if (iint->version != inode->i_version)
-                               iint->flags &= ~IMA_MEASURED;
+       assert_spin_locked(&inode->i_lock);
+
+       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+               if (unlikely(inode->i_readcount == 0)) {
+                       if (!ima_limit_imbalance(file)) {
+                               printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
+                                      __func__, inode->i_readcount);
+                               dump_stack();
+                       }
+                       return;
                }
+               inode->i_readcount--;
        }
+}
 
-       if (((iint->opencount < 0) ||
-            (iint->readcount < 0) ||
-            (iint->writecount < 0)) &&
-           !ima_limit_imbalance(file)) {
-               printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
-                      __func__, iint->readcount, iint->writecount,
-                      iint->opencount);
-               dump_stack();
-       }
+static void ima_check_last_writer(struct ima_iint_cache *iint,
+                                 struct inode *inode,
+                                 struct file *file)
+{
+       mode_t mode = file->f_mode;
+
+       BUG_ON(!mutex_is_locked(&iint->mutex));
+       assert_spin_locked(&inode->i_lock);
+
+       if (mode & FMODE_WRITE &&
+           atomic_read(&inode->i_writecount) == 1 &&
+           iint->version != inode->i_version)
+               iint->flags &= ~IMA_MEASURED;
+}
+
+static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
+                              struct file *file)
+{
+       mutex_lock(&iint->mutex);
+       spin_lock(&inode->i_lock);
+
+       ima_dec_counts(inode, file);
+       ima_check_last_writer(iint, inode, file);
+
+       spin_unlock(&inode->i_lock);
+       mutex_unlock(&iint->mutex);
+}
+
+static void ima_file_free_noiint(struct inode *inode, struct file *file)
+{
+       spin_lock(&inode->i_lock);
+
+       ima_dec_counts(inode, file);
+
+       spin_unlock(&inode->i_lock);
 }
 
 /**
@@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
  * @file: pointer to file structure being freed
  *
  * Flag files that changed, based on i_version;
- * and decrement the iint readcount/writecount.
+ * and decrement the i_readcount.
  */
 void ima_file_free(struct file *file)
 {
@@ -217,14 +212,14 @@ void ima_file_free(struct file *file)
 
        if (!iint_initialized || !S_ISREG(inode->i_mode))
                return;
-       iint = ima_iint_find_get(inode);
-       if (!iint)
-               return;
 
-       mutex_lock(&iint->mutex);
-       ima_dec_counts(iint, inode, file);
-       mutex_unlock(&iint->mutex);
-       kref_put(&iint->refcount, iint_free);
+       iint = ima_iint_find(inode);
+
+       if (iint)
+               ima_file_free_iint(iint, inode, file);
+       else
+               ima_file_free_noiint(inode, file);
+
 }
 
 static int process_measurement(struct file *file, const unsigned char *filename,
@@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
 
        if (!ima_initialized || !S_ISREG(inode->i_mode))
                return 0;
-       iint = ima_iint_find_get(inode);
-       if (!iint)
-               return -ENOMEM;
+
+       rc = ima_must_measure(NULL, inode, mask, function);
+       if (rc != 0)
+               return rc;
+retry:
+       iint = ima_iint_find(inode);
+       if (!iint) {
+               rc = ima_inode_alloc(inode);
+               if (!rc || rc == -EEXIST)
+                       goto retry;
+               return rc;
+       }
 
        mutex_lock(&iint->mutex);
+
        rc = ima_must_measure(iint, inode, mask, function);
        if (rc != 0)
                goto out;
@@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename,
                ima_store_measurement(iint, file, filename);
 out:
        mutex_unlock(&iint->mutex);
-       kref_put(&iint->refcount, iint_free);
        return rc;
 }
 
index b50f472061a43c6ec7fb53781c084fb2cb487dcb..3ef5e2a7a741aca4b13cd08b571e0a0ca0ee7d72 100644 (file)
@@ -325,16 +325,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
 
 int security_inode_alloc(struct inode *inode)
 {
-       int ret;
-
        inode->i_security = NULL;
-       ret =  security_ops->inode_alloc_security(inode);
-       if (ret)
-               return ret;
-       ret = ima_inode_alloc(inode);
-       if (ret)
-               security_inode_free(inode);
-       return ret;
+       return security_ops->inode_alloc_security(inode);
 }
 
 void security_inode_free(struct inode *inode)
index 87e0556bae70ff977ea290b3cdfcc2c308d8edf5..55a755c1a1bd9546a4655e83351cc93bc92cf655 100644 (file)
@@ -978,6 +978,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
        struct inode *ret = new_inode(sb);
 
        if (ret) {
+               ret->i_ino = get_next_ino();
                ret->i_mode = mode;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
        }
index ed8ccd680102b53d98f9b98cb9a3aa05c8143090..1d0bf8fa1922fdedec280ba5085f8cafe43d1d68 100644 (file)
@@ -127,10 +127,8 @@ char *tomoyo_realpath_from_path(struct path *path)
                /* If we don't have a vfsmount, we can't calculate. */
                if (!path->mnt)
                        break;
-               spin_lock(&dcache_lock);
                /* go to whatever namespace root we are under */
                pos = __d_path(path, &ns_root, buf, buf_len);
-               spin_unlock(&dcache_lock);
                /* Prepend "/proc" prefix if using internal proc vfs mount. */
                if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
                    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
index f7c3df8b521b2c85db5771a68acf27f981084aae..57b792e2439a0f9b939c5789d7c23678ff8377bc 100644 (file)
@@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
                return -EEXIST;
        }
        for (idx = 0; idx < snd_ecards_limit; idx++) {
-               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
-                       goto __exist;
+               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+                       if (card == snd_cards[idx])
+                               goto __ok;
+                       else
+                               goto __exist;
+               }
        }
        strcpy(card->id, buf1);
        snd_info_card_id_change(card);
+__ok:
        mutex_unlock(&snd_card_mutex);
 
        return count;
index f50ebf20df966a93380d15fd1a3c3e4acd2890e7..822dd56993ca2a54de249d38e5827be11be9b7ac 100644 (file)
@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
        struct snd_mixer_oss_file *fmixer;
 
        if (file->private_data) {
-               fmixer = (struct snd_mixer_oss_file *) file->private_data;
+               fmixer = file->private_data;
                module_put(fmixer->card->module);
                snd_card_file_remove(fmixer->card, file);
                kfree(fmixer);
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
 
 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
+       return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
 }
 
 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
                                     struct snd_mixer_oss_slot *pslot,
                                     int *left, int *right)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        *left = *right = 100;
        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
        if (numid == ID_UNKNOWN)
                return;
        down_read(&card->controls_rwsem);
-       if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
+       if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+               up_read(&card->controls_rwsem);
                return;
+       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
                return;
        down_read(&card->controls_rwsem);
        if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
-               up_read(&fmixer->card->controls_rwsem);
+               up_read(&card->controls_rwsem);
                return;
        }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
                                     struct snd_mixer_oss_slot *pslot,
                                     int left, int right)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
@@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
                                        struct snd_mixer_oss_slot *pslot,
                                        int *active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        int left, right;
        
        left = right = 1;
@@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
                                           struct snd_mixer_oss_slot *pslot,
                                           int *active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        int left, right;
        
        left = right = 1;
@@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
                                        struct snd_mixer_oss_slot *pslot,
                                        int active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
        return 0;
@@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
                                           struct snd_mixer_oss_slot *pslot,
                                           int active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
        return 0;
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL) {
                err = -ENOMEM;
-               goto __unlock;
+               goto __free_only;
        }
        down_read(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
                pslot = &mixer->slots[idx];
-               slot = (struct slot *)pslot->private_data;
+               slot = pslot->private_data;
                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
                        continue;
                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        err = 0;
       __unlock:
        up_read(&card->controls_rwsem);
+      __free_only:
        kfree(uctl);
        kfree(uinfo);
        return err;
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL) {
                err = -ENOMEM;
-               goto __unlock;
+               goto __free_only;
        }
        down_read(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
                pslot = &mixer->slots[idx];
-               slot = (struct slot *)pslot->private_data;
+               slot = pslot->private_data;
                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
                        continue;
                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        err = 0;
       __unlock:
        up_read(&card->controls_rwsem);
+      __free_only:
        kfree(uctl);
        kfree(uinfo);
        return err;
@@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
 
 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
 {
-       struct slot *p = (struct slot *)chn->private_data;
+       struct slot *p = chn->private_data;
        if (p) {
                if (p->allocated && p->assigned) {
                        kfree(p->assigned->name);
index ac242a377aea8068f859bce49aae6825aae5d001..6b4b1287b314455111c5853334a4aded9425edd3 100644 (file)
@@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
 static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
                                             struct snd_info_buffer *buffer)
 {
-       snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
-                              buffer);
+       snd_pcm_proc_info_read(entry->private_data, buffer);
 }
 
 static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
index e23e0e7ab26f9ff5f02204ca62422a14cc674e5e..a1707cca9c6635c8b4cd7e79b5cebe21bffc2d9e 100644 (file)
@@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                /* delta = "expected next hw_ptr" for in_interrupt != 0 */
                delta = runtime->hw_ptr_interrupt + runtime->period_size;
                if (delta > new_hw_ptr) {
-                       hw_base += runtime->buffer_size;
-                       if (hw_base >= runtime->boundary)
-                               hw_base = 0;
-                       new_hw_ptr = hw_base + pos;
-                       goto __delta;
+                       /* check for double acknowledged interrupts */
+                       hdelta = jiffies - runtime->hw_ptr_jiffies;
+                       if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+                               hw_base += runtime->buffer_size;
+                               if (hw_base >= runtime->boundary)
+                                       hw_base = 0;
+                               new_hw_ptr = hw_base + pos;
+                               goto __delta;
+                       }
                }
        }
        /* new_hw_ptr might be lower than old_hw_ptr in case when */
index d4eb2ef8078416cc8d06e5d80f3ec3bb467a4f1b..8bc7cb3db33056abce9a03cec36a4266305aa12c 100644 (file)
@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
 
 #ifdef RULES_DEBUG
 #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
        HW_PARAM(ACCESS),
        HW_PARAM(FORMAT),
        HW_PARAM(SUBFORMAT),
@@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        runtime->hw_ptr_jiffies = jiffies;
+       runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
+                                                           runtime->rate;
        runtime->status->state = state;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
index 480c38623da80949fded427bcc98ff54e1092872..c8961165277cce21a85147d6571cf014e86bf13d 100644 (file)
@@ -74,6 +74,25 @@ config SND_DUMMY
          To compile this driver as a module, choose M here: the module
          will be called snd-dummy.
 
+config SND_ALOOP
+        tristate "Generic loopback driver (PCM)"
+        select SND_PCM
+        help
+          Say 'Y' or 'M' to include support for the PCM loopback device.
+         This module returns played samples back to the user space using
+         the standard ALSA PCM device. The devices are routed 0->1 and
+          1->0, where first number is the playback PCM device and second
+         number is the capture device. Module creates two PCM devices and
+         configured number of substreams (see the pcm_substreams module
+          parameter).
+
+         The looback device allow time sychronization with an external
+         timing source using the time shift universal control (+-20%
+         of system time).
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-aloop.
+
 config SND_VIRMIDI
        tristate "Virtual MIDI soundcard"
        depends on SND_SEQUENCER
index d4a07f9ff2c7117f018971b37b07ea6950af875a..1a8440c8b1386e5ef4f413c8826b1f80ca93a951 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 snd-dummy-objs := dummy.o
+snd-aloop-objs := aloop.o
 snd-mtpav-objs := mtpav.o
 snd-mts64-objs := mts64.o
 snd-portman2x4-objs := portman2x4.o
@@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
new file mode 100644 (file)
index 0000000..12b44b0
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+ *  Loopback soundcard
+ *
+ *  Original code:
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *
+ *  More accurate positioning and full-duplex support:
+ *  Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de>
+ *
+ *  Major (almost complete) rewrite:
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *  A next major update in 2010 (separate timers for playback and capture):
+ *  Copyright (c) Jaroslav Kysela <perex@perex.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You 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/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("A loopback soundcard");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
+
+#define MAX_PCM_SUBSTREAMS     8
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
+module_param_array(pcm_substreams, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+
+#define NO_PITCH 100000
+
+struct loopback_pcm;
+
+struct loopback_cable {
+       spinlock_t lock;
+       struct loopback_pcm *streams[2];
+       struct snd_pcm_hardware hw;
+       /* flags */
+       unsigned int valid;
+       unsigned int running;
+       unsigned int pause;
+};
+
+struct loopback_setup {
+       unsigned int notify: 1;
+       unsigned int rate_shift;
+       unsigned int format;
+       unsigned int rate;
+       unsigned int channels;
+       struct snd_ctl_elem_id active_id;
+       struct snd_ctl_elem_id format_id;
+       struct snd_ctl_elem_id rate_id;
+       struct snd_ctl_elem_id channels_id;
+};
+
+struct loopback {
+       struct snd_card *card;
+       struct mutex cable_lock;
+       struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
+       struct snd_pcm *pcm[2];
+       struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+};
+
+struct loopback_pcm {
+       struct loopback *loopback;
+       struct snd_pcm_substream *substream;
+       struct loopback_cable *cable;
+       unsigned int pcm_buffer_size;
+       unsigned int buf_pos;   /* position in buffer */
+       unsigned int silent_size;
+       /* PCM parameters */
+       unsigned int pcm_period_size;
+       unsigned int pcm_bps;           /* bytes per second */
+       unsigned int pcm_salign;        /* bytes per sample * channels */
+       unsigned int pcm_rate_shift;    /* rate shift value */
+       /* flags */
+       unsigned int period_update_pending :1;
+       /* timer stuff */
+       unsigned int irq_pos;           /* fractional IRQ position */
+       unsigned int period_size_frac;
+       unsigned long last_jiffies;
+       struct timer_list timer;
+};
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+       if (dpcm->pcm_rate_shift == NO_PITCH) {
+               x /= HZ;
+       } else {
+               x = div_u64(NO_PITCH * (unsigned long long)x,
+                           HZ * (unsigned long long)dpcm->pcm_rate_shift);
+       }
+       return x - (x % dpcm->pcm_salign);
+}
+
+static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+       if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */
+               return x * HZ;
+       } else {
+               x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
+                           NO_PITCH);
+       }
+       return x;
+}
+
+static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
+{
+       int device = dpcm->substream->pstr->pcm->device;
+       
+       if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               device ^= 1;
+       return &dpcm->loopback->setup[dpcm->substream->number][device];
+}
+
+static inline unsigned int get_notify(struct loopback_pcm *dpcm)
+{
+       return get_setup(dpcm)->notify;
+}
+
+static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
+{
+       return get_setup(dpcm)->rate_shift;
+}
+
+static void loopback_timer_start(struct loopback_pcm *dpcm)
+{
+       unsigned long tick;
+       unsigned int rate_shift = get_rate_shift(dpcm);
+
+       if (rate_shift != dpcm->pcm_rate_shift) {
+               dpcm->pcm_rate_shift = rate_shift;
+               dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+       }
+       if (dpcm->period_size_frac <= dpcm->irq_pos) {
+               dpcm->irq_pos %= dpcm->period_size_frac;
+               dpcm->period_update_pending = 1;
+       }
+       tick = dpcm->period_size_frac - dpcm->irq_pos;
+       tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+       dpcm->timer.expires = jiffies + tick;
+       add_timer(&dpcm->timer);
+}
+
+static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+{
+       del_timer(&dpcm->timer);
+       dpcm->timer.expires = 0;
+}
+
+#define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE    (1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH       (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+       struct snd_pcm_runtime *runtime, *cruntime;
+       struct loopback_setup *setup;
+       struct snd_card *card;
+       int check;
+
+       if (cable->valid != CABLE_VALID_BOTH) {
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       goto __notify;
+               return 0;
+       }
+       runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+                                                       substream->runtime;
+       cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+                                                       substream->runtime;
+       check = runtime->format != cruntime->format ||
+               runtime->rate != cruntime->rate ||
+               runtime->channels != cruntime->channels;
+       if (!check)
+               return 0;
+       if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               return -EIO;
+       } else {
+               snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+                                       substream, SNDRV_PCM_STATE_DRAINING);
+             __notify:
+               runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+                                                       substream->runtime;
+               setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
+               card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
+               if (setup->format != runtime->format) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->format_id);
+                       setup->format = runtime->format;
+               }
+               if (setup->rate != runtime->rate) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->rate_id);
+                       setup->rate = runtime->rate;
+               }
+               if (setup->channels != runtime->channels) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->channels_id);
+                       setup->channels = runtime->channels;
+               }
+       }
+       return 0;
+}
+
+static void loopback_active_notify(struct loopback_pcm *dpcm)
+{
+       snd_ctl_notify(dpcm->loopback->card,
+                      SNDRV_CTL_EVENT_MASK_VALUE,
+                      &get_setup(dpcm)->active_id);
+}
+
+static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+       int err, stream = 1 << substream->stream;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               err = loopback_check_format(cable, substream->stream);
+               if (err < 0)
+                       return err;
+               dpcm->last_jiffies = jiffies;
+               dpcm->pcm_rate_shift = 0;
+               spin_lock(&cable->lock);        
+               cable->running |= stream;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_start(dpcm);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       loopback_active_notify(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock(&cable->lock);        
+               cable->running &= ~stream;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_stop(dpcm);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       loopback_active_notify(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock(&cable->lock);        
+               cable->pause |= stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_stop(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock(&cable->lock);
+               dpcm->last_jiffies = jiffies;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_start(dpcm);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void params_change_substream(struct loopback_pcm *dpcm,
+                                   struct snd_pcm_runtime *runtime)
+{
+       struct snd_pcm_runtime *dst_runtime;
+
+       if (dpcm == NULL || dpcm->substream == NULL)
+               return;
+       dst_runtime = dpcm->substream->runtime;
+       if (dst_runtime == NULL)
+               return;
+       dst_runtime->hw = dpcm->cable->hw;
+}
+
+static void params_change(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+
+       cable->hw.formats = (1ULL << runtime->format);
+       cable->hw.rate_min = runtime->rate;
+       cable->hw.rate_max = runtime->rate;
+       cable->hw.channels_min = runtime->channels;
+       cable->hw.channels_max = runtime->channels;
+       params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+                               runtime);
+       params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+                               runtime);
+}
+
+static int loopback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+       int bps, salign;
+
+       salign = (snd_pcm_format_width(runtime->format) *
+                                               runtime->channels) / 8;
+       bps = salign * runtime->rate;
+       if (bps <= 0 || salign <= 0)
+               return -EINVAL;
+
+       dpcm->buf_pos = 0;
+       dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               /* clear capture buffer */
+               dpcm->silent_size = dpcm->pcm_buffer_size;
+               snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+                                          runtime->buffer_size * runtime->channels);
+       }
+
+       dpcm->irq_pos = 0;
+       dpcm->period_update_pending = 0;
+       dpcm->pcm_bps = bps;
+       dpcm->pcm_salign = salign;
+       dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
+
+       mutex_lock(&dpcm->loopback->cable_lock);
+       if (!(cable->valid & ~(1 << substream->stream)) ||
+            (get_setup(dpcm)->notify &&
+            substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+               params_change(substream);
+       cable->valid |= 1 << substream->stream;
+       mutex_unlock(&dpcm->loopback->cable_lock);
+
+       return 0;
+}
+
+static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
+       char *dst = runtime->dma_area;
+       unsigned int dst_off = dpcm->buf_pos;
+
+       if (dpcm->silent_size >= dpcm->pcm_buffer_size)
+               return;
+       if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
+               bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
+
+       for (;;) {
+               unsigned int size = bytes;
+               if (dst_off + size > dpcm->pcm_buffer_size)
+                       size = dpcm->pcm_buffer_size - dst_off;
+               snd_pcm_format_set_silence(runtime->format, dst + dst_off,
+                                          bytes_to_frames(runtime, size) *
+                                               runtime->channels);
+               dpcm->silent_size += size;
+               bytes -= size;
+               if (!bytes)
+                       break;
+               dst_off = 0;
+       }
+}
+
+static void copy_play_buf(struct loopback_pcm *play,
+                         struct loopback_pcm *capt,
+                         unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = play->substream->runtime;
+       char *src = runtime->dma_area;
+       char *dst = capt->substream->runtime->dma_area;
+       unsigned int src_off = play->buf_pos;
+       unsigned int dst_off = capt->buf_pos;
+       unsigned int clear_bytes = 0;
+
+       /* check if playback is draining, trim the capture copy size
+        * when our pointer is at the end of playback ring buffer */
+       if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+           snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { 
+               snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
+               appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
+               appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
+               appl_ptr1 += play->buf_pos / play->pcm_salign;
+               if (appl_ptr < appl_ptr1)
+                       appl_ptr1 -= runtime->buffer_size;
+               diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
+               if (diff < bytes) {
+                       clear_bytes = bytes - diff;
+                       bytes = diff;
+               }
+       }
+
+       for (;;) {
+               unsigned int size = bytes;
+               if (src_off + size > play->pcm_buffer_size)
+                       size = play->pcm_buffer_size - src_off;
+               if (dst_off + size > capt->pcm_buffer_size)
+                       size = capt->pcm_buffer_size - dst_off;
+               memcpy(dst + dst_off, src + src_off, size);
+               capt->silent_size = 0;
+               bytes -= size;
+               if (!bytes)
+                       break;
+               src_off = (src_off + size) % play->pcm_buffer_size;
+               dst_off = (dst_off + size) % capt->pcm_buffer_size;
+       }
+
+       if (clear_bytes > 0) {
+               clear_capture_buf(capt, clear_bytes);
+               capt->silent_size = 0;
+       }
+}
+
+#define BYTEPOS_UPDATE_POSONLY 0
+#define BYTEPOS_UPDATE_CLEAR   1
+#define BYTEPOS_UPDATE_COPY    2
+
+static void loopback_bytepos_update(struct loopback_pcm *dpcm,
+                                   unsigned int delta,
+                                   unsigned int cmd)
+{
+       unsigned int count;
+       unsigned long last_pos;
+
+       last_pos = byte_pos(dpcm, dpcm->irq_pos);
+       dpcm->irq_pos += delta * dpcm->pcm_bps;
+       count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+       if (!count)
+               return;
+       if (cmd == BYTEPOS_UPDATE_CLEAR)
+               clear_capture_buf(dpcm, count);
+       else if (cmd == BYTEPOS_UPDATE_COPY)
+               copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+                             dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+                             count);
+       dpcm->buf_pos += count;
+       dpcm->buf_pos %= dpcm->pcm_buffer_size;
+       if (dpcm->irq_pos >= dpcm->period_size_frac) {
+               dpcm->irq_pos %= dpcm->period_size_frac;
+               dpcm->period_update_pending = 1;
+       }
+}
+
+static unsigned int loopback_pos_update(struct loopback_cable *cable)
+{
+       struct loopback_pcm *dpcm_play =
+                       cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+       struct loopback_pcm *dpcm_capt =
+                       cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+       unsigned long delta_play = 0, delta_capt = 0;
+       unsigned int running;
+
+       spin_lock(&cable->lock);        
+       running = cable->running ^ cable->pause;
+       if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+               delta_play = jiffies - dpcm_play->last_jiffies;
+               dpcm_play->last_jiffies += delta_play;
+       }
+
+       if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+               delta_capt = jiffies - dpcm_capt->last_jiffies;
+               dpcm_capt->last_jiffies += delta_capt;
+       }
+
+       if (delta_play == 0 && delta_capt == 0) {
+               spin_unlock(&cable->lock);
+               return running;
+       }
+               
+       if (delta_play > delta_capt) {
+               loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
+                                       BYTEPOS_UPDATE_POSONLY);
+               delta_play = delta_capt;
+       } else if (delta_play < delta_capt) {
+               loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
+                                       BYTEPOS_UPDATE_CLEAR);
+               delta_capt = delta_play;
+       }
+
+       if (delta_play == 0 && delta_capt == 0) {
+               spin_unlock(&cable->lock);
+               return running;
+       }
+       /* note delta_capt == delta_play at this moment */
+       loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
+       loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+       spin_unlock(&cable->lock);
+       return running;
+}
+
+static void loopback_timer_function(unsigned long data)
+{
+       struct loopback_pcm *dpcm = (struct loopback_pcm *)data;
+       unsigned int running;
+
+       running = loopback_pos_update(dpcm->cable);
+       if (running & (1 << dpcm->substream->stream)) {
+               loopback_timer_start(dpcm);
+               if (dpcm->period_update_pending) {
+                       dpcm->period_update_pending = 0;
+                       snd_pcm_period_elapsed(dpcm->substream);
+               }
+       }
+}
+
+static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+
+       loopback_pos_update(dpcm->cable);
+       return bytes_to_frames(runtime, dpcm->buf_pos);
+}
+
+static struct snd_pcm_hardware loopback_pcm_hardware =
+{
+       .info =         (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+                        SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+       .formats =      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+                        SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
+                        SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
+       .rates =        SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+       .rate_min =             8000,
+       .rate_max =             192000,
+       .channels_min =         1,
+       .channels_max =         32,
+       .buffer_bytes_max =     2 * 1024 * 1024,
+       .period_bytes_min =     64,
+       /* note check overflow in frac_pos() using pcm_rate_shift before
+          changing period_bytes_max value */
+       .period_bytes_max =     1024 * 1024,
+       .periods_min =          1,
+       .periods_max =          1024,
+       .fifo_size =            0,
+};
+
+static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
+{
+       struct loopback_pcm *dpcm = runtime->private_data;
+       kfree(dpcm);
+}
+
+static int loopback_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int loopback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+
+       mutex_lock(&dpcm->loopback->cable_lock);
+       cable->valid &= ~(1 << substream->stream);
+       mutex_unlock(&dpcm->loopback->cable_lock);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static unsigned int get_cable_index(struct snd_pcm_substream *substream)
+{
+       if (!substream->pcm->device)
+               return substream->stream;
+       else
+               return !substream->stream;
+}
+
+static int rule_format(struct snd_pcm_hw_params *params,
+                      struct snd_pcm_hw_rule *rule)
+{
+
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_mask *maskp = hw_param_mask(params, rule->var);
+
+       maskp->bits[0] &= (u_int32_t)hw->formats;
+       maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+       memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+       if (! maskp->bits[0] && ! maskp->bits[1])
+               return -EINVAL;
+       return 0;
+}
+
+static int rule_rate(struct snd_pcm_hw_params *params,
+                    struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_interval t;
+
+        t.min = hw->rate_min;
+        t.max = hw->rate_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int rule_channels(struct snd_pcm_hw_params *params,
+                        struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_interval t;
+
+        t.min = hw->channels_min;
+        t.max = hw->channels_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int loopback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm;
+       struct loopback_cable *cable;
+       int err = 0;
+       int dev = get_cable_index(substream);
+
+       mutex_lock(&loopback->cable_lock);
+       dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+       if (!dpcm) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+       dpcm->loopback = loopback;
+       dpcm->substream = substream;
+       setup_timer(&dpcm->timer, loopback_timer_function,
+                   (unsigned long)dpcm);
+
+       cable = loopback->cables[substream->number][dev];
+       if (!cable) {
+               cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+               if (!cable) {
+                       kfree(dpcm);
+                       err = -ENOMEM;
+                       goto unlock;
+               }
+               spin_lock_init(&cable->lock);
+               cable->hw = loopback_pcm_hardware;
+               loopback->cables[substream->number][dev] = cable;
+       }
+       dpcm->cable = cable;
+       cable->streams[substream->stream] = dpcm;
+
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+       /* use dynamic rules based on actual runtime->hw values */
+       /* note that the default rules created in the PCM midlevel code */
+       /* are cached -> they do not reflect the actual state */
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_FORMAT,
+                                 rule_format, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_FORMAT, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+                                 rule_rate, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS,
+                                 rule_channels, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (err < 0)
+               goto unlock;
+
+       runtime->private_data = dpcm;
+       runtime->private_free = loopback_runtime_free;
+       if (get_notify(dpcm))
+               runtime->hw = loopback_pcm_hardware;
+       else
+               runtime->hw = cable->hw;
+ unlock:
+       mutex_unlock(&loopback->cable_lock);
+       return err;
+}
+
+static int loopback_close(struct snd_pcm_substream *substream)
+{
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm = substream->runtime->private_data;
+       struct loopback_cable *cable;
+       int dev = get_cable_index(substream);
+
+       loopback_timer_stop(dpcm);
+       mutex_lock(&loopback->cable_lock);
+       cable = loopback->cables[substream->number][dev];
+       if (cable->streams[!substream->stream]) {
+               /* other stream is still alive */
+               cable->streams[substream->stream] = NULL;
+       } else {
+               /* free the cable */
+               loopback->cables[substream->number][dev] = NULL;
+               kfree(cable);
+       }
+       mutex_unlock(&loopback->cable_lock);
+       return 0;
+}
+
+static struct snd_pcm_ops loopback_playback_ops = {
+       .open =         loopback_open,
+       .close =        loopback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    loopback_hw_params,
+       .hw_free =      loopback_hw_free,
+       .prepare =      loopback_prepare,
+       .trigger =      loopback_trigger,
+       .pointer =      loopback_pointer,
+};
+
+static struct snd_pcm_ops loopback_capture_ops = {
+       .open =         loopback_open,
+       .close =        loopback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    loopback_hw_params,
+       .hw_free =      loopback_hw_free,
+       .prepare =      loopback_prepare,
+       .trigger =      loopback_trigger,
+       .pointer =      loopback_pointer,
+};
+
+static int __devinit loopback_pcm_new(struct loopback *loopback,
+                                     int device, int substreams)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(loopback->card, "Loopback PCM", device,
+                         substreams, substreams, &pcm);
+       if (err < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops);
+
+       pcm->private_data = loopback;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "Loopback PCM");
+
+       loopback->pcm[device] = pcm;
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                       snd_dma_continuous_data(GFP_KERNEL),
+                       0, 2 * 1024 * 1024);
+       return 0;
+}
+
+static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,   
+                                   struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 80000;
+       uinfo->value.integer.max = 120000;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate_shift;
+       return 0;
+}
+
+static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int change = 0;
+
+       val = ucontrol->value.integer.value[0];
+       if (val < 80000)
+               val = 80000;
+       if (val > 120000)
+               val = 120000;   
+       mutex_lock(&loopback->cable_lock);
+       if (val != loopback->setup[kcontrol->id.subdevice]
+                                 [kcontrol->id.device].rate_shift) {
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate_shift = val;
+               change = 1;
+       }
+       mutex_unlock(&loopback->cable_lock);
+       return change;
+}
+
+static int loopback_notify_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].notify;
+       return 0;
+}
+
+static int loopback_notify_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int change = 0;
+
+       val = ucontrol->value.integer.value[0] ? 1 : 0;
+       if (val != loopback->setup[kcontrol->id.subdevice]
+                               [kcontrol->id.device].notify) {
+               loopback->setup[kcontrol->id.subdevice]
+                       [kcontrol->id.device].notify = val;
+               change = 1;
+       }
+       return change;
+}
+
+static int loopback_active_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       struct loopback_cable *cable = loopback->cables
+                       [kcontrol->id.subdevice][kcontrol->id.device ^ 1];
+       unsigned int val = 0;
+
+       if (cable != NULL)
+               val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+                                                                       1 : 0;
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+static int loopback_format_info(struct snd_kcontrol *kcontrol,   
+                               struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_format_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].format;
+       return 0;
+}
+
+static int loopback_rate_info(struct snd_kcontrol *kcontrol,   
+                             struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 192000;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_rate_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate;
+       return 0;
+}
+
+static int loopback_channels_info(struct snd_kcontrol *kcontrol,   
+                                 struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 1024;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_channels_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].channels;
+       return 0;
+}
+
+static struct snd_kcontrol_new loopback_controls[]  __devinitdata = {
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Rate Shift 100000",
+       .info =         loopback_rate_shift_info,
+       .get =          loopback_rate_shift_get,
+       .put =          loopback_rate_shift_put,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Notify",
+       .info =         snd_ctl_boolean_mono_info,
+       .get =          loopback_notify_get,
+       .put =          loopback_notify_put,
+},
+#define ACTIVE_IDX 2
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Active",
+       .info =         snd_ctl_boolean_mono_info,
+       .get =          loopback_active_get,
+},
+#define FORMAT_IDX 3
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Format",
+       .info =         loopback_format_info,
+       .get =          loopback_format_get
+},
+#define RATE_IDX 4
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Rate",
+       .info =         loopback_rate_info,
+       .get =          loopback_rate_get
+},
+#define CHANNELS_IDX 5
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Channels",
+       .info =         loopback_channels_info,
+       .get =          loopback_channels_get
+}
+};
+
+static int __devinit loopback_mixer_new(struct loopback *loopback, int notify)
+{
+       struct snd_card *card = loopback->card;
+       struct snd_pcm *pcm;
+       struct snd_kcontrol *kctl;
+       struct loopback_setup *setup;
+       int err, dev, substr, substr_count, idx;
+
+       strcpy(card->mixername, "Loopback Mixer");
+       for (dev = 0; dev < 2; dev++) {
+               pcm = loopback->pcm[dev];
+               substr_count =
+                   pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+               for (substr = 0; substr < substr_count; substr++) {
+                       setup = &loopback->setup[substr][dev];
+                       setup->notify = notify;
+                       setup->rate_shift = NO_PITCH;
+                       setup->format = SNDRV_PCM_FORMAT_S16_LE;
+                       setup->rate = 48000;
+                       setup->channels = 2;
+                       for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
+                                                                       idx++) {
+                               kctl = snd_ctl_new1(&loopback_controls[idx],
+                                                   loopback);
+                               if (!kctl)
+                                       return -ENOMEM;
+                               kctl->id.device = dev;
+                               kctl->id.subdevice = substr;
+                               switch (idx) {
+                               case ACTIVE_IDX:
+                                       setup->active_id = kctl->id;
+                                       break;
+                               case FORMAT_IDX:
+                                       setup->format_id = kctl->id;
+                                       break;
+                               case RATE_IDX:
+                                       setup->rate_id = kctl->id;
+                                       break;
+                               case CHANNELS_IDX:
+                                       setup->channels_id = kctl->id;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               err = snd_ctl_add(card, kctl);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void print_dpcm_info(struct snd_info_buffer *buffer,
+                           struct loopback_pcm *dpcm,
+                           const char *id)
+{
+       snd_iprintf(buffer, "  %s\n", id);
+       if (dpcm == NULL) {
+               snd_iprintf(buffer, "    inactive\n");
+               return;
+       }
+       snd_iprintf(buffer, "    buffer_size:\t%u\n", dpcm->pcm_buffer_size);
+       snd_iprintf(buffer, "    buffer_pos:\t\t%u\n", dpcm->buf_pos);
+       snd_iprintf(buffer, "    silent_size:\t%u\n", dpcm->silent_size);
+       snd_iprintf(buffer, "    period_size:\t%u\n", dpcm->pcm_period_size);
+       snd_iprintf(buffer, "    bytes_per_sec:\t%u\n", dpcm->pcm_bps);
+       snd_iprintf(buffer, "    sample_align:\t%u\n", dpcm->pcm_salign);
+       snd_iprintf(buffer, "    rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
+       snd_iprintf(buffer, "    update_pending:\t%u\n",
+                                               dpcm->period_update_pending);
+       snd_iprintf(buffer, "    irq_pos:\t\t%u\n", dpcm->irq_pos);
+       snd_iprintf(buffer, "    period_frac:\t%u\n", dpcm->period_size_frac);
+       snd_iprintf(buffer, "    last_jiffies:\t%lu (%lu)\n",
+                                       dpcm->last_jiffies, jiffies);
+       snd_iprintf(buffer, "    timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void print_substream_info(struct snd_info_buffer *buffer,
+                                struct loopback *loopback,
+                                int sub,
+                                int num)
+{
+       struct loopback_cable *cable = loopback->cables[sub][num];
+
+       snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
+       if (cable == NULL) {
+               snd_iprintf(buffer, "  inactive\n");
+               return;
+       }
+       snd_iprintf(buffer, "  valid: %u\n", cable->valid);
+       snd_iprintf(buffer, "  running: %u\n", cable->running);
+       snd_iprintf(buffer, "  pause: %u\n", cable->pause);
+       print_dpcm_info(buffer, cable->streams[0], "Playback");
+       print_dpcm_info(buffer, cable->streams[1], "Capture");
+}
+
+static void print_cable_info(struct snd_info_entry *entry,
+                            struct snd_info_buffer *buffer)
+{
+       struct loopback *loopback = entry->private_data;
+       int sub, num;
+
+       mutex_lock(&loopback->cable_lock);
+       num = entry->name[strlen(entry->name)-1];
+       num = num == '0' ? 0 : 1;
+       for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
+               print_substream_info(buffer, loopback, sub, num);
+       mutex_unlock(&loopback->cable_lock);
+}
+
+static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)
+{
+       char name[32];
+       struct snd_info_entry *entry;
+       int err;
+
+       snprintf(name, sizeof(name), "cable#%d", cidx);
+       err = snd_card_proc_new(loopback->card, name, &entry);
+       if (err < 0)
+               return err;
+
+       snd_info_set_text_ops(entry, loopback, print_cable_info);
+       return 0;
+}
+
+#else /* !CONFIG_PROC_FS */
+
+#define loopback_proc_new(loopback, cidx) do { } while (0)
+
+#endif
+
+static int __devinit loopback_probe(struct platform_device *devptr)
+{
+       struct snd_card *card;
+       struct loopback *loopback;
+       int dev = devptr->id;
+       int err;
+
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct loopback), &card);
+       if (err < 0)
+               return err;
+       loopback = card->private_data;
+
+       if (pcm_substreams[dev] < 1)
+               pcm_substreams[dev] = 1;
+       if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
+               pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
+       
+       loopback->card = card;
+       mutex_init(&loopback->cable_lock);
+
+       err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
+       if (err < 0)
+               goto __nodev;
+       err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
+       if (err < 0)
+               goto __nodev;
+       err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
+       if (err < 0)
+               goto __nodev;
+       loopback_proc_new(loopback, 0);
+       loopback_proc_new(loopback, 1);
+       strcpy(card->driver, "Loopback");
+       strcpy(card->shortname, "Loopback");
+       sprintf(card->longname, "Loopback %i", dev + 1);
+       err = snd_card_register(card);
+       if (!err) {
+               platform_set_drvdata(devptr, card);
+               return 0;
+       }
+      __nodev:
+       snd_card_free(card);
+       return err;
+}
+
+static int __devexit loopback_remove(struct platform_device *devptr)
+{
+       snd_card_free(platform_get_drvdata(devptr));
+       platform_set_drvdata(devptr, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int loopback_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct loopback *loopback = card->private_data;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       snd_pcm_suspend_all(loopback->pcm[0]);
+       snd_pcm_suspend_all(loopback->pcm[1]);
+       return 0;
+}
+       
+static int loopback_resume(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif
+
+#define SND_LOOPBACK_DRIVER    "snd_aloop"
+
+static struct platform_driver loopback_driver = {
+       .probe          = loopback_probe,
+       .remove         = __devexit_p(loopback_remove),
+#ifdef CONFIG_PM
+       .suspend        = loopback_suspend,
+       .resume         = loopback_resume,
+#endif
+       .driver         = {
+               .name   = SND_LOOPBACK_DRIVER
+       },
+};
+
+static void loopback_unregister_all(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(devices); ++i)
+               platform_device_unregister(devices[i]);
+       platform_driver_unregister(&loopback_driver);
+}
+
+static int __init alsa_card_loopback_init(void)
+{
+       int i, err, cards;
+
+       err = platform_driver_register(&loopback_driver);
+       if (err < 0)
+               return err;
+
+
+       cards = 0;
+       for (i = 0; i < SNDRV_CARDS; i++) {
+               struct platform_device *device;
+               if (!enable[i])
+                       continue;
+               device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
+                                                        i, NULL, 0);
+               if (IS_ERR(device))
+                       continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
+               devices[i] = device;
+               cards++;
+       }
+       if (!cards) {
+#ifdef MODULE
+               printk(KERN_ERR "aloop: No loopback enabled\n");
+#endif
+               loopback_unregister_all();
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit alsa_card_loopback_exit(void)
+{
+       loopback_unregister_all();
+}
+
+module_init(alsa_card_loopback_init)
+module_exit(alsa_card_loopback_exit)
index 0e631c3221e3b72f46b2b1b11569d5931ead1097..f4cd49336f336866e36b6814206fdaf0ff9da226 100644 (file)
@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
                              sizeof(struct snd_card_virmidi), &card);
        if (err < 0)
                return err;
-       vmidi = (struct snd_card_virmidi *)card->private_data;
+       vmidi = card->private_data;
        vmidi->card = card;
 
        if (midi_devs[dev] > MAX_MIDI_DEVICES) {
index 42d7844ecd0bfa66ddf3db96527ccc18c79f7485..57ccba88700d68bacc493d01d030175158f40196 100644 (file)
@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
 static void proc_regs_read(struct snd_info_entry *entry,
                struct snd_info_buffer *buffer)
 {
-       struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+       struct snd_akm4xxx *ak = entry->private_data;
        int reg, val, chip;
        for (chip = 0; chip < ak->num_chips; chip++) {
                for (reg = 0; reg < ak->total_regs; reg++) {
index c6990c6807969ea948dcd1834dc0fb13f3b97ad2..52064cfa91f3f9d1fa82612b3d6ac50dac51b2a4 100644 (file)
@@ -77,6 +77,32 @@ config SND_ALS100
          To compile this driver as a module, choose M here: the module
          will be called snd-als100.
 
+config SND_AZT1605
+       tristate "Aztech AZT1605 Driver"
+       depends on SND
+       select SND_WSS_LIB
+       select SND_MPU401_UART
+       select SND_OPL3_LIB
+       help
+         Say Y here to include support for Aztech Sound Galaxy cards
+         based on the AZT1605 chipset.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-azt1605.
+
+config SND_AZT2316
+       tristate "Aztech AZT2316 Driver"
+       depends on SND
+       select SND_WSS_LIB
+       select SND_MPU401_UART
+       select SND_OPL3_LIB
+       help
+         Say Y here to include support for Aztech Sound Galaxy cards
+         based on the AZT2316 chipset.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-azt2316.
+
 config SND_AZT2320
        tristate "Aztech Systems AZT2320"
        depends on PNP
@@ -351,16 +377,6 @@ config SND_SB16_CSP
          coprocessor can do variable tasks like various compression and
          decompression algorithms.
 
-config SND_SGALAXY
-       tristate "Aztech Sound Galaxy"
-       select SND_WSS_LIB
-       help
-         Say Y here to include support for Aztech Sound Galaxy
-         soundcards.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-sgalaxy.
-
 config SND_SSCAPE
        tristate "Ensoniq SoundScape driver"
        select SND_MPU401_UART
index c73d30c4f46289c982ff793f42f6b3a6828052b8..8d781e419e2ece74797733a4eea86a14ba8ba5d6 100644 (file)
@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-sc6000-objs := sc6000.o
-snd-sgalaxy-objs := sgalaxy.o
 snd-sscape-objs := sscape.o
 
 # Toplevel Module Dependency
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
                     sb/ wavefront/ wss/
index bbcbf92a8ebea1cb11aa8d164f7651d6ab87d11d..3cb75bc9769927a303974783c7667b728eed798b 100644 (file)
@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                                sizeof(struct snd_card_ad1816a), &card);
        if (error < 0)
                return error;
-       acard = (struct snd_card_ad1816a *)card->private_data;
+       acard = card->private_data;
 
        if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
                snd_card_free(card);
index f7aa637b0d181497fccdf1f48ff7f352b68ad5e2..aac8dc15c2fe6eaf0329b780545068789d38ce6c 100644 (file)
@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
                                sizeof(struct snd_card_azt2320), &card);
        if (error < 0)
                return error;
-       acard = (struct snd_card_azt2320 *)card->private_data;
+       acard = card->private_data;
 
        if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
                snd_card_free(card);
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
new file mode 100644 (file)
index 0000000..e307066
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c
new file mode 100644 (file)
index 0000000..9a97643
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR               2
+#define GALAXY_DSP_MINOR               1
+
+#define GALAXY_CONFIG_SIZE             3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220          (0 << 0)
+#define GALAXY_CONFIG_SBA_240          (1 << 0)
+#define GALAXY_CONFIG_SBA_260          (2 << 0)
+#define GALAXY_CONFIG_SBA_280          (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK         GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300         (0 << 2)
+#define GALAXY_CONFIG_MPUA_330         (1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE       (1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE      (1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC     (1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI       (1 << 6)
+#define GALAXY_CONFIG_CD_MASK          (\
+       GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED           (1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK      GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2          (1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3          (1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5          (1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7          (1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2         (1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3         (1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5         (1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7         (1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530         (0 << 16)
+#define GALAXY_CONFIG_WSSA_604         (1 << 16)
+#define GALAXY_CONFIG_WSSA_E80         (2 << 16)
+#define GALAXY_CONFIG_WSSA_F40         (3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE       (1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11         (1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12         (1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15         (1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK       (\
+       GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+       GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE    (0 << 22)
+#define GALAXY_CONFIG_CDDMA_0          (1 << 22)
+#define GALAXY_CONFIG_CDDMA_1          (2 << 22)
+#define GALAXY_CONFIG_CDDMA_3          (3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK       GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK             (\
+       GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+       GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+       GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c
new file mode 100644 (file)
index 0000000..1894411
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR               3
+#define GALAXY_DSP_MINOR               1
+
+#define GALAXY_CONFIG_SIZE             4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220          (0 << 0)
+#define GALAXY_CONFIG_SBA_240          (1 << 0)
+#define GALAXY_CONFIG_SBA_260          (2 << 0)
+#define GALAXY_CONFIG_SBA_280          (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK         GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2          (1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5          (1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7          (1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10         (1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE    (0 << 6)
+#define GALAXY_CONFIG_SBDMA_0          (1 << 6)
+#define GALAXY_CONFIG_SBDMA_1          (2 << 6)
+#define GALAXY_CONFIG_SBDMA_3          (3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530         (0 << 8)
+#define GALAXY_CONFIG_WSSA_604         (1 << 8)
+#define GALAXY_CONFIG_WSSA_E80         (2 << 8)
+#define GALAXY_CONFIG_WSSA_F40         (3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE       (1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE      (1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300         (0 << 12)
+#define GALAXY_CONFIG_MPUA_330         (1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE       (1 << 13)
+
+#define GALAXY_CONFIG_CDA_310          (0 << 14)
+#define GALAXY_CONFIG_CDA_320          (1 << 14)
+#define GALAXY_CONFIG_CDA_340          (2 << 14)
+#define GALAXY_CONFIG_CDA_350          (3 << 14)
+#define GALAXY_CONFIG_CDA_MASK         GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE       (0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC     (1 << 16)
+#define GALAXY_CONFIG_CD_SONY          (2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI       (3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH                (4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5      (5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6      (6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7      (7 << 16)
+#define GALAXY_CONFIG_CD_MASK          GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE   (0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0         (1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1         (2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3         (3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK      GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE  (0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5                (1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6                (2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7                (3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK     GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2         (1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5         (1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7         (1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10                (1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5          (1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11         (1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12         (1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15         (1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK       (\
+       GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+       GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK             (\
+       GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+       GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+       GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
new file mode 100644 (file)
index 0000000..ee54df0
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET         0x6
+#define DSP_PORT_READ          0xa
+#define DSP_PORT_COMMAND       0xc
+#define DSP_PORT_STATUS                0xc
+#define DSP_PORT_DATA_AVAIL    0xe
+
+#define DSP_SIGNATURE          0xaa
+
+#define DSP_COMMAND_GET_VERSION        0xe1
+
+static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
+{
+       int loops = 1000;
+
+       while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+               if (!loops--)
+                       return -EIO;
+               cpu_relax();
+       }
+       *val = ioread8(port + DSP_PORT_READ);
+       return 0;
+}
+
+static int __devinit dsp_reset(void __iomem *port)
+{
+       u8 val;
+
+       iowrite8(1, port + DSP_PORT_RESET);
+       udelay(10);
+       iowrite8(0, port + DSP_PORT_RESET);
+
+       if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int __devinit dsp_command(void __iomem *port, u8 cmd)
+{
+       int loops = 1000;
+
+       while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+               if (!loops--)
+                       return -EIO;
+               cpu_relax();
+       }
+       iowrite8(cmd, port + DSP_PORT_COMMAND);
+       return 0;
+}
+
+static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+       int err;
+
+       err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(port, major);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(port, minor);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0       (1 << 0)
+#define WSS_CONFIG_DMA_1       (2 << 0)
+#define WSS_CONFIG_DMA_3       (3 << 0)
+#define WSS_CONFIG_DUPLEX      (1 << 2)
+#define WSS_CONFIG_IRQ_7       (1 << 3)
+#define WSS_CONFIG_IRQ_9       (2 << 3)
+#define WSS_CONFIG_IRQ_10      (3 << 3)
+#define WSS_CONFIG_IRQ_11      (4 << 3)
+
+#define WSS_PORT_CONFIG                0
+#define WSS_PORT_SIGNATURE     3
+
+#define WSS_SIGNATURE          4
+
+static int __devinit wss_detect(void __iomem *wss_port)
+{
+       if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+       iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG     1024
+#define CONFIG_PORT_SET                4
+
+#define DSP_COMMAND_GALAXY_8   8
+#define GALAXY_COMMAND_GET_TYPE        5
+
+#define DSP_COMMAND_GALAXY_9   9
+#define GALAXY_COMMAND_WSSMODE 0
+#define GALAXY_COMMAND_SB8MODE 1
+
+#define GALAXY_MODE_WSS                GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8                GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+       void __iomem *port;
+       void __iomem *config_port;
+       void __iomem *wss_port;
+       u32 config;
+       struct resource *res_port;
+       struct resource *res_config_port;
+       struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
+{
+       if (!enable[n])
+               return 0;
+
+       switch (port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_err(dev, "please specify port\n");
+               return 0;
+       case 0x220:
+               config[n] |= GALAXY_CONFIG_SBA_220;
+               break;
+       case 0x240:
+               config[n] |= GALAXY_CONFIG_SBA_240;
+               break;
+       case 0x260:
+               config[n] |= GALAXY_CONFIG_SBA_260;
+               break;
+       case 0x280:
+               config[n] |= GALAXY_CONFIG_SBA_280;
+               break;
+       default:
+               dev_err(dev, "invalid port %#lx\n", port[n]);
+               return 0;
+       }
+
+       switch (wss_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_err(dev,  "please specify wss_port\n");
+               return 0;
+       case 0x530:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+               break;
+       case 0x604:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+               break;
+       case 0xe80:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+               break;
+       case 0xf40:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+               break;
+       default:
+               dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+               return 0;
+       }
+
+       switch (irq[n]) {
+       case SNDRV_AUTO_IRQ:
+               dev_err(dev,  "please specify irq\n");
+               return 0;
+       case 7:
+               wss_config[n] |= WSS_CONFIG_IRQ_7;
+               break;
+       case 2:
+               irq[n] = 9;
+       case 9:
+               wss_config[n] |= WSS_CONFIG_IRQ_9;
+               break;
+       case 10:
+               wss_config[n] |= WSS_CONFIG_IRQ_10;
+               break;
+       case 11:
+               wss_config[n] |= WSS_CONFIG_IRQ_11;
+               break;
+       default:
+               dev_err(dev, "invalid IRQ %d\n", irq[n]);
+               return 0;
+       }
+
+       switch (dma1[n]) {
+       case SNDRV_AUTO_DMA:
+               dev_err(dev,  "please specify dma1\n");
+               return 0;
+       case 0:
+               wss_config[n] |= WSS_CONFIG_DMA_0;
+               break;
+       case 1:
+               wss_config[n] |= WSS_CONFIG_DMA_1;
+               break;
+       case 3:
+               wss_config[n] |= WSS_CONFIG_DMA_3;
+               break;
+       default:
+               dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+               return 0;
+       }
+
+       if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+               dma2[n] = -1;
+               goto mpu;
+       }
+
+       wss_config[n] |= WSS_CONFIG_DUPLEX;
+       switch (dma2[n]) {
+       case 0:
+               break;
+       case 1:
+               if (dma1[n] == 0)
+                       break;
+       default:
+               dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+               return 0;
+       }
+
+mpu:
+       switch (mpu_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+               mpu_port[n] = -1;
+               goto fm;
+       case 0x300:
+               config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+               break;
+       case 0x330:
+               config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+               break;
+       default:
+               dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+               return 0;
+       }
+
+       switch (mpu_irq[n]) {
+       case SNDRV_AUTO_IRQ:
+               dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+               mpu_irq[n] = -1;
+               break;
+       case 2:
+               mpu_irq[n] = 9;
+       case 9:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+               break;
+#ifdef AZT1605
+       case 3:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+               break;
+#endif
+       case 5:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+               break;
+       case 7:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+               break;
+#ifdef AZT2316
+       case 10:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+               break;
+#endif
+       default:
+               dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+               return 0;
+       }
+
+       if (mpu_irq[n] == irq[n]) {
+               dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+               return 0;
+       }
+
+fm:
+       switch (fm_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_warn(dev, "fm_port not specified: not using OPL3\n");
+               fm_port[n] = -1;
+               break;
+       case 0x388:
+               break;
+       default:
+               dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+               return 0;
+       }
+
+       config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+       return 1;
+}
+
+static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+       u8 major;
+       u8 minor;
+       int err;
+
+       err = dsp_reset(galaxy->port);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_version(galaxy->port, &major, &minor);
+       if (err < 0)
+               return err;
+
+       if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+               return -ENODEV;
+
+       err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+       if (err < 0)
+               return err;
+
+       err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(galaxy->port, type);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+       int err;
+
+       err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+       if (err < 0)
+               return err;
+
+       err = dsp_command(galaxy->port, mode);
+       if (err < 0)
+               return err;
+
+#ifdef AZT1605
+       /*
+        * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+        */
+       err = dsp_reset(galaxy->port);
+       if (err < 0)
+               return err;
+#endif
+
+       return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+       u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+       int i;
+
+       iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+       for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+               iowrite8(config, galaxy->config_port + i);
+               config >>= 8;
+       }
+       iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+       msleep(10);
+}
+
+static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+       int i;
+
+       for (i = GALAXY_CONFIG_SIZE; i; i--) {
+               u8 tmp = ioread8(galaxy->config_port + i - 1);
+               galaxy->config = (galaxy->config << 8) | tmp;
+       }
+       config |= galaxy->config & GALAXY_CONFIG_MASK;
+       galaxy_set_config(galaxy, config);
+}
+
+static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+       int err;
+
+       err = wss_detect(galaxy->wss_port);
+       if (err < 0)
+               return err;
+
+       wss_set_config(galaxy->wss_port, wss_config);
+
+       err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+       struct snd_galaxy *galaxy = card->private_data;
+
+       if (galaxy->wss_port) {
+               wss_set_config(galaxy->wss_port, 0);
+               ioport_unmap(galaxy->wss_port);
+               release_and_free_resource(galaxy->res_wss_port);
+       }
+       if (galaxy->config_port) {
+               galaxy_set_config(galaxy, galaxy->config);
+               ioport_unmap(galaxy->config_port);
+               release_and_free_resource(galaxy->res_config_port);
+       }
+       if (galaxy->port) {
+               ioport_unmap(galaxy->port);
+               release_and_free_resource(galaxy->res_port);
+       }
+}
+
+static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+       struct snd_galaxy *galaxy;
+       struct snd_wss *chip;
+       struct snd_card *card;
+       u8 type;
+       int err;
+
+       err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
+                             &card);
+       if (err < 0)
+               return err;
+
+       snd_card_set_dev(card, dev);
+
+       card->private_free = snd_galaxy_free;
+       galaxy = card->private_data;
+
+       galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+       if (!galaxy->res_port) {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+                       port[n] + 15);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->port = ioport_map(port[n], 16);
+
+       err = galaxy_init(galaxy, &type);
+       if (err < 0) {
+               dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+               goto error;
+       }
+       dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+       galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+                                                16, DRV_NAME);
+       if (!galaxy->res_config_port) {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n",
+                       port[n] + GALAXY_PORT_CONFIG,
+                       port[n] + GALAXY_PORT_CONFIG + 15);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+       galaxy_config(galaxy, config[n]);
+
+       galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+       if (!galaxy->res_wss_port)  {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+                       wss_port[n] + 3);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+       err = galaxy_wss_config(galaxy, wss_config[n]);
+       if (err < 0) {
+               dev_err(dev, "could not configure WSS\n");
+               goto error;
+       }
+
+       strcpy(card->driver, DRV_NAME);
+       strcpy(card->shortname, DRV_NAME);
+       sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+               card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+               dma2[n]);
+
+       err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+                            dma2[n], WSS_HW_DETECT, 0, &chip);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_pcm(chip, 0, NULL);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_mixer(chip);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_timer(chip, 0, NULL);
+       if (err < 0)
+               goto error;
+
+       if (mpu_port[n] >= 0) {
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                                         mpu_port[n], 0, mpu_irq[n],
+                                         IRQF_DISABLED, NULL);
+               if (err < 0)
+                       goto error;
+       }
+
+       if (fm_port[n] >= 0) {
+               struct snd_opl3 *opl3;
+
+               err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+                                     OPL3_HW_AUTO, 0, &opl3);
+               if (err < 0) {
+                       dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+                       goto error;
+               }
+               err = snd_opl3_timer_new(opl3, 1, 2);
+               if (err < 0)
+                       goto error;
+
+               err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+               if (err < 0)
+                       goto error;
+       }
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dev_set_drvdata(dev, card);
+       return 0;
+
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+       snd_card_free(dev_get_drvdata(dev));
+       dev_set_drvdata(dev, NULL);
+       return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+       .match          = snd_galaxy_match,
+       .probe          = snd_galaxy_probe,
+       .remove         = __devexit_p(snd_galaxy_remove),
+
+       .driver         = {
+               .name   = DEV_NAME
+       }
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+       return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+       isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);
index f26eac8d8110093aed72bfc51dce0340ca972ee9..3e4a58b72913d613e719a9ccc912d0bf75661a0d 100644 (file)
@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
 
 static void snd_gusmax_free(struct snd_card *card)
 {
-       struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+       struct snd_gusmax *maxcard = card->private_data;
        
        if (maxcard == NULL)
                return;
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
        if (err < 0)
                return err;
        card->private_free = snd_gusmax_free;
-       maxcard = (struct snd_gusmax *)card->private_data;
+       maxcard = card->private_data;
        maxcard->card = card;
        maxcard->irq = -1;
        
index 81284a8fa0ceb56db3fc246638a792fffadba88f..2259e3f726a7c257cf6b51ab728cebf8d9e83a2b 100644 (file)
@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
 
 static void snd_sb8_free(struct snd_card *card)
 {
-       struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+       struct snd_sb8 *acard = card->private_data;
 
        if (acard == NULL)
                return;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
deleted file mode 100644 (file)
index 6fe27b9..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- *  Driver for Aztech Sound Galaxy cards
- *  Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- *  I don't have documentation for this card, I based this driver on the
- *  driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/isa.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/wss.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX    "sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
-       int i;
-
-       outb(1, SBP1(port, RESET));
-       udelay(10);
-       outb(0, SBP1(port, RESET));
-       udelay(30);
-       for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
-       if (inb(SBP1(port, READ)) != 0xaa) {
-               snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
-                                              unsigned char val)
-{
-       int i;
-               
-       for (i = 10000; i; i--)
-               if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
-                       outb(val, SBP1(port, COMMAND));
-                       return 1;
-               }
-
-       return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
-{
-       return IRQ_NONE;
-}
-
-static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
-       static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 
-                                      0x10, 0x18, 0x20, -1, -1, -1, -1};
-       static int dma_bits[] = {1, 2, 0, 3};
-       int tmp, tmp1;
-
-       if ((tmp = inb(port + 3)) == 0xff)
-       {
-               snd_printdd("I/O address dead (0x%lx)\n", port);
-               return 0;
-       }
-#if 0
-       snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
-        if ((tmp & 0x3f) != 0x04 &&
-            (tmp & 0x3f) != 0x0f &&
-            (tmp & 0x3f) != 0x00) {
-               snd_printdd("No WSS signature detected on port 0x%lx\n",
-                           port + 3);
-               return 0;
-       }
-
-#if 0
-       snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
-        /* initialize IRQ for WSS codec */
-        tmp = interrupt_bits[irq % 16];
-        if (tmp < 0)
-                return -EINVAL;
-
-       if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
-               snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
-               return -EIO;
-       }
-
-        outb(tmp | 0x40, port);
-        tmp1 = dma_bits[dma % 4];
-        outb(tmp | tmp1, port);
-
-       free_irq(irq, NULL);
-
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
-       snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
-       /* switch to WSS mode */
-       snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
-       snd_sgalaxy_sbdsp_command(sbport[dev], 9);
-       snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
-       udelay(400);
-       return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
-WSS_DOUBLE("Aux Playback Switch", 0,
-               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
-               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
-{
-       struct snd_card *card = chip->card;
-       struct snd_ctl_elem_id id1, id2;
-       unsigned int idx;
-       int err;
-
-       memset(&id1, 0, sizeof(id1));
-       memset(&id2, 0, sizeof(id2));
-       id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       /* reassign AUX0 to LINE */
-       strcpy(id1.name, "Aux Playback Switch");
-       strcpy(id2.name, "Line Playback Switch");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       strcpy(id1.name, "Aux Playback Volume");
-       strcpy(id2.name, "Line Playback Volume");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       /* reassign AUX1 to FM */
-       strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
-       strcpy(id2.name, "FM Playback Switch");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       strcpy(id1.name, "Aux Playback Volume");
-       strcpy(id2.name, "FM Playback Volume");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       /* build AUX2 input */
-       for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
-               err = snd_ctl_add(card,
-                               snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
-{
-       if (!enable[dev])
-               return 0;
-       if (sbport[dev] == SNDRV_AUTO_PORT) {
-               snd_printk(KERN_ERR PFX "specify SB port\n");
-               return 0;
-       }
-       if (wssport[dev] == SNDRV_AUTO_PORT) {
-               snd_printk(KERN_ERR PFX "specify WSS port\n");
-               return 0;
-       }
-       return 1;
-}
-
-static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
-{
-       static int possible_irqs[] = {7, 9, 10, 11, -1};
-       static int possible_dmas[] = {1, 3, 0, -1};
-       int err, xirq, xdma1;
-       struct snd_card *card;
-       struct snd_wss *chip;
-
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
-       if (err < 0)
-               return err;
-
-       xirq = irq[dev];
-       if (xirq == SNDRV_AUTO_IRQ) {
-               if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
-                       snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
-                       err = -EBUSY;
-                       goto _err;
-               }
-       }
-       xdma1 = dma1[dev];
-        if (xdma1 == SNDRV_AUTO_DMA) {
-               if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
-                       snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
-                       err = -EBUSY;
-                       goto _err;
-               }
-       }
-
-       if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
-               goto _err;
-
-       err = snd_wss_create(card, wssport[dev] + 4, -1,
-                            xirq, xdma1, -1,
-                            WSS_HW_DETECT, 0, &chip);
-       if (err < 0)
-               goto _err;
-       card->private_data = chip;
-
-       err = snd_wss_pcm(chip, 0, NULL);
-       if (err < 0) {
-               snd_printdd(PFX "error creating new WSS PCM device\n");
-               goto _err;
-       }
-       err = snd_wss_mixer(chip);
-       if (err < 0) {
-               snd_printdd(PFX "error creating new WSS mixer\n");
-               goto _err;
-       }
-       if ((err = snd_sgalaxy_mixer(chip)) < 0) {
-               snd_printdd(PFX "the mixer rewrite failed\n");
-               goto _err;
-       }
-
-       strcpy(card->driver, "Sound Galaxy");
-       strcpy(card->shortname, "Sound Galaxy");
-       sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
-               wssport[dev], xirq, xdma1);
-
-       snd_card_set_dev(card, devptr);
-
-       if ((err = snd_card_register(card)) < 0)
-               goto _err;
-
-       dev_set_drvdata(devptr, card);
-       return 0;
-
- _err:
-       snd_card_free(card);
-       return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
-{
-       snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
-                              pm_message_t state)
-{
-       struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_wss *chip = card->private_data;
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       chip->suspend(chip);
-       return 0;
-}
-
-static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
-{
-       struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_wss *chip = card->private_data;
-
-       chip->resume(chip);
-       snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
-       snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-       return 0;
-}
-#endif
-
-#define DEV_NAME "sgalaxy"
-
-static struct isa_driver snd_sgalaxy_driver = {
-       .match          = snd_sgalaxy_match,
-       .probe          = snd_sgalaxy_probe,
-       .remove         = __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
-       .suspend        = snd_sgalaxy_suspend,
-       .resume         = snd_sgalaxy_resume,
-#endif
-       .driver         = {
-               .name   = DEV_NAME
-       },
-};
-
-static int __init alsa_card_sgalaxy_init(void)
-{
-       return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
-       isa_unregister_driver(&snd_sgalaxy_driver);
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)
index a513651fa149897061406c166904277ea5f67131..76c09021807325944e3edb8b57bc2525e14b306c 100644 (file)
@@ -545,11 +545,3 @@ config SOUND_KAHLUA
 
 endif  # SOUND_OSS
 
-config SOUND_SH_DAC_AUDIO
-       tristate "SuperH DAC audio support"
-       depends on CPU_SH3 && HIGH_RES_TIMERS
-
-config SOUND_SH_DAC_AUDIO_CHANNEL
-       int "DAC channel"
-       default "1"
-       depends on SOUND_SH_DAC_AUDIO
index 567b8a74178a36bfca43a3f7b1a408a60bfec922..96f14dcd0cd19e73bcf09f1f11321e88fb5829b3 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS)         += sound.o
 
 # Please leave it as is, cause the link order is significant !
 
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
 obj-$(CONFIG_SOUND_AEDSP16)    += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
index c6f2621221baeebb428652df9dd51abfb5628b5b..a8f626d99c5b9245e4a0eaf3bf074718caf1889d 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -77,6 +76,7 @@
 /* Boot options
  * 0 = no VRA, 1 = use VRA if codec supports it
  */
+static DEFINE_MUTEX(au1550_ac97_mutex);
 static int      vra = 1;
 module_param(vra, bool, 0);
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
@@ -171,7 +171,7 @@ au1550_delay(int msec)
 static u16
 rdcodec(struct ac97_codec *codec, u8 addr)
 {
-       struct au1550_state *s = (struct au1550_state *)codec->private_data;
+       struct au1550_state *s = codec->private_data;
        unsigned long   flags;
        u32             cmd, val;
        u16             data;
@@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
 static void
 wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
 {
-       struct au1550_state *s = (struct au1550_state *)codec->private_data;
+       struct au1550_state *s = codec->private_data;
        unsigned long   flags;
        u32             cmd, val;
        int             i;
@@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
 static int
 au1550_open_mixdev(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        file->private_data = &au1550_state;
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return 0;
 }
 
@@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
 static long
 au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct ac97_codec *codec = s->codec;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        ret = mixdev_ioctl(codec, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
 
        return ret;
 }
@@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
 static ssize_t
 au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db = &s->dma_adc;
        DECLARE_WAITQUEUE(wait, current);
        ssize_t         ret;
@@ -1111,7 +1111,7 @@ out2:
 static ssize_t
 au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db = &s->dma_dac;
        DECLARE_WAITQUEUE(wait, current);
        ssize_t         ret = 0;
@@ -1211,7 +1211,7 @@ out2:
 static unsigned int
 au1550_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        unsigned long   flags;
        unsigned int    mask = 0;
 
@@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
 static int
 au1550_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db;
        unsigned long   size;
        int ret = 0;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        mutex_lock(&s->sem);
        if (vma->vm_flags & VM_WRITE)
                db = &s->dma_dac;
@@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
        db->mapped = 1;
 out:
        mutex_unlock(&s->sem);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return ret;
 }
 
@@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
 static int
 au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        unsigned long   flags;
        audio_buf_info  abinfo;
        count_info      cinfo;
@@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        ret = au1550_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
 
        return ret;
 }
@@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
 #endif
 
        file->private_data = s;
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        /* wait for device to become free */
        mutex_lock(&s->open_mutex);
        while (s->open_mode & file->f_mode) {
@@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
 out:
        mutex_unlock(&s->open_mutex);
 out2:
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return ret;
 }
 
 static int
 au1550_release(struct inode *inode, struct file *file)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
 
        if (file->f_mode & FMODE_WRITE) {
-               unlock_kernel();
+               mutex_unlock(&au1550_ac97_mutex);
                drain_dac(s, file->f_flags & O_NONBLOCK);
-               lock_kernel();
+               mutex_lock(&au1550_ac97_mutex);
        }
 
        mutex_lock(&s->open_mutex);
@@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
        s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
        mutex_unlock(&s->open_mutex);
        wake_up(&s->open_wait);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return 0;
 }
 
index 6ecd41abb0667fbdfc580c51fb134fcae9fa46f8..87e2c72651f5fa1555f708c743465ee5843134a4 100644 (file)
 #include <linux/init.h>
 #include <linux/soundcard.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
      *  Declarations
      */
 
+static DEFINE_MUTEX(dmasound_core_mutex);
 int dmasound_catchRadius = 0;
 module_param(dmasound_catchRadius, int, 0);
 
@@ -323,22 +324,22 @@ static struct {
 
 static int mixer_open(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        if (!try_module_get(dmasound.mach.owner)) {
-               unlock_kernel();
+               mutex_unlock(&dmasound_core_mutex);
                return -ENODEV;
        }
        mixer.busy = 1;
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
 static int mixer_release(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        mixer.busy = 0;
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
@@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = mixer_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return ret;
 }
@@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
 {
        int rc;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        if (!try_module_get(dmasound.mach.owner)) {
-               unlock_kernel();
+               mutex_unlock(&dmasound_core_mutex);
                return -ENODEV;
        }
 
@@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
                sound_set_format(AFMT_MU_LAW);
        }
 #endif
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
  out:
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return rc;
 }
 
@@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
 {
        int rc = 0;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
 
        if (file->f_mode & FMODE_WRITE) {
                if (write_sq.busy)
@@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
        write_sq_wake_up(file); /* checks f_mode */
 #endif /* blocking open() */
 
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return rc;
 }
@@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = sq_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return ret;
 }
@@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
        int len = 0;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = -EBUSY;
        if (state.busy)
                goto out;
@@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
        state.len = len;
        ret = 0;
 out:
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return ret;
 }
 
 static int state_release(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        state.busy = 0;
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
index ca942f7cd2313c38c95d091f20c78658b36b36b7..7b5c77b32a90b9a5d4c967dcb58f2cb8e335fd24 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/gfp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -79,6 +79,7 @@
                                         dev.rec_sample_rate /          \
                                         dev.rec_channels)
 
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
 static multisound_dev_t                        dev;
 
 #ifndef HAVE_DSPCODEH
@@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        ret = -EINVAL;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                ret = dsp_ioctl(file, cmd, arg);
        else if (minor == dev.mixer_minor)
                ret = mixer_ioctl(cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
 
        return ret;
 }
@@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
        int minor = iminor(inode);
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor) {
                if ((file->f_mode & FMODE_WRITE &&
                     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
@@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
        } else
                err = -EINVAL;
 out:
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
 }
 
@@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
        int minor = iminor(inode);
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                err = dsp_release(file);
        else if (minor == dev.mixer_minor) {
                /* nothing */
        } else
                err = -EINVAL;
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
 }
 
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
deleted file mode 100644 (file)
index 479e302..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- *  Copyright (C) 2004,2005  Andriy Skulysh
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/smp_lock.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <cpu/dac.h>
-#include <asm/machvec.h>
-#include <mach/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-static struct hrtimer hrtimer;
-static ktime_t wakeups_per_second;
-
-static void dac_audio_start_timer(void)
-{
-       hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-}
-
-static void dac_audio_stop_timer(void)
-{
-       hrtimer_cancel(&hrtimer);
-}
-
-static void dac_audio_reset(void)
-{
-       dac_audio_stop_timer();
-       buffer_begin = buffer_end = data_buffer;
-       empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
-       while (!empty)
-               schedule();
-}
-
-static void dac_audio_start(void)
-{
-       if (mach_is_hp6xx()) {
-               u16 v = __raw_readw(HD64461_GPADR);
-               v &= ~HD64461_GPADR_SPEAKER;
-               __raw_writew(v, HD64461_GPADR);
-       }
-
-       sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-static void dac_audio_stop(void)
-{
-       dac_audio_stop_timer();
-
-       if (mach_is_hp6xx()) {
-               u16 v = __raw_readw(HD64461_GPADR);
-               v |= HD64461_GPADR_SPEAKER;
-               __raw_writew(v, HD64461_GPADR);
-       }
-
-       sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-       sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
-       wakeups_per_second = ktime_set(0, 1000000000 / rate);
-}
-
-static int dac_audio_ioctl(struct file *file,
-                          unsigned int cmd, unsigned long arg)
-{
-       int val;
-
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, (int *)arg);
-
-       case SNDCTL_DSP_SYNC:
-               dac_audio_sync();
-               return 0;
-
-       case SNDCTL_DSP_RESET:
-               dac_audio_reset();
-               return 0;
-
-       case SNDCTL_DSP_GETFMTS:
-               return put_user(AFMT_U8, (int *)arg);
-
-       case SNDCTL_DSP_SETFMT:
-               return put_user(AFMT_U8, (int *)arg);
-
-       case SNDCTL_DSP_NONBLOCK:
-               spin_lock(&file->f_lock);
-               file->f_flags |= O_NONBLOCK;
-               spin_unlock(&file->f_lock);
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-               return 0;
-
-       case SOUND_PCM_WRITE_RATE:
-               val = *(int *)arg;
-               if (val > 0) {
-                       rate = val;
-                       dac_audio_set_rate();
-               }
-               return put_user(rate, (int *)arg);
-
-       case SNDCTL_DSP_STEREO:
-               return put_user(0, (int *)arg);
-
-       case SOUND_PCM_WRITE_CHANNELS:
-               return put_user(1, (int *)arg);
-
-       case SNDCTL_DSP_SETDUPLEX:
-               return -EINVAL;
-
-       case SNDCTL_DSP_PROFILE:
-               return -EINVAL;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               return put_user(BUFFER_SIZE, (int *)arg);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               return 0;
-
-       default:
-               printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
-                      cmd);
-               return -EINVAL;
-       }
-       return -EINVAL;
-}
-
-static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
-{
-       int ret;
-
-       lock_kernel();
-       ret = dac_audio_ioctl(file, cmd, arg);
-       unlock_kernel();
-
-       return ret;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
-                              loff_t * ppos)
-{
-       int free;
-       int nbytes;
-
-       if (!count) {
-               dac_audio_sync();
-               return 0;
-       }
-
-       free = buffer_begin - buffer_end;
-
-       if (free < 0)
-               free += BUFFER_SIZE;
-       if ((free == 0) && (empty))
-               free = BUFFER_SIZE;
-       if (count > free)
-               count = free;
-       if (buffer_begin > buffer_end) {
-               if (copy_from_user((void *)buffer_end, buf, count))
-                       return -EFAULT;
-
-               buffer_end += count;
-       } else {
-               nbytes = data_buffer + BUFFER_SIZE - buffer_end;
-               if (nbytes > count) {
-                       if (copy_from_user((void *)buffer_end, buf, count))
-                               return -EFAULT;
-                       buffer_end += count;
-               } else {
-                       if (copy_from_user((void *)buffer_end, buf, nbytes))
-                               return -EFAULT;
-                       if (copy_from_user
-                           ((void *)data_buffer, buf + nbytes, count - nbytes))
-                               return -EFAULT;
-                       buffer_end = data_buffer + count - nbytes;
-               }
-       }
-
-       if (empty) {
-               empty = 0;
-               dac_audio_start_timer();
-       }
-
-       return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
-                             loff_t * ppos)
-{
-       return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
-       if (file->f_mode & FMODE_READ)
-               return -ENODEV;
-
-       lock_kernel();
-       if (in_use) {
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       in_use = 1;
-
-       dac_audio_start();
-       unlock_kernel();
-       return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
-       dac_audio_sync();
-       dac_audio_stop();
-       in_use = 0;
-
-       return 0;
-}
-
-const struct file_operations dac_audio_fops = {
-      .read =          dac_audio_read,
-      .write =         dac_audio_write,
-      .unlocked_ioctl =        dac_audio_unlocked_ioctl,
-      .open =          dac_audio_open,
-      .release =       dac_audio_release,
-};
-
-static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
-{
-       if (!empty) {
-               sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-               buffer_begin++;
-
-               if (buffer_begin == data_buffer + BUFFER_SIZE)
-                       buffer_begin = data_buffer;
-               if (buffer_begin == buffer_end)
-                       empty = 1;
-       }
-
-       if (!empty)
-               hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-
-       return HRTIMER_NORESTART;
-}
-
-static int __init dac_audio_init(void)
-{
-       if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
-               printk(KERN_ERR "Cannot register dsp device");
-               return device_major;
-       }
-
-       in_use = 0;
-
-       data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-       if (data_buffer == NULL)
-               return -ENOMEM;
-
-       dac_audio_reset();
-       rate = 8000;
-       dac_audio_set_rate();
-
-       /* Today: High Resolution Timer driven DAC playback.
-        * The timer callback gets called once per sample. Ouch.
-        *
-        * Future: A much better approach would be to use the
-        * SH7720 CMT+DMAC+DAC hardware combination like this:
-        * - Program sample rate using CMT0 or CMT1
-        * - Program DMAC to use CMT for timing and output to DAC
-        * - Play sound using DMAC, let CPU sleep.
-        * - While at it, rewrite this driver to use ALSA.
-        */
-
-       hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hrtimer.function = sh_dac_audio_timer;
-
-       return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
-       unregister_sound_dsp(device_major);
-       kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");
index 07f803e6d203a41615db0923cf073f7eadc283b6..46c0d03dbecced68ca318dbbe20df52d1da4ab0b 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/device.h>
@@ -56,6 +56,7 @@
  * Table for permanently allocated memory (used when unloading the module)
  */
 void *          sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
 int             sound_nblocks = 0;
 
 /* Persistent DMA buffers */
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
         *      big one anyway, we might as well bandage here..
         */
         
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        
        DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
        case SND_DEV_MIDIN:
                ret = MIDIbuf_read(dev, file, buf, count);
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
        int dev = iminor(file->f_path.dentry->d_inode);
        int ret = -EINVAL;
        
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
        case SND_DEV_SEQ:
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
                ret =  MIDIbuf_write(dev, file, buf, count);
                break;
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
                printk(KERN_ERR "Invalid minor device %d\n", dev);
                return -ENXIO;
        }
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
                dev >>= 4;
@@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
                retval = -ENXIO;
        }
 
-       unlock_kernel();
-       return 0;
+       mutex_unlock(&soundcard_mutex);
+       return retval;
 }
 
 static int sound_release(struct inode *inode, struct file *file)
 {
        int dev = iminor(inode);
 
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        DEB(printk("sound_release(dev=%d)\n", dev));
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
@@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
        default:
                printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
 
        return 0;
 }
@@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        if (cmd == OSS_GETVERSION)
                return __put_user(SOUND_VERSION, (int __user *)p);
        
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 &&   /* Mixer ioctl */
            (dev & 0x0f) != SND_DEV_CTL) {              
                dtype = dev & 0x0f;
@@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        ret = sound_mixer_ioctl(dev >> 4, cmd, p);
                        break;
                }
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return ret;
        }
 
@@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
                printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
                return -EINVAL;
        }
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        if (vma->vm_flags & VM_WRITE)   /* Map write and read/write to the output buf */
                dmap = audio_devs[dev]->dmap_out;
        else if (vma->vm_flags & VM_READ)
                dmap = audio_devs[dev]->dmap_in;
        else {
                printk(KERN_ERR "Sound: Undefined mmap() access\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EINVAL;
        }
 
        if (dmap == NULL) {
                printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (dmap->raw_buf == NULL) {
                printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (dmap->mapping_flags) {
                printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (vma->vm_pgoff != 0) {
                printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EINVAL;
        }
        size = vma->vm_end - vma->vm_start;
@@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
        if (remap_pfn_range(vma, vma->vm_start,
                        virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
                        vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EAGAIN;
        }
 
@@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
        memset(dmap->raw_buf,
               dmap->neutral_byte,
               dmap->bytes_in_use);
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return 0;
 }
 
index b15840ad2527820bc78f9d00c4fe5d20a011b785..44357d877a275a384ff54fea2e1322eaf7ff37a0 100644 (file)
@@ -68,7 +68,6 @@
 #include <linux/delay.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/soundcard.h>
 #include <linux/ac97_codec.h>
 #include <linux/pci.h>
@@ -94,6 +93,7 @@
 
 struct cs4297a_state;
 
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
 static void stop_dac(struct cs4297a_state *s);
 static void stop_adc(struct cs4297a_state *s);
 static void start_dac(struct cs4297a_state *s);
@@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
        CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
                  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        list_for_each(entry, &cs4297a_devs)
        {
                s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
                CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
                        printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
 
-               unlock_kernel();
+               mutex_unlock(&swarm_cs4297a_mutex);
                return -ENODEV;
        }
        VALIDATE_STATE(s);
@@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 
        CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
                  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return nonseekable_open(inode, file);
 }
@@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
                               unsigned int cmd, unsigned long arg)
 {
        int ret;
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
                           arg);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
        return ret;
 }
 
@@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = cs4297a_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return ret;
 }
@@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = cs4297a_open(inode, file);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return ret;
 }
index 8cd73cdd88afeedbaf90e1bdbab62eb56fc0949e..643f1113b1d8844c4e2850eff613b152aafcb737 100644 (file)
 #include <linux/init.h>
 
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
 #ifdef VWSND_DEBUG
 
+static DEFINE_MUTEX(vwsnd_mutex);
 static int shut_up = 1;
 
 /*
@@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
        vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->io_mutex);
        ret = vwsnd_audio_do_ioctl(file, cmd, arg);
        mutex_unlock(&devc->io_mutex);
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
 
        return ret;
 }
@@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        INC_USE_COUNT;
        for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
                if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        if (devc == NULL) {
                DEC_USE_COUNT;
-               unlock_kernel();
+               mutex_unlock(&vwsnd_mutex);
                return -ENODEV;
        }
 
@@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
                mutex_unlock(&devc->open_mutex);
                if (file->f_flags & O_NONBLOCK) {
                        DEC_USE_COUNT;
-                       unlock_kernel();
+                       mutex_unlock(&vwsnd_mutex);
                        return -EBUSY;
                }
                interruptible_sleep_on(&devc->open_wait);
                if (signal_pending(current)) {
                        DEC_USE_COUNT;
-                       unlock_kernel();
+                       mutex_unlock(&vwsnd_mutex);
                        return -ERESTARTSYS;
                }
                mutex_lock(&devc->open_mutex);
@@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        file->private_data = devc;
        DBGRV();
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return 0;
 }
 
@@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
        vwsnd_port_t *wport = NULL, *rport = NULL;
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->io_mutex);
        {
                DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
        wake_up(&devc->open_wait);
        DEC_USE_COUNT;
        DBGR();
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return err;
 }
 
@@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
        DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 
        INC_USE_COUNT;
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
                if (devc->mixer_minor == iminor(inode))
                        break;
 
        if (devc == NULL) {
                DEC_USE_COUNT;
-               unlock_kernel();
+               mutex_unlock(&vwsnd_mutex);
                return -ENODEV;
        }
        file->private_data = devc;
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return 0;
 }
 
@@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
 
        DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->mix_mutex);
        {
                if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
                        retval = -EINVAL;
        }
        mutex_unlock(&devc->mix_mutex);
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return retval;
 }
 
index e7a8cd058efb59190851730ee352eca5926d0df7..12e34653b8a842ec5dd04778850438bec4b67aa7 100644 (file)
@@ -207,12 +207,12 @@ config SND_CMIPCI
 
 config SND_OXYGEN_LIB
         tristate
-       select SND_PCM
-       select SND_MPU401_UART
 
 config SND_OXYGEN
        tristate "C-Media 8788 (Oxygen)"
        select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
        help
          Say Y here to include support for sound cards based on the
          C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@ config SND_HDSPM
 config SND_HIFIER
        tristate "TempoTec HiFier Fantasia"
        select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
        help
          Say Y here to include support for the MediaTek/TempoTec HiFier
          Fantasia sound card.
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
          will be called snd-via82xx-modem.
 
 config SND_VIRTUOSO
-       tristate "Asus Virtuoso 100/200 (Xonar)"
+       tristate "Asus Virtuoso 66/100/200 (Xonar)"
        select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
+       select SND_JACK if INPUT=y || INPUT=SND
        help
          Say Y here to include support for sound cards based on the
-         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+         Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
          Essence ST (Deluxe), and Essence STX.
-         Support for the DS is experimental.
-         Support for the HDAV1.3 (Deluxe) is very experimental.
+         Support for the HDAV1.3 (Deluxe) is incomplete; for the
+         HDAV1.3 Slim and Xense, missing.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-virtuoso.
index c92f493d341e266c36b870f116aaf6adb9ef48a7..557c782ae4fc8caca953c1ec85111b0179066b48 100644 (file)
@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
        if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
                return err;
        memset(&ac97, 0, sizeof(ac97));
-       // Intialize AC97 codec stuff.
+       // Initialize AC97 codec stuff.
        ac97.private_data = vortex;
        ac97.scaps = AC97_SCAP_NO_SPDIF;
        err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
index 14b8d9a91aae27655439e487aed6aed853b9e426..f19c11077255ddfe5f7d30dbb2543740717c6b43 100644 (file)
@@ -670,8 +670,9 @@ struct snd_ca0106_details {
                           gpio_type = 2 -> shared side-out/line-in. */
        int i2c_adc;    /* with i2c_adc=1, the driver adds some capture volume
                           controls, phone, mic, line-in and aux. */
-       int spi_dac;    /* spi_dac=1 adds the mute switch for each analog
-                          output, front, rear, etc. */
+       u16 spi_dac;    /* spi_dac = 0 -> no spi interface for DACs
+                          spi_dac = 0x<front><rear><center-lfe><side>
+                          -> specifies DAC id for each channel pair. */
 };
 
 // definition of the chip-specific record
index 0a3d3d6e77b4d668bad27a929cda8fa174d1cd1c..d2d12c08f93759bb069f580ece58e1043c00e2af 100644 (file)
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "Audigy SE [SB0570]",
           .gpio_type = 1,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
         /* New Audigy LS. Has a different DAC. */
         /* SB0570:
          * CTRL:CA0106-DAT
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "Audigy SE OEM [SB0570a]",
           .gpio_type = 1,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
+       /* Sound Blaster 5.1vx
+        * Tested: Playback on front, rear, center/lfe speakers
+        * Not-Tested: Capture
+        */
+       { .serial = 0x10041102,
+         .name   = "Sound Blaster 5.1vx [SB1070]",
+         .gpio_type = 1,
+         .i2c_adc = 0,
+         .spi_dac = 0x0124
+        } ,
         /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
         /* SB0438
          * CTRL:CA0106-DAT
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB",
           .gpio_type = 2,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
        /* Giga-byte GA-G1975X mobo
         * Novell bnc#395807
         */
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
 }
 
 static const int spi_dacd_reg[] = {
-       [PCM_FRONT_CHANNEL]     = SPI_DACD4_REG,
-       [PCM_REAR_CHANNEL]      = SPI_DACD0_REG,
-       [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
-       [PCM_UNKNOWN_CHANNEL]   = SPI_DACD1_REG,
+       SPI_DACD0_REG,
+       SPI_DACD1_REG,
+       SPI_DACD2_REG,
+       0,
+       SPI_DACD4_REG,
 };
 static const int spi_dacd_bit[] = {
-       [PCM_FRONT_CHANNEL]     = SPI_DACD4_BIT,
-       [PCM_REAR_CHANNEL]      = SPI_DACD0_BIT,
-       [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
-       [PCM_UNKNOWN_CHANNEL]   = SPI_DACD1_BIT,
+       SPI_DACD0_BIT,
+       SPI_DACD1_BIT,
+       SPI_DACD2_BIT,
+       0,
+       SPI_DACD4_BIT,
 };
 
 static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
        }
 }
 
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+                                 int channel_id)
+{
+       switch (channel_id) {
+       case PCM_FRONT_CHANNEL:
+               return (details->spi_dac & 0xf000) >> (4 * 3);
+       case PCM_REAR_CHANNEL:
+               return (details->spi_dac & 0x0f00) >> (4 * 2);
+       case PCM_CENTER_LFE_CHANNEL:
+               return (details->spi_dac & 0x00f0) >> (4 * 1);
+       case PCM_UNKNOWN_CHANNEL:
+               return (details->spi_dac & 0x000f) >> (4 * 0);
+       default:
+               snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+                          channel_id);
+       }
+       return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+                                   int power)
+{
+       if (chip->details->spi_dac) {
+               const int dac = snd_ca0106_channel_dac(chip->details,
+                                                      channel_id);
+               const int reg = spi_dacd_reg[dac];
+               const int bit = spi_dacd_bit[dac];
+
+               if (power)
+                       /* Power up */
+                       chip->spi_dac_reg[reg] &= ~bit;
+               else
+                       /* Power down */
+                       chip->spi_dac_reg[reg] |= bit;
+               return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       }
+       return 0;
+}
+
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
                                                int channel_id)
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
                 return err;
        snd_pcm_set_sync(substream);
 
-       if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[channel_id];
-
-               /* Power up dac */
-               chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
-               err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should already be on */
+       if (channel_id != PCM_FRONT_CHANNEL) {
+               err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
                if (err < 0)
                        return err;
        }
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
 
        restore_spdif_bits(chip, epcm->channel_id);
 
-       if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[epcm->channel_id];
-
-               /* Power down DAC */
-               chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
-               snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should stay on */
+       if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+               int err;
+               err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+               if (err < 0)
+                       return err;
        }
+
        /* FIXME: maybe zero others */
        return 0;
 }
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
        struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_ca0106_pcm *epcm = runtime->private_data;
-       snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+       unsigned int ptr, prev_ptr;
        int channel = epcm->channel_id;
+       int timeout = 10;
 
        if (!epcm->running)
                return 0;
 
-       ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr2 = bytes_to_frames(runtime, ptr1);
-       ptr2+= (ptr4 >> 3) * runtime->period_size;
-       ptr=ptr2;
-        if (ptr >= runtime->buffer_size)
-               ptr -= runtime->buffer_size;
-       /*
-       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
-              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
-              ptr1, ptr2, ptr, (int)runtime->buffer_size,
-              (int)runtime->period_size, (int)runtime->frame_bits,
-              (int)runtime->rate);
-       */
-       return ptr;
+       prev_ptr = -1;
+       do {
+               ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+               ptr = (ptr >> 3) * runtime->period_size;
+               ptr += bytes_to_frames(runtime,
+                       snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+               if (ptr >= runtime->buffer_size)
+                       ptr -= runtime->buffer_size;
+               if (prev_ptr == ptr)
+                       return ptr;
+               prev_ptr = ptr;
+       } while (--timeout);
+       snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+       return 0;
 }
 
 /* pointer_capture callback */
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
        SPI_REG(12,             0x00),
        SPI_REG(SPI_LDA4_REG,   SPI_DA_BIT_0dB),
        SPI_REG(SPI_RDA4_REG,   SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
-       SPI_REG(SPI_DACD4_REG,  0x00),
+       SPI_REG(SPI_DACD4_REG,  SPI_DACD4_BIT),
 };
 
 static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
        }
 
-       if (chip->details->spi_dac == 1) {
+       if (chip->details->spi_dac) {
                /* The SB0570 use SPI to control DAC. */
                int size, n;
 
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                        if (reg < ARRAY_SIZE(chip->spi_dac_reg))
                                chip->spi_dac_reg[reg] = spi_dac_init[n];
                }
+
+               /* Enable front dac only */
+               snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
        }
 }
 
index 85fd315d99990d6cba86001840d5cd7389975e2a..630aa499818947f79f0bd7aba8f750c3a4942de9 100644 (file)
@@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
         I2C_VOLUME("Aux Capture Volume", 3),
 };
 
-#define SPI_SWITCH(xname,reg,bit) \
-{                                                              \
-       .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,    \
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,              \
-       .info   = spi_mute_info,                                \
-       .get    = spi_mute_get,                                 \
-       .put    = spi_mute_put,                                 \
-       .private_value = (reg<<SPI_REG_SHIFT) | (bit)           \
-}
-
-static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
-__devinitdata = {
-       SPI_SWITCH("Analog Front Playback Switch",
-                  SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
-       SPI_SWITCH("Analog Rear Playback Switch",
-                  SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
-       SPI_SWITCH("Analog Center/LFE Playback Switch",
-                  SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
-       SPI_SWITCH("Analog Side Playback Switch",
-                  SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+static const int spi_dmute_reg[] = {
+       SPI_DMUTE0_REG,
+       SPI_DMUTE1_REG,
+       SPI_DMUTE2_REG,
+       0,
+       SPI_DMUTE4_REG,
+};
+static const int spi_dmute_bit[] = {
+       SPI_DMUTE0_BIT,
+       SPI_DMUTE1_BIT,
+       SPI_DMUTE2_BIT,
+       0,
+       SPI_DMUTE4_BIT,
 };
 
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+                             int channel_id)
+{
+       struct snd_kcontrol_new spi_switch = {0};
+       int reg, bit;
+       int dac_id;
+
+       spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+       spi_switch.info = spi_mute_info;
+       spi_switch.get = spi_mute_get;
+       spi_switch.put = spi_mute_put;
+
+       switch (channel_id) {
+       case PCM_FRONT_CHANNEL:
+               spi_switch.name = "Analog Front Playback Switch";
+               dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+               break;
+       case PCM_REAR_CHANNEL:
+               spi_switch.name = "Analog Rear Playback Switch";
+               dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+               break;
+       case PCM_CENTER_LFE_CHANNEL:
+               spi_switch.name = "Analog Center/LFE Playback Switch";
+               dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+               break;
+       case PCM_UNKNOWN_CHANNEL:
+               spi_switch.name = "Analog Side Playback Switch";
+               dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+               break;
+       default:
+               /* Unused channel */
+               spi_switch.name = NULL;
+               dac_id = 0;
+       }
+       reg = spi_dmute_reg[dac_id];
+       bit = spi_dmute_bit[dac_id];
+
+       spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+       return spi_switch;
+}
+
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 {
        struct snd_ctl_elem_id id;
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                if (err < 0)
                        return err;
        }
-       if (emu->details->spi_dac == 1)
-               ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+       if (emu->details->spi_dac) {
+               int i;
+               for (i = 0;; i++) {
+                       struct snd_kcontrol_new ctl;
+                       ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+                       if (!ctl.name)
+                               break;
+                       err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+                       if (err < 0)
+                               return err;
+               }
+       }
 
        /* Create virtual master controls */
        vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                return err;
        add_slaves(card, vmaster, slave_vols);
 
-       if (emu->details->spi_dac == 1) {
+       if (emu->details->spi_dac) {
                vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
                                                      NULL);
                if (!vmaster)
index 8578c70c61f2b4ee15a7583c47641bd2405d4e78..bab564824efe11ebdf1160e81b568254c3a7fd1c 100644 (file)
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
 
 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 {
-       struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+       struct snd_emu10k1_midi *midi = rmidi->private_data;
        midi->interrupt = NULL;
        midi->rmidi = NULL;
 }
index 9194c3c1d04adf176a01ff91f3a8990327aab6fc..0ea5cc60ac782f1cd9d05161455b1e1a79d4cd85 100644 (file)
@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
          snd-hda-codec-via.
          This module is automatically loaded at probing.
 
-config SND_HDA_CODEC_ATIHDMI
-       bool "Build ATI HDMI HD-audio codec support"
-       default y
-       help
-         Say Y here to include ATI HDMI HD-audio codec support in
-         snd-hda-intel driver, such as ATI RS600 HDMI.
-
-         When the HD-audio driver is built as a module, the codec
-         support code is also built as another module,
-         snd-hda-codec-atihdmi.
-         This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_NVHDMI
-       bool "Build NVIDIA HDMI HD-audio codec support"
-       default y
-       help
-         Say Y here to include NVIDIA HDMI HD-audio codec support in
-         snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-         When the HD-audio driver is built as a module, the codec
-         support code is also built as another module,
-         snd-hda-codec-nvhdmi.
-         This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_INTELHDMI
-       bool "Build INTEL HDMI HD-audio codec support"
+config SND_HDA_CODEC_HDMI
+       bool "Build HDMI/DisplayPort HD-audio codec support"
        select SND_DYNAMIC_MINORS
        default y
        help
-         Say Y here to include INTEL HDMI HD-audio codec support in
-         snd-hda-intel driver, such as Eaglelake integrated HDMI.
+         Say Y here to include HDMI and DisplayPort HD-audio codec
+         support in snd-hda-intel driver.  This includes all AMD/ATI,
+         Intel and Nvidia HDMI/DisplayPort codecs.
 
          When the HD-audio driver is built as a module, the codec
          support code is also built as another module,
-         snd-hda-codec-intelhdmi.
+         snd-hda-codec-hdmi.
          This module is automatically loaded at probing.
 
-config SND_HDA_ELD
-       def_bool y
-       depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
-
 config SND_HDA_CODEC_CIRRUS
        bool "Build Cirrus Logic codec support"
        depends on SND_HDA_INTEL
index 24bc195b02daef99fa675601712f04cfc6eb73e8..17ef3658f34b72d42d1deede9bc5f4efb1054a27 100644 (file)
@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
 snd-hda-codec-y := hda_codec.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs :=        patch_cmedia.o
 snd-hda-codec-analog-objs :=   patch_analog.o
 snd-hda-codec-idt-objs :=      patch_sigmatel.o
 snd-hda-codec-si3054-objs :=   patch_si3054.o
-snd-hda-codec-atihdmi-objs :=  patch_atihdmi.o
 snd-hda-codec-cirrus-objs :=   patch_cirrus.o
 snd-hda-codec-ca0110-objs :=   patch_ca0110.o
 snd-hda-codec-conexant-objs := patch_conexant.o
 snd-hda-codec-via-objs :=      patch_via.o
-snd-hda-codec-nvhdmi-objs :=   patch_nvhdmi.o
-snd-hda-codec-intelhdmi-objs :=        patch_intelhdmi.o
+snd-hda-codec-hdmi-objs :=     patch_hdmi.o hda_eld.o
 
 # common driver
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
@@ -39,9 +36,6 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_SI3054
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
 endif
-ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
-endif
 ifdef CONFIG_SND_HDA_CODEC_CIRRUS
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
 endif
@@ -54,11 +48,8 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_VIA
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
 endif
-ifdef CONFIG_SND_HDA_CODEC_NVHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+ifdef CONFIG_SND_HDA_CODEC_HDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
 endif
 
 # this must be the last entry after codec drivers;
index 14829210ef0bf4b1bac018d4f5e31a1d1c4728b9..644e3f14f8ca5aea7af2e465450caab86d2f90cb 100644 (file)
@@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        struct hda_codec *c;
        struct hda_cvt_setup *p;
        unsigned int oldval, newval;
+       int type;
        int i;
 
        if (!nid)
@@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        p->dirty = 0;
 
        /* make other inactive cvts with the same stream-tag dirty */
+       type = get_wcaps_type(get_wcaps(codec, nid));
        list_for_each_entry(c, &codec->bus->codec_list, list) {
                for (i = 0; i < c->cvt_setups.used; i++) {
                        p = snd_array_elem(&c->cvt_setups, i);
-                       if (!p->active && p->stream_tag == stream_tag)
+                       if (!p->active && p->stream_tag == stream_tag &&
+                           get_wcaps_type(get_wcaps(codec, p->nid)) == type)
                                p->dirty = 1;
                }
        }
@@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
        if (!nid)
                return;
 
+       if (codec->no_sticky_stream)
+               do_now = 1;
+
        snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
        p = get_hda_cvt_setup(codec, nid);
        if (p) {
@@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        hda_nid_t nid = get_amp_nid(kcontrol);
        int dir = get_amp_direction(kcontrol);
        unsigned int ofs = get_amp_offset(kcontrol);
+       bool min_mute = get_amp_min_mute(kcontrol);
        u32 caps, val1, val2;
 
        if (size < 4 * sizeof(unsigned int))
@@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
        val1 += ofs;
        val1 = ((int)val1) * ((int)val2);
+       if (min_mute)
+               val2 |= TLV_DB_SCALE_MUTE;
        if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
                return -EFAULT;
        if (put_user(2 * sizeof(unsigned int), _tlv + 1))
@@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
                                                   HDA_AMP_MUTE,
                                                   *valp ? 0 : HDA_AMP_MUTE);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, nid);
-#endif
+       hda_call_check_power_status(codec, nid);
        snd_hda_power_down(codec);
        return change;
 }
@@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
 }
 
 
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+                                  int type)
+{
+       if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+               cfg->inputs[cfg->num_inputs].pin = nid;
+               cfg->inputs[cfg->num_inputs].type = type;
+               cfg->num_inputs++;
+       }
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+       int i, j;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               for (j = i + 1; j < cfg->num_inputs; j++) {
+                       if (cfg->inputs[i].type > cfg->inputs[j].type) {
+                               struct auto_pin_cfg_item tmp;
+                               tmp = cfg->inputs[i];
+                               cfg->inputs[i] = cfg->inputs[j];
+                               cfg->inputs[j] = tmp;
+                       }
+               }
+       }
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * if any analog output exists.
  *
- * The analog input pins are assigned to input_pins array.
+ * The analog input pins are assigned to inputs array.
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
  */
@@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
        short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
        short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+       int i;
 
        memset(cfg, 0, sizeof(*cfg));
 
@@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
                        cfg->hp_outs++;
                        break;
-               case AC_JACK_MIC_IN: {
-                       int preferred, alt;
-                       if (loc == AC_JACK_LOC_FRONT ||
-                           (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
-                               preferred = AUTO_PIN_FRONT_MIC;
-                               alt = AUTO_PIN_MIC;
-                       } else {
-                               preferred = AUTO_PIN_MIC;
-                               alt = AUTO_PIN_FRONT_MIC;
-                       }
-                       if (!cfg->input_pins[preferred])
-                               cfg->input_pins[preferred] = nid;
-                       else if (!cfg->input_pins[alt])
-                               cfg->input_pins[alt] = nid;
+               case AC_JACK_MIC_IN:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
                        break;
-               }
                case AC_JACK_LINE_IN:
-                       if (loc == AC_JACK_LOC_FRONT)
-                               cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
-                       else
-                               cfg->input_pins[AUTO_PIN_LINE] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
                        break;
                case AC_JACK_CD:
-                       cfg->input_pins[AUTO_PIN_CD] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
                        break;
                case AC_JACK_AUX:
-                       cfg->input_pins[AUTO_PIN_AUX] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
                        break;
                case AC_JACK_SPDIF_OUT:
                case AC_JACK_DIG_OTHER_OUT:
@@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        memmove(sequences_hp + i, sequences_hp + i + 1,
                                sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
                }
+               memset(cfg->hp_pins + cfg->hp_outs, 0,
+                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
        }
 
        /* sort by sequence */
@@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
                              cfg->hp_outs);
 
-       /* if we have only one mic, make it AUTO_PIN_MIC */
-       if (!cfg->input_pins[AUTO_PIN_MIC] &&
-           cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
-               cfg->input_pins[AUTO_PIN_MIC] =
-                       cfg->input_pins[AUTO_PIN_FRONT_MIC];
-               cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
-       }
-       /* ditto for line-in */
-       if (!cfg->input_pins[AUTO_PIN_LINE] &&
-           cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
-               cfg->input_pins[AUTO_PIN_LINE] =
-                       cfg->input_pins[AUTO_PIN_FRONT_LINE];
-               cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
-       }
-
        /*
         * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
         * as a primary output
@@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                break;
        }
 
+       sort_autocfg_input_pins(cfg);
+
        /*
         * debug prints of the parsed results
         */
@@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        if (cfg->dig_outs)
                snd_printd("   dig-out=0x%x/0x%x\n",
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
-                  " cd=0x%x, aux=0x%x\n",
-                  cfg->input_pins[AUTO_PIN_MIC],
-                  cfg->input_pins[AUTO_PIN_FRONT_MIC],
-                  cfg->input_pins[AUTO_PIN_LINE],
-                  cfg->input_pins[AUTO_PIN_FRONT_LINE],
-                  cfg->input_pins[AUTO_PIN_CD],
-                  cfg->input_pins[AUTO_PIN_AUX]);
+       snd_printd("   inputs:");
+       for (i = 0; i < cfg->num_inputs; i++) {
+               snd_printdd(" %s=0x%x",
+                           hda_get_autocfg_input_label(codec, cfg, i),
+                           cfg->inputs[i].pin);
+       }
+       snd_printd("\n");
        if (cfg->dig_in_pin)
                snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
@@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
-/* labels for input pins */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
-       "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
-};
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+       unsigned int loc = get_defcfg_location(def_conf);
+       unsigned int conn = get_defcfg_connect(def_conf);
+       if (conn == AC_JACK_PORT_NONE)
+               return INPUT_PIN_ATTR_UNUSED;
+       /* Windows may claim the internal mic to be BOTH, too */
+       if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+               return INPUT_PIN_ATTR_DOCK;
+       if (loc == AC_JACK_LOC_REAR)
+               return INPUT_PIN_ATTR_REAR;
+       if (loc == AC_JACK_LOC_FRONT)
+               return INPUT_PIN_ATTR_FRONT;
+       return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+                                       int check_location)
+{
+       unsigned int def_conf;
+       static const char *mic_names[] = {
+               "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+       };
+       int attr;
+
+       def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_MIC_IN:
+               if (!check_location)
+                       return "Mic";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               return mic_names[attr - 1];
+       case AC_JACK_LINE_IN:
+               if (!check_location)
+                       return "Line";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               if (attr == INPUT_PIN_ATTR_DOCK)
+                       return "Dock Line";
+               return "Line";
+       case AC_JACK_AUX:
+               return "Aux";
+       case AC_JACK_CD:
+               return "CD";
+       case AC_JACK_SPDIF_IN:
+               return "SPDIF In";
+       case AC_JACK_DIG_OTHER_IN:
+               return "Digital In";
+       default:
+               return "Misc";
+       }
+}
+EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+                                  const struct auto_pin_cfg *cfg,
+                                  int input)
+{
+       unsigned int defc;
+       int i, attr, attr2;
+
+       defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+       attr = snd_hda_get_input_pin_attr(defc);
+       /* for internal or docking mics, we need locations */
+       if (attr <= INPUT_PIN_ATTR_NORMAL)
+               return 1;
+
+       attr = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+               attr2 = snd_hda_get_input_pin_attr(defc);
+               if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+                       if (attr && attr != attr2)
+                               return 1; /* different locations found */
+                       attr = attr2;
+               }
+       }
+       return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input)
+{
+       int type = cfg->inputs[input].type;
+       int has_multiple_pins = 0;
+
+       if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+           (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+               has_multiple_pins = 1;
+       if (has_multiple_pins && type == AUTO_PIN_MIC)
+               has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+       return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+                                      has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/**
+ * snd_hda_add_imux_item - Add an item to input_mux
+ *
+ * When the same label is used already in the existing items, the number
+ * suffix is appended to the label.  This label index number is stored
+ * to type_idx when non-NULL pointer is given.
+ */
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+                         int index, int *type_idx)
+{
+       int i, label_idx = 0;
+       if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
+               snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < imux->num_items; i++) {
+               if (!strncmp(label, imux->items[i].label, strlen(label)))
+                       label_idx++;
+       }
+       if (type_idx)
+               *type_idx = label_idx;
+       if (label_idx > 0)
+               snprintf(imux->items[imux->num_items].label,
+                        sizeof(imux->items[imux->num_items].label),
+                        "%s %d", label, label_idx);
+       else
+               strlcpy(imux->items[imux->num_items].label, label,
+                       sizeof(imux->items[imux->num_items].label));
+       imux->items[imux->num_items].index = index;
+       imux->num_items++;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
 
 
 #ifdef CONFIG_PM
index 62c70224010808dca1b7a8330e28dfa791bbe61e..fdf8d44f8b6b041fc4a9b1e0e63a31315a9fbe3b 100644 (file)
@@ -850,6 +850,7 @@ struct hda_codec {
        unsigned int pin_amp_workaround:1; /* pin out-amp takes index
                                            * (e.g. Conexant codecs)
                                            */
+       unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
        unsigned int pins_shutup:1;     /* pins are shut up */
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static inline
+int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (codec->patch_ops.check_power_status)
+               return codec->patch_ops.check_power_status(codec, nid);
+       return 0;
+}
+#else  
+#define hda_call_check_power_status(codec, nid)                0
+#endif
+
 /*
  * get widget information
  */
index 26c3ade735838624c9f6d2ca889b4ca724df96db..cb0c23a6b473e07bd9d768f9430e7cde2342639c 100644 (file)
@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
        return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
                                                 AC_DIPSIZE_ELD_BUF);
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
 
 int snd_hdmi_get_eld(struct hdmi_eld *eld,
                     struct hda_codec *codec, hda_nid_t nid)
@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        kfree(buf);
        return ret;
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
 
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 {
@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
        }
        buf[j] = '\0';  /* necessary when j == 0 */
 }
-EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
 
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 {
@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
        for (i = 0; i < e->sad_count; i++)
                hdmi_show_short_audio_desc(e->sad + i);
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
 
 #ifdef CONFIG_PROC_FS
 
@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
 
        return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
 
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 {
@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
                eld->proc_entry = NULL;
        }
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
 
 #endif /* CONFIG_PROC_FS */
 
@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
        pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
        pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
 }
-EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
index 5ea21285ee1f6e700fa320b3710495e47f06aca7..fb0582f8d72503905566f3db047e4f8c65fc7f68 100644 (file)
@@ -61,7 +61,6 @@ struct hda_gspec {
        struct hda_gnode *cap_vol_node; /* Node for capture volume */
        unsigned int cur_cap_src;       /* current capture source */
        struct hda_input_mux input_mux;
-       char cap_labels[HDA_MAX_NUM_INPUTS][16];
 
        unsigned int def_amp_in_caps;
        unsigned int def_amp_out_caps;
@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
  * returns 0 if not found, 1 if found, or a negative error code.
  */
 static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
-                              struct hda_gnode *node)
+                              struct hda_gnode *node, int idx)
 {
        int i, err;
        unsigned int pinctl;
-       char *label;
        const char *type;
 
        if (node->checked)
@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
                        child = hda_get_node(spec, node->conn_list[i]);
                        if (! child)
                                continue;
-                       err = parse_adc_sub_nodes(codec, spec, child);
+                       err = parse_adc_sub_nodes(codec, spec, child, idx);
                        if (err < 0)
                                return err;
                        if (err > 0) {
@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
                        return 0;
                type = "Input";
        }
-       label = spec->cap_labels[spec->input_mux.num_items];
-       strcpy(label, type);
-       spec->input_mux.items[spec->input_mux.num_items].label = label;
+       snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
 
        /* unmute the PIN external input */
        unmute_input(codec, node, 0); /* index = 0? */
@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
        return 1; /* found */
 }
 
-/* add a capture source element */
-static void add_cap_src(struct hda_gspec *spec, int idx)
-{
-       struct hda_input_mux_item *csrc;
-       char *buf;
-       int num, ocap;
-
-       num = spec->input_mux.num_items;
-       csrc = &spec->input_mux.items[num];
-       buf = spec->cap_labels[num];
-       for (ocap = 0; ocap < num; ocap++) {
-               if (! strcmp(buf, spec->cap_labels[ocap])) {
-                       /* same label already exists,
-                        * put the index number to be unique
-                        */
-                       sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
-                       break;
-               }
-       }
-       csrc->index = idx;
-       spec->input_mux.num_items++;
-}
-
 /*
  * parse input
  */
@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
        for (i = 0; i < adc_node->nconns; i++) {
                node = hda_get_node(spec, adc_node->conn_list[i]);
                if (node && node->type == AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node);
+                       err = parse_adc_sub_nodes(codec, spec, node, i);
                        if (err < 0)
                                return err;
-                       else if (err > 0)
-                               add_cap_src(spec, i);
                }
        }
        /* ... then check the rests, more complicated connections */
        for (i = 0; i < adc_node->nconns; i++) {
                node = hda_get_node(spec, adc_node->conn_list[i]);
                if (node && node->type != AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node);
+                       err = parse_adc_sub_nodes(codec, spec, node, i);
                        if (err < 0)
                                return err;
-                       else if (err > 0)
-                               add_cap_src(spec, i);
                }
        }
 
index 34940a07905192590a056efe734e155d66f575f7..21aa9b0e28f6cb466a81a4d1e4c48622c71f89c9 100644 (file)
@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
 module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-                "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+                "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -305,6 +305,7 @@ enum {
        POS_FIX_AUTO,
        POS_FIX_LPIB,
        POS_FIX_POSBUF,
+       POS_FIX_VIACOMBO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -433,7 +434,6 @@ struct azx {
        unsigned int polling_mode :1;
        unsigned int msi :1;
        unsigned int irq_pending_warned :1;
-       unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
        unsigned int probing :1; /* codec probing phase */
 
        /* for debugging */
@@ -458,6 +458,7 @@ enum {
        AZX_DRIVER_ULI,
        AZX_DRIVER_NVIDIA,
        AZX_DRIVER_TERA,
+       AZX_DRIVER_CTX,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
        [AZX_DRIVER_NVIDIA] = "HDA NVidia",
        [AZX_DRIVER_TERA] = "HDA Teradici", 
+       [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
-       azx_writew(chip, RINTCNT, 1);
+       if (chip->driver_type == AZX_DRIVER_CTX)
+               azx_writew(chip, RINTCNT, 0xc0);
+       else
+               azx_writew(chip, RINTCNT, 1);
        /* enable rirb dma and response irq */
        azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE)
+               if (status & RIRB_INT_RESPONSE) {
+                       if (chip->driver_type == AZX_DRIVER_CTX)
+                               udelay(80);
                        azx_update_rirb(chip);
+               }
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
 
@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
        /* enable the position buffer */
-       if (chip->position_fix[0] == POS_FIX_POSBUF ||
-           chip->position_fix[0] == POS_FIX_AUTO ||
-           chip->position_fix[1] == POS_FIX_POSBUF ||
-           chip->position_fix[1] == POS_FIX_AUTO ||
-           chip->via_dmapos_patch) {
+       if (chip->position_fix[0] != POS_FIX_LPIB ||
+           chip->position_fix[1] != POS_FIX_LPIB) {
                if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
                        azx_writel(chip, DPLBASE,
                                (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
        struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int bufsize, period_bytes, format_val;
+       unsigned int bufsize, period_bytes, format_val, stream_tag;
        int err;
 
        azx_stream_reset(chip, azx_dev);
@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        else
                azx_dev->fifo_size = 0;
 
-       return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+       stream_tag = azx_dev->stream_tag;
+       /* CA-IBG chips need the playback stream starting from 1 */
+       if (chip->driver_type == AZX_DRIVER_CTX &&
+           stream_tag > chip->capture_streams)
+               stream_tag -= chip->capture_streams;
+       return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
                                     azx_dev->format_val, substream);
 }
 
@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
                                     struct azx_dev *azx_dev)
 {
        unsigned int pos;
+       int stream = azx_dev->substream->stream;
 
-       if (chip->via_dmapos_patch)
+       switch (chip->position_fix[stream]) {
+       case POS_FIX_LPIB:
+               /* read LPIB */
+               pos = azx_sd_readl(azx_dev, SD_LPIB);
+               break;
+       case POS_FIX_VIACOMBO:
                pos = azx_via_get_position(chip, azx_dev);
-       else {
-               int stream = azx_dev->substream->stream;
-               if (chip->position_fix[stream] == POS_FIX_POSBUF ||
-                   chip->position_fix[stream] == POS_FIX_AUTO) {
-                       /* use the position buffer */
-                       pos = le32_to_cpu(*azx_dev->posbuf);
-               } else {
-                       /* read LPIB */
-                       pos = azx_sd_readl(azx_dev, SD_LPIB);
-               }
+               break;
+       default:
+               /* use the position buffer */
+               pos = le32_to_cpu(*azx_dev->posbuf);
        }
+
        if (pos >= azx_dev->bufsize)
                pos = 0;
        return pos;
@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        switch (fix) {
        case POS_FIX_LPIB:
        case POS_FIX_POSBUF:
+       case POS_FIX_VIACOMBO:
                return fix;
        }
 
-       /* Check VIA/ATI HD Audio Controller exist */
-       switch (chip->driver_type) {
-       case AZX_DRIVER_VIA:
-       case AZX_DRIVER_ATI:
-               chip->via_dmapos_patch = 1;
-               /* Use link position directly, avoid any transfer problem. */
-               return POS_FIX_LPIB;
-       }
-       chip->via_dmapos_patch = 0;
-
        q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
        if (q) {
                printk(KERN_INFO
@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
                       q->value, q->subvendor, q->subdevice);
                return q->value;
        }
+
+       /* Check VIA/ATI HD Audio Controller exist */
+       switch (chip->driver_type) {
+       case AZX_DRIVER_VIA:
+       case AZX_DRIVER_ATI:
+               /* Use link position directly, avoid any transfer problem. */
+               return POS_FIX_VIACOMBO;
+       }
+
        return POS_FIX_AUTO;
 }
 
@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
-       /* ICH 6..10 */
-       { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
-       /* PCH */
-       { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
        /* CPT */
        { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
        /* PBG */
        { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       /* Generic Intel */
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
+         .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+         .class_mask = 0xffffff,
+         .driver_data = AZX_DRIVER_ICH },
        /* ATI SB 450/600 */
        { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
        { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_CTX },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
 #endif
+       /* Vortex86MX */
+       { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
index 28ab4aead48fd17db36098f2eb36b306f4a5d534..46bbefe2e4a9465189d2341d42825f1439d17a40 100644 (file)
  */
 #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)           \
        ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
+#define HDA_AMP_VAL_MIN_MUTE (1<<29)
 #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
        HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
 /* mono volume with index (index=0,1,...) (channel=1,2) */
-#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
          .subdevice = HDA_SUBDEV_AMP_FLAG, \
          .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
          .get = snd_hda_mixer_amp_volume_get, \
          .put = snd_hda_mixer_amp_volume_put, \
          .tlv = { .c = snd_hda_mixer_amp_tlv },                \
-         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
 /* stereo volume with index */
 #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
-       HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+       HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
 /* mono volume */
 #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
-       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
 /* stereo volume */
 #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
        HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+/* stereo volume with min=mute */
+#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
+       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
+                                 HDA_AMP_VAL_MIN_MUTE)
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
  */
 #define HDA_MAX_NUM_INPUTS     16
 struct hda_input_mux_item {
-       const char *label;
+       char label[32];
        unsigned int index;
 };
 struct hda_input_mux {
@@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
 
 enum {
        AUTO_PIN_MIC,
-       AUTO_PIN_FRONT_MIC,
-       AUTO_PIN_LINE,
-       AUTO_PIN_FRONT_LINE,
+       AUTO_PIN_LINE_IN,
        AUTO_PIN_CD,
        AUTO_PIN_AUX,
        AUTO_PIN_LAST
@@ -380,9 +383,33 @@ enum {
        AUTO_PIN_HP_OUT
 };
 
-extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
-
 #define AUTO_CFG_MAX_OUTS      5
+#define AUTO_CFG_MAX_INS       8
+
+struct auto_pin_cfg_item {
+       hda_nid_t pin;
+       int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+                                   int check_location);
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+                         int index, int *type_index_ret);
+
+enum {
+       INPUT_PIN_ATTR_UNUSED,  /* pin not connected */
+       INPUT_PIN_ATTR_INT,     /* internal mic/line-in */
+       INPUT_PIN_ATTR_DOCK,    /* docking mic/line-in */
+       INPUT_PIN_ATTR_NORMAL,  /* mic/line-in jack */
+       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
+       INPUT_PIN_ATTR_REAR,    /* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
 
 struct auto_pin_cfg {
        int line_outs;
@@ -393,7 +420,8 @@ struct auto_pin_cfg {
        int hp_outs;
        int line_out_type;      /* AUTO_PIN_XXX_OUT */
        hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-       hda_nid_t input_pins[AUTO_PIN_LAST];
+       int num_inputs;
+       struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
        int dig_outs;
        hda_nid_t dig_out_pins[2];
        hda_nid_t dig_in_pin;
@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
 #define get_amp_offset(kc)     (((kc)->private_value >> 23) & 0x3f)
+#define get_amp_min_mute(kc)   (((kc)->private_value >> 29) & 0x1)
 
 /*
  * CEA Short Audio Descriptor data
index 10bbbaf6ebc3d2b0531ba2fb1ab7e3f2be1f8994..f7ff3f7ccb8e938e7f074afea766495907bc7e1e 100644 (file)
@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
        spec->multiout.no_share_stream = 1;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
        codec->patch_ops = ad198x_patch_ops;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
-                           const char *ctlname, int boost)
+                           const char *ctlname, int ctlidx, int boost)
 {
        char name[32];
        int err, idx;
@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
 }
 
 /* create playback/capture controls for input pins */
-static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
+static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
+       struct ad198x_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
-       int i, err;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               err = new_analog_input(spec, cfg->input_pins[i],
-                                      auto_pin_cfg_labels[i],
-                                      i <= AUTO_PIN_FRONT_MIC);
+       int i, err, type, type_idx;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               const char *label;
+               type = cfg->inputs[i].type;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label,
+                                     ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
+                                     &type_idx);
+               err = new_analog_input(spec, cfg->inputs[i].pin,
+                                      label, type_idx,
+                                      type == AUTO_PIN_MIC);
                if (err < 0)
                        return err;
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
-               imux->num_items++;
        }
-       imux->items[imux->num_items].label = "Mix";
-       imux->items[imux->num_items].index = 9;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Mix", 9, NULL);
 
        if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
                               "Analog Mix Playback Volume",
@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int i, idx;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (! nid)
-                       continue;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                switch (nid) {
                case 0x15: /* port-C */
                        snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
                        break;
                }
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+                                   i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
                if (nid != AD1988_PIN_CD_NID)
                        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                            AMP_OUT_MUTE);
@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
                                                "Speaker")) < 0 ||
            (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
                                                "Headphone")) < 0 ||
-           (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+           (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
        spec->vmaster_nid = 0x04;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
        codec->patch_ops = ad198x_patch_ops;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
deleted file mode 100644 (file)
index fb684f0..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for ATI HDMI codecs
- *
- * Copyright (c) 2006 ATI Technologies Inc.
- *
- *
- *  This driver is free software; you can redistribute it and/or modify
- *  it under the terms of the 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 driver is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You 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/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-struct atihdmi_spec {
-       struct hda_multi_out multiout;
-
-       struct hda_pcm pcm_rec;
-};
-
-#define CVT_NID                0x02    /* audio converter */
-#define PIN_NID                0x03    /* HDMI output pin */
-
-static struct hda_verb atihdmi_basic_init[] = {
-       /* enable digital output on pin widget */
-       { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {} /* terminator */
-};
-
-/*
- * Controls
- */
-static int atihdmi_build_controls(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int atihdmi_init(struct hda_codec *codec)
-{
-       snd_hda_sequence_write(codec, atihdmi_basic_init);
-       /* SI codec requires to unmute the pin */
-       if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, PIN_NID, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_OUT_UNMUTE);
-       return 0;
-}
-
-/*
- * Digital out
- */
-static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                    struct hda_codec *codec,
-                                    struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                           struct hda_codec *codec,
-                                           unsigned int stream_tag,
-                                           unsigned int format,
-                                           struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       int chans = substream->runtime->channels;
-       int i, err;
-
-       err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                           format, substream);
-       if (err < 0)
-               return err;
-       snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
-                           chans - 1);
-       /* FIXME: XXX */
-       for (i = 0; i < chans; i++) {
-               snd_hda_codec_write(codec, CVT_NID, 0,
-                                   AC_VERB_SET_HDMI_CHAN_SLOT,
-                                   (i << 4) | i);
-       }
-       return 0;
-}
-
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = CVT_NID, /* NID to query formats and rates and setup streams */
-       .ops = {
-               .open = atihdmi_dig_playback_pcm_open,
-               .close = atihdmi_dig_playback_pcm_close,
-               .prepare = atihdmi_dig_playback_pcm_prepare
-       },
-};
-
-static int atihdmi_build_pcms(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm_rec;
-       unsigned int chans;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "ATI HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
-
-       /* FIXME: we must check ELD and change the PCM parameters dynamically
-        */
-       chans = get_wcaps(codec, CVT_NID);
-       chans = get_wcaps_channels(chans);
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-
-       return 0;
-}
-
-static void atihdmi_free(struct hda_codec *codec)
-{
-       kfree(codec->spec);
-}
-
-static struct hda_codec_ops atihdmi_patch_ops = {
-       .build_controls = atihdmi_build_controls,
-       .build_pcms = atihdmi_build_pcms,
-       .init = atihdmi_init,
-       .free = atihdmi_free,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;      /* no analog */
-       spec->multiout.max_channels = 2;
-       /* NID for copying analog to digital,
-        * seems to be unused in pure-digital
-        * case.
-        */
-       spec->multiout.dig_out_nid = CVT_NID;
-
-       codec->patch_ops = atihdmi_patch_ops;
-
-       return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
-       { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
-       { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
-       { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
-       { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
-       { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
-       { .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
-       {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:1002793c");
-MODULE_ALIAS("snd-hda-codec-id:10027919");
-MODULE_ALIAS("snd-hda-codec-id:1002791a");
-MODULE_ALIAS("snd-hda-codec-id:1002aa01");
-MODULE_ALIAS("snd-hda-codec-id:10951390");
-MODULE_ALIAS("snd-hda-codec-id:17e80047");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
-
-static struct hda_codec_preset_list atihdmi_list = {
-       .preset = snd_hda_preset_atihdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_atihdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&atihdmi_list);
-}
-
-static void __exit patch_atihdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&atihdmi_list);
-}
-
-module_init(patch_atihdmi_init)
-module_exit(patch_atihdmi_exit)
index af478019088eea787528f115df7a5f7e4270f701..46c8bf48c31fb7c0dfeea8881d1ff4784697a564 100644 (file)
@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
                        spec->dig_in = nid;
                        continue;
                }
-               for (j = 0; j < AUTO_PIN_LAST; j++)
-                       if (cfg->input_pins[j] == pin)
+               for (j = 0; j < cfg->num_inputs; j++)
+                       if (cfg->inputs[j].pin == pin)
                                break;
-               if (j >= AUTO_PIN_LAST)
+               if (j >= cfg->num_inputs)
                        continue;
                spec->input_pins[n] = pin;
-               spec->input_labels[n] = auto_pin_cfg_labels[j];
+               spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
                spec->adcs[n] = nid;
                n++;
        }
@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
        if (cfg->dig_outs &&
            snd_hda_get_connections(codec, cfg->dig_out_pins[0],
                                    &spec->dig_out, 1) == 1)
-               spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+               spec->multiout.dig_out_nid = spec->dig_out;
 }
 
 static int ca0110_parse_auto_config(struct hda_codec *codec)
index 488fd9ade1ba2bf7b306bf6e48ae106ef823294b..460fb2ef7e394614a4045a51d4306c429e818d6a 100644 (file)
@@ -65,6 +65,7 @@ struct cs_spec {
 
 /* available models */
 enum {
+       CS420X_MBP53,
        CS420X_MBP55,
        CS420X_IMAC27,
        CS420X_AUTO,
@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t pin = cfg->input_pins[idx];
+       hda_nid_t pin = cfg->inputs[idx].pin;
        unsigned int val = snd_hda_query_pin_caps(codec, pin);
        if (!(val & AC_PINCAP_PRES_DETECT))
                return 0;
        val = snd_hda_codec_get_pincfg(codec, pin);
-       return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
+       return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
 }
 
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t pin = cfg->input_pins[i];
-               if (!pin)
-                       continue;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
                spec->input_idx[spec->num_inputs] = i;
                spec->capsrc_idx[i] = spec->num_inputs++;
                spec->cur_input = i;
@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
 
        /* check whether the automatic mic switch is available */
        if (spec->num_inputs == 2 &&
-           spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
-               if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
-                       if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+           cfg->inputs[0].type == AUTO_PIN_MIC &&
+           cfg->inputs[1].type == AUTO_PIN_MIC) {
+               if (is_ext_mic(codec, cfg->inputs[0].pin)) {
+                       if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
-                               spec->automic_idx = AUTO_PIN_FRONT_MIC;
+                               spec->automic_idx = 0;
                        }
                } else {
-                       if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+                       if (is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
-                               spec->automic_idx = AUTO_PIN_MIC;
+                               spec->automic_idx = 1;
                        }
                }
        }
@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int idx;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
        if (uinfo->value.enumerated.item >= spec->num_inputs)
                uinfo->value.enumerated.item = spec->num_inputs - 1;
        idx = spec->input_idx[uinfo->value.enumerated.item];
-       strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+       strcpy(uinfo->value.enumerated.name,
+              hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
        return 0;
 }
 
@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
        return bind;
 }
 
+/* add a (input-boost) volume control to the given input pin */
+static int add_input_volume_control(struct hda_codec *codec,
+                                   struct auto_pin_cfg *cfg,
+                                   int item)
+{
+       hda_nid_t pin = cfg->inputs[item].pin;
+       u32 caps;
+       const char *label;
+       struct snd_kcontrol *kctl;
+               
+       if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+               return 0;
+       caps = query_amp_caps(codec, pin, HDA_INPUT);
+       caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+       if (caps <= 1)
+               return 0;
+       label = hda_get_autocfg_input_label(codec, cfg, item);
+       return add_volume(codec, label, 0,
+                         HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
 static int build_input(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
                        return err;
        }
 
+       for (i = 0; i < spec->num_inputs; i++) {
+               err = add_input_volume_control(codec, &spec->autocfg, i);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    hp_present ? 0 : PIN_OUT);
        }
-       if (spec->board_config == CS420X_MBP55 ||
+       if (spec->board_config == CS420X_MBP53 ||
+           spec->board_config == CS420X_MBP55 ||
            spec->board_config == CS420X_IMAC27) {
                unsigned int gpio = hp_present ? 0x02 : 0x08;
                snd_hda_codec_write(codec, 0x01, 0,
@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
        hda_nid_t nid;
        unsigned int present;
        
-       nid = cfg->input_pins[spec->automic_idx];
+       nid = cfg->inputs[spec->automic_idx].pin;
        present = snd_hda_jack_detect(codec, nid);
        if (present)
                change_cur_input(codec, spec->automic_idx, 0);
-       else {
-               unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
-                       AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
-               change_cur_input(codec, imic, 0);
-       }
+       else
+               change_cur_input(codec, !spec->automic_idx, 0);
 }
 
 /*
@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
        unsigned int coef;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
+       for (i = 0; i < cfg->num_inputs; i++) {
                unsigned int ctl;
-               hda_nid_t pin = cfg->input_pins[i];
-               if (!pin || !spec->adc_nid[i])
+               hda_nid_t pin = cfg->inputs[i].pin;
+               if (!spec->adc_nid[i])
                        continue;
                /* set appropriate pin control and mute first */
                ctl = PIN_IN;
-               if (i <= AUTO_PIN_FRONT_MIC) {
+               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
                        unsigned int caps = snd_hda_query_pin_caps(codec, pin);
                        caps >>= AC_PINCAP_VREF_SHIFT;
                        if (caps & AC_PINCAP_VREF_80)
@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
 }
 
 static const char *cs420x_models[CS420X_MODELS] = {
+       [CS420X_MBP53] = "mbp53",
        [CS420X_MBP55] = "mbp55",
        [CS420X_IMAC27] = "imac27",
        [CS420X_AUTO] = "auto",
@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+       SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
        {} /* terminator */
 };
@@ -1147,6 +1177,20 @@ struct cs_pincfg {
        u32 val;
 };
 
+static struct cs_pincfg mbp53_pincfgs[] = {
+       { 0x09, 0x012b4050 },
+       { 0x0a, 0x90100141 },
+       { 0x0b, 0x90100140 },
+       { 0x0c, 0x018b3020 },
+       { 0x0d, 0x90a00110 },
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x01cbe030 },
+       { 0x10, 0x014be060 },
+       { 0x12, 0x400000f0 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
 static struct cs_pincfg mbp55_pincfgs[] = {
        { 0x09, 0x012b4030 },
        { 0x0a, 0x90100121 },
@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
 };
 
 static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+       [CS420X_MBP53] = mbp53_pincfgs,
        [CS420X_MBP55] = mbp55_pincfgs,
        [CS420X_IMAC27] = imac27_pincfgs,
 };
@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
 
        switch (spec->board_config) {
        case CS420X_IMAC27:
+       case CS420X_MBP53:
        case CS420X_MBP55:
                /* GPIO1 = headphones */
                /* GPIO3 = speakers */
index 972e7c453b3d6c8320d58b6aebe6ef41fc259920..6361f752b5f35cfddff7f8423f0d5d185a9003d8 100644 (file)
@@ -57,6 +57,12 @@ struct conexant_jack {
 
 };
 
+struct pin_dac_pair {
+       hda_nid_t pin;
+       hda_nid_t dac;
+       int type;
+};
+
 struct conexant_spec {
 
        struct snd_kcontrol_new *mixers[5];
@@ -77,6 +83,7 @@ struct conexant_spec {
        unsigned int cur_eapd;
        unsigned int hp_present;
        unsigned int auto_mic;
+       int auto_mic_ext;               /* autocfg.inputs[] index for ext mic */
        unsigned int need_dac_fix;
 
        /* capture */
@@ -110,9 +117,12 @@ struct conexant_spec {
        struct auto_pin_cfg autocfg;
        struct hda_input_mux private_imux;
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+       struct pin_dac_pair dac_info[8];
+       int dac_info_filled;
 
-       unsigned int dell_automute;
        unsigned int port_d_mode;
+       unsigned int auto_mute:1;       /* used in auto-parser */
+       unsigned int dell_automute:1;
        unsigned int dell_vostro:1;
        unsigned int ideapad:1;
        unsigned int thinkpad:1;
@@ -3065,7 +3075,7 @@ enum {
        CXT5066_LAPTOP,         /* Laptops w/ EAPD support */
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
        CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
-       CXT5066_DELL_VOSTO,     /* Dell Vostro 1015i */
+       CXT5066_DELL_VOSTRO,    /* Dell Vostro 1015i */
        CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_THINKPAD,       /* Lenovo ThinkPad T410s, others? */
        CXT5066_HP_LAPTOP,      /* HP Laptop */
@@ -3076,25 +3086,26 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_LAPTOP]        = "laptop",
        [CXT5066_DELL_LAPTOP]   = "dell-laptop",
        [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
-       [CXT5066_DELL_VOSTO]    = "dell-vostro",
+       [CXT5066_DELL_VOSTRO]   = "dell-vostro",
        [CXT5066_IDEAPAD]       = "ideapad",
        [CXT5066_THINKPAD]      = "thinkpad",
        [CXT5066_HP_LAPTOP]     = "hp-laptop",
 };
 
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
-                     CXT5066_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
                      CXT5066_DELL_LAPTOP),
-       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
-       SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO),
-       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
+       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
+       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+                     CXT5066_LAPTOP),
+       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
@@ -3196,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->capture_prepare = cxt5066_olpc_capture_prepare;
                spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
                break;
-       case CXT5066_DELL_VOSTO:
+       case CXT5066_DELL_VOSTRO:
                codec->patch_ops.init = cxt5066_init;
                codec->patch_ops.unsol_event = cxt5066_vostro_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
@@ -3253,6 +3264,604 @@ static int patch_cxt5066(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * Automatic parser for CX20641 & co
+ */
+
+static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
+
+/* get the connection index of @nid in the widget @mux */
+static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
+                               hda_nid_t nid)
+{
+       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+       int i, nums;
+
+       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+       for (i = 0; i < nums; i++)
+               if (conn[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* get an unassigned DAC from the given list.
+ * Return the nid if found and reduce the DAC list, or return zero if
+ * not found
+ */
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
+                                   hda_nid_t *dacs, int *num_dacs)
+{
+       int i, nums = *num_dacs;
+       hda_nid_t ret = 0;
+
+       for (i = 0; i < nums; i++) {
+               if (get_connection_index(codec, pin, dacs[i]) >= 0) {
+                       ret = dacs[i];
+                       break;
+               }
+       }
+       if (!ret)
+               return 0;
+       if (--nums > 0)
+               memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
+       *num_dacs = nums;
+       return ret;
+}
+
+#define MAX_AUTO_DACS  5
+
+/* fill analog DAC list from the widget tree */
+static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
+{
+       hda_nid_t nid, end_nid;
+       int nums = 0;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int type = get_wcaps_type(wcaps);
+               if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
+                       dacs[nums++] = nid;
+                       if (nums >= MAX_AUTO_DACS)
+                               break;
+               }
+       }
+       return nums;
+}
+
+/* fill pin_dac_pair list from the pin and dac list */
+static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
+                             int num_pins, hda_nid_t *dacs, int *rest,
+                             struct pin_dac_pair *filled, int type)
+{
+       int i, nums;
+
+       nums = 0;
+       for (i = 0; i < num_pins; i++) {
+               filled[nums].pin = pins[i];
+               filled[nums].type = type;
+               filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
+               nums++;
+       }
+       return nums;
+}
+
+/* parse analog output paths */
+static void cx_auto_parse_output(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t dacs[MAX_AUTO_DACS];
+       int i, j, nums, rest;
+
+       rest = fill_cx_auto_dacs(codec, dacs);
+       /* parse all analog output pins */
+       nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
+                                 dacs, &rest, spec->dac_info,
+                                 AUTO_PIN_LINE_OUT);
+       nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+                                 dacs, &rest, spec->dac_info + nums,
+                                 AUTO_PIN_HP_OUT);
+       nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+                                 dacs, &rest, spec->dac_info + nums,
+                                 AUTO_PIN_SPEAKER_OUT);
+       spec->dac_info_filled = nums;
+       /* fill multiout struct */
+       for (i = 0; i < nums; i++) {
+               hda_nid_t dac = spec->dac_info[i].dac;
+               if (!dac)
+                       continue;
+               switch (spec->dac_info[i].type) {
+               case AUTO_PIN_LINE_OUT:
+                       spec->private_dac_nids[spec->multiout.num_dacs] = dac;
+                       spec->multiout.num_dacs++;
+                       break;
+               case AUTO_PIN_HP_OUT:
+               case AUTO_PIN_SPEAKER_OUT:
+                       if (!spec->multiout.hp_nid) {
+                               spec->multiout.hp_nid = dac;
+                               break;
+                       }
+                       for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
+                               if (!spec->multiout.extra_out_nid[j]) {
+                                       spec->multiout.extra_out_nid[j] = dac;
+                                       break;
+                               }
+                       break;
+               }
+       }
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.max_channels = nums * 2;
+
+       if (cfg->hp_outs > 0)
+               spec->auto_mute = 1;
+       spec->vmaster_nid = spec->private_dac_nids[0];
+}
+
+/* auto-mute/unmute speaker and line outs according to headphone jack */
+static void cx_auto_hp_automute(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, present;
+
+       if (!spec->auto_mute)
+               return;
+       present = 0;
+       for (i = 0; i < cfg->hp_outs; i++) {
+               if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
+                       present = 1;
+                       break;
+               }
+       }
+       for (i = 0; i < cfg->line_outs; i++) {
+               snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   present ? 0 : PIN_OUT);
+       }
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   present ? 0 : PIN_OUT);
+       }
+}
+
+/* automatic switch internal and external mic */
+static void cx_auto_automic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux = &spec->private_imux;
+       int ext_idx = spec->auto_mic_ext;
+
+       if (!spec->auto_mic)
+               return;
+       if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
+               snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   imux->items[ext_idx].index);
+       } else {
+               snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   imux->items[!ext_idx].index);
+       }
+}
+
+static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cx_auto_hp_automute(codec);
+               conexant_report_jack(codec, nid);
+               break;
+       case CONEXANT_MIC_EVENT:
+               cx_auto_automic(codec);
+               conexant_report_jack(codec, nid);
+               break;
+       }
+}
+
+/* return true if it's an internal-mic pin */
+static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+       return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+               snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
+}
+
+/* return true if it's an external-mic pin */
+static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+       return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+               snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
+               (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
+}
+
+/* check whether the pin config is suitable for auto-mic switching;
+ * auto-mic is enabled only when one int-mic and one-ext mic exist
+ */
+static void cx_auto_check_auto_mic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (is_ext_mic(codec, cfg->inputs[0].pin) &&
+           is_int_mic(codec, cfg->inputs[1].pin)) {
+               spec->auto_mic = 1;
+               spec->auto_mic_ext = 1;
+               return;
+       }
+       if (is_int_mic(codec, cfg->inputs[1].pin) &&
+           is_ext_mic(codec, cfg->inputs[0].pin)) {
+               spec->auto_mic = 1;
+               spec->auto_mic_ext = 0;
+               return;
+       }
+}
+
+static void cx_auto_parse_input(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux;
+       int i;
+
+       imux = &spec->private_imux;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               int idx = get_connection_index(codec, spec->adc_nids[0],
+                                              cfg->inputs[i].pin);
+               if (idx >= 0) {
+                       const char *label;
+                       label = hda_get_autocfg_input_label(codec, cfg, i);
+                       snd_hda_add_imux_item(imux, label, idx, NULL);
+               }
+       }
+       if (imux->num_items == 2 && cfg->num_inputs == 2)
+               cx_auto_check_auto_mic(codec);
+       if (imux->num_items > 1 && !spec->auto_mic)
+               spec->input_mux = imux;
+}
+
+/* get digital-input audio widget corresponding to the given pin */
+static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
+{
+       hda_nid_t nid, end_nid;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int type = get_wcaps_type(wcaps);
+               if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
+                       if (get_connection_index(codec, nid, pin) >= 0)
+                               return nid;
+               }
+       }
+       return 0;
+}
+
+static void cx_auto_parse_digital(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+
+       if (cfg->dig_outs &&
+           snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
+               spec->multiout.dig_out_nid = nid;
+       if (cfg->dig_in_pin)
+               spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
+}
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static void cx_auto_parse_beep(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       hda_nid_t nid, end_nid;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++)
+               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
+                       set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+                       break;
+               }
+}
+#else
+#define cx_auto_parse_beep(codec)
+#endif
+
+static int cx_auto_parse_auto_config(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+
+       cx_auto_parse_output(codec);
+       cx_auto_parse_input(codec);
+       cx_auto_parse_digital(codec);
+       cx_auto_parse_beep(codec);
+       return 0;
+}
+
+static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
+                                hda_nid_t *pins)
+{
+       int i;
+       for (i = 0; i < num_pins; i++) {
+               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+                       snd_hda_codec_write(codec, pins[i], 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+       }
+}
+
+static void select_connection(struct hda_codec *codec, hda_nid_t pin,
+                             hda_nid_t src)
+{
+       int idx = get_connection_index(codec, pin, src);
+       if (idx >= 0)
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_CONNECT_SEL, idx);
+}
+
+static void cx_auto_init_output(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+       int i;
+
+       for (i = 0; i < spec->multiout.num_dacs; i++)
+               snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       for (i = 0; i < cfg->hp_outs; i++)
+               snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+       if (spec->auto_mute) {
+               for (i = 0; i < cfg->hp_outs; i++) {
+                       snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | CONEXANT_HP_EVENT);
+               }
+               cx_auto_hp_automute(codec);
+       } else {
+               for (i = 0; i < cfg->line_outs; i++)
+                       snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               for (i = 0; i < cfg->speaker_outs; i++)
+                       snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       }
+
+       for (i = 0; i < spec->dac_info_filled; i++) {
+               nid = spec->dac_info[i].dac;
+               if (!nid)
+                       nid = spec->multiout.dac_nids[0];
+               select_connection(codec, spec->dac_info[i].pin, nid);
+       }
+
+       /* turn on EAPD */
+       cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
+       cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
+       cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
+}
+
+static void cx_auto_init_input(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < spec->num_adc_nids; i++)
+               snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               unsigned int type;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC)
+                       type = PIN_VREF80;
+               else
+                       type = PIN_IN;
+               snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+       }
+
+       if (spec->auto_mic) {
+               int ext_idx = spec->auto_mic_ext;
+               snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | CONEXANT_MIC_EVENT);
+               cx_auto_automic(codec);
+       } else {
+               for (i = 0; i < spec->num_adc_nids; i++) {
+                       snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           spec->private_imux.items[0].index);
+               }
+       }
+}
+
+static void cx_auto_init_digital(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (spec->multiout.dig_out_nid)
+               snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       if (spec->dig_in_nid)
+               snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+}
+
+static int cx_auto_init(struct hda_codec *codec)
+{
+       /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
+       cx_auto_init_output(codec);
+       cx_auto_init_input(codec);
+       cx_auto_init_digital(codec);
+       return 0;
+}
+
+static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
+                             const char *dir, int cidx,
+                             hda_nid_t nid, int hda_dir)
+{
+       static char name[32];
+       static struct snd_kcontrol_new knew[] = {
+               HDA_CODEC_VOLUME(name, 0, 0, 0),
+               HDA_CODEC_MUTE(name, 0, 0, 0),
+       };
+       static char *sfx[2] = { "Volume", "Switch" };
+       int i, err;
+
+       for (i = 0; i < 2; i++) {
+               struct snd_kcontrol *kctl;
+               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
+               knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
+               knew[i].index = cidx;
+               snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
+               kctl = snd_ctl_new1(&knew[i], codec);
+               if (!kctl)
+                       return -ENOMEM;
+               err = snd_hda_ctl_add(codec, nid, kctl);
+               if (err < 0)
+                       return err;
+               if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
+                       break;
+       }
+       return 0;
+}
+
+#define cx_auto_add_pb_volume(codec, nid, str, idx)                    \
+       cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
+
+static int cx_auto_build_output_controls(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int i, err;
+       int num_line = 0, num_hp = 0, num_spk = 0;
+       static const char *texts[3] = { "Front", "Surround", "CLFE" };
+
+       if (spec->dac_info_filled == 1)
+               return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
+                                            "Master", 0);
+       for (i = 0; i < spec->dac_info_filled; i++) {
+               const char *label;
+               int idx, type;
+               if (!spec->dac_info[i].dac)
+                       continue;
+               type = spec->dac_info[i].type;
+               if (type == AUTO_PIN_LINE_OUT)
+                       type = spec->autocfg.line_out_type;
+               switch (type) {
+               case AUTO_PIN_LINE_OUT:
+               default:
+                       label = texts[num_line++];
+                       idx = 0;
+                       break;
+               case AUTO_PIN_HP_OUT:
+                       label = "Headphone";
+                       idx = num_hp++;
+                       break;
+               case AUTO_PIN_SPEAKER_OUT:
+                       label = "Speaker";
+                       idx = num_spk++;
+                       break;
+               }
+               err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
+                                           label, idx);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int cx_auto_build_input_controls(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       static const char *prev_label;
+       int i, err, cidx;
+
+       err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
+                                HDA_INPUT);
+       if (err < 0)
+               return err;
+       prev_label = NULL;
+       cidx = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               const char *label;
+               if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+                       continue;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               if (label == prev_label)
+                       cidx++;
+               else
+                       cidx = 0;
+               prev_label = label;
+               err = cx_auto_add_volume(codec, label, " Capture", cidx,
+                                        nid, HDA_INPUT);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int cx_auto_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = cx_auto_build_output_controls(codec);
+       if (err < 0)
+               return err;
+       err = cx_auto_build_input_controls(codec);
+       if (err < 0)
+               return err;
+       return conexant_build_controls(codec);
+}
+
+static struct hda_codec_ops cx_auto_patch_ops = {
+       .build_controls = cx_auto_build_controls,
+       .build_pcms = conexant_build_pcms,
+       .init = cx_auto_init,
+       .free = conexant_free,
+       .unsol_event = cx_auto_unsol_event,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       .suspend = conexant_suspend,
+#endif
+       .reboot_notify = snd_hda_shutup_pins,
+};
+
+static int patch_conexant_auto(struct hda_codec *codec)
+{
+       struct conexant_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       spec->adc_nids = cx_auto_adc_nids;
+       spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
+       spec->capsrc_nids = spec->adc_nids;
+       err = cx_auto_parse_auto_config(codec);
+       if (err < 0) {
+               kfree(codec->spec);
+               codec->spec = NULL;
+               return err;
+       }
+       codec->patch_ops = cx_auto_patch_ops;
+       if (spec->beep_amp)
+               snd_hda_attach_beep_device(codec, spec->beep_amp);
+       return 0;
+}
+
 /*
  */
 
@@ -3271,6 +3880,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_cxt5066 },
        { .id = 0x14f15069, .name = "CX20585",
          .patch = patch_cxt5066 },
+       { .id = 0x14f15097, .name = "CX20631",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15098, .name = "CX20632",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150a1, .name = "CX20641",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150a2, .name = "CX20642",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150ab, .name = "CX20651",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150ac, .name = "CX20652",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150b8, .name = "CX20664",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150b9, .name = "CX20665",
+         .patch = patch_conexant_auto },
        {} /* terminator */
 };
 
@@ -3281,6 +3906,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
 MODULE_ALIAS("snd-hda-codec-id:14f15068");
 MODULE_ALIAS("snd-hda-codec-id:14f15069");
+MODULE_ALIAS("snd-hda-codec-id:14f15097");
+MODULE_ALIAS("snd-hda-codec-id:14f15098");
+MODULE_ALIAS("snd-hda-codec-id:14f150a1");
+MODULE_ALIAS("snd-hda-codec-id:14f150a2");
+MODULE_ALIAS("snd-hda-codec-id:14f150ab");
+MODULE_ALIAS("snd-hda-codec-id:14f150ac");
+MODULE_ALIAS("snd-hda-codec-id:14f150b8");
+MODULE_ALIAS("snd-hda-codec-id:14f150b9");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index afd6022a96a75bda3b24b652973dccbe591c625f..d3e49aa5b9ecd42f6db6f5892319e6602ad9b7ab 100644 (file)
@@ -3,6 +3,9 @@
  *  patch_hdmi.c - routines for HDMI/DisplayPort codecs
  *
  *  Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
+ *  Copyright (c) 2006 ATI Technologies Inc.
+ *  Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
+ *  Copyright (c) 2008 Wei Ni <wni@nvidia.com>
  *
  *  Authors:
  *                     Wu Fengguang <wfg@linux.intel.com>
  *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
+ * could support two independent pipes, each of them can be connected to one or
+ * more ports (DVI, HDMI or DisplayPort).
+ *
+ * The HDA correspondence of pipes/ports are converter/pin nodes.
+ */
+#define MAX_HDMI_CVTS  3
+#define MAX_HDMI_PINS  3
 
 struct hdmi_spec {
        int num_cvts;
@@ -49,10 +68,10 @@ struct hdmi_spec {
        struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
 
        /*
-        * nvhdmi specific
+        * ati/nvhdmi specific
         */
        struct hda_multi_out multiout;
-       unsigned int codec_type;
+       struct hda_pcm_stream *pcm_playback;
 
        /* misc flags */
        /* PD bit indicates only the update, not the current state */
@@ -65,13 +84,25 @@ struct hdmi_audio_infoframe {
        u8 ver;  /* 0x01 */
        u8 len;  /* 0x0a */
 
-       u8 checksum;    /* PB0 */
+       u8 checksum;
+
        u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
        u8 SS01_SF24;
        u8 CXT04;
        u8 CA;
        u8 LFEPBL01_LSV36_DM_INH7;
-       u8 reserved[5]; /* PB6 - PB10 */
+};
+
+struct dp_audio_infoframe {
+       u8 type; /* 0x84 */
+       u8 len;  /* 0x1b */
+       u8 ver;  /* 0x11 << 2 */
+
+       u8 CC02_CT47;   /* match with HDMI infoframe from this on */
+       u8 SS01_SF24;
+       u8 CXT04;
+       u8 CA;
+       u8 LFEPBL01_LSV36_DM_INH7;
 };
 
 /*
@@ -162,7 +193,7 @@ static int hdmi_channel_mapping[0x32][8] = {
        /* 4ch */
        [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
        /* surround41 */
-       [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
+       [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
        /* surround50 */
        [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
        /* surround51 */
@@ -175,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = {
  * This is an ordered list!
  *
  * The preceding ones have better chances to be selected by
- * hdmi_setup_channel_allocation().
+ * hdmi_channel_allocation().
  */
 static struct cea_channel_speaker_allocation channel_allocations[] = {
 /*                       channel:   7     6    5    4    3     2    1    0  */
@@ -352,14 +383,14 @@ static void init_channel_allocations(void)
  *
  * TODO: it could select the wrong CA from multiple candidates.
 */
-static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
-                                        struct hdmi_audio_infoframe *ai)
+static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
+                                  int channels)
 {
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld;
        int i;
+       int ca = 0;
        int spk_mask = 0;
-       int channels = 1 + (ai->CC02_CT47 & 0x7);
        char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
 
        /*
@@ -397,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
                if (channels == channel_allocations[i].channels &&
                    (spk_mask & channel_allocations[i].spk_mask) ==
                                channel_allocations[i].spk_mask) {
-                       ai->CA = channel_allocations[i].ca_index;
+                       ca = channel_allocations[i].ca_index;
                        break;
                }
        }
 
        snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
        snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
-                   ai->CA, channels, buf);
+                   ca, channels, buf);
 
-       return ai->CA;
+       return ca;
 }
 
 static void hdmi_debug_channel_mapping(struct hda_codec *codec,
@@ -428,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
 
 static void hdmi_setup_channel_mapping(struct hda_codec *codec,
                                       hda_nid_t pin_nid,
-                                      struct hdmi_audio_infoframe *ai)
+                                      int ca)
 {
        int i;
-       int ca = ai->CA;
        int err;
 
        if (hdmi_channel_mapping[ca][1] == 0) {
@@ -528,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
 #endif
 }
 
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
 {
-       u8 *bytes = (u8 *)ai;
+       u8 *bytes = (u8 *)hdmi_ai;
        u8 sum = 0;
        int i;
 
-       ai->checksum = 0;
+       hdmi_ai->checksum = 0;
 
-       for (i = 0; i < sizeof(*ai); i++)
+       for (i = 0; i < sizeof(*hdmi_ai); i++)
                sum += bytes[i];
 
-       ai->checksum = -sum;
+       hdmi_ai->checksum = -sum;
 }
 
 static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
                                      hda_nid_t pin_nid,
-                                     struct hdmi_audio_infoframe *ai)
+                                     u8 *dip, int size)
 {
-       u8 *bytes = (u8 *)ai;
        int i;
 
        hdmi_debug_dip_size(codec, pin_nid);
        hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
 
-       hdmi_checksum_audio_infoframe(ai);
-
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++)
-               hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
+       for (i = 0; i < size; i++)
+               hdmi_write_dip_byte(codec, pin_nid, dip[i]);
 }
 
 static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
-                                   struct hdmi_audio_infoframe *ai)
+                                   u8 *dip, int size)
 {
-       u8 *bytes = (u8 *)ai;
        u8 val;
        int i;
 
@@ -571,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
                return false;
 
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++) {
+       for (i = 0; i < size; i++) {
                val = snd_hda_codec_read(codec, pin_nid, 0,
                                         AC_VERB_GET_HDMI_DIP_DATA, 0);
-               if (val != bytes[i])
+               if (val != dip[i])
                        return false;
        }
 
@@ -586,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
 {
        struct hdmi_spec *spec = codec->spec;
        hda_nid_t pin_nid;
+       int channels = substream->runtime->channels;
+       int ca;
        int i;
-       struct hdmi_audio_infoframe ai = {
-               .type           = 0x84,
-               .ver            = 0x01,
-               .len            = 0x0a,
-               .CC02_CT47      = substream->runtime->channels - 1,
-       };
+       u8 ai[max(sizeof(struct hdmi_audio_infoframe),
+                 sizeof(struct dp_audio_infoframe))];
 
-       hdmi_setup_channel_allocation(codec, nid, &ai);
+       ca = hdmi_channel_allocation(codec, nid, channels);
 
        for (i = 0; i < spec->num_pins; i++) {
                if (spec->pin_cvt[i] != nid)
@@ -603,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                        continue;
 
                pin_nid = spec->pin[i];
-               if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
+
+               memset(ai, 0, sizeof(ai));
+               if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
+                       struct hdmi_audio_infoframe *hdmi_ai;
+
+                       hdmi_ai = (struct hdmi_audio_infoframe *)ai;
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x01;
+                       hdmi_ai->len            = 0x0a;
+                       hdmi_ai->CC02_CT47      = channels - 1;
+                       hdmi_checksum_audio_infoframe(hdmi_ai);
+               } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
+                       struct dp_audio_infoframe *dp_ai;
+
+                       dp_ai = (struct dp_audio_infoframe *)ai;
+                       dp_ai->type             = 0x84;
+                       dp_ai->len              = 0x1b;
+                       dp_ai->ver              = 0x11 << 2;
+                       dp_ai->CC02_CT47        = channels - 1;
+               } else {
+                       snd_printd("HDMI: unknown connection type at pin %d\n",
+                                  pin_nid);
+                       continue;
+               }
+
+               /*
+                * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+                * sizeof(*dp_ai) to avoid partial match/update problems when
+                * the user switches between HDMI/DP monitors.
+                */
+               if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
                        snd_printdd("hdmi_setup_audio_infoframe: "
                                    "cvt=%d pin=%d channels=%d\n",
                                    nid, pin_nid,
-                                   substream->runtime->channels);
-                       hdmi_setup_channel_mapping(codec, pin_nid, &ai);
+                                   channels);
+                       hdmi_setup_channel_mapping(codec, pin_nid, ca);
                        hdmi_stop_infoframe_trans(codec, pin_nid);
-                       hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
+                       hdmi_fill_audio_infoframe(codec, pin_nid,
+                                                 ai, sizeof(ai));
                        hdmi_start_infoframe_trans(codec, pin_nid);
                }
        }
@@ -791,7 +846,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 /*
  * HDA/HDMI auto parsing
  */
-
 static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -922,3 +976,664 @@ static int hdmi_parse_codec(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ */
+static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+       "HDMI 0",
+       "HDMI 1",
+       "HDMI 2",
+};
+
+/*
+ * HDMI callbacks
+ */
+
+static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          unsigned int stream_tag,
+                                          unsigned int format,
+                                          struct snd_pcm_substream *substream)
+{
+       hdmi_set_channel_count(codec, hinfo->nid,
+                              substream->runtime->channels);
+
+       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+
+       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+}
+
+static struct hda_pcm_stream generic_hdmi_pcm_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .ops = {
+               .open = hdmi_pcm_open,
+               .prepare = generic_hdmi_playback_pcm_prepare,
+       },
+};
+
+static int generic_hdmi_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+       int i;
+
+       codec->num_pcms = spec->num_cvts;
+       codec->pcm_info = info;
+
+       for (i = 0; i < codec->num_pcms; i++, info++) {
+               unsigned int chans;
+               struct hda_pcm_stream *pstr;
+
+               chans = get_wcaps(codec, spec->cvt[i]);
+               chans = get_wcaps_channels(chans);
+
+               info->name = generic_hdmi_pcm_names[i];
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               if (spec->pcm_playback)
+                       *pstr = *spec->pcm_playback;
+               else
+                       *pstr = generic_hdmi_pcm_playback;
+               pstr->nid = spec->cvt[i];
+               if (pstr->channels_max <= 2 && chans && chans <= 16)
+                       pstr->channels_max = chans;
+       }
+
+       return 0;
+}
+
+static int generic_hdmi_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int err;
+       int i;
+
+       for (i = 0; i < codec->num_pcms; i++) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int generic_hdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; spec->pin[i]; i++) {
+               hdmi_enable_output(codec, spec->pin[i]);
+               snd_hda_codec_write(codec, spec->pin[i], 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | spec->pin[i]);
+       }
+       return 0;
+}
+
+static void generic_hdmi_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+
+       kfree(spec);
+}
+
+static struct hda_codec_ops generic_hdmi_patch_ops = {
+       .init                   = generic_hdmi_init,
+       .free                   = generic_hdmi_free,
+       .build_pcms             = generic_hdmi_build_pcms,
+       .build_controls         = generic_hdmi_build_controls,
+       .unsol_event            = hdmi_unsol_event,
+};
+
+static int patch_generic_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int i;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       if (hdmi_parse_codec(codec) < 0) {
+               codec->spec = NULL;
+               kfree(spec);
+               return -EINVAL;
+       }
+       codec->patch_ops = generic_hdmi_patch_ops;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
+
+       init_channel_allocations();
+
+       return 0;
+}
+
+/*
+ * Nvidia specific implementations
+ */
+
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define nvhdmi_master_con_nid_7x       0x04
+#define nvhdmi_master_pin_nid_7x       0x05
+
+static hda_nid_t nvhdmi_con_nids_7x[4] = {
+       /*front, rear, clfe, rear_surr */
+       0x6, 0x8, 0xa, 0xc,
+};
+
+static struct hda_verb nvhdmi_basic_init_7x[] = {
+       /* set audio protect on */
+       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+       /* enable digital output on pin widget */
+       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       {} /* terminator */
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS       16
+#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+        SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS       24
+#define SUPPORTED_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+static int nvhdmi_7x_init(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
+       return 0;
+}
+
+static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       for (i = 0; i < 4; i++) {
+               /* set the stream id */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, 0);
+               /* set the stream format */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_STREAM_FORMAT, 0);
+       }
+
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    unsigned int stream_tag,
+                                    unsigned int format,
+                                    struct snd_pcm_substream *substream)
+{
+       int chs;
+       unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
+       int i;
+
+       mutex_lock(&codec->spdif_mutex);
+
+       chs = substream->runtime->channels;
+       chan = chs ? (chs - 1) : 1;
+
+       switch (chs) {
+       default:
+       case 0:
+       case 2:
+               chanmask = 0x00;
+               break;
+       case 4:
+               chanmask = 0x08;
+               break;
+       case 6:
+               chanmask = 0x0b;
+               break;
+       case 8:
+               chanmask = 0x13;
+               break;
+       }
+       dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
+       dataDCC2 = 0x2;
+
+       /* set the Audio InforFrame Channel Allocation */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Channel_Allocation, chanmask);
+
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+
+       /* set the stream id */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+       /* set the stream format */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_STREAM_FORMAT, format);
+
+       /* turn on again (if needed) */
+       /* enable and set the channel status audio/data flag */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & 0xff);
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (chs == 2)
+                       channel_id = 0;
+               else
+                       channel_id = i * 2;
+
+               /* turn off SPDIF once;
+                *otherwise the IEC958 bits won't be updated
+                */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE))
+                       snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+               /* set the stream id */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_CHANNEL_STREAMID,
+                               (stream_tag << 4) | channel_id);
+               /* set the stream format */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_STREAM_FORMAT,
+                               format);
+               /* turn on again (if needed) */
+               /* enable and set the channel status audio/data flag */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_1,
+                                       codec->spdif_ctls & 0xff);
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+               }
+       }
+
+       /* set the Audio Info Frame Checksum */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Info_Frame_Checksum,
+                       (0x71 - chan - chanmask));
+
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
+}
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = nvhdmi_master_con_nid_7x,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = nvhdmi_8ch_7x_pcm_close,
+               .prepare = nvhdmi_8ch_7x_pcm_prepare
+       },
+};
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = nvhdmi_master_con_nid_7x,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = simple_playback_pcm_close,
+               .prepare = simple_playback_pcm_prepare
+       },
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = nvhdmi_7x_init,
+       .free = generic_hdmi_free,
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = nvhdmi_7x_init,
+       .free = generic_hdmi_free,
+};
+
+static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_generic_hdmi(codec);
+
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       spec->old_pin_detect = 1;
+       return 0;
+}
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;  /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
+       spec->old_pin_detect = 1;
+       spec->num_cvts = 1;
+       spec->cvt[0] = nvhdmi_master_con_nid_7x;
+       spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
+
+       codec->patch_ops = nvhdmi_patch_ops_2ch;
+
+       return 0;
+}
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_nvhdmi_2ch(codec);
+
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       spec->multiout.max_channels = 8;
+       spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
+       codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
+       return 0;
+}
+
+/*
+ * ATI-specific implementations
+ *
+ * FIXME: we may omit the whole this and use the generic code once after
+ * it's confirmed to work.
+ */
+
+#define ATIHDMI_CVT_NID                0x02    /* audio converter */
+#define ATIHDMI_PIN_NID                0x03    /* HDMI output pin */
+
+static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int chans = substream->runtime->channels;
+       int i, err;
+
+       err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
+                                         substream);
+       if (err < 0)
+               return err;
+       snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
+                           chans - 1);
+       /* FIXME: XXX */
+       for (i = 0; i < chans; i++) {
+               snd_hda_codec_write(codec, spec->cvt[0], 0,
+                                   AC_VERB_SET_HDMI_CHAN_SLOT,
+                                   (i << 4) | i);
+       }
+       return 0;
+}
+
+static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = ATIHDMI_CVT_NID,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = simple_playback_pcm_close,
+               .prepare = atihdmi_playback_pcm_prepare
+       },
+};
+
+static struct hda_verb atihdmi_basic_init[] = {
+       /* enable digital output on pin widget */
+       { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {} /* terminator */
+};
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       snd_hda_sequence_write(codec, atihdmi_basic_init);
+       /* SI codec requires to unmute the pin */
+       if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, spec->pin[0], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_UNMUTE);
+       return 0;
+}
+
+static struct hda_codec_ops atihdmi_patch_ops = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = atihdmi_init,
+       .free = generic_hdmi_free,
+};
+
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;      /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
+       spec->num_cvts = 1;
+       spec->cvt[0] = ATIHDMI_CVT_NID;
+       spec->pin[0] = ATIHDMI_PIN_NID;
+       spec->pcm_playback = &atihdmi_pcm_digital_playback;
+
+       codec->patch_ops = atihdmi_patch_ops;
+
+       return 0;
+}
+
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_hdmi[] = {
+{ .id = 0x1002793c, .name = "RS600 HDMI",      .patch = patch_atihdmi },
+{ .id = 0x10027919, .name = "RS600 HDMI",      .patch = patch_atihdmi },
+{ .id = 0x1002791a, .name = "RS690/780 HDMI",  .patch = patch_atihdmi },
+{ .id = 0x1002aa01, .name = "R6xx HDMI",       .patch = patch_atihdmi },
+{ .id = 0x10951390, .name = "SiI1390 HDMI",    .patch = patch_generic_hdmi },
+{ .id = 0x10951392, .name = "SiI1392 HDMI",    .patch = patch_generic_hdmi },
+{ .id = 0x17e80047, .name = "Chrontel HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x10de0002, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0003, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0005, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0006, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0007, .name = "MCP79/7A HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000c, .name = "MCP89 HDMI",      .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0067, .name = "MCP67 HDMI",      .patch = patch_nvhdmi_2ch },
+{ .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
+{ .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862801, .name = "Bearlake HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862802, .name = "Cantiga HDMI",    .patch = patch_generic_hdmi },
+{ .id = 0x80862803, .name = "Eaglelake HDMI",  .patch = patch_generic_hdmi },
+{ .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_generic_hdmi },
+{ .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_generic_hdmi },
+{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0003");
+MODULE_ALIAS("snd-hda-codec-id:10de0005");
+MODULE_ALIAS("snd-hda-codec-id:10de0006");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+MODULE_ALIAS("snd-hda-codec-id:10de000a");
+MODULE_ALIAS("snd-hda-codec-id:10de000b");
+MODULE_ALIAS("snd-hda-codec-id:10de000c");
+MODULE_ALIAS("snd-hda-codec-id:10de000d");
+MODULE_ALIAS("snd-hda-codec-id:10de0010");
+MODULE_ALIAS("snd-hda-codec-id:10de0011");
+MODULE_ALIAS("snd-hda-codec-id:10de0012");
+MODULE_ALIAS("snd-hda-codec-id:10de0013");
+MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0018");
+MODULE_ALIAS("snd-hda-codec-id:10de0019");
+MODULE_ALIAS("snd-hda-codec-id:10de001a");
+MODULE_ALIAS("snd-hda-codec-id:10de001b");
+MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0040");
+MODULE_ALIAS("snd-hda-codec-id:10de0041");
+MODULE_ALIAS("snd-hda-codec-id:10de0042");
+MODULE_ALIAS("snd-hda-codec-id:10de0043");
+MODULE_ALIAS("snd-hda-codec-id:10de0044");
+MODULE_ALIAS("snd-hda-codec-id:10de0067");
+MODULE_ALIAS("snd-hda-codec-id:10de8001");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+MODULE_ALIAS("snd-hda-codec-id:80860054");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80862805");
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HDMI HD-audio codec");
+MODULE_ALIAS("snd-hda-codec-intelhdmi");
+MODULE_ALIAS("snd-hda-codec-nvhdmi");
+MODULE_ALIAS("snd-hda-codec-atihdmi");
+
+static struct hda_codec_preset_list intel_list = {
+       .preset = snd_hda_preset_hdmi,
+       .owner = THIS_MODULE,
+};
+
+static int __init patch_hdmi_init(void)
+{
+       return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_hdmi_exit(void)
+{
+       snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_hdmi_init)
+module_exit(patch_hdmi_exit)
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
deleted file mode 100644 (file)
index 36a9b83..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *
- *  patch_intelhdmi.c - Patch for Intel HDMI codecs
- *
- *  Copyright(c) 2008 Intel Corporation. All rights reserved.
- *
- *  Authors:
- *                     Jiang Zhe <zhe.jiang@intel.com>
- *                     Wu Fengguang <wfg@linux.intel.com>
- *
- *  Maintained by:
- *                     Wu Fengguang <wfg@linux.intel.com>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software Foundation,
- *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-/*
- * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support two independent pipes, each of them can be connected to one or
- * more ports (DVI, HDMI or DisplayPort).
- *
- * The HDA correspondence of pipes/ports are converter/pin nodes.
- */
-#define MAX_HDMI_CVTS  3
-#define MAX_HDMI_PINS  3
-
-#include "patch_hdmi.c"
-
-static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
-       "INTEL HDMI 0",
-       "INTEL HDMI 1",
-       "INTEL HDMI 2",
-};
-
-/*
- * HDMI callbacks
- */
-
-static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          unsigned int stream_tag,
-                                          unsigned int format,
-                                          struct snd_pcm_substream *substream)
-{
-       hdmi_set_channel_count(codec, hinfo->nid,
-                              substream->runtime->channels);
-
-       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
-       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static struct hda_pcm_stream intel_hdmi_pcm_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .ops = {
-               .open = hdmi_pcm_open,
-               .prepare = intel_hdmi_playback_pcm_prepare,
-       },
-};
-
-static int intel_hdmi_build_pcms(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
-
-       codec->num_pcms = spec->num_cvts;
-       codec->pcm_info = info;
-
-       for (i = 0; i < codec->num_pcms; i++, info++) {
-               unsigned int chans;
-
-               chans = get_wcaps(codec, spec->cvt[i]);
-               chans = get_wcaps_channels(chans);
-
-               info->name = intel_hdmi_pcm_names[i];
-               info->pcm_type = HDA_PCM_TYPE_HDMI;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                                                       intel_hdmi_pcm_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-       }
-
-       return 0;
-}
-
-static int intel_hdmi_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       for (i = 0; i < codec->num_pcms; i++) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int intel_hdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; spec->pin[i]; i++) {
-               hdmi_enable_output(codec, spec->pin[i]);
-               snd_hda_codec_write(codec, spec->pin[i], 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | spec->pin[i]);
-       }
-       return 0;
-}
-
-static void intel_hdmi_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
-
-       kfree(spec);
-}
-
-static struct hda_codec_ops intel_hdmi_patch_ops = {
-       .init                   = intel_hdmi_init,
-       .free                   = intel_hdmi_free,
-       .build_pcms             = intel_hdmi_build_pcms,
-       .build_controls         = intel_hdmi_build_controls,
-       .unsol_event            = hdmi_unsol_event,
-};
-
-static int patch_intel_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int i;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       if (hdmi_parse_codec(codec) < 0) {
-               codec->spec = NULL;
-               kfree(spec);
-               return -EINVAL;
-       }
-       codec->patch_ops = intel_hdmi_patch_ops;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
-       init_channel_allocations();
-
-       return 0;
-}
-
-static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
-{ .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_intel_hdmi },
-{ .id = 0x80862801, .name = "Bearlake HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80862802, .name = "Cantiga HDMI",    .patch = patch_intel_hdmi },
-{ .id = 0x80862803, .name = "Eaglelake HDMI",  .patch = patch_intel_hdmi },
-{ .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_intel_hdmi },
-{ .id = 0x10951392, .name = "SiI1392 HDMI",    .patch = patch_intel_hdmi },
-{} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:808629fb");
-MODULE_ALIAS("snd-hda-codec-id:80862801");
-MODULE_ALIAS("snd-hda-codec-id:80862802");
-MODULE_ALIAS("snd-hda-codec-id:80862803");
-MODULE_ALIAS("snd-hda-codec-id:80862804");
-MODULE_ALIAS("snd-hda-codec-id:80862805");
-MODULE_ALIAS("snd-hda-codec-id:80860054");
-MODULE_ALIAS("snd-hda-codec-id:10951392");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
-
-static struct hda_codec_preset_list intel_list = {
-       .preset = snd_hda_preset_intelhdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_intelhdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&intel_list);
-}
-
-static void __exit patch_intelhdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&intel_list);
-}
-
-module_init(patch_intelhdmi_init)
-module_exit(patch_intelhdmi_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
deleted file mode 100644 (file)
index baa108b..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for NVIDIA HDMI codecs
- *
- * Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
- * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
- *
- *
- *  This driver is free software; you can redistribute it and/or modify
- *  it under the terms of the 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 driver is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You 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/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-#define MAX_HDMI_CVTS  1
-#define MAX_HDMI_PINS  1
-
-#include "patch_hdmi.c"
-
-static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
-       "NVIDIA HDMI",
-};
-
-/* define below to restrict the supported rates and formats */
-/* #define LIMITED_RATE_FMT_SUPPORT */
-
-enum HDACodec {
-       HDA_CODEC_NVIDIA_MCP7X,
-       HDA_CODEC_NVIDIA_MCP89,
-       HDA_CODEC_NVIDIA_GT21X,
-       HDA_CODEC_INVALID
-};
-
-#define Nv_VERB_SET_Channel_Allocation          0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
-#define Nv_VERB_SET_Audio_Protection_On         0xF98
-#define Nv_VERB_SET_Audio_Protection_Off        0xF99
-
-#define nvhdmi_master_con_nid_7x       0x04
-#define nvhdmi_master_pin_nid_7x       0x05
-
-#define nvhdmi_master_con_nid_89       0x04
-#define nvhdmi_master_pin_nid_89       0x05
-
-static hda_nid_t nvhdmi_con_nids_7x[4] = {
-       /*front, rear, clfe, rear_surr */
-       0x6, 0x8, 0xa, 0xc,
-};
-
-static struct hda_verb nvhdmi_basic_init_7x[] = {
-       /* set audio protect on */
-       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-       /* enable digital output on pin widget */
-       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       {} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS       16
-#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_RATES \
-       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
-        SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS       24
-#define SUPPORTED_FORMATS \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-/*
- * Controls
- */
-static int nvhdmi_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; i < codec->num_pcms; i++) {
-                       err = snd_hda_create_spdif_out_ctls(codec,
-                                                           spec->cvt[i]);
-                       if (err < 0)
-                               return err;
-               }
-       } else {
-               err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int nvhdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; spec->pin[i]; i++) {
-                       hdmi_enable_output(codec, spec->pin[i]);
-                       snd_hda_codec_write(codec, spec->pin[i], 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | spec->pin[i]);
-               }
-       } else {
-               snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
-       }
-       return 0;
-}
-
-static void nvhdmi_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; i < spec->num_pins; i++)
-                       snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
-       }
-
-       kfree(spec);
-}
-
-/*
- * Digital out
- */
-static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
-                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-       for (i = 0; i < 4; i++) {
-               /* set the stream id */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_CHANNEL_STREAMID, 0);
-               /* set the stream format */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_STREAM_FORMAT, 0);
-       }
-
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       hdmi_set_channel_count(codec, hinfo->nid,
-                              substream->runtime->channels);
-
-       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
-       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       int chs;
-       unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
-       int i;
-
-       mutex_lock(&codec->spdif_mutex);
-
-       chs = substream->runtime->channels;
-       chan = chs ? (chs - 1) : 1;
-
-       switch (chs) {
-       default:
-       case 0:
-       case 2:
-               chanmask = 0x00;
-               break;
-       case 4:
-               chanmask = 0x08;
-               break;
-       case 6:
-               chanmask = 0x0b;
-               break;
-       case 8:
-               chanmask = 0x13;
-               break;
-       }
-       dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
-       dataDCC2 = 0x2;
-
-       /* set the Audio InforFrame Channel Allocation */
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Channel_Allocation, chanmask);
-
-       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-
-       /* set the stream id */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
-       /* set the stream format */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_STREAM_FORMAT, format);
-
-       /* turn on again (if needed) */
-       /* enable and set the channel status audio/data flag */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & 0xff);
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-       }
-
-       for (i = 0; i < 4; i++) {
-               if (chs == 2)
-                       channel_id = 0;
-               else
-                       channel_id = i * 2;
-
-               /* turn off SPDIF once;
-                *otherwise the IEC958 bits won't be updated
-                */
-               if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE))
-                       snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-               /* set the stream id */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_CHANNEL_STREAMID,
-                               (stream_tag << 4) | channel_id);
-               /* set the stream format */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_STREAM_FORMAT,
-                               format);
-               /* turn on again (if needed) */
-               /* enable and set the channel status audio/data flag */
-               if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_1,
-                                       codec->spdif_ctls & 0xff);
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-               }
-       }
-
-       /* set the Audio Info Frame Checksum */
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Info_Frame_Checksum,
-                       (0x71 - chan - chanmask));
-
-       mutex_unlock(&codec->spdif_mutex);
-       return 0;
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                       format, substream);
-}
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
-       .substreams = 1,
-       .channels_min = 2,
-       .ops = {
-               .open = hdmi_pcm_open,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
-       },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       .nid = nvhdmi_master_con_nid_7x,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
-       .ops = {
-               .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close_8ch_7x,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch
-       },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = nvhdmi_master_con_nid_7x,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
-       .ops = {
-               .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close_2ch,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_2ch
-       },
-};
-
-static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
-
-       codec->num_pcms = spec->num_cvts;
-       codec->pcm_info = info;
-
-       for (i = 0; i < codec->num_pcms; i++, info++) {
-               unsigned int chans;
-
-               chans = get_wcaps(codec, spec->cvt[i]);
-               chans = get_wcaps_channels(chans);
-
-               info->name = nvhdmi_pcm_names[i];
-               info->pcm_type = HDA_PCM_TYPE_HDMI;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_8ch_89;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-       }
-
-       return 0;
-}
-
-static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "NVIDIA HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_8ch_7x;
-
-       return 0;
-}
-
-static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "NVIDIA HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_2ch;
-
-       return 0;
-}
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_8ch_89,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-       .unsol_event = hdmi_unsol_event,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_8ch_7x,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_2ch,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-};
-
-static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int i;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
-       spec->old_pin_detect = 1;
-
-       if (hdmi_parse_codec(codec) < 0) {
-               codec->spec = NULL;
-               kfree(spec);
-               return -EINVAL;
-       }
-       codec->patch_ops = nvhdmi_patch_ops_8ch_89;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
-       init_channel_allocations();
-
-       return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;  /* no analog */
-       spec->multiout.max_channels = 8;
-       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
-       spec->old_pin_detect = 1;
-
-       codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
-
-       return 0;
-}
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;  /* no analog */
-       spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
-       spec->old_pin_detect = 1;
-
-       codec->patch_ops = nvhdmi_patch_ops_2ch;
-
-       return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-       { .id = 0x10de0002, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0003, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0005, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0006, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0007, .name = "MCP79/7A HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000c, .name = "MCP89 HDMI",     .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0067, .name = "MCP67 HDMI",     .patch = patch_nvhdmi_2ch },
-       { .id = 0x10de8001, .name = "MCP73 HDMI",     .patch = patch_nvhdmi_2ch },
-       {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:10de0002");
-MODULE_ALIAS("snd-hda-codec-id:10de0003");
-MODULE_ALIAS("snd-hda-codec-id:10de0005");
-MODULE_ALIAS("snd-hda-codec-id:10de0006");
-MODULE_ALIAS("snd-hda-codec-id:10de0007");
-MODULE_ALIAS("snd-hda-codec-id:10de000a");
-MODULE_ALIAS("snd-hda-codec-id:10de000b");
-MODULE_ALIAS("snd-hda-codec-id:10de000c");
-MODULE_ALIAS("snd-hda-codec-id:10de000d");
-MODULE_ALIAS("snd-hda-codec-id:10de0010");
-MODULE_ALIAS("snd-hda-codec-id:10de0011");
-MODULE_ALIAS("snd-hda-codec-id:10de0012");
-MODULE_ALIAS("snd-hda-codec-id:10de0013");
-MODULE_ALIAS("snd-hda-codec-id:10de0014");
-MODULE_ALIAS("snd-hda-codec-id:10de0018");
-MODULE_ALIAS("snd-hda-codec-id:10de0019");
-MODULE_ALIAS("snd-hda-codec-id:10de001a");
-MODULE_ALIAS("snd-hda-codec-id:10de001b");
-MODULE_ALIAS("snd-hda-codec-id:10de001c");
-MODULE_ALIAS("snd-hda-codec-id:10de0040");
-MODULE_ALIAS("snd-hda-codec-id:10de0041");
-MODULE_ALIAS("snd-hda-codec-id:10de0042");
-MODULE_ALIAS("snd-hda-codec-id:10de0043");
-MODULE_ALIAS("snd-hda-codec-id:10de0044");
-MODULE_ALIAS("snd-hda-codec-id:10de0067");
-MODULE_ALIAS("snd-hda-codec-id:10de8001");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
-
-static struct hda_codec_preset_list nvhdmi_list = {
-       .preset = snd_hda_preset_nvhdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_nvhdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&nvhdmi_list);
-}
-
-static void __exit patch_nvhdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&nvhdmi_list);
-}
-
-module_init(patch_nvhdmi_init)
-module_exit(patch_nvhdmi_exit)
index a432e6efd19bbe7bbce3ad9b6607c44661f912cf..5f00589cb791aebed2d7aa1f0bd908819b9123b8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -282,6 +283,12 @@ struct alc_mic_route {
        unsigned char amix_idx;
 };
 
+struct alc_jack {
+       hda_nid_t nid;
+       int type;
+       struct snd_jack *jack;
+};
+
 #define MUX_IDX_UNDEF  ((unsigned char)-1)
 
 struct alc_customize_define {
@@ -294,6 +301,7 @@ struct alc_customize_define {
        unsigned int  platform_type:1;
        unsigned int  swap:1;
        unsigned int  override:1;
+       unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
 };
 
 struct alc_spec {
@@ -357,6 +365,9 @@ struct alc_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
+       /* jack detection */
+       struct snd_array jacks;
+
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct alc_customize_define cdefine;
@@ -383,6 +394,7 @@ struct alc_spec {
        unsigned int no_analog :1; /* digital I/O only */
        unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
        int init_amp;
+       int codec_variant;      /* flag for other variants */
 
        /* for virtual master */
        hda_nid_t vmaster_nid;
@@ -846,7 +858,7 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int val = PIN_IN;
 
-       if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+       if (auto_pin_type == AUTO_PIN_MIC) {
                unsigned int pincap;
                unsigned int oldval;
                oldval = snd_hda_codec_read(codec, nid, 0,
@@ -866,6 +878,28 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
 }
 
+static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (!cfg->line_outs) {
+               while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->line_out_pins[cfg->line_outs])
+                       cfg->line_outs++;
+       }
+       if (!cfg->speaker_outs) {
+               while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->speaker_pins[cfg->speaker_outs])
+                       cfg->speaker_outs++;
+       }
+       if (!cfg->hp_outs) {
+               while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->hp_pins[cfg->hp_outs])
+                       cfg->hp_outs++;
+       }
+}
+
 /*
  */
 static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
@@ -934,6 +968,8 @@ static void setup_preset(struct hda_codec *codec,
 
        if (preset->setup)
                preset->setup(codec);
+
+       alc_fixup_autocfg_pin_nums(codec);
 }
 
 /* Enable GPIO mask and set output */
@@ -990,25 +1026,136 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-static void alc_automute_pin(struct hda_codec *codec)
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+static void alc_free_jack_priv(struct snd_jack *jack)
+{
+       struct alc_jack *jacks = jack->private_data;
+       jacks->nid = 0;
+       jacks->jack = NULL;
+}
+
+static int alc_add_jack(struct hda_codec *codec,
+               hda_nid_t nid, int type)
+{
+       struct alc_spec *spec;
+       struct alc_jack *jack;
+       const char *name;
+       int err;
+
+       spec = codec->spec;
+       snd_array_init(&spec->jacks, sizeof(*jack), 32);
+       jack = snd_array_new(&spec->jacks);
+       if (!jack)
+               return -ENOMEM;
+
+       jack->nid = nid;
+       jack->type = type;
+       name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
+
+       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+       if (err < 0)
+               return err;
+       jack->jack->private_data = jack;
+       jack->jack->private_free = alc_free_jack_priv;
+       return 0;
+}
+
+static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int nid = spec->autocfg.hp_pins[0];
+       struct alc_jack *jacks = spec->jacks.list;
+
+       if (jacks) {
+               int i;
+               for (i = 0; i < spec->jacks.used; i++) {
+                       if (jacks->nid == nid) {
+                               unsigned int present;
+                               present = snd_hda_jack_detect(codec, nid);
+
+                               present = (present) ? jacks->type : 0;
+
+                               snd_jack_report(jacks->jack, present);
+                       }
+                       jacks++;
+               }
+       }
+}
+
+static int alc_init_jacks(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err;
+       unsigned int hp_nid = spec->autocfg.hp_pins[0];
+       unsigned int mic_nid = spec->ext_mic.pin;
+
+       if (hp_nid) {
+               err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+               if (err < 0)
+                       return err;
+               alc_report_jack(codec, hp_nid);
+       }
+
+       if (mic_nid) {
+               err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+               if (err < 0)
+                       return err;
+               alc_report_jack(codec, mic_nid);
+       }
+
+       return 0;
+}
+#else
+static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+}
+
+static inline int alc_init_jacks(struct hda_codec *codec)
+{
+       return 0;
+}
+#endif
+
+static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int mute;
+       hda_nid_t nid;
        int i;
 
-       if (!nid)
-               return;
-       spec->jack_present = snd_hda_jack_detect(codec, nid);
+       spec->jack_present = 0;
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+               nid = spec->autocfg.hp_pins[i];
+               if (!nid)
+                       break;
+               if (snd_hda_jack_detect(codec, nid)) {
+                       spec->jack_present = 1;
+                       break;
+               }
+               alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+       }
+
+       mute = spec->jack_present ? HDA_AMP_MUTE : 0;
+       /* Toggle internal speakers muting */
        for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
                nid = spec->autocfg.speaker_pins[i];
                if (!nid)
                        break;
-               snd_hda_codec_write(codec, nid, 0,
+               if (pinctl) {
+                       snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    spec->jack_present ? 0 : PIN_OUT);
+               } else {
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               }
        }
 }
 
+static void alc_automute_pin(struct hda_codec *codec)
+{
+       alc_automute_speaker(codec, 1);
+}
+
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
                                hda_nid_t nid)
 {
@@ -1090,6 +1237,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL,
                                          alive->mux_idx);
        }
+       alc_report_jack(codec, spec->ext_mic.pin);
 
        /* FIXME: analog mixer */
 }
@@ -1236,24 +1384,35 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
 
-       if (!spec->autocfg.hp_pins[0])
-               return;
+       if (!cfg->hp_pins[0]) {
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+                       return;
+       }
 
-       if (!spec->autocfg.speaker_pins[0]) {
-               if (spec->autocfg.line_out_pins[0] &&
-                   spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       spec->autocfg.speaker_pins[0] =
-                               spec->autocfg.line_out_pins[0];
-               else
+       if (!cfg->speaker_pins[0]) {
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
                        return;
+               memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                      sizeof(cfg->speaker_pins));
+               cfg->speaker_outs = cfg->line_outs;
        }
 
-       snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
-                   spec->autocfg.hp_pins[0]);
-       snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+       if (!cfg->hp_pins[0]) {
+               memcpy(cfg->hp_pins, cfg->line_out_pins,
+                      sizeof(cfg->hp_pins));
+               cfg->hp_outs = cfg->line_outs;
+       }
+
+       for (i = 0; i < cfg->hp_outs; i++) {
+               snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+                           cfg->hp_pins[i]);
+               snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
                                  AC_USRSP_EN | ALC880_HP_EVENT);
+       }
        spec->unsol_event = alc_sku_unsol_event;
 }
 
@@ -1265,30 +1424,28 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        int i;
 
        /* there must be only two mic inputs exclusively */
-       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
-               if (cfg->input_pins[i])
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
                        return;
 
        fixed = ext = 0;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                unsigned int defcfg;
-               if (!nid)
-                       return;
                defcfg = snd_hda_codec_get_pincfg(codec, nid);
-               switch (get_defcfg_connect(defcfg)) {
-               case AC_JACK_PORT_FIXED:
+               switch (snd_hda_get_input_pin_attr(defcfg)) {
+               case INPUT_PIN_ATTR_INT:
                        if (fixed)
                                return; /* already occupied */
                        fixed = nid;
                        break;
-               case AC_JACK_PORT_COMPLEX:
+               case INPUT_PIN_ATTR_UNUSED:
+                       return; /* invalid entry */
+               default:
                        if (ext)
                                return; /* already occupied */
                        ext = nid;
                        break;
-               default:
-                       return; /* invalid entry */
                }
        }
        if (!ext || !fixed)
@@ -1308,6 +1465,11 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        spec->unsol_event = alc_sku_unsol_event;
 }
 
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
 static int alc_auto_parse_customize_define(struct hda_codec *codec)
 {
        unsigned int ass, tmp, i;
@@ -1316,6 +1478,13 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
 
        spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
 
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return -1;
+               goto do_sku;
+       }
+
        ass = codec->subsystem_id & 0xffff;
        if (ass != codec->bus->pci->subsystem_device && (ass & 1))
                goto do_sku;
@@ -1383,6 +1552,13 @@ static int alc_subsystem_id(struct hda_codec *codec,
        unsigned nid;
        struct alc_spec *spec = codec->spec;
 
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return 0;
+               goto do_sku;
+       }
+
        ass = codec->subsystem_id & 0xffff;
        if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
                goto do_sku;
@@ -1502,6 +1678,7 @@ struct alc_pincfg {
 };
 
 struct alc_fixup {
+       unsigned int sku;
        const struct alc_pincfg *pins;
        const struct hda_verb *verbs;
 };
@@ -1512,12 +1689,22 @@ static void alc_pick_fixup(struct hda_codec *codec,
                           int pre_init)
 {
        const struct alc_pincfg *cfg;
+       struct alc_spec *spec;
 
        quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
        if (!quirk)
                return;
        fix += quirk->value;
        cfg = fix->pins;
+       if (pre_init && fix->sku) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+               snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
+                           codec->chip_name, quirk->name);
+#endif
+               spec = codec->spec;
+               spec->cdefine.sku_cfg = fix->sku;
+               spec->cdefine.fixup = 1;
+       }
        if (pre_init && cfg) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
@@ -1546,6 +1733,15 @@ static int alc_read_coef_idx(struct hda_codec *codec,
        return val;
 }
 
+static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
+                                                       unsigned int coef_val)
+{
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+                           coef_idx);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
+                           coef_val);
+}
+
 /* set right pin controls for digital I/O */
 static void alc_auto_init_digital(struct hda_codec *codec)
 {
@@ -1723,31 +1919,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 
 static void alc_automute_amp(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       unsigned int mute;
-       hda_nid_t nid;
-       int i;
-
-       spec->jack_present = 0;
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-               nid = spec->autocfg.hp_pins[i];
-               if (!nid)
-                       break;
-               if (snd_hda_jack_detect(codec, nid)) {
-                       spec->jack_present = 1;
-                       break;
-               }
-       }
-
-       mute = spec->jack_present ? HDA_AMP_MUTE : 0;
-       /* Toggle internal speakers muting */
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-               nid = spec->autocfg.speaker_pins[i];
-               if (!nid)
-                       break;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
+       alc_automute_speaker(codec, 0);
 }
 
 static void alc_automute_amp_unsol_event(struct hda_codec *codec,
@@ -3602,10 +3774,7 @@ static int alc_init(struct hda_codec *codec)
        if (spec->init_hook)
                spec->init_hook(codec);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+       hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
@@ -4001,10 +4170,7 @@ static int alc_resume(struct hda_codec *codec)
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+       hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 #endif
@@ -4729,7 +4895,7 @@ static struct snd_kcontrol_new alc880_control_templates[] = {
 
 /* add dynamic controls */
 static int add_control(struct alc_spec *spec, int type, const char *name,
-                      unsigned long val)
+                      int cidx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -4741,6 +4907,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
+       knew->index = cidx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
@@ -4749,17 +4916,21 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
 
 static int add_control_with_pfx(struct alc_spec *spec, int type,
                                const char *pfx, const char *dir,
-                               const char *sfx, unsigned long val)
+                               const char *sfx, int cidx, unsigned long val)
 {
        char name[32];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-       return add_control(spec, type, name, val);
+       return add_control(spec, type, name, cidx, val);
 }
 
-#define add_pb_vol_ctrl(spec, type, pfx, val) \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
-#define add_pb_sw_ctrl(spec, type, pfx, val) \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
 
 #define alc880_is_fixed_pin(nid)       ((nid) >= 0x14 && (nid) <= 0x17)
 #define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
@@ -4912,16 +5083,16 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
-                           const char *ctlname,
+                           const char *ctlname, int ctlidx,
                            int idx, hda_nid_t mix_nid)
 {
        int err;
 
-       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
+       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
-       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
+       err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -4942,20 +5113,27 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
 {
        struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx;
+       int i, err, idx, type, type_idx = 0;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
+       for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t pin;
+               const char *label;
 
-               pin = cfg->input_pins[i];
+               pin = cfg->inputs[i].pin;
                if (!alc_is_input_pin(codec, pin))
                        continue;
 
+               type = cfg->inputs[i].type;
+               if (i > 0 && type == cfg->inputs[i - 1].type)
+                       type_idx++;
+               else
+                       type_idx = 0;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
                if (mixer) {
                        idx = get_connection_index(codec, mixer, pin);
                        if (idx >= 0) {
                                err = new_analog_input(spec, pin,
-                                                      auto_pin_cfg_labels[i],
+                                                      label, type_idx,
                                                       idx, mixer);
                                if (err < 0)
                                        return err;
@@ -4967,12 +5145,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
                idx = get_connection_index(codec, cap1, pin);
                if (idx < 0 && cap2)
                        idx = get_connection_index(codec, cap2, pin);
-               if (idx >= 0) {
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index = idx;
-                       imux->num_items++;
-               }
+               if (idx >= 0)
+                       snd_hda_add_imux_item(imux, label, idx, NULL);
        }
        return 0;
 }
@@ -5044,12 +5218,13 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
 static void alc880_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC880_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -5214,19 +5389,13 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
 static void fixup_single_adc(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t pin = 0;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
        /* search for the input pin; there must be only one */
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (spec->autocfg.input_pins[i]) {
-                       pin = spec->autocfg.input_pins[i];
-                       break;
-               }
-       }
-       if (!pin)
+       if (cfg->num_inputs != 1)
                return;
-       i = init_capsrc_for_pin(codec, pin);
+       i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
        if (i >= 0) {
                /* use only this ADC */
                if (spec->capsrc_nids)
@@ -5279,6 +5448,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                                 int num_nids)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int n;
        hda_nid_t fallback_adc = 0, fallback_cap = 0;
 
@@ -5304,10 +5474,8 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                        fallback_adc = adc;
                        fallback_cap = cap;
                }
-               for (i = 0; i < AUTO_PIN_LAST; i++) {
-                       hda_nid_t nid = spec->autocfg.input_pins[i];
-                       if (!nid)
-                               continue;
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       hda_nid_t nid = cfg->inputs[i].pin;
                        for (j = 0; j < nconns; j++) {
                                if (conn[j] == nid)
                                        break;
@@ -5315,7 +5483,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                        if (j >= nconns)
                                break;
                }
-               if (i >= AUTO_PIN_LAST) {
+               if (i >= cfg->num_inputs) {
                        int num_adcs = spec->num_adc_nids;
                        spec->private_adc_nids[num_adcs] = adc;
                        spec->private_capsrc_nids[num_adcs] = cap;
@@ -6683,12 +6851,13 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
 static void alc260_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x12) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC260_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -6810,14 +6979,12 @@ enum {
        PINFIX_HP_DC5750,
 };
 
-static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
-       { 0x11, 0x90130110 }, /* speaker */
-       { }
-};
-
 static const struct alc_fixup alc260_fixups[] = {
        [PINFIX_HP_DC5750] = {
-               .pins = alc260_hp_dc5750_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x11, 0x90130110 }, /* speaker */
+                       { }
+               }
        },
 };
 
@@ -10461,32 +10628,33 @@ static struct alc_config_preset alc882_presets[] = {
 enum {
        PINFIX_ABIT_AW9D_MAX,
        PINFIX_PB_M5210,
-};
-
-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
-       { 0x15, 0x01080104 }, /* side */
-       { 0x16, 0x01011012 }, /* rear */
-       { 0x17, 0x01016011 }, /* clfe */
-       { }
-};
-
-static const struct hda_verb pb_m5210_verbs[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
-       {}
+       PINFIX_ACER_ASPIRE_7736,
 };
 
 static const struct alc_fixup alc882_fixups[] = {
        [PINFIX_ABIT_AW9D_MAX] = {
-               .pins = alc882_abit_aw9d_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x01080104 }, /* side */
+                       { 0x16, 0x01011012 }, /* rear */
+                       { 0x17, 0x01016011 }, /* clfe */
+                       { }
+               }
        },
        [PINFIX_PB_M5210] = {
-               .verbs = pb_m5210_verbs
+               .verbs = (const struct hda_verb[]) {
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
+               }
+       },
+       [PINFIX_ACER_ASPIRE_7736] = {
+               .sku = ALC_FIXUP_SKU_IGNORE,
        },
 };
 
 static struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
        {}
 };
 
@@ -10535,16 +10703,21 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t pin, dac;
+       int i;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin) {
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+               pin = spec->autocfg.hp_pins[i];
+               if (!pin)
+                       break;
                dac = spec->multiout.hp_nid;
                if (!dac)
                        dac = spec->multiout.dac_nids[0]; /* to front */
                alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
        }
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin) {
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+               pin = spec->autocfg.speaker_pins[i];
+               if (!pin)
+                       break;
                dac = spec->multiout.extra_out_nid[0];
                if (!dac)
                        dac = spec->multiout.dac_nids[0]; /* to front */
@@ -10555,13 +10728,12 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
 static void alc882_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (!nid)
-                       continue;
-               alc_set_input_pin(codec, nid, i);
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -10623,24 +10795,23 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
 static int alc_auto_add_mic_boost(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
        hda_nid_t nid;
 
-       nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
-       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Mic Boost",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       }
-       nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
-       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Front Mic Boost",
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type > AUTO_PIN_MIC)
+                       break;
+               nid = cfg->inputs[i].pin;
+               if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+                       char label[32];
+                       snprintf(label, sizeof(label), "%s Boost",
+                                hda_get_autocfg_input_label(codec, cfg, i));
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
+                       if (err < 0)
+                               return err;
+               }
        }
        return 0;
 }
@@ -10726,8 +10897,6 @@ static int patch_alc882(struct hda_codec *codec)
 
        codec->spec = spec;
 
-       alc_auto_parse_customize_define(codec);
-
        switch (codec->vendor_id) {
        case 0x10ec0882:
        case 0x10ec0885:
@@ -10755,6 +10924,8 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config == ALC882_AUTO)
                alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
 
+       alc_auto_parse_customize_define(codec);
+
        if (board_config == ALC882_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc882_parse_auto_config(codec);
@@ -10835,6 +11006,8 @@ static int patch_alc882(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC882_AUTO)
                spec->init_hook = alc882_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc882_loopbacks;
@@ -11831,7 +12004,7 @@ static int alc262_check_volbit(hda_nid_t nid)
 }
 
 static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                 const char *pfx, int *vbits)
+                                 const char *pfx, int *vbits, int idx)
 {
        unsigned long val;
        int vbit;
@@ -11846,11 +12019,11 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
                val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
+       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
 }
 
 static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                const char *pfx)
+                                const char *pfx, int idx)
 {
        unsigned long val;
 
@@ -11860,7 +12033,7 @@ static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
                val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
+       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
 }
 
 /* add playback controls from the parsed DAC table */
@@ -11869,7 +12042,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 {
        const char *pfx;
        int vbits;
-       int err;
+       int i, err;
 
        spec->multiout.num_dacs = 1;    /* only use one dac */
        spec->multiout.dac_nids = spec->private_dac_nids;
@@ -11879,39 +12052,52 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                pfx = "Master";
        else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
                pfx = "Speaker";
+       else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
+               pfx = "Headphone";
        else
                pfx = "Front";
-       err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
-       if (err < 0)
-               return err;
-       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
-       if (err < 0)
-               return err;
+       for (i = 0; i < 2; i++) {
+               err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
+               if (err < 0)
+                       return err;
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
+                                                   "Speaker", i);
+                       if (err < 0)
+                               return err;
+               }
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+                       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
+                                                   "Headphone", i);
+                       if (err < 0)
+                               return err;
+               }
+       }
 
        vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
                alc262_check_volbit(cfg->speaker_pins[0]) |
                alc262_check_volbit(cfg->hp_pins[0]);
        if (vbits == 1 || vbits == 2)
                pfx = "Master"; /* only one mixer is used */
-       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               pfx = "Speaker";
-       else
-               pfx = "Front";
        vbits = 0;
-       err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
-                                    &vbits);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
-                                    &vbits);
-       if (err < 0)
-               return err;
+       for (i = 0; i < 2; i++) {
+               err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
+                                            &vbits, i);
+               if (err < 0)
+                       return err;
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
+                                                    "Speaker", &vbits, i);
+                       if (err < 0)
+                               return err;
+               }
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+                       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
+                                                    "Headphone", &vbits, i);
+                       if (err < 0)
+                               return err;
+               }
+       }
        return 0;
 }
 
@@ -12199,6 +12385,35 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
        {}
 };
 
+/*
+ * Pin config fixes
+ */
+enum {
+       PINFIX_FSC_H270,
+};
+
+static const struct alc_fixup alc262_fixups[] = {
+       [PINFIX_FSC_H270] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0221142f }, /* front HP */
+                       { 0x1b, 0x0121141f }, /* rear HP */
+                       { }
+               }
+       },
+       [PINFIX_PB_M5210] = {
+               .verbs = (const struct hda_verb[]) {
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
+               }
+       },
+};
+
+static struct snd_pci_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+       {}
+};
+
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc262_loopbacks       alc880_loopbacks
@@ -12622,6 +12837,9 @@ static int patch_alc262(struct hda_codec *codec)
                board_config = ALC262_AUTO;
        }
 
+       if (board_config == ALC262_AUTO)
+               alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+
        if (board_config == ALC262_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc262_parse_auto_config(codec);
@@ -12690,11 +12908,16 @@ static int patch_alc262(struct hda_codec *codec)
        if (!spec->no_analog && has_cdefine_beep(codec))
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
+       if (board_config == ALC262_AUTO)
+               alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+
        spec->vmaster_nid = 0x0c;
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC262_AUTO)
                spec->init_hook = alc262_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc262_loopbacks;
@@ -13310,8 +13533,10 @@ static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
 static void alc268_auto_init_multi_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
+       int i;
+
+       for (i = 0; i < spec->autocfg.line_outs; i++) {
+               hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
                alc268_auto_set_output_and_unmute(codec, nid, pin_type);
        }
@@ -13321,13 +13546,19 @@ static void alc268_auto_init_hp_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t pin;
+       int i;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
+       for (i = 0; i < spec->autocfg.hp_outs; i++) {
+               pin = spec->autocfg.hp_pins[i];
                alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
+       }
+       for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+               pin = spec->autocfg.speaker_pins[i];
                alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
+       }
+       if (spec->autocfg.mono_out_pin)
+               snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 }
 
 static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
@@ -13766,6 +13997,8 @@ static int patch_alc268(struct hda_codec *codec)
        if (board_config == ALC268_AUTO)
                spec->init_hook = alc268_auto_init;
 
+       alc_init_jacks(codec);
+
        return 0;
 }
 
@@ -14132,6 +14365,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
+       alc_report_jack(codec, nid);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -14386,6 +14620,13 @@ static int alc275_setup_dual_adc(struct hda_codec *codec)
        return 0;
 }
 
+/* different alc269-variants */
+enum {
+       ALC269_TYPE_NORMAL,
+       ALC269_TYPE_ALC259,
+       ALC269_TYPE_ALC271X,
+};
+
 /*
  * BIOS auto configuration
  */
@@ -14403,7 +14644,11 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+       if (spec->codec_variant == ALC269_TYPE_NORMAL)
+               err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+       else
+               err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
+                                                0x22, 0);
        if (err < 0)
                return err;
 
@@ -14414,7 +14659,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
+       if (spec->codec_variant != ALC269_TYPE_NORMAL) {
                add_verb(spec, alc269vb_init_verbs);
                alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
        } else {
@@ -14461,19 +14706,71 @@ static void alc269_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+#ifdef SND_HDA_NEEDS_RESUME
+static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
+{
+       int val = alc_read_coef_idx(codec, 0x04);
+       if (power_up)
+               val |= 1 << 11;
+       else
+               val &= ~(1 << 11);
+       alc_write_coef_idx(codec, 0x04, val);
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+               alc269_toggle_power_output(codec, 0);
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
+
+       alc_shutup(codec);
+       if (spec && spec->power_hook)
+               spec->power_hook(codec);
+       return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
+static int alc269_resume(struct hda_codec *codec)
+{
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
+
+       codec->patch_ops.init(codec);
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               alc269_toggle_power_output(codec, 1);
+               msleep(200);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+               alc269_toggle_power_output(codec, 1);
+
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
+#endif /* SND_HDA_NEEDS_RESUME */
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC269_FIXUP_DELL_M101Z,
 };
 
-static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
-       {}
-};
-
 static const struct alc_fixup alc269_fixups[] = {
        [ALC269_FIXUP_SONY_VAIO] = {
-               .verbs = alc269_sony_vaio_fixup_verbs
+               .verbs = (const struct hda_verb[]) {
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+                       {}
+               }
        },
        [ALC269_FIXUP_DELL_M101Z] = {
                .verbs = (const struct hda_verb[]) {
@@ -14486,8 +14783,7 @@ static const struct alc_fixup alc269_fixups[] = {
 };
 
 static struct snd_pci_quirk alc269_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
+       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        {}
 };
@@ -14689,12 +14985,46 @@ static struct alc_config_preset alc269_presets[] = {
        },
 };
 
+static int alc269_fill_coef(struct hda_codec *codec)
+{
+       int val;
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8817);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8814);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               val = alc_read_coef_idx(codec, 0x04);
+               /* Power up output pin */
+               alc_write_coef_idx(codec, 0x04, val | (1<<11));
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               val = alc_read_coef_idx(codec, 0xd);
+               if ((val & 0x0c00) >> 10 != 0x1) {
+                       /* Capless ramp up clock control */
+                       alc_write_coef_idx(codec, 0xd, val | 1<<10);
+               }
+               val = alc_read_coef_idx(codec, 0x17);
+               if ((val & 0x01c0) >> 6 != 0x4) {
+                       /* Class D power on reset */
+                       alc_write_coef_idx(codec, 0x17, val | 1<<7);
+               }
+       }
+       return 0;
+}
+
 static int patch_alc269(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
        int err;
-       int is_alc269vb = 0;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -14706,14 +15036,18 @@ static int patch_alc269(struct hda_codec *codec)
 
        if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
                if (codec->bus->pci->subsystem_vendor == 0x1025 &&
-                   spec->cdefine.platform_type == 1)
+                   spec->cdefine.platform_type == 1) {
                        alc_codec_rename(codec, "ALC271X");
-               else
+                       spec->codec_variant = ALC269_TYPE_ALC271X;
+               } else {
                        alc_codec_rename(codec, "ALC259");
-               is_alc269vb = 1;
+                       spec->codec_variant = ALC269_TYPE_ALC259;
+               }
        } else
                alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       alc269_fill_coef(codec);
+
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
                                                  alc269_models,
                                                  alc269_cfg_tbl);
@@ -14770,7 +15104,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
        if (!spec->adc_nids) { /* wasn't filled automatically? use default */
-               if (!is_alc269vb) {
+               if (spec->codec_variant != ALC269_TYPE_NORMAL) {
                        spec->adc_nids = alc269_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
                        spec->capsrc_nids = alc269_capsrc_nids;
@@ -14792,8 +15126,16 @@ static int patch_alc269(struct hda_codec *codec)
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       codec->patch_ops.suspend = alc269_suspend;
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+       codec->patch_ops.resume = alc269_resume;
+#endif
        if (board_config == ALC269_AUTO)
                spec->init_hook = alc269_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc269_loopbacks;
@@ -15606,12 +15948,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x0c && nid <= 0x11)
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
        }
 }
 
@@ -15840,15 +16183,13 @@ enum {
        PINFIX_FSC_AMILO_PI1505,
 };
 
-static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
-       { 0x0b, 0x0221101f }, /* HP */
-       { 0x0f, 0x90170310 }, /* speaker */
-       { }
-};
-
 static const struct alc_fixup alc861_fixups[] = {
        [PINFIX_FSC_AMILO_PI1505] = {
-               .pins = alc861_fsc_amilo_pi1505_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x0b, 0x0221101f }, /* HP */
+                       { 0x0f, 0x90170310 }, /* speaker */
+                       { }
+               }
        },
 };
 
@@ -16600,12 +16941,13 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
 static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC861VD_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -16815,16 +17157,14 @@ enum {
 };
 
 /* reset GPIO1 */
-static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-       { }
-};
-
 static const struct alc_fixup alc861vd_fixups[] = {
        [ALC660VD_FIX_ASUS_GPIO1] = {
-               .verbs = alc660vd_fix_asus_gpio1_verbs,
+               .verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+                       { }
+               }
        },
 };
 
@@ -18838,12 +19178,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC662_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -18935,10 +19276,40 @@ static void alc662_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+enum {
+       ALC662_FIXUP_ASPIRE,
+       ALC662_FIXUP_IDEAPAD,
+};
+
+static const struct alc_fixup alc662_fixups[] = {
+       [ALC662_FIXUP_ASPIRE] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x99130112 }, /* subwoofer */
+                       { }
+               }
+       },
+       [ALC662_FIXUP_IDEAPAD] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x17, 0x99130112 }, /* subwoofer */
+                       { }
+               }
+       },
+};
+
+static struct snd_pci_quirk alc662_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+       {}
+};
+
+
+
 static int patch_alc662(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int err, board_config;
+       int coef;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
@@ -18950,12 +19321,15 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
-       if (alc_read_coef_idx(codec, 0) == 0x8020)
+       coef = alc_read_coef_idx(codec, 0);
+       if (coef == 0x8020 || coef == 0x8011)
                alc_codec_rename(codec, "ALC661");
-       else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
-                codec->bus->pci->subsystem_vendor == 0x1025 &&
-                spec->cdefine.platform_type == 1)
+       else if (coef & (1 << 14) &&
+               codec->bus->pci->subsystem_vendor == 0x1025 &&
+               spec->cdefine.platform_type == 1)
                alc_codec_rename(codec, "ALC272X");
+       else if (coef == 0x4011)
+               alc_codec_rename(codec, "ALC656");
 
        board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
                                                  alc662_models,
@@ -18967,6 +19341,7 @@ static int patch_alc662(struct hda_codec *codec)
        }
 
        if (board_config == ALC662_AUTO) {
+               alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
                /* automatic parse from the BIOS config */
                err = alc662_parse_auto_config(codec);
                if (err < 0) {
@@ -19025,8 +19400,13 @@ static int patch_alc662(struct hda_codec *codec)
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC662_AUTO)
+       if (board_config == ALC662_AUTO) {
                spec->init_hook = alc662_auto_init;
+               alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+       }
+
+       alc_init_jacks(codec);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc662_loopbacks;
@@ -19070,6 +19450,39 @@ static hda_nid_t alc680_adc_nids[3] = {
 /*
  * Analog capture ADC cgange
  */
+static void alc680_rec_autoswitch(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int pin_found = 0;
+       int type_found = AUTO_PIN_LAST;
+       hda_nid_t nid;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               if (!(snd_hda_query_pin_caps(codec, nid) &
+                     AC_PINCAP_PRES_DETECT))
+                       continue;
+               if (snd_hda_jack_detect(codec, nid)) {
+                       if (cfg->inputs[i].type < type_found) {
+                               type_found = cfg->inputs[i].type;
+                               pin_found = nid;
+                       }
+               }
+       }
+
+       nid = 0x07;
+       if (pin_found)
+               snd_hda_get_connections(codec, pin_found, &nid, 1);
+
+       if (nid != spec->cur_adc)
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+       spec->cur_adc = nid;
+       snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
+                                  spec->cur_adc_format);
+}
+
 static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct hda_codec *codec,
                                      unsigned int stream_tag,
@@ -19077,24 +19490,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int pre_mic, pre_line;
-
-       pre_mic  = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-       pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]);
 
+       spec->cur_adc = 0x07;
        spec->cur_adc_stream_tag = stream_tag;
        spec->cur_adc_format = format;
 
-       if (pre_mic || pre_line) {
-               if (pre_mic)
-                       snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0,
-                                                                       format);
-               else
-                       snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0,
-                                                                       format);
-       } else
-               snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format);
+       alc680_rec_autoswitch(codec);
        return 0;
 }
 
@@ -19180,6 +19581,7 @@ static struct hda_verb alc680_init_verbs[] = {
 
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT   | AC_USRSP_EN},
        {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
 
        { }
 };
@@ -19192,25 +19594,11 @@ static void alc680_base_setup(struct hda_codec *codec)
        spec->autocfg.hp_pins[0] = 0x16;
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18;
-       spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19;
-}
-
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int present;
-       hda_nid_t new_adc;
-
-       present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-
-       new_adc = present ? 0x8 : 0x7;
-       __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1);
-       snd_hda_codec_setup_stream(codec, new_adc,
-                                  spec->cur_adc_stream_tag, 0,
-                                  spec->cur_adc_format);
-
+       spec->autocfg.num_inputs = 2;
+       spec->autocfg.inputs[0].pin = 0x18;
+       spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
+       spec->autocfg.inputs[1].pin = 0x19;
+       spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
 }
 
 static void alc680_unsol_event(struct hda_codec *codec,
index c16c5ba0fda0fe61387d6924a6b84307b0dedcbb..82ebeb9544fe54296ab3043d9a25e34cee04f415 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -263,6 +264,7 @@ struct sigmatel_spec {
 
        struct sigmatel_mic_route ext_mic;
        struct sigmatel_mic_route int_mic;
+       struct sigmatel_mic_route dock_mic;
 
        const char **spdif_labels;
 
@@ -382,6 +384,11 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
        0x03, 0x0c, 0x20, 0x40,
 };
 
+#define STAC92HD83XXX_NUM_DMICS         2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+       0x11, 0x20, 0
+};
+
 #define STAC92HD83XXX_NUM_CAPS 2
 static unsigned long stac92hd83xxx_capvols[] = {
        HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -986,7 +993,7 @@ static struct hda_verb stac9205_core_init[] = {
        }
 
 static struct snd_kcontrol_new stac9200_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
@@ -1014,7 +1021,7 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
        { } /* end */
 };
@@ -1105,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                struct hda_input_mux *smux = &spec->private_smux;
                /* check for mute support on SPDIF out */
                if (wcaps & AC_WCAP_OUT_AMP) {
-                       smux->items[smux->num_items].label = "Off";
-                       smux->items[smux->num_items].index = 0;
-                       smux->num_items++;
+                       snd_hda_add_imux_item(smux, "Off", 0, NULL);
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
@@ -1140,6 +1145,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                                        HDA_OUTPUT, vmaster_tlv);
                /* correct volume offset */
                vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
+               /* minimum value is actually mute */
+               vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
                                          vmaster_tlv, slave_vols);
                if (err < 0)
@@ -1180,14 +1187,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               nid = cfg->input_pins[i];
-               if (nid) {
-                       err = stac92xx_add_jack(codec, nid,
-                                               SND_JACK_MICROPHONE);
-                       if (err < 0)
-                               return err;
-               }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
+               if (err < 0)
+                       return err;
        }
 
        return 0;       
@@ -2779,7 +2783,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        char name[22];
 
-       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+       if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
                        && nid == spec->line_switch)
                        control = STAC_CTL_WIDGET_IO_SWITCH;
@@ -2791,7 +2795,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        }
 
        if (control) {
-               strcpy(name, auto_pin_cfg_labels[idx]);
+               strcpy(name, hda_get_input_pin_label(codec, nid, 1));
                return stac92xx_add_control(codec->spec, control,
                                        strcat(name, " Jack Mode"), nid);
        }
@@ -2823,41 +2827,49 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        unsigned int pincap;
+       int i;
 
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       nid = cfg->input_pins[AUTO_PIN_LINE];
-       pincap = snd_hda_query_pin_caps(codec, nid);
-       if (pincap & AC_PINCAP_OUT)
-               return nid;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
+                       nid = cfg->inputs[i].pin;
+                       pincap = snd_hda_query_pin_caps(codec, nid);
+                       if (pincap & AC_PINCAP_OUT)
+                               return nid;
+               }
+       }
        return 0;
 }
 
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
+
 /* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int def_conf, pincap;
-       unsigned int mic_pin;
+       int i;
 
+       *dac = 0;
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       mic_pin = AUTO_PIN_MIC;
-       for (;;) {
-               hda_nid_t nid = cfg->input_pins[mic_pin];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
                /* some laptops have an internal analog microphone
                 * which can't be used as a output */
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+               if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                        pincap = snd_hda_query_pin_caps(codec, nid);
-                       if (pincap & AC_PINCAP_OUT)
-                               return nid;
+                       if (pincap & AC_PINCAP_OUT) {
+                               *dac = get_unassigned_dac(codec, nid);
+                               if (*dac)
+                                       return nid;
+                       }
                }
-               if (mic_pin == AUTO_PIN_MIC)
-                       mic_pin = AUTO_PIN_FRONT_MIC;
-               else
-                       break;
        }
        return 0;
 }
@@ -3004,17 +3016,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
        /* add mic as output */
-       nid = check_mic_out_switch(codec);
-       if (nid) {
-               dac = get_unassigned_dac(codec, nid);
-               if (dac) {
-                       snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
-                                   nid, cfg->line_outs);
-                       cfg->line_out_pins[cfg->line_outs] = nid;
-                       cfg->line_outs++;
-                       spec->mic_switch = nid;
-                       add_spec_dacs(spec, dac);
-               }
+       nid = check_mic_out_switch(codec, &dac);
+       if (nid && dac) {
+               snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+                           nid, cfg->line_outs);
+               cfg->line_out_pins[cfg->line_outs] = nid;
+               cfg->line_outs++;
+               spec->mic_switch = nid;
+               add_spec_dacs(spec, dac);
        }
 
        snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
@@ -3204,13 +3213,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
-               nid = cfg->input_pins[idx];
-               if (nid) {
-                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
-                       if (err < 0)
-                               return err;
-               }
+       for (idx = 0; idx < cfg->num_inputs; idx++) {
+               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+                       break;
+               nid = cfg->inputs[idx].pin;
+               err = stac92xx_add_jack_mode_control(codec, nid, idx);
+               if (err < 0)
+                       return err;
        }
 
        return 0;
@@ -3256,12 +3265,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
        if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
                return -EINVAL;
 
-       for (i = 0; i < num_cons; i++) {
-               mono_mux->items[mono_mux->num_items].label =
-                                       stac92xx_mono_labels[i];
-               mono_mux->items[mono_mux->num_items].index = i;
-               mono_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
+                                     NULL);
 
        return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
                                "Mono Mux", spec->mono_nid);
@@ -3386,11 +3392,8 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
        if (!labels)
                labels = stac92xx_spdif_labels;
 
-       for (i = 0; i < num_cons; i++) {
-               spdif_mux->items[spdif_mux->num_items].label = labels[i];
-               spdif_mux->items[spdif_mux->num_items].index = i;
-               spdif_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
 
        return 0;
 }
@@ -3417,7 +3420,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 /* create a volume assigned to the given pin (only if supported) */
 /* return 1 if the volume control is created */
 static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
-                                  const char *label, int direction)
+                                  const char *label, int idx, int direction)
 {
        unsigned int caps, nums;
        char name[32];
@@ -3434,8 +3437,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
        if (!nums)
                return 0;
        snprintf(name, sizeof(name), "%s Capture Volume", label);
-       err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
-                                   HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
+                                      HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
        if (err < 0)
                return err;
        return 1;
@@ -3448,27 +3451,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        struct hda_input_mux *dimux = &spec->private_dimux;
-       int err, i, active_mics;
+       int err, i;
        unsigned int def_conf;
 
-       dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
-       dimux->items[dimux->num_items].index = 0;
-       dimux->num_items++;
-
-       active_mics = 0;
-       for (i = 0; i < spec->num_dmics; i++) {
-               /* check the validity: sometimes it's a dead vendor-spec node */
-               if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
-                   != AC_WID_PIN)
-                       continue;
-               def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-                       active_mics++;
-       }
+       snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
 
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
-               int index;
+               int index, type_idx;
                const char *label;
 
                nid = spec->dmic_nids[i];
@@ -3482,28 +3472,23 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (index < 0)
                        continue;
 
-               if (active_mics == 1)
-                       label = "Digital Mic";
-               else
-                       label = stac92xx_dmic_labels[dimux->num_items];
+               label = hda_get_input_pin_label(codec, nid, 1);
+               snd_hda_add_imux_item(dimux, label, index, &type_idx);
 
-               err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
+               err = create_elem_capture_vol(codec, nid, label, type_idx,
+                                             HDA_INPUT);
                if (err < 0)
                        return err;
                if (!err) {
                        err = create_elem_capture_vol(codec, nid, label,
-                                                     HDA_OUTPUT);
+                                                     type_idx, HDA_OUTPUT);
                        if (err < 0)
                                return err;
                }
 
-               dimux->items[dimux->num_items].label = label;
-               dimux->items[dimux->num_items].index = index;
-               dimux->num_items++;
                if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
-                       imux->items[imux->num_items].label = label;
-                       imux->items[imux->num_items].index = index;
-                       imux->num_items++;
+                       snd_hda_add_imux_item(imux, label, index, NULL);
+                       spec->num_analog_muxes++;
                }
        }
 
@@ -3511,20 +3496,27 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
 }
 
 static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
-                        hda_nid_t *fixed, hda_nid_t *ext)
+                        hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 {
        unsigned int cfg;
 
        if (!nid)
                return 0;
        cfg = snd_hda_codec_get_pincfg(codec, nid);
-       switch (get_defcfg_connect(cfg)) {
-       case AC_JACK_PORT_FIXED:
+       switch (snd_hda_get_input_pin_attr(cfg)) {
+       case INPUT_PIN_ATTR_INT:
                if (*fixed)
                        return 1; /* already occupied */
                *fixed = nid;
                break;
-       case AC_JACK_PORT_COMPLEX:
+       case INPUT_PIN_ATTR_UNUSED:
+               break;
+       case INPUT_PIN_ATTR_DOCK:
+               if (*dock)
+                       return 1; /* already occupied */
+               *dock = nid;
+               break;
+       default:
                if (*ext)
                        return 1; /* already occupied */
                *ext = nid;
@@ -3542,10 +3534,13 @@ static int set_mic_route(struct hda_codec *codec,
        int i;
 
        mic->pin = pin;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (pin == cfg->input_pins[i])
+       if (pin == 0)
+               return 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (pin == cfg->inputs[i].pin)
                        break;
-       if (i <= AUTO_PIN_FRONT_MIC) {
+       }
+       if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
                /* analog pin */
                i = get_connection_index(codec, spec->mux_nids[0], pin);
                if (i < 0)
@@ -3576,26 +3571,29 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t fixed, ext;
+       hda_nid_t fixed, ext, dock;
        int i;
 
-       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
-               if (cfg->input_pins[i])
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
                        return 0; /* must be exclusively mics */
        }
-       fixed = ext = 0;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+       fixed = ext = dock = 0;
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (check_mic_pin(codec, cfg->inputs[i].pin,
+                   &fixed, &ext, &dock))
                        return 0;
        for (i = 0; i < spec->num_dmics; i++)
-               if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+               if (check_mic_pin(codec, spec->dmic_nids[i],
+                   &fixed, &ext, &dock))
                        return 0;
-       if (!fixed || !ext)
-               return 0;
+       if (!fixed && !ext && !dock)
+               return 0; /* no input to switch */
        if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
                return 0; /* no unsol support */
        if (set_mic_route(codec, &spec->ext_mic, ext) ||
-           set_mic_route(codec, &spec->int_mic, fixed))
+           set_mic_route(codec, &spec->int_mic, fixed) ||
+           set_mic_route(codec, &spec->dock_mic, dock))
                return 0; /* something is wrong */
        return 1;
 }
@@ -3606,13 +3604,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        int i, j;
+       const char *label;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               int index, err;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int index, err, type_idx;
 
-               if (!nid)
-                       continue;
                index = -1;
                for (j = 0; j < spec->num_muxes; j++) {
                        index = get_connection_index(codec, spec->mux_nids[j],
@@ -3623,15 +3620,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
                if (index < 0)
                        continue;
 
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label, index, &type_idx);
+
                err = create_elem_capture_vol(codec, nid,
-                                             auto_pin_cfg_labels[i],
+                                             label, type_idx,
                                              HDA_INPUT);
                if (err < 0)
                        return err;
-
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = index;
-               imux->num_items++;
        }
        spec->num_analog_muxes = imux->num_items;
 
@@ -4305,38 +4301,38 @@ static int stac92xx_init(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL, 0);
                if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
                        stac_issue_unsol_event(codec, spec->ext_mic.pin);
-       }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               if (nid) {
-                       unsigned int pinctl, conf;
-                       if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
-                               /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_default_vref(codec, nid);
+               if (enable_pin_detect(codec, spec->dock_mic.pin,
+                   STAC_MIC_EVENT))
+                       stac_issue_unsol_event(codec, spec->dock_mic.pin);
+       }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int type = cfg->inputs[i].type;
+               unsigned int pinctl, conf;
+               if (type == AUTO_PIN_MIC) {
+                       /* for mic pins, force to initialize */
+                       pinctl = stac92xx_get_default_vref(codec, nid);
+                       pinctl |= AC_PINCTL_IN_EN;
+                       stac92xx_auto_set_pinctl(codec, nid, pinctl);
+               } else {
+                       pinctl = snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       /* if PINCTL already set then skip */
+                       /* Also, if both INPUT and OUTPUT are set,
+                        * it must be a BIOS bug; need to override, too
+                        */
+                       if (!(pinctl & AC_PINCTL_IN_EN) ||
+                           (pinctl & AC_PINCTL_OUT_EN)) {
+                               pinctl &= ~AC_PINCTL_OUT_EN;
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
-                       } else {
-                               pinctl = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                               /* if PINCTL already set then skip */
-                               /* Also, if both INPUT and OUTPUT are set,
-                                * it must be a BIOS bug; need to override, too
-                                */
-                               if (!(pinctl & AC_PINCTL_IN_EN) ||
-                                   (pinctl & AC_PINCTL_OUT_EN)) {
-                                       pinctl &= ~AC_PINCTL_OUT_EN;
-                                       pinctl |= AC_PINCTL_IN_EN;
-                                       stac92xx_auto_set_pinctl(codec, nid,
-                                                                pinctl);
-                               }
-                       }
-                       conf = snd_hda_codec_get_pincfg(codec, nid);
-                       if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
-                               if (enable_pin_detect(codec, nid,
-                                                     STAC_INSERT_EVENT))
-                                       stac_issue_unsol_event(codec, nid);
                        }
                }
+               conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+                       if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
+                               stac_issue_unsol_event(codec, nid);
+               }
        }
        for (i = 0; i < spec->num_dmics; i++)
                stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
@@ -4383,11 +4379,9 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_issue_unsol_event(codec, nid);
        }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4688,6 +4682,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int cfg;
+
+       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+       return get_defcfg_connect(cfg);
+}
+
+static int stac92xx_connected_ports(struct hda_codec *codec,
+                                        hda_nid_t *nids, int num_nids)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx, num;
+       unsigned int def_conf;
+
+       for (num = 0; num < num_nids; num++) {
+               for (idx = 0; idx < spec->num_pins; idx++)
+                       if (spec->pin_nids[idx] == nids[num])
+                               break;
+               if (idx >= spec->num_pins)
+                       break;
+               def_conf = stac_get_defcfg_connect(codec, idx);
+               if (def_conf == AC_JACK_PORT_NONE)
+                       break;
+       }
+       return num;
+}
+
 static void stac92xx_mic_detect(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4695,6 +4719,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
 
        if (get_pin_presence(codec, spec->ext_mic.pin))
                mic = &spec->ext_mic;
+       else if (get_pin_presence(codec, spec->dock_mic.pin))
+               mic = &spec->dock_mic;
        else
                mic = &spec->int_mic;
        if (mic->dmux_idx >= 0)
@@ -4937,11 +4963,9 @@ static int stac92xx_resume(struct hda_codec *codec)
                        stac_issue_unsol_event(codec,
                                               spec->autocfg.line_out_pins[0]);
        }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
@@ -5313,11 +5337,16 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       /* reset pin power-down; Windows may leave these bits after reboot */
+       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
+       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
        codec->no_trigger_sense = 1;
        codec->spec = spec;
        spec->linear_tone_beep = 1;
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
+       spec->dmic_nids = stac92hd83xxx_dmic_nids;
+       spec->dmux_nids = stac92hd83xxx_mux_nids;
        spec->mux_nids = stac92hd83xxx_mux_nids;
        spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
        spec->adc_nids = stac92hd83xxx_adc_nids;
@@ -5363,9 +5392,13 @@ again:
        case 0x111d76d4:
        case 0x111d7605:
        case 0x111d76d5:
+       case 0x111d76e7:
                if (spec->board_config == STAC_92HD83XXX_PWR_REF)
                        break;
                spec->num_pwrs = 0;
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd83xxx_dmic_nids,
+                               STAC92HD83XXX_NUM_DMICS);
                break;
        }
 
@@ -5424,36 +5457,6 @@ again:
        return 0;
 }
 
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int cfg;
-
-       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
-       return get_defcfg_connect(cfg);
-}
-
-static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
-                                        hda_nid_t *nids, int num_nids)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int idx, num;
-       unsigned int def_conf;
-
-       for (num = 0; num < num_nids; num++) {
-               for (idx = 0; idx < spec->num_pins; idx++)
-                       if (spec->pin_nids[idx] == nids[num])
-                               break;
-               if (idx >= spec->num_pins)
-                       break;
-               def_conf = stac_get_defcfg_connect(codec, idx);
-               if (def_conf == AC_JACK_PORT_NONE)
-                       break;
-       }
-       return num;
-}
-
 static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
                                          hda_nid_t dig0pin)
 {
@@ -5592,7 +5595,7 @@ again:
        case 0x111d76b5:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -5624,7 +5627,7 @@ again:
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
                stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS - 1);
                break;
@@ -5638,7 +5641,7 @@ again:
        default:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -6320,6 +6323,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
        { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
        { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
        {} /* terminator */
 };
 
index ae3acb2b42d11366a2d24bd768d823dbc61853b4..d1c3f8defc48d059f42124542d4e09b1fda000cf 100644 (file)
@@ -444,8 +444,8 @@ static hda_nid_t vt1812_adc_nids[2] = {
 
 
 /* add dynamic controls */
-static int via_add_control(struct via_spec *spec, int type, const char *name,
-                          unsigned long val)
+static int __via_add_control(struct via_spec *spec, int type, const char *name,
+                            int idx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -463,6 +463,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
        return 0;
 }
 
+#define via_add_control(spec, type, name, val) \
+       __via_add_control(spec, type, name, 0, val)
+
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
                                                struct snd_kcontrol_new *tmpl)
 {
@@ -494,18 +497,18 @@ static void via_free_kctls(struct hda_codec *codec)
 
 /* create input playback/capture controls for the given pin */
 static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
-                               int idx, int mix_nid)
+                               int type_idx, int idx, int mix_nid)
 {
        char name[32];
        int err;
 
        sprintf(name, "%s Playback Volume", ctlname);
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+       err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
                              HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
        sprintf(name, "%s Playback Switch", ctlname);
-       err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
+       err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
                              HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -557,17 +560,15 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
 static void via_auto_init_analog_input(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int ctl;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (!nid)
-                       continue;
-
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (spec->smart51_enabled && is_smart51_pins(spec, nid))
                        ctl = PIN_OUT;
-               else if (i <= AUTO_PIN_FRONT_MIC)
+               else if (i == AUTO_PIN_MIC)
                        ctl = PIN_VREF50;
                else
                        ctl = PIN_IN;
@@ -1322,15 +1323,14 @@ static void mute_aa_path(struct hda_codec *codec, int mute)
 }
 static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
 {
-       int res = 0;
-       int index;
-       for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
-               if (pin == spec->autocfg.input_pins[index]) {
-                       res = 1;
-                       break;
-               }
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (pin == cfg->inputs[i].pin)
+                       return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
        }
-       return res;
+       return 0;
 }
 
 static int via_smart51_info(struct snd_kcontrol *kcontrol,
@@ -1348,25 +1348,21 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int on = 1;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-               if (nid) {
-                       int ctl =
-                           snd_hda_codec_read(codec, nid, 0,
-                                              AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                              0);
-                       if (i == AUTO_PIN_FRONT_MIC
-                           && spec->hp_independent_mode
-                           && spec->codec_type != VT1718S)
-                               continue; /* ignore FMic for independent HP */
-                       if (ctl & AC_PINCTL_IN_EN
-                           && !(ctl & AC_PINCTL_OUT_EN))
-                               on = 0;
-               }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int ctl = snd_hda_codec_read(codec, nid, 0,
+                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+                       continue;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+                   spec->hp_independent_mode && spec->codec_type != VT1718S)
+                       continue; /* ignore FMic for independent HP */
+               if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
+                       on = 0;
        }
        *ucontrol->value.integer.value = on;
        return 0;
@@ -1377,36 +1373,38 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int out_in = *ucontrol->value.integer.value
                ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-               if (i == AUTO_PIN_FRONT_MIC
-                   && spec->hp_independent_mode
-                   && spec->codec_type != VT1718S)
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               unsigned int parm;
+
+               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+                       continue;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+                   spec->hp_independent_mode && spec->codec_type != VT1718S)
                        continue; /* don't retask FMic for independent HP */
-               if (nid) {
-                       unsigned int parm = snd_hda_codec_read(
-                               codec, nid, 0,
-                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                       parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
-                       parm |= out_in;
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           parm);
-                       if (out_in == AC_PINCTL_OUT_EN) {
-                               mute_aa_path(codec, 1);
-                               notify_aa_path_ctls(codec);
-                       }
-                       if (spec->codec_type == VT1718S)
-                               snd_hda_codec_amp_stereo(
+
+               parm = snd_hda_codec_read(codec, nid, 0,
+                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+               parm |= out_in;
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   parm);
+               if (out_in == AC_PINCTL_OUT_EN) {
+                       mute_aa_path(codec, 1);
+                       notify_aa_path_ctls(codec);
+               }
+               if (spec->codec_type == VT1718S) {
+                       snd_hda_codec_amp_stereo(
                                        codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
                                        HDA_AMP_UNMUTE);
                }
-               if (i == AUTO_PIN_FRONT_MIC) {
+               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
                        if (spec->codec_type == VT1708S
                            || spec->codec_type == VT1716S) {
                                /* input = index 1 (AOW3) */
@@ -1442,7 +1440,7 @@ static struct snd_kcontrol_new via_smart51_mixer[2] = {
 static int via_smart51_build(struct via_spec *spec)
 {
        struct snd_kcontrol_new *knew;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        int i;
 
@@ -1450,13 +1448,14 @@ static int via_smart51_build(struct via_spec *spec)
        if (knew == NULL)
                return -ENOMEM;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               nid = spec->autocfg.input_pins[index[i]];
-               if (nid) {
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
                        knew = via_clone_control(spec, &via_smart51_mixer[1]);
                        if (knew == NULL)
                                return -ENOMEM;
                        knew->subdevice = nid;
+                       break;
                }
        }
 
@@ -2375,13 +2374,8 @@ static void create_hp_imux(struct via_spec *spec)
        static const char *texts[] = { "OFF", "ON", NULL};
 
        /* for hp mode select */
-       i = 0;
-       while (texts[i] != NULL) {
-               imux->items[imux->num_items].label =  texts[i];
-               imux->items[imux->num_items].index = i;
-               imux->num_items++;
-               i++;
-       }
+       for (i = 0; texts[i]; i++)
+               snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
        spec->hp_mux = &spec->private_imux[1];
 }
@@ -2413,51 +2407,53 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
+static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
+                                           const struct auto_pin_cfg *cfg,
+                                           hda_nid_t cap_nid,
+                                           hda_nid_t pin_idxs[], int num_idxs)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
+       int i, err, idx, type, type_idx = 0;
 
        /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1d: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1e: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x21: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x24: /* CD */
-                       idx = 1;
+       for (idx = 0; idx < num_idxs; idx++) {
+               if (pin_idxs[idx] == 0xff) {
+                       snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
                        break;
                }
-               err = via_new_analog_input(spec, labels[i], idx, 0x17);
+       }
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               const char *label;
+               type = cfg->inputs[i].type;
+               for (idx = 0; idx < num_idxs; idx++)
+                       if (pin_idxs[idx] == cfg->inputs[i].pin)
+                               break;
+               if (idx >= num_idxs)
+                       continue;
+               if (i > 0 && type == cfg->inputs[i - 1].type)
+                       type_idx++;
+               else
+                       type_idx = 0;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
                if (err < 0)
                        return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
+               snd_hda_add_imux_item(imux, label, idx, NULL);
        }
        return 0;
 }
 
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static struct hda_amp_list vt1708_loopbacks[] = {
        { 0x17, HDA_INPUT, 1 },
@@ -2554,7 +2550,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
        /* add jack detect on/off control */
@@ -3021,49 +3017,12 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1d: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1e: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x21: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x23: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x18);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1709_parse_auto_config(struct hda_codec *codec)
@@ -3086,7 +3045,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
        err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -3588,49 +3547,12 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1708B_parse_auto_config(struct hda_codec *codec)
@@ -3653,7 +3575,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
        err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4061,49 +3983,12 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 /* fill out digital output widgets; one for master and one for slave outputs */
@@ -4151,7 +4036,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
        err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4441,58 +4326,20 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
        imux = &spec->private_imux[1];
 
        /* for hp mode select */
-       i = 0;
-       while (texts[i] != NULL)        {
-               imux->items[imux->num_items].label =  texts[i];
-               imux->items[imux->num_items].index = i;
-               imux->num_items++;
-               i++;
-       }
+       for (i = 0; texts[i]; i++)
+               snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
        spec->hp_mux = &spec->private_imux[1];
        return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 3;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x14: /* Mic */
-                       idx = 1;
-                       break;
-
-               case 0x15: /* Line In */
-                       idx = 2;
-                       break;
-
-               case 0x18: /* Front Mic */
-                       idx = 3;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x1A);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1702_parse_auto_config(struct hda_codec *codec)
@@ -4521,7 +4368,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
                                  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
                                  (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
                                  (1 << AC_AMPCAP_MUTE_SHIFT));
-       err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4872,49 +4719,12 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 1;
-                       break;
-
-               case 0x2a: /* Line In */
-                       idx = 2;
-                       break;
-
-               case 0x29: /* Front Mic */
-                       idx = 3;
-                       break;
-
-               case 0x2c: /* CD */
-                       idx = 0;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1718S_parse_auto_config(struct hda_codec *codec)
@@ -4938,7 +4748,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
        err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -5371,49 +5181,12 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1716S_parse_auto_config(struct hda_codec *codec)
@@ -5436,7 +5209,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
        err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -5717,54 +5490,25 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 0;
-                       break;
-
-               case 0x2a: /* Line In */
-                       idx = 1;
-                       break;
-
-               case 0x29: /* Front Mic */
-                       idx = 2;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
+       static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+       int err;
 
+       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                              ARRAY_SIZE(pin_idxs));
+       if (err < 0)
+               return err;
        /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
+       err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
        if (err < 0)
                return err;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 3;
-       imux->num_items++;
-
        /* for digital mic select */
-       imux->items[imux->num_items].label = "Digital Mic";
-       imux->items[imux->num_items].index = 4;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
 
        return 0;
 }
@@ -5792,7 +5536,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
        err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -6067,53 +5811,26 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 0;
-                       break;
+       static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+       int err;
 
-               case 0x2a: /* Line In */
-                       idx = 1;
-                       break;
+       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                              ARRAY_SIZE(pin_idxs));
+       if (err < 0)
+               return err;
 
-               case 0x29: /* Front Mic */
-                       idx = 2;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
        /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
+       err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
        if (err < 0)
                return err;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
        /* for digital mic select */
-       imux->items[imux->num_items].label = "Digital Mic";
-       imux->items[imux->num_items].index = 6;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
 
        return 0;
 }
@@ -6141,7 +5858,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
        err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
index d216362626d019826adb262da1341c898666c65d..712c1710f9a2083398122552e66d4478cadae98d 100644 (file)
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_DELTA1010E:
        case ICE1712_SUBDEVICE_DELTA1010LT:
        case ICE1712_SUBDEVICE_MEDIASTATION:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                ice->num_total_dacs = 8;
                ice->num_total_adcs = 8;
                break;
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
                err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
                break;
        case ICE1712_SUBDEVICE_DELTA1010LT:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
                break;
        case ICE1712_SUBDEVICE_DELTA66:
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_DELTA66:
        case ICE1712_SUBDEVICE_VX442:
        case ICE1712_SUBDEVICE_DELTA66E:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                err = snd_ice1712_akm4xxx_build_controls(ice);
                if (err < 0)
                        return err;
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
                .chip_init = snd_ice1712_delta_init,
                .build_controls = snd_ice1712_delta_add_controls,
        },
+       {
+               .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
+               .name = "Edirol DA2496",
+               .model = "da2496",
+               .chip_init = snd_ice1712_delta_init,
+               .build_controls = snd_ice1712_delta_add_controls,
+       },
        { } /* terminator */
 };
index f7f14df81f26e301089b77bcf26825872d8045c5..1a0ac6cd65014995245d4804315ad8d9ef1331f0 100644 (file)
@@ -34,7 +34,8 @@
                "{MidiMan M Audio,Delta 410},"\
                "{MidiMan M Audio,Audiophile 24/96},"\
                "{Digigram,VX442},"\
-               "{Lionstracs,Mediastation},"
+               "{Lionstracs,Mediastation},"\
+               "{Edirol,DA2496},"
 
 #define ICE1712_SUBDEVICE_DELTA1010    0x121430d6
 #define ICE1712_SUBDEVICE_DELTA1010E   0xff1430d6
@@ -47,6 +48,7 @@
 #define ICE1712_SUBDEVICE_DELTA1010LT  0x12143bd6
 #define ICE1712_SUBDEVICE_VX442                0x12143cd6
 #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
+#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
index 6bc3f91b728149ef7ab180856bcfd46b6ef8397e..cdb873f5da50923fb2ca1a1ff43d57ecf0ff4d01 100644 (file)
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
  */
 static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        char line[64];
        unsigned int reg, val;
        mutex_lock(&ice->gpio_mutex);
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
 
 static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
 
        mutex_lock(&ice->gpio_mutex);
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice)
 
 static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
 
        mutex_lock(&ice->gpio_mutex);
index 2a8e5cd8f2d8093f18b3f2c12591ed503c483530..e36ddb94c382932a4e5c9b35095678d3b9c90ea5 100644 (file)
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
 static void stac9460_proc_regs_read(struct snd_info_entry *entry,
                struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
        /* registers 0x0 - 0x14 */
        for (reg = 0; reg <= 0x15; reg++) {
index 6c0a11adb2a84511b83b23b69d5efce9fb2085c6..98a8eb3c92f76a614bba10332d519f5fd0e2b26d 100644 (file)
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
        { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
                         PLAYBACK_2_TO_AC97_1 |
                         CAPTURE_0_FROM_I2S_1 |
                         CAPTURE_1_FROM_SPDIF |
-                        CAPTURE_2_FROM_AC97_1,
+                        CAPTURE_2_FROM_AC97_1 |
+                        AC97_CD_INPUT,
        .dac_channels = 8,
        .dac_volume_min = 0,
        .dac_volume_max = 255,
index a3409edcfb5094791c33563f8ad3911826ce3e26..7d5222caa0a92e5ca844269e02253fed98cfba98 100644 (file)
@@ -34,6 +34,7 @@
      /* CAPTURE_3_FROM_I2S_3           not implemented */
 #define MIDI_OUTPUT            0x0800
 #define MIDI_INPUT             0x1000
+#define AC97_CD_INPUT          0x2000
 
 enum {
        CONTROL_SPDIF_PCM,
index 7e93cf884437d0b5844c9515250c49994390e54c..e5ebe56fb0c5c5129206f5fa4be6fcfc99e8888c 100644 (file)
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
        }
 }
 
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
 {
-       struct pci_dev *pci = NULL;
+       enum { PEX811X, PI7C9X110 };
+       static const struct pci_device_id bridge_ids[] = {
+               { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+               { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+               { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+               { }
+       };
+       struct pci_dev *bridge;
+       const struct pci_device_id *id;
        u32 tmp;
 
-       for (;;) {
-               /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
-               pci = pci_get_device(0x12d8, 0xe110, pci);
-               if (!pci)
-                       break;
-               /*
-                * ... configure its secondary internal arbiter to park to
-                * the secondary port, instead of to the last master.
-                */
-               if (!pci_read_config_dword(pci, 0x40, &tmp)) {
-                       tmp |= 1;
-                       pci_write_config_dword(pci, 0x40, tmp);
-               }
-               /* Why?  Try asking C-Media. */
+       if (!pci->bus || !pci->bus->self)
+               return;
+       bridge = pci->bus->self;
+
+       id = pci_match_id(bridge_ids, bridge);
+       if (!id)
+               return;
+
+       switch (id->driver_data) {
+       case PEX811X:   /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+               pci_read_config_dword(bridge, 0x48, &tmp);
+               tmp |= 1;       /* enable blind prefetching */
+               tmp |= 1 << 11; /* enable beacon generation */
+               pci_write_config_dword(bridge, 0x48, tmp);
+
+               pci_write_config_dword(bridge, 0x84, 0x0c);
+               pci_read_config_dword(bridge, 0x88, &tmp);
+               tmp &= ~(7 << 27);
+               tmp |= 2 << 27; /* set prefetch size to 128 bytes */
+               pci_write_config_dword(bridge, 0x88, tmp);
+               break;
+
+       case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
+               pci_read_config_dword(bridge, 0x40, &tmp);
+               tmp |= 1;       /* park the PCI arbiter to the sound chip */
+               pci_write_config_dword(bridge, 0x40, tmp);
+               break;
        }
 }
 
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
-       pci_bridge_magic();
+       configure_pcie_bridge(pci);
        oxygen_init(chip);
        chip->model.init(chip);
 
index f375b8a27862452bb6ec24b4f46028136910263a..2849b36f5f7e72100c1691414cb6279e17f5d1ce 100644 (file)
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
        }
 
-static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
 static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
 static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
 
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
                if (!strcmp(template.name, "Stereo Upmixing") &&
                    chip->model.dac_channels == 2)
                        continue;
+               if (!strncmp(template.name, "CD Capture ", 11) &&
+                   !(chip->model.device_config & AC97_CD_INPUT))
+                       continue;
                if (!strcmp(template.name, "Master Playback Volume") &&
                    chip->model.dac_tlv) {
                        template.tlv.p = chip->model.dac_tlv;
index 9dff6954c397a902980b6dedb2bb6ebe45337e38..814667442eb04f086e19e157ba43840f1a4d12b2 100644 (file)
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .channels_max = 8,
        .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 
index 72de159d45673b123df400486962078e3f401650..4dcd41b782586b7d7d9251a4c75aef37c36a4169 100644 (file)
 /* OXYGEN_CHANNEL_* */
 
 #define OXYGEN_CODEC_VERSION           0xe4
-#define  OXYGEN_XCID_MASK              0x07
+#define  OXYGEN_CODEC_ID_MASK          0x07
 
 #define OXYGEN_REVISION                        0xe6
-#define  OXYGEN_REVISION_XPKGID_MASK   0x0007
+#define  OXYGEN_PACKAGE_ID_MASK                0x0007
+#define  OXYGEN_PACKAGE_ID_8786                0x0004
+#define  OXYGEN_PACKAGE_ID_8787                0x0006
+#define  OXYGEN_PACKAGE_ID_8788                0x0007
 #define  OXYGEN_REVISION_MASK          0xfff8
-#define  OXYGEN_REVISION_2             0x0008  /* bit flag */
-#define  OXYGEN_REVISION_8787          0x0014  /* 8 bits */
+#define  OXYGEN_REVISION_2             0x0008
 
 #define OXYGEN_OFFSIN_48K              0xe8
 #define OXYGEN_OFFSBASE_48K            0xe9
index 06c863e86e3d3d24a5dfd0f7b43f56a47b120719..469010a8b8497abcf615e88994683d6f69e6d46e 100644 (file)
@@ -25,9 +25,9 @@
 #include "xonar.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AVx00 driver");
+MODULE_DESCRIPTION("Asus Virtuoso driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
        { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
        { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
index 7c4986b27f2b07bd8faa7d824a0056d1db821308..aa27c31049afba1d8d759cc4c5fb7ce7d04e1947 100644 (file)
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
 
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int xonar_d1_mixer_init(struct oxygen *chip)
 {
        int err;
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
        .init = xonar_d1_init,
-       .control_filter = xonar_d1_control_filter,
        .mixer_init = xonar_d1_mixer_init,
        .cleanup = xonar_d1_cleanup,
        .suspend = xonar_d1_suspend,
index ba18fb546b4f9d7c8ace8b82d5100e3c82d0e3b1..d491fd6c0be239906380ae6af8864f1bfe0e4f6f 100644 (file)
  * GPIO 5 <- 0
  */
 
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * GPIO 1 -> enable output
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
-       data->generic.anti_pop_delay = 100;
        data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
        data->dacs = chip->model.private_data ? 4 : 1;
        data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
+       data->generic.anti_pop_delay = 100;
        data->has_cs2000 = 1;
        data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
 
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
        struct xonar_pcm179x *data = chip->model_data;
 
        xonar_st_init_i2c(chip);
+       data->generic.anti_pop_delay = 800;
        data->generic.ext_power_reg = OXYGEN_GPI_DATA;
        data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
        data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
        return 0;
 }
 
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int add_pcm1796_controls(struct oxygen *chip)
 {
        int err;
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
                         CAPTURE_0_FROM_I2S_2 |
                         CAPTURE_1_FROM_SPDIF |
                         MIDI_OUTPUT |
-                        MIDI_INPUT,
+                        MIDI_INPUT |
+                        AC97_CD_INPUT,
        .dac_channels = 8,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
        .init = xonar_st_init,
-       .control_filter = xonar_st_control_filter,
        .mixer_init = xonar_st_mixer_init,
        .cleanup = xonar_st_cleanup,
        .suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
                chip->model.resume = xonar_stx_resume;
                chip->model.set_dac_params = set_pcm1796_params;
                break;
+       case 0x835e:
+               snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
+               return -ENODEV;
        default:
                return -EINVAL;
        }
index b82c1cfa96f5334554435a6eeebc6e82fa63857d..200f7601276f8e5b5fa841a34ea5ad4a07c0fc44 100644 (file)
  * SPI 0 -> WM8766 (surround, center/LFE, back)
  * SPI 1 -> WM8776 (front, input)
  *
- * GPIO 4 <- headphone detect
- * GPIO 6 -> route input jack to input 1/2 (1/0)
- * GPIO 7 -> enable output to speakers
- * GPIO 8 -> enable output to speakers
+ * GPIO 4 <- headphone detect, 0 = plugged
+ * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ * GPIO 7 -> enable output to front L/R speaker channels
+ * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ *
+ * WM8766:
+ *
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
  */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
@@ -44,7 +52,8 @@
 
 #define GPIO_DS_HP_DETECT      0x0010
 #define GPIO_DS_INPUT_ROUTE    0x0040
-#define GPIO_DS_OUTPUT_ENABLE  0x0180
+#define GPIO_DS_OUTPUT_FRONTLR 0x0080
+#define GPIO_DS_OUTPUT_ENABLE  0x0100
 
 #define LC_CONTROL_LIMITER     0x40000000
 #define LC_CONTROL_ALC         0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
        struct snd_kcontrol *line_adcmux_control;
        struct snd_kcontrol *mic_adcmux_control;
        struct snd_kcontrol *lc_controls[13];
+       struct snd_jack *hp_jack;
 };
 
 static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
                         (0 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
-       if (reg < ARRAY_SIZE(data->wm8766_regs))
+       if (reg < ARRAY_SIZE(data->wm8766_regs)) {
+               if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
+                   (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
+                       value &= ~WM8766_UPDATE;
                data->wm8766_regs[reg] = value;
+       }
 }
 
 static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
        struct xonar_wm87x6 *data = chip->model_data;
 
        if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
-           value != data->wm8766_regs[reg]) {
-               if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
-                   (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
-                       value &= ~WM8766_UPDATE;
+           value != data->wm8766_regs[reg])
                wm8766_write(chip, reg, value);
-       }
 }
 
 static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
 
 static void wm8766_registers_init(struct oxygen *chip)
 {
+       struct xonar_wm87x6 *data = chip->model_data;
+
        wm8766_write(chip, WM8766_RESET, 0);
+       wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
        wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
        wm8766_write(chip, WM8766_DAC_CTRL2,
                     WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
        wm8776_registers_init(chip);
 }
 
+static void wm8766_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       data->wm8766_regs[WM8766_DAC_CTRL] =
+               WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+       wm8766_registers_init(chip);
+}
+
+static void xonar_ds_handle_hp_jack(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       bool hp_plugged;
+       unsigned int reg;
+
+       mutex_lock(&chip->mutex);
+
+       hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                      GPIO_DS_HP_DETECT);
+
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
+                             GPIO_DS_OUTPUT_FRONTLR);
+
+       reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
+       if (hp_plugged)
+               reg |= WM8766_MUTEALL;
+       wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+
+       snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
+
+       mutex_unlock(&chip->mutex);
+}
+
 static void xonar_ds_init(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
        data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
 
        wm8776_init(chip);
-       wm8766_registers_init(chip);
+       wm8766_init(chip);
 
-       oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
-                             GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                           GPIO_DS_HP_DETECT);
        oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
        oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
        chip->interrupt_mask |= OXYGEN_INT_GPIO;
 
        xonar_enable_output(chip);
 
+       snd_jack_new(chip->card, "Headphone",
+                    SND_JACK_HEADPHONE, &data->hp_jack);
+       xonar_ds_handle_hp_jack(chip);
+
        snd_component_add(chip->card, "WM8776");
        snd_component_add(chip->card, "WM8766");
 }
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
        wm8776_registers_init(chip);
        wm8766_registers_init(chip);
        xonar_enable_output(chip);
+       xonar_ds_handle_hp_jack(chip);
 }
 
 static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
                            (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
 }
 
-static void xonar_ds_gpio_changed(struct oxygen *chip)
+static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
 {
-       u16 bits;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int reg;
 
-       bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+       /*
+        * The WM8766 can mix left and right channels, but this setting
+        * applies to all three stereo pairs.
+        */
+       reg = data->wm8766_regs[WM8766_DAC_CTRL] &
+               ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
+       if (mixed)
+               reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
+       else
+               reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+       wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+}
+
+static void xonar_ds_gpio_changed(struct oxygen *chip)
+{
+       xonar_ds_handle_hp_jack(chip);
 }
 
 static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
                .put = wm8776_input_mux_put,
                .private_value = 1 << 1,
        },
-       WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+       WM8776_BIT_SWITCH("Front Mic Capture Switch",
+                         WM8776_ADCMUX, 1 << 2, 0, 0),
+       WM8776_BIT_SWITCH("Aux Capture Switch",
+                         WM8776_ADCMUX, 1 << 3, 0, 0),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
                                LC_CONTROL_ALC, wm8776_ngth_db_scale),
 };
 
-static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int xonar_ds_mixer_init(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
 
 static const struct oxygen_model model_xonar_ds = {
        .shortname = "Xonar DS",
-       .longname = "Asus Virtuoso 200",
+       .longname = "Asus Virtuoso 66",
        .chip = "AV200",
        .init = xonar_ds_init,
-       .control_filter = xonar_ds_control_filter,
        .mixer_init = xonar_ds_mixer_init,
        .cleanup = xonar_ds_cleanup,
        .suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
        .set_adc_params = set_wm8776_adc_params,
        .update_dac_volume = update_wm87x6_volume,
        .update_dac_mute = update_wm87x6_mute,
+       .update_center_lfe_mix = update_wm8766_center_lfe_mix,
        .gpio_changed = xonar_ds_gpio_changed,
        .dac_tlv = wm87x6_dac_db_scale,
        .model_data_size = sizeof(struct xonar_wm87x6),
index d19dc052c3912f0aa235f8fae0344b5f241833fa..d5f5b440fc40f3ea7024adefe33d88d45e0377a5 100644 (file)
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data)
 static void
 snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
 {
-       struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+       struct rme96 *rme96 = pcm->private_data;
        rme96->spdif_pcm = NULL;
 }
 
 static void
 snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
 {
-       struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+       struct rme96 *rme96 = pcm->private_data;
        rme96->adat_pcm = NULL;
 }
 
@@ -1661,7 +1661,7 @@ static void
 snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
        int n;
-       struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+       struct rme96 *rme96 = entry->private_data;
        
        rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
 
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
        card->private_free = snd_rme96_card_free;
-       rme96 = (struct rme96 *)card->private_data;     
+       rme96 = card->private_data;
        rme96->card = card;
        rme96->pci = pci;
        snd_card_set_dev(card, &pci->dev);
index d6fa7bfd9aa123d7f8bb8142a8def39888129434..0b720cf7783e8d1347d0ddd766a3505014f3c7b4 100644 (file)
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 static void
 snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct hdsp *hdsp = (struct hdsp *) entry->private_data;
+       struct hdsp *hdsp = entry->private_data;
        unsigned int status;
        unsigned int status2;
        char *pref_sync_ref;
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
 
 static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct hdsp *hdsp = (struct hdsp *)hw->private_data;
+       struct hdsp *hdsp = hw->private_data;
        void __user *argp = (void __user *)arg;
        int err;
 
@@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
 
 static void snd_hdsp_card_free(struct snd_card *card)
 {
-       struct hdsp *hdsp = (struct hdsp *) card->private_data;
+       struct hdsp *hdsp = card->private_data;
 
        if (hdsp)
                snd_hdsp_free(hdsp);
@@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
 
-       hdsp = (struct hdsp *) card->private_data;
+       hdsp = card->private_data;
        card->private_free = snd_hdsp_card_free;
        hdsp->dev = dev;
        hdsp->pci = pci;
index 20afdf9772eefd1e23768e724ab06e0a919da260..961d982976958aaaf0c4dae4906210ad3df0bfb4 100644 (file)
@@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
        if (! mix->i2c.client)
                return -ENODEV;
        if (mix->capture_source)
-               mix->acs = mix->acs |= 2;
+               mix->acs |= 2;
        else
                mix->acs &= ~2;
        return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
index dc5249fba85c71884c613c5b028a9fd173143bf5..d0e75323ec190a317d2c6c8252ad8cf1e1e8035a 100644 (file)
@@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = params_buffer_bytes(params);
 
-       prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
        prtd->dma_buffer = runtime->dma_addr;
@@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                pr_debug("at32-pcm:"
                                "Allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
 }
 
 #ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
 {
-       struct snd_pcm *pcm = dai_link->pcm;
-       struct snd_pcm_str *stream = &pcm->streams[0];
-       struct snd_pcm_substream *substream = stream->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_runtime *runtime = dai->runtime;
        struct atmel_runtime_data *prtd;
        struct atmel_pcm_dma_params *params;
 
@@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
        return 0;
 }
 
-static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
 {
-       struct snd_pcm *pcm = dai_link->pcm;
-       struct snd_pcm_str *stream = &pcm->streams[0];
-       struct snd_pcm_substream *substream = stream->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_runtime *runtime = dai->runtime;
        struct atmel_runtime_data *prtd;
        struct atmel_pcm_dma_params *params;
 
@@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
 #define atmel_pcm_resume       NULL
 #endif
 
-struct snd_soc_platform atmel_soc_platform = {
-       .name           = "atmel-audio",
-       .pcm_ops        = &atmel_pcm_ops,
+static struct snd_soc_platform_driver atmel_soc_platform = {
+       .ops            = &atmel_pcm_ops,
        .pcm_new        = atmel_pcm_new,
        .pcm_free       = atmel_pcm_free_dma_buffers,
        .suspend        = atmel_pcm_suspend,
        .resume         = atmel_pcm_resume,
 };
-EXPORT_SYMBOL_GPL(atmel_soc_platform);
 
-static int __init atmel_pcm_modinit(void)
+static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
+}
+
+static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver atmel_pcm_driver = {
+       .driver = {
+                       .name = "atmel-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = atmel_soc_platform_probe,
+       .remove = __devexit_p(atmel_soc_platform_remove),
+};
+
+static int __init snd_atmel_pcm_init(void)
 {
-       return snd_soc_register_platform(&atmel_soc_platform);
+       return platform_driver_register(&atmel_pcm_driver);
 }
-module_init(atmel_pcm_modinit);
+module_init(snd_atmel_pcm_init);
 
-static void __exit atmel_pcm_modexit(void)
+static void __exit snd_atmel_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&atmel_soc_platform);
+       platform_driver_unregister(&atmel_pcm_driver);
 }
-module_exit(atmel_pcm_modexit);
+module_exit(snd_atmel_pcm_exit);
 
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("Atmel PCM module");
index ec9b2824b66381d3e3e1479ef7039e875c0cbacd..2597329302e76c0c6d50a9f536eea39891f45c64 100644 (file)
@@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
        void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
 };
 
-extern struct snd_soc_platform atmel_soc_platform;
-
-
 /*
  * SSC register access (since ssc_writel() / ssc_readl() require literal name)
  */
index c85844d4845bdc15f24c94c8d4a82dbedcfcc1ec..5d230cee3fa7a7ad9c0fb2dcb9d39d13bb5759fb 100644 (file)
@@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
 static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        int dir_mask;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, dir_mask;
 
@@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       int id = rtd->dai->cpu_dai->id;
+       int id = dai->id;
        struct atmel_ssc_info *ssc_p = &ssc_info[id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, channels, bits;
@@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
         * function.  It should not be used for other purposes
         * as it is common to all substreams.
         */
-       snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
 
        channels = params_channels(params);
 
@@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir;
 
@@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #  define atmel_ssc_resume     NULL
 #endif /* CONFIG_PM */
 
+static int atmel_ssc_probe(struct snd_soc_dai *dai)
+{
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+       int ret = 0;
+
+       snd_soc_dai_set_drvdata(dai, ssc_p);
+
+       /*
+        * Request SSC device
+        */
+       ssc_p->ssc = ssc_request(dai->id);
+       if (IS_ERR(ssc_p->ssc)) {
+               printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
+               ret = PTR_ERR(ssc_p->ssc);
+       }
+
+       return ret;
+}
+
+static int atmel_ssc_remove(struct snd_soc_dai *dai)
+{
+       struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
+
+       ssc_free(ssc_p->ssc);
+       return 0;
+}
 
 #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
 
@@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
        .set_clkdiv     = atmel_ssc_set_dai_clkdiv,
 };
 
-struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
-       {       .name = "atmel-ssc0",
-               .id = 0,
+static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
+       {
+               .name = "atmel-ssc-dai.0",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[0],
        },
 #if NUM_SSC_DEVICES == 3
-       {       .name = "atmel-ssc1",
-               .id = 1,
+       {
+               .name = "atmel-ssc-dai.1",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[1],
        },
-       {       .name = "atmel-ssc2",
-               .id = 2,
+       {
+               .name = "atmel-ssc-dai.2",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[2],
        },
 #endif
 };
-EXPORT_SYMBOL_GPL(atmel_ssc_dai);
 
-static int __init atmel_ssc_modinit(void)
+static __devinit int asoc_ssc_probe(struct platform_device *pdev)
+{
+       BUG_ON(pdev->id < 0);
+       BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
+       return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
+}
+
+static int __devexit asoc_ssc_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_ssc_driver = {
+       .driver = {
+                       .name = "atmel-ssc-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_ssc_probe,
+       .remove = __devexit_p(asoc_ssc_remove),
+};
+
+/**
+ * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
+ */
+int atmel_ssc_set_audio(int ssc_id)
+{
+       struct ssc_device *ssc;
+       static struct platform_device *dma_pdev;
+       struct platform_device *ssc_pdev;
+       int ret;
+
+       if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
+               return -EINVAL;
+
+       /* Allocate a dummy device for DMA if we don't have one already */
+       if (!dma_pdev) {
+               dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
+               if (!dma_pdev)
+                       return -ENOMEM;
+
+               ret = platform_device_add(dma_pdev);
+               if (ret < 0) {
+                       platform_device_put(dma_pdev);
+                       dma_pdev = NULL;
+                       return ret;
+               }
+       }
+
+       ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+       if (!ssc_pdev) {
+               ssc_free(ssc);
+               return -ENOMEM;
+       }
+
+       /* If we can grab the SSC briefly to parent the DAI device off it */
+       ssc = ssc_request(ssc_id);
+       if (IS_ERR(ssc))
+               pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+                       PTR_ERR(ssc));
+       else
+               ssc_pdev->dev.parent = &(ssc->pdev->dev);
+       ssc_free(ssc);
+
+       ret = platform_device_add(ssc_pdev);
+       if (ret < 0)
+               platform_device_put(ssc_pdev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
+
+static int __init snd_atmel_ssc_init(void)
 {
-       return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+       return platform_driver_register(&asoc_ssc_driver);
 }
-module_init(atmel_ssc_modinit);
+module_init(snd_atmel_ssc_init);
 
-static void __exit atmel_ssc_modexit(void)
+static void __exit snd_atmel_ssc_exit(void)
 {
-       snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+       platform_driver_unregister(&asoc_ssc_driver);
 }
-module_exit(atmel_ssc_modexit);
+module_exit(snd_atmel_ssc_exit);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
index 391135f9c6c10b0057b7a1b742da180ca44927f2..5d4f0f9b4d9a875eb935ec79488b76ff17073ab0 100644 (file)
@@ -116,6 +116,7 @@ struct atmel_ssc_info {
        struct atmel_pcm_dma_params *dma_params[2];
        struct atmel_ssc_state ssc_state;
 };
-extern struct snd_soc_dai atmel_ssc_dai[];
+
+int atmel_ssc_set_audio(int ssc);
 
 #endif /* _AT91_SSC_DAI_H */
index 9df4c68ef000440cfeccd0cd0123de35c03e2a76..5f4e59f4461c3599a1cf3443e48d96e1e2aeee73 100644 (file)
@@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *cpu_dai)
 {
-       struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssc_device *ssc = ssc_p->ssc;
        struct ssc_clock_data cd;
        unsigned int rate, width_bits, channels;
@@ -131,9 +131,9 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssc_device *ssc = ssc_p->ssc;
        unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
        int ret;
@@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 
 
-static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int i;
 
        /*
@@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 
 
        /* Make CSB show PLL rate */
-       snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+       snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
                                       WM8510_OPCLKDIV_1 | 4);
 
        return 0;
@@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link playpaq_wm8510_dai = {
        .name = "WM8510",
        .stream_name = "WM8510 PCM",
-       .cpu_dai = &at32_ssc_dai[0],
-       .codec_dai = &wm8510_dai,
+       .cpu_dai_name= "atmel-ssc-dai.0",
+       .platform_name = "atmel-pcm-audio",
+       .codec_name = "wm8510-codec.0-0x1a",
+       .codec_dai_name = "wm8510-hifi",
        .init = playpaq_wm8510_init,
        .ops = &playpaq_wm8510_ops,
 };
@@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
 
 static struct snd_soc_card snd_soc_playpaq = {
        .name = "LRS_PlayPaq_WM8510",
-       .platform = &at32_soc_platform,
        .dai_link = &playpaq_wm8510_dai,
        .num_links = 1,
 };
 
-
-
-static struct wm8510_setup_data playpaq_wm8510_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1a,
-};
-
-
-
-static struct snd_soc_device playpaq_wm8510_snd_devdata = {
-       .card = &snd_soc_playpaq,
-       .codec_dev = &soc_codec_dev_wm8510,
-       .codec_data = &playpaq_wm8510_setup,
-};
-
 static struct platform_device *playpaq_snd_device;
 
 
 static int __init playpaq_asoc_init(void)
 {
        int ret = 0;
-       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
-
-
-       /*
-        * Request SSC device
-        */
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               ret = PTR_ERR(ssc);
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
-
 
        /*
         * Configure MCLK for WM8510
@@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
                goto err_device_alloc;
        }
 
-       platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
-       playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+       platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
 
        ret = platform_device_add(playpaq_snd_device);
        if (ret) {
@@ -468,25 +440,12 @@ err_pll0:
                clk_put(_gclk0);
                _gclk0 = NULL;
        }
-err_gclk0:
-       ssc_free(ssc);
-err_ssc:
        return ret;
 }
 
 
 static void __exit playpaq_asoc_exit(void)
 {
-       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-       struct ssc_device *ssc;
-
-       if (ssc_p != NULL) {
-               ssc = ssc_p->ssc;
-               if (ssc != NULL)
-                       ssc_free(ssc);
-               ssc_p->ssc = NULL;
-       }
-
        if (_gclk0 != NULL) {
                clk_put(_gclk0);
                _gclk0 = NULL;
index e028744c32ce9928c9160cc4f79f10642fa1d693..293569dfd0edec6d70551d90e610a93bba74ad7f 100644 (file)
@@ -69,8 +69,8 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* set codec DAI configuration */
@@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
 /*
  * Logic for a wm8731 as connected on a at91sam9g20ek board.
  */
-static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = &codec->dai[0];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
        printk(KERN_DEBUG
                        "at91sam9g20ek_wm8731 "
                        ": at91sam9g20ek_wm8731_init() called\n");
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                MCLK_RATE, SND_SOC_CLOCK_IN);
        if (ret < 0) {
                printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .name = "WM8731",
        .stream_name = "WM8731 PCM",
-       .cpu_dai = &atmel_ssc_dai[0],
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "atmel-ssc-dai.0",
+       .codec_dai_name = "wm8731-hifi",
        .init = at91sam9g20ek_wm8731_init,
+       .platform_name = "atmel-pcm-audio",
+       .codec_name = "wm8731-codec.0-001b",
        .ops = &at91sam9g20ek_ops,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .name = "AT91SAMG20-EK",
-       .platform = &atmel_soc_platform,
        .dai_link = &at91sam9g20ek_dai,
        .num_links = 1,
        .set_bias_level = at91sam9g20ek_set_bias_level,
 };
 
-static struct snd_soc_device at91sam9g20ek_snd_devdata = {
-       .card = &snd_soc_at91sam9g20ek,
-       .codec_dev = &soc_codec_dev_wm8731,
-};
-
 static struct platform_device *at91sam9g20ek_snd_device;
 
 static int __init at91sam9g20ek_init(void)
 {
-       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
        struct clk *pllb;
        int ret;
 
        if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
                return -ENODEV;
 
+       ret = atmel_ssc_set_audio(0);
+       if (ret != 0) {
+               pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+               return ret;
+       }
+
        /*
         * Codec MCLK is supplied by PCK0 - set it up.
         */
@@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
 
        clk_set_rate(mclk, MCLK_RATE);
 
-       /*
-        * Request SSC device
-        */
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-               ret = PTR_ERR(ssc);
-               ssc = NULL;
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
-
        at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
        if (!at91sam9g20ek_snd_device) {
                printk(KERN_ERR "ASoC: Platform device allocation failed\n");
@@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
        }
 
        platform_set_drvdata(at91sam9g20ek_snd_device,
-                       &at91sam9g20ek_snd_devdata);
-       at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+                       &snd_soc_at91sam9g20ek);
 
        ret = platform_device_add(at91sam9g20ek_snd_device);
        if (ret) {
@@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
 
        return ret;
 
-err_ssc:
-       ssc_free(ssc);
-       ssc_p->ssc = NULL;
 err_mclk:
        clk_put(mclk);
        mclk = NULL;
@@ -277,16 +262,6 @@ err:
 
 static void __exit at91sam9g20ek_exit(void)
 {
-       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-       struct ssc_device *ssc;
-
-       if (ssc_p != NULL) {
-               ssc = ssc_p->ssc;
-               if (ssc != NULL)
-                       ssc_free(ssc);
-               ssc_p->ssc = NULL;
-       }
-
        platform_device_unregister(at91sam9g20ek_snd_device);
        at91sam9g20ek_snd_device = NULL;
        clk_put(mclk);
index 23349de273134871e153ce42a1129815c4fae745..e3d283561c196a8198e97d6bf2cc3b1b11987624 100644 (file)
@@ -46,8 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Add afeb9260 specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link afeb9260_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &atmel_ssc_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name = "atmel-ssc-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "atmel_pcm-audio",
+       .codec_name = "tlv320aic23-codec.0-0x1a",
        .init = afeb9260_tlv320aic23_init,
        .ops = &afeb9260_ops,
 };
@@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_machine_afeb9260 = {
        .name = "AFEB9260",
-       .platform = &atmel_soc_platform,
        .dai_link = &afeb9260_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device afeb9260_snd_devdata = {
-       .card = &snd_soc_machine_afeb9260,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *afeb9260_snd_device;
 
 static int __init afeb9260_soc_init(void)
 {
        int err;
        struct device *dev;
-       struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
 
        if (!(machine_is_afeb9260()))
                return -ENODEV;
 
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-               err = PTR_ERR(ssc);
-               ssc = NULL;
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
 
        afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
        if (!afeb9260_snd_device) {
@@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
-       afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+       platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
        err = platform_device_add(afeb9260_snd_device);
        if (err)
                goto err1;
@@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
 err1:
        platform_device_del(afeb9260_snd_device);
        platform_device_put(afeb9260_snd_device);
-err_ssc:
        return err;
-
 }
 
 static void __exit afeb9260_soc_exit(void)
index cdf7be1b9b91095ce0053e0c39595c4f5911ebb1..b62fcd33e586f812b9c556002bdec1b44ee774aa 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-db1x00/bcsr.h>
 
-#include "../codecs/ac97.h"
 #include "../codecs/wm8731.h"
 #include "psc.h"
 
 static struct snd_soc_dai_link db1200_ac97_dai = {
        .name           = "AC97",
        .stream_name    = "AC97 HiFi",
-       .cpu_dai        = &au1xpsc_ac97_dai,
-       .codec_dai      = &ac97_dai,
+       .codec_dai_name = "ac97-hifi",
+       .cpu_dai_name   = "au1xpsc_ac97.1",
+       .platform_name  = "au1xpsc-pcm.1",
+       .codec_name     = "ac97-codec.1",
 };
 
 static struct snd_soc_card db1200_ac97_machine = {
        .name           = "DB1200_AC97",
        .dai_link       = &db1200_ac97_dai,
        .num_links      = 1,
-       .platform       = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_ac97_devdata = {
-       .card           = &db1200_ac97_machine,
-       .codec_dev      = &soc_codec_dev_ac97,
 };
 
 /*-------------------------  I2S PART  ---------------------------*/
@@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
 static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* WM8731 has its own 12MHz crystal */
-       snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+       snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                                12000000, SND_SOC_CLOCK_IN);
 
        /* codec is bitclock and lrclk master */
@@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
 static struct snd_soc_dai_link db1200_i2s_dai = {
        .name           = "WM8731",
        .stream_name    = "WM8731 PCM",
-       .cpu_dai        = &au1xpsc_i2s_dai,
-       .codec_dai      = &wm8731_dai,
+       .codec_dai_name = "wm8731-hifi",
+       .cpu_dai_name   = "au1xpsc_i2s.1",
+       .platform_name  = "au1xpsc-pcm.1",
+       .codec_name     = "wm8731-codec.0-001b",
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
@@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
        .name           = "DB1200_I2S",
        .dai_link       = &db1200_i2s_dai,
        .num_links      = 1,
-       .platform       = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_i2s_devdata = {
-       .card           = &db1200_i2s_machine,
-       .codec_dev      = &soc_codec_dev_wm8731,
 };
 
 /*-------------------------  COMMON PART  ---------------------------*/
@@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
        int ret;
 
        ret = -ENOMEM;
-       db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+       db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
        if (!db1200_asoc_dev)
                goto out;
 
        /* DB1200 board setup set PSC1MUX to preferred audio device */
        if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
-               platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
+               platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
        else
-               platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
+               platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
 
-       db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
-       db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
        ret = platform_device_add(db1200_asoc_dev);
 
        if (ret) {
index 6d9f4c624949ed65906433a2efc2caa33bde841d..10fdd2854e584aaf17593521458abc4ba6a0818b 100644 (file)
@@ -10,9 +10,6 @@
  *
  * DMA glue for Au1x-PSC audio.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
        int msbits;
 };
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
 /*
  * These settings are somewhat okay, at least on my machine audio plays
  * almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@ out:
        return 0;
 }
 
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+       struct au1xpsc_audio_dmadata *pcd =
+                               snd_soc_platform_get_drvdata(rtd->platform);
+       return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params)
 {
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
                goto out;
 
        stype = SUBSTREAM_TYPE(substream);
-       pcd = au1xpsc_audio_pcmdma[stype];
+       pcd = to_dmadata(substream);
 
        DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
            "runtime->min_align %d\n",
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct au1xpsc_audio_dmadata *pcd =
-                       au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+       struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
 
        au1xxx_dbdma_reset(pcd->ddma_chan);
 
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+       u32 c = to_dmadata(substream)->ddma_chan;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t
 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       return bytes_to_frames(substream->runtime,
-               au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+       return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
 }
 
 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
 {
-       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+       au1x_pcm_dbdma_free(to_dmadata(substream));
        return 0;
 }
 
@@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
        return 0;
 }
 
-static int au1xpsc_pcm_probe(struct platform_device *pdev)
-{
-       if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
-               return -ENODEV;
-
-       return 0;
-}
-
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 /* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
-       .name           = "au1xpsc-pcm-dbdma",
-       .probe          = au1xpsc_pcm_probe,
-       .remove         = au1xpsc_pcm_remove,
-       .pcm_ops        = &au1xpsc_pcm_ops,
+struct snd_soc_platform_driver au1xpsc_soc_platform = {
+       .ops            = &au1xpsc_pcm_ops,
        .pcm_new        = au1xpsc_pcm_new,
        .pcm_free       = au1xpsc_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
 
 static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 {
+       struct au1xpsc_audio_dmadata *dmadata;
        struct resource *r;
        int ret;
 
-       if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
-               return -EBUSY;
-
-       /* TX DMA */
-       au1xpsc_audio_pcmdma[PCM_TX]
-               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-       if (!au1xpsc_audio_pcmdma[PCM_TX])
+       dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+       if (!dmadata)
                return -ENOMEM;
 
        r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
                ret = -ENODEV;
                goto out1;
        }
-       (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+       dmadata[PCM_TX].ddma_id = r->start;
 
        /* RX DMA */
-       au1xpsc_audio_pcmdma[PCM_RX]
-               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-       if (!au1xpsc_audio_pcmdma[PCM_RX])
-               return -ENOMEM;
-
        r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!r) {
                ret = -ENODEV;
-               goto out2;
+               goto out1;
        }
-       (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+       dmadata[PCM_RX].ddma_id = r->start;
+
+       platform_set_drvdata(pdev, dmadata);
 
-       ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
        if (!ret)
                return ret;
 
-out2:
-       kfree(au1xpsc_audio_pcmdma[PCM_RX]);
-       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
 out1:
-       kfree(au1xpsc_audio_pcmdma[PCM_TX]);
-       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+       kfree(dmadata);
        return ret;
 }
 
 static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
 {
-       int i;
+       struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_platform(&au1xpsc_soc_platform);
-
-       for (i = 0; i < 2; i++) {
-               if (au1xpsc_audio_pcmdma[i]) {
-                       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
-                       kfree(au1xpsc_audio_pcmdma[i]);
-                       au1xpsc_audio_pcmdma[i] = NULL;
-               }
-       }
+       snd_soc_unregister_platform(&pdev->dev);
+       kfree(dmadata);
 
        return 0;
 }
@@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
 
 static int __init au1xpsc_audio_dbdma_load(void)
 {
-       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
-       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
        return platform_driver_register(&au1xpsc_pcm_driver);
 }
 
@@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
        res[1].start = res[1].end = id[1];
        res[0].flags = res[1].flags = IORESOURCE_DMA;
 
-       pd = platform_device_alloc("au1xpsc-pcm", -1);
+       pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
        if (!pd)
                goto out;
 
index d14a5a91a4654dc347af790ace1244479659fb36..d0db66f24a00cc0ce68f622161bef3b4155a7c82 100644 (file)
@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC AC97 glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 #include <linux/init.h>
 /* instance data. There can be only one, MacLeod!!!! */
 static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
 
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+       struct snd_soc_card *c = x->bus->card->private_data;
+       return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x)     au1xpsc_ac97_workdata
+
+#endif
+
 /* AC97 controller reads codec register */
 static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
                                        unsigned short reg)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        unsigned short retry, tmo;
        unsigned long data;
 
@@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
 static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short val)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        unsigned int tmo, retry;
 
        au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 /* AC97 controller asserts a warm reset */
 static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 
        au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
        au_sync();
@@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 
 static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        int i;
 
        /* disable PSC during cold reset */
@@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        unsigned long r, ro, stat;
        int chans, t, stype = SUBSTREAM_TYPE(substream);
 
@@ -283,8 +293,7 @@ out:
 static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        int ret, stype = SUBSTREAM_TYPE(substream);
 
        ret = 0;
@@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static int au1xpsc_ac97_probe(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
 {
        return au1xpsc_ac97_workdata ? 0 : -ENODEV;
 }
 
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
        .trigger        = au1xpsc_ac97_trigger,
        .hw_params      = au1xpsc_ac97_hw_params,
 };
 
-struct snd_soc_dai au1xpsc_ac97_dai = {
-       .name                   = "au1xpsc_ac97",
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
        .ac97_control           = 1,
        .probe                  = au1xpsc_ac97_probe,
-       .remove                 = au1xpsc_ac97_remove,
        .playback = {
                .rates          = AC97_RATES,
                .formats        = AC97_FMTS,
@@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
        },
        .ops = &au1xpsc_ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 
 static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
@@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        unsigned long sel;
        struct au1xpsc_audio_data *wd;
 
-       if (au1xpsc_ac97_workdata)
-               return -EBUSY;
-
        wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
@@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
        au_sync();
 
-       ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+       /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+       memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+              sizeof(struct snd_soc_dai_driver));
+       wd->dai_drv.name = dev_name(&pdev->dev);
+
+       platform_set_drvdata(pdev, wd);
+
+       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
        if (ret)
                goto out1;
 
        wd->dmapd = au1xpsc_pcm_add(pdev);
        if (wd->dmapd) {
-               platform_set_drvdata(pdev, wd);
-               au1xpsc_ac97_workdata = wd;     /* MDEV */
+               au1xpsc_ac97_workdata = wd;
                return 0;
        }
 
-       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 out1:
        release_mem_region(r->start, resource_size(r));
 out0:
@@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
        if (wd->dmapd)
                au1xpsc_pcm_destroy(wd->dmapd);
 
-       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        /* disable PSC completely */
        au_writel(0, AC97_CFG(wd));
index 6083fe7799faba3b6b4737136b12d74cc428f59b..fca091276320930e7f8abd230556dabbc392e2d7 100644 (file)
@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC I2S glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  * NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
  */
 
        ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
 
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
 static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                               unsigned int fmt)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long ct;
        int ret;
 
@@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 
        int cfgbits;
        unsigned long stat;
@@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
 static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        int ret, stype = SUBSTREAM_TYPE(substream);
 
        switch (cmd) {
@@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int au1xpsc_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
-{
-       return  au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
        .trigger        = au1xpsc_i2s_trigger,
        .hw_params      = au1xpsc_i2s_hw_params,
        .set_fmt        = au1xpsc_i2s_set_fmt,
 };
 
-struct snd_soc_dai au1xpsc_i2s_dai = {
-       .name                   = "au1xpsc_i2s",
-       .probe                  = au1xpsc_i2s_probe,
-       .remove                 = au1xpsc_i2s_remove,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
        .playback = {
                .rates          = AU1XPSC_I2S_RATES,
                .formats        = AU1XPSC_I2S_FMTS,
@@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
        },
        .ops = &au1xpsc_i2s_dai_ops,
 };
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
 
 static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
@@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
        int ret;
        struct au1xpsc_audio_data *wd;
 
-       if (au1xpsc_i2s_workdata)
-               return -EBUSY;
-
        wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
@@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
         * time out.
         */
 
-       ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+       /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+       memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+              sizeof(struct snd_soc_dai_driver));
+       wd->dai_drv.name = dev_name(&pdev->dev);
+
+       platform_set_drvdata(pdev, wd);
+
+       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
        if (ret)
                goto out1;
 
        /* finally add the DMA device for this PSC */
        wd->dmapd = au1xpsc_pcm_add(pdev);
-       if (wd->dmapd) {
-               platform_set_drvdata(pdev, wd);
-               au1xpsc_i2s_workdata = wd;
+       if (wd->dmapd)
                return 0;
-       }
 
-       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 out1:
        release_mem_region(r->start, resource_size(r));
 out0:
@@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
        if (wd->dmapd)
                au1xpsc_pcm_destroy(wd->dmapd);
 
-       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        au_writel(0, I2S_CFG(wd));
        au_sync();
@@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
        release_mem_region(r->start, resource_size(r));
        kfree(wd);
 
-       au1xpsc_i2s_workdata = NULL;    /* MDEV */
-
        return 0;
 }
 
@@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
 
 static int __init au1xpsc_i2s_load(void)
 {
-       au1xpsc_i2s_workdata = NULL;
        return platform_driver_register(&au1xpsc_i2s_driver);
 }
 
index 093775d4dc3e47185759c737e1bb18338a615b7c..b30eadd422a7fb7aee4856e671d491d769d2c6ac 100644 (file)
@@ -8,19 +8,11 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 #ifndef _AU1X_PCM_H
 #define _AU1X_PCM_H
 
-extern struct snd_soc_dai au1xpsc_ac97_dai;
-extern struct snd_soc_dai au1xpsc_i2s_dai;
-extern struct snd_soc_platform au1xpsc_soc_platform;
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
 /* DBDMA helpers */
 extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
 extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
        unsigned long cfg;
        unsigned long rate;
 
+       struct snd_soc_dai_driver dai_drv;
+
        unsigned long pm[2];
        struct mutex lock;
        struct platform_device *dmapd;
index 5e7aacf3bb5a2027c2decfe98e3b49919c04a207..5a2fd8abaefaee65e5509e4c98adf252c06293df 100644 (file)
@@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform bf5xx_ac97_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_ac97_ops,
+static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+       .ops                    = &bf5xx_pcm_ac97_ops,
        .pcm_new        = bf5xx_pcm_ac97_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
 
-static int __init bfin_ac97_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
 }
-module_init(bfin_ac97_init);
 
-static void __exit bfin_ac97_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bf5xx_pcm_driver = {
+       .driver = {
+                       .name = "bf5xx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bf5xx_soc_platform_probe,
+       .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bf5xx_pcm_init(void)
+{
+       return platform_driver_register(&bf5xx_pcm_driver);
+}
+module_init(snd_bf5xx_pcm_init);
+
+static void __exit snd_bf5xx_pcm_exit(void)
+{
+       platform_driver_unregister(&bf5xx_pcm_driver);
 }
-module_exit(bfin_ac97_exit);
+module_exit(snd_bf5xx_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
index 350125a0ae21282a74acd35c007c98de97d741f1..d324d5826a9baaaba648129bd21e2634160666df 100644 (file)
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
        u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_ac97_soc_platform;
-
 #endif
index c0eba51099804fcebc40ee13d5b495b3106448f2..c5f856ec27ca1bedc8d0256cf5fe97d11ebac730 100644 (file)
@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
 #ifdef CONFIG_PM
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 {
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
        if (!dai->active)
@@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 {
        int ret;
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
        if (!dai->active)
@@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume      NULL
 #endif
 
-static int bf5xx_ac97_probe(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 {
        int ret = 0;
        cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
@@ -379,8 +378,7 @@ peripheral_err:
        return ret;
 }
 
-static void bf5xx_ac97_remove(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
 {
        free_page((unsigned long)cmd_count);
        cmd_count = NULL;
@@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
+       return 0;
 }
 
-struct snd_soc_dai bfin_ac97_dai = {
-       .name = "bf5xx-ac97",
-       .id = 0,
+struct snd_soc_dai_driver bfin_ac97_dai = {
        .ac97_control = 1,
        .probe = bf5xx_ac97_probe,
        .remove = bf5xx_ac97_remove,
@@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
 };
 EXPORT_SYMBOL_GPL(bfin_ac97_dai);
 
+static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+}
+
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_bfin_ac97_driver = {
+       .driver = {
+                       .name = "bfin-ac97",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_bfin_ac97_probe,
+       .remove = __devexit_p(asoc_bfin_ac97_remove),
+};
+
 static int __init bfin_ac97_init(void)
 {
-       return snd_soc_register_dai(&bfin_ac97_dai);
+       return platform_driver_register(&asoc_bfin_ac97_driver);
 }
 module_init(bfin_ac97_init);
 
 static void __exit bfin_ac97_exit(void)
 {
-       snd_soc_unregister_dai(&bfin_ac97_dai);
+       platform_driver_unregister(&asoc_bfin_ac97_driver);
 }
 module_exit(bfin_ac97_exit);
 
+
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
 MODULE_LICENSE("GPL");
index a1f97dd809d63fda550f4d62cd18a5a2c1eb7bde..15c635e33f4d99a42b6386cbc7e7c54e2bf807ef 100644 (file)
@@ -50,8 +50,6 @@ struct ac97_frame {
 #define TAG_PCM_SR             0x0080
 #define TAG_PCM_LFE            0x0040
 
-extern struct snd_soc_dai bfin_ac97_dai;
-
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
                size_t count, unsigned int chan_mask);
 
index 0f45a3f56be8f3ff4ae335941d30c0fda62d24b8..2394bff2b655bce897b5ea209f134744dc8ffc94 100644 (file)
@@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
 static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -50,8 +50,8 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
        int ret = 0;
        /* set cpu DAI configuration */
@@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
 static struct snd_soc_dai_link bf5xx_ad1836_dai = {
        .name = "ad1836",
        .stream_name = "AD1836",
-       .cpu_dai = &bf5xx_tdm_dai,
-       .codec_dai = &ad1836_dai,
+       .cpu_dai_name = "bf5xx-tdm",
+       .codec_dai_name = "ad1836-hifi",
+       .platform_name = "bf5xx-tdm-pcm-audio",
+       .codec_name = "ad1836-codec.0",
        .ops = &bf5xx_ad1836_ops,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
        .name = "bf5xx_ad1836",
-       .platform = &bf5xx_tdm_soc_platform,
        .dai_link = &bf5xx_ad1836_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
-       .card = &bf5xx_ad1836,
-       .codec_dev = &soc_codec_dev_ad1836,
-};
-
 static struct platform_device *bfxx_ad1836_snd_device;
 
 static int __init bf5xx_ad1836_init(void)
@@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
        if (!bfxx_ad1836_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
-       bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
+       platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
        ret = platform_device_add(bfxx_ad1836_snd_device);
 
        if (ret)
index b8c9060cfd8e801d15620d2c710f62a96c96c02d..e4a625317a1acde4e62ea0cc9a03eeaf0ad2e00f 100644 (file)
@@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
 static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -59,8 +59,8 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
        int ret = 0;
        /* set cpu DAI configuration */
@@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
 static struct snd_soc_dai_link bf5xx_ad193x_dai = {
        .name = "ad193x",
        .stream_name = "AD193X",
-       .cpu_dai = &bf5xx_tdm_dai,
-       .codec_dai = &ad193x_dai,
+       .cpu_dai_name = "bf5xx-tdm",
+       .codec_dai_name ="ad193x-hifi",
+       .platform_name = "bf5xx-tdm-pcm-audio",
+       .codec_name = "ad193x-codec.5",
        .ops = &bf5xx_ad193x_ops,
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
        .name = "bf5xx_ad193x",
-       .platform = &bf5xx_tdm_soc_platform,
        .dai_link = &bf5xx_ad193x_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
-       .card = &bf5xx_ad193x,
-       .codec_dev = &soc_codec_dev_ad193x,
-};
-
 static struct platform_device *bfxx_ad193x_snd_device;
 
 static int __init bf5xx_ad193x_init(void)
@@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
        if (!bfxx_ad193x_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
-       bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
+       platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
        ret = platform_device_add(bfxx_ad193x_snd_device);
 
        if (ret)
index 92f7c327bb7a371c93d4298e6541fb9bc31b925f..d57c9c9c9883207039174b71cdfa490b64109dfa 100644 (file)
@@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
 static int bf5xx_board_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
 static struct snd_soc_dai_link bf5xx_board_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &bfin_ac97_dai,
-       .codec_dai = &ad1980_dai,
+       .cpu_dai_name = "bfin-ac97",
+       .codec_dai_name = "ad1980-hifi",
+       .platform_name = "bfin-pcm-audio",
+       .codec_name = "ad1980-codec",
        .ops = &bf5xx_board_ops,
 };
 
 static struct snd_soc_card bf5xx_board = {
        .name = "bf5xx-board",
-       .platform = &bf5xx_ac97_soc_platform,
        .dai_link = &bf5xx_board_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_board_snd_devdata = {
-       .card = &bf5xx_board,
-       .codec_dev = &soc_codec_dev_ad1980,
-};
-
 static struct platform_device *bf5xx_board_snd_device;
 
 static int __init bf5xx_board_init(void)
@@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
        if (!bf5xx_board_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
-       bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+       platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
        ret = platform_device_add(bf5xx_board_snd_device);
 
        if (ret)
index 9825b71d0e28a3a7002ab690afcc867efaaf7123..900ced54ac79bee6290e917f99faba5c71f1cb7d 100644 (file)
@@ -47,7 +47,6 @@
 #include "../codecs/ad73311.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 #if CONFIG_SND_BF5XX_SPORT_NUM == 0
 #define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
@@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
 static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -161,7 +160,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
@@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
 static struct snd_soc_dai_link bf5xx_ad73311_dai = {
        .name = "ad73311",
        .stream_name = "AD73311",
-       .cpu_dai = &bf5xx_i2s_dai,
-       .codec_dai = &ad73311_dai,
+       .cpu_dai_name = "bf5xx-i2s",
+       .codec_dai_name = "ad73311-hifi",
+       .platform_name = "bfin-pcm-audio",
+       .codec_name = "ad73311-codec",
        .ops = &bf5xx_ad73311_ops,
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
        .name = "bf5xx_ad73311",
-       .platform = &bf5xx_i2s_soc_platform,
        .probe = bf5xx_probe,
        .dai_link = &bf5xx_ad73311_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
-       .card = &bf5xx_ad73311,
-       .codec_dev = &soc_codec_dev_ad73311,
-};
-
 static struct platform_device *bf5xx_ad73311_snd_device;
 
 static int __init bf5xx_ad73311_init(void)
@@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
        if (!bf5xx_ad73311_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
-       bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+       platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
        ret = platform_device_add(bf5xx_ad73311_snd_device);
 
        if (ret)
index 1d2a1adf25759070cfa96a3cab81c89c31630b30..890a0dccf902a4fc14922cd11565406df86ec0b7 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/dma.h>
 
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 #include "bf5xx-sport.h"
 
 static void bf5xx_dma_irq(void *data)
@@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform bf5xx_i2s_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_i2s_ops,
+static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+       .ops            = &bf5xx_pcm_i2s_ops,
        .pcm_new        = bf5xx_pcm_i2s_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
 
-static int __init bfin_i2s_init(void)
+static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
 }
-module_init(bfin_i2s_init);
 
-static void __exit bfin_i2s_exit(void)
+static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_i2s_pcm_driver = {
+       .driver = {
+                       .name = "bfin-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bfin_i2s_soc_platform_probe,
+       .remove = __devexit_p(bfin_i2s_soc_platform_remove),
+};
+
+static int __init snd_bfin_i2s_pcm_init(void)
+{
+       return platform_driver_register(&bfin_i2s_pcm_driver);
+}
+module_init(snd_bfin_i2s_pcm_init);
+
+static void __exit snd_bfin_i2s_pcm_exit(void)
+{
+       platform_driver_unregister(&bfin_i2s_pcm_driver);
 }
-module_exit(bfin_i2s_exit);
+module_exit(snd_bfin_i2s_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
index 4d4609a97c598df1a8ec0dddd2a7d76618b41f3a..0c2c5a68d4fff43bc2438749bceb7c5bc1b32148 100644 (file)
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
        u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_i2s_soc_platform;
-
 #endif
index 3e6ada0dd1c42ef1b07ee144aca320fea9ebeaf5..d453b1e9d607d0d0e9d712bf981a3e6dda4ae17f 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/gpio.h>
 
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s.h"
 
 struct bf5xx_i2s_port {
        u16 tcr1;
@@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
                bf5xx_i2s.configured = 0;
 }
 
-static int bf5xx_i2s_probe(struct platform_device *pdev,
-                          struct snd_soc_dai *dai)
+static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
        if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
@@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
        return 0;
 }
 
-static void bf5xx_i2s_remove(struct platform_device *pdev,
-                       struct snd_soc_dai *dai)
+static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
        peripheral_free_list(&sport_req[sport_num][0]);
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
-       if (dai->capture.active)
+       if (dai->capture_active)
                sport_rx_stop(sport_handle);
-       if (dai->playback.active)
+       if (dai->playback_active)
                sport_tx_stop(sport_handle);
        return 0;
 }
@@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
        .set_fmt        = bf5xx_i2s_set_dai_fmt,
 };
 
-struct snd_soc_dai bf5xx_i2s_dai = {
-       .name = "bf5xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .probe = bf5xx_i2s_probe,
        .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
@@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
                .formats = BF5XX_I2S_FORMATS,},
        .ops = &bf5xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+static int bfin_i2s_drv_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+}
+
+static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+       .probe = bfin_i2s_drv_probe,
+       .remove = __devexit_p(bfin_i2s_drv_remove),
+
+       .driver = {
+               .name = "bf5xx-i2s",
+               .owner = THIS_MODULE,
+       },
+};
 
 static int __init bfin_i2s_init(void)
 {
-       return snd_soc_register_dai(&bf5xx_i2s_dai);
+       return platform_driver_register(&bfin_i2s_driver);
 }
-module_init(bfin_i2s_init);
 
 static void __exit bfin_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&bf5xx_i2s_dai);
+       platform_driver_unregister(&bfin_i2s_driver);
 }
+
+module_init(bfin_i2s_init);
 module_exit(bfin_i2s_exit);
 
 /* Module information */
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
deleted file mode 100644 (file)
index 264ecdc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-i2s.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.
- */
-
-#ifndef _BF5XX_I2S_H
-#define _BF5XX_I2S_H
-
-extern struct snd_soc_dai bf5xx_i2s_dai;
-
-#endif
index 3a00fa4dbe6d4202d5e32647a684000335c71e29..36f2769eb912b67c04bb08cb60a28681f7977f29 100644 (file)
 #include "../codecs/ssm2602.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 static struct snd_soc_card bf5xx_ssm2602;
 
 static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -60,8 +59,8 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
 static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
        .name = "ssm2602",
        .stream_name = "SSM2602",
-       .cpu_dai = &bf5xx_i2s_dai,
-       .codec_dai = &ssm2602_dai,
+       .cpu_dai_name = "bf5xx-i2s",
+       .codec_dai_name = "ssm2602-hifi",
+       .platform_name = "bf5xx-pcm-audio",
+       .codec_name = "ssm2602-codec.0-0x1b",
        .ops = &bf5xx_ssm2602_ops,
 };
 
-/*
- * SSM2602 2 wire address is determined by CSB
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-
-static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1b,
-};
-
 static struct snd_soc_card bf5xx_ssm2602 = {
        .name = "bf5xx_ssm2602",
-       .platform = &bf5xx_i2s_soc_platform,
        .dai_link = &bf5xx_ssm2602_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
-       .card = &bf5xx_ssm2602,
-       .codec_dev = &soc_codec_dev_ssm2602,
-       .codec_data = &bf5xx_ssm2602_setup,
-};
-
 static struct platform_device *bf5xx_ssm2602_snd_device;
 
 static int __init bf5xx_ssm2602_init(void)
@@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
        if (!bf5xx_ssm2602_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_ssm2602_snd_device,
-                               &bf5xx_ssm2602_snd_devdata);
-       bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+       platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
        ret = platform_device_add(bf5xx_ssm2602_snd_device);
 
        if (ret)
index 6bac1ac1a315b72ee8b9fe134f4b94665a2cb47b..74cf759b78a6ceac0fa2210e25f540e191ed1e08 100644 (file)
@@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -307,25 +307,44 @@ out:
        return ret;
 }
 
-struct snd_soc_platform bf5xx_tdm_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_tdm_ops,
+static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
+       .ops        = &bf5xx_pcm_tdm_ops,
        .pcm_new        = bf5xx_pcm_tdm_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
 
-static int __init bfin_pcm_tdm_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
 }
-module_init(bfin_pcm_tdm_init);
 
-static void __exit bfin_pcm_tdm_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_tdm_driver = {
+       .driver = {
+                       .name = "bf5xx-tdm-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bf5xx_soc_platform_probe,
+       .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bfin_tdm_init(void)
+{
+       return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(snd_bfin_tdm_init);
+
+static void __exit snd_bfin_tdm_exit(void)
+{
+       platform_driver_unregister(&bfin_tdm_driver);
 }
-module_exit(bfin_pcm_tdm_exit);
+module_exit(snd_bfin_tdm_exit);
 
 MODULE_AUTHOR("Barry Song");
 MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
index ddc5047df88c9b00477ec7034884609c3cc9dce6..7f8cc01c447714326e88c126fc850fc87405c382 100644 (file)
@@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
        char *name;                     /* stream identifier */
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_tdm_soc_platform;
-
 #endif
index 24c14269f4bc498601fb920e130b1ff44c5d4028..125123929f16c28d1e52ca01ebde662196f66253 100644 (file)
@@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 
        if (!dai->active)
                return 0;
-       if (dai->capture.active)
+       if (dai->capture_active)
                sport_rx_stop(sport);
-       if (dai->playback.active)
+       if (dai->playback_active)
                sport_tx_stop(sport);
        return 0;
 }
@@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 {
        int ret;
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return 0;
@@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
        .set_channel_map   = bf5xx_tdm_set_channel_map,
 };
 
-struct snd_soc_dai bf5xx_tdm_dai = {
-       .name = "bf5xx-tdm",
-       .id = 0,
+static struct snd_soc_dai_driver bf5xx_tdm_dai = {
        .suspend = bf5xx_tdm_suspend,
        .resume = bf5xx_tdm_resume,
        .playback = {
@@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
                .formats = SNDRV_PCM_FMTBIT_S32_LE,},
        .ops = &bf5xx_tdm_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
@@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -337,7 +334,7 @@ sport_config_err:
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
        peripheral_free_list(&sport_req[sport_num][0]);
-       snd_soc_unregister_dai(&bf5xx_tdm_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        return 0;
 }
index 04189a18c1bad941dc0a77d6d66134b7492109a7..e986a3ea3315781afadda87eff824944ae07d78a 100644 (file)
@@ -20,6 +20,4 @@ struct bf5xx_tdm_port {
        int configured;
 };
 
-extern struct snd_soc_dai bf5xx_tdm_dai;
-
 #endif
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644 (file)
index 0000000..01d19e9
--- /dev/null
@@ -0,0 +1,1486 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN           20
+#define REG_CACHE_SIZE         0x40
+#define REG_CACHE_BASE         0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1           0x01
+#define MIC_STATUS             (1 << 7)
+#define HOOK_STATUS            (1 << 6)
+#define HEADSET_STATUS         (1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET            0x37
+#define CONTINUOUS_POLLING     (3 << 1)
+#define EN_MIC_DET             (1 << 0)
+#define MICDET_MASK            0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET             0x38
+#define EN_HS_DET              (1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2              0x42
+#define AUDIO_PLL              (1 << 5)
+#define AUDIO_SECTION_RESET    (1 << 4)
+#define AUDIO_SECTION_ON       (1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK          (1 << 6)        /* Bit clock polarity */
+#define PCM_INF2_FS            (1 << 5)        /* Frame Sync polarity */
+#define PCM_INF2_MASTER                (1 << 4)        /* Master / Slave */
+#define PCM_INF2_18WL          (1 << 3)        /* 18 / 16 bits */
+#define PCM_GENERAL_I2S                0
+#define PCM_EXACT_I2S          1
+#define PCM_LEFT_I2S           2
+#define PCM_RIGHT_I2S          3
+#define PCM_SHORT_FS           4
+#define PCM_LONG_FS            5
+#define PCM_MODE_MASK          7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP            (1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE               (1 << 7)
+#define MUTE_LEFT              (1 << 6)
+#define MUTE_RIGHT             (1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1          0xd0
+#define MIC1BIAS_MASK          0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2               0xda
+#define RSYNC_CHANGE           (1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2          0xdc
+#define LDO15_READY            (1 << 4)
+#define LDO15_EN               (1 << 3)
+#define CPUMP_READY            (1 << 2)
+#define CPUMP_EN               (1 << 1)
+#define AUDIO_EN               (1 << 0)
+#define SUPPLY_MASK            (LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT          (1 << 1)
+#define ADC_MOD_LEFT           (1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT               (1 << 5)
+#define ADC_RIGHT              (1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT               (1 << 5)
+#define DAC_RIGHT              (1 << 4)
+#define MODULATOR              (1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS             0xeb
+#define CLR_SHORT_LO2          (1 << 7)
+#define SHORT_LO2              (1 << 6)
+#define CLR_SHORT_LO1          (1 << 5)
+#define SHORT_LO1              (1 << 4)
+#define CLR_SHORT_HS2          (1 << 3)
+#define SHORT_HS2              (1 << 2)
+#define CLR_SHORT_HS1          (1 << 1)
+#define SHORT_HS1              (1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent)      \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+       .shift = 0, .invert = 0, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+
+struct pm860x_det {
+       struct snd_soc_jack     *hp_jack;
+       struct snd_soc_jack     *mic_jack;
+       int                     hp_det;
+       int                     mic_det;
+       int                     hook_det;
+       int                     hs_shrt;
+       int                     lo_shrt;
+};
+
+struct pm860x_priv {
+       unsigned int            sysclk;
+       unsigned int            pcmclk;
+       unsigned int            dir;
+       unsigned int            filter;
+       struct snd_soc_codec    *codec;
+       struct i2c_client       *i2c;
+       struct pm860x_chip      *chip;
+       struct pm860x_det       det;
+
+       int                     irq[4];
+       unsigned char           name[4][MAX_NAME_LEN];
+       unsigned char           reg_cache[REG_CACHE_SIZE];
+};
+
+/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const unsigned int mic_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+       3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+       4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
+};
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const unsigned int aux_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+       3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
+};
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const unsigned int out_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+       4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+       5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
+};
+
+static const unsigned int st_tlv[] = {
+       TLV_DB_RANGE_HEAD(8),
+       0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+       2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+       4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+       8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+       10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+       14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+       18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
+};
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+       unsigned int    db;
+       unsigned int    m;
+       unsigned int    n;
+};
+
+static struct st_gain st_table[] = {
+       {-12041,  1, 15}, {-11439,  1, 14}, {-11087,  3, 15}, {-10837,  1, 13},
+       {-10643,  5, 15}, {-10485,  3, 14}, {-10351,  7, 15}, {-10235,  1, 12},
+       {-10133,  9, 15}, {-10041,  5, 14}, { -9958, 11, 15}, { -9883,  3, 13},
+       { -9813, 13, 15}, { -9749,  7, 14}, { -9689, 15, 15}, { -9633,  1, 11},
+       { -9580, 17, 15}, { -9531,  9, 14}, { -9484, 19, 15}, { -9439,  5, 13},
+       { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281,  3, 12},
+       { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147,  7, 13},
+       { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031,  1, 10},
+       { -8978, 17, 14}, { -8929,  9, 13}, { -8882, 19, 14}, { -8837,  5, 12},
+       { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679,  3, 11},
+       { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545,  7, 12},
+       { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429,  1,  9},
+       { -8376, 17, 13}, { -8327,  9, 12}, { -8280, 19, 13}, { -8235,  5, 11},
+       { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077,  3, 10},
+       { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943,  7, 11},
+       { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827,  1,  8},
+       { -7774, 17, 12}, { -7724,  9, 11}, { -7678, 19, 12}, { -7633,  5, 10},
+       { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475,  3,  9},
+       { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341,  7, 10},
+       { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225,  1,  7},
+       { -7172, 17, 11}, { -7122,  9, 10}, { -7075, 19, 11}, { -7031,  5,  9},
+       { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873,  3,  8},
+       { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739,  7,  9},
+       { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623,  1,  6},
+       { -6570, 17, 10}, { -6520,  9,  9}, { -6473, 19, 10}, { -6429,  5,  8},
+       { -6386, 21, 10}, { -6346, 11,  9}, { -6307, 23, 10}, { -6270,  3,  7},
+       { -6235, 25, 10}, { -6201, 13,  9}, { -6168, 27, 10}, { -6137,  7,  8},
+       { -6106, 29, 10}, { -6077, 15,  9}, { -6048, 31, 10}, { -6021,  1,  5},
+       { -5968, 17,  9}, { -5918,  9,  8}, { -5871, 19,  9}, { -5827,  5,  7},
+       { -5784, 21,  9}, { -5744, 11,  8}, { -5705, 23,  9}, { -5668,  3,  6},
+       { -5633, 25,  9}, { -5599, 13,  8}, { -5566, 27,  9}, { -5535,  7,  7},
+       { -5504, 29,  9}, { -5475, 15,  8}, { -5446, 31,  9}, { -5419,  1,  4},
+       { -5366, 17,  8}, { -5316,  9,  7}, { -5269, 19,  8}, { -5225,  5,  6},
+       { -5182, 21,  8}, { -5142, 11,  7}, { -5103, 23,  8}, { -5066,  3,  5},
+       { -5031, 25,  8}, { -4997, 13,  7}, { -4964, 27,  8}, { -4932,  7,  6},
+       { -4902, 29,  8}, { -4873, 15,  7}, { -4844, 31,  8}, { -4816,  1,  3},
+       { -4764, 17,  7}, { -4714,  9,  6}, { -4667, 19,  7}, { -4623,  5,  5},
+       { -4580, 21,  7}, { -4540, 11,  6}, { -4501, 23,  7}, { -4464,  3,  4},
+       { -4429, 25,  7}, { -4395, 13,  6}, { -4362, 27,  7}, { -4330,  7,  5},
+       { -4300, 29,  7}, { -4270, 15,  6}, { -4242, 31,  7}, { -4214,  1,  2},
+       { -4162, 17,  6}, { -4112,  9,  5}, { -4065, 19,  6}, { -4021,  5,  4},
+       { -3978, 21,  6}, { -3938, 11,  5}, { -3899, 23,  6}, { -3862,  3,  3},
+       { -3827, 25,  6}, { -3793, 13,  5}, { -3760, 27,  6}, { -3728,  7,  4},
+       { -3698, 29,  6}, { -3668, 15,  5}, { -3640, 31,  6}, { -3612,  1,  1},
+       { -3560, 17,  5}, { -3510,  9,  4}, { -3463, 19,  5}, { -3419,  5,  3},
+       { -3376, 21,  5}, { -3336, 11,  4}, { -3297, 23,  5}, { -3260,  3,  2},
+       { -3225, 25,  5}, { -3191, 13,  4}, { -3158, 27,  5}, { -3126,  7,  3},
+       { -3096, 29,  5}, { -3066, 15,  4}, { -3038, 31,  5}, { -3010,  1,  0},
+       { -2958, 17,  4}, { -2908,  9,  3}, { -2861, 19,  4}, { -2816,  5,  2},
+       { -2774, 21,  4}, { -2734, 11,  3}, { -2695, 23,  4}, { -2658,  3,  1},
+       { -2623, 25,  4}, { -2589, 13,  3}, { -2556, 27,  4}, { -2524,  7,  2},
+       { -2494, 29,  4}, { -2464, 15,  3}, { -2436, 31,  4}, { -2408,  2,  0},
+       { -2356, 17,  3}, { -2306,  9,  2}, { -2259, 19,  3}, { -2214,  5,  1},
+       { -2172, 21,  3}, { -2132, 11,  2}, { -2093, 23,  3}, { -2056,  3,  0},
+       { -2021, 25,  3}, { -1987, 13,  2}, { -1954, 27,  3}, { -1922,  7,  1},
+       { -1892, 29,  3}, { -1862, 15,  2}, { -1834, 31,  3}, { -1806,  4,  0},
+       { -1754, 17,  2}, { -1704,  9,  1}, { -1657, 19,  2}, { -1612,  5,  0},
+       { -1570, 21,  2}, { -1530, 11,  1}, { -1491, 23,  2}, { -1454,  6,  0},
+       { -1419, 25,  2}, { -1384, 13,  1}, { -1352, 27,  2}, { -1320,  7,  0},
+       { -1290, 29,  2}, { -1260, 15,  1}, { -1232, 31,  2}, { -1204,  8,  0},
+       { -1151, 17,  1}, { -1102,  9,  0}, { -1055, 19,  1}, { -1010, 10,  0},
+       {  -968, 21,  1}, {  -928, 11,  0}, {  -889, 23,  1}, {  -852, 12,  0},
+       {  -816, 25,  1}, {  -782, 13,  0}, {  -750, 27,  1}, {  -718, 14,  0},
+       {  -688, 29,  1}, {  -658, 15,  0}, {  -630, 31,  1}, {  -602, 16,  0},
+       {  -549, 17,  0}, {  -500, 18,  0}, {  -453, 19,  0}, {  -408, 20,  0},
+       {  -366, 21,  0}, {  -325, 22,  0}, {  -287, 23,  0}, {  -250, 24,  0},
+       {  -214, 25,  0}, {  -180, 26,  0}, {  -148, 27,  0}, {  -116, 28,  0},
+       {   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},
+};
+
+static int pm860x_volatile(unsigned int reg)
+{
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       switch (reg) {
+       case PM860X_AUDIO_SUPPLIES_2:
+               return 1;
+       }
+
+       return 0;
+}
+
+static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
+                                         unsigned int reg)
+{
+       unsigned char *cache = codec->reg_cache;
+
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       if (pm860x_volatile(reg))
+               return cache[reg];
+
+       reg += REG_CACHE_BASE;
+
+       return pm860x_reg_read(codec->control_data, reg);
+}
+
+static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
+                                 unsigned int reg, unsigned int value)
+{
+       unsigned char *cache = codec->reg_cache;
+
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       if (!pm860x_volatile(reg))
+               cache[reg] = (unsigned char)value;
+
+       reg += REG_CACHE_BASE;
+
+       return pm860x_reg_write(codec->control_data, reg, value);
+}
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       int val[2], val2[2], i;
+
+       val[0] = snd_soc_read(codec, reg) & 0x3f;
+       val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+       val2[0] = snd_soc_read(codec, reg2) & 0x3f;
+       val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+       for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+               if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+                       ucontrol->value.integer.value[0] = i;
+               if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+                       ucontrol->value.integer.value[1] = i;
+       }
+       return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       int err;
+       unsigned int val, val2;
+
+       val = ucontrol->value.integer.value[0];
+       val2 = ucontrol->value.integer.value[1];
+
+       err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+       if (err < 0)
+               return err;
+       err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+                                 st_table[val].n << 4);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+       if (err < 0)
+               return err;
+       err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+                                 st_table[val2].n);
+       return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max, val, val2;
+       unsigned int mask = (1 << fls(max)) - 1;
+
+       val = snd_soc_read(codec, reg) >> shift;
+       val2 = snd_soc_read(codec, reg2) >> shift;
+       ucontrol->value.integer.value[0] = (max - val) & mask;
+       ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+       return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       int err;
+       unsigned int val, val2, val_mask;
+
+       val_mask = mask << shift;
+       val = ((max - ucontrol->value.integer.value[0]) & mask);
+       val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+       return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       /*
+        * In order to avoid current on the load, mute power-on and power-off
+        * should be transients.
+        * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+        * finished.
+        */
+       snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                           RSYNC_CHANGE, RSYNC_CHANGE);
+       return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int dac = 0;
+       int data;
+
+       if (!strcmp(w->name, "Left DAC"))
+               dac = DAC_LEFT;
+       if (!strcmp(w->name, "Right DAC"))
+               dac = DAC_RIGHT;
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (dac) {
+                       /* Auto mute in power-on sequence. */
+                       dac |= MODULATOR;
+                       snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+                                           DAC_MUTE, DAC_MUTE);
+                       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                                           RSYNC_CHANGE, RSYNC_CHANGE);
+                       /* update dac */
+                       snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+                                           dac, dac);
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               if (dac) {
+                       /* Auto mute in power-off sequence. */
+                       snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+                                           DAC_MUTE, DAC_MUTE);
+                       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                                           RSYNC_CHANGE, RSYNC_CHANGE);
+                       /* update dac */
+                       data = snd_soc_read(codec, PM860X_DAC_EN_2);
+                       data &= ~dac;
+                       if (!(data & (DAC_LEFT | DAC_RIGHT)))
+                               data &= ~MODULATOR;
+                       snd_soc_write(codec, PM860X_DAC_EN_2, data);
+               }
+               break;
+       }
+       return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static const struct soc_enum pm860x_hs1_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs2_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs1_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_hs2_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo1_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo2_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo1_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo2_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_ear_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_ear_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+                       PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+       SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+                       aux_tlv),
+       SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+                       mic_tlv),
+       SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+                       mic_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+                            PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+                            0, snd_soc_get_volsw_2r_st,
+                            snd_soc_put_volsw_2r_st, st_tlv),
+       SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+                       0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+                        PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+                        PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+                            PM860X_HIFIL_GAIN_LEFT,
+                            PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+                            PM860X_HIFIR_GAIN_LEFT,
+                            PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+                            PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_ENUM("Headset1 Operational Amplifier Current",
+                pm860x_hs1_opamp_enum),
+       SOC_ENUM("Headset2 Operational Amplifier Current",
+                pm860x_hs2_opamp_enum),
+       SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+       SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+       SOC_ENUM("Lineout1 Operational Amplifier Current",
+                pm860x_lo1_opamp_enum),
+       SOC_ENUM("Lineout2 Operational Amplifier Current",
+                pm860x_lo2_opamp_enum),
+       SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+       SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+       SOC_ENUM("Speaker Operational Amplifier Current",
+                pm860x_spk_ear_opamp_enum),
+       SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+       SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+       "PCM L", "PCM R",
+};
+
+static const struct soc_enum aif1_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+       SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+       "DIN", "DIN1",
+};
+
+static const struct soc_enum i2s_din_enum =
+       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+       SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+       "Ex PA", "ADC",
+};
+
+static const struct soc_enum i2s_mic_enum =
+       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+       SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+       "ADCR", "ADCL",
+};
+
+static const struct soc_enum adcl_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+       SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+       "ADCL", "ADCR",
+};
+
+static const struct soc_enum adcr_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+       SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+       "ADCR", "EC",
+};
+
+static const struct soc_enum adcr_ec_enum =
+       SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+       SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+       "Left", "Right", "Left + Right",
+};
+
+static const struct soc_enum ec_enum =
+       SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+       SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+       "No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static const struct soc_enum dac_hs1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+       SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static const struct soc_enum dac_hs2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+       SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static const struct soc_enum dac_lo1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+       SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static const struct soc_enum dac_lo2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+       SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static const struct soc_enum dac_spk_ear_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+       SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+       "Digital", "Analog",
+};
+
+static const struct soc_enum hs1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+       SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static const struct soc_enum hs2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+       SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static const struct soc_enum lo1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+       SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static const struct soc_enum lo2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+       SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+       "Earpiece", "Speaker",
+};
+
+static const struct soc_enum spk_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+       SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+       "Mic 1", "Mic 2",
+};
+
+static const struct soc_enum mic_enum =
+       SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+       SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+                           PM860X_ADC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+                            PM860X_PCM_IFACE_3, 1, 1),
+
+
+       SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+                           PM860X_DAC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+                           PM860X_DAC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+                            PM860X_I2S_IFACE_3, 5, 1),
+       SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+       SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+       SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+       SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+       SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+       SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+                           &lepa_switch_controls),
+       SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+                           &repa_switch_controls),
+
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+                        0, 1, 1, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+                        1, 1, 1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+       SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+       SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+                           &aux1_switch_controls),
+       SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+                           &aux2_switch_controls),
+
+       SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+       SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+       SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+       SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_INPUT("AUX1"),
+       SND_SOC_DAPM_INPUT("AUX2"),
+       SND_SOC_DAPM_INPUT("MIC1P"),
+       SND_SOC_DAPM_INPUT("MIC1N"),
+       SND_SOC_DAPM_INPUT("MIC2P"),
+       SND_SOC_DAPM_INPUT("MIC2N"),
+       SND_SOC_DAPM_INPUT("MIC3P"),
+       SND_SOC_DAPM_INPUT("MIC3N"),
+
+       SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+                          pm860x_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+                          pm860x_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+       SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+       SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+       SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+       SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+       SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+       SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+       SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+       SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+       SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+       SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+                        &spk_demux),
+
+
+       SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("HS1"),
+       SND_SOC_DAPM_OUTPUT("HS2"),
+       SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+       SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("EARP"),
+       SND_SOC_DAPM_OUTPUT("EARN"),
+       SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("LSP"),
+       SND_SOC_DAPM_OUTPUT("LSN"),
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+                        0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+       PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* supply */
+       {"Left DAC", NULL, "VCODEC"},
+       {"Right DAC", NULL, "VCODEC"},
+       {"Left ADC", NULL, "VCODEC"},
+       {"Right ADC", NULL, "VCODEC"},
+       {"Left ADC", NULL, "Left ADC MOD"},
+       {"Right ADC", NULL, "Right ADC MOD"},
+
+       /* PCM/AIF1 Inputs */
+       {"PCM SDO", NULL, "ADC Left Mux"},
+       {"PCM SDO", NULL, "ADCR EC Mux"},
+
+       /* PCM/AFI2 Outputs */
+       {"Lofi PGA", NULL, "PCM SDI"},
+       {"Lofi PGA", NULL, "Sidetone PGA"},
+       {"Left DAC", NULL, "Lofi PGA"},
+       {"Right DAC", NULL, "Lofi PGA"},
+
+       /* I2S/AIF2 Inputs */
+       {"MIC Mux", "Mic 1", "MIC1P"},
+       {"MIC Mux", "Mic 1", "MIC1N"},
+       {"MIC Mux", "Mic 2", "MIC2P"},
+       {"MIC Mux", "Mic 2", "MIC2N"},
+       {"MIC1 Volume", NULL, "MIC Mux"},
+       {"MIC3 Volume", NULL, "MIC3P"},
+       {"MIC3 Volume", NULL, "MIC3N"},
+       {"Left ADC", NULL, "MIC1 Volume"},
+       {"Right ADC", NULL, "MIC3 Volume"},
+       {"ADC Left Mux", "ADCR", "Right ADC"},
+       {"ADC Left Mux", "ADCL", "Left ADC"},
+       {"ADC Right Mux", "ADCL", "Left ADC"},
+       {"ADC Right Mux", "ADCR", "Right ADC"},
+       {"Left EPA", "Switch", "Left DAC"},
+       {"Right EPA", "Switch", "Right DAC"},
+       {"EC Mux", "Left", "Left DAC"},
+       {"EC Mux", "Right", "Right DAC"},
+       {"EC Mux", "Left + Right", "Left DAC"},
+       {"EC Mux", "Left + Right", "Right DAC"},
+       {"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+       {"ADCR EC Mux", "EC", "EC Mux"},
+       {"I2S Mic Mux", "Ex PA", "Left EPA"},
+       {"I2S Mic Mux", "Ex PA", "Right EPA"},
+       {"I2S Mic Mux", "ADC", "ADC Left Mux"},
+       {"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+       {"I2S DOUT", NULL, "I2S Mic Mux"},
+
+       /* I2S/AIF2 Outputs */
+       {"I2S DIN Mux", "DIN", "I2S DIN"},
+       {"I2S DIN Mux", "DIN1", "I2S DIN1"},
+       {"Left DAC", NULL, "I2S DIN Mux"},
+       {"Right DAC", NULL, "I2S DIN Mux"},
+       {"DAC HS1 Mux", "Left", "Left DAC"},
+       {"DAC HS1 Mux", "Right", "Right DAC"},
+       {"DAC HS2 Mux", "Left", "Left DAC"},
+       {"DAC HS2 Mux", "Right", "Right DAC"},
+       {"DAC LO1 Mux", "Left", "Left DAC"},
+       {"DAC LO1 Mux", "Right", "Right DAC"},
+       {"DAC LO2 Mux", "Left", "Left DAC"},
+       {"DAC LO2 Mux", "Right", "Right DAC"},
+       {"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+       {"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+       {"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+       {"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+       {"Headset1 PGA", NULL, "Headset1 Mux"},
+       {"Headset2 PGA", NULL, "Headset2 Mux"},
+       {"Lineout1 PGA", NULL, "Lineout1 Mux"},
+       {"Lineout2 PGA", NULL, "Lineout2 Mux"},
+       {"DAC SP Mux", "Left", "Left DAC"},
+       {"DAC SP Mux", "Right", "Right DAC"},
+       {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+       {"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+       {"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+       {"RSYNC", NULL, "Headset1 PGA"},
+       {"RSYNC", NULL, "Headset2 PGA"},
+       {"RSYNC", NULL, "Lineout1 PGA"},
+       {"RSYNC", NULL, "Lineout2 PGA"},
+       {"RSYNC", NULL, "Speaker PGA"},
+       {"RSYNC", NULL, "Speaker PGA"},
+       {"RSYNC", NULL, "Earpiece PGA"},
+       {"RSYNC", NULL, "Earpiece PGA"},
+
+       {"HS1", NULL, "RSYNC"},
+       {"HS2", NULL, "RSYNC"},
+       {"LINEOUT1", NULL, "RSYNC"},
+       {"LINEOUT2", NULL, "RSYNC"},
+       {"LSP", NULL, "RSYNC"},
+       {"LSN", NULL, "RSYNC"},
+       {"EARP", NULL, "RSYNC"},
+       {"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+       if (mute)
+               data = mask;
+       snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
+       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                           RSYNC_CHANGE, RSYNC_CHANGE);
+       return 0;
+}
+
+static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned char inf = 0, mask = 0;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               inf &= ~PCM_INF2_18WL;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               inf |= PCM_INF2_18WL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       mask |= PCM_INF2_18WL;
+       snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+
+       /* sample rate */
+       switch (params_rate(params)) {
+       case 8000:
+               inf = 0;
+               break;
+       case 16000:
+               inf = 3;
+               break;
+       case 32000:
+               inf = 6;
+               break;
+       case 48000:
+               inf = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+
+       return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                 unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       unsigned char inf = 0, mask = 0;
+       int ret = -EINVAL;
+
+       mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+                       inf |= PCM_INF2_MASTER;
+                       ret = 0;
+               }
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_IN) {
+                       inf &= ~PCM_INF2_MASTER;
+                       ret = 0;
+               }
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               inf |= PCM_EXACT_I2S;
+               ret = 0;
+               break;
+       }
+       mask |= PCM_MODE_MASK;
+       if (ret)
+               return ret;
+       snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+       return 0;
+}
+
+static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+       if (dir == PM860X_CLK_DIR_OUT)
+               pm860x->dir = PM860X_CLK_DIR_OUT;
+       else {
+               pm860x->dir = PM860X_CLK_DIR_IN;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned char inf;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               inf = 0;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               inf = PCM_INF2_18WL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+       /* sample rate */
+       switch (params_rate(params)) {
+       case 8000:
+               inf = 0;
+               break;
+       case 11025:
+               inf = 1;
+               break;
+       case 16000:
+               inf = 3;
+               break;
+       case 22050:
+               inf = 4;
+               break;
+       case 32000:
+               inf = 6;
+               break;
+       case 44100:
+               inf = 7;
+               break;
+       case 48000:
+               inf = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+
+       return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                 unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       unsigned char inf = 0, mask = 0;
+
+       mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if (pm860x->dir == PM860X_CLK_DIR_OUT)
+                       inf |= PCM_INF2_MASTER;
+               else
+                       return -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_IN)
+                       inf &= ~PCM_INF2_MASTER;
+               else
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               inf |= PCM_EXACT_I2S;
+               break;
+       default:
+               return -EINVAL;
+       }
+       mask |= PCM_MODE_MASK;
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+       return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int data;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Enable Audio PLL & Audio section */
+                       data = AUDIO_PLL | AUDIO_SECTION_RESET
+                               | AUDIO_SECTION_ON;
+                       pm860x_reg_write(codec->control_data, REG_MISC2, data);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+               pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+       .digital_mute   = pm860x_digital_mute,
+       .hw_params      = pm860x_pcm_hw_params,
+       .set_fmt        = pm860x_pcm_set_dai_fmt,
+       .set_sysclk     = pm860x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+       .digital_mute   = pm860x_digital_mute,
+       .hw_params      = pm860x_i2s_hw_params,
+       .set_fmt        = pm860x_i2s_set_dai_fmt,
+       .set_sysclk     = pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |   \
+                        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+       {
+               /* DAI PCM */
+               .name   = "88pm860x-pcm",
+               .id     = 1,
+               .playback = {
+                       .stream_name    = "PCM Playback",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = PM860X_RATES,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .capture = {
+                       .stream_name    = "PCM Capture",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = PM860X_RATES,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .ops    = &pm860x_pcm_dai_ops,
+       }, {
+               /* DAI I2S */
+               .name   = "88pm860x-i2s",
+               .id     = 2,
+               .playback = {
+                       .stream_name    = "I2S Playback",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = SNDRV_PCM_RATE_8000_48000,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .capture = {
+                       .stream_name    = "I2S Capture",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = SNDRV_PCM_RATE_8000_48000,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .ops    = &pm860x_i2s_dai_ops,
+       },
+};
+
+static irqreturn_t pm860x_codec_handler(int irq, void *data)
+{
+       struct pm860x_priv *pm860x = data;
+       int status, shrt, report = 0, mic_report = 0;
+       int mask;
+
+       status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+       shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+       mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+               | pm860x->det.hp_det;
+
+       if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+               && (status & HEADSET_STATUS))
+               report |= SND_JACK_HEADPHONE;
+
+       if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+               && (status & MIC_STATUS))
+               mic_report |= SND_JACK_MICROPHONE;
+
+       if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+               report |= pm860x->det.hs_shrt;
+
+       if (pm860x->det.hook_det && (status & HOOK_STATUS))
+               report |= pm860x->det.hook_det;
+
+       if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+               report |= pm860x->det.lo_shrt;
+
+       if (report)
+               snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+       if (mic_report)
+               snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+                                   SND_JACK_MICROPHONE);
+
+       dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+               report, mask);
+       dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+       return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+                         struct snd_soc_jack *jack,
+                         int det, int hook, int hs_shrt, int lo_shrt)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       int data;
+
+       pm860x->det.hp_jack = jack;
+       pm860x->det.hp_det = det;
+       pm860x->det.hook_det = hook;
+       pm860x->det.hs_shrt = hs_shrt;
+       pm860x->det.lo_shrt = lo_shrt;
+
+       if (det & SND_JACK_HEADPHONE)
+               pm860x_set_bits(codec->control_data, REG_HS_DET,
+                               EN_HS_DET, EN_HS_DET);
+       /* headset short detect */
+       if (hs_shrt) {
+               data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+               pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+       }
+       /* Lineout short detect */
+       if (lo_shrt) {
+               data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+               pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+       }
+
+       /* sync status */
+       pm860x_codec_handler(0, pm860x);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+                          struct snd_soc_jack *jack, int det)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+       pm860x->det.mic_jack = jack;
+       pm860x->det.mic_det = det;
+
+       if (det & SND_JACK_MICROPHONE)
+               pm860x_set_bits(codec->control_data, REG_MIC_DET,
+                               MICDET_MASK, MICDET_MASK);
+
+       /* sync status */
+       pm860x_codec_handler(0, pm860x);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
+
+static int pm860x_probe(struct snd_soc_codec *codec)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+
+       pm860x->codec = codec;
+
+       codec->control_data = pm860x->i2c;
+
+       for (i = 0; i < 4; i++) {
+               ret = request_threaded_irq(pm860x->irq[i], NULL,
+                                          pm860x_codec_handler, IRQF_ONESHOT,
+                                          pm860x->name[i], pm860x);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Failed to request IRQ!\n");
+                       goto out_irq;
+               }
+       }
+
+       pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
+                              REG_CACHE_SIZE, codec->reg_cache);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to fill register cache: %d\n",
+                       ret);
+               goto out_codec;
+       }
+
+       snd_soc_add_controls(codec, pm860x_snd_controls,
+                            ARRAY_SIZE(pm860x_snd_controls));
+       snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+                                 ARRAY_SIZE(pm860x_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       return 0;
+
+out_codec:
+       i = 3;
+out_irq:
+       for (; i >= 0; i--)
+               free_irq(pm860x->irq[i], pm860x);
+       return -EINVAL;
+}
+
+static int pm860x_remove(struct snd_soc_codec *codec)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 3; i >= 0; i--)
+               free_irq(pm860x->irq[i], pm860x);
+       pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+       .probe          = pm860x_probe,
+       .remove         = pm860x_remove,
+       .read           = pm860x_read_reg_cache,
+       .write          = pm860x_write_reg_cache,
+       .reg_cache_size = REG_CACHE_SIZE,
+       .reg_word_size  = sizeof(u8),
+       .set_bias_level = pm860x_set_bias_level,
+};
+
+static int __devinit pm860x_codec_probe(struct platform_device *pdev)
+{
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm860x_priv *pm860x;
+       struct resource *res;
+       int i, ret;
+
+       pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+       if (pm860x == NULL)
+               return -ENOMEM;
+
+       pm860x->chip = chip;
+       pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+                       : chip->companion;
+       platform_set_drvdata(pdev, pm860x);
+
+       for (i = 0; i < 4; i++) {
+               res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+               if (!res) {
+                       dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+                       goto out;
+               }
+               pm860x->irq[i] = res->start + chip->irq_base;
+               strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+       }
+
+       ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+                                    pm860x_dai, ARRAY_SIZE(pm860x_dai));
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register codec\n");
+               goto out;
+       }
+       return ret;
+
+out:
+       platform_set_drvdata(pdev, NULL);
+       kfree(pm860x);
+       return -EINVAL;
+}
+
+static int __devexit pm860x_codec_remove(struct platform_device *pdev)
+{
+       struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(pm860x);
+       return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+       .driver = {
+               .name   = "88pm860x-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = pm860x_codec_probe,
+       .remove = __devexit_p(pm860x_codec_remove),
+};
+
+static __init int pm860x_init(void)
+{
+       return platform_driver_register(&pm860x_codec_driver);
+}
+module_init(pm860x_init);
+
+static __exit void pm860x_exit(void)
+{
+       platform_driver_unregister(&pm860x_codec_driver);
+}
+module_exit(pm860x_exit);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644 (file)
index 0000000..3364ba4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.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 __88PM860X_H
+#define __88PM860X_H
+
+/* The offset of these registers are 0xb0 */
+#define PM860X_PCM_IFACE_1             0x00
+#define PM860X_PCM_IFACE_2             0x01
+#define PM860X_PCM_IFACE_3             0x02
+#define PM860X_PCM_RATE                        0x03
+#define PM860X_EC_PATH                 0x04
+#define PM860X_SIDETONE_L_GAIN         0x05
+#define PM860X_SIDETONE_R_GAIN         0x06
+#define PM860X_SIDETONE_SHIFT          0x07
+#define PM860X_ADC_OFFSET_1            0x08
+#define PM860X_ADC_OFFSET_2            0x09
+#define PM860X_DMIC_DELAY              0x0a
+
+#define PM860X_I2S_IFACE_1             0x0b
+#define PM860X_I2S_IFACE_2             0x0c
+#define PM860X_I2S_IFACE_3             0x0d
+#define PM860X_I2S_IFACE_4             0x0e
+#define PM860X_EQUALIZER_N0_1          0x0f
+#define PM860X_EQUALIZER_N0_2          0x10
+#define PM860X_EQUALIZER_N1_1          0x11
+#define PM860X_EQUALIZER_N1_2          0x12
+#define PM860X_EQUALIZER_D1_1          0x13
+#define PM860X_EQUALIZER_D1_2          0x14
+#define PM860X_LOFI_GAIN_LEFT          0x15
+#define PM860X_LOFI_GAIN_RIGHT         0x16
+#define PM860X_HIFIL_GAIN_LEFT         0x17
+#define PM860X_HIFIL_GAIN_RIGHT                0x18
+#define PM860X_HIFIR_GAIN_LEFT         0x19
+#define PM860X_HIFIR_GAIN_RIGHT                0x1a
+#define PM860X_DAC_OFFSET              0x1b
+#define PM860X_OFFSET_LEFT_1           0x1c
+#define PM860X_OFFSET_LEFT_2           0x1d
+#define PM860X_OFFSET_RIGHT_1          0x1e
+#define PM860X_OFFSET_RIGHT_2          0x1f
+#define PM860X_ADC_ANA_1               0x20
+#define PM860X_ADC_ANA_2               0x21
+#define PM860X_ADC_ANA_3               0x22
+#define PM860X_ADC_ANA_4               0x23
+#define PM860X_ANA_TO_ANA              0x24
+#define PM860X_HS1_CTRL                        0x25
+#define PM860X_HS2_CTRL                        0x26
+#define PM860X_LO1_CTRL                        0x27
+#define PM860X_LO2_CTRL                        0x28
+#define PM860X_EAR_CTRL_1              0x29
+#define PM860X_EAR_CTRL_2              0x2a
+#define PM860X_AUDIO_SUPPLIES_1                0x2b
+#define PM860X_AUDIO_SUPPLIES_2                0x2c
+#define PM860X_ADC_EN_1                        0x2d
+#define PM860X_ADC_EN_2                        0x2e
+#define PM860X_DAC_EN_1                        0x2f
+#define PM860X_DAC_EN_2                        0x31
+#define PM860X_AUDIO_CAL_1             0x32
+#define PM860X_AUDIO_CAL_2             0x33
+#define PM860X_AUDIO_CAL_3             0x34
+#define PM860X_AUDIO_CAL_4             0x35
+#define PM860X_AUDIO_CAL_5             0x36
+#define PM860X_ANA_INPUT_SEL_1         0x37
+#define PM860X_ANA_INPUT_SEL_2         0x38
+
+#define PM860X_PCM_IFACE_4             0x39
+#define PM860X_I2S_IFACE_5             0x3a
+
+#define PM860X_SHORTS                  0x3b
+#define PM860X_PLL_ADJ_1               0x3c
+#define PM860X_PLL_ADJ_2               0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN              0
+#define PM860X_CLK_DIR_OUT             1
+
+#define PM860X_DET_HEADSET             (1 << 0)
+#define PM860X_DET_MIC                 (1 << 1)
+#define PM860X_DET_HOOK                        (1 << 2)
+#define PM860X_SHORT_HEADSET           (1 << 3)
+#define PM860X_SHORT_LINEOUT           (1 << 4)
+#define PM860X_DET_MASK                        0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+                                int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+                                 int);
+
+#endif /* __88PM860X_H */
index 83f5c67d3c41630794ee8d2aa3fc54409e240a70..94a9d06b90277797215e299907444a85ca3f379a 100644 (file)
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
+       select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
        select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
        select SND_SOC_AD1836 if SPI_MASTER
@@ -26,6 +27,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS4270 if I2C
        select SND_SOC_DA7210 if I2C
        select SND_SOC_JZ4740 if SOC_JZ4740
+       select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
        select SND_SOC_SPDIF
@@ -40,6 +42,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TWL6040 if TWL4030_CORE
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
+       select SND_SOC_WL1273 if WL1273_CORE
        select SND_SOC_WM2000 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
        select SND_SOC_WM8400 if MFD_WM8400
@@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
@@ -61,9 +65,11 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8961 if I2C
+       select SND_SOC_WM8962 if I2C
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8974 if I2C
        select SND_SOC_WM8978 if I2C
+       select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8990 if I2C
        select SND_SOC_WM8993 if I2C
@@ -84,6 +90,9 @@ config SND_SOC_ALL_CODECS
 
           If unsure select "N".
 
+config SND_SOC_88PM860X
+       tristate
+
 config SND_SOC_WM_HUBS
        tristate
        default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
@@ -150,6 +159,9 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_MAX98088
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -188,6 +200,9 @@ config SND_SOC_UDA134X
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WL1273
+       tristate
+
 config SND_SOC_WM8350
        tristate
 
@@ -227,6 +242,9 @@ config SND_SOC_WM8753
 config SND_SOC_WM8776
        tristate
 
+config SND_SOC_WM8804
+       tristate
+
 config SND_SOC_WM8900
        tristate
 
@@ -248,6 +266,9 @@ config SND_SOC_WM8960
 config SND_SOC_WM8961
        tristate
 
+config SND_SOC_WM8962
+       tristate
+
 config SND_SOC_WM8971
        tristate
 
@@ -257,6 +278,9 @@ config SND_SOC_WM8974
 config SND_SOC_WM8978
        tristate
 
+config SND_SOC_WM8985
+       tristate
+
 config SND_SOC_WM8988
        tristate
 
index 53524095759c62ed322a033d818c78543182749a..f67a2d6f7a46c0386f67f8a1b6dc43bb4318aeff 100644 (file)
@@ -1,3 +1,4 @@
+snd-soc-88pm860x-objs := 88pm860x-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
@@ -14,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
@@ -26,6 +28,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -39,6 +42,7 @@ snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
@@ -46,9 +50,11 @@ snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
 snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8993-objs := wm8993.o
@@ -66,6 +72,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm9090-objs := wm9090.o
 
+obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)   += snd-soc-ad193x.o
@@ -83,6 +90,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
@@ -95,6 +103,7 @@ obj-$(CONFIG_SND_SOC_TWL4030)        += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)  += snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)   += snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
@@ -108,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8741)        += snd-soc-wm8741.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
@@ -115,9 +125,11 @@ obj-$(CONFIG_SND_SOC_WM8940)       += snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)   += snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8961)   += snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962)   += snd-soc-wm8962.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
 obj-$(CONFIG_SND_SOC_WM8978)   += snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8985)   += snd-soc-wm8985.o
 obj-$(CONFIG_SND_SOC_WM8988)   += snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM8993)   += snd-soc-wm8993.o
index 1f5e57a4bb7accdfdad3eefdd209b9b056b7351c..3c087936aa57028b11b0567d5165088a4aa5aed9 100644 (file)
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include "ac97.h"
-
-#define AC97_VERSION "0.6"
 
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -46,8 +42,8 @@ static struct snd_soc_dai_ops ac97_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
-struct snd_soc_dai ac97_dai = {
-       .name = "AC97 HiFi",
+static struct snd_soc_dai_driver ac97_dai = {
+       .name = "ac97-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
@@ -63,7 +59,6 @@ struct snd_soc_dai ac97_dai = {
                .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ac97_dai);
 
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
@@ -78,95 +73,41 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-static int ac97_soc_probe(struct platform_device *pdev)
+static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec;
        struct snd_ac97_bus *ac97_bus;
        struct snd_ac97_template ac97_template;
-       int i;
-       int ret = 0;
-
-       printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
-
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->card->codec)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->name = "AC97";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ac97_dai;
-       codec->num_dai = 1;
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto err;
+       int ret;
 
        /* add codec as bus device for standard ac97 */
-       ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+       ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
        if (ret < 0)
-               goto bus_err;
+               return ret;
 
        memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
        ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
        if (ret < 0)
-               goto bus_err;
-
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].codec_dai->ac97_control) {
-                       snd_ac97_dev_add_pdata(codec->ac97,
-                               card->dai_link[i].cpu_dai->ac97_pdata);
-               }
-       }
+               return ret;
 
        return 0;
-
-bus_err:
-       snd_soc_free_pcms(socdev);
-
-err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
 }
 
-static int ac97_soc_remove(struct platform_device *pdev)
+static int ac97_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (!codec)
-               return 0;
-
-       snd_soc_free_pcms(socdev);
-       kfree(socdev->card->codec);
-
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_ac97_suspend(socdev->card->codec->ac97);
+       snd_ac97_suspend(codec->ac97);
 
        return 0;
 }
 
-static int ac97_soc_resume(struct platform_device *pdev)
+static int ac97_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_ac97_resume(socdev->card->codec->ac97);
+       snd_ac97_resume(codec->ac97);
 
        return 0;
 }
@@ -175,14 +116,50 @@ static int ac97_soc_resume(struct platform_device *pdev)
 #define ac97_soc_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_ac97 = {
+static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+       .write =        ac97_write,
+       .read =         ac97_read,
        .probe =        ac97_soc_probe,
        .remove =       ac97_soc_remove,
        .suspend =      ac97_soc_suspend,
        .resume =       ac97_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+static __devinit int ac97_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ac97, &ac97_dai, 1);
+}
+
+static int __devexit ac97_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+       .driver = {
+               .name = "ac97-codec",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = ac97_probe,
+       .remove = __devexit_p(ac97_remove),
+};
+
+static int __init ac97_init(void)
+{
+       return platform_driver_register(&ac97_codec_driver);
+}
+module_init(ac97_init);
+
+static void __exit ac97_exit(void)
+{
+       platform_driver_unregister(&ac97_codec_driver);
+}
+module_exit(ac97_exit);
 
 MODULE_DESCRIPTION("Soc Generic AC97 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
deleted file mode 100644 (file)
index 281aa42..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/codecs/ac97.h -- ALSA SoC Layer
- *
- * Author:             Liam Girdwood
- * Created:            Dec 1st 2005
- * Copyright:  Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can 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 __LINUX_SND_SOC_AC97_H
-#define __LINUX_SND_SOC_AC97_H
-
-extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_dai ac97_dai;
-
-#endif
index a01006c8c606ffd613b250bf7f95fbc95ebaa05c..d272534c8f8413dba5221dc60d01fdbfb74b72e8 100644 (file)
 
 /* codec private data */
 struct ad1836_priv {
-       struct snd_soc_codec codec;
-       u16 reg_cache[AD1836_NUM_REGS];
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *ad1836_codec;
-struct snd_soc_codec_device soc_codec_dev_ad1836;
-static int ad1836_register(struct ad1836_priv *ad1836);
-static void ad1836_unregister(struct ad1836_priv *ad1836);
-
 /*
  * AD1836 volume/mute/de-emphasis etc. controls
  */
@@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        int word_len = 0;
 
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* bit size */
        switch (params_format(params)) {
@@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 #ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct platform_device *pdev,
+static int ad1836_soc_suspend(struct snd_soc_codec *codec,
                pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* reset clock control mode */
        u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
        adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
@@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev,
        return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-static int ad1836_soc_resume(struct platform_device *pdev)
+static int ad1836_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* restore clock control mode */
        u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
        adc_ctrl2 |= AD1836_ADC_AUX;
@@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev)
 #define ad1836_soc_resume  NULL
 #endif
 
-static int __devinit ad1836_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_codec *codec;
-       struct ad1836_priv *ad1836;
-
-       ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
-       if (ad1836 == NULL)
-               return -ENOMEM;
-
-       codec = &ad1836->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, ad1836);
-
-       return ad1836_register(ad1836);
-}
-
-static int __devexit ad1836_spi_remove(struct spi_device *spi)
-{
-       struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
-
-       ad1836_unregister(ad1836);
-       return 0;
-}
-
-static struct spi_driver ad1836_spi_driver = {
-       .driver = {
-               .name   = "ad1836",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ad1836_spi_probe,
-       .remove         = __devexit_p(ad1836_spi_remove),
-};
-
 static struct snd_soc_dai_ops ad1836_dai_ops = {
        .hw_params = ad1836_hw_params,
        .set_fmt = ad1836_set_dai_fmt,
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad1836_dai = {
-       .name = "AD1836",
+static struct snd_soc_dai_driver ad1836_dai = {
+       .name = "ad1836-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = {
        },
        .ops = &ad1836_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad1836_dai);
 
-static int ad1836_register(struct ad1836_priv *ad1836)
+static int ad1836_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_codec *codec = &ad1836->codec;
-
-       if (ad1836_codec) {
-               dev_err(codec->dev, "Another ad1836 is registered\n");
-               kfree(ad1836);
-               return -EINVAL;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       snd_soc_codec_set_drvdata(codec, ad1836);
-       codec->reg_cache = ad1836->reg_cache;
-       codec->reg_cache_size = AD1836_NUM_REGS;
-       codec->name = "AD1836";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad1836_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ad1836_dai.dev = codec->dev;
-       ad1836_codec = codec;
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
 
+       codec->control_data = ad1836->control_data;
        ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836)
        snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
        snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               kfree(ad1836);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&ad1836_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               kfree(ad1836);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void ad1836_unregister(struct ad1836_priv *ad1836)
-{
-       snd_soc_unregister_dai(&ad1836_dai);
-       snd_soc_unregister_codec(&ad1836->codec);
-       kfree(ad1836);
-       ad1836_codec = NULL;
-}
-
-static int ad1836_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (ad1836_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = ad1836_codec;
-       codec = ad1836_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
        snd_soc_add_controls(codec, ad1836_snd_controls,
                             ARRAY_SIZE(ad1836_snd_controls));
        snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
                                  ARRAY_SIZE(ad1836_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
        return ret;
 }
 
 /* power down chip */
-static int ad1836_remove(struct platform_device *pdev)
+static int ad1836_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       /* reset clock control mode */
+       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+       adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
 
-       return 0;
+       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1836 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .probe =        ad1836_probe,
        .remove =       ad1836_remove,
        .suspend =      ad1836_soc_suspend,
        .resume =       ad1836_soc_resume,
+       .reg_cache_size = AD1836_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+static int __devinit ad1836_spi_probe(struct spi_device *spi)
+{
+       struct ad1836_priv *ad1836;
+       int ret;
+
+       ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+       if (ad1836 == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ad1836);
+       ad1836->control_data = spi;
+       ad1836->control_type = SND_SOC_SPI;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_ad1836, &ad1836_dai, 1);
+       if (ret < 0)
+               kfree(ad1836);
+       return ret;
+}
+
+static int __devexit ad1836_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver ad1836_spi_driver = {
+       .driver = {
+               .name   = "ad1836-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad1836_spi_probe,
+       .remove         = __devexit_p(ad1836_spi_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
 
 static int __init ad1836_init(void)
 {
index e9d90d3951c520f4c18fdb56d9eae6d72dd0b160..845596717fdf522d2de2d83d37e123825a36cade 100644 (file)
@@ -60,6 +60,4 @@
 
 #define AD1836_NUM_REGS                16
 
-extern struct snd_soc_dai ad1836_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1836;
 #endif
index 1def75e4862f60fe2a143470cdb2ae458453e08a..fa2834c91b9f5e8507841eba8155d54a59386e35 100644 (file)
 
 /* codec private data */
 struct ad193x_priv {
-       unsigned int sysclk;
-       struct snd_soc_codec codec;
        u8 reg_cache[AD193X_NUM_REGS];
+       enum snd_soc_control_type bus_type;
+       void *control_data;
+       int sysclk;
 };
 
 /* ad193x register cache & default register settings */
@@ -34,9 +35,6 @@ static const u8 ad193x_reg[AD193X_NUM_REGS] = {
        0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
 };
 
-static struct snd_soc_codec *ad193x_codec;
-struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 /*
  * AD193X volume/mute/de-emphasis etc. controls
  */
@@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
        int word_len = 0, reg = 0, master_rate = 0;
 
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
        /* bit size */
@@ -323,100 +320,6 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
-{
-       struct snd_soc_codec *codec;
-       struct ad193x_priv *ad193x;
-       int ret;
-
-       if (ad193x_codec) {
-               dev_err(dev, "Another ad193x is registered\n");
-               return -EINVAL;
-       }
-
-       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
-       if (ad193x == NULL)
-               return -ENOMEM;
-
-       dev_set_drvdata(dev, ad193x);
-
-       codec = &ad193x->codec;
-       mutex_init(&codec->mutex);
-       codec->control_data = ctrl_data;
-       codec->dev = dev;
-       snd_soc_codec_set_drvdata(codec, ad193x);
-       codec->reg_cache = ad193x->reg_cache;
-       codec->reg_cache_size = AD193X_NUM_REGS;
-       codec->name = "AD193X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad193x_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ad193x_dai.dev = codec->dev;
-       ad193x_codec = codec;
-
-       memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
-
-       if (bus_type == SND_SOC_I2C)
-               ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
-       else
-               ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
-               kfree(ad193x);
-               return ret;
-       }
-
-       /* default setting for ad193x */
-
-       /* unmute dac channels */
-       snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
-       /* de-emphasis: 48kHz, powedown dac */
-       snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
-       /* powerdown dac, dac in tdm mode */
-       snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
-       /* high-pass filter enable */
-       snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
-       /* sata delay=1, adc aux mode */
-       snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
-       /* pll input: mclki/xi */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
-       ad193x->sysclk = 12288000;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               kfree(ad193x);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&ad193x_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               kfree(ad193x);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ad193x_bus_remove(struct device *dev)
-{
-       struct ad193x_priv *ad193x = dev_get_drvdata(dev);
-
-       snd_soc_unregister_dai(&ad193x_dai);
-       snd_soc_unregister_codec(&ad193x->codec);
-       kfree(ad193x);
-       ad193x_codec = NULL;
-
-       return 0;
-}
-
 static struct snd_soc_dai_ops ad193x_dai_ops = {
        .hw_params = ad193x_hw_params,
        .digital_mute = ad193x_mute,
@@ -426,8 +329,8 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad193x_dai = {
-       .name = "AD193X",
+static struct snd_soc_dai_driver ad193x_dai = {
+       .name = "ad193x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -446,28 +349,39 @@ struct snd_soc_dai ad193x_dai = {
        },
        .ops = &ad193x_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad193x_dai);
 
-static int ad193x_probe(struct platform_device *pdev)
+static int ad193x_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (ad193x_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = ad193x->control_data;
+       if (ad193x->bus_type == SND_SOC_I2C)
+               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+       else
+               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to set cache I/O: %d\n",
+                               ret);
+               kfree(ad193x);
+               return ret;
        }
 
-       socdev->card->codec = ad193x_codec;
-       codec = ad193x_codec;
+       /* default setting for ad193x */
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
+       /* unmute dac channels */
+       snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
+       /* de-emphasis: 48kHz, powedown dac */
+       snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
+       /* powerdown dac, dac in tdm mode */
+       snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
+       /* high-pass filter enable */
+       snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
+       /* sata delay=1, adc aux mode */
+       snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
+       /* pll input: mclki/xi */
+       snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+       snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
 
        snd_soc_add_controls(codec, ad193x_snd_controls,
                             ARRAY_SIZE(ad193x_snd_controls));
@@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev)
                                  ARRAY_SIZE(ad193x_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
        return ret;
 }
 
-/* power down chip */
-static int ad193x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ad193x = {
+static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
        .probe =        ad193x_probe,
-       .remove =       ad193x_remove,
+       .reg_cache_default = ad193x_reg,
+       .reg_cache_size = AD193X_NUM_REGS,
+       .reg_word_size = sizeof(u16),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
 
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
 {
-       return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+       struct ad193x_priv *ad193x;
+       int ret;
+
+       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       if (ad193x == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ad193x);
+       ad193x->control_data = spi;
+       ad193x->bus_type = SND_SOC_SPI;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
+       if (ret < 0)
+               kfree(ad193x);
+       return ret;
 }
 
 static int __devexit ad193x_spi_remove(struct spi_device *spi)
 {
-       return ad193x_bus_remove(&spi->dev);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
 }
 
 static struct spi_driver ad193x_spi_driver = {
        .driver = {
-               .name   = "ad193x",
+               .name   = "ad193x-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = ad193x_spi_probe,
@@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
 static int __devinit ad193x_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
+       struct ad193x_priv *ad193x;
+       int ret;
+
+       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       if (ad193x == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, ad193x);
+       ad193x->control_data = client;
+       ad193x->bus_type = SND_SOC_I2C;
+
+       ret =  snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
+       if (ret < 0)
+               kfree(ad193x);
+       return ret;
 }
 
 static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 {
-       return ad193x_bus_remove(&client->dev);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
 static struct i2c_driver ad193x_i2c_driver = {
        .driver = {
-               .name = "ad193x",
+               .name = "ad193x-codec",
        },
        .probe    = ad193x_i2c_probe,
        .remove   = __devexit_p(ad193x_i2c_remove),
index 654ba64ae04c6d4b0e8ebc89a0138916c37eed1c..9747b54978775cd43fe5d5af4f0234670ba2ff2f 100644 (file)
@@ -80,7 +80,4 @@
 
 #define AD193X_NUM_REGS          17
 
-extern struct snd_soc_dai ad193x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 #endif
index 70cfaec3be2c0efbcf57c0c753622e747683b67c..410ccd5d41cdeb5ab2ca706bd67bccb075245ec2 100644 (file)
 
 #include "ad1980.h"
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-       unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
-       unsigned int reg, unsigned int val);
-
 /*
  * AD1980 register cache
  */
@@ -138,8 +133,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-struct snd_soc_dai ad1980_dai = {
-       .name = "AC97",
+static struct snd_soc_dai_driver ad1980_dai = {
+       .name = "ad1980-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "Playback",
@@ -185,53 +180,20 @@ err:
        return -EIO;
 }
 
-static int ad1980_soc_probe(struct platform_device *pdev)
+static int ad1980_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       int ret;
        u16 vendor_id2;
        u16 ext_status;
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache =
-               kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
-                       ARRAY_SIZE(ad1980_reg));
-       codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
-       codec->reg_cache_step = 2;
-       codec->name = "AD1980";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad1980_dai;
-       codec->num_dai = 1;
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
-
        ret = ad1980_reset(codec, 0);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
@@ -270,41 +232,60 @@ static int ad1980_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
-codec_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int ad1980_soc_remove(struct platform_device *pdev)
+static int ad1980_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
        .probe =        ad1980_soc_probe,
        .remove =       ad1980_soc_remove,
+       .reg_cache_size = ARRAY_SIZE(ad1980_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = ad1980_reg,
+       .reg_cache_step = 2,
+       .write = ac97_write,
+       .read = ac97_read,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+static __devinit int ad1980_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ad1980, &ad1980_dai, 1);
+}
+
+static int __devexit ad1980_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ad1980_codec_driver = {
+       .driver = {
+                       .name = "ad1980-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ad1980_probe,
+       .remove = __devexit_p(ad1980_remove),
+};
+
+static int __init ad1980_init(void)
+{
+       return platform_driver_register(&ad1980_codec_driver);
+}
+module_init(ad1980_init);
+
+static void __exit ad1980_exit(void)
+{
+       platform_driver_unregister(&ad1980_codec_driver);
+}
+module_exit(ad1980_exit);
 
 MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
 MODULE_AUTHOR("Roy Huang, Cliff Cai");
index 538f37c908068628eddf039194762a8e1bfb0898..eb0af44ad3dfb6f7050e8943814172d7ca4bc26e 100644 (file)
@@ -23,7 +23,4 @@
 #define PR5            0x2000
 #define PR6            0x4000
 
-extern struct snd_soc_dai ad1980_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1980;
-
 #endif
index 475807bea2c229d04e4e3ed91dd8647ffa26d259..c53955fe17b65875e8354063e897c6501edc7b50 100644 (file)
@@ -23,8 +23,8 @@
 
 #include "ad73311.h"
 
-struct snd_soc_dai ad73311_dai = {
-       .name = "AD73311",
+static struct snd_soc_dai_driver ad73311_dai = {
+       .name = "ad73311-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -38,68 +38,40 @@ struct snd_soc_dai ad73311_dai = {
                .rates = SNDRV_PCM_RATE_8000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
-EXPORT_SYMBOL_GPL(ad73311_dai);
 
-static int ad73311_soc_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-       mutex_init(&codec->mutex);
-       codec->name = "AD73311";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad73311_dai;
-       codec->num_dai = 1;
-       socdev->card->codec = codec;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ad73311: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       return ret;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311;
 
-pcm_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
+static int ad73311_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ad73311, &ad73311_dai, 1);
 }
 
-static int ad73311_soc_remove(struct platform_device *pdev)
+static int ad73311_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-       snd_soc_free_pcms(socdev);
-       kfree(codec);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad73311 = {
-       .probe =        ad73311_soc_probe,
-       .remove =       ad73311_soc_remove,
+static struct platform_driver ad73311_codec_driver = {
+       .driver = {
+                       .name = "ad73311-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ad73311_probe,
+       .remove = __devexit_p(ad73311_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
 
 static int __init ad73311_init(void)
 {
-       return snd_soc_register_dai(&ad73311_dai);
+       return platform_driver_register(&ad73311_codec_driver);
 }
 module_init(ad73311_init);
 
 static void __exit ad73311_exit(void)
 {
-       snd_soc_unregister_dai(&ad73311_dai);
+       platform_driver_unregister(&ad73311_codec_driver);
 }
 module_exit(ad73311_exit);
 
index 569573d2d4d7a628b18c9c1a108512e11a4e9008..4b353eefc0bf04508ffce2c24ecc36405773381d 100644 (file)
@@ -85,6 +85,4 @@
 #define REGF_INV               (1 << 6)
 #define REGF_ALB               (1 << 7)
 
-extern struct snd_soc_dai ad73311_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad73311;
 #endif
index f8e75edb27b7ec793f21f32e10200db2d734148c..8402854ec15e30b320d31e1416896ced2f964850 100644 (file)
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "ads117x.h"
-
 #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
-
 #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
-struct snd_soc_dai ads117x_dai = {
+static struct snd_soc_dai_driver ads117x_dai = {
 /* ADC */
-       .name = "ADS117X ADC",
-       .id = 1,
+       .name = "ads117x-hifi",
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -36,75 +32,29 @@ struct snd_soc_dai ads117x_dai = {
                .rates = ADS117X_RATES,
                .formats = ADS117X_FORMATS,},
 };
-EXPORT_SYMBOL_GPL(ads117x_dai);
-
-static int ads117x_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
 
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->name = "ADS117X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ads117x_dai;
-       codec->num_dai = 1;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ads117x: failed to create pcms\n");
-               kfree(codec);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ads117x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_free_pcms(socdev);
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ads117x = {
-       .probe =        ads117x_probe,
-       .remove =       ads117x_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+static struct snd_soc_codec_driver soc_codec_dev_ads117x;
 
-static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+static __devinit int ads117x_probe(struct platform_device *pdev)
 {
-       ads117x_dai.dev = &pdev->dev;
-       return snd_soc_register_dai(&ads117x_dai);
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ads117x, &ads117x_dai, 1);
 }
 
-static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+static int __devexit ads117x_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&ads117x_dai);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver ads117x_codec_driver = {
        .driver = {
-                       .name = "ads117x",
+                       .name = "ads117x-codec",
                        .owner = THIS_MODULE,
        },
 
-       .probe = ads117x_platform_probe,
-       .remove = __devexit_p(ads117x_platform_remove),
+       .probe = ads117x_probe,
+       .remove = __devexit_p(ads117x_remove),
 };
 
 static int __init ads117x_init(void)
index dbcf50ec9bd175e32efed8f14b0d295730b87849..3ce028614002c1bbc14d094ccdf7d056fb8b436a 100644 (file)
@@ -9,5 +9,5 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  */
-extern struct snd_soc_dai ads117x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ads117x;
+extern struct snd_soc_dai_driver ads117x_dai;
+extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
index 192aebda3029628efa7f11e8a4b019d825f857ca..c27f8f59dc66d38cc4fb98fe7a428168333ac3db 100644 (file)
@@ -17,8 +17,6 @@
 #include <linux/spi/spi.h>
 #include <sound/asoundef.h>
 
-#include "ak4104.h"
-
 /* AK4104 registers addresses */
 #define AK4104_REG_CONTROL1            0x00
 #define AK4104_REG_RESERVED            0x01
 #define AK4104_TX_TXE                  (1 << 0)
 #define AK4104_TX_V                    (1 << 1)
 
-#define DRV_NAME "ak4104"
+#define DRV_NAME "ak4104-codec"
 
 struct ak4104_private {
-       struct snd_soc_codec codec;
-       u8 reg_cache[AK4104_NUM_REGS];
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static int ak4104_fill_cache(struct snd_soc_codec *codec)
@@ -58,7 +56,7 @@ static int ak4104_fill_cache(struct snd_soc_codec *codec)
        u8 *reg_cache = codec->reg_cache;
        struct spi_device *spi = codec->control_data;
 
-       for (i = 0; i < codec->reg_cache_size; i++) {
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
                int ret = spi_w8r8(spi, i | AK4104_READ);
                if (ret < 0) {
                        dev_err(&spi->dev, "SPI write failure\n");
@@ -76,7 +74,7 @@ static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
 {
        u8 *reg_cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        return reg_cache[reg];
@@ -88,7 +86,7 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 *cache = codec->reg_cache;
        struct spi_device *spi = codec->control_data;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        /* only write to the hardware if value has changed */
@@ -145,8 +143,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        int val = 0;
 
        /* set the IEC958 bits: consumer mode, no copyright bit */
@@ -178,8 +175,8 @@ static struct snd_soc_dai_ops ak4101_dai_ops = {
        .set_fmt = ak4104_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4104_dai = {
-       .name = DRV_NAME,
+static struct snd_soc_dai_driver ak4104_dai = {
+       .name = "ak4104-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -192,45 +189,17 @@ struct snd_soc_dai ak4104_dai = {
        .ops = &ak4101_dai_ops,
 };
 
-static struct snd_soc_codec *ak4104_codec;
-
-static int ak4104_spi_probe(struct spi_device *spi)
+static int ak4104_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec;
-       struct ak4104_private *ak4104;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int ret, val;
 
-       spi->bits_per_word = 8;
-       spi->mode = SPI_MODE_0;
-       ret = spi_setup(spi);
-       if (ret < 0)
-               return ret;
-
-       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
-       if (!ak4104) {
-               dev_err(&spi->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-
-       codec = &ak4104->codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &spi->dev;
-       codec->name = DRV_NAME;
-       codec->owner = THIS_MODULE;
-       codec->dai = &ak4104_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, ak4104);
-       codec->control_data = spi;
-       codec->reg_cache = ak4104->reg_cache;
-       codec->reg_cache_size = AK4104_NUM_REGS;
+       codec->control_data = ak4104->control_data;
 
        /* read all regs and fill the cache */
        ret = ak4104_fill_cache(codec);
        if (ret < 0) {
-               dev_err(&spi->dev, "failed to fill register cache\n");
+               dev_err(codec->dev, "failed to fill register cache\n");
                return ret;
        }
 
@@ -238,93 +207,81 @@ static int ak4104_spi_probe(struct spi_device *spi)
         * should contain 0x5b. Not a good way to verify the presence of
         * the device, but there is no hardware ID register. */
        if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
-                                        AK4104_RESERVED_VAL) {
-               ret = -ENODEV;
-               goto error_free_codec;
-       }
+                                        AK4104_RESERVED_VAL)
+               return -ENODEV;
 
        /* set power-up and non-reset bits */
        val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
        val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
        ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
        if (ret < 0)
-               goto error_free_codec;
+               return ret;
 
        /* enable transmitter */
        val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
        val |= AK4104_TX_TXE;
        ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
        if (ret < 0)
-               goto error_free_codec;
-
-       ak4104_codec = codec;
-       ret = snd_soc_register_dai(&ak4104_dai);
-       if (ret < 0) {
-               dev_err(&spi->dev, "failed to register DAI\n");
-               goto error_free_codec;
-       }
+               return ret;
 
-       spi_set_drvdata(spi, ak4104);
-       dev_info(&spi->dev, "SPI device initialized\n");
+       dev_info(codec->dev, "SPI device initialized\n");
        return 0;
-
-error_free_codec:
-       kfree(ak4104);
-       ak4104_dai.dev = NULL;
-       return ret;
 }
 
-static int __devexit ak4104_spi_remove(struct spi_device *spi)
+static int ak4104_remove(struct snd_soc_codec *codec)
 {
-       int ret, val;
-       struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+       int val, ret;
 
-       val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+       val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
        if (val < 0)
                return val;
 
        /* clear power-up and non-reset bits */
        val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
-       ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
-       if (ret < 0)
-               return ret;
+       ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 
-       ak4104_codec = NULL;
-       kfree(ak4104);
-       return 0;
+       return ret;
 }
 
-static int ak4104_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+       .probe =        ak4104_probe,
+       .remove =       ak4104_remove,
+       .reg_cache_size = AK4104_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+static int ak4104_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = ak4104_codec;
+       struct ak4104_private *ak4104;
        int ret;
 
-       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
-       socdev->card->codec = codec;
-
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
                return ret;
-       }
 
-       return 0;
+       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+       if (ak4104 == NULL)
+               return -ENOMEM;
+
+       ak4104->control_data = spi;
+       ak4104->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, ak4104);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_device_ak4104, &ak4104_dai, 1);
+       if (ret < 0)
+               kfree(ak4104);
+       return ret;
 }
 
-static int ak4104_remove(struct platform_device *pdev)
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       snd_soc_free_pcms(socdev);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
-};
-
-struct snd_soc_codec_device soc_codec_device_ak4104 = {
-       .probe =        ak4104_probe,
-       .remove =       ak4104_remove
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+}
 
 static struct spi_driver ak4104_spi_driver = {
        .driver  = {
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
deleted file mode 100644 (file)
index eb88fe7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _AK4104_H
-#define _AK4104_H
-
-extern struct snd_soc_dai ak4104_dai;
-extern struct snd_soc_codec_device soc_codec_device_ak4104;
-
-#endif
index d4253675b2d386f6aaa4d5a7fa53a20ebc07d22d..cd88c8f32a3871da48e1f2b5d4874e5b23cc0b78 100644 (file)
 
 #define AK4535_VERSION "0.3"
 
-struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 /* codec private data */
 struct ak4535_priv {
        unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 /*
@@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
        u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
        int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
 static int ak4535_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
-       u16 i;
+       u16 i, mute_reg;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               ak4535_mute(codec->dai, 0);
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+               ak4535_write(codec, AK4535_DAC, mute_reg);
                break;
        case SND_SOC_BIAS_PREPARE:
-               ak4535_mute(codec->dai, 1);
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+               ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
                break;
        case SND_SOC_BIAS_STANDBY:
                i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
        .set_sysclk     = ak4535_set_dai_sysclk,
 };
 
-struct snd_soc_dai ak4535_dai = {
-       .name = "AK4535",
+static struct snd_soc_dai_driver ak4535_dai = {
+       .name = "ak4535-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &ak4535_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4535_dai);
 
-static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int ak4535_resume(struct platform_device *pdev)
+static int ak4535_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        ak4535_sync(codec);
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-/*
- * initialise the AK4535 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4535_init(struct snd_soc_device *socdev)
+static int ak4535_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
+       struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 
-       codec->name = "AK4535";
-       codec->owner = THIS_MODULE;
-       codec->read = ak4535_read_reg_cache;
-       codec->write = ak4535_write;
-       codec->set_bias_level = ak4535_set_bias_level;
-       codec->dai = &ak4535_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
-       codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4535: failed to create pcms\n");
-               goto pcm_err;
-       }
+       codec->control_data = ak4535->control_data;
 
        /* power on device */
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(ak4535_snd_controls));
        ak4535_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
-       kfree(codec->reg_cache);
+       return 0;
+}
 
-       return ret;
+/* power down chip */
+static int ak4535_remove(struct snd_soc_codec *codec)
+{
+       ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static struct snd_soc_device *ak4535_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+       .probe =        ak4535_probe,
+       .remove =       ak4535_remove,
+       .suspend =      ak4535_suspend,
+       .resume =       ak4535_resume,
+       .read = ak4535_read_reg_cache,
+       .write = ak4535_write,
+       .set_bias_level = ak4535_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(ak4535_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = ak4535_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int ak4535_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = ak4535_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct ak4535_priv *ak4535;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+       if (ak4535 == NULL)
+               return -ENOMEM;
 
-       ret = ak4535_init(socdev);
-       if (ret < 0)
-               printk(KERN_ERR "failed to initialise AK4535\n");
+       i2c_set_clientdata(i2c, ak4535);
+       ak4535->control_data = i2c;
+       ak4535->control_type = SND_SOC_I2C;
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ak4535, &ak4535_dai, 1);
+       if (ret < 0)
+               kfree(ak4535);
        return ret;
 }
 
-static int ak4535_i2c_remove(struct i2c_client *client)
+static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
 
 static struct i2c_driver ak4535_i2c_driver = {
        .driver = {
-               .name = "AK4535 I2C Codec",
+               .name = "ak4535-codec",
                .owner = THIS_MODULE,
        },
        .probe =    ak4535_i2c_probe,
-       .remove =   ak4535_i2c_remove,
+       .remove =   __devexit_p(ak4535_i2c_remove),
        .id_table = ak4535_i2c_id,
 };
-
-static int ak4535_add_i2c_device(struct platform_device *pdev,
-                                const struct ak4535_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&ak4535_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&ak4535_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int ak4535_probe(struct platform_device *pdev)
+static int __init ak4535_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct ak4535_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct ak4535_priv *ak4535;
-       int ret;
-
-       printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
-       if (ak4535 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, ak4535);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ak4535_socdev = socdev;
-       ret = -ENODEV;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = ak4535_add_i2c_device(pdev, setup);
-       }
-#endif
-
+       ret = i2c_add_driver(&ak4535_i2c_driver);
        if (ret != 0) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
+                      ret);
        }
+#endif
        return ret;
 }
+module_init(ak4535_modinit);
 
-/* power down chip */
-static int ak4535_remove(struct platform_device *pdev)
+static void __exit ak4535_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (codec->control_data)
-               i2c_unregister_device(codec->control_data);
        i2c_del_driver(&ak4535_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4535 = {
-       .probe =        ak4535_probe,
-       .remove =       ak4535_remove,
-       .suspend =      ak4535_suspend,
-       .resume =       ak4535_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
-
-static int __init ak4535_modinit(void)
-{
-       return snd_soc_register_dai(&ak4535_dai);
-}
-module_init(ak4535_modinit);
-
-static void __exit ak4535_exit(void)
-{
-       snd_soc_unregister_dai(&ak4535_dai);
 }
 module_exit(ak4535_exit);
 
index c7a58703ea394ccd30c79a359d4be1401b438710..0431e5f634a2440c8ef9f0206fe1c0959a6cd553 100644 (file)
 
 #define AK4535_CACHEREGNUM     0x10
 
-struct ak4535_setup_data {
-       int            i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai ak4535_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 #endif
index 3d7dc55305ec3531838627e7a33f8b22009cfb2f..90c90b7f4a2ee553fcc8af76537da0c5ae7067ed 100644 (file)
@@ -30,8 +30,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "ak4642.h"
-
 #define AK4642_VERSION "0.0.1"
 
 #define PW_MGMT1       0x00
 
 #define AK4642_CACHEREGNUM     0x25
 
+/* PW_MGMT1*/
+#define PMVCM          (1 << 6) /* VCOM Power Management */
+#define PMMIN          (1 << 5) /* MIN Input Power Management */
+#define PMDAC          (1 << 2) /* DAC Power Management */
+#define PMADL          (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
 /* PW_MGMT2 */
 #define HPMTN          (1 << 6)
 #define PMHPL          (1 << 5)
 #define PMHP_MASK      (PMHPL | PMHPR)
 #define PMHP           PMHP_MASK
 
+/* PW_MGMT3 */
+#define PMADR          (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS           (1 << 6) /* Switch from MIN to Speaker */
+#define DACL           (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP           (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0         (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param)     ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param)     (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC            (1 << 5) /* ALC Enable */
+#define LMTH0          (1 << 0) /* ALC Limiter / Recovery Level */
+
 /* MD_CTL1 */
 #define PLL3           (1 << 7)
 #define PLL2           (1 << 6)
 #define FS3            (1 << 5)
 #define FS_MASK                (FS0 | FS1 | FS2 | FS3)
 
-struct snd_soc_codec_device soc_codec_dev_ak4642;
+/* MD_CTL3 */
+#define BST1           (1 << 3)
+
+/* MD_CTL4 */
+#define DACH           (1 << 0)
 
 /*
  * Playback Volume (table 39)
@@ -123,11 +148,11 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
 
 /* codec private data */
 struct ak4642_priv {
-       struct snd_soc_codec codec;
+       unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *ak4642_codec;
-
 /*
  * ak4642 register cache
  */
@@ -219,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                 * This operation came from example code of
                 * "ASAHI KASEI AK4642" (japanese) manual p97.
                 */
-               ak4642_write(codec, 0x0f, 0x09);
-               ak4642_write(codec, 0x0e, 0x19);
-               ak4642_write(codec, 0x09, 0x91);
-               ak4642_write(codec, 0x0c, 0x91);
-               ak4642_write(codec, 0x00, 0x64);
+               snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+               snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+               ak4642_write(codec, L_IVC, 0x91); /* volume */
+               ak4642_write(codec, R_IVC, 0x91); /* volume */
+               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+                                                    PMVCM | PMMIN | PMDAC);
                snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
                snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     HPMTN);
        } else {
@@ -240,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                 * This operation came from example code of
                 * "ASAHI KASEI AK4642" (japanese) manual p94.
                 */
-               ak4642_write(codec, 0x02, 0x05);
-               ak4642_write(codec, 0x06, 0x3c);
-               ak4642_write(codec, 0x08, 0xe1);
-               ak4642_write(codec, 0x0b, 0x00);
-               ak4642_write(codec, 0x07, 0x21);
-               ak4642_write(codec, 0x00, 0x41);
-               ak4642_write(codec, 0x10, 0x01);
+               ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+               ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+               ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+                                                    PMVCM | PMADL);
+               snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
        }
 
        return 0;
@@ -262,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
                /* stop headphone output */
                snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     0);
                snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
-               ak4642_write(codec, 0x00, 0x40);
-               ak4642_write(codec, 0x0e, 0x11);
-               ak4642_write(codec, 0x0f, 0x08);
+               snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+               snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+               snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
        } else {
                /* stop stereo input */
-               ak4642_write(codec, 0x00, 0x40);
-               ak4642_write(codec, 0x10, 0x00);
-               ak4642_write(codec, 0x07, 0x01);
+               snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+               snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+               snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
        }
 }
 
@@ -393,8 +418,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
        .hw_params      = ak4642_dai_hw_params,
 };
 
-struct snd_soc_dai ak4642_dai = {
-       .name = "AK4642",
+static struct snd_soc_dai_driver ak4642_dai = {
+       .name = "ak4642-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -410,112 +435,65 @@ struct snd_soc_dai ak4642_dai = {
        .ops = &ak4642_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(ak4642_dai);
 
-static int ak4642_resume(struct platform_device *pdev)
+static int ak4642_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ak4642_sync(codec);
        return 0;
 }
 
-/*
- * initialise the AK4642 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4642_init(struct ak4642_priv *ak4642)
+
+static int ak4642_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &ak4642->codec;
-       int ret = 0;
+       struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
 
-       if (ak4642_codec) {
-               dev_err(codec->dev, "Another ak4642 is registered\n");
-               return -EINVAL;
-       }
+       dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, ak4642);
-       codec->name             = "AK4642";
-       codec->owner            = THIS_MODULE;
-       codec->read             = ak4642_read_reg_cache;
-       codec->write            = ak4642_write;
-       codec->dai              = &ak4642_dai;
-       codec->num_dai          = 1;
        codec->hw_write         = (hw_write_t)i2c_master_send;
-       codec->reg_cache_size   = ARRAY_SIZE(ak4642_reg);
-       codec->reg_cache        = kmemdup(ak4642_reg,
-                                         sizeof(ak4642_reg), GFP_KERNEL);
+       codec->control_data     = ak4642->control_data;
 
-       if (!codec->reg_cache)
-               return -ENOMEM;
-
-       ak4642_dai.dev = codec->dev;
-       ak4642_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto reg_cache_err;
-       }
-
-       ret = snd_soc_register_dai(&ak4642_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto reg_cache_err;
-       }
-
-       return ret;
-
-reg_cache_err:
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
+       snd_soc_add_controls(codec, ak4642_snd_controls,
+                            ARRAY_SIZE(ak4642_snd_controls));
 
-       return ret;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+       .probe                  = ak4642_probe,
+       .resume                 = ak4642_resume,
+       .read                   = ak4642_read_reg_cache,
+       .write                  = ak4642_write,
+       .reg_cache_size         = ARRAY_SIZE(ak4642_reg),
+       .reg_word_size          = sizeof(u8),
+       .reg_cache_default      = ak4642_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int ak4642_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct ak4642_priv *ak4642;
-       struct snd_soc_codec *codec;
        int ret;
 
        ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
        if (!ak4642)
                return -ENOMEM;
 
-       codec = &ak4642->codec;
-       codec->dev = &i2c->dev;
-
        i2c_set_clientdata(i2c, ak4642);
-       codec->control_data = i2c;
+       ak4642->control_data = i2c;
+       ak4642->control_type = SND_SOC_I2C;
 
-       ret = ak4642_init(ak4642);
-       if (ret < 0) {
-               printk(KERN_ERR "failed to initialise AK4642\n");
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ak4642, &ak4642_dai, 1);
+       if (ret < 0)
                kfree(ak4642);
-       }
-
        return ret;
 }
 
-static int ak4642_i2c_remove(struct i2c_client *client)
+static __devexit int ak4642_i2c_remove(struct i2c_client *client)
 {
-       struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_dai(&ak4642_dai);
-       snd_soc_unregister_codec(&ak4642->codec);
-       kfree(ak4642->codec.reg_cache);
-       kfree(ak4642);
-       ak4642_codec = NULL;
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -528,64 +506,15 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
 
 static struct i2c_driver ak4642_i2c_driver = {
        .driver = {
-               .name = "AK4642 I2C Codec",
+               .name = "ak4642-codec",
                .owner = THIS_MODULE,
        },
        .probe          = ak4642_i2c_probe,
-       .remove         = ak4642_i2c_remove,
+       .remove         = __devexit_p(ak4642_i2c_remove),
        .id_table       = ak4642_i2c_id,
 };
-
 #endif
 
-static int ak4642_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       int ret;
-
-       if (!ak4642_codec) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = ak4642_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4642: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
-                            ARRAY_SIZE(ak4642_snd_controls));
-
-       dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
-       return ret;
-
-pcm_err:
-       return ret;
-
-}
-
-/* power down chip */
-static int ak4642_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4642 = {
-       .probe =        ak4642_probe,
-       .remove =       ak4642_remove,
-       .resume =       ak4642_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
-
 static int __init ak4642_modinit(void)
 {
        int ret = 0;
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h
deleted file mode 100644 (file)
index e476833..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ak4642.h  --  AK4642 Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ak4535.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _AK4642_H
-#define _AK4642_H
-
-extern struct snd_soc_dai ak4642_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4642;
-
-#endif
index 87566932a3b174c8afa318c679421882ff906356..24f5f49bb9d2cf9f5a84b205643b74ddfca47126 100644 (file)
 
 #include "ak4671.h"
 
-static struct snd_soc_codec *ak4671_codec;
 
 /* codec private data */
 struct ak4671_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u8 reg_cache[AK4671_CACHEREGNUM];
 };
 
@@ -619,8 +619,8 @@ static struct snd_soc_dai_ops ak4671_dai_ops = {
        .set_fmt        = ak4671_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4671_dai = {
-       .name = "AK4671",
+static struct snd_soc_dai_driver ak4671_dai = {
+       .name = "ak4671-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -635,27 +635,18 @@ struct snd_soc_dai ak4671_dai = {
                .formats = AK4671_FORMATS,},
        .ops = &ak4671_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4671_dai);
 
-static int ak4671_probe(struct platform_device *pdev)
+static int ak4671_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (ak4671_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
+       struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       socdev->card->codec = ak4671_codec;
-       codec = ak4671_codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        snd_soc_add_controls(codec, ak4671_snd_controls,
@@ -665,121 +656,48 @@ static int ak4671_probe(struct platform_device *pdev)
        ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
-static int ak4671_remove(struct platform_device *pdev)
+static int ak4671_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
        .probe = ak4671_probe,
        .remove = ak4671_remove,
+       .set_bias_level = ak4671_set_bias_level,
+       .reg_cache_size = AK4671_CACHEREGNUM,
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = ak4671_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
-
-static int ak4671_register(struct ak4671_priv *ak4671,
-               enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &ak4671->codec;
-
-       if (ak4671_codec) {
-               dev_err(codec->dev, "Another AK4671 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec,  ak4671);
-       codec->name = "AK4671";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = ak4671_set_bias_level;
-       codec->dai = &ak4671_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = AK4671_CACHEREGNUM;
-       codec->reg_cache = &ak4671->reg_cache;
-
-       memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       ak4671_dai.dev = codec->dev;
-       ak4671_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&ak4671_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(ak4671);
-       return ret;
-}
-
-static void ak4671_unregister(struct ak4671_priv *ak4671)
-{
-       ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&ak4671_dai);
-       snd_soc_unregister_codec(&ak4671->codec);
-       kfree(ak4671);
-       ak4671_codec = NULL;
-}
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct ak4671_priv *ak4671;
-       struct snd_soc_codec *codec;
+       int ret;
 
        ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
        if (ak4671 == NULL)
                return -ENOMEM;
 
-       codec = &ak4671->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(client, ak4671);
-       codec->control_data = client;
-
-       codec->dev = &client->dev;
+       ak4671->control_data = client;
+       ak4671->control_type = SND_SOC_I2C;
 
-       return ak4671_register(ak4671, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_ak4671, &ak4671_dai, 1);
+       if (ret < 0)
+               kfree(ak4671);
+       return ret;
 }
 
 static __devexit int ak4671_i2c_remove(struct i2c_client *client)
 {
-       struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
-
-       ak4671_unregister(ak4671);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -791,7 +709,7 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
 
 static struct i2c_driver ak4671_i2c_driver = {
        .driver = {
-               .name = "ak4671",
+               .name = "ak4671-codec",
                .owner = THIS_MODULE,
        },
        .probe = ak4671_i2c_probe,
index e2fad964e88b125e54a58967743d2e2837a676ad..61cb7ab7552ce5a390fd1306905214a60bdd442e 100644 (file)
 /* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
 #define AK4671_MUTEN                           0x04
 
-extern struct snd_soc_dai ak4671_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4671;
-
 #endif
index a320fb5a0e26afefba683311539584a71c6ade7c..823643932dde2eb6208fd290f90254a2416e29bc 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -41,8 +42,6 @@
 
 #include <mach/dm365.h>
 
-#include "cq93vc.h"
-
 static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
                                                unsigned int reg)
 {
@@ -130,8 +129,8 @@ static struct snd_soc_dai_ops cq93vc_dai_ops = {
        .set_sysclk     = cq93vc_set_dai_sysclk,
 };
 
-struct snd_soc_dai cq93vc_dai = {
-       .name = "CQ93VC",
+static struct snd_soc_dai_driver cq93vc_dai = {
+       .name = "cq93vc-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -146,36 +145,20 @@ struct snd_soc_dai cq93vc_dai = {
                .formats = CQ93VC_FORMATS,},
        .ops = &cq93vc_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cq93vc_dai);
 
-static int cq93vc_resume(struct platform_device *pdev)
+static int cq93vc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-static struct snd_soc_codec *cq93vc_codec;
-
-static int cq93vc_probe(struct platform_device *pdev)
+static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct device *dev = &pdev->dev;
-       struct snd_soc_codec *codec;
-       int ret;
-
-       socdev->card->codec = cq93vc_codec;
-       codec = socdev->card->codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(dev, "%s: failed to create pcms\n", pdev->name);
-               return ret;
-       }
+       struct davinci_vc *davinci_vc = codec->dev->platform_data;
+
+       davinci_vc->cq93vc.codec = codec;
+       codec->control_data = davinci_vc;
 
        /* Set controls */
        snd_soc_add_controls(codec, cq93vc_snd_controls,
@@ -187,108 +170,51 @@ static int cq93vc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int cq93vc_remove(struct platform_device *pdev)
+static int cq93vc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_cq93vc = {
+static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+       .read = cq93vc_read,
+       .write = cq93vc_write,
+       .set_bias_level = cq93vc_set_bias_level,
        .probe = cq93vc_probe,
        .remove = cq93vc_remove,
        .resume = cq93vc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
 
-static __init int cq93vc_codec_probe(struct platform_device *pdev)
+static int cq93vc_platform_probe(struct platform_device *pdev)
 {
-       struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL) {
-               dev_dbg(davinci_vc->dev,
-                       "could not allocate memory for codec data\n");
-               return -ENOMEM;
-       }
-
-       davinci_vc->cq93vc.codec = codec;
-
-       cq93vc_dai.dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->dev = &pdev->dev;
-       codec->name = "CQ93VC";
-       codec->owner = THIS_MODULE;
-       codec->read = cq93vc_read;
-       codec->write = cq93vc_write;
-       codec->set_bias_level = cq93vc_set_bias_level;
-       codec->dai = &cq93vc_dai;
-       codec->num_dai = 1;
-       codec->control_data = davinci_vc;
-
-       cq93vc_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(davinci_vc->dev, "failed to register codec\n");
-               goto fail1;
-       }
-
-       ret = snd_soc_register_dai(&cq93vc_dai);
-       if (ret) {
-               dev_err(davinci_vc->dev, "could register dai\n");
-               goto fail2;
-       }
-       return 0;
-
-fail2:
-       snd_soc_unregister_codec(codec);
-
-fail1:
-       kfree(codec);
-       cq93vc_codec = NULL;
-
-       return ret;
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_cq93vc, &cq93vc_dai, 1);
 }
 
-static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
+static int cq93vc_platform_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_unregister_dai(&cq93vc_dai);
-       snd_soc_unregister_codec(&codec);
-
-       kfree(codec);
-       cq93vc_codec = NULL;
-
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver cq93vc_codec_driver = {
        .driver = {
-                  .name = "cq93vc",
-                  .owner = THIS_MODULE,
-                  },
-       .probe = cq93vc_codec_probe,
-       .remove = __devexit_p(cq93vc_codec_remove),
+                       .name = "cq93vc-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = cq93vc_platform_probe,
+       .remove = __devexit_p(cq93vc_platform_remove),
 };
 
-static __init int cq93vc_init(void)
+static int __init cq93vc_init(void)
 {
-       return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
+       return platform_driver_register(&cq93vc_codec_driver);
 }
 module_init(cq93vc_init);
 
-static __exit void cq93vc_exit(void)
+static void __exit cq93vc_exit(void)
 {
        platform_driver_unregister(&cq93vc_codec_driver);
 }
diff --git a/sound/soc/codecs/cq93vc.h b/sound/soc/codecs/cq93vc.h
deleted file mode 100644 (file)
index 845b196..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
- *
- * Copyright (C) 2010 Texas Instruments, Inc
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _CQ93VC_H
-#define _CQ93VC_H
-
-extern struct snd_soc_dai cq93vc_dai;
-extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
-
-#endif
index 30d949239def0727127497f6a8f5c92f6885d386..6d4bdc609ac87db254e6a145f35b952509c92a2f 100644 (file)
@@ -31,8 +31,6 @@
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
-#include "cs4270.h"
-
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
  * interface requires data to be sent serially with the MSbit first.
@@ -114,7 +112,8 @@ static const char *supply_names[] = {
 
 /* Private data for the CS4270 */
 struct cs4270_private {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u8 reg_cache[CS4270_NUMREGS];
        unsigned int mclk; /* Input frequency of the MCLK pin */
        unsigned int mode; /* The mode (I2S or left-justified) */
@@ -212,44 +211,8 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
-       unsigned int i;
 
        cs4270->mclk = freq;
-
-       if (cs4270->mclk) {
-               for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-                       unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
-                       rates |= snd_pcm_rate_to_rate_bit(rate);
-                       if (rate < rate_min)
-                               rate_min = rate;
-                       if (rate > rate_max)
-                               rate_max = rate;
-               }
-               /* FIXME: soc should support a rate list */
-               rates &= ~SNDRV_PCM_RATE_KNOT;
-
-               if (!rates) {
-                       dev_err(codec->dev, "could not find a valid sample rate\n");
-                       return -EINVAL;
-               }
-       } else {
-               /* enable all possible rates */
-               rates = SNDRV_PCM_RATE_8000_192000;
-               rate_min = 8000;
-               rate_max = 192000;
-       }
-
-       codec_dai->playback.rates = rates;
-       codec_dai->playback.rate_min = rate_min;
-       codec_dai->playback.rate_max = rate_max;
-
-       codec_dai->capture.rates = rates;
-       codec_dai->capture.rate_min = rate_min;
-       codec_dai->capture.rate_max = rate_max;
-
        return 0;
 }
 
@@ -410,8 +373,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
@@ -549,19 +511,6 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
                snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
-/*
- * cs4270_codec - global variable to store codec for the ASoC probe function
- *
- * If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_codec.  This is the only way to pass the codec structure from
- * cs4270_i2c_probe() to cs4270_probe().  Unfortunately, there is no good
- * way to synchronize these two functions.  cs4270_i2c_probe() can be called
- * multiple times before cs4270_probe() is called even once.  So for now, we
- * also only allow cs4270_i2c_probe() to be run once.  That means that we do
- * not support more than one cs4270 device in the system, at least for now.
- */
-static struct snd_soc_codec *cs4270_codec;
-
 static struct snd_soc_dai_ops cs4270_dai_ops = {
        .hw_params      = cs4270_hw_params,
        .set_sysclk     = cs4270_set_dai_sysclk,
@@ -569,25 +518,28 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
        .digital_mute   = cs4270_dai_mute,
 };
 
-struct snd_soc_dai cs4270_dai = {
-       .name = "cs4270",
+static struct snd_soc_dai_driver cs4270_dai = {
+       .name = "cs4270-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = 0,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 4000,
+               .rate_max = 216000,
                .formats = CS4270_FORMATS,
        },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = 0,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 4000,
+               .rate_max = 216000,
                .formats = CS4270_FORMATS,
        },
        .ops = &cs4270_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cs4270_dai);
 
 /**
  * cs4270_probe - ASoC probe function
@@ -596,153 +548,19 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
  * This function is called when ASoC has all the pieces it needs to
  * instantiate a sound driver.
  */
-static int cs4270_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = cs4270_codec;
-       struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
-
-       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
-       socdev->card->codec = codec;
-
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               return ret;
-       }
-
-       /* Add the non-DAPM controls */
-       ret = snd_soc_add_controls(codec, cs4270_snd_controls,
-                               ARRAY_SIZE(cs4270_snd_controls));
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to add controls\n");
-               goto error_free_pcms;
-       }
-
-       /* get the power supply regulators */
-       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
-               cs4270->supplies[i].supply = supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
-                                cs4270->supplies);
-       if (ret < 0)
-               goto error_free_pcms;
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
-                                   cs4270->supplies);
-       if (ret < 0)
-               goto error_free_regulators;
-
-       return 0;
-
-error_free_regulators:
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
-                           cs4270->supplies);
-
-error_free_pcms:
-       snd_soc_free_pcms(socdev);
-
-       return ret;
-}
-
-/**
- * cs4270_remove - ASoC remove function
- * @pdev: platform device
- *
- * This function is the counterpart to cs4270_probe().
- */
-static int cs4270_remove(struct platform_device *pdev)
+static int cs4270_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+       int i, ret, reg;
 
-       snd_soc_free_pcms(socdev);
-       regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-
-       return 0;
-};
-
-/**
- * cs4270_i2c_probe - initialize the I2C interface of the CS4270
- * @i2c_client: the I2C client object
- * @id: the I2C device ID (ignored)
- *
- * This function is called whenever the I2C subsystem finds a device that
- * matches the device ID given via a prior call to i2c_add_driver().
- */
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
-{
-       struct snd_soc_codec *codec;
-       struct cs4270_private *cs4270;
-       unsigned int reg;
-       int ret;
-
-       /* For now, we only support one cs4270 device in the system.  See the
-        * comment for cs4270_codec.
-        */
-       if (cs4270_codec) {
-               dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
-                      i2c_client->addr);
-               dev_err(&i2c_client->dev, "only one per board allowed\n");
-               /* Should we return something other than ENODEV here? */
-               return -ENODEV;
-       }
-
-       /* Verify that we have a CS4270 */
-
-       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
-                      i2c_client->addr);
-               return ret;
-       }
-       /* The top four bits of the chip ID should be 1100. */
-       if ((ret & 0xF0) != 0xC0) {
-               dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
-                      i2c_client->addr);
-               return -ENODEV;
-       }
-
-       dev_info(&i2c_client->dev, "found device at i2c address %X\n",
-               i2c_client->addr);
-       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
-
-       /* Allocate enough space for the snd_soc_codec structure
-          and our private data together. */
-       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
-       if (!cs4270) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-       codec = &cs4270->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c_client->dev;
-       codec->name = "CS4270";
-       codec->owner = THIS_MODULE;
-       codec->dai = &cs4270_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, cs4270);
-       codec->control_data = i2c_client;
-       codec->read = cs4270_read_reg_cache;
-       codec->write = cs4270_i2c_write;
-       codec->reg_cache = cs4270->reg_cache;
-       codec->reg_cache_size = CS4270_NUMREGS;
+       codec->control_data = cs4270->control_data;
 
        /* The I2C interface is set up, so pre-fill our register cache */
 
        ret = cs4270_fill_cache(codec);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to fill register cache\n");
-               goto error_free_codec;
+               dev_err(codec->dev, "failed to fill register cache\n");
+               return ret;
        }
 
        /* Disable auto-mute.  This feature appears to be buggy.  In some
@@ -755,7 +573,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        reg &= ~CS4270_MUTE_AUTO;
        ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "i2c write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
@@ -769,65 +587,56 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
        ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "i2c write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
-       /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
-        * structure for each CS4270 device, but the machine driver needs to
-        * have a pointer to the DAI structure, so for now it must be a global
-        * variable.
-        */
-       cs4270_dai.dev = &i2c_client->dev;
-
-       /* Register the DAI.  If all the other ASoC driver have already
-        * registered, then this will call our probe function, so
-        * cs4270_codec needs to be ready.
-        */
-       cs4270_codec = codec;
-       ret = snd_soc_register_dai(&cs4270_dai);
+       /* Add the non-DAPM controls */
+       ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+                               ARRAY_SIZE(cs4270_snd_controls));
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to register DAIe\n");
-               goto error_free_codec;
+               dev_err(codec->dev, "failed to add controls\n");
+               return ret;
        }
 
-       i2c_set_clientdata(i2c_client, cs4270);
+       /* get the power supply regulators */
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               cs4270->supplies[i].supply = supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
+                                cs4270->supplies);
+       if (ret < 0)
+               return ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+                                   cs4270->supplies);
+       if (ret < 0)
+               goto error_free_regulators;
 
        return 0;
 
-error_free_codec:
-       kfree(cs4270);
-       cs4270_codec = NULL;
-       cs4270_dai.dev = NULL;
+error_free_regulators:
+       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
+                           cs4270->supplies);
 
        return ret;
 }
 
 /**
- * cs4270_i2c_remove - remove an I2C device
- * @i2c_client: the I2C client object
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
  *
- * This function is the counterpart to cs4270_i2c_probe().
+ * This function is the counterpart to cs4270_probe().
  */
-static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+static int cs4270_remove(struct snd_soc_codec *codec)
 {
-       struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+       struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
 
-       kfree(cs4270);
-       cs4270_codec = NULL;
-       cs4270_dai.dev = NULL;
+       regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
+       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
 
        return 0;
-}
-
-/*
- * cs4270_id - I2C device IDs supported by this driver
- */
-static struct i2c_device_id cs4270_id[] = {
-       {"cs4270", 0},
-       {}
 };
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
 
 #ifdef CONFIG_PM
 
@@ -840,9 +649,8 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
  * and all registers are written back to the hardware when resuming.
  */
 
-static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
 {
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int reg, ret;
 
@@ -860,9 +668,8 @@ static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
        return 0;
 }
 
-static int cs4270_soc_resume(struct platform_device *pdev)
+static int cs4270_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c_client = codec->control_data;
        int reg;
@@ -895,6 +702,95 @@ static int cs4270_soc_resume(struct platform_device *pdev)
 #define cs4270_soc_resume      NULL
 #endif /* CONFIG_PM */
 
+/*
+ * ASoC codec device structure
+ *
+ * Assign this variable to the codec_dev field of the machine driver's
+ * snd_soc_device structure.
+ */
+static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
+       .probe =        cs4270_probe,
+       .remove =       cs4270_remove,
+       .suspend =      cs4270_soc_suspend,
+       .resume =       cs4270_soc_resume,
+       .read = cs4270_read_reg_cache,
+       .write = cs4270_i2c_write,
+       .reg_cache_size = CS4270_NUMREGS,
+       .reg_word_size = sizeof(u8),
+};
+
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
+ *
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
+ */
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+       const struct i2c_device_id *id)
+{
+       struct cs4270_private *cs4270;
+       int ret;
+
+       /* Verify that we have a CS4270 */
+
+       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+                      i2c_client->addr);
+               return ret;
+       }
+       /* The top four bits of the chip ID should be 1100. */
+       if ((ret & 0xF0) != 0xC0) {
+               dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+                      i2c_client->addr);
+               return -ENODEV;
+       }
+
+       dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+               i2c_client->addr);
+       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
+
+       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+       if (!cs4270) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs4270);
+       cs4270->control_data = i2c_client;
+       cs4270->control_type = SND_SOC_I2C;
+
+       ret = snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_device_cs4270, &cs4270_dai, 1);
+       if (ret < 0)
+               kfree(cs4270);
+       return ret;
+}
+
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+       snd_soc_unregister_codec(&i2c_client->dev);
+       kfree(i2c_get_clientdata(i2c_client));
+       return 0;
+}
+
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+       {"cs4270", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
 /*
  * cs4270_i2c_driver - I2C device identification
  *
@@ -903,7 +799,7 @@ static int cs4270_soc_resume(struct platform_device *pdev)
  */
 static struct i2c_driver cs4270_i2c_driver = {
        .driver = {
-               .name = "cs4270",
+               .name = "cs4270-codec",
                .owner = THIS_MODULE,
        },
        .id_table = cs4270_id,
@@ -911,20 +807,6 @@ static struct i2c_driver cs4270_i2c_driver = {
        .remove = cs4270_i2c_remove,
 };
 
-/*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
- */
-struct snd_soc_codec_device soc_codec_device_cs4270 = {
-       .probe =        cs4270_probe,
-       .remove =       cs4270_remove,
-       .suspend =      cs4270_soc_suspend,
-       .resume =       cs4270_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
-
 static int __init cs4270_init(void)
 {
        pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h
deleted file mode 100644 (file)
index adc6cd9..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Cirrus Logic CS4270 ALSA SoC Codec Driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, 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 _CS4270_H
-#define _CS4270_H
-
-/*
- * The ASoC codec DAI structure for the CS4270.  Assign this structure to
- * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
- */
-extern struct snd_soc_dai cs4270_dai;
-
-/*
- * The ASoC codec device structure for the CS4270.  Assign this structure
- * to the .codec_dev field of your machine driver's snd_soc_device
- * structure.
- */
-extern struct snd_soc_codec_device soc_codec_device_cs4270;
-
-#endif
index dd9b8550c402bcb65f2757ecc4123ba6c6c3c219..cb086eaf4e07dd3382331acd9009f81f2e3647fd 100644 (file)
@@ -42,15 +42,14 @@ enum master_slave_mode {
 };
 
 struct cs42l51_private {
+       enum snd_soc_control_type control_type;
+       void *control_data;
        unsigned int mclk;
        unsigned int audio_mode;        /* The mode (I2S or left-justified) */
        enum master_slave_mode func;
-       struct snd_soc_codec codec;
        u8 reg_cache[CS42L51_NUMREGS];
 };
 
-static struct snd_soc_codec *cs42l51_codec;
-
 #define CS42L51_FORMATS ( \
                SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
                SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
@@ -75,134 +74,6 @@ static int cs42l51_fill_cache(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
-{
-       struct snd_soc_codec *codec;
-       struct cs42l51_private *cs42l51;
-       int ret = 0;
-       int reg;
-
-       if (cs42l51_codec)
-               return -EBUSY;
-
-       /* Verify that we have a CS42L51 */
-       ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to read I2C\n");
-               goto error;
-       }
-
-       if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
-           (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
-               dev_err(&i2c_client->dev, "Invalid chip id\n");
-               ret = -ENODEV;
-               goto error;
-       }
-
-       dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
-                               ret & 7);
-
-       cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
-       if (!cs42l51) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-       codec = &cs42l51->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c_client->dev;
-       codec->name = "CS42L51";
-       codec->owner = THIS_MODULE;
-       codec->dai = &cs42l51_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, cs42l51);
-
-       codec->control_data = i2c_client;
-       codec->reg_cache = cs42l51->reg_cache;
-       codec->reg_cache_size = CS42L51_NUMREGS;
-       i2c_set_clientdata(i2c_client, codec);
-
-       ret = cs42l51_fill_cache(codec);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to fill register cache\n");
-               goto error_alloc;
-       }
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
-               goto error_alloc;
-       }
-
-       /*
-        * DAC configuration
-        * - Use signal processor
-        * - auto mute
-        * - vol changes immediate
-        * - no de-emphasize
-        */
-       reg = CS42L51_DAC_CTL_DATA_SEL(1)
-               | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
-       ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
-       if (ret < 0)
-               goto error_alloc;
-
-       cs42l51_dai.dev = codec->dev;
-       cs42l51_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_alloc;
-       }
-
-       ret = snd_soc_register_dai(&cs42l51_dai);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to register DAIe\n");
-               goto error_reg;
-       }
-
-       return 0;
-
-error_reg:
-       snd_soc_unregister_codec(codec);
-error_alloc:
-       kfree(cs42l51);
-error:
-       return ret;
-}
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
-       struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
-       snd_soc_unregister_dai(&cs42l51_dai);
-       snd_soc_unregister_codec(cs42l51_codec);
-       cs42l51_codec = NULL;
-       kfree(cs42l51);
-       return 0;
-}
-
-
-static const struct i2c_device_id cs42l51_id[] = {
-       {"cs42l51", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
-
-static struct i2c_driver cs42l51_i2c_driver = {
-       .driver = {
-               .name = "CS42L51 I2C",
-               .owner = THIS_MODULE,
-       },
-       .id_table = cs42l51_id,
-       .probe = cs42l51_i2c_probe,
-       .remove = cs42l51_i2c_remove,
-};
-
 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
@@ -484,51 +355,8 @@ static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
-       struct cs42l51_ratios *ratios = NULL;
-       int nr_ratios = 0;
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
-       int i;
 
        cs42l51->mclk = freq;
-
-       switch (cs42l51->func) {
-       case MODE_MASTER:
-               return -EINVAL;
-       case MODE_SLAVE:
-               ratios = slave_ratios;
-               nr_ratios = ARRAY_SIZE(slave_ratios);
-               break;
-       case MODE_SLAVE_AUTO:
-               ratios = slave_auto_ratios;
-               nr_ratios = ARRAY_SIZE(slave_auto_ratios);
-               break;
-       }
-
-       for (i = 0; i < nr_ratios; i++) {
-               unsigned int rate = freq / ratios[i].ratio;
-               rates |= snd_pcm_rate_to_rate_bit(rate);
-               if (rate < rate_min)
-                       rate_min = rate;
-               if (rate > rate_max)
-                       rate_max = rate;
-       }
-       rates &= ~SNDRV_PCM_RATE_KNOT;
-
-       if (!rates) {
-               dev_err(codec->dev, "could not find a valid sample rate\n");
-               return -EINVAL;
-       }
-
-       codec_dai->playback.rates = rates;
-       codec_dai->playback.rate_min = rate_min;
-       codec_dai->playback.rate_max = rate_max;
-
-       codec_dai->capture.rates = rates;
-       codec_dai->capture.rate_min = rate_min;
-       codec_dai->capture.rate_max = rate_max;
-
        return 0;
 }
 
@@ -537,8 +365,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
@@ -670,8 +497,8 @@ static struct snd_soc_dai_ops cs42l51_dai_ops = {
        .digital_mute   = cs42l51_dai_mute,
 };
 
-struct snd_soc_dai cs42l51_dai = {
-       .name = "CS42L51 HiFi",
+static struct snd_soc_dai_driver cs42l51_dai = {
+       .name = "cs42l51-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -688,30 +515,39 @@ struct snd_soc_dai cs42l51_dai = {
        },
        .ops = &cs42l51_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cs42l51_dai);
-
 
-static int cs42l51_probe(struct platform_device *pdev)
+static int cs42l51_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+       int ret, reg;
 
-       if (!cs42l51_codec) {
-               dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
-               return -EINVAL;
-       }
+       codec->control_data = cs42l51->control_data;
 
-       socdev->card->codec = cs42l51_codec;
-       codec = socdev->card->codec;
+       ret = cs42l51_fill_cache(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to fill register cache\n");
+               return ret;
+       }
 
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create PCMs\n");
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
+       /*
+        * DAC configuration
+        * - Use signal processor
+        * - auto mute
+        * - vol changes immediate
+        * - no de-emphasize
+        */
+       reg = CS42L51_DAC_CTL_DATA_SEL(1)
+               | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+       ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+       if (ret < 0)
+               return ret;
+
        snd_soc_add_controls(codec, cs42l51_snd_controls,
                ARRAY_SIZE(cs42l51_snd_controls));
        snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
@@ -722,22 +558,77 @@ static int cs42l51_probe(struct platform_device *pdev)
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+       .probe =        cs42l51_probe,
+       .reg_cache_size = CS42L51_NUMREGS,
+       .reg_word_size = sizeof(u8),
+};
 
-static int cs42l51_remove(struct platform_device *pdev)
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+       const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct cs42l51_private *cs42l51;
+       int ret;
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       /* Verify that we have a CS42L51 */
+       ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to read I2C\n");
+               goto error;
+       }
+
+       if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+           (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+               dev_err(&i2c_client->dev, "Invalid chip id\n");
+               ret = -ENODEV;
+               goto error;
+       }
+
+       dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+                               ret & 7);
+
+       cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+       if (!cs42l51) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs42l51);
+       cs42l51->control_data = i2c_client;
+       cs42l51->control_type = SND_SOC_I2C;
 
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_device_cs42l51, &cs42l51_dai, 1);
+       if (ret < 0)
+               kfree(cs42l51);
+error:
+       return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+       struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       kfree(cs42l51);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_device_cs42l51 = {
-       .probe =        cs42l51_probe,
-       .remove =       cs42l51_remove
+static const struct i2c_device_id cs42l51_id[] = {
+       {"cs42l51", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+       .driver = {
+               .name = "cs42l51-codec",
+               .owner = THIS_MODULE,
+       },
+       .id_table = cs42l51_id,
+       .probe = cs42l51_i2c_probe,
+       .remove = cs42l51_i2c_remove,
 };
-EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
 
 static int __init cs42l51_init(void)
 {
@@ -758,6 +649,6 @@ static void __exit cs42l51_exit(void)
 }
 module_exit(cs42l51_exit);
 
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");
index 8f0bd9786ad2a4966421bab434441944bebd84c5..2beeb171db4b99f8635b01304d97f7b0439e7fe0 100644 (file)
 #define CS42L51_LASTREG                0x20
 #define CS42L51_NUMREGS                (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
 
-extern struct snd_soc_dai cs42l51_dai;
-extern struct snd_soc_codec_device soc_codec_device_cs42l51;
 #endif
index f07a415c753fd12a31d1b24d7cc4e82deafa5819..e8d27c8f9ba392e16a8f05ae38da6cd7a274fab2 100644 (file)
@@ -24,7 +24,8 @@
 
 
 struct cx20442_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u8 reg_cache[1];
 };
 
@@ -102,7 +103,7 @@ static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
 {
        u8 *reg_cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        return reg_cache[reg];
@@ -164,16 +165,17 @@ static int cx20442_pm_to_v253_vsp(u8 value)
 static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
                                                        unsigned int value)
 {
+       struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
        u8 *reg_cache = codec->reg_cache;
        int vls, vsp, old, len;
        char buf[18];
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        /* hw_write and control_data pointers required for talking to the modem
         * are expected to be set by the line discipline initialization code */
-       if (!codec->hw_write || !codec->control_data)
+       if (!codec->hw_write || !cx20442->control_data)
                return -EIO;
 
        old = reg_cache[reg];
@@ -202,17 +204,13 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
                return -ENOMEM;
 
        dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
-       if (codec->hw_write(codec->control_data, buf, len) != len)
+       if (codec->hw_write(cx20442->control_data, buf, len) != len)
                return -EIO;
 
        return 0;
 }
 
 
-/* Moved up here as line discipline referres it during initialization */
-static struct snd_soc_codec *cx20442_codec;
-
-
 /*
  * Line discpline related code
  *
@@ -228,15 +226,15 @@ static const char *v253_init = "ate0m0q0+fclass=8\r";
 /* Line discipline .open() */
 static int v253_open(struct tty_struct *tty)
 {
-       struct snd_soc_codec *codec = cx20442_codec;
        int ret, len = strlen(v253_init);
 
        /* Doesn't make sense without write callback */
        if (!tty->ops->write)
                return -EINVAL;
 
-       /* Pass the codec structure address for use by other ldisc callbacks */
-       tty->disc_data = codec;
+       /* Won't work if no codec pointer has been passed by a card driver */
+       if (!tty->disc_data)
+               return -ENODEV;
 
        if (tty->ops->write(tty, v253_init, len) != len) {
                ret = -EIO;
@@ -253,15 +251,18 @@ err:
 static void v253_close(struct tty_struct *tty)
 {
        struct snd_soc_codec *codec = tty->disc_data;
+       struct cx20442_priv *cx20442;
 
        tty->disc_data = NULL;
 
        if (!codec)
                return;
 
+       cx20442 = snd_soc_codec_get_drvdata(codec);
+
        /* Prevent the codec driver from further accessing the modem */
        codec->hw_write = NULL;
-       codec->control_data = NULL;
+       cx20442->control_data = NULL;
        codec->pop_time = 0;
 }
 
@@ -277,15 +278,18 @@ static void v253_receive(struct tty_struct *tty,
                                const unsigned char *cp, char *fp, int count)
 {
        struct snd_soc_codec *codec = tty->disc_data;
+       struct cx20442_priv *cx20442;
 
        if (!codec)
                return;
 
-       if (!codec->control_data) {
+       cx20442 = snd_soc_codec_get_drvdata(codec);
+
+       if (!cx20442->control_data) {
                /* First modem response, complete setup procedure */
 
                /* Set up codec driver access to modem controls */
-               codec->control_data = tty;
+               cx20442->control_data = tty;
                codec->hw_write = (hw_write_t)tty->ops->write;
                codec->pop_time = 1;
        }
@@ -313,8 +317,8 @@ EXPORT_SYMBOL_GPL(v253_ops);
  * Codec DAI
  */
 
-struct snd_soc_dai cx20442_dai = {
-       .name = "CX20442",
+static struct snd_soc_dai_driver cx20442_dai = {
+       .name = "cx20442-voice",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -330,142 +334,63 @@ struct snd_soc_dai cx20442_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 };
-EXPORT_SYMBOL_GPL(cx20442_dai);
 
-static int cx20442_codec_probe(struct platform_device *pdev)
+static int cx20442_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!cx20442_codec) {
-               dev_err(&pdev->dev, "cx20442 not yet discovered\n");
-               return -ENODEV;
-       }
-       codec = cx20442_codec;
-
-       socdev->card->codec = codec;
+       struct cx20442_priv *cx20442;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto pcm_err;
-       }
+       cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+       if (cx20442 == NULL)
+               return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, cx20442);
 
        cx20442_add_widgets(codec);
 
-pcm_err:
-       return ret;
+       cx20442->control_data = NULL;
+       codec->hw_write = NULL;
+       codec->pop_time = 0;
+
+       return 0;
 }
 
 /* power down chip */
-static int cx20442_codec_remove(struct platform_device *pdev)
+static int cx20442_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       if (cx20442->control_data) {
+                       struct tty_struct *tty = cx20442->control_data;
+                       tty_hangup(tty);
+       }
 
+       kfree(cx20442);
        return 0;
 }
 
-struct snd_soc_codec_device cx20442_codec_dev = {
+static struct snd_soc_codec_driver cx20442_codec_dev = {
        .probe =        cx20442_codec_probe,
        .remove =       cx20442_codec_remove,
+       .reg_cache_size = 1,
+       .reg_word_size = sizeof(u8),
+       .read = cx20442_read_reg_cache,
+       .write = cx20442_write,
 };
-EXPORT_SYMBOL_GPL(cx20442_codec_dev);
-
-static int cx20442_register(struct cx20442_priv *cx20442)
-{
-       struct snd_soc_codec *codec = &cx20442->codec;
-       int ret;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "CX20442";
-       codec->owner = THIS_MODULE;
-       snd_soc_codec_set_drvdata(codec, cx20442);
-
-       codec->dai = &cx20442_dai;
-       codec->num_dai = 1;
-
-       codec->reg_cache = &cx20442->reg_cache;
-       codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
-       codec->read = cx20442_read_reg_cache;
-       codec->write = cx20442_write;
-
-       codec->bias_level = SND_SOC_BIAS_OFF;
-
-       cx20442_dai.dev = codec->dev;
-
-       cx20442_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&cx20442_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       cx20442_codec = NULL;
-       kfree(cx20442);
-       return ret;
-}
-
-static void cx20442_unregister(struct cx20442_priv *cx20442)
-{
-       snd_soc_unregister_dai(&cx20442_dai);
-       snd_soc_unregister_codec(&cx20442->codec);
-
-       cx20442_codec = NULL;
-       kfree(cx20442);
-}
 
 static int cx20442_platform_probe(struct platform_device *pdev)
 {
-       struct cx20442_priv *cx20442;
-       struct snd_soc_codec *codec;
-
-       cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
-       if (cx20442 == NULL)
-               return -ENOMEM;
-
-       codec = &cx20442->codec;
-
-       codec->control_data = NULL;
-       codec->hw_write = NULL;
-       codec->pop_time = 0;
-
-       codec->dev = &pdev->dev;
-       platform_set_drvdata(pdev, cx20442);
-
-       return cx20442_register(cx20442);
+       return snd_soc_register_codec(&pdev->dev,
+                       &cx20442_codec_dev, &cx20442_dai, 1);
 }
 
 static int __exit cx20442_platform_remove(struct platform_device *pdev)
 {
-       struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
-
-       cx20442_unregister(cx20442);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver cx20442_platform_driver = {
        .driver = {
-               .name = "cx20442",
+               .name = "cx20442-codec",
                .owner = THIS_MODULE,
                },
        .probe = cx20442_platform_probe,
@@ -487,4 +412,4 @@ module_exit(cx20442_exit);
 MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
 MODULE_AUTHOR("Janusz Krzysztofik");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cx20442");
+MODULE_ALIAS("platform:cx20442-codec");
index 688a5eb62e17d7ab4dbafa3c28e36f705b9465f5..c7a7c79ef0cd4d242783ccf7050a0ebc65cafacc 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef _CX20442_CODEC_H
 #define _CX20442_CODEC_H
 
-extern struct snd_soc_dai cx20442_dai;
-extern struct snd_soc_codec_device cx20442_codec_dev;
 extern struct tty_ldisc_ops v253_ops;
 
 #endif
index 3c51d6a575237270de5d540bb13a1b93a77829d2..58bb9b994811ac9ea946db98ffa4836266afb510 100644 (file)
@@ -25,8 +25,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "da7210.h"
-
 /* DA7210 register space */
 #define DA7210_STATUS                  0x02
 #define DA7210_STARTUP1                        0x03
@@ -162,11 +160,10 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
 
 /* Codec private data */
 struct da7210_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *da7210_codec;
-
 /*
  * Register cache
  */
@@ -209,12 +206,12 @@ static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
        u8 *cache = codec->reg_cache;
        u8 data[2];
 
-       BUG_ON(codec->volatile_register);
+       BUG_ON(codec->driver->volatile_register);
 
        data[0] = reg & 0xff;
        data[1] = value & 0xff;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EIO;
 
        if (2 != codec->hw_write(codec->control_data, data, 2))
@@ -267,8 +264,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u32 dai_cfg1;
        u32 hpf_reg, hpf_mask, hpf_value;
        u32 fs, bypass;
@@ -430,9 +426,8 @@ static struct snd_soc_dai_ops da7210_dai_ops = {
        .set_fmt        = da7210_set_dai_fmt,
 };
 
-struct snd_soc_dai da7210_dai = {
-       .name = "DA7210 IIS",
-       .id = 0,
+static struct snd_soc_dai_driver da7210_dai = {
+       .name = "da7210-hifi",
        /* playback capabilities */
        .playback = {
                .stream_name = "Playback",
@@ -452,55 +447,15 @@ struct snd_soc_dai da7210_dai = {
        .ops = &da7210_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(da7210_dai);
 
-/*
- * Initialize the DA7210 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int da7210_init(struct da7210_priv *da7210)
+static int da7210_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &da7210->codec;
-       int ret = 0;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
 
-       if (da7210_codec) {
-               dev_err(codec->dev, "Another da7210 is registered\n");
-               return -EINVAL;
-       }
+       dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, da7210);
-       codec->name             = "DA7210";
-       codec->owner            = THIS_MODULE;
-       codec->read             = da7210_read;
-       codec->write            = da7210_write;
-       codec->dai              = &da7210_dai;
-       codec->num_dai          = 1;
+       codec->control_data     = da7210->control_data;
        codec->hw_write         = (hw_write_t)i2c_master_send;
-       codec->reg_cache_size   = ARRAY_SIZE(da7210_reg);
-       codec->reg_cache        = kmemdup(da7210_reg,
-                                         sizeof(da7210_reg), GFP_KERNEL);
-
-       if (!codec->reg_cache)
-               return -ENOMEM;
-
-       da7210_dai.dev = codec->dev;
-       da7210_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
-               goto init_err;
-       }
-
-       ret = snd_soc_register_dai(&da7210_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto codec_err;
-       }
 
        /* FIXME
         *
@@ -583,54 +538,50 @@ static int da7210_init(struct da7210_priv *da7210)
        /* Activate all enabled subsystem */
        da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
-       return ret;
-
-codec_err:
-       snd_soc_unregister_codec(codec);
-init_err:
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
+       snd_soc_add_controls(codec, da7210_snd_controls,
+                            ARRAY_SIZE(da7210_snd_controls));
 
-       return ret;
+       dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+       .probe                  = da7210_probe,
+       .read                   = da7210_read,
+       .write                  = da7210_write,
+       .reg_cache_size         = ARRAY_SIZE(da7210_reg),
+       .reg_word_size          = sizeof(u8),
+       .reg_cache_default      = da7210_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct da7210_priv *da7210;
-       struct snd_soc_codec *codec;
        int ret;
 
        da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
        if (!da7210)
                return -ENOMEM;
 
-       codec = &da7210->codec;
-       codec->dev = &i2c->dev;
-
        i2c_set_clientdata(i2c, da7210);
-       codec->control_data = i2c;
+       da7210->control_data = i2c;
+       da7210->control_type = SND_SOC_I2C;
 
-       ret = da7210_init(da7210);
-       if (ret < 0) {
-               pr_err("Failed to initialise da7210 audio codec\n");
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_da7210, &da7210_dai, 1);
+       if (ret < 0)
                kfree(da7210);
-       }
 
        return ret;
 }
 
 static int __devexit da7210_i2c_remove(struct i2c_client *client)
 {
-       struct da7210_priv *da7210 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_dai(&da7210_dai);
-       kfree(da7210->codec.reg_cache);
-       kfree(da7210);
-       da7210_codec = NULL;
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -643,59 +594,15 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
 /* I2C codec control layer */
 static struct i2c_driver da7210_i2c_driver = {
        .driver = {
-               .name = "DA7210 I2C Codec",
+               .name = "da7210-codec",
                .owner = THIS_MODULE,
        },
-       .probe = da7210_i2c_probe,
-       .remove  __devexit_p(da7210_i2c_remove),
-       .id_table = da7210_i2c_id,
+       .probe          = da7210_i2c_probe,
+       .remove         = __devexit_p(da7210_i2c_remove),
+       .id_table       = da7210_i2c_id,
 };
 #endif
 
-static int da7210_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!da7210_codec) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = da7210_codec;
-       codec = da7210_codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
-       snd_soc_add_controls(da7210_codec, da7210_snd_controls,
-                            ARRAY_SIZE(da7210_snd_controls));
-
-       dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
-
-pcm_err:
-       return ret;
-}
-
-static int da7210_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_da7210 = {
-       .probe =        da7210_probe,
-       .remove =       da7210_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
-
 static int __init da7210_modinit(void)
 {
        int ret = 0;
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
deleted file mode 100644 (file)
index 390d621..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * da7210.h  --  audio driver for da7210
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by 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 as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef _DA7210_H
-#define _DA7210_H
-
-extern struct snd_soc_dai da7210_dai;
-extern struct snd_soc_codec_device soc_codec_dev_da7210;
-
-#endif
-
index 66557de1e4fec533f0e0e1f4ddb8a9294b58c13f..16253ec9b0228e0bf8bd5fce98ba2a7c62436444 100644 (file)
@@ -74,29 +74,22 @@ static const uint32_t jz4740_codec_regs[] = {
 struct jz4740_codec {
        void __iomem *base;
        struct resource *mem;
-
-       uint32_t reg_cache[2];
-       struct snd_soc_codec codec;
 };
 
-static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
-{
-       return container_of(codec, struct jz4740_codec, codec);
-}
-
 static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
-       struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
        return readl(jz4740_codec->base + (reg << 2));
 }
 
 static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
        unsigned int val)
 {
-       struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+       u32 *cache = codec->reg_cache;
 
-       jz4740_codec->reg_cache[reg] = val;
+       cache[reg] = val;
        writel(val, jz4740_codec->base + (reg << 2));
 
        return 0;
@@ -172,8 +165,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
 {
        uint32_t val;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
 
        switch (params_rate(params)) {
        case 8000:
@@ -219,8 +211,8 @@ static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
        .hw_params = jz4740_codec_hw_params,
 };
 
-struct snd_soc_dai jz4740_codec_dai = {
-       .name = "jz4740",
+static struct snd_soc_dai_driver jz4740_codec_dai = {
+       .name = "jz4740-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -238,7 +230,6 @@ struct snd_soc_dai jz4740_codec_dai = {
        .ops = &jz4740_codec_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(jz4740_codec_dai);
 
 static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
 {
@@ -302,23 +293,10 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static struct snd_soc_codec *jz4740_codec_codec;
-
-static int jz4740_codec_dev_probe(struct platform_device *pdev)
+static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = jz4740_codec_codec;
-
-       BUG_ON(!codec);
-
-       socdev->card->codec = codec;
-
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
-               return ret;
-       }
+       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+                       JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
        snd_soc_add_controls(codec, jz4740_codec_controls,
                ARRAY_SIZE(jz4740_codec_controls));
@@ -331,34 +309,27 @@ static int jz4740_codec_dev_probe(struct platform_device *pdev)
 
        snd_soc_dapm_new_widgets(codec);
 
+       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        return 0;
 }
 
-static int jz4740_codec_dev_remove(struct platform_device *pdev)
+static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
 
-static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int jz4740_codec_resume(struct platform_device *pdev)
+static int jz4740_codec_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 }
 
@@ -367,19 +338,23 @@ static int jz4740_codec_resume(struct platform_device *pdev)
 #define jz4740_codec_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .probe = jz4740_codec_dev_probe,
        .remove = jz4740_codec_dev_remove,
        .suspend = jz4740_codec_suspend,
        .resume = jz4740_codec_resume,
+       .read = jz4740_codec_read,
+       .write = jz4740_codec_write,
+       .set_bias_level = jz4740_codec_set_bias_level,
+       .reg_cache_default      = jz4740_codec_regs,
+       .reg_word_size = sizeof(u32),
+       .reg_cache_size = 2,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
 
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_codec *jz4740_codec;
-       struct snd_soc_codec *codec;
        struct resource *mem;
 
        jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
@@ -408,55 +383,17 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
        }
        jz4740_codec->mem = mem;
 
-       jz4740_codec_dai.dev = &pdev->dev;
-
-       codec = &jz4740_codec->codec;
-
-       codec->dev              = &pdev->dev;
-       codec->name             = "jz4740";
-       codec->owner            = THIS_MODULE;
-
-       codec->read             = jz4740_codec_read;
-       codec->write            = jz4740_codec_write;
-       codec->set_bias_level   = jz4740_codec_set_bias_level;
-       codec->bias_level       = SND_SOC_BIAS_OFF;
-
-       codec->dai              = &jz4740_codec_dai;
-       codec->num_dai          = 1;
-
-       codec->reg_cache        = jz4740_codec->reg_cache;
-       codec->reg_cache_size   = 2;
-       memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       jz4740_codec_codec = codec;
-
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
-                       JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
-
        platform_set_drvdata(pdev, jz4740_codec);
 
-       ret = snd_soc_register_codec(codec);
+       ret = snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Failed to register codec\n");
                goto err_iounmap;
        }
 
-       ret = snd_soc_register_dai(&jz4740_codec_dai);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to register codec dai\n");
-               goto err_unregister_codec;
-       }
-
-       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 
-err_unregister_codec:
-       snd_soc_unregister_codec(codec);
 err_iounmap:
        iounmap(jz4740_codec->base);
 err_release_mem_region:
@@ -472,8 +409,7 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev)
        struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
        struct resource *mem = jz4740_codec->mem;
 
-       snd_soc_unregister_dai(&jz4740_codec_dai);
-       snd_soc_unregister_codec(&jz4740_codec->codec);
+       snd_soc_unregister_codec(&pdev->dev);
 
        iounmap(jz4740_codec->base);
        release_mem_region(mem->start, resource_size(mem));
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
deleted file mode 100644 (file)
index b5a0691..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.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.
- *
- *  You 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 __SND_SOC_CODECS_JZ4740_CODEC_H__
-#define __SND_SOC_CODECS_JZ4740_CODEC_H__
-
-extern struct snd_soc_dai jz4740_codec_dai;
-extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
-
-#endif
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644 (file)
index 0000000..e7a40d1
--- /dev/null
@@ -0,0 +1,2097 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+struct max98088_cdata {
+       unsigned int rate;
+       unsigned int fmt;
+       int eq_sel;
+};
+
+struct max98088_priv {
+       u8 reg_cache[M98088_REG_CNT];
+       void *control_data;
+       struct max98088_pdata *pdata;
+       unsigned int sysclk;
+       struct max98088_cdata dai[2];
+       int eq_textcnt;
+       const char **eq_texts;
+       struct soc_enum eq_enum;
+       u8 ina_state;
+       u8 inb_state;
+       unsigned int ex_mode;
+       unsigned int digmic;
+       unsigned int mic1pre;
+       unsigned int mic2pre;
+       unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+       0x00, /* 00 IRQ status */
+       0x00, /* 01 MIC status */
+       0x00, /* 02 jack status */
+       0x00, /* 03 battery voltage */
+       0x00, /* 04 */
+       0x00, /* 05 */
+       0x00, /* 06 */
+       0x00, /* 07 */
+       0x00, /* 08 */
+       0x00, /* 09 */
+       0x00, /* 0A */
+       0x00, /* 0B */
+       0x00, /* 0C */
+       0x00, /* 0D */
+       0x00, /* 0E */
+       0x00, /* 0F interrupt enable */
+
+       0x00, /* 10 master clock */
+       0x00, /* 11 DAI1 clock mode */
+       0x00, /* 12 DAI1 clock control */
+       0x00, /* 13 DAI1 clock control */
+       0x00, /* 14 DAI1 format */
+       0x00, /* 15 DAI1 clock */
+       0x00, /* 16 DAI1 config */
+       0x00, /* 17 DAI1 TDM */
+       0x00, /* 18 DAI1 filters */
+       0x00, /* 19 DAI2 clock mode */
+       0x00, /* 1A DAI2 clock control */
+       0x00, /* 1B DAI2 clock control */
+       0x00, /* 1C DAI2 format */
+       0x00, /* 1D DAI2 clock */
+       0x00, /* 1E DAI2 config */
+       0x00, /* 1F DAI2 TDM */
+
+       0x00, /* 20 DAI2 filters */
+       0x00, /* 21 data config */
+       0x00, /* 22 DAC mixer */
+       0x00, /* 23 left ADC mixer */
+       0x00, /* 24 right ADC mixer */
+       0x00, /* 25 left HP mixer */
+       0x00, /* 26 right HP mixer */
+       0x00, /* 27 HP control */
+       0x00, /* 28 left REC mixer */
+       0x00, /* 29 right REC mixer */
+       0x00, /* 2A REC control */
+       0x00, /* 2B left SPK mixer */
+       0x00, /* 2C right SPK mixer */
+       0x00, /* 2D SPK control */
+       0x00, /* 2E sidetone */
+       0x00, /* 2F DAI1 playback level */
+
+       0x00, /* 30 DAI1 playback level */
+       0x00, /* 31 DAI2 playback level */
+       0x00, /* 32 DAI2 playbakc level */
+       0x00, /* 33 left ADC level */
+       0x00, /* 34 right ADC level */
+       0x00, /* 35 MIC1 level */
+       0x00, /* 36 MIC2 level */
+       0x00, /* 37 INA level */
+       0x00, /* 38 INB level */
+       0x00, /* 39 left HP volume */
+       0x00, /* 3A right HP volume */
+       0x00, /* 3B left REC volume */
+       0x00, /* 3C right REC volume */
+       0x00, /* 3D left SPK volume */
+       0x00, /* 3E right SPK volume */
+       0x00, /* 3F MIC config */
+
+       0x00, /* 40 MIC threshold */
+       0x00, /* 41 excursion limiter filter */
+       0x00, /* 42 excursion limiter threshold */
+       0x00, /* 43 ALC */
+       0x00, /* 44 power limiter threshold */
+       0x00, /* 45 power limiter config */
+       0x00, /* 46 distortion limiter config */
+       0x00, /* 47 audio input */
+       0x00, /* 48 microphone */
+       0x00, /* 49 level control */
+       0x00, /* 4A bypass switches */
+       0x00, /* 4B jack detect */
+       0x00, /* 4C input enable */
+       0x00, /* 4D output enable */
+       0xF0, /* 4E bias control */
+       0x00, /* 4F DAC power */
+
+       0x0F, /* 50 DAC power */
+       0x00, /* 51 system */
+       0x00, /* 52 DAI1 EQ1 */
+       0x00, /* 53 DAI1 EQ1 */
+       0x00, /* 54 DAI1 EQ1 */
+       0x00, /* 55 DAI1 EQ1 */
+       0x00, /* 56 DAI1 EQ1 */
+       0x00, /* 57 DAI1 EQ1 */
+       0x00, /* 58 DAI1 EQ1 */
+       0x00, /* 59 DAI1 EQ1 */
+       0x00, /* 5A DAI1 EQ1 */
+       0x00, /* 5B DAI1 EQ1 */
+       0x00, /* 5C DAI1 EQ2 */
+       0x00, /* 5D DAI1 EQ2 */
+       0x00, /* 5E DAI1 EQ2 */
+       0x00, /* 5F DAI1 EQ2 */
+
+       0x00, /* 60 DAI1 EQ2 */
+       0x00, /* 61 DAI1 EQ2 */
+       0x00, /* 62 DAI1 EQ2 */
+       0x00, /* 63 DAI1 EQ2 */
+       0x00, /* 64 DAI1 EQ2 */
+       0x00, /* 65 DAI1 EQ2 */
+       0x00, /* 66 DAI1 EQ3 */
+       0x00, /* 67 DAI1 EQ3 */
+       0x00, /* 68 DAI1 EQ3 */
+       0x00, /* 69 DAI1 EQ3 */
+       0x00, /* 6A DAI1 EQ3 */
+       0x00, /* 6B DAI1 EQ3 */
+       0x00, /* 6C DAI1 EQ3 */
+       0x00, /* 6D DAI1 EQ3 */
+       0x00, /* 6E DAI1 EQ3 */
+       0x00, /* 6F DAI1 EQ3 */
+
+       0x00, /* 70 DAI1 EQ4 */
+       0x00, /* 71 DAI1 EQ4 */
+       0x00, /* 72 DAI1 EQ4 */
+       0x00, /* 73 DAI1 EQ4 */
+       0x00, /* 74 DAI1 EQ4 */
+       0x00, /* 75 DAI1 EQ4 */
+       0x00, /* 76 DAI1 EQ4 */
+       0x00, /* 77 DAI1 EQ4 */
+       0x00, /* 78 DAI1 EQ4 */
+       0x00, /* 79 DAI1 EQ4 */
+       0x00, /* 7A DAI1 EQ5 */
+       0x00, /* 7B DAI1 EQ5 */
+       0x00, /* 7C DAI1 EQ5 */
+       0x00, /* 7D DAI1 EQ5 */
+       0x00, /* 7E DAI1 EQ5 */
+       0x00, /* 7F DAI1 EQ5 */
+
+       0x00, /* 80 DAI1 EQ5 */
+       0x00, /* 81 DAI1 EQ5 */
+       0x00, /* 82 DAI1 EQ5 */
+       0x00, /* 83 DAI1 EQ5 */
+       0x00, /* 84 DAI2 EQ1 */
+       0x00, /* 85 DAI2 EQ1 */
+       0x00, /* 86 DAI2 EQ1 */
+       0x00, /* 87 DAI2 EQ1 */
+       0x00, /* 88 DAI2 EQ1 */
+       0x00, /* 89 DAI2 EQ1 */
+       0x00, /* 8A DAI2 EQ1 */
+       0x00, /* 8B DAI2 EQ1 */
+       0x00, /* 8C DAI2 EQ1 */
+       0x00, /* 8D DAI2 EQ1 */
+       0x00, /* 8E DAI2 EQ2 */
+       0x00, /* 8F DAI2 EQ2 */
+
+       0x00, /* 90 DAI2 EQ2 */
+       0x00, /* 91 DAI2 EQ2 */
+       0x00, /* 92 DAI2 EQ2 */
+       0x00, /* 93 DAI2 EQ2 */
+       0x00, /* 94 DAI2 EQ2 */
+       0x00, /* 95 DAI2 EQ2 */
+       0x00, /* 96 DAI2 EQ2 */
+       0x00, /* 97 DAI2 EQ2 */
+       0x00, /* 98 DAI2 EQ3 */
+       0x00, /* 99 DAI2 EQ3 */
+       0x00, /* 9A DAI2 EQ3 */
+       0x00, /* 9B DAI2 EQ3 */
+       0x00, /* 9C DAI2 EQ3 */
+       0x00, /* 9D DAI2 EQ3 */
+       0x00, /* 9E DAI2 EQ3 */
+       0x00, /* 9F DAI2 EQ3 */
+
+       0x00, /* A0 DAI2 EQ3 */
+       0x00, /* A1 DAI2 EQ3 */
+       0x00, /* A2 DAI2 EQ4 */
+       0x00, /* A3 DAI2 EQ4 */
+       0x00, /* A4 DAI2 EQ4 */
+       0x00, /* A5 DAI2 EQ4 */
+       0x00, /* A6 DAI2 EQ4 */
+       0x00, /* A7 DAI2 EQ4 */
+       0x00, /* A8 DAI2 EQ4 */
+       0x00, /* A9 DAI2 EQ4 */
+       0x00, /* AA DAI2 EQ4 */
+       0x00, /* AB DAI2 EQ4 */
+       0x00, /* AC DAI2 EQ5 */
+       0x00, /* AD DAI2 EQ5 */
+       0x00, /* AE DAI2 EQ5 */
+       0x00, /* AF DAI2 EQ5 */
+
+       0x00, /* B0 DAI2 EQ5 */
+       0x00, /* B1 DAI2 EQ5 */
+       0x00, /* B2 DAI2 EQ5 */
+       0x00, /* B3 DAI2 EQ5 */
+       0x00, /* B4 DAI2 EQ5 */
+       0x00, /* B5 DAI2 EQ5 */
+       0x00, /* B6 DAI1 biquad */
+       0x00, /* B7 DAI1 biquad */
+       0x00, /* B8 DAI1 biquad */
+       0x00, /* B9 DAI1 biquad */
+       0x00, /* BA DAI1 biquad */
+       0x00, /* BB DAI1 biquad */
+       0x00, /* BC DAI1 biquad */
+       0x00, /* BD DAI1 biquad */
+       0x00, /* BE DAI1 biquad */
+       0x00, /* BF DAI1 biquad */
+
+       0x00, /* C0 DAI2 biquad */
+       0x00, /* C1 DAI2 biquad */
+       0x00, /* C2 DAI2 biquad */
+       0x00, /* C3 DAI2 biquad */
+       0x00, /* C4 DAI2 biquad */
+       0x00, /* C5 DAI2 biquad */
+       0x00, /* C6 DAI2 biquad */
+       0x00, /* C7 DAI2 biquad */
+       0x00, /* C8 DAI2 biquad */
+       0x00, /* C9 DAI2 biquad */
+       0x00, /* CA */
+       0x00, /* CB */
+       0x00, /* CC */
+       0x00, /* CD */
+       0x00, /* CE */
+       0x00, /* CF */
+
+       0x00, /* D0 */
+       0x00, /* D1 */
+       0x00, /* D2 */
+       0x00, /* D3 */
+       0x00, /* D4 */
+       0x00, /* D5 */
+       0x00, /* D6 */
+       0x00, /* D7 */
+       0x00, /* D8 */
+       0x00, /* D9 */
+       0x00, /* DA */
+       0x70, /* DB */
+       0x00, /* DC */
+       0x00, /* DD */
+       0x00, /* DE */
+       0x00, /* DF */
+
+       0x00, /* E0 */
+       0x00, /* E1 */
+       0x00, /* E2 */
+       0x00, /* E3 */
+       0x00, /* E4 */
+       0x00, /* E5 */
+       0x00, /* E6 */
+       0x00, /* E7 */
+       0x00, /* E8 */
+       0x00, /* E9 */
+       0x00, /* EA */
+       0x00, /* EB */
+       0x00, /* EC */
+       0x00, /* ED */
+       0x00, /* EE */
+       0x00, /* EF */
+
+       0x00, /* F0 */
+       0x00, /* F1 */
+       0x00, /* F2 */
+       0x00, /* F3 */
+       0x00, /* F4 */
+       0x00, /* F5 */
+       0x00, /* F6 */
+       0x00, /* F7 */
+       0x00, /* F8 */
+       0x00, /* F9 */
+       0x00, /* FA */
+       0x00, /* FB */
+       0x00, /* FC */
+       0x00, /* FD */
+       0x00, /* FE */
+       0x00, /* FF */
+};
+
+static struct {
+       int readable;
+       int writable;
+       int vol;
+} max98088_access[M98088_REG_CNT] = {
+       { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+       { 0xFF, 0x00, 1 }, /* 01 MIC status */
+       { 0xFF, 0x00, 1 }, /* 02 jack status */
+       { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+       { 0xFF, 0xFF, 0 }, /* 04 */
+       { 0xFF, 0xFF, 0 }, /* 05 */
+       { 0xFF, 0xFF, 0 }, /* 06 */
+       { 0xFF, 0xFF, 0 }, /* 07 */
+       { 0xFF, 0xFF, 0 }, /* 08 */
+       { 0xFF, 0xFF, 0 }, /* 09 */
+       { 0xFF, 0xFF, 0 }, /* 0A */
+       { 0xFF, 0xFF, 0 }, /* 0B */
+       { 0xFF, 0xFF, 0 }, /* 0C */
+       { 0xFF, 0xFF, 0 }, /* 0D */
+       { 0xFF, 0xFF, 0 }, /* 0E */
+       { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+       { 0xFF, 0xFF, 0 }, /* 10 master clock */
+       { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+       { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+       { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+       { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+       { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+       { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+       { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+       { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+       { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+       { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+       { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+       { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+       { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+       { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+       { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+       { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+       { 0xFF, 0xFF, 0 }, /* 21 data config */
+       { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+       { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+       { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+       { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+       { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+       { 0xFF, 0xFF, 0 }, /* 27 HP control */
+       { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+       { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+       { 0xFF, 0xFF, 0 }, /* 2A REC control */
+       { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+       { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+       { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+       { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+       { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+       { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+       { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+       { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+       { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+       { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+       { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+       { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+       { 0xFF, 0xFF, 0 }, /* 37 INA level */
+       { 0xFF, 0xFF, 0 }, /* 38 INB level */
+       { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+       { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+       { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+       { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+       { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+       { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+       { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+       { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+       { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+       { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+       { 0xFF, 0xFF, 0 }, /* 43 ALC */
+       { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+       { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+       { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+       { 0xFF, 0xFF, 0 }, /* 47 audio input */
+       { 0xFF, 0xFF, 0 }, /* 48 microphone */
+       { 0xFF, 0xFF, 0 }, /* 49 level control */
+       { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+       { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+       { 0xFF, 0xFF, 0 }, /* 4C input enable */
+       { 0xFF, 0xFF, 0 }, /* 4D output enable */
+       { 0xFF, 0xFF, 0 }, /* 4E bias control */
+       { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+       { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+       { 0xFF, 0xFF, 0 }, /* 51 system */
+       { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+       { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+       { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+       { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+       { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+       { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+       { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+       { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+       { 0x00, 0x00, 0 }, /* CA */
+       { 0x00, 0x00, 0 }, /* CB */
+       { 0x00, 0x00, 0 }, /* CC */
+       { 0x00, 0x00, 0 }, /* CD */
+       { 0x00, 0x00, 0 }, /* CE */
+       { 0x00, 0x00, 0 }, /* CF */
+
+       { 0x00, 0x00, 0 }, /* D0 */
+       { 0x00, 0x00, 0 }, /* D1 */
+       { 0x00, 0x00, 0 }, /* D2 */
+       { 0x00, 0x00, 0 }, /* D3 */
+       { 0x00, 0x00, 0 }, /* D4 */
+       { 0x00, 0x00, 0 }, /* D5 */
+       { 0x00, 0x00, 0 }, /* D6 */
+       { 0x00, 0x00, 0 }, /* D7 */
+       { 0x00, 0x00, 0 }, /* D8 */
+       { 0x00, 0x00, 0 }, /* D9 */
+       { 0x00, 0x00, 0 }, /* DA */
+       { 0x00, 0x00, 0 }, /* DB */
+       { 0x00, 0x00, 0 }, /* DC */
+       { 0x00, 0x00, 0 }, /* DD */
+       { 0x00, 0x00, 0 }, /* DE */
+       { 0x00, 0x00, 0 }, /* DF */
+
+       { 0x00, 0x00, 0 }, /* E0 */
+       { 0x00, 0x00, 0 }, /* E1 */
+       { 0x00, 0x00, 0 }, /* E2 */
+       { 0x00, 0x00, 0 }, /* E3 */
+       { 0x00, 0x00, 0 }, /* E4 */
+       { 0x00, 0x00, 0 }, /* E5 */
+       { 0x00, 0x00, 0 }, /* E6 */
+       { 0x00, 0x00, 0 }, /* E7 */
+       { 0x00, 0x00, 0 }, /* E8 */
+       { 0x00, 0x00, 0 }, /* E9 */
+       { 0x00, 0x00, 0 }, /* EA */
+       { 0x00, 0x00, 0 }, /* EB */
+       { 0x00, 0x00, 0 }, /* EC */
+       { 0x00, 0x00, 0 }, /* ED */
+       { 0x00, 0x00, 0 }, /* EE */
+       { 0x00, 0x00, 0 }, /* EF */
+
+       { 0x00, 0x00, 0 }, /* F0 */
+       { 0x00, 0x00, 0 }, /* F1 */
+       { 0x00, 0x00, 0 }, /* F2 */
+       { 0x00, 0x00, 0 }, /* F3 */
+       { 0x00, 0x00, 0 }, /* F4 */
+       { 0x00, 0x00, 0 }, /* F5 */
+       { 0x00, 0x00, 0 }, /* F6 */
+       { 0x00, 0x00, 0 }, /* F7 */
+       { 0x00, 0x00, 0 }, /* F8 */
+       { 0x00, 0x00, 0 }, /* F9 */
+       { 0x00, 0x00, 0 }, /* FA */
+       { 0x00, 0x00, 0 }, /* FB */
+       { 0x00, 0x00, 0 }, /* FC */
+       { 0x00, 0x00, 0 }, /* FD */
+       { 0x00, 0x00, 0 }, /* FE */
+       { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+       return max98088_access[reg].vol;
+}
+
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+                   unsigned int band, u16 *coefs)
+{
+       unsigned int eq_reg;
+       unsigned int i;
+
+       BUG_ON(band > 4);
+       BUG_ON(dai > 1);
+
+       /* Load the base register address */
+       eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+       /* Add the band address offset, note adjustment for word address */
+       eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+       /* Step through the registers and coefs */
+       for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+               snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+               snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+       }
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_exmode_texts[] = {
+       "Off", "100Hz", "400Hz", "600Hz", "800Hz", "1000Hz", "200-400Hz",
+       "400-600Hz", "400-800Hz",
+};
+
+static const unsigned int max98088_exmode_values[] = {
+       0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
+};
+
+static const struct soc_enum max98088_exmode_enum =
+       SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
+                             ARRAY_SIZE(max98088_exmode_texts),
+                             max98088_exmode_texts,
+                             max98088_exmode_values);
+static const struct snd_kcontrol_new max98088_exmode_controls =
+       SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+       "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+               max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98088_extmic_enum =
+       SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+
+static const struct snd_kcontrol_new max98088_extmic_mux =
+       SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
+
+static const char *max98088_dai1_fltr[] = {
+       "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+       "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic1pre = sel;
+       snd_soc_update_bits(codec, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98088->mic1pre;
+       return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic2pre = sel;
+       snd_soc_update_bits(codec, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98088->mic2pre;
+       return 0;
+}
+
+static const unsigned int max98088_micboost_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+       SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+               M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+       SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+               M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+       SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+               M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+       SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+               M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+       SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+               M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+       SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+               M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+       SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+       SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+       SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+                       M98088_REG_35_LVL_MIC1, 5, 2, 0,
+                       max98088_mic1pre_get, max98088_mic1pre_set,
+                       max98088_micboost_tlv),
+       SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+                       M98088_REG_36_LVL_MIC2, 5, 2, 0,
+                       max98088_mic2pre_get, max98088_mic2pre_set,
+                       max98088_micboost_tlv),
+
+       SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+       SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+       SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+       SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+       SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+       SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+       SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+       SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+       SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+       SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+       SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+       SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+       SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+               0, 1, 0),
+
+       SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+       SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+       SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+       SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+       SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+               4, 15, 0),
+       SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+       SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+       SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+       SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+       SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (w->reg == M98088_REG_35_LVL_MIC1) {
+                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+               } else {
+                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * The line inputs are 2-channel stereo inputs with the left
+ * and right channels sharing a common PGA power control signal.
+ */
+static int max98088_line_pga(struct snd_soc_dapm_widget *w,
+                            int event, int line, u8 channel)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       u8 *state;
+
+       BUG_ON(!((channel == 1) || (channel == 2)));
+
+       switch (line) {
+       case LINE_INA:
+               state = &max98088->ina_state;
+               break;
+       case LINE_INB:
+               state = &max98088->inb_state;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               *state |= channel;
+               snd_soc_update_bits(codec, w->reg,
+                       (1 << w->shift), (1 << w->shift));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               *state &= ~channel;
+               if (*state == 0) {
+                       snd_soc_update_bits(codec, w->reg,
+                               (1 << w->shift), 0);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int max98088_pga_ina1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 1);
+}
+
+static int max98088_pga_ina2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 2);
+}
+
+static int max98088_pga_inb1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 1);
+}
+
+static int max98088_pga_inb2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 2);
+}
+
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+       SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+       SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+       SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+       SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+       SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+               7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+               6, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+               5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+               4, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+               3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+               2, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+               &max98088_extmic_mux),
+
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_left_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_right_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+       SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
+               &max98088_exmode_controls),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("RECL"),
+       SND_SOC_DAPM_OUTPUT("RECR"),
+
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("INA1"),
+       SND_SOC_DAPM_INPUT("INA2"),
+       SND_SOC_DAPM_INPUT("INB1"),
+       SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Left headphone output mixer */
+       {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right headphone output mixer */
+       {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right HP Mixer", "Left DAC2 Switch", "DACL2"  },
+       {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Left speaker output mixer */
+       {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right speaker output mixer */
+       {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       {"HP Left Out", NULL, "Left HP Mixer"},
+       {"HP Right Out", NULL, "Right HP Mixer"},
+       {"SPK Left Out", NULL, "Left SPK Mixer"},
+       {"SPK Right Out", NULL, "Right SPK Mixer"},
+       {"REC Left Out", NULL, "Left REC Mixer"},
+       {"REC Right Out", NULL, "Right REC Mixer"},
+
+       {"HPL", NULL, "HP Left Out"},
+       {"HPR", NULL, "HP Right Out"},
+       {"SPKL", NULL, "SPK Left Out"},
+       {"SPKR", NULL, "SPK Right Out"},
+       {"RECL", NULL, "REC Left Out"},
+       {"RECR", NULL, "REC Right Out"},
+
+       /* Left ADC input mixer */
+       {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right ADC input mixer */
+       {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Inputs */
+       {"ADCL", NULL, "Left ADC Mixer"},
+       {"ADCR", NULL, "Right ADC Mixer"},
+       {"INA1 Input", NULL, "INA1"},
+       {"INA2 Input", NULL, "INA2"},
+       {"INB1 Input", NULL, "INB1"},
+       {"INB2 Input", NULL, "INB2"},
+       {"MIC1 Input", NULL, "MIC1"},
+       {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+                                 ARRAY_SIZE(max98088_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_add_controls(codec, max98088_snd_controls,
+                            ARRAY_SIZE(max98088_snd_controls));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+       u32 rate;
+       u8  sr;
+} rate_table[] = {
+       {8000,  0x10},
+       {11025, 0x20},
+       {16000, 0x30},
+       {22050, 0x40},
+       {24000, 0x50},
+       {32000, 0x60},
+       {44100, 0x70},
+       {48000, 0x80},
+       {88200, 0x90},
+       {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+               if (rate_table[i].rate >= rate) {
+                       *value = rate_table[i].sr;
+                       return 0;
+               }
+       }
+       *value = rate_table[0].sr;
+       return -EINVAL;
+}
+
+static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[0];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98088_REG_11_DAI1_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[1];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98088_REG_19_DAI2_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       /* Requested clock frequency is already setup */
+       if (freq == max98088->sysclk)
+               return 0;
+
+       max98088->sysclk = freq; /* remember current sysclk */
+
+       /* Setup clocks for slave mode, and using the PLL
+        * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+        *         0x02 (when master clk is 20MHz to 30MHz)..
+        */
+       if ((freq >= 10000000) && (freq < 20000000)) {
+               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+       } else if ((freq >= 20000000) && (freq < 30000000)) {
+               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+       } else {
+               dev_err(codec->dev, "Invalid master clock frequency\n");
+               return -EINVAL;
+       }
+
+       if (snd_soc_read(codec, M98088_REG_51_PWR_SYS)  & M98088_SHDNRUN) {
+               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, 0);
+               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, M98088_SHDNRUN);
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       max98088->sysclk = freq;
+       return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       u8 reg15val;
+       u8 reg14val = 0;
+
+       cdata = &max98088->dai[0];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg14val |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg14val |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg14val |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg14val |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg14val);
+
+               reg15val = M98088_DAI_BSEL64;
+               if (max98088->digmic)
+                       reg15val |= M98088_DAI_OSR64;
+               snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+       }
+
+       return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       u8 reg1Cval = 0;
+
+       cdata = &max98088->dai[1];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg1Cval |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg1Cval |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg1Cval |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg1Cval |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg1Cval);
+
+               snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+                       M98088_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       codec->cache_only = 0;
+
+       /* write back cached values if they're writeable and
+        * different from the hardware default.
+        */
+       for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+               if (!max98088_access[i].writable)
+                       continue;
+
+               if (max98088->reg_cache[i] == max98088_reg[i])
+                       continue;
+
+               snd_soc_write(codec, i, max98088->reg_cache[i]);
+       }
+
+       codec->cache_sync = 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_codec *codec,
+                                  enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF)
+                       max98088_sync_cache(codec);
+
+               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+                               M98088_MBEN, M98088_MBEN);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+                               M98088_MBEN, 0);
+               codec->cache_sync = 1;
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai1_set_fmt,
+       .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai2_set_fmt,
+       .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+       .name = "HiFi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+        .ops = &max98088_dai1_ops,
+},
+{
+       .name = "Aux",
+       .playback = {
+               .stream_name = "Aux Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .ops = &max98088_dai2_ops,
+}
+};
+
+static int max98088_get_channel(const char *name)
+{
+       if (strcmp(name, "EQ1 Mode") == 0)
+               return 0;
+       if (strcmp(name, "EQ2 Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[0];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+       sel = cdata->eq_sel;
+
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(codec, 0, 0, coef_set->band1);
+       m98088_eq_band(codec, 0, 1, coef_set->band2);
+       m98088_eq_band(codec, 0, 2, coef_set->band3);
+       m98088_eq_band(codec, 0, 3, coef_set->band4);
+       m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[1];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+
+       sel = cdata->eq_sel;
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(codec, 1, 0, coef_set->band1);
+       m98088_eq_band(codec, 1, 1, coef_set->band2);
+       m98088_eq_band(codec, 1, 2, coef_set->band3);
+       m98088_eq_band(codec, 1, 3, coef_set->band4);
+       m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+               save);
+}
+
+static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       int channel = max98088_get_channel(kcontrol->id.name);
+       struct max98088_cdata *cdata;
+       int sel = ucontrol->value.integer.value[0];
+
+       cdata = &max98088->dai[channel];
+
+       if (sel >= pdata->eq_cfgcnt)
+               return -EINVAL;
+
+       cdata->eq_sel = sel;
+
+       switch (channel) {
+       case 0:
+               max98088_setup_eq1(codec);
+               break;
+       case 1:
+               max98088_setup_eq2(codec);
+               break;
+       }
+
+       return 0;
+}
+
+static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       int channel = max98088_get_channel(kcontrol->id.name);
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[channel];
+       ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+       return 0;
+}
+
+static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *cfg;
+       unsigned int cfgcnt;
+       int i, j;
+       const char **t;
+       int ret;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("EQ1 Mode",
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+               SOC_ENUM_EXT("EQ2 Mode",
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+       };
+
+       cfg = pdata->eq_cfg;
+       cfgcnt = pdata->eq_cfgcnt;
+
+       /* Setup an array of texts for the equalizer enum.
+        * This is based on Mark Brown's equalizer driver code.
+        */
+       max98088->eq_textcnt = 0;
+       max98088->eq_texts = NULL;
+       for (i = 0; i < cfgcnt; i++) {
+               for (j = 0; j < max98088->eq_textcnt; j++) {
+                       if (strcmp(cfg[i].name, max98088->eq_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != max98088->eq_textcnt)
+                       continue;
+
+               /* Expand the array */
+               t = krealloc(max98088->eq_texts,
+                            sizeof(char *) * (max98088->eq_textcnt + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* Store the new entry */
+               t[max98088->eq_textcnt] = cfg[i].name;
+               max98088->eq_textcnt++;
+               max98088->eq_texts = t;
+       }
+
+       /* Now point the soc_enum to .texts array items */
+       max98088->eq_enum.texts = max98088->eq_texts;
+       max98088->eq_enum.max = max98088->eq_textcnt;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       u8 regval = 0;
+
+       if (!pdata) {
+               dev_dbg(codec->dev, "No platform data\n");
+               return;
+       }
+
+       /* Configure mic for analog/digital mic mode */
+       if (pdata->digmic_left_mode)
+               regval |= M98088_DIGMIC_L;
+
+       if (pdata->digmic_right_mode)
+               regval |= M98088_DIGMIC_R;
+
+       max98088->digmic = (regval ? 1 : 0);
+
+       snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+       /* Configure receiver output */
+       regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+       snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+               M98088_REC_LINEMODE_MASK, regval);
+
+       /* Configure equalizers */
+       if (pdata->eq_cfgcnt)
+               max98088_handle_eq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       int ret = 0;
+
+       codec->cache_sync = 1;
+       memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* initalize private data */
+
+       max98088->sysclk = (unsigned)-1;
+       max98088->eq_textcnt = 0;
+
+       cdata = &max98088->dai[0];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       cdata = &max98088->dai[1];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       max98088->ina_state = 0;
+       max98088->inb_state = 0;
+       max98088->ex_mode = 0;
+       max98088->digmic = 0;
+       max98088->mic1pre = 0;
+       max98088->mic2pre = 0;
+
+       ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_access;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+       /* initialize registers cache to hardware default */
+       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+       snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+               M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+               M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+       snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+       snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+       snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+               M98088_S1NORMAL|M98088_SDATA);
+
+       snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+               M98088_S2NORMAL|M98088_SDATA);
+
+       max98088_handle_pdata(codec);
+
+       max98088_add_widgets(codec);
+
+err_access:
+       return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+       .probe   = max98088_probe,
+       .remove  = max98088_remove,
+       .suspend = max98088_suspend,
+       .resume  = max98088_resume,
+       .set_bias_level = max98088_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(max98088_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = max98088_reg,
+       .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct max98088_priv *max98088;
+       int ret;
+
+       max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+       if (max98088 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, max98088);
+       max98088->control_data = i2c;
+       max98088->pdata = i2c->dev.platform_data;
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_max98088, &max98088_dai[0], 2);
+       if (ret < 0)
+               kfree(max98088);
+       return ret;
+}
+
+static int max98088_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+       { "max98088", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+       .driver = {
+               .name = "max98088",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max98088_i2c_probe,
+       .remove = __devexit_p(max98088_i2c_remove),
+       .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&max98088_i2c_driver);
+       if (ret)
+               pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(max98088_init);
+
+static void __exit max98088_exit(void)
+{
+       i2c_del_driver(&max98088_i2c_driver);
+}
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644 (file)
index 0000000..56554c7
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can 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 _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS            0x00
+#define M98088_REG_01_MIC_STATUS            0x01
+#define M98088_REG_02_JACK_STAUS            0x02
+#define M98088_REG_03_BATTERY_VOLTAGE       0x03
+#define M98088_REG_0F_IRQ_ENABLE            0x0F
+#define M98088_REG_10_SYS_CLK               0x10
+#define M98088_REG_11_DAI1_CLKMODE          0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI        0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO        0x13
+#define M98088_REG_14_DAI1_FORMAT           0x14
+#define M98088_REG_15_DAI1_CLOCK            0x15
+#define M98088_REG_16_DAI1_IOCFG            0x16
+#define M98088_REG_17_DAI1_TDM              0x17
+#define M98088_REG_18_DAI1_FILTERS          0x18
+#define M98088_REG_19_DAI2_CLKMODE          0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI        0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO        0x1B
+#define M98088_REG_1C_DAI2_FORMAT           0x1C
+#define M98088_REG_1D_DAI2_CLOCK            0x1D
+#define M98088_REG_1E_DAI2_IOCFG            0x1E
+#define M98088_REG_1F_DAI2_TDM              0x1F
+#define M98088_REG_20_DAI2_FILTERS          0x20
+#define M98088_REG_21_SRC                   0x21
+#define M98088_REG_22_MIX_DAC               0x22
+#define M98088_REG_23_MIX_ADC_LEFT          0x23
+#define M98088_REG_24_MIX_ADC_RIGHT         0x24
+#define M98088_REG_25_MIX_HP_LEFT           0x25
+#define M98088_REG_26_MIX_HP_RIGHT          0x26
+#define M98088_REG_27_MIX_HP_CNTL           0x27
+#define M98088_REG_28_MIX_REC_LEFT          0x28
+#define M98088_REG_29_MIX_REC_RIGHT         0x29
+#define M98088_REG_2A_MIC_REC_CNTL          0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT          0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT         0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL          0x2D
+#define M98088_REG_2E_LVL_SIDETONE          0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY         0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ      0x30
+#define M98088_REG_31_LVL_DAI2_PLAY         0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ      0x32
+#define M98088_REG_33_LVL_ADC_L             0x33
+#define M98088_REG_34_LVL_ADC_R             0x34
+#define M98088_REG_35_LVL_MIC1              0x35
+#define M98088_REG_36_LVL_MIC2              0x36
+#define M98088_REG_37_LVL_INA               0x37
+#define M98088_REG_38_LVL_INB               0x38
+#define M98088_REG_39_LVL_HP_L              0x39
+#define M98088_REG_3A_LVL_HP_R              0x3A
+#define M98088_REG_3B_LVL_REC_L             0x3B
+#define M98088_REG_3C_LVL_REC_R             0x3C
+#define M98088_REG_3D_LVL_SPK_L             0x3D
+#define M98088_REG_3E_LVL_SPK_R             0x3E
+#define M98088_REG_3F_MICAGC_CFG            0x3F
+#define M98088_REG_40_MICAGC_THRESH         0x40
+#define M98088_REG_41_SPKDHP                0x41
+#define M98088_REG_42_SPKDHP_THRESH         0x42
+#define M98088_REG_43_SPKALC_COMP           0x43
+#define M98088_REG_44_PWRLMT_CFG            0x44
+#define M98088_REG_45_PWRLMT_TIME           0x45
+#define M98088_REG_46_THDLMT_CFG            0x46
+#define M98088_REG_47_CFG_AUDIO_IN          0x47
+#define M98088_REG_48_CFG_MIC               0x48
+#define M98088_REG_49_CFG_LEVEL             0x49
+#define M98088_REG_4A_CFG_BYPASS            0x4A
+#define M98088_REG_4B_CFG_JACKDET           0x4B
+#define M98088_REG_4C_PWR_EN_IN             0x4C
+#define M98088_REG_4D_PWR_EN_OUT            0x4D
+#define M98088_REG_4E_BIAS_CNTL             0x4E
+#define M98088_REG_4F_DAC_BIAS1             0x4F
+#define M98088_REG_50_DAC_BIAS2             0x50
+#define M98088_REG_51_PWR_SYS               0x51
+#define M98088_REG_52_DAI1_EQ_BASE          0x52
+#define M98088_REG_84_DAI2_EQ_BASE          0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE      0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE      0xC0
+#define M98088_REG_FF_REV_ID                0xFF
+
+#define M98088_REG_CNT                      (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
+       #define M98088_CLKMODE_MASK             0xFF
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+       #define M98088_DAI_MAS                  (1<<7)
+       #define M98088_DAI_WCI                  (1<<6)
+       #define M98088_DAI_BCI                  (1<<5)
+       #define M98088_DAI_DLY                  (1<<4)
+       #define M98088_DAI_TDM                  (1<<2)
+       #define M98088_DAI_FSW                  (1<<1)
+       #define M98088_DAI_WS                   (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+       #define M98088_DAI_BSEL64               (1<<0)
+       #define M98088_DAI_OSR64                (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+       #define M98088_S1NORMAL                 (1<<6)
+       #define M98088_S2NORMAL                 (2<<6)
+       #define M98088_SDATA                    (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+       #define M98088_DAI_DHF                  (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+       #define M98088_DAI1L_TO_DACL            (1<<7)
+       #define M98088_DAI1R_TO_DACL            (1<<6)
+       #define M98088_DAI2L_TO_DACL            (1<<5)
+       #define M98088_DAI2R_TO_DACL            (1<<4)
+       #define M98088_DAI1L_TO_DACR            (1<<3)
+       #define M98088_DAI1R_TO_DACR            (1<<2)
+       #define M98088_DAI2L_TO_DACR            (1<<1)
+       #define M98088_DAI2R_TO_DACR            (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+       #define M98088_REC_LINEMODE             (1<<7)
+       #define M98088_REC_LINEMODE_MASK        (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+       #define M98088_MICPRE_MASK              (3<<5)
+       #define M98088_MICPRE_SHIFT             5
+
+/* M98088_REG_3A_LVL_HP_R */
+       #define M98088_HP_MUTE                  (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+       #define M98088_REC_MUTE                 (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+       #define M98088_SP_MUTE                  (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+       #define M98088_EXTMIC_MASK              (3<<0)
+       #define M98088_DIGMIC_L                 (1<<5)
+       #define M98088_DIGMIC_R                 (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+       #define M98088_VSEN                     (1<<6)
+       #define M98088_ZDEN                     (1<<5)
+       #define M98088_EQ2EN                    (1<<1)
+       #define M98088_EQ1EN                    (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+       #define M98088_INAEN                    (1<<7)
+       #define M98088_INBEN                    (1<<6)
+       #define M98088_MBEN                     (1<<3)
+       #define M98088_ADLEN                    (1<<1)
+       #define M98088_ADREN                    (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+       #define M98088_HPLEN                    (1<<7)
+       #define M98088_HPREN                    (1<<6)
+       #define M98088_HPEN                     ((1<<7)|(1<<6))
+       #define M98088_SPLEN                    (1<<5)
+       #define M98088_SPREN                    (1<<4)
+       #define M98088_RECEN                    (1<<3)
+       #define M98088_DALEN                    (1<<1)
+       #define M98088_DAREN                    (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+       #define M98088_SHDNRUN                  (1<<7)
+       #define M98088_PERFMODE                 (1<<3)
+       #define M98088_HPPLYBACK                (1<<2)
+       #define M98088_PWRSV8K                  (1<<1)
+       #define M98088_PWRSV                    (1<<0)
+
+/* Line inputs */
+#define LINE_INA  0
+#define LINE_INB  1
+
+#define M98088_COEFS_PER_BAND               5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+#endif
index 5a5f187a265738283cb4f05049f78d12430d9789..bd8f26e41602cf2fe8bcb36dd423bc62a1c1c521 100644 (file)
@@ -32,8 +32,8 @@
 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |   \
                       SNDRV_PCM_RATE_48000)
 
-struct snd_soc_dai pcm3008_dai = {
-       .name = "PCM3008 HiFi",
+static struct snd_soc_dai_driver pcm3008_dai = {
+       .name = "pcm3008-hifi",
        .playback = {
                .stream_name = "PCM3008 Playback",
                .channels_min = 1,
@@ -49,7 +49,6 @@ struct snd_soc_dai pcm3008_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 };
-EXPORT_SYMBOL_GPL(pcm3008_dai);
 
 static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
 {
@@ -59,38 +58,13 @@ static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
        gpio_free(setup->pdda_pin);
 }
 
-static int pcm3008_soc_probe(struct platform_device *pdev)
+static int pcm3008_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
        int ret = 0;
 
        printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->card->codec)
-               return -ENOMEM;
-
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->name = "PCM3008";
-       codec->owner = THIS_MODULE;
-       codec->dai = &pcm3008_dai;
-       codec->num_dai = 1;
-       codec->write = NULL;
-       codec->read = NULL;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* Register PCMs. */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "pcm3008: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* DEM1  DEM0  DE-EMPHASIS_MODE
         * Low   Low   De-emphasis 44.1 kHz ON
         * Low   High  De-emphasis OFF
@@ -130,33 +104,22 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
 
 gpio_err:
        pcm3008_gpio_free(setup);
-pcm_err:
-       kfree(socdev->card->codec);
 
        return ret;
 }
 
-static int pcm3008_soc_remove(struct platform_device *pdev)
+static int pcm3008_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct pcm3008_setup_data *setup = socdev->codec_data;
-
-       if (!codec)
-               return 0;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        pcm3008_gpio_free(setup);
-       snd_soc_free_pcms(socdev);
-       kfree(socdev->card->codec);
-
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value(setup->pdad_pin, 0);
        gpio_set_value(setup->pdda_pin, 0);
@@ -164,10 +127,9 @@ static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
        return 0;
 }
 
-static int pcm3008_soc_resume(struct platform_device *pdev)
+static int pcm3008_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value(setup->pdad_pin, 1);
        gpio_set_value(setup->pdda_pin, 1);
@@ -179,23 +141,45 @@ static int pcm3008_soc_resume(struct platform_device *pdev)
 #define pcm3008_soc_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
        .probe =        pcm3008_soc_probe,
        .remove =       pcm3008_soc_remove,
        .suspend =      pcm3008_soc_suspend,
        .resume =       pcm3008_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
 
-static int __init pcm3008_init(void)
+static int __devinit pcm3008_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
+}
+
+static int __devexit pcm3008_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:pcm3008-codec");
+
+static struct platform_driver pcm3008_codec_driver = {
+       .probe          = pcm3008_codec_probe,
+       .remove         = __devexit_p(pcm3008_codec_remove),
+       .driver         = {
+               .name   = "pcm3008-codec",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init pcm3008_modinit(void)
 {
-       return snd_soc_register_dai(&pcm3008_dai);
+       return platform_driver_register(&pcm3008_codec_driver);
 }
-module_init(pcm3008_init);
+module_init(pcm3008_modinit);
 
 static void __exit pcm3008_exit(void)
 {
-       snd_soc_unregister_dai(&pcm3008_dai);
+       platform_driver_unregister(&pcm3008_codec_driver);
 }
 module_exit(pcm3008_exit);
 
index d04e87d3c060c964614fcfcb803e0d07b016309f..7e5489ab48123ec46b19a239a15bf2b39944693e 100644 (file)
@@ -19,7 +19,4 @@ struct pcm3008_setup_data {
        unsigned pdda_pin;
 };
 
-extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
-extern struct snd_soc_dai pcm3008_dai;
-
 #endif
index 9119836051a4721abef78468869c07b7bdc409a8..4c32b54913ad0f6316de3bea2f4e03a558fe8ec6 100644 (file)
 #include <sound/pcm.h>
 #include <sound/initval.h>
 
-#include "spdif_transciever.h"
-
 MODULE_LICENSE("GPL");
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
 
-static struct snd_soc_codec *spdif_dit_codec;
-
-static int spdif_dit_codec_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (spdif_dit_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = spdif_dit_codec;
-       codec = spdif_dit_codec;
-
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto err_create_pcms;
-       }
-
-       return 0;
-
-err_create_pcms:
-       return ret;
-}
-
-static int spdif_dit_codec_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-
-       return 0;
-}
 
-struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
-       .probe          = spdif_dit_codec_probe,
-       .remove         = spdif_dit_codec_remove,
-}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+static struct snd_soc_codec_driver soc_codec_spdif_dit;
 
-struct snd_soc_dai dit_stub_dai = {
-       .name           = "DIT",
+static struct snd_soc_dai_driver dit_stub_dai = {
+       .name           = "dit-hifi",
        .playback       = {
                .stream_name    = "Playback",
                .channels_min   = 1,
@@ -80,65 +39,16 @@ struct snd_soc_dai dit_stub_dai = {
                .formats        = STUB_FORMATS,
        },
 };
-EXPORT_SYMBOL_GPL(dit_stub_dai);
 
 static int spdif_dit_probe(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (spdif_dit_codec) {
-               dev_err(&pdev->dev, "Another Codec is registered\n");
-               ret = -EINVAL;
-               goto err_reg_codec;
-       }
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       codec->dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "spdif-dit";
-       codec->owner = THIS_MODULE;
-       codec->dai = &dit_stub_dai;
-       codec->num_dai = 1;
-
-       spdif_dit_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_reg_codec;
-       }
-
-       dit_stub_dai.dev = &pdev->dev;
-       ret = snd_soc_register_dai(&dit_stub_dai);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to register dai: %d\n", ret);
-               goto err_reg_dai;
-       }
-
-       return 0;
-
-err_reg_dai:
-       snd_soc_unregister_codec(codec);
-err_reg_codec:
-       kfree(spdif_dit_codec);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
+                       &dit_stub_dai, 1);
 }
 
 static int spdif_dit_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&dit_stub_dai);
-       snd_soc_unregister_codec(spdif_dit_codec);
-       kfree(spdif_dit_codec);
-       spdif_dit_codec = NULL;
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
deleted file mode 100644 (file)
index 1e10212..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA SoC DIT/DIR driver header
- *
- * Author:      Steve Chen,  <schen@mvista.com>
- * Copyright:   (C) 2008 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef CODEC_STUBS_H
-#define CODEC_STUBS_H
-
-extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
-extern struct snd_soc_dai dit_stub_dai;
-
-#endif /* CODEC_STUBS_H */
index b47ed4f6ab2072b86157b97da602d168e3756bd6..6f38d619bf8ab207ab35252f16c4a7f4db3d41fe 100644 (file)
 
 #define SSM2602_VERSION "0.1"
 
-struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
 /* codec private data */
 struct ssm2602_priv {
        unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
 };
@@ -276,8 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 {
        u16 srate;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c = codec->control_data;
        u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -321,8 +320,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
@@ -360,8 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        /* set active */
        ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 
@@ -372,8 +369,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
@@ -518,8 +514,8 @@ static struct snd_soc_dai_ops ssm2602_dai_ops = {
        .set_fmt        = ssm2602_set_dai_fmt,
 };
 
-struct snd_soc_dai ssm2602_dai = {
-       .name = "SSM2602",
+static struct snd_soc_dai_driver ssm2602_dai = {
+       .name = "ssm2602-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -534,21 +530,15 @@ struct snd_soc_dai ssm2602_dai = {
                .formats = SSM2602_FORMATS,},
        .ops = &ssm2602_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ssm2602_dai);
 
-static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int ssm2602_resume(struct platform_device *pdev)
+static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -563,36 +553,17 @@ static int ssm2602_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the ssm2602 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ssm2602_init(struct snd_soc_device *socdev)
+static int ssm2602_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int reg, ret = 0;
-
-       codec->name = "SSM2602";
-       codec->owner = THIS_MODULE;
-       codec->read = ssm2602_read_reg_cache;
-       codec->write = ssm2602_write;
-       codec->set_bias_level = ssm2602_set_bias_level;
-       codec->dai = &ssm2602_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = sizeof(ssm2602_reg);
-       codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
+
+       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+       codec->control_data = ssm2602->control_data;
 
        ssm2602_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               pr_err("ssm2602: failed to create pcms\n");
-               goto pcm_err;
-       }
        /*power on device*/
        ssm2602_write(codec, SSM2602_ACTIVE, 0);
        /* set the update bits */
@@ -614,13 +585,27 @@ static int ssm2602_init(struct snd_soc_device *socdev)
        ssm2602_add_widgets(codec);
 
        return ret;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+/* remove everything here */
+static int ssm2602_remove(struct snd_soc_codec *codec)
+{
+       ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static struct snd_soc_device *ssm2602_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+       .probe =        ssm2602_probe,
+       .remove =       ssm2602_remove,
+       .suspend =      ssm2602_suspend,
+       .resume =       ssm2602_resume,
+       .read = ssm2602_read_reg_cache,
+       .write = ssm2602_write,
+       .set_bias_level = ssm2602_set_bias_level,
+       .reg_cache_size = sizeof(ssm2602_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = ssm2602_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
@@ -632,24 +617,28 @@ static struct snd_soc_device *ssm2602_socdev;
 static int ssm2602_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = ssm2602_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct ssm2602_priv *ssm2602;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       if (ssm2602 == NULL)
+               return -ENOMEM;
 
-       ret = ssm2602_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise SSM2602\n");
+       i2c_set_clientdata(i2c, ssm2602);
+       ssm2602->control_data = i2c;
+       ssm2602->control_type = SND_SOC_I2C;
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+       if (ret < 0)
+               kfree(ssm2602);
        return ret;
 }
 
 static int ssm2602_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -658,130 +647,39 @@ static const struct i2c_device_id ssm2602_i2c_id[] = {
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
        .driver = {
-               .name = "SSM2602 I2C Codec",
+               .name = "ssm2602-codec",
                .owner = THIS_MODULE,
        },
        .probe = ssm2602_i2c_probe,
        .remove = ssm2602_i2c_remove,
        .id_table = ssm2602_i2c_id,
 };
-
-static int ssm2602_add_i2c_device(struct platform_device *pdev,
-                                 const struct ssm2602_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&ssm2602_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-               setup->i2c_bus);
-               goto err_driver;
-       }
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-               (unsigned int)info.addr);
-               goto err_driver;
-       }
-       return 0;
-err_driver:
-       i2c_del_driver(&ssm2602_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int ssm2602_probe(struct platform_device *pdev)
+
+static int __init ssm2602_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct ssm2602_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct ssm2602_priv *ssm2602;
        int ret = 0;
-
-       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
-       if (ssm2602 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, ssm2602);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ssm2602_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = ssm2602_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&ssm2602_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
+                      ret);
        }
-#else
-       /* other interfaces */
 #endif
        return ret;
 }
+module_init(ssm2602_modinit);
 
-/* remove everything here */
-static int ssm2602_remove(struct platform_device *pdev)
+static void __exit ssm2602_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&ssm2602_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
-       .probe =        ssm2602_probe,
-       .remove =       ssm2602_remove,
-       .suspend =      ssm2602_suspend,
-       .resume =       ssm2602_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
-
-static int __init ssm2602_modinit(void)
-{
-       return snd_soc_register_dai(&ssm2602_dai);
-}
-module_init(ssm2602_modinit);
-
-static void __exit ssm2602_exit(void)
-{
-       snd_soc_unregister_dai(&ssm2602_dai);
 }
 module_exit(ssm2602_exit);
 
index f344e6d76e31735d43d15c6b34d4ab3a01a1c6ad..42a47d0f8e2551879c7d9397e1d035ecfe918f46 100644 (file)
@@ -124,7 +124,4 @@ struct ssm2602_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai ssm2602_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
 #endif
index ee86568545c255f2746c32eb6d469a3633f2a470..00d67cc8e2062a9071dcb78ee0fb2d64b5a77166 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/soc-of-simple.h>
 
 #include "stac9766.h"
 
@@ -257,20 +256,15 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
        return 0;
 }
 
-static int stac9766_codec_suspend(struct platform_device *pdev,
+static int stac9766_codec_suspend(struct snd_soc_codec *codec,
                                  pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int stac9766_codec_resume(struct platform_device *pdev)
+static int stac9766_codec_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 id, reset;
 
        reset = 0;
@@ -300,10 +294,9 @@ static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
        .prepare = ac97_digital_prepare,
 };
 
-struct snd_soc_dai stac9766_dai[] = {
+static struct snd_soc_dai_driver stac9766_dai[] = {
 {
-       .name = "stac9766 analog",
-       .id = 0,
+       .name = "stac9766-hifi-analog",
        .ac97_control = 1,
 
        /* stream cababilities */
@@ -325,8 +318,7 @@ struct snd_soc_dai stac9766_dai[] = {
        .ops = &stac9766_dai_ops_analog,
 },
 {
-       .name = "stac9766 IEC958",
-       .id = 1,
+       .name = "stac9766-hifi-IEC958",
        .ac97_control = 1,
 
        /* stream cababilities */
@@ -342,57 +334,24 @@ struct snd_soc_dai stac9766_dai[] = {
        .ops = &stac9766_dai_ops_digital,
 }
 };
-EXPORT_SYMBOL_GPL(stac9766_dai);
 
-static int stac9766_codec_probe(struct platform_device *pdev)
+static int stac9766_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(stac9766_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "STAC9766";
-       codec->owner = THIS_MODULE;
-       codec->dai = stac9766_dai;
-       codec->num_dai = ARRAY_SIZE(stac9766_dai);
-       codec->write = stac9766_ac97_write;
-       codec->read = stac9766_ac97_read;
-       codec->set_bias_level = stac9766_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        /* do a cold reset for the controller and then try
         * a warm reset followed by an optional cold reset for codec */
        stac9766_reset(codec, 0);
        ret = stac9766_reset(codec, 1);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
-               goto reset_err;
+               goto codec_err;
        }
 
        stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -402,40 +361,63 @@ static int stac9766_codec_probe(struct platform_device *pdev)
 
        return 0;
 
-reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
-       snd_soc_free_ac97_codec(codec);
 codec_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
+       snd_soc_free_ac97_codec(codec);
        return ret;
 }
 
-static int stac9766_codec_remove(struct platform_device *pdev)
+static int stac9766_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+       .write = stac9766_ac97_write,
+       .read = stac9766_ac97_read,
+       .set_bias_level = stac9766_set_bias_level,
        .probe = stac9766_codec_probe,
        .remove = stac9766_codec_remove,
        .suspend = stac9766_codec_suspend,
        .resume = stac9766_codec_resume,
+       .reg_cache_size = sizeof(stac9766_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+};
+
+static __devinit int stac9766_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
+}
+
+static int __devexit stac9766_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver stac9766_codec_driver = {
+       .driver = {
+                       .name = "stac9766-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = stac9766_probe,
+       .remove = __devexit_p(stac9766_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+static int __init stac9766_init(void)
+{
+       return platform_driver_register(&stac9766_codec_driver);
+}
+module_init(stac9766_init);
+
+static void __exit stac9766_exit(void)
+{
+       platform_driver_unregister(&stac9766_codec_driver);
+}
+module_exit(stac9766_exit);
 
 MODULE_DESCRIPTION("ASoC stac9766 driver");
 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
index 65642eb8393e2d71ad26d7413496976520cbdcff..c726f907e2c03311c54ff31318193fff5cee4e7e 100644 (file)
@@ -14,8 +14,4 @@
 #define STAC9766_DAI_AC97_ANALOG               0
 #define STAC9766_DAI_AC97_DIGITAL              1
 
-extern struct snd_soc_dai stac9766_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_stac9766;
-
-
 #endif
index 0a4b0fef33550f217adf1a597636963e76cb4d48..e8652b1ae32606b5c57bd0ff7d0a8b4a304fa9d5 100644 (file)
@@ -240,7 +240,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 /* AIC23 driver data */
 struct aic23 {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        int mclk;
        int requested_adc;
        int requested_dac;
@@ -404,11 +405,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface_reg;
        int ret;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
        u32 sample_rate_adc = aic23->requested_adc;
        u32 sample_rate_dac = aic23->requested_dac;
        u32 sample_rate = params_rate(params);
@@ -452,8 +452,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
                                   struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* set active */
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -465,9 +464,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct snd_soc_codec *codec = rtd->codec;
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
        if (!codec->active) {
@@ -546,8 +544,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                      int clk_id, unsigned int freq, int dir)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
        aic23->mclk = freq;
        return 0;
 }
@@ -594,8 +591,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
        .set_sysclk     = tlv320aic23_set_dai_sysclk,
 };
 
-struct snd_soc_dai tlv320aic23_dai = {
-       .name = "tlv320aic23",
+static struct snd_soc_dai_driver tlv320aic23_dai = {
+       .name = "tlv320aic23-hifi",
        .playback = {
                     .stream_name = "Playback",
                     .channels_min = 2,
@@ -610,23 +607,17 @@ struct snd_soc_dai tlv320aic23_dai = {
                    .formats = AIC23_FORMATS,},
        .ops = &tlv320aic23_dai_ops,
 };
-EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
-static int tlv320aic23_suspend(struct platform_device *pdev,
+static int tlv320aic23_suspend(struct snd_soc_codec *codec,
                               pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int tlv320aic23_resume(struct platform_device *pdev)
+static int tlv320aic23_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Sync reg_cache with the hardware */
@@ -639,39 +630,19 @@ static int tlv320aic23_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the AIC23 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int tlv320aic23_init(struct snd_soc_device *socdev)
+static int tlv320aic23_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-       u16 reg;
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+       int reg;
 
-       codec->name = "tlv320aic23";
-       codec->owner = THIS_MODULE;
-       codec->read = tlv320aic23_read_reg_cache;
-       codec->write = tlv320aic23_write;
-       codec->set_bias_level = tlv320aic23_set_bias_level;
-       codec->dai = &tlv320aic23_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
-       codec->reg_cache =
-           kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+       codec->control_data = aic23->control_data;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       codec->hw_read = NULL;
 
        /* Reset codec */
        tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* power on device */
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -707,13 +678,27 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(tlv320aic23_snd_controls));
        tlv320aic23_add_widgets(codec);
 
-       return ret;
+       return 0;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+static int tlv320aic23_remove(struct snd_soc_codec *codec)
+{
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
-static struct snd_soc_device *tlv320aic23_socdev;
+
+static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+       .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = tlv320aic23_reg,
+       .probe = tlv320aic23_probe,
+       .remove = tlv320aic23_remove,
+       .suspend = tlv320aic23_suspend,
+       .resume = tlv320aic23_resume,
+       .read = tlv320aic23_read_reg_cache,
+       .write = tlv320aic23_write,
+       .set_bias_level = tlv320aic23_set_bias_level,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
@@ -723,31 +708,30 @@ static struct snd_soc_device *tlv320aic23_socdev;
 static int tlv320aic23_codec_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *i2c_id)
 {
-       struct snd_soc_device *socdev = tlv320aic23_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct aic23 *aic23;
        int ret;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EINVAL;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+       if (aic23 == NULL)
+               return -ENOMEM;
 
-       ret = tlv320aic23_init(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
-               goto err;
-       }
-       return ret;
+       i2c_set_clientdata(i2c, aic23);
+       aic23->control_data = i2c;
+       aic23->control_type = SND_SOC_I2C;
 
-err:
-       kfree(codec);
-       kfree(i2c);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
+       if (ret < 0)
+               kfree(aic23);
        return ret;
 }
 static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
 {
-       put_device(&i2c->dev);
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
@@ -760,7 +744,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
 
 static struct i2c_driver tlv320aic23_i2c_driver = {
        .driver = {
-                  .name = "tlv320aic23",
+                  .name = "tlv320aic23-codec",
                   },
        .probe = tlv320aic23_codec_probe,
        .remove = __exit_p(tlv320aic23_i2c_remove),
@@ -769,71 +753,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
 
 #endif
 
-static int tlv320aic23_probe(struct platform_device *pdev)
+static int __init tlv320aic23_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct aic23 *aic23;
-       int ret = 0;
-
-       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
-       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
-       if (aic23 == NULL)
-               return -ENOMEM;
-       codec = &aic23->codec;
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       tlv320aic23_socdev = socdev;
+       int ret;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       codec->hw_write = (hw_write_t) i2c_master_send;
-       codec->hw_read = NULL;
        ret = i2c_add_driver(&tlv320aic23_i2c_driver);
-       if (ret != 0)
-               printk(KERN_ERR "can't add i2c driver");
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
+                      ret);
+       }
 #endif
        return ret;
 }
+module_init(tlv320aic23_modinit);
 
-static int tlv320aic23_remove(struct platform_device *pdev)
+static void __exit tlv320aic23_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
-
-       if (codec->control_data)
-               tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&tlv320aic23_i2c_driver);
 #endif
-       kfree(codec->reg_cache);
-       kfree(aic23);
-
-       return 0;
-}
-struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
-       .probe = tlv320aic23_probe,
-       .remove = tlv320aic23_remove,
-       .suspend = tlv320aic23_suspend,
-       .resume = tlv320aic23_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
-
-static int __init tlv320aic23_modinit(void)
-{
-       return snd_soc_register_dai(&tlv320aic23_dai);
-}
-module_init(tlv320aic23_modinit);
-
-static void __exit tlv320aic23_exit(void)
-{
-       snd_soc_unregister_dai(&tlv320aic23_dai);
 }
 module_exit(tlv320aic23_exit);
 
index 79d1faf8e570bafa76147716e3b2fa3b247bd8ab..e804120bd3da3bae2354fe5bfd46809d93f561cb 100644 (file)
 #define TLV320AIC23_SIDETONE_12                0x080
 #define TLV320AIC23_SIDETONE_18                0x0c0
 
-extern struct snd_soc_dai tlv320aic23_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
-
 #endif /* _TLV320AIC23_H */
index f0e00fd4b43578ef78f1f20a8d82c5561379a556..6b7d71ec0004ddb660e9e962a64002dc430ecd2d 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
-#include <sound/soc-of-simple.h>
 #include <sound/initval.h>
 
 #include "tlv320aic26.h"
@@ -130,8 +129,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
        int fsref, divisor, wlen, pval, jval, dval, qval;
        u16 reg;
@@ -278,8 +276,8 @@ static struct snd_soc_dai_ops aic26_dai_ops = {
        .set_fmt        = aic26_set_fmt,
 };
 
-struct snd_soc_dai aic26_dai = {
-       .name = "tlv320aic26",
+static struct snd_soc_dai_driver aic26_dai = {
+       .name = "tlv320aic26-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -296,7 +294,6 @@ struct snd_soc_dai aic26_dai = {
        },
        .ops = &aic26_dai_ops,
 };
-EXPORT_SYMBOL_GPL(aic26_dai);
 
 /* ---------------------------------------------------------------------
  * ALSA controls
@@ -318,61 +315,6 @@ static const struct snd_kcontrol_new aic26_snd_controls[] = {
        SOC_ENUM("Capture Source", aic26_capture_src_enum),
 };
 
-/* ---------------------------------------------------------------------
- * SoC CODEC portion of driver: probe and release routines
- */
-static int aic26_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct aic26 *aic26;
-       int ret, err;
-
-       dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
-       dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
-       dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
-
-       /* Fetch the relevant aic26 private data here (it's already been
-        * stored in the .codec pointer) */
-       aic26 = socdev->codec_data;
-       if (aic26 == NULL) {
-               dev_err(&pdev->dev, "aic26: missing codec pointer\n");
-               return -ENODEV;
-       }
-       codec = &aic26->codec;
-       socdev->card->codec = codec;
-
-       dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
-               &pdev->dev, socdev->dev);
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "aic26: failed to create pcms\n");
-               return -ENODEV;
-       }
-
-       /* register controls */
-       dev_dbg(&pdev->dev, "Registering controls\n");
-       err = snd_soc_add_controls(codec, aic26_snd_controls,
-                       ARRAY_SIZE(aic26_snd_controls));
-       WARN_ON(err < 0);
-
-       return 0;
-}
-
-static int aic26_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       snd_soc_free_pcms(socdev);
-       return 0;
-}
-
-struct snd_soc_codec_device aic26_soc_codec_dev = {
-       .probe = aic26_probe,
-       .remove = aic26_remove,
-};
-EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
-
 /* ---------------------------------------------------------------------
  * SPI device portion of driver: sysfs files for debugging
  */
@@ -409,95 +351,95 @@ static ssize_t aic26_keyclick_set(struct device *dev,
 static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
 
 /* ---------------------------------------------------------------------
- * SPI device portion of driver: probe and release routines and SPI
- *                              driver registration.
+ * SoC CODEC portion of driver: probe and release routines
  */
-static int aic26_spi_probe(struct spi_device *spi)
+static int aic26_probe(struct snd_soc_codec *codec)
 {
-       struct aic26 *aic26;
-       int ret, i, reg;
-
-       dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
-
-       /* Allocate driver data */
-       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
-       if (!aic26)
-               return -ENOMEM;
-
-       /* Initialize the driver data */
-       aic26->spi = spi;
-       dev_set_drvdata(&spi->dev, aic26);
+       struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+       int ret, err, i, reg;
 
-       /* Setup what we can in the codec structure so that the register
-        * access functions will work as expected.  More will be filled
-        * out when it is probed by the SoC CODEC part of this driver */
-       snd_soc_codec_set_drvdata(&aic26->codec, aic26);
-       aic26->codec.name = "aic26";
-       aic26->codec.owner = THIS_MODULE;
-       aic26->codec.dai = &aic26_dai;
-       aic26->codec.num_dai = 1;
-       aic26->codec.read = aic26_reg_read;
-       aic26->codec.write = aic26_reg_write;
-       aic26->master = 1;
-       mutex_init(&aic26->codec.mutex);
-       INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
-       INIT_LIST_HEAD(&aic26->codec.dapm_paths);
-       aic26->codec.reg_cache_size = AIC26_NUM_REGS;
-       aic26->codec.reg_cache = aic26->reg_cache;
-
-       aic26_dai.dev = &spi->dev;
-       ret = snd_soc_register_dai(&aic26_dai);
-       if (ret != 0) {
-               dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
-               kfree(aic26);
-               return ret;
-       }
+       dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
 
        /* Reset the codec to power on defaults */
-       aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+       aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
 
        /* Power up CODEC */
-       aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+       aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
 
        /* Audio Control 3 (master mode, fsref rate) */
-       reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+       reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
        reg &= ~0xf800;
        reg |= 0x0800; /* set master mode */
-       aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
        /* Fill register cache */
        for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
-               aic26_reg_read(&aic26->codec, i);
+               aic26_reg_read(codec, i);
 
        /* Register the sysfs files for debugging */
        /* Create SysFS files */
-       ret = device_create_file(&spi->dev, &dev_attr_keyclick);
+       ret = device_create_file(codec->dev, &dev_attr_keyclick);
        if (ret)
-               dev_info(&spi->dev, "error creating sysfs files\n");
+               dev_info(codec->dev, "error creating sysfs files\n");
 
-#if defined(CONFIG_SND_SOC_OF_SIMPLE)
-       /* Tell the of_soc helper about this codec */
-       of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
-                                 spi->dev.archdata.of_node);
-#endif
+       /* register controls */
+       dev_dbg(codec->dev, "Registering controls\n");
+       err = snd_soc_add_controls(codec, aic26_snd_controls,
+                       ARRAY_SIZE(aic26_snd_controls));
+       WARN_ON(err < 0);
 
-       dev_dbg(&spi->dev, "SPI device initialized\n");
        return 0;
 }
 
-static int aic26_spi_remove(struct spi_device *spi)
+static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+       .probe = aic26_probe,
+       .read = aic26_reg_read,
+       .write = aic26_reg_write,
+       .reg_cache_size = AIC26_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ *                              driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
 {
-       struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+       struct aic26 *aic26;
+       int ret;
 
-       snd_soc_unregister_dai(&aic26_dai);
-       kfree(aic26);
+       dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+       /* Allocate driver data */
+       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+       if (!aic26)
+               return -ENOMEM;
 
+       /* Initialize the driver data */
+       aic26->spi = spi;
+       dev_set_drvdata(&spi->dev, aic26);
+       aic26->master = 1;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &aic26_soc_codec_dev, &aic26_dai, 1);
+       if (ret < 0)
+               kfree(aic26);
+       return ret;
+
+       dev_dbg(&spi->dev, "SPI device initialized\n");
+       return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver aic26_spi = {
        .driver = {
-               .name = "tlv320aic26",
+               .name = "tlv320aic26-codec",
                .owner = THIS_MODULE,
        },
        .probe = aic26_spi_probe,
index 786ba16c945fa13728e2169baab21f5a3ffadfcc..62b1f2261429cf8c25747b5ecb4c4554c5b6d71f 100644 (file)
@@ -90,7 +90,4 @@ enum aic26_wlen {
        AIC26_WLEN_32   = 3 << 10,
 };
 
-extern struct snd_soc_dai aic26_dai;
-extern struct snd_soc_codec_device aic26_soc_codec_dev;
-
 #endif /* _TLV320AIC16_H_ */
index 71a69908ccf69485e0bbdb3e2804fcf06ee3fe8f..fc687790188b2f1ee2b33f48f2dab0b831f3ffa9 100644 (file)
  *
  * Notes:
  *  The AIC3X is a driver for a low power stereo audio
- *  codecs aic31, aic32, aic33.
+ *  codecs aic31, aic32, aic33, aic3007.
  *
  *  It supports full aic33 codec functionality.
- *  The compatibility with aic32, aic31 is as follows:
- *        aic32        |        aic31
+ *  The compatibility with aic32, aic31 and aic3007 is as follows:
+ *    aic32/aic3007    |        aic31
  *  ---------------------------------------
  *   MONO_LOUT -> N/A  |  MONO_LOUT -> N/A
  *                     |  IN1L -> LINE1L
@@ -61,13 +61,29 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
        "DRVDD",        /* ADC Analog and Output Driver Voltage */
 };
 
+struct aic3x_priv;
+
+struct aic3x_disable_nb {
+       struct notifier_block nb;
+       struct aic3x_priv *aic3x;
+};
+
 /* codec private data */
 struct aic3x_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
+       struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
+       enum snd_soc_control_type control_type;
+       struct aic3x_setup_data *setup;
+       void *control_data;
        unsigned int sysclk;
        int master;
        int gpio_reset;
+       int power;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+       u16 model;
 };
 
 /*
@@ -106,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
 };
 
 /*
- * read aic3x register cache
+ * read from the aic3x register space. Only use for this function is if
+ * wanting to read volatile bits from those registers that has both read-only
+ * and read/write bits. All other cases should use snd_soc_read.
  */
-static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
-                                               unsigned int reg)
+static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
+                     u8 *value)
 {
        u8 *cache = codec->reg_cache;
-       if (reg >= AIC3X_CACHEREGNUM)
-               return -1;
-       return cache[reg];
-}
 
-/*
- * write aic3x register cache
- */
-static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
-                                        u8 reg, u8 value)
-{
-       u8 *cache = codec->reg_cache;
+       if (codec->cache_only)
+               return -EINVAL;
        if (reg >= AIC3X_CACHEREGNUM)
-               return;
-       cache[reg] = value;
-}
-
-/*
- * write to the aic3x register space
- */
-static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
-                      unsigned int value)
-{
-       u8 data[2];
-
-       /* data is
-        *   D15..D8 aic3x register offset
-        *   D7...D0 register data
-        */
-       data[0] = reg & 0xff;
-       data[1] = value & 0xff;
-
-       aic3x_write_reg_cache(codec, data[0], data[1]);
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
-}
-
-/*
- * read from the aic3x register space
- */
-static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
-                     u8 *value)
-{
-       *value = reg & 0xff;
+               return -1;
 
-       value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+       *value = codec->hw_read(codec, reg);
+       cache[reg] = *value;
 
-       aic3x_write_reg_cache(codec, reg, *value);
        return 0;
 }
 
@@ -286,64 +263,102 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("PCM Playback Volume",
                         LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
 
+       /*
+        * Output controls that map to output mixer switches. Note these are
+        * only for swapped L-to-R and R-to-L routes. See below stereo controls
+        * for direct L-to-L and R-to-R routes.
+        */
+       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
+                      PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
+                      DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
+                      PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
+                      DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
+                      PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
+                      DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
+                      PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
+                      DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
+                      PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
+                      DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
+                      PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
+                      DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       /* Stereo output controls for direct L-to-L and R-to-R routes */
+       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
+                        PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
                         DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
-       SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
-                        DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
-                        0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
-                      PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
-                      PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
-                        LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
+
+       SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+                        LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
-                        LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
+       SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+                        PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
                         DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
-                        PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+
+       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
-                        LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+       SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
+                        PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
                         DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
-                    0x01, 0),
-       SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
-                        PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+
+       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
-                      PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
-                      PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
-                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+       SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
+                        PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
                         DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+
+       /* Output pin mute controls */
+       SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
+                    0x01, 0),
+       SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+       SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+                    0x01, 0),
+       SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
-       SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
-                      PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
-                      PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
-                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
-                        0, 118, 1, output_stage_tlv),
 
        /*
         * Note: enable Automatic input Gain Controller with care. It can
@@ -359,6 +374,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+       SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -375,22 +398,74 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
 static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
 
-/* Left DAC_L1 Mixer */
-static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+/* Left Line Mixer */
+static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+};
+
+/* Right Line Mixer */
+static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+};
+
+/* Left HP Mixer */
+static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+};
+
+/* Right HP Mixer */
+static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+};
+
+/* Left HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
 };
 
-/* Right DAC_R1 Mixer */
-static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+/* Right HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left PGA Mixer */
@@ -427,54 +502,11 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
 static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
 
-/* Left PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Right PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Left Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
-};
-
-/* Right Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
-};
-
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        /* Left DAC to Left Outputs */
        SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
        SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_dac_mux_controls),
-       SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_dac_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
        SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_hpcom_mux_controls),
        SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
@@ -485,9 +517,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
        SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_dac_mux_controls),
-       SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_dac_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
        SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_hpcom_mux_controls),
        SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
@@ -551,25 +580,28 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
                         MICBIAS_CTRL, 6, 3, 3, 0),
 
-       /* Left PGA to Left Output bypass */
-       SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_pga_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
-
-       /* Right PGA to Right Output bypass */
-       SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_pga_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
-
-       /* Left Line2 to Left Output bypass */
-       SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_line2_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
-
-       /* Right Line2 to Right Output bypass */
-       SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_line2_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
+       /* Output mixers */
+       SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_line_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_line_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_mono_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_mono_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
 
        SND_SOC_DAPM_OUTPUT("LLOUT"),
        SND_SOC_DAPM_OUTPUT("RLOUT"),
@@ -585,69 +617,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("LINE1R"),
        SND_SOC_DAPM_INPUT("LINE2L"),
        SND_SOC_DAPM_INPUT("LINE2R"),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-       /* Left Output */
-       {"Left DAC Mux", "DAC_L1", "Left DAC"},
-       {"Left DAC Mux", "DAC_L2", "Left DAC"},
-       {"Left DAC Mux", "DAC_L3", "Left DAC"},
-
-       {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
-       {"Left Line Out", NULL, "Left DAC Mux"},
-       {"Left HP Out", NULL, "Left DAC Mux"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
-
-       {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
-       {"Mono Out", NULL, "Left DAC_L1 Mixer"},
-       {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
-       {"Left HP Com", NULL, "Left HPCOM Mux"},
-
-       {"LLOUT", NULL, "Left Line Out"},
-       {"LLOUT", NULL, "Left Line Out"},
-       {"HPLOUT", NULL, "Left HP Out"},
-       {"HPLCOM", NULL, "Left HP Com"},
-
-       /* Right Output */
-       {"Right DAC Mux", "DAC_R1", "Right DAC"},
-       {"Right DAC Mux", "DAC_R2", "Right DAC"},
-       {"Right DAC Mux", "DAC_R3", "Right DAC"},
 
-       {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
-       {"Right Line Out", NULL, "Right DAC Mux"},
-       {"Right HP Out", NULL, "Right DAC Mux"},
+       /*
+        * Virtual output pin to detection block inside codec. This can be
+        * used to keep codec bias on if gpio or detection features are needed.
+        * Force pin on or construct a path with an input jack and mic bias
+        * widgets.
+        */
+       SND_SOC_DAPM_OUTPUT("Detection"),
+};
 
-       {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+       /* Class-D outputs */
+       SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
 
-       {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
-       {"Mono Out", NULL, "Right DAC_R1 Mixer"},
-       {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
-       {"Right HP Com", NULL, "Right HPCOM Mux"},
-
-       {"RLOUT", NULL, "Right Line Out"},
-       {"RLOUT", NULL, "Right Line Out"},
-       {"HPROUT", NULL, "Right HP Out"},
-       {"HPRCOM", NULL, "Right HP Com"},
-
-       /* Mono Output */
-       {"MONO_LOUT", NULL, "Mono Out"},
-       {"MONO_LOUT", NULL, "Mono Out"},
+       SND_SOC_DAPM_OUTPUT("SPOP"),
+       SND_SOC_DAPM_OUTPUT("SPOM"),
+};
 
+static const struct snd_soc_dapm_route intercon[] = {
        /* Left Input */
        {"Left Line1L Mux", "single-ended", "LINE1L"},
        {"Left Line1L Mux", "differential", "LINE1L"},
@@ -680,74 +669,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right ADC", NULL, "Right PGA Mixer"},
        {"Right ADC", NULL, "GPIO1 dmic modclk"},
 
-       /* Left PGA Bypass */
-       {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
-
-       {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
-       {"Mono Out", NULL, "Left PGA Bypass Mixer"},
-       {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
-
-       /* Right PGA Bypass */
-       {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
-
-       {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
-
-       {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
-       {"Mono Out", NULL, "Right PGA Bypass Mixer"},
-       {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
-
-       /* Left Line2 Bypass */
-       {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
-
-       {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
-       {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
-       {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
-
-       /* Right Line2 Bypass */
-       {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
-
-       {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
-
-       {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
-       {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
-       {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
-
        /*
         * Logical path between digital mic enable and GPIO1 modulator clock
         * output function
@@ -755,16 +676,131 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
        {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
        {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+       /* Left DAC Output */
+       {"Left DAC Mux", "DAC_L1", "Left DAC"},
+       {"Left DAC Mux", "DAC_L2", "Left DAC"},
+       {"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+       /* Right DAC Output */
+       {"Right DAC Mux", "DAC_R1", "Right DAC"},
+       {"Right DAC Mux", "DAC_R2", "Right DAC"},
+       {"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+       /* Left Line Output */
+       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left Line Out", NULL, "Left Line Mixer"},
+       {"Left Line Out", NULL, "Left DAC Mux"},
+       {"LLOUT", NULL, "Left Line Out"},
+
+       /* Right Line Output */
+       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right Line Out", NULL, "Right Line Mixer"},
+       {"Right Line Out", NULL, "Right DAC Mux"},
+       {"RLOUT", NULL, "Right Line Out"},
+
+       /* Mono Output */
+       {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Mono Out", NULL, "Mono Mixer"},
+       {"MONO_LOUT", NULL, "Mono Out"},
+
+       /* Left HP Output */
+       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left HP Out", NULL, "Left HP Mixer"},
+       {"Left HP Out", NULL, "Left DAC Mux"},
+       {"HPLOUT", NULL, "Left HP Out"},
+
+       /* Right HP Output */
+       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right HP Out", NULL, "Right HP Mixer"},
+       {"Right HP Out", NULL, "Right DAC Mux"},
+       {"HPROUT", NULL, "Right HP Out"},
+
+       /* Left HPCOM Output */
+       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
+       {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
+       {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
+       {"Left HP Com", NULL, "Left HPCOM Mux"},
+       {"HPLCOM", NULL, "Left HP Com"},
+
+       /* Right HPCOM Output */
+       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
+       {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
+       {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
+       {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
+       {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
+       {"Right HP Com", NULL, "Right HPCOM Mux"},
+       {"HPRCOM", NULL, "Right HP Com"},
+};
+
+static const struct snd_soc_dapm_route intercon_3007[] = {
+       /* Class-D outputs */
+       {"Left Class-D Out", NULL, "Left Line Out"},
+       {"Right Class-D Out", NULL, "Left Line Out"},
+       {"SPOP", NULL, "Left Class-D Out"},
+       {"SPOM", NULL, "Right Class-D Out"},
 };
 
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+                       ARRAY_SIZE(aic3007_dapm_widgets));
+               snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+       }
+
        return 0;
 }
 
@@ -773,8 +809,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -783,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        int clk;
 
        /* select data word length */
-       data =
-           aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+       data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                break;
@@ -798,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                data |= (0x03 << 4);
                break;
        }
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data);
 
        /* Fsref can be 44100 or 48000 */
        fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
@@ -813,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 
        if (bypass_pll) {
                pll_q &= 0xf;
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
-               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+               snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
                /* disable PLL if it is bypassed */
-               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
 
        } else {
-               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+               snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
                /* enable PLL when it is used */
-               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
        }
 
        /* Route Left DAC to left channel input and
@@ -832,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
        if (params_rate(params) >= 64000)
                data |= DUAL_RATE_MODE;
-       aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+       snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
 
        /* codec sample rate select */
        data = (fsref * 20) / params_rate(params);
@@ -841,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        data /= 5;
        data -= 2;
        data |= (data << 4);
-       aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+       snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
 
        if (bypass_pll)
                return 0;
@@ -910,13 +944,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        }
 
 found:
-       data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-       aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
-       aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGD_REG,
-                   (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+       data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                     data | (pll_p << PLLP_SHIFT));
+       snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+                     pll_r << PLLR_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGC_REG,
+                     (pll_d >> 6) << PLLD_MSB_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGD_REG,
+                     (pll_d & 0x3F) << PLLD_LSB_SHIFT);
 
        return 0;
 }
@@ -924,15 +961,15 @@ found:
 static int aic3x_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
-       u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
+       u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON;
+       u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON;
 
        if (mute) {
-               aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
-               aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+               snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
+               snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
        } else {
-               aic3x_write(codec, LDAC_VOL, ldac_reg);
-               aic3x_write(codec, RDAC_VOL, rdac_reg);
+               snd_soc_write(codec, LDAC_VOL, ldac_reg);
+               snd_soc_write(codec, RDAC_VOL, rdac_reg);
        }
 
        return 0;
@@ -956,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        u8 iface_areg, iface_breg;
        int delay = 0;
 
-       iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
-       iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+       iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+       iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
 
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -996,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* set iface */
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+
+       return 0;
+}
+
+static int aic3x_init_3007(struct snd_soc_codec *codec)
+{
+       u8 tmp1, tmp2, *cache = codec->reg_cache;
+
+       /*
+        * There is no need to cache writes to undocumented page 0xD but
+        * respective page 0 register cache entries must be preserved
+        */
+       tmp1 = cache[0xD];
+       tmp2 = cache[0x8];
+       /* Class-D speaker driver init; datasheet p. 46 */
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
+       snd_soc_write(codec, 0xD, 0x0D);
+       snd_soc_write(codec, 0x8, 0x5C);
+       snd_soc_write(codec, 0x8, 0x5D);
+       snd_soc_write(codec, 0x8, 0x5C);
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
+       cache[0xD] = tmp1;
+       cache[0x8] = tmp2;
 
        return 0;
 }
 
+static int aic3x_regulator_event(struct notifier_block *nb,
+                                unsigned long event, void *data)
+{
+       struct aic3x_disable_nb *disable_nb =
+               container_of(nb, struct aic3x_disable_nb, nb);
+       struct aic3x_priv *aic3x = disable_nb->aic3x;
+
+       if (event & REGULATOR_EVENT_DISABLE) {
+               /*
+                * Put codec to reset and require cache sync as at least one
+                * of the supplies was disabled
+                */
+               if (aic3x->gpio_reset >= 0)
+                       gpio_set_value(aic3x->gpio_reset, 0);
+               aic3x->codec->cache_sync = 1;
+       }
+
+       return 0;
+}
+
+static int aic3x_set_power(struct snd_soc_codec *codec, int power)
+{
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+       u8 *cache = codec->reg_cache;
+
+       if (power) {
+               ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
+                                           aic3x->supplies);
+               if (ret)
+                       goto out;
+               aic3x->power = 1;
+               /*
+                * Reset release and cache sync is necessary only if some
+                * supply was off or if there were cached writes
+                */
+               if (!codec->cache_sync)
+                       goto out;
+
+               if (aic3x->gpio_reset >= 0) {
+                       udelay(1);
+                       gpio_set_value(aic3x->gpio_reset, 1);
+               }
+
+               /* Sync reg_cache with the hardware */
+               codec->cache_only = 0;
+               for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
+                       snd_soc_write(codec, i, cache[i]);
+               if (aic3x->model == AIC3X_MODEL_3007)
+                       aic3x_init_3007(codec);
+               codec->cache_sync = 0;
+       } else {
+               aic3x->power = 0;
+               /* HW writes are needless when bias is off */
+               codec->cache_only = 1;
+               ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
+                                            aic3x->supplies);
+       }
+out:
+       return ret;
+}
+
 static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
@@ -1013,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
                break;
        case SND_SOC_BIAS_PREPARE:
-               if (aic3x->master) {
+               if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
+                   aic3x->master) {
                        /* enable pll */
-                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
-                                   reg | PLL_ENABLE);
+                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                                     reg | PLL_ENABLE);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* fall through and disable pll */
-       case SND_SOC_BIAS_OFF:
-               if (aic3x->master) {
+               if (!aic3x->power)
+                       aic3x_set_power(codec, 1);
+               if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
+                   aic3x->master) {
                        /* disable pll */
-                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
-                                   reg & ~PLL_ENABLE);
+                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                                     reg & ~PLL_ENABLE);
                }
                break;
+       case SND_SOC_BIAS_OFF:
+               if (aic3x->power)
+                       aic3x_set_power(codec, 0);
+               break;
        }
        codec->bias_level = level;
 
@@ -1040,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
 {
        u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
        u8 bit = gpio ? 3: 0;
-       u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
-       aic3x_write(codec, reg, val | (!!state << bit));
+       u8 val = snd_soc_read(codec, reg) & ~(1 << bit);
+       snd_soc_write(codec, reg, val | (!!state << bit));
 }
 EXPORT_SYMBOL_GPL(aic3x_set_gpio);
 
@@ -1070,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
        if (detect & AIC3X_HEADSET_DETECT_MASK)
                val |= AIC3X_HEADSET_DETECT_ENABLED;
 
-       aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
+       snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
 }
 EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
 
@@ -1101,8 +1229,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = {
        .set_fmt        = aic3x_set_dai_fmt,
 };
 
-struct snd_soc_dai aic3x_dai = {
-       .name = "tlv320aic3x",
+static struct snd_soc_dai_driver aic3x_dai = {
+       .name = "tlv320aic3x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1116,34 +1244,18 @@ struct snd_soc_dai aic3x_dai = {
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
        .ops = &aic3x_dai_ops,
+       .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(aic3x_dai);
 
-static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
+static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int aic3x_resume(struct platform_device *pdev)
+static int aic3x_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
-       u8 data[2];
-       u8 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
-               data[0] = i;
-               data[1] = cache[i];
-               codec->hw_write(codec->control_data, data, 2);
-       }
-
        aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1155,152 +1267,203 @@ static int aic3x_resume(struct platform_device *pdev)
  */
 static int aic3x_init(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int reg;
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "tlv320aic3x";
-       codec->owner = THIS_MODULE;
-       codec->read = aic3x_read_reg_cache;
-       codec->write = aic3x_write;
-       codec->set_bias_level = aic3x_set_bias_level;
-       codec->dai = &aic3x_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
-       codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
-
-       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
-       aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+       snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
 
        /* DAC default volume and mute */
-       aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
-       aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+       snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+       snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
 
        /* DAC to HP default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
        /* DAC to Line Out default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
        /* DAC to Mono Line Out default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
        /* unmute all outputs */
-       reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
-       aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
-       aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
-       aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
-       aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
-       aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
-       aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
-       aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, LLOPM_CTRL);
+       snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, RLOPM_CTRL);
+       snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, MONOLOPM_CTRL);
+       snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPLOUT_CTRL);
+       snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPROUT_CTRL);
+       snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPLCOM_CTRL);
+       snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPRCOM_CTRL);
+       snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE);
 
        /* ADC default volume and unmute */
-       aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
-       aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
+       snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
+       snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN);
        /* By default route Line1 to ADC PGA mixer */
-       aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
-       aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+       snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0);
+       snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0);
 
        /* PGA to HP Bypass default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
        /* PGA to Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
        /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
 
        /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
        /* Line2 Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
        /* Line2 to Mono Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 
-       /* off, with power on */
-       aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               aic3x_init_3007(codec);
+               snd_soc_write(codec, CLASSD_CTRL, 0);
+       }
 
        return 0;
 }
 
-static struct snd_soc_codec *aic3x_codec;
-
-static int aic3x_register(struct snd_soc_codec *codec)
+static int aic3x_probe(struct snd_soc_codec *codec)
 {
-       int ret;
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
 
-       ret = aic3x_init(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to initialise device\n");
+       codec->control_data = aic3x->control_data;
+       aic3x->codec = codec;
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       aic3x_codec = codec;
+       if (aic3x->gpio_reset >= 0) {
+               ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
+               if (ret != 0)
+                       goto err_gpio;
+               gpio_direction_output(aic3x->gpio_reset, 0);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+               aic3x->supplies[i].supply = aic3x_supply_names[i];
 
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec\n");
-               return ret;
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
+                                aic3x->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err_get;
+       }
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+               aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+               aic3x->disable_nb[i].aic3x = aic3x;
+               ret = regulator_register_notifier(aic3x->supplies[i].consumer,
+                                                 &aic3x->disable_nb[i].nb);
+               if (ret) {
+                       dev_err(codec->dev,
+                               "Failed to request regulator notifier: %d\n",
+                                ret);
+                       goto err_notif;
+               }
        }
 
-       ret = snd_soc_register_dai(&aic3x_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register dai\n");
-               snd_soc_unregister_codec(codec);
-               return ret;
+       codec->cache_only = 1;
+       aic3x_init(codec);
+
+       if (aic3x->setup) {
+               /* setup GPIO functions */
+               snd_soc_write(codec, AIC3X_GPIO1_REG,
+                             (aic3x->setup->gpio_func[0] & 0xf) << 4);
+               snd_soc_write(codec, AIC3X_GPIO2_REG,
+                             (aic3x->setup->gpio_func[1] & 0xf) << 4);
        }
 
+       snd_soc_add_controls(codec, aic3x_snd_controls,
+                            ARRAY_SIZE(aic3x_snd_controls));
+       if (aic3x->model == AIC3X_MODEL_3007)
+               snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+
+       aic3x_add_widgets(codec);
+
        return 0;
+
+err_notif:
+       while (i--)
+               regulator_unregister_notifier(aic3x->supplies[i].consumer,
+                                             &aic3x->disable_nb[i].nb);
+       regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+err_get:
+       if (aic3x->gpio_reset >= 0)
+               gpio_free(aic3x->gpio_reset);
+err_gpio:
+       kfree(aic3x);
+       return ret;
 }
 
-static int aic3x_unregister(struct aic3x_priv *aic3x)
+static int aic3x_remove(struct snd_soc_codec *codec)
 {
-       aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_unregister_dai(&aic3x_dai);
-       snd_soc_unregister_codec(&aic3x->codec);
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int i;
 
+       aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        if (aic3x->gpio_reset >= 0) {
                gpio_set_value(aic3x->gpio_reset, 0);
                gpio_free(aic3x->gpio_reset);
        }
-       regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+               regulator_unregister_notifier(aic3x->supplies[i].consumer,
+                                             &aic3x->disable_nb[i].nb);
        regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
 
-       kfree(aic3x);
-       aic3x_codec = NULL;
-
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+       .set_bias_level = aic3x_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(aic3x_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = aic3x_reg,
+       .probe = aic3x_probe,
+       .remove = aic3x_remove,
+       .suspend = aic3x_suspend,
+       .resume = aic3x_resume,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * AIC3X 2 wire address can be up to 4 devices with device addresses
  * 0x18, 0x19, 0x1A, 0x1B
  */
 
+static const struct i2c_device_id aic3x_i2c_id[] = {
+       [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
+       [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
+       [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
 /*
  * If the i2c layer weren't so broken, we could pass this kind of data
  * around
@@ -1308,10 +1471,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
 static int aic3x_i2c_probe(struct i2c_client *i2c,
                           const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
-       struct aic3x_priv *aic3x;
        struct aic3x_pdata *pdata = i2c->dev.platform_data;
-       int ret, i;
+       struct aic3x_priv *aic3x;
+       int ret;
+       const struct i2c_device_id *tbl;
 
        aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
        if (aic3x == NULL) {
@@ -1319,75 +1482,41 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
        }
 
-       codec = &aic3x->codec;
-       codec->dev = &i2c->dev;
-       snd_soc_codec_set_drvdata(codec, aic3x);
-       codec->control_data = i2c;
-       codec->hw_write = (hw_write_t) i2c_master_send;
+       aic3x->control_data = i2c;
+       aic3x->control_type = SND_SOC_I2C;
 
        i2c_set_clientdata(i2c, aic3x);
-
-       aic3x->gpio_reset = -1;
-       if (pdata && pdata->gpio_reset >= 0) {
-               ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
-               if (ret != 0)
-                       goto err_gpio;
+       if (pdata) {
                aic3x->gpio_reset = pdata->gpio_reset;
-               gpio_direction_output(aic3x->gpio_reset, 0);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
-               aic3x->supplies[i].supply = aic3x_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
-                                aic3x->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
-                                   aic3x->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_enable;
+               aic3x->setup = pdata->setup;
+       } else {
+               aic3x->gpio_reset = -1;
        }
 
-       if (aic3x->gpio_reset >= 0) {
-               udelay(1);
-               gpio_set_value(aic3x->gpio_reset, 1);
+       for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
+               if (!strcmp(tbl->name, id->name))
+                       break;
        }
+       aic3x->model = tbl - aic3x_i2c_id;
 
-       return aic3x_register(codec);
-
-err_enable:
-       regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
-err_get:
-       if (aic3x->gpio_reset >= 0)
-               gpio_free(aic3x->gpio_reset);
-err_gpio:
-       kfree(aic3x);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_aic3x, &aic3x_dai, 1);
+       if (ret < 0)
+               kfree(aic3x);
        return ret;
 }
 
 static int aic3x_i2c_remove(struct i2c_client *client)
 {
-       struct aic3x_priv *aic3x = i2c_get_clientdata(client);
-
-       return aic3x_unregister(aic3x);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
-static const struct i2c_device_id aic3x_i2c_id[] = {
-       { "tlv320aic3x", 0 },
-       { "tlv320aic33", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
-
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
        .driver = {
-               .name = "aic3x I2C Codec",
+               .name = "tlv320aic3x-codec",
                .owner = THIS_MODULE,
        },
        .probe  = aic3x_i2c_probe,
@@ -1409,90 +1538,27 @@ static inline void aic3x_i2c_exit(void)
 {
        i2c_del_driver(&aic3x_i2c_driver);
 }
-#else
-static inline void aic3x_i2c_init(void) { }
-static inline void aic3x_i2c_exit(void) { }
 #endif
 
-static int aic3x_probe(struct platform_device *pdev)
+static int __init aic3x_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct aic3x_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       codec = aic3x_codec;
-       if (!codec) {
-               dev_err(&pdev->dev, "Codec not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = codec;
-       setup = socdev->codec_data;
-
-       if (setup) {
-               /* setup GPIO functions */
-               aic3x_write(codec, AIC3X_GPIO1_REG,
-                           (setup->gpio_func[0] & 0xf) << 4);
-               aic3x_write(codec, AIC3X_GPIO2_REG,
-                           (setup->gpio_func[1] & 0xf) << 4);
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "aic3x: failed to create pcms\n");
-               goto pcm_err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&aic3x_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(codec, aic3x_snd_controls,
-                            ARRAY_SIZE(aic3x_snd_controls));
-
-       aic3x_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       kfree(codec->reg_cache);
+#endif
        return ret;
 }
-
-static int aic3x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       /* power down chip */
-       if (codec->control_data)
-               aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       kfree(codec->reg_cache);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_aic3x = {
-       .probe = aic3x_probe,
-       .remove = aic3x_remove,
-       .suspend = aic3x_suspend,
-       .resume = aic3x_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
-
-static int __init aic3x_modinit(void)
-{
-       aic3x_i2c_init();
-
-       return 0;
-}
 module_init(aic3x_modinit);
 
 static void __exit aic3x_exit(void)
 {
-       aic3x_i2c_exit();
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&aic3x_i2c_driver);
+#endif
 }
 module_exit(aic3x_exit);
 
index 9af1c886213c0f1d432014ea65a259dfea4ecfd8..06a19784b162dddfd2f719d850deaf45d52dfef6 100644 (file)
 /* DAC Digital control registers */
 #define LDAC_VOL                       43
 #define RDAC_VOL                       44
-/* High Power Output control registers */
+/* Left High Power Output control registers */
 #define LINE2L_2_HPLOUT_VOL            45
-#define LINE2R_2_HPROUT_VOL            62
 #define PGAL_2_HPLOUT_VOL              46
-#define PGAL_2_HPROUT_VOL              60
-#define PGAR_2_HPLOUT_VOL              49
-#define PGAR_2_HPROUT_VOL              63
 #define DACL1_2_HPLOUT_VOL             47
-#define DACR1_2_HPROUT_VOL             64
+#define LINE2R_2_HPLOUT_VOL            48
+#define PGAR_2_HPLOUT_VOL              49
+#define DACR1_2_HPLOUT_VOL             50
 #define HPLOUT_CTRL                    51
-#define HPROUT_CTRL                    65
-/* High Power COM control registers */
+/* Left High Power COM control registers */
 #define LINE2L_2_HPLCOM_VOL            52
-#define LINE2R_2_HPRCOM_VOL            69
 #define PGAL_2_HPLCOM_VOL              53
+#define DACL1_2_HPLCOM_VOL             54
+#define LINE2R_2_HPLCOM_VOL            55
 #define PGAR_2_HPLCOM_VOL              56
+#define DACR1_2_HPLCOM_VOL             57
+#define HPLCOM_CTRL                    58
+/* Right High Power Output control registers */
+#define LINE2L_2_HPROUT_VOL            59
+#define PGAL_2_HPROUT_VOL              60
+#define DACL1_2_HPROUT_VOL             61
+#define LINE2R_2_HPROUT_VOL            62
+#define PGAR_2_HPROUT_VOL              63
+#define DACR1_2_HPROUT_VOL             64
+#define HPROUT_CTRL                    65
+/* Right High Power COM control registers */
+#define LINE2L_2_HPRCOM_VOL            66
 #define PGAL_2_HPRCOM_VOL              67
+#define DACL1_2_HPRCOM_VOL             68
+#define LINE2R_2_HPRCOM_VOL            69
 #define PGAR_2_HPRCOM_VOL              70
-#define DACL1_2_HPLCOM_VOL             54
 #define DACR1_2_HPRCOM_VOL             71
-#define HPLCOM_CTRL                    58
 #define HPRCOM_CTRL                    72
 /* Mono Line Output Plus/Minus control registers */
 #define LINE2L_2_MONOLOPM_VOL          73
-#define LINE2R_2_MONOLOPM_VOL          76
 #define PGAL_2_MONOLOPM_VOL            74
-#define PGAR_2_MONOLOPM_VOL            77
 #define DACL1_2_MONOLOPM_VOL           75
+#define LINE2R_2_MONOLOPM_VOL          76
+#define PGAR_2_MONOLOPM_VOL            77
 #define DACR1_2_MONOLOPM_VOL           78
 #define MONOLOPM_CTRL                  79
-/* Line Output Plus/Minus control registers */
+/* Class-D speaker driver on tlv320aic3007 */
+#define CLASSD_CTRL                    73
+/* Left Line Output Plus/Minus control registers */
 #define LINE2L_2_LLOPM_VOL             80
-#define LINE2L_2_RLOPM_VOL             87
-#define LINE2R_2_LLOPM_VOL             83
-#define LINE2R_2_RLOPM_VOL             90
 #define PGAL_2_LLOPM_VOL               81
-#define PGAL_2_RLOPM_VOL               88
-#define PGAR_2_LLOPM_VOL               84
-#define PGAR_2_RLOPM_VOL               91
 #define DACL1_2_LLOPM_VOL              82
-#define DACL1_2_RLOPM_VOL              89
-#define DACR1_2_RLOPM_VOL              92
+#define LINE2R_2_LLOPM_VOL             83
+#define PGAR_2_LLOPM_VOL               84
 #define DACR1_2_LLOPM_VOL              85
 #define LLOPM_CTRL                     86
+/* Right Line Output Plus/Minus control registers */
+#define LINE2L_2_RLOPM_VOL             87
+#define PGAL_2_RLOPM_VOL               88
+#define DACL1_2_RLOPM_VOL              89
+#define LINE2R_2_RLOPM_VOL             90
+#define PGAR_2_RLOPM_VOL               91
+#define DACR1_2_RLOPM_VOL              92
 #define RLOPM_CTRL                     93
 /* GPIO/IRQ registers */
 #define AIC3X_STICKY_IRQ_FLAGS_REG     96
 /* Default input volume */
 #define DEFAULT_GAIN    0x20
 
-/* GPIO API */
-enum {
-       AIC3X_GPIO1_FUNC_DISABLED               = 0,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
-       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
-       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
-       AIC3X_GPIO1_FUNC_INPUT                  = 8,
-       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
-       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
-       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
-       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
-};
-
-enum {
-       AIC3X_GPIO2_FUNC_DISABLED               = 0,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
-       AIC3X_GPIO2_FUNC_INPUT                  = 3,
-       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
-       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
-       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
-       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
-       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
-       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
-       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
-};
-
 void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
 int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
 
@@ -281,11 +258,4 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
 int aic3x_headset_detected(struct snd_soc_codec *codec);
 int aic3x_button_pressed(struct snd_soc_codec *codec);
 
-struct aic3x_setup_data {
-       unsigned int gpio_func[2];
-};
-
-extern struct snd_soc_dai aic3x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_aic3x;
-
 #endif /* _AIC3X_H */
index 8651b01ed22358a636abdd7ba2c63e051ae95461..d251ff54a2d36f8b691b4aca2073d74adb010673 100644 (file)
@@ -66,8 +66,6 @@
 static void dac33_calculate_times(struct snd_pcm_substream *substream);
 static int dac33_prepare_chip(struct snd_pcm_substream *substream);
 
-static struct snd_soc_codec *tlv320dac33_codec;
-
 enum dac33_state {
        DAC33_IDLE = 0,
        DAC33_PREFILL,
@@ -93,7 +91,7 @@ struct tlv320dac33_priv {
        struct mutex mutex;
        struct workqueue_struct *dac33_wq;
        struct work_struct work;
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
        struct snd_pcm_substream *substream;
        int power_gpio;
@@ -128,6 +126,8 @@ struct tlv320dac33_priv {
        unsigned int uthr;
 
        enum dac33_state state;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
                            dac33_fifo_mode_texts);
 
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+       "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+       "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+       SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+                       ARRAY_SIZE(lr_lineout_gain_texts),
+                       lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+       SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+                       ARRAY_SIZE(lr_lineout_gain_texts),
+                       lr_lineout_gain_texts);
+
 /*
  * DACL/R digital volume control:
  * from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
                 DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
        SOC_DOUBLE_R("Line to Line Out Volume",
                 DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+       SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+       SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
 };
 
 static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
@@ -650,9 +668,8 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
 
 static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 {
-       struct snd_soc_codec *codec;
-
-       codec = &dac33->codec;
+       struct snd_soc_codec *codec = dac33->codec;
+       unsigned int delay;
 
        switch (dac33->fifo_mode) {
        case DAC33_FIFO_MODE1:
@@ -668,8 +685,9 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
                dac33_write16(codec, DAC33_PREFILL_MSB,
                                DAC33_THRREG(dac33->alarm_threshold));
                /* Enable Alarm Threshold IRQ with a delay */
-               udelay(SAMPLES_TO_US(dac33->burst_rate,
-                                    dac33->alarm_threshold));
+               delay = SAMPLES_TO_US(dac33->burst_rate,
+                                    dac33->alarm_threshold) + 1000;
+               usleep_range(delay, delay + 500);
                dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
                break;
        case DAC33_FIFO_MODE7:
@@ -695,9 +713,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 
 static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 {
-       struct snd_soc_codec *codec;
-
-       codec = &dac33->codec;
+       struct snd_soc_codec *codec = dac33->codec;
 
        switch (dac33->fifo_mode) {
        case DAC33_FIFO_MODE1:
@@ -726,7 +742,7 @@ static void dac33_work(struct work_struct *work)
        u8 reg;
 
        dac33 = container_of(work, struct tlv320dac33_priv, work);
-       codec = &dac33->codec;
+       codec = dac33->codec;
 
        mutex_lock(&dac33->mutex);
        switch (dac33->state) {
@@ -771,11 +787,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 
 static void dac33_oscwait(struct snd_soc_codec *codec)
 {
-       int timeout = 20;
+       int timeout = 60;
        u8 reg;
 
        do {
-               msleep(1);
+               usleep_range(1000, 2000);
                dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
        } while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
        if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
@@ -787,8 +803,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        /* Stream started, save the substream pointer */
@@ -801,8 +816,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33->substream = NULL;
@@ -817,8 +831,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Check parameters for validity */
        switch (params_rate(params)) {
@@ -856,8 +869,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
        u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1049,8 +1061,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 static void dac33_calculate_times(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int period_size = substream->runtime->period_size;
        unsigned int rate = substream->runtime->rate;
@@ -1129,8 +1140,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
@@ -1163,8 +1173,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned long long t0, t1, t_now;
        unsigned int time_delta, uthr;
@@ -1389,24 +1398,46 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-static int dac33_soc_probe(struct platform_device *pdev)
+static int dac33_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct tlv320dac33_priv *dac33;
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       BUG_ON(!tlv320dac33_codec);
+       codec->control_data = dac33->control_data;
+       codec->hw_write = (hw_write_t) i2c_master_send;
+       codec->idle_bias_off = 1;
+       dac33->codec = codec;
 
-       codec = tlv320dac33_codec;
-       socdev->card->codec = codec;
-       dac33 = snd_soc_codec_get_drvdata(codec);
+       /* Read the tlv320dac33 ID registers */
+       ret = dac33_hard_power(codec, 1);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+               goto err_power;
+       }
+       dac33_read_id(codec);
+       dac33_hard_power(codec, 0);
+
+       /* Check if the IRQ number is valid and request it */
+       if (dac33->irq >= 0) {
+               ret = request_irq(dac33->irq, dac33_interrupt_handler,
+                                 IRQF_TRIGGER_RISING | IRQF_DISABLED,
+                                 codec->name, codec);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+                                               dac33->irq, ret);
+                       dac33->irq = -1;
+               }
+               if (dac33->irq != -1) {
+                       /* Setup work queue */
+                       dac33->dac33_wq =
+                               create_singlethread_workqueue("tlv320dac33");
+                       if (dac33->dac33_wq == NULL) {
+                               free_irq(dac33->irq, codec);
+                               return -ENOMEM;
+                       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               goto pcm_err;
+                       INIT_WORK(&dac33->work, dac33_work);
+               }
        }
 
        snd_soc_add_controls(codec, dac33_snd_controls,
@@ -1420,56 +1451,51 @@ static int dac33_soc_probe(struct platform_device *pdev)
                        snd_soc_add_controls(codec, dac33_fifo_snd_controls,
                                        ARRAY_SIZE(dac33_fifo_snd_controls));
        }
-
        dac33_add_widgets(codec);
 
-       return 0;
-
-pcm_err:
-       dac33_hard_power(codec, 0);
+err_power:
        return ret;
 }
 
-static int dac33_soc_remove(struct platform_device *pdev)
+static int dac33_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       if (dac33->irq >= 0) {
+               free_irq(dac33->irq, dac33->codec);
+               destroy_workqueue(dac33->dac33_wq);
+       }
        return 0;
 }
 
-static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int dac33_soc_resume(struct platform_device *pdev)
+static int dac33_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+       .read = dac33_read_reg_cache,
+       .write = dac33_write_locked,
+       .set_bias_level = dac33_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(dac33_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = dac33_reg,
        .probe = dac33_soc_probe,
        .remove = dac33_soc_remove,
        .suspend = dac33_soc_suspend,
        .resume = dac33_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
 
 #define DAC33_RATES    (SNDRV_PCM_RATE_44100 | \
                         SNDRV_PCM_RATE_48000)
@@ -1485,8 +1511,8 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
        .set_fmt        = dac33_set_dai_fmt,
 };
 
-struct snd_soc_dai dac33_dai = {
-       .name = "tlv320dac33",
+static struct snd_soc_dai_driver dac33_dai = {
+       .name = "tlv320dac33-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -1495,14 +1521,12 @@ struct snd_soc_dai dac33_dai = {
                .formats = DAC33_FORMATS,},
        .ops = &dac33_dai_ops,
 };
-EXPORT_SYMBOL_GPL(dac33_dai);
 
 static int __devinit dac33_i2c_probe(struct i2c_client *client,
                                     const struct i2c_device_id *id)
 {
        struct tlv320dac33_platform_data *pdata;
        struct tlv320dac33_priv *dac33;
-       struct snd_soc_codec *codec;
        int ret, i;
 
        if (client->dev.platform_data == NULL) {
@@ -1515,33 +1539,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
        if (dac33 == NULL)
                return -ENOMEM;
 
-       codec = &dac33->codec;
-       snd_soc_codec_set_drvdata(codec, dac33);
-       codec->control_data = client;
-
-       mutex_init(&codec->mutex);
+       dac33->control_data = client;
        mutex_init(&dac33->mutex);
        spin_lock_init(&dac33->lock);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "tlv320dac33";
-       codec->owner = THIS_MODULE;
-       codec->read = dac33_read_reg_cache;
-       codec->write = dac33_write_locked;
-       codec->hw_write = (hw_write_t) i2c_master_send;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = dac33_set_bias_level;
-       codec->idle_bias_off = 1;
-       codec->dai = &dac33_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
-       codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto error_reg;
-       }
 
        i2c_set_clientdata(client, dac33);
 
@@ -1561,125 +1561,59 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
        /* Disable FIFO use by default */
        dac33->fifo_mode = DAC33_FIFO_BYPASS;
 
-       tlv320dac33_codec = codec;
-
-       codec->dev = &client->dev;
-       dac33_dai.dev = codec->dev;
-
        /* Check if the reset GPIO number is valid and request it */
        if (dac33->power_gpio >= 0) {
                ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
                if (ret < 0) {
-                       dev_err(codec->dev,
+                       dev_err(&client->dev,
                                "Failed to request reset GPIO (%d)\n",
                                dac33->power_gpio);
-                       snd_soc_unregister_dai(&dac33_dai);
-                       snd_soc_unregister_codec(codec);
-                       goto error_gpio;
+                       goto err_gpio;
                }
                gpio_direction_output(dac33->power_gpio, 0);
        }
 
-       /* Check if the IRQ number is valid and request it */
-       if (dac33->irq >= 0) {
-               ret = request_irq(dac33->irq, dac33_interrupt_handler,
-                                 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-                                 codec->name, codec);
-               if (ret < 0) {
-                       dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
-                                               dac33->irq, ret);
-                       dac33->irq = -1;
-               }
-               if (dac33->irq != -1) {
-                       /* Setup work queue */
-                       dac33->dac33_wq =
-                               create_singlethread_workqueue("tlv320dac33");
-                       if (dac33->dac33_wq == NULL) {
-                               free_irq(dac33->irq, &dac33->codec);
-                               ret = -ENOMEM;
-                               goto error_wq;
-                       }
-
-                       INIT_WORK(&dac33->work, dac33_work);
-               }
-       }
-
        for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
                dac33->supplies[i].supply = dac33_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
+       ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
                                 dac33->supplies);
 
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
                goto err_get;
        }
 
-       /* Read the tlv320dac33 ID registers */
-       ret = dac33_hard_power(codec, 1);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
-               goto error_codec;
-       }
-       dac33_read_id(codec);
-       dac33_hard_power(codec, 0);
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_codec;
-       }
-
-       ret = snd_soc_register_dai(&dac33_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto error_codec;
-       }
+       ret = snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+       if (ret < 0)
+               goto err_register;
 
        return ret;
-
-error_codec:
+err_register:
        regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 err_get:
-       if (dac33->irq >= 0) {
-               free_irq(dac33->irq, &dac33->codec);
-               destroy_workqueue(dac33->dac33_wq);
-       }
-error_wq:
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
-error_gpio:
-       kfree(codec->reg_cache);
-error_reg:
-       tlv320dac33_codec = NULL;
+err_gpio:
        kfree(dac33);
-
        return ret;
 }
 
 static int __devexit dac33_i2c_remove(struct i2c_client *client)
 {
-       struct tlv320dac33_priv *dac33;
-
-       dac33 = i2c_get_clientdata(client);
+       struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
 
        if (unlikely(dac33->chip_power))
-               dac33_hard_power(&dac33->codec, 0);
+               dac33_hard_power(dac33->codec, 0);
 
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
-       if (dac33->irq >= 0)
-               free_irq(dac33->irq, &dac33->codec);
 
        regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 
-       destroy_workqueue(dac33->dac33_wq);
-       snd_soc_unregister_dai(&dac33_dai);
-       snd_soc_unregister_codec(&dac33->codec);
-       kfree(dac33->codec.reg_cache);
+       snd_soc_unregister_codec(&client->dev);
        kfree(dac33);
-       tlv320dac33_codec = NULL;
 
        return 0;
 }
@@ -1694,7 +1628,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
 
 static struct i2c_driver tlv320dac33_i2c_driver = {
        .driver = {
-               .name = "tlv320dac33",
+               .name = "tlv320dac33-codec",
                .owner = THIS_MODULE,
        },
        .probe          = dac33_i2c_probe,
index eb8ae07f0bd2e166003aeda14789e47799e82b2b..7c318b5da4370bfb1c8cee6af5e436161068203e 100644 (file)
 #define TLV320DAC33_MCLK               0
 #define TLV320DAC33_SLEEPCLK           1
 
-extern struct snd_soc_dai dac33_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
-
 #endif /* __TLV320DAC33_H */
index 99b70e5978a2ee122e6799df5f27e20711a93976..329acc1a207457942a560e86d7f990a2fc44ffd8 100644 (file)
@@ -98,16 +98,21 @@ static u8 tpa6130a2_read(int reg)
        return data->regs[reg];
 }
 
-static void tpa6130a2_initialize(void)
+static int tpa6130a2_initialize(void)
 {
        struct tpa6130a2_data *data;
-       int i;
+       int i, ret = 0;
 
        BUG_ON(tpa6130a2_client == NULL);
        data = i2c_get_clientdata(tpa6130a2_client);
 
-       for (i = 1; i < TPA6130A2_REG_VERSION; i++)
-               tpa6130a2_i2c_write(i, data->regs[i]);
+       for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
+               ret = tpa6130a2_i2c_write(i, data->regs[i]);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
 }
 
 static int tpa6130a2_power(int power)
@@ -133,7 +138,16 @@ static int tpa6130a2_power(int power)
                }
 
                data->power_state = 1;
-               tpa6130a2_initialize();
+               ret = tpa6130a2_initialize();
+               if (ret < 0) {
+                       dev_err(&tpa6130a2_client->dev,
+                               "Failed to initialize chip\n");
+                       if (data->power_gpio >= 0)
+                               gpio_set_value(data->power_gpio, 0);
+                       regulator_disable(data->supply);
+                       data->power_state = 0;
+                       goto exit;
+               }
 
                /* Clear SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
@@ -375,7 +389,9 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
 {
        struct  tpa6130a2_data *data;
 
-       BUG_ON(tpa6130a2_client == NULL);
+       if (tpa6130a2_client == NULL)
+               return -ENODEV;
+
        data = i2c_get_clientdata(tpa6130a2_client);
 
        snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
index 7b618bbff8844d65f55092780b199d4b213e433b..cbebec6ba1ba42fda499b018b9f6a1a6938eb1c6 100644 (file)
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "twl4030.h"
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-codec.h>
+
+/* Shadow register used by the audio driver */
+#define TWL4030_REG_SW_SHADOW          0x4A
+#define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
+
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN                 0x01
+#define TWL4030_HFR_EN                 0x02
 
 /*
  * twl4030 register cache & default register settings
@@ -277,21 +286,19 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
 
 }
 
-static void twl4030_init_chip(struct platform_device *pdev)
+static void twl4030_init_chip(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct twl4030_setup_data *setup = socdev->codec_data;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 reg, byte;
        int i = 0;
 
        /* Check defaults, if instructed before anything else */
-       if (setup && setup->check_defaults)
+       if (pdata && pdata->check_defaults)
                twl4030_check_defaults(codec);
 
        /* Reset registers, if no setup data or if instructed to do so */
-       if (!setup || (setup && setup->reset_registers))
+       if (!pdata || (pdata && pdata->reset_registers))
                twl4030_reset_registers(codec);
 
        /* Refresh APLL_CTL register from HW */
@@ -312,20 +319,14 @@ static void twl4030_init_chip(struct platform_device *pdev)
        twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
 
        /* Machine dependent setup */
-       if (!setup)
+       if (!pdata)
                return;
 
-       twl4030->digimic_delay = setup->digimic_delay;
-
-       /* Configuration for headset ramp delay from setup data */
-       if (setup->sysclk != twl4030->sysclk)
-               dev_warn(codec->dev,
-                               "Mismatch in APLL mclk: %u (configured: %u)\n",
-                               setup->sysclk, twl4030->sysclk);
+       twl4030->digimic_delay = pdata->digimic_delay;
 
        reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
        reg &= ~TWL4030_RAMP_DELAY;
-       reg |= (setup->ramp_delay_value << 2);
+       reg |= (pdata->ramp_delay_value << 2);
        twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
 
        /* initiate offset cancellation */
@@ -333,7 +334,7 @@ static void twl4030_init_chip(struct platform_device *pdev)
 
        reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
        reg &= ~TWL4030_OFFSET_CNCL_SEL;
-       reg |= setup->offset_cncl_path;
+       reg |= pdata->offset_cncl_path;
        twl4030_write(codec, TWL4030_REG_ANAMICL,
                reg | TWL4030_CNCL_OFFSET_START);
 
@@ -718,9 +719,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct snd_soc_device *socdev = codec->socdev;
-       struct twl4030_setup_data *setup = socdev->codec_data;
-
+       struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -732,9 +731,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 
        /* Enable external mute control, this dramatically reduces
         * the pop-noise */
-       if (setup && setup->hs_extmute) {
-               if (setup->set_hs_extmute) {
-                       setup->set_hs_extmute(1);
+       if (pdata && pdata->hs_extmute) {
+               if (pdata->set_hs_extmute) {
+                       pdata->set_hs_extmute(1);
                } else {
                        hs_pop |= TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -772,9 +771,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
        }
 
        /* Disable external mute */
-       if (setup && setup->hs_extmute) {
-               if (setup->set_hs_extmute) {
-                       setup->set_hs_extmute(0);
+       if (pdata && pdata->hs_extmute) {
+               if (pdata->set_hs_extmute) {
+                       pdata->set_hs_extmute(0);
                } else {
                        hs_pop &= ~TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -1707,8 +1706,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream) {
@@ -1738,8 +1736,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream == substream)
@@ -1764,8 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode, old_mode, format, old_format;
 
@@ -1999,8 +1995,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode;
 
@@ -2033,8 +2028,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Enable voice digital filters */
        twl4030_voice_enable(codec, substream->stream, 0);
@@ -2044,8 +2038,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 old_mode, mode;
 
@@ -2175,7 +2168,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 #define TWL4030_RATES   (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
 
-static struct snd_soc_dai_ops twl4030_dai_ops = {
+static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
        .startup        = twl4030_startup,
        .shutdown       = twl4030_shutdown,
        .hw_params      = twl4030_hw_params,
@@ -2193,9 +2186,9 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
        .set_tristate   = twl4030_voice_set_tristate,
 };
 
-struct snd_soc_dai twl4030_dai[] = {
+static struct snd_soc_dai_driver twl4030_dai[] = {
 {
-       .name = "twl4030",
+       .name = "twl4030-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 2,
@@ -2208,10 +2201,10 @@ struct snd_soc_dai twl4030_dai[] = {
                .channels_max = 4,
                .rates = TWL4030_RATES,
                .formats = TWL4030_FORMATS,},
-       .ops = &twl4030_dai_ops,
+       .ops = &twl4030_dai_hifi_ops,
 },
 {
-       .name = "twl4030 Voice",
+       .name = "twl4030-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -2227,164 +2220,91 @@ struct snd_soc_dai twl4030_dai[] = {
        .ops = &twl4030_dai_voice_ops,
 },
 };
-EXPORT_SYMBOL_GPL(twl4030_dai);
 
-static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
        return 0;
 }
 
-static int twl4030_soc_resume(struct platform_device *pdev)
+static int twl4030_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static struct snd_soc_codec *twl4030_codec;
-
-static int twl4030_soc_probe(struct platform_device *pdev)
+static int twl4030_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       BUG_ON(!twl4030_codec);
-
-       codec = twl4030_codec;
-       socdev->card->codec = codec;
-
-       twl4030_init_chip(pdev);
+       struct twl4030_priv *twl4030;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
+       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+       if (twl4030 == NULL) {
+               printk("Can not allocate memroy\n");
+               return -ENOMEM;
        }
+       snd_soc_codec_set_drvdata(codec, twl4030);
+       /* Set the defaults, and power up the codec */
+       twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
+       codec->idle_bias_off = 1;
+
+       twl4030_init_chip(codec);
 
        snd_soc_add_controls(codec, twl4030_snd_controls,
                                ARRAY_SIZE(twl4030_snd_controls));
        twl4030_add_widgets(codec);
-
        return 0;
 }
 
-static int twl4030_soc_remove(struct platform_device *pdev)
+static int twl4030_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* Reset registers to their chip default before leaving */
        twl4030_reset_registers(codec);
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+       .probe = twl4030_soc_probe,
+       .remove = twl4030_soc_remove,
+       .suspend = twl4030_soc_suspend,
+       .resume = twl4030_soc_resume,
+       .read = twl4030_read_reg_cache,
+       .write = twl4030_write,
+       .set_bias_level = twl4030_set_bias_level,
+       .reg_cache_size = sizeof(twl4030_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = twl4030_reg,
+};
+
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
        struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
-       struct snd_soc_codec *codec;
-       struct twl4030_priv *twl4030;
-       int ret;
 
        if (!pdata) {
                dev_err(&pdev->dev, "platform_data is missing\n");
                return -EINVAL;
        }
 
-       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
-       if (twl4030 == NULL) {
-               dev_err(&pdev->dev, "Can not allocate memroy\n");
-               return -ENOMEM;
-       }
-
-       codec = &twl4030->codec;
-       snd_soc_codec_set_drvdata(codec, twl4030);
-       codec->dev = &pdev->dev;
-       twl4030_dai[0].dev = &pdev->dev;
-       twl4030_dai[1].dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "twl4030";
-       codec->owner = THIS_MODULE;
-       codec->read = twl4030_read_reg_cache;
-       codec->write = twl4030_write;
-       codec->set_bias_level = twl4030_set_bias_level;
-       codec->idle_bias_off = 1;
-       codec->dai = twl4030_dai;
-       codec->num_dai = ARRAY_SIZE(twl4030_dai);
-       codec->reg_cache_size = sizeof(twl4030_reg);
-       codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto error_cache;
-       }
-
-       platform_set_drvdata(pdev, twl4030);
-       twl4030_codec = codec;
-
-       /* Set the defaults, and power up the codec */
-       twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_codec;
-       }
-
-       ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto error_codec;
-       }
-
-       return 0;
-
-error_codec:
-       twl4030_codec_enable(codec, 0);
-       kfree(codec->reg_cache);
-error_cache:
-       kfree(twl4030);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
+                       twl4030_dai, ARRAY_SIZE(twl4030_dai));
 }
 
 static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 {
-       struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
+       struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
-       snd_soc_unregister_codec(&twl4030->codec);
-       kfree(twl4030->codec.reg_cache);
+       snd_soc_unregister_codec(&pdev->dev);
        kfree(twl4030);
-
-       twl4030_codec = NULL;
        return 0;
 }
 
-MODULE_ALIAS("platform:twl4030_codec_audio");
+MODULE_ALIAS("platform:twl4030-codec");
 
 static struct platform_driver twl4030_codec_driver = {
        .probe          = twl4030_codec_probe,
        .remove         = __devexit_p(twl4030_codec_remove),
        .driver         = {
-               .name   = "twl4030_codec_audio",
+               .name   = "twl4030-codec",
                .owner  = THIS_MODULE,
        },
 };
@@ -2401,14 +2321,6 @@ static void __exit twl4030_exit(void)
 }
 module_exit(twl4030_exit);
 
-struct snd_soc_codec_device soc_codec_dev_twl4030 = {
-       .probe = twl4030_soc_probe,
-       .remove = twl4030_soc_remove,
-       .suspend = twl4030_soc_suspend,
-       .resume = twl4030_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
-
 MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
 MODULE_AUTHOR("Steve Sakoman");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
deleted file mode 100644 (file)
index 6c57430..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ALSA SoC TWL4030 codec driver
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TWL4030_AUDIO_H__
-#define __TWL4030_AUDIO_H__
-
-/* Register descriptions are here */
-#include <linux/mfd/twl4030-codec.h>
-
-/* Shadow register used by the audio driver */
-#define TWL4030_REG_SW_SHADOW          0x4A
-#define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
-
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
-#define TWL4030_HFL_EN                 0x01
-#define TWL4030_HFR_EN                 0x02
-
-#define TWL4030_DAI_HIFI               0
-#define TWL4030_DAI_VOICE              1
-
-extern struct snd_soc_dai twl4030_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_twl4030;
-
-struct twl4030_setup_data {
-       unsigned int ramp_delay_value;
-       unsigned int digimic_delay; /* in ms */
-       unsigned int sysclk;
-       unsigned int offset_cncl_path;
-       unsigned int check_defaults:1;
-       unsigned int reset_registers:1;
-       unsigned int hs_extmute:1;
-       void (*set_hs_extmute)(int mute);
-};
-
-#endif /* End of __TWL4030_AUDIO_H__ */
-
-
index 64a807f1a8a1812e4b01d891b8809f69ce1bf1f9..10f6e521451161dbdd169b59d69101a3010f41c3 100644 (file)
@@ -45,7 +45,6 @@
 
 /* codec private data */
 struct twl6040_data {
-       struct snd_soc_codec codec;
        int audpwron;
        int naudint;
        int codec_powered;
@@ -770,8 +769,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        if (!priv->sysclk) {
@@ -803,8 +801,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        u8 lppllctl;
        int rate;
@@ -839,8 +836,7 @@ static int twl6040_trigger(struct snd_pcm_substream *substream,
                        int cmd, struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        switch (cmd) {
@@ -978,8 +974,8 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
        .set_sysclk     = twl6040_set_dai_sysclk,
 };
 
-struct snd_soc_dai twl6040_dai = {
-       .name = "twl6040",
+static struct snd_soc_dai_driver twl6040_dai = {
+       .name = "twl6040-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -996,24 +992,17 @@ struct snd_soc_dai twl6040_dai = {
        },
        .ops = &twl6040_dai_ops,
 };
-EXPORT_SYMBOL_GPL(twl6040_dai);
 
 #ifdef CONFIG_PM
-static int twl6040_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int twl6040_resume(struct platform_device *pdev)
+static int twl6040_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1023,68 +1012,9 @@ static int twl6040_resume(struct platform_device *pdev)
 #define twl6040_resume NULL
 #endif
 
-static struct snd_soc_codec *twl6040_codec;
-
-static int twl6040_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       BUG_ON(!twl6040_codec);
-
-       codec = twl6040_codec;
-       socdev->card->codec = codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
-       }
-
-       snd_soc_add_controls(codec, twl6040_snd_controls,
-                               ARRAY_SIZE(twl6040_snd_controls));
-       twl6040_add_widgets(codec);
-
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register card\n");
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       return ret;
-}
-
-static int twl6040_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_twl6040 = {
-       .probe = twl6040_probe,
-       .remove = twl6040_remove,
-       .suspend = twl6040_suspend,
-       .resume = twl6040_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl6040);
-
-static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+static int twl6040_probe(struct snd_soc_codec *codec)
 {
-       struct twl4030_codec_data *twl_codec = pdev->dev.platform_data;
-       struct snd_soc_codec *codec;
+       struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
        struct twl6040_data *priv;
        int audpwron, naudint;
        int ret = 0;
@@ -1092,6 +1022,7 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, priv);
 
        if (twl_codec) {
                audpwron = twl_codec->audpwron_gpio;
@@ -1104,29 +1035,6 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        priv->audpwron = audpwron;
        priv->naudint = naudint;
 
-       codec = &priv->codec;
-       codec->dev = &pdev->dev;
-       twl6040_dai.dev = &pdev->dev;
-
-       codec->name = "twl6040";
-       codec->owner = THIS_MODULE;
-       codec->read = twl6040_read_reg_cache;
-       codec->write = twl6040_write;
-       codec->set_bias_level = twl6040_set_bias_level;
-       snd_soc_codec_set_drvdata(codec, priv);
-       codec->dai = &twl6040_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(twl6040_reg);
-       codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
        init_completion(&priv->ready);
 
        if (gpio_is_valid(audpwron)) {
@@ -1169,23 +1077,12 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        if (ret)
                goto irq_err;
 
-       ret = snd_soc_register_codec(codec);
-       if (ret)
-               goto reg_err;
-
-       twl6040_codec = codec;
-
-       ret = snd_soc_register_dai(&twl6040_dai);
-       if (ret)
-               goto dai_err;
+       snd_soc_add_controls(codec, twl6040_snd_controls,
+                               ARRAY_SIZE(twl6040_snd_controls));
+       twl6040_add_widgets(codec);
 
        return 0;
 
-dai_err:
-       snd_soc_unregister_codec(codec);
-       twl6040_codec = NULL;
-reg_err:
-       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 irq_err:
        if (naudint)
                free_irq(naudint, codec);
@@ -1193,36 +1090,57 @@ gpio2_err:
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 gpio1_err:
-       kfree(codec->reg_cache);
-cache_err:
        kfree(priv);
        return ret;
 }
 
-static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+static int twl6040_remove(struct snd_soc_codec *codec)
 {
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(twl6040_codec);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int audpwron = priv->audpwron;
        int naudint = priv->naudint;
 
+       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 
        if (naudint)
-               free_irq(naudint, twl6040_codec);
+               free_irq(naudint, codec);
 
-       snd_soc_unregister_dai(&twl6040_dai);
-       snd_soc_unregister_codec(twl6040_codec);
+       kfree(priv);
 
-       kfree(twl6040_codec);
-       twl6040_codec = NULL;
+       return 0;
+}
 
+static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+       .probe = twl6040_probe,
+       .remove = twl6040_remove,
+       .suspend = twl6040_suspend,
+       .resume = twl6040_resume,
+       .read = twl6040_read_reg_cache,
+       .write = twl6040_write,
+       .set_bias_level = twl6040_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(twl6040_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = twl6040_reg,
+};
+
+static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_twl6040, &twl6040_dai, 1);
+}
+
+static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver twl6040_codec_driver = {
        .driver = {
-               .name = "twl6040_codec",
+               .name = "twl6040-codec",
                .owner = THIS_MODULE,
        },
        .probe = twl6040_codec_probe,
index c472070a1da2c93544cc67e9fe827eb5d146eccd..f7c77fa58a3c4b5de3e836dfd7cdc98b4c15b52f 100644 (file)
 #define TWL6040_HPPLL_ID               1
 #define TWL6040_LPPLL_ID               2
 
-extern struct snd_soc_dai twl6040_dai;
-extern struct snd_soc_codec_device soc_codec_dev_twl6040;
-
 #endif /* End of __TWL6040_H__ */
index f3b4c1d6a82d1927975d80c303a62d38448bb238..7540a509a6f58acec8c29aad5c76b65a86a5f83a 100644 (file)
@@ -161,8 +161,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        struct snd_pcm_runtime *master_runtime;
 
@@ -194,8 +193,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
        if (uda134x->master_substream == substream)
@@ -209,8 +207,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        u8 hw_params;
 
@@ -364,7 +361,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                        pd->power(1);
                        /* Sync reg_cache with the hardware */
                        for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
-                               codec->write(codec, i, *cache++);
+                               codec->driver->write(codec, i, *cache++);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
@@ -465,8 +462,8 @@ static struct snd_soc_dai_ops uda134x_dai_ops = {
        .set_fmt        = uda134x_set_dai_fmt,
 };
 
-struct snd_soc_dai uda134x_dai = {
-       .name = "UDA134X",
+static struct snd_soc_dai_driver uda134x_dai = {
+       .name = "uda134x-hifi",
        /* playback capabilities */
        .playback = {
                .stream_name = "Playback",
@@ -486,27 +483,21 @@ struct snd_soc_dai uda134x_dai = {
        /* pcm operations */
        .ops = &uda134x_dai_ops,
 };
-EXPORT_SYMBOL(uda134x_dai);
 
-
-static int uda134x_soc_probe(struct platform_device *pdev)
+static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        struct uda134x_priv *uda134x;
-       void *codec_setup_data = socdev->codec_data;
-       int ret = -ENOMEM;
-       struct uda134x_platform_data *pd;
+       struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
+       int ret;
 
        printk(KERN_INFO "UDA134X SoC Audio Codec\n");
 
-       if (!codec_setup_data) {
+       if (!pd) {
                printk(KERN_ERR "UDA134X SoC codec: "
                       "missing L3 bitbang function\n");
                return -ENODEV;
        }
 
-       pd = codec_setup_data;
        switch (pd->model) {
        case UDA134X_UDA1340:
        case UDA134X_UDA1341:
@@ -520,58 +511,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return ret;
-
-       codec = socdev->card->codec;
-
        uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
        if (uda134x == NULL)
-               goto priv_err;
+               return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, uda134x);
 
-       codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               goto reg_err;
-
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache_size = sizeof(uda134x_reg);
-       codec->reg_cache_step = 1;
-
-       codec->name = "UDA134X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &uda134x_dai;
-       codec->num_dai = 1;
-       codec->read = uda134x_read_reg_cache;
-       codec->write = uda134x_write;
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->control_data = codec_setup_data;
+       codec->control_data = pd;
 
        if (pd->power)
                pd->power(1);
 
        uda134x_reset(codec);
 
-       if (pd->is_powered_on_standby) {
-               codec->set_bias_level = NULL;
+       if (pd->is_powered_on_standby)
                uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
-       } else {
-               codec->set_bias_level = uda134x_set_bias_level;
+       else
                uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "UDA134X: failed to register pcms\n");
-               goto pcm_err;
-       }
 
        switch (pd->model) {
        case UDA134X_UDA1340:
@@ -590,61 +545,42 @@ static int uda134x_soc_probe(struct platform_device *pdev)
        default:
                printk(KERN_ERR "%s unknown codec type: %d",
                        __func__, pd->model);
-       return -EINVAL;
+               kfree(uda134x);
+               return -EINVAL;
        }
 
        if (ret < 0) {
                printk(KERN_ERR "UDA134X: failed to register controls\n");
-               goto pcm_err;
+               kfree(uda134x);
+               return ret;
        }
 
        return 0;
-
-pcm_err:
-       kfree(codec->reg_cache);
-reg_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-priv_err:
-       kfree(codec);
-       return ret;
 }
 
 /* power down chip */
-static int uda134x_soc_remove(struct platform_device *pdev)
+static int uda134x_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec->reg_cache);
-       kfree(codec);
-
+       kfree(uda134x);
        return 0;
 }
 
 #if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct platform_device *pdev,
+static int uda134x_soc_suspend(struct snd_soc_codec *codec,
                                                pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int uda134x_soc_resume(struct platform_device *pdev)
+static int uda134x_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
        return 0;
@@ -654,25 +590,53 @@ static int uda134x_soc_resume(struct platform_device *pdev)
 #define uda134x_soc_resume NULL
 #endif /* CONFIG_PM */
 
-struct snd_soc_codec_device soc_codec_dev_uda134x = {
+static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .probe =        uda134x_soc_probe,
        .remove =       uda134x_soc_remove,
        .suspend =      uda134x_soc_suspend,
        .resume =       uda134x_soc_resume,
+       .reg_cache_size = sizeof(uda134x_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_step = 1,
+       .read = uda134x_read_reg_cache,
+       .write = uda134x_write,
+#ifdef POWER_OFF_ON_STANDBY
+       .set_bias_level = uda134x_set_bias_level,
+#endif
+};
+
+static int __devinit uda134x_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_uda134x, &uda134x_dai, 1);
+}
+
+static int __devexit uda134x_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver uda134x_codec_driver = {
+       .driver = {
+               .name = "uda134x-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = uda134x_codec_probe,
+       .remove = __devexit_p(uda134x_codec_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
 
-static int __init uda134x_init(void)
+static int __init uda134x_codec_init(void)
 {
-       return snd_soc_register_dai(&uda134x_dai);
+       return platform_driver_register(&uda134x_codec_driver);
 }
-module_init(uda134x_init);
+module_init(uda134x_codec_init);
 
-static void __exit uda134x_exit(void)
+static void __exit uda134x_codec_exit(void)
 {
-       snd_soc_unregister_dai(&uda134x_dai);
+       platform_driver_unregister(&uda134x_codec_driver);
 }
-module_exit(uda134x_exit);
+module_exit(uda134x_codec_exit);
 
 MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
index 205f03b3eaf81674de74f4a60e8ac28cddbf4c83..9faae06972b32fc226cbb9450e84e86b7f6f271e 100644 (file)
@@ -31,7 +31,4 @@
 #define STATUS0_DAIFMT_MASK (~(7<<1))
 #define STATUS0_SYSCLK_MASK (~(3<<4))
 
-extern struct snd_soc_dai uda134x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_uda134x;
-
 #endif
index 2f925a27dcde2353f35566aa8dd2f057ebe3a971..0c6c725736c628b0046dad43cc9d30260483de8d 100644 (file)
 
 #include "uda1380.h"
 
-static struct snd_soc_codec *uda1380_codec;
-
 /* codec private data */
 struct uda1380_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        u16 reg_cache[UDA1380_CACHEREGNUM];
        unsigned int dac_clk;
        struct work_struct work;
+       void *control_data;
 };
 
 /*
@@ -131,10 +130,51 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-#define uda1380_reset(c)       uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_sync_cache(struct snd_soc_codec *codec)
+{
+       int reg;
+       u8 data[3];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (reg = 0; reg < UDA1380_MVOL; reg++) {
+               data[0] = reg;
+               data[1] = (cache[reg] & 0xff00) >> 8;
+               data[2] = cache[reg] & 0x00ff;
+               if (codec->hw_write(codec->control_data, data, 3) != 3)
+                       dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+                               __func__, reg);
+       }
+}
+
+static int uda1380_reset(struct snd_soc_codec *codec)
+{
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               gpio_set_value(pdata->gpio_reset, 1);
+               mdelay(1);
+               gpio_set_value(pdata->gpio_reset, 0);
+       } else {
+               u8 data[3];
+
+               data[0] = UDA1380_RESET;
+               data[1] = 0;
+               data[2] = 0;
+
+               if (codec->hw_write(codec->control_data, data, 3) != 3) {
+                       dev_err(codec->dev, "%s: failed\n", __func__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
 
 static void uda1380_flush_work(struct work_struct *work)
 {
+       struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
+       struct snd_soc_codec *uda1380_codec = uda1380->codec;
        int bit, reg;
 
        for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
@@ -145,6 +185,7 @@ static void uda1380_flush_work(struct work_struct *work)
                                uda1380_read_reg_cache(uda1380_codec, reg));
                clear_bit(bit, &uda1380_cache_dirty);
        }
+
 }
 
 /* declarations of ALSA reg_elem_REAL controls */
@@ -474,8 +515,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
        int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
@@ -501,8 +541,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* set WSPLL power and divider if running from this clock */
@@ -540,8 +579,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* shut down WSPLL power if running from this clock */
@@ -562,18 +600,41 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
        int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+       int reg;
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (codec->bias_level == level)
+               return 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
+               /* ADC, DAC on */
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
-               break;
-       case SND_SOC_BIAS_OFF:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       if (gpio_is_valid(pdata->gpio_power)) {
+                               gpio_set_value(pdata->gpio_power, 1);
+                               mdelay(1);
+                               uda1380_reset(codec);
+                       }
+
+                       uda1380_sync_cache(codec);
+               }
                uda1380_write(codec, UDA1380_PM, 0x0);
                break;
+       case SND_SOC_BIAS_OFF:
+               if (!gpio_is_valid(pdata->gpio_power))
+                       break;
+
+               gpio_set_value(pdata->gpio_power, 0);
+
+               /* Mark mixer regs cache dirty to sync them with
+                * codec regs on power on.
+                */
+               for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+                       set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
        codec->bias_level = level;
        return 0;
@@ -604,9 +665,9 @@ static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
        .set_fmt        = uda1380_set_dai_fmt_capture,
 };
 
-struct snd_soc_dai uda1380_dai[] = {
+static struct snd_soc_dai_driver uda1380_dai[] = {
 {
-       .name = "UDA1380",
+       .name = "uda1380-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -622,7 +683,7 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops,
 },
 { /* playback only - dual interface */
-       .name = "UDA1380",
+       .name = "uda1380-hifi-playback",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -633,7 +694,7 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops_playback,
 },
 { /* capture only - dual interface*/
-       .name = "UDA1380",
+       .name = "uda1380-hifi-capture",
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -644,67 +705,69 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops_capture,
 },
 };
-EXPORT_SYMBOL_GPL(uda1380_dai);
 
-static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
+static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int uda1380_resume(struct platform_device *pdev)
+static int uda1380_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
-       u8 data[2];
-       u16 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
-               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-               data[1] = cache[i] & 0x00ff;
-               codec->hw_write(codec->control_data, data, 2);
-       }
        uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static int uda1380_probe(struct platform_device *pdev)
+static int uda1380_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct uda1380_platform_data *pdata;
-       int ret = 0;
+       struct uda1380_platform_data *pdata =codec->dev->platform_data;
+       struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (uda1380_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
+       uda1380->codec = codec;
+
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       codec->control_data = uda1380->control_data;
+
+       if (!pdata)
+               return -EINVAL;
 
-       socdev->card->codec = uda1380_codec;
-       codec = uda1380_codec;
-       pdata = codec->dev->platform_data;
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+               if (ret)
+                       goto err_out;
+               ret = gpio_direction_output(pdata->gpio_reset, 0);
+               if (ret)
+                       goto err_gpio_reset_conf;
+       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+       if (gpio_is_valid(pdata->gpio_power)) {
+               ret = gpio_request(pdata->gpio_power, "uda1380 power");
+               if (ret)
+                       goto err_gpio;
+               ret = gpio_direction_output(pdata->gpio_power, 0);
+               if (ret)
+                       goto err_gpio_power_conf;
+       } else {
+               ret = uda1380_reset(codec);
+               if (ret) {
+                       dev_err(codec->dev, "Failed to issue reset\n");
+                       goto err_reset;
+               }
        }
 
+       INIT_WORK(&uda1380->work, uda1380_flush_work);
+
        /* power on device */
        uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        /* set clock input */
        switch (pdata->dac_clk) {
        case UDA1380_DAC_CLK_SYSCLK:
-               uda1380_write(codec, UDA1380_CLK, 0);
+               uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
                break;
        case UDA1380_DAC_CLK_WSPLL:
-               uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+               uda1380_write_reg_cache(codec, UDA1380_CLK,
+                       R00_DAC_CLK);
                break;
        }
 
@@ -712,167 +775,73 @@ static int uda1380_probe(struct platform_device *pdev)
                                ARRAY_SIZE(uda1380_snd_controls));
        uda1380_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
        return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
-       .probe =        uda1380_probe,
-       .remove =       uda1380_remove,
-       .suspend =      uda1380_suspend,
-       .resume =       uda1380_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
-
-static int uda1380_register(struct uda1380_priv *uda1380)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &uda1380->codec;
-       struct uda1380_platform_data *pdata = codec->dev->platform_data;
-
-       if (uda1380_codec) {
-               dev_err(codec->dev, "Another UDA1380 is registered\n");
-               return -EINVAL;
-       }
-
-       if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
-               return -EINVAL;
-
-       ret = gpio_request(pdata->gpio_power, "uda1380 power");
-       if (ret)
-               goto err_out;
-       ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
-       if (ret)
-               goto err_gpio;
-
-       gpio_direction_output(pdata->gpio_power, 1);
-
-       /* we may need to have the clock running here - pH5 */
-       gpio_direction_output(pdata->gpio_reset, 1);
-       udelay(5);
-       gpio_set_value(pdata->gpio_reset, 0);
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, uda1380);
-       codec->name = "UDA1380";
-       codec->owner = THIS_MODULE;
-       codec->read = uda1380_read_reg_cache;
-       codec->write = uda1380_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = uda1380_set_bias_level;
-       codec->dai = uda1380_dai;
-       codec->num_dai = ARRAY_SIZE(uda1380_dai);
-       codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
-       codec->reg_cache = &uda1380->reg_cache;
-       codec->reg_cache_step = 1;
-
-       memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
-
-       ret = uda1380_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_reset;
-       }
-
-       INIT_WORK(&uda1380->work, uda1380_flush_work);
 
-       for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
-               uda1380_dai[i].dev = codec->dev;
-
-       uda1380_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_reset;
-       }
-
-       ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_dai;
-       }
-
-       return 0;
-
-err_dai:
-       snd_soc_unregister_codec(codec);
 err_reset:
-       gpio_set_value(pdata->gpio_power, 0);
-       gpio_free(pdata->gpio_reset);
+err_gpio_power_conf:
+       if (gpio_is_valid(pdata->gpio_power))
+               gpio_free(pdata->gpio_power);
+
+err_gpio_reset_conf:
 err_gpio:
-       gpio_free(pdata->gpio_power);
+       if (gpio_is_valid(pdata->gpio_reset))
+               gpio_free(pdata->gpio_reset);
 err_out:
        return ret;
 }
 
-static void uda1380_unregister(struct uda1380_priv *uda1380)
+/* power down chip */
+static int uda1380_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &uda1380->codec;
-       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+       struct uda1380_platform_data *pdata =codec->dev->platform_data;
 
-       snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
-       snd_soc_unregister_codec(&uda1380->codec);
+       uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       gpio_set_value(pdata->gpio_power, 0);
        gpio_free(pdata->gpio_reset);
        gpio_free(pdata->gpio_power);
 
-       kfree(uda1380);
-       uda1380_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+       .probe =        uda1380_probe,
+       .remove =       uda1380_remove,
+       .suspend =      uda1380_suspend,
+       .resume =       uda1380_resume,
+       .read =         uda1380_read_reg_cache,
+       .write =        uda1380_write,
+       .set_bias_level = uda1380_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(uda1380_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = uda1380_reg,
+       .reg_cache_step = 1,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct uda1380_priv *uda1380;
-       struct snd_soc_codec *codec;
        int ret;
 
        uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
        if (uda1380 == NULL)
                return -ENOMEM;
 
-       codec = &uda1380->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, uda1380);
-       codec->control_data = i2c;
+       uda1380->control_data = i2c;
 
-       codec->dev = &i2c->dev;
-
-       ret = uda1380_register(uda1380);
-       if (ret != 0)
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+       if (ret < 0)
                kfree(uda1380);
-
        return ret;
 }
 
 static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
 {
-       struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
-       uda1380_unregister(uda1380);
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
@@ -884,7 +853,7 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
 
 static struct i2c_driver uda1380_i2c_driver = {
        .driver = {
-               .name =  "UDA1380 I2C Codec",
+               .name =  "uda1380-codec",
                .owner = THIS_MODULE,
        },
        .probe =    uda1380_i2c_probe,
index 9cefa8a54770da1c003db0e0cfb029b1a65a8baa..942e3927c72b11e033a98cda16dbf9b80b9b2dd1 100644 (file)
@@ -76,7 +76,4 @@
 #define UDA1380_DAI_PLAYBACK   1 /* playback DAI */
 #define UDA1380_DAI_CAPTURE    2 /* capture DAI */
 
-extern struct snd_soc_dai uda1380_dai[3];
-extern struct snd_soc_codec_device soc_codec_dev_uda1380;
-
 #endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
new file mode 100644 (file)
index 0000000..0c47c78
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * ALSA SoC WL1273 codec driver
+ *
+ * Author:      Matti Aaltonen, <matti.j.aaltonen@nokia.com>
+ *
+ * Copyright:   (C) 2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wl1273.h"
+
+enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
+
+/* codec private data */
+struct wl1273_priv {
+       enum wl1273_mode mode;
+       struct wl1273_core *core;
+       unsigned int channels;
+};
+
+static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
+                                     int rate, int width)
+{
+       struct device *dev = &core->i2c_dev->dev;
+       int r = 0;
+       u16 mode;
+
+       dev_dbg(dev, "rate: %d\n", rate);
+       dev_dbg(dev, "width: %d\n", width);
+
+       mutex_lock(&core->lock);
+
+       mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
+
+       switch (rate) {
+       case 48000:
+               mode |= WL1273_IS2_RATE_48K;
+               break;
+       case 44100:
+               mode |= WL1273_IS2_RATE_44_1K;
+               break;
+       case 32000:
+               mode |= WL1273_IS2_RATE_32K;
+               break;
+       case 22050:
+               mode |= WL1273_IS2_RATE_22_05K;
+               break;
+       case 16000:
+               mode |= WL1273_IS2_RATE_16K;
+               break;
+       case 12000:
+               mode |= WL1273_IS2_RATE_12K;
+               break;
+       case 11025:
+               mode |= WL1273_IS2_RATE_11_025;
+               break;
+       case 8000:
+               mode |= WL1273_IS2_RATE_8K;
+               break;
+       default:
+               dev_err(dev, "Sampling rate: %d not supported\n", rate);
+               r = -EINVAL;
+               goto out;
+       }
+
+       switch (width) {
+       case 16:
+               mode |= WL1273_IS2_WIDTH_32;
+               break;
+       case 20:
+               mode |= WL1273_IS2_WIDTH_40;
+               break;
+       case 24:
+               mode |= WL1273_IS2_WIDTH_48;
+               break;
+       case 25:
+               mode |= WL1273_IS2_WIDTH_50;
+               break;
+       case 30:
+               mode |= WL1273_IS2_WIDTH_60;
+               break;
+       case 32:
+               mode |= WL1273_IS2_WIDTH_64;
+               break;
+       case 40:
+               mode |= WL1273_IS2_WIDTH_80;
+               break;
+       case 48:
+               mode |= WL1273_IS2_WIDTH_96;
+               break;
+       case 64:
+               mode |= WL1273_IS2_WIDTH_128;
+               break;
+       default:
+               dev_err(dev, "Data width: %d not supported\n", width);
+               r = -EINVAL;
+               goto out;
+       }
+
+       dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n",  WL1273_I2S_DEF_MODE);
+       dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
+       dev_dbg(dev, "mode: 0x%04x\n", mode);
+
+       if (core->i2s_mode != mode) {
+               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+               if (r)
+                       goto out;
+
+               core->i2s_mode = mode;
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+                                       WL1273_AUDIO_ENABLE_I2S);
+               if (r)
+                       goto out;
+       }
+out:
+       mutex_unlock(&core->lock);
+
+       return r;
+}
+
+static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
+                                           int channel_number)
+{
+       struct i2c_client *client = core->i2c_dev;
+       struct device *dev = &client->dev;
+       int r = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       mutex_lock(&core->lock);
+
+       if (core->channel_number == channel_number)
+               goto out;
+
+       if (channel_number == 1 && core->mode == WL1273_MODE_RX)
+               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+                                       WL1273_RX_MONO);
+       else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
+               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+                                       WL1273_TX_MONO);
+       else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
+               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+                                       WL1273_RX_STEREO);
+       else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
+               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+                                       WL1273_TX_STEREO);
+       else
+               r = -EINVAL;
+out:
+       mutex_unlock(&core->lock);
+
+       return r;
+}
+
+static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wl1273->mode;
+
+       return 0;
+}
+
+static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+
+static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       if (wl1273->mode == ucontrol->value.integer.value[0])
+               return 0;
+
+       /* Do not allow changes while stream is running */
+       if (codec->active)
+               return -EPERM;
+
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] >=  ARRAY_SIZE(wl1273_audio_route))
+               return -EINVAL;
+
+       wl1273->mode = ucontrol->value.integer.value[0];
+
+       return 1;
+}
+
+static const struct soc_enum wl1273_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+
+static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
+
+       return 0;
+}
+
+static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+       int val, r = 0;
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       val = ucontrol->value.integer.value[0];
+       if (wl1273->core->audio_mode == val)
+               return 0;
+
+       r = wl1273_fm_set_audio(wl1273->core, val);
+       if (r < 0)
+               return r;
+
+       return 1;
+}
+
+static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
+
+static const struct soc_enum wl1273_audio_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
+                           wl1273_audio_strings);
+
+static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       ucontrol->value.integer.value[0] = wl1273->core->volume;
+
+       return 0;
+}
+
+static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+       int r;
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       r = wl1273_fm_set_volume(wl1273->core,
+                                ucontrol->value.integer.value[0]);
+       if (r)
+               return r;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new wl1273_controls[] = {
+       SOC_ENUM_EXT("Codec Mode", wl1273_enum,
+                    snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
+       SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
+                    snd_wl1273_fm_audio_get,  snd_wl1273_fm_audio_put),
+       SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
+                      snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
+};
+
+static int wl1273_startup(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       switch (wl1273->mode) {
+       case WL1273_MODE_BT:
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            8000, 8000);
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
+               break;
+       case WL1273_MODE_FM_RX:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       pr_err("Cannot play in RX mode.\n");
+                       return -EINVAL;
+               }
+               break;
+       case WL1273_MODE_FM_TX:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       pr_err("Cannot capture in TX mode.\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+static int wl1273_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+       struct wl1273_core *core = wl1273->core;
+       unsigned int rate, width, r;
+
+       if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
+               pr_err("Only SNDRV_PCM_FORMAT_S16_LE supported.\n");
+               return -EINVAL;
+       }
+
+       rate = params_rate(params);
+       width =  hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+
+       if (wl1273->mode == WL1273_MODE_BT) {
+               if (rate != 8000) {
+                       pr_err("Rate %d not supported.\n", params_rate(params));
+                       return -EINVAL;
+               }
+
+               if (params_channels(params) != 1) {
+                       pr_err("Only mono supported.\n");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+
+       if (wl1273->mode == WL1273_MODE_FM_TX &&
+           substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               pr_err("Only playback supported with TX.\n");
+               return -EINVAL;
+       }
+
+       if (wl1273->mode == WL1273_MODE_FM_RX  &&
+           substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               pr_err("Only capture supported with RX.\n");
+               return -EINVAL;
+       }
+
+       if (wl1273->mode != WL1273_MODE_FM_RX  &&
+           wl1273->mode != WL1273_MODE_FM_TX) {
+               pr_err("Unexpected mode: %d.\n", wl1273->mode);
+               return -EINVAL;
+       }
+
+       r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
+       if (r)
+               return r;
+
+       wl1273->channels = params_channels(params);
+       r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops wl1273_dai_ops = {
+       .startup        = wl1273_startup,
+       .hw_params      = wl1273_hw_params,
+};
+
+static struct snd_soc_dai_driver wl1273_dai = {
+       .name = "wl1273-fm",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE},
+       .ops = &wl1273_dai_ops,
+};
+
+/* Audio interface format for the soc_card driver */
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
+{
+       struct wl1273_priv *wl1273;
+
+       if (codec == NULL || fmt == NULL)
+               return -EINVAL;
+
+       wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       switch (wl1273->mode) {
+       case WL1273_MODE_FM_RX:
+       case WL1273_MODE_FM_TX:
+               *fmt =  SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+
+               break;
+       case WL1273_MODE_BT:
+               *fmt =  SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wl1273_get_format);
+
+static int wl1273_probe(struct snd_soc_codec *codec)
+{
+       struct wl1273_core **core = codec->dev->platform_data;
+       struct wl1273_priv *wl1273;
+       int r;
+
+       dev_dbg(codec->dev, "%s.\n", __func__);
+
+       if (!core) {
+               dev_err(codec->dev, "Platform data is missing.\n");
+               return -EINVAL;
+       }
+
+       wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
+       if (wl1273 == NULL) {
+               dev_err(codec->dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       wl1273->mode = WL1273_MODE_BT;
+       wl1273->core = *core;
+
+       snd_soc_codec_set_drvdata(codec, wl1273);
+       mutex_init(&codec->mutex);
+
+       r = snd_soc_add_controls(codec, wl1273_controls,
+                                ARRAY_SIZE(wl1273_controls));
+       if (r)
+               kfree(wl1273);
+
+       return r;
+}
+
+static int wl1273_remove(struct snd_soc_codec *codec)
+{
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s\n", __func__);
+       kfree(wl1273);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+       .probe = wl1273_probe,
+       .remove = wl1273_remove,
+};
+
+static int __devinit wl1273_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
+                                     &wl1273_dai, 1);
+}
+
+static int __devexit wl1273_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:wl1273-codec");
+
+static struct platform_driver wl1273_platform_driver = {
+       .driver         = {
+               .name   = "wl1273-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wl1273_platform_probe,
+       .remove         = __devexit_p(wl1273_platform_remove),
+};
+
+static int __init wl1273_init(void)
+{
+       return platform_driver_register(&wl1273_platform_driver);
+}
+module_init(wl1273_init);
+
+static void __exit wl1273_exit(void)
+{
+       platform_driver_unregister(&wl1273_platform_driver);
+}
+module_exit(wl1273_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION("ASoC WL1273 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
new file mode 100644 (file)
index 0000000..14ed027
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * sound/soc/codec/wl1273.h
+ *
+ * ALSA SoC WL1273 codec driver
+ *
+ * Copyright (C) Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1273_CODEC_H__
+#define __WL1273_CODEC_H__
+
+/* I2S protocol, left channel first, data width 16 bits */
+#define WL1273_PCM_DEF_MODE            0x00
+
+/* Rx */
+#define WL1273_AUDIO_ENABLE_I2S                (1 << 0)
+#define WL1273_AUDIO_ENABLE_ANALOG     (1 << 1)
+
+/* Tx */
+#define WL1273_AUDIO_IO_SET_ANALOG     0
+#define WL1273_AUDIO_IO_SET_I2S                1
+
+#define WL1273_POWER_SET_OFF           0
+#define WL1273_POWER_SET_FM            (1 << 0)
+#define WL1273_POWER_SET_RDS           (1 << 1)
+#define WL1273_POWER_SET_RETENTION     (1 << 4)
+
+#define WL1273_PUPD_SET_OFF            0x00
+#define WL1273_PUPD_SET_ON             0x01
+#define WL1273_PUPD_SET_RETENTION      0x10
+
+/* I2S mode */
+#define WL1273_IS2_WIDTH_32    0x0
+#define WL1273_IS2_WIDTH_40    0x1
+#define WL1273_IS2_WIDTH_22_23 0x2
+#define WL1273_IS2_WIDTH_23_22 0x3
+#define WL1273_IS2_WIDTH_48    0x4
+#define WL1273_IS2_WIDTH_50    0x5
+#define WL1273_IS2_WIDTH_60    0x6
+#define WL1273_IS2_WIDTH_64    0x7
+#define WL1273_IS2_WIDTH_80    0x8
+#define WL1273_IS2_WIDTH_96    0x9
+#define WL1273_IS2_WIDTH_128   0xa
+#define WL1273_IS2_WIDTH       0xf
+
+#define WL1273_IS2_FORMAT_STD  (0x0 << 4)
+#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
+#define WL1273_IS2_FORMAT_RIGHT        (0x2 << 4)
+#define WL1273_IS2_FORMAT_USER (0x3 << 4)
+
+#define WL1273_IS2_MASTER      (0x0 << 6)
+#define WL1273_IS2_SLAVEW      (0x1 << 6)
+
+#define WL1273_IS2_TRI_AFTER_SENDING   (0x0 << 7)
+#define WL1273_IS2_TRI_ALWAYS_ACTIVE   (0x1 << 7)
+
+#define WL1273_IS2_SDOWS_RR    (0x0 << 8)
+#define WL1273_IS2_SDOWS_RF    (0x1 << 8)
+#define WL1273_IS2_SDOWS_FR    (0x2 << 8)
+#define WL1273_IS2_SDOWS_FF    (0x3 << 8)
+
+#define WL1273_IS2_TRI_OPT     (0x0 << 10)
+#define WL1273_IS2_TRI_ALWAYS  (0x1 << 10)
+
+#define WL1273_IS2_RATE_48K    (0x0 << 12)
+#define WL1273_IS2_RATE_44_1K  (0x1 << 12)
+#define WL1273_IS2_RATE_32K    (0x2 << 12)
+#define WL1273_IS2_RATE_22_05K (0x4 << 12)
+#define WL1273_IS2_RATE_16K    (0x5 << 12)
+#define WL1273_IS2_RATE_12K    (0x8 << 12)
+#define WL1273_IS2_RATE_11_025 (0x9 << 12)
+#define WL1273_IS2_RATE_8K     (0xa << 12)
+#define WL1273_IS2_RATE                (0xf << 12)
+
+#define WL1273_I2S_DEF_MODE    (WL1273_IS2_WIDTH_32 | \
+                                WL1273_IS2_FORMAT_STD | \
+                                WL1273_IS2_MASTER | \
+                                WL1273_IS2_TRI_AFTER_SENDING | \
+                                WL1273_IS2_SDOWS_RR | \
+                                WL1273_IS2_TRI_OPT | \
+                                WL1273_IS2_RATE_48K)
+
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
+
+#endif /* End of __WL1273_CODEC_H__ */
index c18e261c3c7fb089cefc032dd4e67e74675570b5..0b6f056f73cc53a80ab0fedc5733641573bc4974 100644 (file)
@@ -16,9 +16,6 @@ struct wm2000_setup_data {
 
 extern int wm2000_add_controls(struct snd_soc_codec *codec);
 
-extern struct snd_soc_dai wm2000_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm2000;
-
 #define WM2000_REG_SYS_START       0x8000
 #define WM2000_REG_SPEECH_CLARITY   0x8fef
 #define WM2000_REG_SYS_WATCHDOG     0x8ff6
index 0221ca79b3ae59831a15499e263b7ca9cbf1118b..f4f1fba38eb9458176f5bda41cc93d12c87722eb 100644 (file)
@@ -1321,20 +1321,14 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8350_resume(struct platform_device *pdev)
+static int wm8350_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1489,24 +1483,74 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
 
-static struct snd_soc_codec *wm8350_codec;
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+        .hw_params     = wm8350_pcm_hw_params,
+        .digital_mute  = wm8350_mute,
+        .trigger       = wm8350_pcm_trigger,
+        .set_fmt       = wm8350_set_dai_fmt,
+        .set_sysclk    = wm8350_set_dai_sysclk,
+        .set_pll       = wm8350_set_fll,
+        .set_clkdiv    = wm8350_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8350_dai = {
+       .name = "wm8350-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8350_RATES,
+               .formats = WM8350_FORMATS,
+       },
+       .capture = {
+                .stream_name = "Capture",
+                .channels_min = 1,
+                .channels_max = 2,
+                .rates = WM8350_RATES,
+                .formats = WM8350_FORMATS,
+        },
+       .ops = &wm8350_dai_ops,
+};
 
-static int wm8350_probe(struct platform_device *pdev)
+static  int wm8350_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm8350 *wm8350;
+       struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
        struct wm8350_data *priv;
-       int ret;
        struct wm8350_output *out1;
        struct wm8350_output *out2;
+       int ret, i;
 
-       BUG_ON(!wm8350_codec);
+       if (wm8350->codec.platform_data == NULL) {
+               dev_err(codec->dev, "No audio platform data supplied\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, priv);
+
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               priv->supplies[i].supply = supply_names[i];
+
+       ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+                                priv->supplies);
+       if (ret != 0)
+               goto err_priv;
+
+       wm8350->codec.codec = codec;
+       codec->control_data = wm8350;
 
-       socdev->card->codec = wm8350_codec;
-       codec = socdev->card->codec;
-       wm8350 = codec->control_data;
-       priv = snd_soc_codec_get_drvdata(codec);
+       /* Put the codec into reset if it wasn't already */
+       wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
 
        /* Enable the codec */
        wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1557,11 +1601,6 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
                            wm8350_mic_handler, 0, "Microphone detect", priv);
 
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
-       }
 
        snd_soc_add_controls(codec, wm8350_snd_controls,
                                ARRAY_SIZE(wm8350_snd_controls));
@@ -1570,14 +1609,16 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
+
+err_priv:
+       kfree(priv);
+       return ret;
 }
 
-static int wm8350_remove(struct platform_device *pdev)
+static int  wm8350_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct wm8350 *wm8350 = codec->control_data;
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
        int ret;
 
        wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
@@ -1607,134 +1648,30 @@ static int wm8350_remove(struct platform_device *pdev)
 
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
+       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+       kfree(priv);
        return 0;
 }
 
-#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
-
-#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-                       SNDRV_PCM_FMTBIT_S20_3LE |\
-                       SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_ops wm8350_dai_ops = {
-        .hw_params     = wm8350_pcm_hw_params,
-        .digital_mute  = wm8350_mute,
-        .trigger       = wm8350_pcm_trigger,
-        .set_fmt       = wm8350_set_dai_fmt,
-        .set_sysclk    = wm8350_set_dai_sysclk,
-        .set_pll       = wm8350_set_fll,
-        .set_clkdiv    = wm8350_set_clkdiv,
-};
-
-struct snd_soc_dai wm8350_dai = {
-       .name = "WM8350",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = WM8350_RATES,
-               .formats = WM8350_FORMATS,
-       },
-       .capture = {
-                .stream_name = "Capture",
-                .channels_min = 1,
-                .channels_max = 2,
-                .rates = WM8350_RATES,
-                .formats = WM8350_FORMATS,
-        },
-       .ops = &wm8350_dai_ops,
-};
-EXPORT_SYMBOL_GPL(wm8350_dai);
-
-struct snd_soc_codec_device soc_codec_dev_wm8350 = {
-       .probe =        wm8350_probe,
-       .remove =       wm8350_remove,
+static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
+       .probe =        wm8350_codec_probe,
+       .remove =       wm8350_codec_remove,
        .suspend =      wm8350_suspend,
        .resume =       wm8350_resume,
+       .read = wm8350_codec_read,
+       .write = wm8350_codec_write,
+       .set_bias_level = wm8350_set_bias_level,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
 
-static __devinit int wm8350_codec_probe(struct platform_device *pdev)
+static int __devinit wm8350_probe(struct platform_device *pdev)
 {
-       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
-       struct wm8350_data *priv;
-       struct snd_soc_codec *codec;
-       int ret, i;
-
-       if (wm8350->codec.platform_data == NULL) {
-               dev_err(&pdev->dev, "No audio platform data supplied\n");
-               return -EINVAL;
-       }
-
-       priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
-       if (priv == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
-               priv->supplies[i].supply = supply_names[i];
-
-       ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
-                                priv->supplies);
-       if (ret != 0)
-               goto err_priv;
-
-       codec = &priv->codec;
-       wm8350->codec.codec = codec;
-
-       wm8350_dai.dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->dev = &pdev->dev;
-       codec->name = "WM8350";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8350_codec_read;
-       codec->write = wm8350_codec_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8350_set_bias_level;
-       codec->dai = &wm8350_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8350_MAX_REGISTER;
-       snd_soc_codec_set_drvdata(codec, priv);
-       codec->control_data = wm8350;
-
-       /* Put the codec into reset if it wasn't already */
-       wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
-
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0)
-               goto err_supply;
-
-       wm8350_codec = codec;
-
-       ret = snd_soc_register_dai(&wm8350_dai);
-       if (ret != 0)
-               goto err_codec;
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err_supply:
-       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-err_priv:
-       kfree(priv);
-       wm8350_codec = NULL;
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
+                       &wm8350_dai, 1);
 }
 
-static int __devexit wm8350_codec_remove(struct platform_device *pdev)
+static int __devexit wm8350_remove(struct platform_device *pdev)
 {
-       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = wm8350->codec.codec;
-       struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-
-       snd_soc_unregister_dai(&wm8350_dai);
-       snd_soc_unregister_codec(codec);
-       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-       kfree(priv);
-       wm8350_codec = NULL;
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
@@ -1743,8 +1680,8 @@ static struct platform_driver wm8350_codec_driver = {
                   .name = "wm8350-codec",
                   .owner = THIS_MODULE,
                   },
-       .probe = wm8350_codec_probe,
-       .remove = __devexit_p(wm8350_codec_remove),
+       .probe = wm8350_probe,
+       .remove = __devexit_p(wm8350_remove),
 };
 
 static __init int wm8350_init(void)
index 9ed0467c71db70b42db50e563b10abbf4485348e..74108eb82938ca29b3caec1156bc8dd22e4931a1 100644 (file)
@@ -15,9 +15,6 @@
 #include <sound/soc.h>
 #include <linux/mfd/wm8350/audio.h>
 
-extern struct snd_soc_dai wm8350_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8350;
-
 enum wm8350_jack {
        WM8350_JDL = 1,
        WM8350_JDR = 2,
index 8f294066b0ed3e4edfc382b992e943a6157e1af2..850299786e02d0d87f77e673bb093fffb68bcbdc 100644 (file)
@@ -65,7 +65,7 @@ static struct regulator_bulk_data power[] = {
 
 /* codec private data */
 struct wm8400_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct wm8400 *wm8400;
        u16 fake_register;
        unsigned int sysclk;
@@ -1163,8 +1163,7 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8400_AIF_WL_MASK;
@@ -1332,10 +1331,9 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
-struct snd_soc_dai wm8400_dai = {
+static struct snd_soc_dai_driver wm8400_dai = {
 /* ADC/DAC on primary */
-       .name = "WM8400 ADC/DAC Primary",
-       .id = 1,
+       .name = "wm8400-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1352,147 +1350,53 @@ struct snd_soc_dai wm8400_dai = {
        },
        .ops = &wm8400_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8400_dai);
 
-static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8400_resume(struct platform_device *pdev)
+static int wm8400_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8400_codec;
-
-static int wm8400_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!wm8400_codec) {
-               dev_err(&pdev->dev, "wm8400 not yet discovered\n");
-               return -ENODEV;
-       }
-       codec = wm8400_codec;
-
-       socdev->card->codec = codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       wm8400_add_controls(codec);
-       wm8400_add_widgets(codec);
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8400_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8400 = {
-       .probe =        wm8400_probe,
-       .remove =       wm8400_remove,
-       .suspend =      wm8400_suspend,
-       .resume =       wm8400_resume,
-};
-
 static void wm8400_probe_deferred(struct work_struct *work)
 {
        struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
                                                work);
-       struct snd_soc_codec *codec = &priv->codec;
-       int ret;
+       struct snd_soc_codec *codec = priv->codec;
 
        /* charge output caps */
        wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* We're done, tell the subsystem. */
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(priv->wm8400->dev,
-                       "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8400_dai);
-       if (ret != 0) {
-               dev_err(priv->wm8400->dev,
-                       "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int wm8400_codec_probe(struct platform_device *dev)
+static int wm8400_codec_probe(struct snd_soc_codec *codec)
 {
+       struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
        struct wm8400_priv *priv;
        int ret;
        u16 reg;
-       struct snd_soc_codec *codec;
 
        priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
 
-       codec = &priv->codec;
        snd_soc_codec_set_drvdata(codec, priv);
-       codec->control_data = dev_get_drvdata(&dev->dev);
-       priv->wm8400 = dev_get_drvdata(&dev->dev);
+       codec->control_data = priv->wm8400 = wm8400;
+       priv->codec = codec;
 
-       ret = regulator_bulk_get(priv->wm8400->dev,
+       ret = regulator_bulk_get(wm8400->dev,
                                 ARRAY_SIZE(power), &power[0]);
        if (ret != 0) {
-               dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+               dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
                goto err;
        }
 
-       codec->dev = &dev->dev;
-       wm8400_dai.dev = &dev->dev;
-
-       codec->name = "WM8400";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8400_read;
-       codec->write = wm8400_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8400_set_bias_level;
-       codec->dai = &wm8400_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8400_REGISTER_COUNT;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
        INIT_WORK(&priv->work, wm8400_probe_deferred);
 
        wm8400_codec_reset(codec);
@@ -1511,65 +1415,78 @@ static int wm8400_codec_probe(struct platform_device *dev)
        wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
        wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-       wm8400_codec = codec;
-
        if (!schedule_work(&priv->work)) {
                ret = -EINVAL;
                goto err_regulator;
        }
-
+       wm8400_add_controls(codec);
+       wm8400_add_widgets(codec);
        return 0;
 
 err_regulator:
-       wm8400_codec = NULL;
        regulator_bulk_free(ARRAY_SIZE(power), power);
 err:
        kfree(priv);
        return ret;
 }
 
-static int __exit wm8400_codec_remove(struct platform_device *dev)
+static int  wm8400_codec_remove(struct snd_soc_codec *codec)
 {
-       struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
+       struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
        u16 reg;
 
-       snd_soc_unregister_dai(&wm8400_dai);
-       snd_soc_unregister_codec(wm8400_codec);
-
-       reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
-       wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
                     reg & (~WM8400_CODEC_ENA));
 
        regulator_bulk_free(ARRAY_SIZE(power), power);
        kfree(priv);
 
-       wm8400_codec = NULL;
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
+       .probe =        wm8400_codec_probe,
+       .remove =       wm8400_codec_remove,
+       .suspend =      wm8400_suspend,
+       .resume =       wm8400_resume,
+       .read = wm8400_read,
+       .write = wm8400_write,
+       .set_bias_level = wm8400_set_bias_level,
+};
+
+static int __devinit wm8400_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
+                       &wm8400_dai, 1);
+}
 
+static int __devexit wm8400_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver wm8400_codec_driver = {
        .driver = {
-               .name = "wm8400-codec",
-               .owner = THIS_MODULE,
-       },
-       .probe = wm8400_codec_probe,
-       .remove = __exit_p(wm8400_codec_remove),
+                  .name = "wm8400-codec",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = wm8400_probe,
+       .remove = __devexit_p(wm8400_remove),
 };
 
-static int __init wm8400_codec_init(void)
+static __init int wm8400_init(void)
 {
        return platform_driver_register(&wm8400_codec_driver);
 }
-module_init(wm8400_codec_init);
+module_init(wm8400_init);
 
-static void __exit wm8400_codec_exit(void)
+static __exit void wm8400_exit(void)
 {
        platform_driver_unregister(&wm8400_codec_driver);
 }
-module_exit(wm8400_codec_exit);
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+module_exit(wm8400_exit);
 
 MODULE_DESCRIPTION("ASoC WM8400 driver");
 MODULE_AUTHOR("Mark Brown");
index 79c5934d4776f2b3cda9907e7ca5c7d2d3a383fc..521adb19387087048e3d86e299d3f4b5682ba0d6 100644 (file)
@@ -56,7 +56,4 @@
 #define WM8400_BCLK_DIV_44                      (0xE << 1)
 #define WM8400_BCLK_DIV_48                      (0xF << 1)
 
-extern struct snd_soc_dai wm8400_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8400;
-
 #endif
index 0f7bcb61071ac6a12cd9fc4b82ea2350d5b469c8..8f107095760e2206f875e0be53b88001395787bb 100644 (file)
 
 #include "wm8510.h"
 
-#define WM8510_VERSION "0.6"
-
-struct snd_soc_codec_device soc_codec_dev_wm8510;
-
 /*
  * wm8510 register cache
  * We can't read the WM8510 register space when we are
@@ -61,6 +57,11 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
 
 #define wm8510_reset(c)        snd_soc_write(c, WM8510_RESET, 0)
 
+/* codec private data */
+struct wm8510_priv {
+       enum snd_soc_control_type control_type;
+};
+
 static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
 static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
 static const char *wm8510_alc[] = { "ALC", "Limiter" };
@@ -403,8 +404,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
        u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
@@ -514,8 +514,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
        .set_pll        = wm8510_set_dai_pll,
 };
 
-struct snd_soc_dai wm8510_dai = {
-       .name = "WM8510 HiFi",
+static struct snd_soc_dai_driver wm8510_dai = {
+       .name = "wm8510-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -531,21 +531,15 @@ struct snd_soc_dai wm8510_dai = {
        .ops = &wm8510_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8510_dai);
 
-static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8510_resume(struct platform_device *pdev)
+static int wm8510_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -561,256 +555,158 @@ static int wm8510_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the WM8510 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8510_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8510_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-
-       codec->name = "WM8510";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8510_set_bias_level;
-       codec->dai = &wm8510_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
-       codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9,  wm8510->control_type);
        if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
-                      ret);
-               goto err;
+               printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        wm8510_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to create pcms\n");
-               goto err;
-       }
-
        /* power on device */
-       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm8510_snd_controls,
                                ARRAY_SIZE(wm8510_snd_controls));
        wm8510_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-static struct snd_soc_device *wm8510_socdev;
+/* power down chip */
+static int wm8510_remove(struct snd_soc_codec *codec)
+{
+       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       kfree(wm8510);
+       return 0;
+}
 
-/*
- * WM8510 2 wire address is 0x1a
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+       .probe =        wm8510_probe,
+       .remove =       wm8510_remove,
+       .suspend =      wm8510_suspend,
+       .resume =       wm8510_resume,
+       .set_bias_level = wm8510_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8510_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default =wm8510_reg,
+};
 
-static int wm8510_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8510_priv *wm8510;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       if (wm8510 == NULL)
+               return -ENOMEM;
 
-       ret = wm8510_init(socdev, SND_SOC_I2C);
-       if (ret < 0)
-               pr_err("failed to initialise WM8510\n");
+       wm8510->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8510);
 
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8510, &wm8510_dai, 1);
+       if (ret < 0)
+               kfree(wm8510);
        return ret;
 }
 
-static int wm8510_i2c_remove(struct i2c_client *client)
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&spi->dev);
        return 0;
 }
 
-static const struct i2c_device_id wm8510_i2c_id[] = {
-       { "wm8510", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
-
-static struct i2c_driver wm8510_i2c_driver = {
+static struct spi_driver wm8510_spi_driver = {
        .driver = {
-               .name = "WM8510 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8510",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8510_i2c_probe,
-       .remove =   wm8510_i2c_remove,
-       .id_table = wm8510_i2c_id,
+       .probe          = wm8510_spi_probe,
+       .remove         = __devexit_p(wm8510_spi_remove),
 };
+#endif /* CONFIG_SPI_MASTER */
 
-static int wm8510_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8510_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
+       struct wm8510_priv *wm8510;
        int ret;
 
-       ret = i2c_add_driver(&wm8510_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8510_i2c_driver);
-       return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8510_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret;
+       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       if (wm8510 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = spi;
+       i2c_set_clientdata(i2c, wm8510);
+       wm8510->control_type = SND_SOC_I2C;
 
-       ret = wm8510_init(socdev, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8510, &wm8510_dai, 1);
        if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8510\n");
-
+               kfree(wm8510);
        return ret;
 }
 
-static int __devexit wm8510_spi_remove(struct spi_device *spi)
+static __devexit int wm8510_i2c_remove(struct i2c_client *client)
 {
+       snd_soc_unregister_codec(&client->dev);
        return 0;
 }
 
-static struct spi_driver wm8510_spi_driver = {
+static const struct i2c_device_id wm8510_i2c_id[] = {
+       { "wm8510", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
+
+static struct i2c_driver wm8510_i2c_driver = {
        .driver = {
-               .name   = "wm8510",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8510-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8510_spi_probe,
-       .remove         = __devexit_p(wm8510_spi_remove),
+       .probe =    wm8510_i2c_probe,
+       .remove =   __devexit_p(wm8510_i2c_remove),
+       .id_table = wm8510_i2c_id,
 };
-#endif /* CONFIG_SPI_MASTER */
+#endif
 
-static int wm8510_probe(struct platform_device *pdev)
+static int __init wm8510_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8510_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8510_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8510_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&wm8510_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+                      ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               ret = spi_register_driver(&wm8510_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
+       ret = spi_register_driver(&wm8510_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+                      ret);
        }
 #endif
-
-       if (ret != 0)
-               kfree(codec);
        return ret;
 }
+module_init(wm8510_modinit);
 
-/* power down chip */
-static int wm8510_remove(struct platform_device *pdev)
+static void __exit wm8510_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8510_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8510_spi_driver);
 #endif
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8510 = {
-       .probe =        wm8510_probe,
-       .remove =       wm8510_remove,
-       .suspend =      wm8510_suspend,
-       .resume =       wm8510_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
-
-static int __init wm8510_modinit(void)
-{
-       return snd_soc_register_dai(&wm8510_dai);
-}
-module_init(wm8510_modinit);
-
-static void __exit wm8510_exit(void)
-{
-       snd_soc_unregister_dai(&wm8510_dai);
 }
 module_exit(wm8510_exit);
 
index bdefcf5c69ff2a9ed57e160843710467d19d33d0..b3e26ed9f2d0f40b234977cf3a4d90f64eeafed5 100644 (file)
@@ -99,7 +99,4 @@ struct wm8510_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai wm8510_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8510;
-
 #endif
index 0ad039b4adf5fd0b12e587a115f91196e921b331..712ef7c76f90bbde579229ea85716dd14f7acb10 100644 (file)
@@ -30,9 +30,6 @@
 
 #include "wm8523.h"
 
-static struct snd_soc_codec *wm8523_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8523;
-
 #define WM8523_NUM_SUPPLIES 2
 static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
        "AVDD",
@@ -43,7 +40,7 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8523_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8523_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
        unsigned int sysclk;
@@ -162,8 +159,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
@@ -387,8 +383,8 @@ static struct snd_soc_dai_ops wm8523_dai_ops = {
        .set_fmt        = wm8523_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8523_dai = {
-       .name = "WM8523",
+static struct snd_soc_dai_driver wm8523_dai = {
+       .name = "wm8523-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,  /* Mono modes not yet supported */
@@ -398,25 +394,17 @@ struct snd_soc_dai wm8523_dai = {
        },
        .ops = &wm8523_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8523_dai);
 
 #ifdef CONFIG_PM
-static int wm8523_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8523_resume(struct platform_device *pdev)
+static int wm8523_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 }
 #else
@@ -424,93 +412,20 @@ static int wm8523_resume(struct platform_device *pdev)
 #define wm8523_resume NULL
 #endif
 
-static int wm8523_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8523_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8523_codec;
-       codec = wm8523_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8523_snd_controls,
-                            ARRAY_SIZE(wm8523_snd_controls));
-       wm8523_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8523_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8523 = {
-       .probe =        wm8523_probe,
-       .remove =       wm8523_remove,
-       .suspend =      wm8523_suspend,
-       .resume =       wm8523_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
-
-static int wm8523_register(struct wm8523_priv *wm8523,
-                          enum snd_soc_control_type control)
+static int wm8523_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_codec *codec = &wm8523->codec;
-       int i;
-
-       if (wm8523_codec) {
-               dev_err(codec->dev, "Another WM8523 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8523);
-       codec->name = "WM8523";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8523_set_bias_level;
-       codec->dai = &wm8523_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8523_REGISTER_COUNT;
-       codec->reg_cache = &wm8523->reg_cache;
-       codec->volatile_register = wm8523_volatile_register;
+       struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
 
+       codec->hw_write = (hw_write_t)i2c_master_send;
        wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
        wm8523->rate_constraint.count =
                ARRAY_SIZE(wm8523->rate_constraint_list);
 
-       memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
@@ -520,7 +435,7 @@ static int wm8523_register(struct wm8523_priv *wm8523,
                                 wm8523->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
@@ -555,8 +470,6 @@ static int wm8523_register(struct wm8523_priv *wm8523,
                goto err_enable;
        }
 
-       wm8523_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
        wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
@@ -566,69 +479,67 @@ static int wm8523_register(struct wm8523_priv *wm8523,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
 
-       wm8523_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8523_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8523_snd_controls,
+                            ARRAY_SIZE(wm8523_snd_controls));
+       wm8523_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-err:
-       kfree(wm8523);
+
        return ret;
 }
 
-static void wm8523_unregister(struct wm8523_priv *wm8523)
+static int wm8523_remove(struct snd_soc_codec *codec)
 {
-       wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF);
+       struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+
+       wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-       snd_soc_unregister_dai(&wm8523_dai);
-       snd_soc_unregister_codec(&wm8523->codec);
-       kfree(wm8523);
-       wm8523_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
+       .probe =        wm8523_probe,
+       .remove =       wm8523_remove,
+       .suspend =      wm8523_suspend,
+       .resume =       wm8523_resume,
+       .set_bias_level = wm8523_set_bias_level,
+       .reg_cache_size = WM8523_REGISTER_COUNT,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8523_reg,
+       .volatile_register = wm8523_volatile_register,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8523_priv *wm8523;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
        if (wm8523 == NULL)
                return -ENOMEM;
 
-       codec = &wm8523->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8523);
-       codec->control_data = i2c;
+       wm8523->control_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8523, &wm8523_dai, 1);
+       if (ret < 0)
+               kfree(wm8523);
+       return ret;
 
-       return wm8523_register(wm8523, SND_SOC_I2C);
 }
 
 static __devexit int wm8523_i2c_remove(struct i2c_client *client)
 {
-       struct wm8523_priv *wm8523 = i2c_get_clientdata(client);
-       wm8523_unregister(wm8523);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -640,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
 
 static struct i2c_driver wm8523_i2c_driver = {
        .driver = {
-               .name = "WM8523",
+               .name = "wm8523-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8523_i2c_probe,
index 1aa9ce3e135775ce03cce3e4d57b75e54b98167d..4d5b1eb8f2fc806d20552698cce5df6bf43b1da0 100644 (file)
 #define WM8523_ZD_COUNT_SHIFT                        0  /* ZD_COUNT - [1:0] */
 #define WM8523_ZD_COUNT_WIDTH                        2  /* ZD_COUNT - [1:0] */
 
-extern struct snd_soc_dai wm8523_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8523;
-
 #endif
index 72deeabef4fe4cf7b4fbb822054cc5e99ce1708e..a2e0ed59b3769f0b7d73024a6e4740338b1ccb81 100644 (file)
@@ -94,6 +94,8 @@
 
 #define WM8580_MAX_REGISTER                  0x35
 
+#define WM8580_DACOSR 0x40
+
 /* PLLB4 (register 7h) */
 #define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
 #define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
 
 /* AIF control 1 (registers 9h-bh) */
 #define WM8580_AIF_RATE_MASK       0x7
-#define WM8580_AIF_RATE_128        0x0
-#define WM8580_AIF_RATE_192        0x1
-#define WM8580_AIF_RATE_256        0x2
-#define WM8580_AIF_RATE_384        0x3
-#define WM8580_AIF_RATE_512        0x4
-#define WM8580_AIF_RATE_768        0x5
-#define WM8580_AIF_RATE_1152       0x6
-
 #define WM8580_AIF_BCLKSEL_MASK   0x18
-#define WM8580_AIF_BCLKSEL_64     0x00
-#define WM8580_AIF_BCLKSEL_128    0x08
-#define WM8580_AIF_BCLKSEL_256    0x10
-#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
 
 #define WM8580_AIF_MS             0x20
 
@@ -199,11 +189,12 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8580_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
        u16 reg_cache[WM8580_MAX_REGISTER + 1];
        struct pll_state a;
        struct pll_state b;
+       int sysclk[2];
 };
 
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
@@ -273,8 +264,8 @@ SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
 SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
 SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
 
-SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
-SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
+SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
@@ -476,6 +467,10 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        return 0;
 }
 
+static const int wm8580_sysclk_ratios[] = {
+       128, 192, 256, 384, 512, 768, 1152,
+};
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -484,29 +479,68 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
+       struct snd_soc_codec *codec = rtd->codec;
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       u16 paifa = 0;
+       u16 paifb = 0;
+       int i, ratio, osr;
 
-       paifb &= ~WM8580_AIF_LENGTH_MASK;
        /* bit size */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
+               paifa |= 0x8;
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_20;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_24;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_24;
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
+       /* Look up the SYSCLK ratio; accept only exact matches */
+       ratio = wm8580->sysclk[dai->id] / params_rate(params);
+       for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
+               if (ratio == wm8580_sysclk_ratios[i])
+                       break;
+       if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
+               dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
+                       wm8580->sysclk[dai->id], params_rate(params));
+               return -EINVAL;
+       }
+       paifa |= i;
+       dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n",
+               wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               switch (ratio) {
+               case 128:
+               case 192:
+                       osr = WM8580_DACOSR;
+                       dev_dbg(codec->dev, "Selecting 64x OSR\n");
+                       break;
+               default:
+                       osr = 0;
+                       dev_dbg(codec->dev, "Selecting 128x OSR\n");
+                       break;
+               }
+
+               snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr);
+       }
+
+       snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id,
+                           WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
+                           paifa);
+       snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id,
+                           WM8580_AIF_LENGTH_MASK, paifb);
        return 0;
 }
 
@@ -518,8 +552,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
        unsigned int aifb;
        int can_invert_lrclk;
 
-       aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
-       aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
+       aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
+       aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
 
        aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
 
@@ -585,8 +619,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
-       snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+       snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+       snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
 
        return 0;
 }
@@ -624,28 +658,6 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                snd_soc_write(codec, WM8580_PLLB4, reg);
                break;
 
-       case WM8580_DAC_CLKSEL:
-               reg = snd_soc_read(codec, WM8580_CLKSEL);
-               reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
-
-               switch (div) {
-               case WM8580_CLKSRC_MCLK:
-                       break;
-
-               case WM8580_CLKSRC_PLLA:
-                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
-                       break;
-
-               case WM8580_CLKSRC_PLLB:
-                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-               snd_soc_write(codec, WM8580_CLKSEL, reg);
-               break;
-
        case WM8580_CLKOUTSRC:
                reg = snd_soc_read(codec, WM8580_PLLB4);
                reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
@@ -679,6 +691,55 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       int sel, sel_mask, sel_shift;
+
+       switch (dai->driver->id) {
+       case WM8580_DAI_PAIFRX:
+               sel_mask = 0x3;
+               sel_shift = 0;
+               break;
+
+       case WM8580_DAI_PAIFTX:
+               sel_mask = 0xc;
+               sel_shift = 2;
+               break;
+
+       default:
+               BUG_ON("Unknown DAI driver ID\n");
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case WM8580_CLKSRC_ADCMCLK:
+               if (dai->id != WM8580_DAI_PAIFTX)
+                       return -EINVAL;
+               sel = 0 << sel_shift;
+               break;
+       case WM8580_CLKSRC_PLLA:
+               sel = 1 << sel_shift;
+               break;
+       case WM8580_CLKSRC_PLLB:
+               sel = 2 << sel_shift;
+               break;
+       case WM8580_CLKSRC_MCLK:
+               sel = 3 << sel_shift;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       /* We really should validate PLL settings but not yet */
+       wm8580->sysclk[dai->id] = freq;
+
+       return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+}
+
 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -732,6 +793,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+       .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
        .set_clkdiv     = wm8580_set_dai_clkdiv,
@@ -740,16 +802,17 @@ static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
 };
 
 static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+       .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
        .set_clkdiv     = wm8580_set_dai_clkdiv,
        .set_pll        = wm8580_set_dai_pll,
 };
 
-struct snd_soc_dai wm8580_dai[] = {
+static struct snd_soc_dai_driver wm8580_dai[] = {
        {
-               .name = "WM8580 PAIFRX",
-               .id = 0,
+               .name = "wm8580-hifi-playback",
+               .id     = WM8580_DAI_PAIFRX,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 1,
@@ -760,8 +823,8 @@ struct snd_soc_dai wm8580_dai[] = {
                .ops = &wm8580_dai_ops_playback,
        },
        {
-               .name = "WM8580 PAIFTX",
-               .id = 1,
+               .name = "wm8580-hifi-capture",
+               .id     =       WM8580_DAI_PAIFTX,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
@@ -772,90 +835,16 @@ struct snd_soc_dai wm8580_dai[] = {
                .ops = &wm8580_dai_ops_capture,
        },
 };
-EXPORT_SYMBOL_GPL(wm8580_dai);
-
-static struct snd_soc_codec *wm8580_codec;
 
-static int wm8580_probe(struct platform_device *pdev)
+static int wm8580_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8580_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8580_codec;
-       codec = wm8580_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8580_snd_controls,
-                            ARRAY_SIZE(wm8580_snd_controls));
-       wm8580_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
-       .probe =        wm8580_probe,
-       .remove =       wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int wm8580_register(struct wm8580_priv *wm8580,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8580->codec;
-
-       if (wm8580_codec) {
-               dev_err(codec->dev, "Another WM8580 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8580);
-       codec->name = "WM8580";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8580_set_bias_level;
-       codec->dai = wm8580_dai;
-       codec->num_dai = ARRAY_SIZE(wm8580_dai);
-       codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
-       codec->reg_cache = &wm8580->reg_cache;
-
-       memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0,i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
@@ -865,7 +854,7 @@ static int wm8580_register(struct wm8580_priv *wm8580,
                                 wm8580->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
@@ -882,74 +871,68 @@ static int wm8580_register(struct wm8580_priv *wm8580,
                goto err_regulator_enable;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
-               wm8580_dai[i].dev = codec->dev;
-
        wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8580_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_regulator_enable;
-       }
-
-       ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8580_snd_controls,
+                            ARRAY_SIZE(wm8580_snd_controls));
+       wm8580_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
 err_regulator_get:
        regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-err:
-       kfree(wm8580);
        return ret;
 }
 
-static void wm8580_unregister(struct wm8580_priv *wm8580)
+/* power down chip */
+static int wm8580_remove(struct snd_soc_codec *codec)
 {
-       wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-       snd_soc_unregister_codec(&wm8580->codec);
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+
+       wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
        regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-       kfree(wm8580);
-       wm8580_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
+       .probe =        wm8580_probe,
+       .remove =       wm8580_remove,
+       .set_bias_level = wm8580_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8580_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = &wm8580_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8580_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8580_priv *wm8580;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
        if (wm8580 == NULL)
                return -ENOMEM;
 
-       codec = &wm8580->codec;
-
        i2c_set_clientdata(i2c, wm8580);
-       codec->control_data = i2c;
+       wm8580->control_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
-
-       return wm8580_register(wm8580, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+       if (ret < 0)
+               kfree(wm8580);
+       return ret;
 }
 
 static int wm8580_i2c_remove(struct i2c_client *client)
 {
-       struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
-       wm8580_unregister(wm8580);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -961,7 +944,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
 
 static struct i2c_driver wm8580_i2c_driver = {
        .driver = {
-               .name = "wm8580",
+               .name = "wm8580-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8580_i2c_probe,
@@ -972,7 +955,7 @@ static struct i2c_driver wm8580_i2c_driver = {
 
 static int __init wm8580_modinit(void)
 {
-       int ret;
+       int ret = 0;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8580_i2c_driver);
@@ -981,7 +964,7 @@ static int __init wm8580_modinit(void)
        }
 #endif
 
-       return 0;
+       return ret;
 }
 module_init(wm8580_modinit);
 
index 0dfb5ddde6a2a700fe4aacb878ae9def6af73777..1d34656d0dcb1b8711b2996d25857cb8c1f5d672 100644 (file)
 #define WM8580_PLLB  2
 
 #define WM8580_MCLK       1
-#define WM8580_DAC_CLKSEL 2
-#define WM8580_CLKOUTSRC  3
+#define WM8580_CLKOUTSRC  2
 
-#define WM8580_CLKSRC_MCLK 1
-#define WM8580_CLKSRC_PLLA 2
-#define WM8580_CLKSRC_PLLB 3
-#define WM8580_CLKSRC_OSC  4
-#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_MCLK    1
+#define WM8580_CLKSRC_PLLA    2
+#define WM8580_CLKSRC_PLLB    3
+#define WM8580_CLKSRC_OSC     4
+#define WM8580_CLKSRC_NONE    5
+#define WM8580_CLKSRC_ADCMCLK 6
 
 #define WM8580_DAI_PAIFRX 0
 #define WM8580_DAI_PAIFTX 1
 
-extern struct snd_soc_dai wm8580_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8580;
-
 #endif
 
index e2dba07f0260d77279e32b9a433220465d6071f9..54fbd76c8bca3aeeb8799b7dabd8694f60b221b9 100644 (file)
 
 #include "wm8711.h"
 
-static struct snd_soc_codec *wm8711_codec;
-
 /* codec private data */
 struct wm8711_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type bus_type;
        u16 reg_cache[WM8711_CACHEREGNUM];
        unsigned int sysclk;
 };
@@ -163,7 +161,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
        int i = get_coeff(wm8711->sysclk, params_rate(params));
        u16 srate = (coeff_div[i].sr << 2) |
@@ -227,7 +225,7 @@ static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
 
        switch (freq) {
        case 11289600:
@@ -338,8 +336,8 @@ static struct snd_soc_dai_ops wm8711_ops = {
        .set_fmt = wm8711_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8711_dai = {
-       .name = "WM8711",
+static struct snd_soc_dai_driver wm8711_dai = {
+       .name = "wm8711-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -349,22 +347,16 @@ struct snd_soc_dai wm8711_dai = {
        },
        .ops = &wm8711_ops,
 };
-EXPORT_SYMBOL_GPL(wm8711_dai);
 
-static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        snd_soc_write(codec, WM8711_ACTIVE, 0x0);
        wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8711_resume(struct platform_device *pdev)
+static int wm8711_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -380,99 +372,23 @@ static int wm8711_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8711_probe(struct platform_device *pdev)
+static int wm8711_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8711_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8711_codec;
-       codec = wm8711_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8711_snd_controls,
-                            ARRAY_SIZE(wm8711_snd_controls));
-       wm8711_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8711_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8711 = {
-       .probe =        wm8711_probe,
-       .remove =       wm8711_remove,
-       .suspend =      wm8711_suspend,
-       .resume =       wm8711_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
-
-static int wm8711_register(struct wm8711_priv *wm8711,
-                          enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8711->codec;
-       u16 reg;
-
-       if (wm8711_codec) {
-               dev_err(codec->dev, "Another WM8711 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8711);
-       codec->name = "WM8711";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8711_set_bias_level;
-       codec->dai = &wm8711_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8711_CACHEREGNUM;
-       codec->reg_cache = &wm8711->reg_cache;
-
-       memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
+       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       int ret, reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8711_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8711_dai.dev = codec->dev;
-
        wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
@@ -481,70 +397,62 @@ static int wm8711_register(struct wm8711_priv *wm8711,
        reg = snd_soc_read(codec, WM8711_ROUT1V);
        snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
 
-       wm8711_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8711_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
+       snd_soc_add_controls(codec, wm8711_snd_controls,
+                            ARRAY_SIZE(wm8711_snd_controls));
+       wm8711_add_widgets(codec);
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8711);
        return ret;
+
 }
 
-static void wm8711_unregister(struct wm8711_priv *wm8711)
+/* power down chip */
+static int wm8711_remove(struct snd_soc_codec *codec)
 {
-       wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8711_dai);
-       snd_soc_unregister_codec(&wm8711->codec);
-       kfree(wm8711);
-       wm8711_codec = NULL;
+       wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
+       .probe =        wm8711_probe,
+       .remove =       wm8711_remove,
+       .suspend =      wm8711_suspend,
+       .resume =       wm8711_resume,
+       .set_bias_level = wm8711_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8711_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8711_reg,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8711_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8711_priv *wm8711;
+       int ret;
 
        wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
-       codec = &wm8711->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
+       spi_set_drvdata(spi, wm8711);
+       wm8711->bus_type = SND_SOC_SPI;
 
-       dev_set_drvdata(&spi->dev, wm8711);
-
-       return wm8711_register(wm8711, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8711, &wm8711_dai, 1);
+       if (ret < 0)
+               kfree(wm8711);
+       return ret;
 }
 
 static int __devexit wm8711_spi_remove(struct spi_device *spi)
 {
-       struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
-
-       wm8711_unregister(wm8711);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8711_spi_driver = {
        .driver = {
-               .name   = "wm8711",
-               .bus    = &spi_bus_type,
+               .name   = "wm8711-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8711_spi_probe,
@@ -553,31 +461,30 @@ static struct spi_driver wm8711_spi_driver = {
 #endif /* CONFIG_SPI_MASTER */
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+static __devinit int wm8711_i2c_probe(struct i2c_client *client,
                                      const struct i2c_device_id *id)
 {
        struct wm8711_priv *wm8711;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
-       codec = &wm8711->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
-       i2c_set_clientdata(i2c, wm8711);
-       codec->control_data = i2c;
+       i2c_set_clientdata(client, wm8711);
+       wm8711->bus_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
-
-       return wm8711_register(wm8711, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_wm8711, &wm8711_dai, 1);
+       if (ret < 0)
+               kfree(wm8711);
+       return ret;
 }
 
 static __devexit int wm8711_i2c_remove(struct i2c_client *client)
 {
-       struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
-       wm8711_unregister(wm8711);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -589,7 +496,7 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
 
 static struct i2c_driver wm8711_i2c_driver = {
        .driver = {
-               .name = "WM8711 I2C Codec",
+               .name = "wm8711-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8711_i2c_probe,
index 381e84a4381696699a9b796d6c9c125ddf0fa3ea..a61db985499f933e88736664510e90bfa1505e03 100644 (file)
@@ -36,7 +36,4 @@ struct wm8711_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai wm8711_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8711;
-
 #endif
index 9d1df26281361ef9ed569e0b87a39d9a934f9254..7488082851191ce120a8a66fd8704b53613b8189 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "wm8727.h"
 /*
  * Note this is a simple chip with no configuration interface, sample rate is
  * determined automatically by examining the Master clock and Bit clock ratios
@@ -33,8 +32,8 @@
                        SNDRV_PCM_RATE_192000)
 
 
-struct snd_soc_dai wm8727_dai = {
-       .name = "WM8727",
+static struct snd_soc_dai_driver wm8727_dai = {
+       .name = "wm8727-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -43,103 +42,18 @@ struct snd_soc_dai wm8727_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
                },
 };
-EXPORT_SYMBOL_GPL(wm8727_dai);
 
-static struct snd_soc_codec *wm8727_codec;
+static struct snd_soc_codec_driver soc_codec_dev_wm8727;
 
-static int wm8727_soc_probe(struct platform_device *pdev)
+static __devinit int wm8727_probe(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       int ret = 0;
-
-       BUG_ON(!wm8727_codec);
-
-       socdev->card->codec = wm8727_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8727: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       return ret;
-
-pcm_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
-}
-
-static int wm8727_soc_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8727 = {
-       .probe =        wm8727_soc_probe,
-       .remove =       wm8727_soc_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
-
-
-static __devinit int wm8727_platform_probe(struct platform_device *pdev)
-{
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (wm8727_codec) {
-               dev_err(&pdev->dev, "Another WM8727 is registered\n");
-               return -EBUSY;
-       }
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-       wm8727_codec = codec;
-
-       platform_set_drvdata(pdev, codec);
-
-       mutex_init(&codec->mutex);
-       codec->dev = &pdev->dev;
-       codec->name = "WM8727";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8727_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8727_dai.dev = &pdev->dev;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8727_dai);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(codec);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm8727, &wm8727_dai, 1);
 }
 
-static int __devexit wm8727_platform_remove(struct platform_device *pdev)
+static int __devexit wm8727_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&wm8727_dai);
-       snd_soc_unregister_codec(platform_get_drvdata(pdev));
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
@@ -149,8 +63,8 @@ static struct platform_driver wm8727_codec_driver = {
                        .owner = THIS_MODULE,
        },
 
-       .probe = wm8727_platform_probe,
-       .remove = __devexit_p(wm8727_platform_remove),
+       .probe = wm8727_probe,
+       .remove = __devexit_p(wm8727_remove),
 };
 
 static int __init wm8727_init(void)
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
deleted file mode 100644 (file)
index ee19aa7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * wm8727.h
- *
- *  Created on: 15-Oct-2009
- *      Author: neil.jones@imgtec.com
- *
- * Copyright (C) 2009 Imagination Technologies 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.
- */
-
-#ifndef WM8727_H_
-#define WM8727_H_
-
-extern struct snd_soc_dai wm8727_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8727;
-
-#endif /* WM8727_H_ */
index 34be2d2b69eff81ab96f8b243d5541a7b71f2b73..075f35e4f4cbbd33bde2b9904e0bc3b894350d39 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "wm8728.h"
 
-struct snd_soc_codec_device soc_codec_dev_wm8728;
-
 /*
  * We can't read the WM8728 register space so we cache them instead.
  * Note that the defaults here aren't the physical defaults, we latch
@@ -44,6 +42,11 @@ static const u16 wm8728_reg_defaults[] = {
        0x100,
 };
 
+/* codec private data */
+struct wm8728_priv {
+       enum snd_soc_control_type control_type;
+};
+
 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
 
 static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -96,8 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 dac = snd_soc_read(codec, WM8728_DACCTL);
 
        dac &= ~0x18;
@@ -210,8 +212,8 @@ static struct snd_soc_dai_ops wm8728_dai_ops = {
        .set_fmt        = wm8728_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8728_dai = {
-       .name = "WM8728",
+static struct snd_soc_dai_driver wm8728_dai = {
+       .name = "wm8728-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -221,63 +223,31 @@ struct snd_soc_dai wm8728_dai = {
        },
        .ops = &wm8728_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8728_dai);
 
-static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8728_resume(struct platform_device *pdev)
+static int wm8728_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-/*
- * initialise the WM8728 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8728_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8728_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-
-       codec->name = "WM8728";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8728_set_bias_level;
-       codec->dai = &wm8728_dai;
-       codec->num_dai = 1;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
-       codec->reg_cache = kmemdup(wm8728_reg_defaults,
-                                  sizeof(wm8728_reg_defaults),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
                       ret);
-               goto err;
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8728: failed to create pcms\n");
-               goto err;
+               return ret;
        }
 
        /* power on device */
@@ -288,215 +258,136 @@ static int wm8728_init(struct snd_soc_device *socdev,
        wm8728_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-static struct snd_soc_device *wm8728_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8728_remove(struct snd_soc_codec *codec)
+{
+       wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-/*
- * WM8728 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
+       .probe =        wm8728_probe,
+       .remove =       wm8728_remove,
+       .suspend =      wm8728_suspend,
+       .resume =       wm8728_resume,
+       .set_bias_level = wm8728_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8728_reg_defaults,
+};
 
-static int wm8728_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8728_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8728_priv *wm8728;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       if (wm8728 == NULL)
+               return -ENOMEM;
+
+       wm8728->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8728);
 
-       ret = wm8728_init(socdev, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8728, &wm8728_dai, 1);
        if (ret < 0)
-               pr_err("failed to initialise WM8728\n");
-
+               kfree(wm8728);
        return ret;
 }
 
-static int wm8728_i2c_remove(struct i2c_client *client)
+static int __devexit wm8728_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8728_i2c_id[] = {
-       { "wm8728", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
-
-static struct i2c_driver wm8728_i2c_driver = {
+static struct spi_driver wm8728_spi_driver = {
        .driver = {
-               .name = "WM8728 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8728-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8728_i2c_probe,
-       .remove =   wm8728_i2c_remove,
-       .id_table = wm8728_i2c_id,
+       .probe          = wm8728_spi_probe,
+       .remove         = __devexit_p(wm8728_spi_remove),
 };
+#endif /* CONFIG_SPI_MASTER */
 
-static int wm8728_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8728_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
+       struct wm8728_priv *wm8728;
        int ret;
 
-       ret = i2c_add_driver(&wm8728_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8728_i2c_driver);
-       return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8728_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret;
+       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       if (wm8728 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = spi;
+       i2c_set_clientdata(i2c, wm8728);
+       wm8728->control_type = SND_SOC_I2C;
 
-       ret = wm8728_init(socdev, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8728, &wm8728_dai, 1);
        if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8728\n");
-
+               kfree(wm8728);
        return ret;
 }
 
-static int __devexit wm8728_spi_remove(struct spi_device *spi)
+static __devexit int wm8728_i2c_remove(struct i2c_client *client)
 {
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8728_spi_driver = {
+static const struct i2c_device_id wm8728_i2c_id[] = {
+       { "wm8728", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
+
+static struct i2c_driver wm8728_i2c_driver = {
        .driver = {
-               .name   = "wm8728",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8728-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8728_spi_probe,
-       .remove         = __devexit_p(wm8728_spi_remove),
+       .probe =    wm8728_i2c_probe,
+       .remove =   __devexit_p(wm8728_i2c_remove),
+       .id_table = wm8728_i2c_id,
 };
-#endif /* CONFIG_SPI_MASTER */
+#endif
 
-static int wm8728_probe(struct platform_device *pdev)
+static int __init wm8728_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8728_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8728_socdev = socdev;
-       ret = -ENODEV;
-
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8728_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&wm8728_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
+                      ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               ret = spi_register_driver(&wm8728_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
+       ret = spi_register_driver(&wm8728_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
+                      ret);
        }
 #endif
-
-       if (ret != 0)
-               kfree(codec);
-
        return ret;
 }
+module_init(wm8728_modinit);
 
-/* power down chip */
-static int wm8728_remove(struct platform_device *pdev)
+static void __exit wm8728_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8728_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8728_spi_driver);
 #endif
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8728 = {
-       .probe =        wm8728_probe,
-       .remove =       wm8728_remove,
-       .suspend =      wm8728_suspend,
-       .resume =       wm8728_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
-
-static int __init wm8728_modinit(void)
-{
-       return snd_soc_register_dai(&wm8728_dai);
-}
-module_init(wm8728_modinit);
-
-static void __exit wm8728_exit(void)
-{
-       snd_soc_unregister_dai(&wm8728_dai);
 }
 module_exit(wm8728_exit);
 
index d269c132474b7e0e2c44ad78182b45d21208dd7f..8aea362ffd47e2c7672937e5c5e89db4bd099c6b 100644 (file)
 #define WM8728_DACCTL    0x02
 #define WM8728_IFCTL     0x03
 
-struct wm8728_setup_data {
-       int            spi;
-       int            i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8728_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8728;
-
 #endif
index 0ab9b6355297d9116aa2f27045ac2c8005c42f4c..631385802eb44a587f5fe375d8f1c61e89ba9d02 100644 (file)
@@ -32,9 +32,6 @@
 
 #include "wm8731.h"
 
-static struct snd_soc_codec *wm8731_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8731;
-
 #define WM8731_NUM_SUPPLIES 4
 static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
        "AVDD",
@@ -45,10 +42,11 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8731_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
        u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
+       int sysclk_type;
 };
 
 
@@ -113,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
 
 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
 SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
        &wm8731_output_mixer_controls[0],
        ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -130,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
 SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 
+static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+                           struct snd_soc_dapm_widget *sink)
+{
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+
+       return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
+}
+
 static const struct snd_soc_dapm_route intercon[] = {
+       {"DAC", NULL, "OSC", wm8731_check_osc},
+       {"ADC", NULL, "OSC", wm8731_check_osc},
+
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -222,9 +232,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
        int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -252,9 +260,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
 static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* set active */
        snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
@@ -265,9 +271,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
 static void wm8731_shutdown(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* deactivate */
        if (!codec->active) {
@@ -294,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
+       switch (clk_id) {
+       case WM8731_SYSCLK_XTAL:
+       case WM8731_SYSCLK_MCLK:
+               wm8731->sysclk_type = clk_id;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        switch (freq) {
        case 11289600:
        case 12000000:
@@ -301,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        case 16934400:
        case 18432000:
                wm8731->sysclk = freq;
-               return 0;
+               break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
 }
 
 
@@ -428,8 +446,8 @@ static struct snd_soc_dai_ops wm8731_dai_ops = {
        .set_fmt        = wm8731_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8731_dai = {
-       .name = "WM8731",
+static struct snd_soc_dai_driver wm8731_dai = {
+       .name = "wm8731-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -445,24 +463,17 @@ struct snd_soc_dai wm8731_dai = {
        .ops = &wm8731_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8731_dai);
 
 #ifdef CONFIG_PM
-static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8731_resume(struct platform_device *pdev)
+static int wm8731_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -472,88 +483,15 @@ static int wm8731_resume(struct platform_device *pdev)
 #define wm8731_resume NULL
 #endif
 
-static int wm8731_probe(struct platform_device *pdev)
+static int wm8731_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8731_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8731_codec;
-       codec = wm8731_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8731_snd_controls,
-                            ARRAY_SIZE(wm8731_snd_controls));
-       wm8731_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
-       .probe =        wm8731_probe,
-       .remove =       wm8731_remove,
-       .suspend =      wm8731_suspend,
-       .resume =       wm8731_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
-
-static int wm8731_register(struct wm8731_priv *wm8731,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8731->codec;
-
-       if (wm8731_codec) {
-               dev_err(codec->dev, "Another WM8731 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8731);
-       codec->name = "WM8731";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8731_set_bias_level;
-       codec->dai = &wm8731_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8731_CACHEREGNUM;
-       codec->reg_cache = &wm8731->reg_cache;
-
-       memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
@@ -563,7 +501,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                                 wm8731->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
@@ -579,8 +517,6 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                goto err_regulator_enable;
        }
 
-       wm8731_dai.dev = codec->dev;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
@@ -592,79 +528,78 @@ static int wm8731_register(struct wm8731_priv *wm8731,
        /* Disable bypass path by default */
        snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
 
-       wm8731_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_regulator_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8731_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8731_snd_controls,
+                            ARRAY_SIZE(wm8731_snd_controls));
+       wm8731_add_widgets(codec);
 
        /* Regulators will have been enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 err_regulator_get:
        regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err:
+
        kfree(wm8731);
        return ret;
 }
 
-static void wm8731_unregister(struct wm8731_priv *wm8731)
+/* power down chip */
+static int wm8731_remove(struct snd_soc_codec *codec)
 {
-       wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8731_dai);
-       snd_soc_unregister_codec(&wm8731->codec);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
        regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-       kfree(wm8731);
-       wm8731_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
+       .probe =        wm8731_probe,
+       .remove =       wm8731_remove,
+       .suspend =      wm8731_suspend,
+       .resume =       wm8731_resume,
+       .set_bias_level = wm8731_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8731_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8731_reg,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8731_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8731_priv *wm8731;
+       int ret;
 
        wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       codec = &wm8731->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8731);
+       wm8731->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8731);
 
-       return wm8731_register(wm8731, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8731, &wm8731_dai, 1);
+       if (ret < 0)
+               kfree(wm8731);
+       return ret;
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-       struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
-
-       wm8731_unregister(wm8731);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
-               .name   = "wm8731",
-               .bus    = &spi_bus_type,
+               .name   = "wm8731-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
@@ -677,26 +612,26 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8731_priv *wm8731;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       codec = &wm8731->codec;
-
        i2c_set_clientdata(i2c, wm8731);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8731->control_type = SND_SOC_I2C;
 
-       return wm8731_register(wm8731, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8731, &wm8731_dai, 1);
+       if (ret < 0)
+               kfree(wm8731);
+       return ret;
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
 {
-       struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
-       wm8731_unregister(wm8731);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -708,7 +643,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
-               .name = "wm8731",
+               .name = "wm8731-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8731_i2c_probe,
@@ -719,7 +654,7 @@ static struct i2c_driver wm8731_i2c_driver = {
 
 static int __init wm8731_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8731_i2c_driver);
        if (ret != 0) {
@@ -734,7 +669,7 @@ static int __init wm8731_modinit(void)
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8731_modinit);
 
index cd7b806e8ad0b745db1116f40b1682733f8d1780..e9c0c76ab73bf4ca72f667e5ef2d2d063ff5028a 100644 (file)
 
 #define WM8731_CACHEREGNUM     10
 
-#define WM8731_SYSCLK  0
-#define WM8731_DAI             0
+#define WM8731_SYSCLK_XTAL 1
+#define WM8731_SYSCLK_MCLK 2
 
-extern struct snd_soc_dai wm8731_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+#define WM8731_DAI             0
 
 #endif
index b9ea8904ad4b2102a7f43f0b7655b0cd661290bf..90e31e9aa6f7c66346c8360a3c1ab900519e4a98 100644 (file)
 
 #include "wm8741.h"
 
-static struct snd_soc_codec *wm8741_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8741;
-
 #define WM8741_NUM_SUPPLIES 2
 static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
        "AVDD",
        "DVDD",
 };
 
-#define WM8741_NUM_RATES 4
+#define WM8741_NUM_RATES 6
 
 /* codec private data */
 struct wm8741_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8741_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
        unsigned int sysclk;
-       unsigned int rate_constraint_list[WM8741_NUM_RATES];
-       struct snd_pcm_hw_constraint_list rate_constraint;
+       struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
 static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
@@ -111,10 +107,84 @@ static struct {
        int value;
        int ratio;
 } lrclk_ratios[WM8741_NUM_RATES] = {
-       { 1, 256 },
-       { 2, 384 },
-       { 3, 512 },
-       { 4, 768 },
+       { 1, 128 },
+       { 2, 192 },
+       { 3, 256 },
+       { 4, 384 },
+       { 5, 512 },
+       { 6, 768 },
+};
+
+static unsigned int rates_11289[] = {
+       44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_11289 = {
+       .count  = ARRAY_SIZE(rates_11289),
+       .list   = rates_11289,
+};
+
+static unsigned int rates_12288[] = {
+       32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+       .count  = ARRAY_SIZE(rates_12288),
+       .list   = rates_12288,
+};
+
+static unsigned int rates_16384[] = {
+       32000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16384 = {
+       .count  = ARRAY_SIZE(rates_16384),
+       .list   = rates_16384,
+};
+
+static unsigned int rates_16934[] = {
+       44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16934 = {
+       .count  = ARRAY_SIZE(rates_16934),
+       .list   = rates_16934,
+};
+
+static unsigned int rates_18432[] = {
+       48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_18432 = {
+       .count  = ARRAY_SIZE(rates_18432),
+       .list   = rates_18432,
+};
+
+static unsigned int rates_22579[] = {
+       44100, 88235, 1764000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_22579 = {
+       .count  = ARRAY_SIZE(rates_22579),
+       .list   = rates_22579,
+};
+
+static unsigned int rates_24576[] = {
+       32000, 48000, 96000, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_24576 = {
+       .count  = ARRAY_SIZE(rates_24576),
+       .list   = rates_24576,
+};
+
+static unsigned int rates_36864[] = {
+       48000, 96000, 19200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_36864 = {
+       .count  = ARRAY_SIZE(rates_36864),
+       .list   = rates_36864,
 };
 
 
@@ -135,7 +205,7 @@ static int wm8741_startup(struct snd_pcm_substream *substream,
 
        snd_pcm_hw_constraint_list(substream->runtime, 0,
                                   SNDRV_PCM_HW_PARAM_RATE,
-                                  &wm8741->rate_constraint);
+                                  wm8741->sysclk_constraints);
 
        return 0;
 }
@@ -145,8 +215,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
        int i;
@@ -196,47 +265,52 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val;
-       int i;
 
        dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
 
-       wm8741->sysclk = freq;
-
-       wm8741->rate_constraint.count = 0;
-
-       for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
-               dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
-                               i, lrclk_ratios[i].ratio, freq);
-
-               val = freq / lrclk_ratios[i].ratio;
-               /* Check that it's a standard rate since core can't
-                * cope with others and having the odd rates confuses
-                * constraint matching.
-                */
-               switch (val) {
-               case 32000:
-               case 44100:
-               case 48000:
-               case 64000:
-               case 88200:
-               case 96000:
-                       dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
-                               val);
-                       wm8741->rate_constraint_list[i] = val;
-                       wm8741->rate_constraint.count++;
-                       break;
-               default:
-                       dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
-                               val);
-               }
+       switch (freq) {
+       case 11289600:
+               wm8741->sysclk_constraints = &constraints_11289;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 12288000:
+               wm8741->sysclk_constraints = &constraints_12288;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 16384000:
+               wm8741->sysclk_constraints = &constraints_16384;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 16934400:
+               wm8741->sysclk_constraints = &constraints_16934;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 18432000:
+               wm8741->sysclk_constraints = &constraints_18432;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 22579200:
+       case 33868800:
+               wm8741->sysclk_constraints = &constraints_22579;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 24576000:
+               wm8741->sysclk_constraints = &constraints_24576;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 36864000:
+               wm8741->sysclk_constraints = &constraints_36864;
+               wm8741->sysclk = freq;
+               return 0;
        }
-
-       /* Need at least one supported rate... */
-       if (wm8741->rate_constraint.count == 0)
-               return -EINVAL;
-
-       return 0;
+       return -EINVAL;
 }
 
 static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -314,8 +388,8 @@ static struct snd_soc_dai_ops wm8741_dai_ops = {
        .set_fmt        = wm8741_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8741_dai = {
-       .name = "WM8741",
+static struct snd_soc_dai_driver wm8741_dai = {
+       .name = "wm8741",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,  /* Mono modes not yet supported */
@@ -325,13 +399,10 @@ struct snd_soc_dai wm8741_dai = {
        },
        .ops = &wm8741_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8741_dai);
 
 #ifdef CONFIG_PM
-static int wm8741_resume(struct platform_device *pdev)
+static int wm8741_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 *cache = codec->reg_cache;
        int i;
 
@@ -348,189 +419,99 @@ static int wm8741_resume(struct platform_device *pdev)
 #define wm8741_resume NULL
 #endif
 
-static int wm8741_probe(struct platform_device *pdev)
+static int wm8741_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       if (wm8741_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8741_codec;
-       codec = wm8741_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8741_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       /* Change some default settings - latch VU */
+       wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+       wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+
        snd_soc_add_controls(codec, wm8741_snd_controls,
                             ARRAY_SIZE(wm8741_snd_controls));
        wm8741_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
+       dev_dbg(codec->dev, "Successful registration\n");
        return ret;
 }
 
-static int wm8741_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8741 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .probe =        wm8741_probe,
-       .remove =       wm8741_remove,
        .resume =       wm8741_resume,
+       .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = &wm8741_reg_defaults,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
 
-static int wm8741_register(struct wm8741_priv *wm8741,
-                          enum snd_soc_control_type control)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8741_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
-       int ret;
-       struct snd_soc_codec *codec = &wm8741->codec;
-       int i;
-
-       if (wm8741_codec) {
-               dev_err(codec->dev, "Another WM8741 is registered\n");
-               return -EINVAL;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8741);
-       codec->name = "WM8741";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = NULL;
-       codec->dai = &wm8741_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8741_REGISTER_COUNT;
-       codec->reg_cache = &wm8741->reg_cache;
-
-       wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
-       wm8741->rate_constraint.count =
-               ARRAY_SIZE(wm8741->rate_constraint_list);
-
-       memcpy(codec->reg_cache, wm8741_reg_defaults,
-               sizeof(wm8741->reg_cache));
+       struct wm8741_priv *wm8741;
+       int ret, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
+       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+       if (wm8741 == NULL)
+               return -ENOMEM;
 
        for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
                wm8741->supplies[i].supply = wm8741_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
+       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
                                 wm8741->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
                goto err;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
                                    wm8741->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
                goto err_get;
        }
 
-       ret = wm8741_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_enable;
-       }
-
-       wm8741_dai.dev = codec->dev;
-
-       /* Change some default settings - latch VU */
-       wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
-       wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
-       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
-       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
-
-       wm8741_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&wm8741_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               return ret;
-       }
+       i2c_set_clientdata(i2c, wm8741);
+       wm8741->control_type = SND_SOC_I2C;
 
-       dev_dbg(codec->dev, "Successful registration\n");
-       return 0;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8741, &wm8741_dai, 1);
+       if (ret < 0)
+               goto err_enable;
+       return ret;
 
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
 
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
 err:
        kfree(wm8741);
        return ret;
 }
 
-static void wm8741_unregister(struct wm8741_priv *wm8741)
-{
-       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
-       snd_soc_unregister_dai(&wm8741_dai);
-       snd_soc_unregister_codec(&wm8741->codec);
-       kfree(wm8741);
-       wm8741_codec = NULL;
-}
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
-{
-       struct wm8741_priv *wm8741;
-       struct snd_soc_codec *codec;
-
-       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
-       if (wm8741 == NULL)
-               return -ENOMEM;
-
-       codec = &wm8741->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
-       i2c_set_clientdata(i2c, wm8741);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
-
-       return wm8741_register(wm8741, SND_SOC_I2C);
-}
-
-static __devexit int wm8741_i2c_remove(struct i2c_client *client)
+static int wm8741_i2c_remove(struct i2c_client *client)
 {
        struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
-       wm8741_unregister(wm8741);
+
+       snd_soc_unregister_codec(&client->dev);
+       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -540,29 +521,28 @@ static const struct i2c_device_id wm8741_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
 
-
 static struct i2c_driver wm8741_i2c_driver = {
        .driver = {
-               .name = "WM8741",
+               .name = "wm8741-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8741_i2c_probe,
-       .remove =   __devexit_p(wm8741_i2c_remove),
+       .remove =   wm8741_i2c_remove,
        .id_table = wm8741_i2c_id,
 };
 #endif
 
 static int __init wm8741_modinit(void)
 {
-       int ret;
+       int ret = 0;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8741_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
-                      ret);
-       }
+       if (ret != 0)
+               pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
 #endif
-       return 0;
+
+       return ret;
 }
 module_init(wm8741_modinit);
 
index fdef6ecd1f6f14db43fe2a59b4f53e9d937d5b98..56c1b1d4a68100f52fcf6ec61363a9140e88e63a 100644 (file)
 
 #define  WM8741_SYSCLK 0
 
-extern struct snd_soc_dai wm8741_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8741;
-
 #endif
index e2c05e3e323a0bb24010d55bf7e8800c1b1c07c0..6c924cd2cfd45a2149f07ca917a4e36faf8149b0 100644 (file)
@@ -52,7 +52,7 @@ static const u16 wm8750_reg[] = {
 /* codec private data */
 struct wm8750_priv {
        unsigned int sysclk;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
 };
 
@@ -560,8 +560,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
@@ -649,8 +648,8 @@ static struct snd_soc_dai_ops wm8750_dai_ops = {
        .set_sysclk     = wm8750_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8750_dai = {
-       .name = "WM8750",
+static struct snd_soc_dai_driver wm8750_dai = {
+       .name = "wm8750-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -665,21 +664,15 @@ struct snd_soc_dai wm8750_dai = {
                .formats = WM8750_FORMATS,},
        .ops = &wm8750_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8750_dai);
 
-static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8750_resume(struct platform_device *pdev)
+static int wm8750_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -698,100 +691,21 @@ static int wm8750_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8750_codec;
-
-static int wm8750_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (!wm8750_codec) {
-               dev_err(&pdev->dev, "WM8750 codec not yet registered\n");
-               return -EINVAL;
-       }
-
-       socdev->card->codec = wm8750_codec;
-       codec = wm8750_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8750: failed to create pcms\n");
-               goto err;
-       }
-
-       snd_soc_add_controls(codec, wm8750_snd_controls,
-                               ARRAY_SIZE(wm8750_snd_controls));
-       wm8750_add_widgets(codec);
-
-       return 0;
-
-err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8750_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8750 = {
-       .probe          = wm8750_probe,
-       .remove         = wm8750_remove,
-       .suspend        = wm8750_suspend,
-       .resume         = wm8750_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
-
-/*
- * initialise the WM8750 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8750_register(struct wm8750_priv *wm8750,
-                       enum snd_soc_control_type control)
+static int wm8750_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8750->codec;
-       int reg, ret = 0;
-
-       if (wm8750_codec) {
-               dev_err(codec->dev, "Multiple WM8750 devices not supported\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8750";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
-       codec->set_bias_level = wm8750_set_bias_level;
-       codec->dai = &wm8750_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1;
-       codec->reg_cache = &wm8750->reg_cache;
-       snd_soc_codec_set_drvdata(codec, wm8750);
-
-       memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache));
+       struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
+       int reg, ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8750_reset(codec);
        if (ret < 0) {
                printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        /* charge output caps */
@@ -815,150 +729,130 @@ static int wm8750_register(struct wm8750_priv *wm8750,
        reg = snd_soc_read(codec, WM8750_RINVOL);
        snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
 
-       wm8750_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(&wm8750_dai, 1);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8750);
+       snd_soc_add_controls(codec, wm8750_snd_controls,
+                               ARRAY_SIZE(wm8750_snd_controls));
+       wm8750_add_widgets(codec);
        return ret;
 }
 
-static void wm8750_unregister(struct wm8750_priv *wm8750)
+static int wm8750_remove(struct snd_soc_codec *codec)
 {
-       wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(&wm8750_dai, 1);
-       snd_soc_unregister_codec(&wm8750->codec);
-       kfree(wm8750);
-       wm8750_codec = NULL;
+       wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8750 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
+       .probe =        wm8750_probe,
+       .remove =       wm8750_remove,
+       .suspend =      wm8750_suspend,
+       .resume =       wm8750_resume,
+       .set_bias_level = wm8750_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8750_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8750_reg,
+};
 
-static int wm8750_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8750_priv *wm8750;
+       int ret;
 
        wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
-       codec = &wm8750->codec;
-       codec->control_data = i2c;
-       i2c_set_clientdata(i2c, wm8750);
-
-       codec->dev = &i2c->dev;
+       wm8750->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8750);
 
-       return wm8750_register(wm8750, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8750, &wm8750_dai, 1);
+       if (ret < 0)
+               kfree(wm8750);
+       return ret;
 }
 
-static int wm8750_i2c_remove(struct i2c_client *client)
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
 {
-       struct wm8750_priv *wm8750 = i2c_get_clientdata(client);
-       wm8750_unregister(wm8750);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8750_i2c_id[] = {
-       { "wm8750", 0 },
-       { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
-
-static struct i2c_driver wm8750_i2c_driver = {
+static struct spi_driver wm8750_spi_driver = {
        .driver = {
-               .name = "WM8750 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8750-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8750_i2c_probe,
-       .remove =   wm8750_i2c_remove,
-       .id_table = wm8750_i2c_id,
+       .probe          = wm8750_spi_probe,
+       .remove         = __devexit_p(wm8750_spi_remove),
 };
-#endif
+#endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8750_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
        struct wm8750_priv *wm8750;
+       int ret;
 
        wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
-       codec = &wm8750->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8750);
+       i2c_set_clientdata(i2c, wm8750);
+       wm8750->control_type = SND_SOC_I2C;
 
-       return wm8750_register(wm8750, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8750, &wm8750_dai, 1);
+       if (ret < 0)
+               kfree(wm8750);
+       return ret;
 }
 
-static int __devexit wm8750_spi_remove(struct spi_device *spi)
+static __devexit int wm8750_i2c_remove(struct i2c_client *client)
 {
-       struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev);
-       wm8750_unregister(wm8750);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static const struct spi_device_id wm8750_spi_id[] = {
+static const struct i2c_device_id wm8750_i2c_id[] = {
        { "wm8750", 0 },
        { "wm8987", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
 
-static struct spi_driver wm8750_spi_driver = {
+static struct i2c_driver wm8750_i2c_driver = {
        .driver = {
-               .name   = "WM8750 SPI Codec",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8750-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8750_spi_probe,
-       .remove         = __devexit_p(wm8750_spi_remove),
-       .id_table       = wm8750_spi_id,
+       .probe =    wm8750_i2c_probe,
+       .remove =   __devexit_p(wm8750_i2c_remove),
+       .id_table = wm8750_i2c_id,
 };
 #endif
 
 static int __init wm8750_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8750_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8750 I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8750_spi_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8750 SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
+                      ret);
+       }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8750_modinit);
 
index 1dc100e19cfe3076019a4c564999f4e061844b4d..121427c047fbfd267cbf2fd2f44f588a6b5f6ff6 100644 (file)
 
 #define WM8750_SYSCLK  0
 
-struct wm8750_setup_data {
-       int spi;
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8750_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8750;
-
 #endif
index b59f349c52184fc9bf83a975f8e921f2fda92632..8f679a13f2bcaae23653adaffafff6fedcd8e66f 100644 (file)
@@ -57,7 +57,7 @@ module_param(caps_charge, int, 0);
 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
 
 static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
-       unsigned int mode);
+               struct snd_soc_dai *dai, unsigned int hifi);
 
 /*
  * wm8753 register cache
@@ -85,10 +85,11 @@ static const u16 wm8753_reg[] = {
 
 /* codec private data */
 struct wm8753_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
        unsigned int pcmclk;
-       struct snd_soc_codec codec;
        u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+       int dai_func;
 };
 
 /*
@@ -228,6 +229,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
        int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
                return 0;
@@ -235,8 +237,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        mode &= 0xfff3;
        mode |= (ucontrol->value.integer.value[0] << 2);
 
-       wm8753_write(codec, WM8753_IOCTL, mode);
-       wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
+       wm8753->dai_func =  ucontrol->value.integer.value[0];
        return 1;
 }
 
@@ -904,6 +905,13 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       wm8753_set_dai_mode(dai->codec, dai, 0);
+       return 0;
+}
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -912,8 +920,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1138,6 +1145,13 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       wm8753_set_dai_mode(dai->codec, dai, 1);
+       return 0;
+}
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -1146,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
        u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1240,12 +1253,12 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
         * make sure we check if they are not both active when we mute */
-       if (mute && dai->id == 1) {
-               if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||
-                       !wm8753_dai[WM8753_DAI_HIFI].playback.active)
+       if (mute && wm8753->dai_func == 1) {
+               if (!codec->active)
                        wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
        } else {
                if (mute)
@@ -1303,6 +1316,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode1h_set_dai_fmt,
@@ -1312,6 +1326,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+       .startup = wm8753_pcm_startup,
        .hw_params      = wm8753_pcm_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode1v_set_dai_fmt,
@@ -1321,6 +1336,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+       .startup = wm8753_pcm_startup,
        .hw_params      = wm8753_pcm_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode2_set_dai_fmt,
@@ -1330,6 +1346,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3        = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode3_4_set_dai_fmt,
@@ -1339,6 +1356,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3   = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4        = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode3_4_set_dai_fmt,
@@ -1347,10 +1365,9 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4  = {
        .set_sysclk     = wm8753_set_dai_sysclk,
 };
 
-static const struct snd_soc_dai wm8753_all_dai[] = {
+static struct snd_soc_dai_driver wm8753_all_dai[] = {
 /* DAI HiFi mode 1 */
-{      .name = "WM8753 HiFi",
-       .id = 1,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1366,8 +1383,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode1,
 },
 /* DAI Voice mode 1 */
-{      .name = "WM8753 Voice",
-       .id = 1,
+{      .name = "wm8753-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1383,12 +1399,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_voice_mode1,
 },
 /* DAI HiFi mode 2 - dummy */
-{      .name = "WM8753 HiFi",
-       .id = 2,
+{      .name = "wm8753-hifi",
 },
 /* DAI Voice mode 2 */
-{      .name = "WM8753 Voice",
-       .id = 2,
+{      .name = "wm8753-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1404,8 +1418,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_voice_mode2,
 },
 /* DAI HiFi mode 3 */
-{      .name = "WM8753 HiFi",
-       .id = 3,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1421,12 +1434,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode3,
 },
 /* DAI Voice mode 3 - dummy */
-{      .name = "WM8753 Voice",
-       .id = 3,
+{      .name = "wm8753-voice",
 },
 /* DAI HiFi mode 4 */
-{      .name = "WM8753 HiFi",
-       .id = 4,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1442,58 +1453,31 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode4,
 },
 /* DAI Voice mode 4 - dummy */
-{      .name = "WM8753 Voice",
-       .id = 4,
+{      .name = "wm8753-voice",
 },
 };
 
-struct snd_soc_dai wm8753_dai[] = {
+static struct snd_soc_dai_driver wm8753_dai[] = {
        {
-               .name = "WM8753 DAI 0",
+               .name = "wm8753-aif0",
        },
        {
-               .name = "WM8753 DAI 1",
+               .name = "wm8753-aif1",
        },
 };
-EXPORT_SYMBOL_GPL(wm8753_dai);
 
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
+static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+               struct snd_soc_dai *dai, unsigned int hifi)
 {
-       if (mode < 4) {
-               int playback_active, capture_active, codec_active, pop_wait;
-               void *private_data;
-               struct list_head list;
-
-               playback_active = wm8753_dai[0].playback.active;
-               capture_active = wm8753_dai[0].capture.active;
-               codec_active = wm8753_dai[0].active;
-               private_data = wm8753_dai[0].private_data;
-               pop_wait = wm8753_dai[0].pop_wait;
-               list = wm8753_dai[0].list;
-               wm8753_dai[0] = wm8753_all_dai[mode << 1];
-               wm8753_dai[0].playback.active = playback_active;
-               wm8753_dai[0].capture.active = capture_active;
-               wm8753_dai[0].active = codec_active;
-               wm8753_dai[0].private_data = private_data;
-               wm8753_dai[0].pop_wait = pop_wait;
-               wm8753_dai[0].list = list;
-
-               playback_active = wm8753_dai[1].playback.active;
-               capture_active = wm8753_dai[1].capture.active;
-               codec_active = wm8753_dai[1].active;
-               private_data = wm8753_dai[1].private_data;
-               pop_wait = wm8753_dai[1].pop_wait;
-               list = wm8753_dai[1].list;
-               wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
-               wm8753_dai[1].playback.active = playback_active;
-               wm8753_dai[1].capture.active = capture_active;
-               wm8753_dai[1].active = codec_active;
-               wm8753_dai[1].private_data = private_data;
-               wm8753_dai[1].pop_wait = pop_wait;
-               wm8753_dai[1].list = list;
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8753->dai_func < 4) {
+               if (hifi)
+                       dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
+               else
+                       dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
        }
-       wm8753_dai[0].codec = codec;
-       wm8753_dai[1].codec = codec;
+       wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
 }
 
 static void wm8753_work(struct work_struct *work)
@@ -1503,19 +1487,14 @@ static void wm8753_work(struct work_struct *work)
        wm8753_set_bias_level(codec, codec->bias_level);
 }
 
-static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8753_resume(struct platform_device *pdev)
+static int wm8753_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1547,41 +1526,6 @@ static int wm8753_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8753_codec;
-
-static int wm8753_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (!wm8753_codec) {
-               dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
-               return -EINVAL;
-       }
-
-       socdev->card->codec = wm8753_codec;
-       codec = wm8753_codec;
-
-       wm8753_set_dai_mode(codec, 0);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8753: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8753_snd_controls,
-                            ARRAY_SIZE(wm8753_snd_controls));
-       wm8753_add_widgets(codec);
-
-       return 0;
-
-pcm_err:
-       return ret;
-}
-
 /*
  * This function forces any delayed work to be queued and run.
  */
@@ -1601,62 +1545,28 @@ static int run_delayed_work(struct delayed_work *dwork)
        return ret;
 }
 
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
+static int wm8753_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
-       .probe =        wm8753_probe,
-       .remove =       wm8753_remove,
-       .suspend =      wm8753_suspend,
-       .resume =       wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
 
-static int wm8753_register(struct wm8753_priv *wm8753)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8753->codec;
-       u16 reg;
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
 
-       if (wm8753_codec) {
-               dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
-               ret = -EINVAL;
-               goto err;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8753";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8753_read_reg_cache;
-       codec->write = wm8753_write;
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
-       codec->set_bias_level = wm8753_set_bias_level;
-       codec->dai = wm8753_dai;
-       codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
-       codec->reg_cache = &wm8753->reg_cache;
-       snd_soc_codec_set_drvdata(codec, wm8753);
-
-       memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
-
        ret = wm8753_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
        }
 
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8753->dai_func = 0;
+
        /* charge output caps */
        wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
        schedule_delayed_work(&codec->delayed_work,
@@ -1684,165 +1594,133 @@ static int wm8753_register(struct wm8753_priv *wm8753)
        reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
        wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
 
-       wm8753_codec = codec;
-
-       for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
-               wm8753_dai[i].dev = codec->dev;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8753_snd_controls,
+                            ARRAY_SIZE(wm8753_snd_controls));
+       wm8753_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       run_delayed_work(&codec->delayed_work);
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8753);
-       return ret;
 }
 
-static void wm8753_unregister(struct wm8753_priv *wm8753)
+/* power down chip */
+static int wm8753_remove(struct snd_soc_codec *codec)
 {
-       wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
-       run_delayed_work(&wm8753->codec.delayed_work);
-       snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
-       snd_soc_unregister_codec(&wm8753->codec);
-       kfree(wm8753);
-       wm8753_codec = NULL;
+       run_delayed_work(&codec->delayed_work);
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
+       .probe =        wm8753_probe,
+       .remove =       wm8753_remove,
+       .suspend =      wm8753_suspend,
+       .resume =       wm8753_resume,
+       .set_bias_level = wm8753_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8753_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8753_reg,
+};
 
-static int wm8753_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8753_priv *wm8753;
+       int ret;
 
        wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
        if (wm8753 == NULL)
                return -ENOMEM;
 
-        codec = &wm8753->codec;
-        codec->hw_write = (hw_write_t)i2c_master_send;
-        codec->control_data = i2c;
-        i2c_set_clientdata(i2c, wm8753);
-
-        codec->dev = &i2c->dev;
+       wm8753->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8753);
 
-       return wm8753_register(wm8753);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+       if (ret < 0)
+               kfree(wm8753);
+       return ret;
 }
 
-static int wm8753_i2c_remove(struct i2c_client *client)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
-        struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
-        wm8753_unregister(wm8753);
-        return 0;
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
 }
 
-static const struct i2c_device_id wm8753_i2c_id[] = {
-       { "wm8753", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
-
-static struct i2c_driver wm8753_i2c_driver = {
+static struct spi_driver wm8753_spi_driver = {
        .driver = {
-               .name = "wm8753",
-               .owner = THIS_MODULE,
+               .name   = "wm8753-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8753_i2c_probe,
-       .remove =   wm8753_i2c_remove,
-       .id_table = wm8753_i2c_id,
+       .probe          = wm8753_spi_probe,
+       .remove         = __devexit_p(wm8753_spi_remove),
 };
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
-{
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
+#endif /* CONFIG_SPI_MASTER */
 
-       msg[0] = data[0];
-       msg[1] = data[1];
-
-       spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
        struct wm8753_priv *wm8753;
+       int ret;
 
        wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
        if (wm8753 == NULL)
                return -ENOMEM;
 
-       codec = &wm8753->codec;
-       codec->control_data = spi;
-       codec->hw_write = (hw_write_t)wm8753_spi_write;
-       codec->dev = &spi->dev;
+       i2c_set_clientdata(i2c, wm8753);
+       wm8753->control_type = SND_SOC_I2C;
 
-       dev_set_drvdata(&spi->dev, wm8753);
-
-       return wm8753_register(wm8753);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+       if (ret < 0)
+               kfree(wm8753);
+       return ret;
 }
 
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
+static __devexit int wm8753_i2c_remove(struct i2c_client *client)
 {
-       struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
-       wm8753_unregister(wm8753);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8753_spi_driver = {
+static const struct i2c_device_id wm8753_i2c_id[] = {
+       { "wm8753", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
+
+static struct i2c_driver wm8753_i2c_driver = {
        .driver = {
-               .name   = "wm8753",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8753-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8753_spi_probe,
-       .remove         = __devexit_p(wm8753_spi_remove),
+       .probe =    wm8753_i2c_probe,
+       .remove =   __devexit_p(wm8753_i2c_remove),
+       .id_table = wm8753_i2c_id,
 };
 #endif
 
 static int __init wm8753_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8753_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8753_spi_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
+                      ret);
+       }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8753_modinit);
 
index 57b2ba244040dea6a26e806c57401cd22a27ebf3..94edac144bcbef3b94754f4d624352f230a4453c 100644 (file)
 #define WM8753_DAI_HIFI                0
 #define WM8753_DAI_VOICE               1
 
-extern struct snd_soc_dai wm8753_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm8753;
-
 #endif
index f8154e661524c64e1098f318d447ba7bfcda3616..04182c464e35ffeffb069ad06242dca74da52248 100644 (file)
 
 #include "wm8776.h"
 
-static struct snd_soc_codec *wm8776_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8776;
-
 /* codec private data */
 struct wm8776_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8776_CACHEREGNUM];
        int sysclk[2];
 };
 
-#ifdef CONFIG_SPI_MASTER
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
-
 static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
        0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
        0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
@@ -144,7 +137,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_codec *codec = dai->codec;
        int reg, iface, master;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -226,7 +219,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 
        iface = 0;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                iface_reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -260,7 +253,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
        /* Only need to set MCLK/LRCLK ratio if we're master */
        if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
                for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
-                       if (wm8776->sysclk[dai->id] / params_rate(params)
+                       if (wm8776->sysclk[dai->driver->id] / params_rate(params)
                            == mclk_ratios[i])
                                break;
                }
@@ -268,7 +261,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
                if (i == ARRAY_SIZE(mclk_ratios)) {
                        dev_err(codec->dev,
                                "Unable to configure MCLK ratio %d/%d\n",
-                               wm8776->sysclk[dai->id], params_rate(params));
+                               wm8776->sysclk[dai->driver->id], params_rate(params));
                        return -EINVAL;
                }
 
@@ -298,9 +291,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
 
-       BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
+       BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
 
-       wm8776->sysclk[dai->id] = freq;
+       wm8776->sysclk[dai->driver->id] = freq;
 
        return 0;
 }
@@ -350,10 +343,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {
        .set_sysclk     = wm8776_set_sysclk,
 };
 
-struct snd_soc_dai wm8776_dai[] = {
+static struct snd_soc_dai_driver wm8776_dai[] = {
        {
-               .name = "WM8776 Playback",
-               .id = WM8776_DAI_DAC,
+               .name = "wm8776-hifi-playback",
+               .id     = WM8776_DAI_DAC,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 2,
@@ -364,8 +357,8 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_dac_ops,
        },
        {
-               .name = "WM8776 Capture",
-               .id = WM8776_DAI_ADC,
+               .name = "wm8776-hifi-capture",
+               .id     = WM8776_DAI_ADC,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
@@ -376,23 +369,17 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_adc_ops,
        },
 };
-EXPORT_SYMBOL_GPL(wm8776_dai);
 
 #ifdef CONFIG_PM
-static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8776_resume(struct platform_device *pdev)
+static int wm8776_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -415,27 +402,30 @@ static int wm8776_resume(struct platform_device *pdev)
 #define wm8776_resume NULL
 #endif
 
-static int wm8776_probe(struct platform_device *pdev)
+static int wm8776_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       if (wm8776_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8776_codec;
-       codec = wm8776_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8776_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
        }
 
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch the update bits; right channel only since we always
+        * update both. */
+       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
+
        snd_soc_add_controls(codec, wm8776_snd_controls,
                             ARRAY_SIZE(wm8776_snd_controls));
        snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
@@ -443,169 +433,56 @@ static int wm8776_probe(struct platform_device *pdev)
        snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
 /* power down chip */
-static int wm8776_remove(struct platform_device *pdev)
+static int wm8776_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8776 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .probe =        wm8776_probe,
        .remove =       wm8776_remove,
        .suspend =      wm8776_suspend,
        .resume =       wm8776_resume,
+       .set_bias_level = wm8776_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8776_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8776_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
-
-static int wm8776_register(struct wm8776_priv *wm8776,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8776->codec;
-
-       if (wm8776_codec) {
-               dev_err(codec->dev, "Another WM8776 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8776);
-       codec->name = "WM8776";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8776_set_bias_level;
-       codec->dai = wm8776_dai;
-       codec->num_dai = ARRAY_SIZE(wm8776_dai);
-       codec->reg_cache_size = WM8776_CACHEREGNUM;
-       codec->reg_cache = &wm8776->reg_cache;
-
-       memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
-               wm8776_dai[i].dev = codec->dev;
-
-       ret = wm8776_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err;
-       }
-
-       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* Latch the update bits; right channel only since we always
-        * update both. */
-       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
-       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
-
-       wm8776_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8776);
-       return ret;
-}
-
-static void wm8776_unregister(struct wm8776_priv *wm8776)
-{
-       wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       snd_soc_unregister_codec(&wm8776->codec);
-       kfree(wm8776);
-       wm8776_codec = NULL;
-}
 
 #if defined(CONFIG_SPI_MASTER)
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
-{
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-
-       spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-
 static int __devinit wm8776_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8776_priv *wm8776;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->control_data = spi;
-       codec->hw_write = (hw_write_t)wm8776_spi_write;
-       codec->dev = &spi->dev;
+       wm8776->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8776);
 
-       dev_set_drvdata(&spi->dev, wm8776);
-
-       return wm8776_register(wm8776, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static int __devexit wm8776_spi_remove(struct spi_device *spi)
 {
-       struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
-
-       wm8776_unregister(wm8776);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8776_spi_driver = {
        .driver = {
-               .name   = "wm8776",
-               .bus    = &spi_bus_type,
+               .name   = "wm8776-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8776_spi_probe,
@@ -618,27 +495,26 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8776_priv *wm8776;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8776);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8776->control_type = SND_SOC_I2C;
 
-       return wm8776_register(wm8776, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
 {
-       struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
-       wm8776_unregister(wm8776);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -650,7 +526,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
 
 static struct i2c_driver wm8776_i2c_driver = {
        .driver = {
-               .name = "wm8776",
+               .name = "wm8776-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8776_i2c_probe,
@@ -661,22 +537,22 @@ static struct i2c_driver wm8776_i2c_driver = {
 
 static int __init wm8776_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8776_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
                       ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8776_spi_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8776_modinit);
 
index 6606d25d2d835be7f9558f23981c75b4522d3c9f..4cf1c8e0bfc9e093ecc8f449de7b1db8b1a2062b 100644 (file)
@@ -45,7 +45,4 @@
 #define WM8776_DAI_DAC 0
 #define WM8776_DAI_ADC 1
 
-extern struct snd_soc_dai wm8776_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8776;
-
 #endif
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
new file mode 100644 (file)
index 0000000..4599e8e
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * wm8804.c  --  WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8804.h"
+
+#define WM8804_NUM_SUPPLIES 2
+static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
+       "PVDD",
+       "DVDD"
+};
+
+static const u8 wm8804_reg_defs[] = {
+       0x05,     /* R0  - RST/DEVID1 */
+       0x88,     /* R1  - DEVID2 */
+       0x04,     /* R2  - DEVREV */
+       0x21,     /* R3  - PLL1 */
+       0xFD,     /* R4  - PLL2 */
+       0x36,     /* R5  - PLL3 */
+       0x07,     /* R6  - PLL4 */
+       0x16,     /* R7  - PLL5 */
+       0x18,     /* R8  - PLL6 */
+       0xFF,     /* R9  - SPDMODE */
+       0x00,     /* R10 - INTMASK */
+       0x00,     /* R11 - INTSTAT */
+       0x00,     /* R12 - SPDSTAT */
+       0x00,     /* R13 - RXCHAN1 */
+       0x00,     /* R14 - RXCHAN2 */
+       0x00,     /* R15 - RXCHAN3 */
+       0x00,     /* R16 - RXCHAN4 */
+       0x00,     /* R17 - RXCHAN5 */
+       0x00,     /* R18 - SPDTX1 */
+       0x00,     /* R19 - SPDTX2 */
+       0x00,     /* R20 - SPDTX3 */
+       0x71,     /* R21 - SPDTX4 */
+       0x0B,     /* R22 - SPDTX5 */
+       0x70,     /* R23 - GPO0 */
+       0x57,     /* R24 - GPO1 */
+       0x00,     /* R25 */
+       0x42,     /* R26 - GPO2 */
+       0x06,     /* R27 - AIFTX */
+       0x06,     /* R28 - AIFRX */
+       0x80,     /* R29 - SPDRX1 */
+       0x07,     /* R30 - PWRDN */
+};
+
+struct wm8804_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+       struct snd_soc_codec *codec;
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol);
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8804_REGULATOR_EVENT(n) \
+static int wm8804_regulator_event_##n(struct notifier_block *nb, \
+                                     unsigned long event, void *data)    \
+{ \
+       struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8804->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8804_REGULATOR_EVENT(0)
+WM8804_REGULATOR_EVENT(1)
+
+static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
+static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+
+static const struct snd_kcontrol_new wm8804_snd_controls[] = {
+       SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
+       SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1),
+       SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec;
+       unsigned int src;
+
+       codec = snd_kcontrol_chip(kcontrol);
+       src = snd_soc_read(codec, WM8804_SPDTX4);
+       if (src & 0x40)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec;
+       unsigned int src, txpwr;
+
+       codec = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.integer.value[0] != 0
+                       && ucontrol->value.integer.value[0] != 1)
+               return -EINVAL;
+
+       src = snd_soc_read(codec, WM8804_SPDTX4);
+       switch ((src & 0x40) >> 6) {
+       case 0:
+               if (!ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       case 1:
+               if (ucontrol->value.integer.value[1])
+                       return 0;
+               break;
+       }
+
+       /* save the current power state of the transmitter */
+       txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
+       /* power down the transmitter */
+       snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
+       /* set the tx source */
+       snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
+                           ucontrol->value.integer.value[0] << 6);
+
+       if (ucontrol->value.integer.value[0]) {
+               /* power down the receiver */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
+               /* power up the AIF */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
+       } else {
+               /* don't power down the AIF -- may be used as an output */
+               /* power up the receiver */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
+       }
+
+       /* restore the transmitter's configuration */
+       snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
+
+       return 0;
+}
+
+static int wm8804_volatile(unsigned int reg)
+{
+       switch (reg) {
+       case WM8804_RST_DEVID1:
+       case WM8804_DEVID2:
+       case WM8804_DEVREV:
+       case WM8804_INTSTAT:
+       case WM8804_SPDSTAT:
+       case WM8804_RXCHAN1:
+       case WM8804_RXCHAN2:
+       case WM8804_RXCHAN3:
+       case WM8804_RXCHAN4:
+       case WM8804_RXCHAN5:
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int wm8804_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+}
+
+static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       u16 format, master, bcp, lrp;
+
+       codec = dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = 0x0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               format = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       /* set data format */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       /* set master/slave mode */
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
+
+       bcp = lrp = 0;
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bcp = lrp = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bcp = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrp = 1;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown polarity configuration\n");
+               return -EINVAL;
+       }
+
+       /* set frame inversion */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
+                           (bcp << 4) | (lrp << 5));
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
+                           (bcp << 4) | (lrp << 5));
+       return 0;
+}
+
+static int wm8804_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec;
+       u16 blen;
+
+       codec = dai->codec;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               blen = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               blen = 0x1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               blen = 0x2;
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length: %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       /* set word length */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
+
+       return 0;
+}
+
+struct pll_div {
+       u32 prescale:1;
+       u32 mclkdiv:1;
+       u32 freqmode:2;
+       u32 n:4;
+       u32 k:22;
+};
+
+/* PLL rate to output rate divisions */
+static struct {
+       unsigned int div;
+       unsigned int freqmode;
+       unsigned int mclkdiv;
+} post_table[] = {
+       {  2,  0, 0 },
+       {  4,  0, 1 },
+       {  4,  1, 0 },
+       {  8,  1, 1 },
+       {  8,  2, 0 },
+       { 16,  2, 1 },
+       { 12,  3, 0 },
+       { 24,  3, 1 }
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned long int K, Ndiv, Nmod, tmp;
+       int i;
+
+       /*
+        * Scale the output frequency up; the PLL should run in the
+        * region of 90-100MHz.
+        */
+       for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+               tmp = target * post_table[i].div;
+               if (tmp >= 90000000 && tmp <= 100000000) {
+                       pll_div->freqmode = post_table[i].freqmode;
+                       pll_div->mclkdiv = post_table[i].mclkdiv;
+                       target *= post_table[i].div;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(post_table)) {
+               pr_err("%s: Unable to scale output frequency: %uHz\n",
+                      __func__, target);
+               return -EINVAL;
+       }
+
+       pll_div->prescale = 0;
+       Ndiv = target / source;
+       if (Ndiv < 5) {
+               source >>= 1;
+               pll_div->prescale = 1;
+               Ndiv = target / source;
+       }
+
+       if (Ndiv < 5 || Ndiv > 13) {
+               pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
+                      __func__, Ndiv);
+               return -EINVAL;
+       }
+       pll_div->n = Ndiv;
+
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xffffffff;
+       if ((K % 10) >= 5)
+               K += 5;
+       K /= 10;
+       pll_div->k = K;
+
+       return 0;
+}
+
+static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
+                         int source, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+       if (!freq_in || !freq_out) {
+               /* disable the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+               return 0;
+       } else {
+               int ret;
+               struct pll_div pll_div;
+
+               ret = pll_factors(&pll_div, freq_out, freq_in);
+               if (ret)
+                       return ret;
+
+               /* power down the PLL before reprogramming it */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+
+               if (!freq_in || !freq_out)
+                       return 0;
+
+               /* set PLLN and PRESCALE */
+               snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+                                   pll_div.n | (pll_div.prescale << 4));
+               /* set mclkdiv and freqmode */
+               snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+                                   pll_div.freqmode | (pll_div.mclkdiv << 3));
+               /* set PLLK */
+               snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
+               snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+               snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+
+               /* power up the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
+       }
+
+       return 0;
+}
+
+static int wm8804_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+
+       switch (clk_id) {
+       case WM8804_TX_CLKSRC_MCLK:
+               if ((freq >= 10000000 && freq <= 14400000)
+                               || (freq >= 16280000 && freq <= 27000000))
+                       snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
+               else {
+                       dev_err(dai->dev, "OSCCLOCK is not within the "
+                               "recommended range: %uHz\n", freq);
+                       return -EINVAL;
+               }
+               break;
+       case WM8804_TX_CLKSRC_PLL:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
+               break;
+       case WM8804_CLKOUT_SRC_CLK1:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
+               break;
+       case WM8804_CLKOUT_SRC_OSCCLK:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
+                            int div_id, int div)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+       switch (div_id) {
+       case WM8804_CLKOUT_DIV:
+               snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
+                                   (div & 0x3) << 4);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void wm8804_sync_cache(struct snd_soc_codec *codec)
+{
+       short i;
+       u8 *cache;
+
+       if (!codec->cache_sync)
+               return;
+
+       codec->cache_only = 0;
+       cache = codec->reg_cache;
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+       codec->cache_sync = 0;
+}
+
+static int wm8804_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct wm8804_priv *wm8804;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               /* power up the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                                   wm8804->supplies);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       wm8804_sync_cache(codec);
+               }
+               /* power down the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* power down the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+               regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
+                                      wm8804->supplies);
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8804_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8804_resume(struct snd_soc_codec *codec)
+{
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8804_suspend NULL
+#define wm8804_resume NULL
+#endif
+
+static int wm8804_remove(struct snd_soc_codec *codec)
+{
+       struct wm8804_priv *wm8804;
+       int i;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+               regulator_unregister_notifier(wm8804->supplies[i].consumer,
+                                             &wm8804->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+       return 0;
+}
+
+static int wm8804_probe(struct snd_soc_codec *codec)
+{
+       struct wm8804_priv *wm8804;
+       int i, id1, id2, ret;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       wm8804->codec = codec;
+
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+               wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+                                wm8804->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+                                                 &wm8804->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                   wm8804->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_get;
+       }
+
+       id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
+       if (id1 < 0) {
+               dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
+               ret = id1;
+               goto err_reg_enable;
+       }
+
+       id2 = snd_soc_read(codec, WM8804_DEVID2);
+       if (id2 < 0) {
+               dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
+               ret = id2;
+               goto err_reg_enable;
+       }
+
+       id2 = (id2 << 8) | id1;
+
+       if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8)
+                       | wm8804_reg_defs[WM8804_RST_DEVID1])) {
+               dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
+               ret = -EINVAL;
+               goto err_reg_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8804_DEVREV);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_reg_enable;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       ret = wm8804_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
+
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       snd_soc_add_controls(codec, wm8804_snd_controls,
+                            ARRAY_SIZE(wm8804_snd_controls));
+       return 0;
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+err_reg_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+       return ret;
+}
+
+static struct snd_soc_dai_ops wm8804_dai_ops = {
+       .hw_params = wm8804_hw_params,
+       .set_fmt = wm8804_set_fmt,
+       .set_sysclk = wm8804_set_sysclk,
+       .set_clkdiv = wm8804_set_clkdiv,
+       .set_pll = wm8804_set_pll
+};
+
+#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver wm8804_dai = {
+       .name = "wm8804-spdif",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = WM8804_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = WM8804_FORMATS,
+       },
+       .ops = &wm8804_dai_ops,
+       .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+       .probe = wm8804_probe,
+       .remove = wm8804_remove,
+       .suspend = wm8804_suspend,
+       .resume = wm8804_resume,
+       .set_bias_level = wm8804_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = wm8804_reg_defs,
+       .volatile_register = wm8804_volatile
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8804_spi_probe(struct spi_device *spi)
+{
+       struct wm8804_priv *wm8804;
+       int ret;
+
+       wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+       if (!wm8804)
+               return -ENOMEM;
+
+       wm8804->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8804);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       if (ret < 0)
+               kfree(wm8804);
+       return ret;
+}
+
+static int __devexit wm8804_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8804_spi_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8804_spi_probe,
+       .remove = __devexit_p(wm8804_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8804_priv *wm8804;
+       int ret;
+
+       wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+       if (!wm8804)
+               return -ENOMEM;
+
+       wm8804->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8804);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       if (ret < 0)
+               kfree(wm8804);
+       return ret;
+}
+
+static __devexit int wm8804_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+       { "wm8804", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static struct i2c_driver wm8804_i2c_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8804_i2c_probe,
+       .remove = __devexit_p(wm8804_i2c_remove),
+       .id_table = wm8804_i2c_id
+};
+#endif
+
+static int __init wm8804_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8804_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8804_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8804_modinit);
+
+static void __exit wm8804_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8804_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8804_spi_driver);
+#endif
+}
+module_exit(wm8804_exit);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
new file mode 100644 (file)
index 0000000..8ec14f5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * wm8804.h  --  WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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 _WM8804_H
+#define _WM8804_H
+
+/*
+ * Register values.
+ */
+#define WM8804_RST_DEVID1                      0x00
+#define WM8804_DEVID2                          0x01
+#define WM8804_DEVREV                          0x02
+#define WM8804_PLL1                            0x03
+#define WM8804_PLL2                            0x04
+#define WM8804_PLL3                            0x05
+#define WM8804_PLL4                            0x06
+#define WM8804_PLL5                            0x07
+#define WM8804_PLL6                            0x08
+#define WM8804_SPDMODE                         0x09
+#define WM8804_INTMASK                         0x0A
+#define WM8804_INTSTAT                         0x0B
+#define WM8804_SPDSTAT                         0x0C
+#define WM8804_RXCHAN1                         0x0D
+#define WM8804_RXCHAN2                         0x0E
+#define WM8804_RXCHAN3                         0x0F
+#define WM8804_RXCHAN4                         0x10
+#define WM8804_RXCHAN5                         0x11
+#define WM8804_SPDTX1                          0x12
+#define WM8804_SPDTX2                          0x13
+#define WM8804_SPDTX3                          0x14
+#define WM8804_SPDTX4                          0x15
+#define WM8804_SPDTX5                          0x16
+#define WM8804_GPO0                            0x17
+#define WM8804_GPO1                            0x18
+#define WM8804_GPO2                            0x1A
+#define WM8804_AIFTX                           0x1B
+#define WM8804_AIFRX                           0x1C
+#define WM8804_SPDRX1                          0x1D
+#define WM8804_PWRDN                           0x1E
+
+#define WM8804_REGISTER_COUNT                  30
+#define WM8804_MAX_REGISTER                    0x1E
+
+#define WM8804_TX_CLKSRC_MCLK                  1
+#define WM8804_TX_CLKSRC_PLL                   2
+
+#define WM8804_CLKOUT_SRC_CLK1                 3
+#define WM8804_CLKOUT_SRC_OSCCLK               4
+
+#define WM8804_CLKOUT_DIV                      1
+
+#endif  /* _WM8804_H */
index 5da17a704e5a9ba2d40d27a14b24a0fff701594e..b4f11724a63ffc771c1a1d83909e31ae5cccaab7 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 
 #define WM8900_LRC_MASK 0xfc00
 
-struct snd_soc_codec_device soc_codec_dev_wm8900;
-
 struct wm8900_priv {
-       struct snd_soc_codec codec;
-
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8900_MAXREG];
 
        u32 fll_in; /* FLL input frequency */
@@ -627,8 +625,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 reg;
 
        reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1015,8 +1012,8 @@ static struct snd_soc_dai_ops wm8900_dai_ops = {
        .digital_mute   = wm8900_digital_mute,
 };
 
-struct snd_soc_dai wm8900_dai = {
-       .name = "WM8900 HiFi",
+static struct snd_soc_dai_driver wm8900_dai = {
+       .name = "wm8900-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1033,7 +1030,6 @@ struct snd_soc_dai wm8900_dai = {
         },
        .ops = &wm8900_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8900_dai);
 
 static int wm8900_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
@@ -1128,10 +1124,8 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        int fll_out = wm8900->fll_out;
        int fll_in  = wm8900->fll_in;
@@ -1140,7 +1134,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
        /* Stop the FLL in an orderly fashion */
        ret = wm8900_set_fll(codec, 0, 0, 0);
        if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               dev_err(codec->dev, "Failed to stop FLL\n");
                return ret;
        }
 
@@ -1152,10 +1146,8 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8900_resume(struct platform_device *pdev)
+static int wm8900_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        u16 *cache;
        int i, ret;
@@ -1176,7 +1168,7 @@ static int wm8900_resume(struct platform_device *pdev)
 
                ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
                if (ret != 0) {
-                       dev_err(&pdev->dev, "Failed to restart FLL\n");
+                       dev_err(codec->dev, "Failed to restart FLL\n");
                        return ret;
                }
        }
@@ -1186,60 +1178,32 @@ static int wm8900_resume(struct platform_device *pdev)
                        snd_soc_write(codec, i, cache[i]);
                kfree(cache);
        } else
-               dev_err(&pdev->dev, "Unable to allocate register cache\n");
+               dev_err(codec->dev, "Unable to allocate register cache\n");
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8900_codec;
-
-static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
+static int wm8900_probe(struct snd_soc_codec *codec)
 {
-       struct wm8900_priv *wm8900;
-       struct snd_soc_codec *codec;
-       unsigned int reg;
-       int ret;
-
-       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
-       if (wm8900 == NULL)
-               return -ENOMEM;
+       struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
 
-       codec = &wm8900->codec;
-       snd_soc_codec_set_drvdata(codec, wm8900);
-       codec->reg_cache = &wm8900->reg_cache[0];
-       codec->reg_cache_size = WM8900_MAXREG;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8900";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8900_dai;
-       codec->num_dai = 1;
-       codec->control_data = i2c;
-       codec->set_bias_level = wm8900_set_bias_level;
-       codec->volatile_register = wm8900_volatile_register;
-       codec->dev = &i2c->dev;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
        if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        reg = snd_soc_read(codec, WM8900_REG_ID);
        if (reg != 0x8900) {
-               dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
-               ret = -ENODEV;
-               goto err;
+               dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
+               return -ENODEV;
        }
 
        /* Read back from the chip */
        reg = snd_soc_read(codec, WM8900_REG_POWER1);
        reg = (reg >> 12) & 0xf;
-       dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
+       dev_info(codec->dev, "WM8900 revision %d\n", reg);
 
        wm8900_reset(codec);
 
@@ -1271,43 +1235,94 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
        /* Set the DAC and mixer output bias */
        snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
 
-       wm8900_dai.dev = &i2c->dev;
+       snd_soc_add_controls(codec, wm8900_snd_controls,
+                               ARRAY_SIZE(wm8900_snd_controls));
+       wm8900_add_widgets(codec);
 
-       wm8900_codec = codec;
+       return 0;
+}
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+/* power down chip */
+static int wm8900_remove(struct snd_soc_codec *codec)
+{
+       wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       ret = snd_soc_register_dai(&wm8900_dai);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
+       .probe =        wm8900_probe,
+       .remove =       wm8900_remove,
+       .suspend =      wm8900_suspend,
+       .resume =       wm8900_resume,
+       .set_bias_level = wm8900_set_bias_level,
+       .volatile_register = wm8900_volatile_register,
+       .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8900_reg_defaults,
+};
 
-       return ret;
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8900_spi_probe(struct spi_device *spi)
+{
+       struct wm8900_priv *wm8900;
+       int ret;
+
+       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       if (wm8900 == NULL)
+               return -ENOMEM;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8900);
-       wm8900_codec = NULL;
+       wm8900->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8900);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8900, &wm8900_dai, 1);
+       if (ret < 0)
+               kfree(wm8900);
        return ret;
 }
 
-static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+static int __devexit wm8900_spi_remove(struct spi_device *spi)
 {
-       snd_soc_unregister_dai(&wm8900_dai);
-       snd_soc_unregister_codec(wm8900_codec);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
 
-       wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
+static struct spi_driver wm8900_spi_driver = {
+       .driver = {
+               .name   = "wm8900-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8900_spi_probe,
+       .remove         = __devexit_p(wm8900_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8900_priv *wm8900;
+       int ret;
+
+       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       if (wm8900 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8900);
+       wm8900->control_type = SND_SOC_I2C;
 
-       wm8900_dai.dev = NULL;
-       kfree(snd_soc_codec_get_drvdata(wm8900_codec));
-       wm8900_codec = NULL;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8900, &wm8900_dai, 1);
+       if (ret < 0)
+               kfree(wm8900);
+       return ret;
+}
 
+static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1319,71 +1334,44 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
 
 static struct i2c_driver wm8900_i2c_driver = {
        .driver = {
-               .name = "WM8900",
+               .name = "wm8900-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8900_i2c_probe,
-       .remove = __devexit_p(wm8900_i2c_remove),
+       .probe =    wm8900_i2c_probe,
+       .remove =   __devexit_p(wm8900_i2c_remove),
        .id_table = wm8900_i2c_id,
 };
+#endif
 
-static int wm8900_probe(struct platform_device *pdev)
+static int __init wm8900_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       if (!wm8900_codec) {
-               dev_err(&pdev->dev, "I2C client not yet instantiated\n");
-               return -ENODEV;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8900_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
+                      ret);
        }
-
-       codec = wm8900_codec;
-       socdev->card->codec = codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to register new PCMs\n");
-               goto pcm_err;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8900_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(codec, wm8900_snd_controls,
-                               ARRAY_SIZE(wm8900_snd_controls));
-       wm8900_add_widgets(codec);
-
-pcm_err:
+#endif
        return ret;
 }
-
-/* power down chip */
-static int wm8900_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8900 = {
-       .probe =        wm8900_probe,
-       .remove =       wm8900_remove,
-       .suspend =      wm8900_suspend,
-       .resume =       wm8900_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
-
-static int __init wm8900_modinit(void)
-{
-       return i2c_add_driver(&wm8900_i2c_driver);
-}
 module_init(wm8900_modinit);
 
 static void __exit wm8900_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8900_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8900_spi_driver);
+#endif
 }
 module_exit(wm8900_exit);
 
index fd15007d10c7ec22950174758a9b688247eede08..583f257e799b4719371abb641d37535f46ba2ba3 100644 (file)
@@ -52,7 +52,4 @@
 #define WM8900_DAC_CLKDIV_5_5 0x14
 #define WM8900_DAC_CLKDIV_6   0x18
 
-extern struct snd_soc_dai wm8900_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8900;
-
 #endif
index bf08282d5ee56384023d7055ff3b355d817d8e05..622b60238a824e084099b3f290dc0dda6ebf6767 100644 (file)
@@ -213,10 +213,11 @@ static u16 wm8903_reg_defaults[] = {
 };
 
 struct wm8903_priv {
-       struct snd_soc_codec codec;
+
        u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
 
        int sysclk;
+       int irq;
 
        /* Reference counts */
        int class_w_users;
@@ -252,7 +253,6 @@ static int wm8903_volatile_register(unsigned int reg)
 static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
 {
        u16 reg[5];
-       struct i2c_client *i2c = codec->control_data;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        BUG_ON(start > 48);
@@ -262,7 +262,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
                      reg[0] | WM8903_WSEQ_ENA);
 
-       dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+       dev_dbg(codec->dev, "Starting sequence at %d\n", start);
 
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
                     start | WM8903_WSEQ_START);
@@ -277,7 +277,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
                reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
        } while (reg[4] & WM8903_WSEQ_BUSY);
 
-       dev_dbg(&i2c->dev, "Sequence complete\n");
+       dev_dbg(codec->dev, "Sequence complete\n");
 
        /* Disable the sequencer again if we enabled it */
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
@@ -422,7 +422,6 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
        struct snd_soc_codec *codec = widget->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        u16 reg;
        int ret;
 
@@ -431,7 +430,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        /* Turn it off if we're about to enable bypass */
        if (ucontrol->value.integer.value[0]) {
                if (wm8903->class_w_users == 0) {
-                       dev_dbg(&i2c->dev, "Disabling Class W\n");
+                       dev_dbg(codec->dev, "Disabling Class W\n");
                        snd_soc_write(codec, WM8903_CLASS_W_0, reg &
                                     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
                }
@@ -444,14 +443,14 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        /* If we've just disabled the last bypass path turn Class W on */
        if (!ucontrol->value.integer.value[0]) {
                if (wm8903->class_w_users == 1) {
-                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       dev_dbg(codec->dev, "Enabling Class W\n");
                        snd_soc_write(codec, WM8903_CLASS_W_0, reg |
                                     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
                }
                wm8903->class_w_users--;
        }
 
-       dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+       dev_dbg(codec->dev, "Bypass use count now %d\n",
                wm8903->class_w_users);
 
        return ret;
@@ -935,7 +934,6 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       struct i2c_client *i2c = codec->control_data;
        u16 reg, reg2;
 
        switch (level) {
@@ -974,7 +972,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                        /* By default no bypass paths are enabled so
                         * enable Class W support.
                         */
-                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       dev_dbg(codec->dev, "Enabling Class W\n");
                        snd_soc_write(codec, WM8903_CLASS_W_0, reg |
                                     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
                }
@@ -1228,10 +1226,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
                          struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1245,7 +1241,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
        if (wm8903->master_substream) {
                master_runtime = wm8903->master_substream->runtime;
 
-               dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+               dev_dbg(codec->dev, "Constraining to %d bits\n",
                        master_runtime->sample_bits);
 
                snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -1264,8 +1260,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1284,10 +1279,8 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        int fs = params_rate(params);
        int bclk;
        int bclk_div;
@@ -1306,7 +1299,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 
        if (substream == wm8903->slave_substream) {
-               dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+               dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
                return 0;
        }
 
@@ -1332,7 +1325,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                switch (sample_rates[dsp_config].rate) {
                case 88200:
                case 96000:
-                       dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+                       dev_err(codec->dev, "%dHz unsupported by ADC\n",
                                fs);
                        return -EINVAL;
 
@@ -1340,7 +1333,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                        break;
                }
 
-       dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+       dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
        clock1 &= ~WM8903_SAMPLE_RATE_MASK;
        clock1 |= sample_rates[dsp_config].value;
 
@@ -1366,7 +1359,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+       dev_dbg(codec->dev, "MCLK = %dHz, target sample rate = %dHz\n",
                wm8903->sysclk, fs);
 
        /* We may not have an MCLK which allows us to generate exactly
@@ -1401,12 +1394,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
        clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
 
-       dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+       dev_dbg(codec->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
                clk_sys_ratios[clk_config].rate,
                clk_sys_ratios[clk_config].mode,
                clk_sys_ratios[clk_config].div);
 
-       dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+       dev_dbg(codec->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
 
        /* We may not get quite the right frequency if using
         * approximate clocks so look for the closest match that is
@@ -1428,7 +1421,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        aif2 &= ~WM8903_BCLK_DIV_MASK;
        aif3 &= ~WM8903_LRCLK_RATE_MASK;
 
-       dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+       dev_dbg(codec->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
                bclk_divs[bclk_div].ratio / 10, bclk,
                (clk_sys * 10) / bclk_divs[bclk_div].ratio);
 
@@ -1504,8 +1497,8 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
 
 static irqreturn_t wm8903_irq(int irq, void *data)
 {
-       struct wm8903_priv *wm8903 = data;
-       struct snd_soc_codec *codec = &wm8903->codec;
+       struct snd_soc_codec *codec = data;
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int mic_report;
        int int_pol;
        int int_val = 0;
@@ -1586,8 +1579,8 @@ static struct snd_soc_dai_ops wm8903_dai_ops = {
        .set_sysclk     = wm8903_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8903_dai = {
-       .name = "WM8903",
+static struct snd_soc_dai_driver wm8903_dai = {
+       .name = "wm8903-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -1605,23 +1598,16 @@ struct snd_soc_dai wm8903_dai = {
        .ops = &wm8903_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8903_dai);
 
-static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8903_resume(struct platform_device *pdev)
+static int wm8903_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct i2c_client *i2c = codec->control_data;
        int i;
        u16 *reg_cache = codec->reg_cache;
        u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
@@ -1637,65 +1623,37 @@ static int wm8903_resume(struct platform_device *pdev)
                                snd_soc_write(codec, i, tmp_cache[i]);
                kfree(tmp_cache);
        } else {
-               dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+               dev_err(codec->dev, "Failed to allocate temporary cache\n");
        }
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8903_codec;
-
-static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
+static int wm8903_probe(struct snd_soc_codec *codec)
 {
-       struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
-       struct wm8903_priv *wm8903;
-       struct snd_soc_codec *codec;
+       struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int ret, i;
        int trigger, irq_pol;
        u16 val;
 
-       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
-       if (wm8903 == NULL)
-               return -ENOMEM;
-
-       codec = &wm8903->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c->dev;
-       codec->name = "WM8903";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8903_set_bias_level;
-       codec->dai = &wm8903_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
-       codec->reg_cache = &wm8903->reg_cache[0];
-       snd_soc_codec_set_drvdata(codec, wm8903);
-       codec->volatile_register = wm8903_volatile_register;
        init_completion(&wm8903->wseq);
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
        if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
-               dev_err(&i2c->dev,
+               dev_err(codec->dev,
                        "Device with ID register %x is not a WM8903\n", val);
                return -ENODEV;
        }
 
        val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
-       dev_info(&i2c->dev, "WM8903 revision %d\n",
+       dev_info(codec->dev, "WM8903 revision %d\n",
                 val & WM8903_CHIP_REV_MASK);
 
        wm8903_reset(codec);
@@ -1721,7 +1679,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                wm8903->mic_delay = pdata->micdet_delay;
        }
        
-       if (i2c->irq) {
+       if (wm8903->irq) {
                if (pdata && pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8903_IRQ_POL;
@@ -1733,13 +1691,13 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
                                    WM8903_IRQ_POL, irq_pol);
                
-               ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+               ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
                                           trigger | IRQF_ONESHOT,
-                                          "wm8903", wm8903);
+                                          "wm8903", codec);
                if (ret != 0) {
-                       dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
                                ret);
-                       goto err;
+                       return ret;
                }
 
                /* Enable write sequencer interrupts */
@@ -1781,133 +1739,96 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
        val |= WM8903_DAC_MUTEMODE;
        snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
 
-       wm8903_dai.dev = &i2c->dev;
-       wm8903_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err_irq;
-       }
-
-       ret = snd_soc_register_dai(&wm8903_dai);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return ret;
+       snd_soc_add_controls(codec, wm8903_snd_controls,
+                               ARRAY_SIZE(wm8903_snd_controls));
+       wm8903_add_widgets(codec);
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err_irq:
-       if (i2c->irq)
-               free_irq(i2c->irq, wm8903);
-err:
-       wm8903_codec = NULL;
-       kfree(wm8903);
        return ret;
 }
 
-static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+/* power down chip */
+static int wm8903_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       struct wm8903_priv *priv = snd_soc_codec_get_drvdata(codec);
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       snd_soc_unregister_dai(&wm8903_dai);
-       snd_soc_unregister_codec(codec);
+static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+       .probe =        wm8903_probe,
+       .remove =       wm8903_remove,
+       .suspend =      wm8903_suspend,
+       .resume =       wm8903_resume,
+       .set_bias_level = wm8903_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8903_reg_defaults,
+       .volatile_register = wm8903_volatile_register,
+};
 
-       wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8903_priv *wm8903;
+       int ret;
 
-       if (client->irq)
-               free_irq(client->irq, priv);
+       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+       if (wm8903 == NULL)
+               return -ENOMEM;
 
-       kfree(priv);
+       i2c_set_clientdata(i2c, wm8903);
+       wm8903->irq = i2c->irq;
 
-       wm8903_codec = NULL;
-       wm8903_dai.dev = NULL;
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8903, &wm8903_dai, 1);
+       if (ret < 0)
+               kfree(wm8903);
+       return ret;
+}
 
+static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* i2c codec control layer */
 static const struct i2c_device_id wm8903_i2c_id[] = {
-       { "wm8903", 0 },
-       { }
+       { "wm8903", 0 },
+       { }
 };
 MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
 
 static struct i2c_driver wm8903_i2c_driver = {
        .driver = {
-               .name = "WM8903",
+               .name = "wm8903-codec",
                .owner = THIS_MODULE,
        },
-       .probe    = wm8903_i2c_probe,
-       .remove   = __devexit_p(wm8903_i2c_remove),
+       .probe =    wm8903_i2c_probe,
+       .remove =   __devexit_p(wm8903_i2c_remove),
        .id_table = wm8903_i2c_id,
 };
+#endif
 
-static int wm8903_probe(struct platform_device *pdev)
+static int __init wm8903_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        int ret = 0;
-
-       if (!wm8903_codec) {
-               dev_err(&pdev->dev, "I2C device not yet probed\n");
-               goto err;
-       }
-
-       socdev->card->codec = wm8903_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8903_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
-                               ARRAY_SIZE(wm8903_snd_controls));
-       wm8903_add_widgets(socdev->card->codec);
-
+#endif
        return ret;
-
-err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8903_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8903 = {
-       .probe =        wm8903_probe,
-       .remove =       wm8903_remove,
-       .suspend =      wm8903_suspend,
-       .resume =       wm8903_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
-
-static int __init wm8903_modinit(void)
-{
-       return i2c_add_driver(&wm8903_i2c_driver);
 }
 module_init(wm8903_modinit);
 
 static void __exit wm8903_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8903_i2c_driver);
+#endif
 }
 module_exit(wm8903_exit);
 
index ce384a2ad820ec3b8bbf894f1bc9a8f246184862..996435e681e5e2a8bce5ca1d84aebbc0fe907066 100644 (file)
@@ -15,9 +15,6 @@
 
 #include <linux/i2c.h>
 
-extern struct snd_soc_dai wm8903_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8903;
-
 extern int wm8903_mic_detect(struct snd_soc_codec *codec,
                             struct snd_soc_jack *jack,
                             int det, int shrt);
index f7dcabf6283c165877fd5a12cd2adcd69f245e5e..33be84e506ea7d4e2927a4e44a06e49ab648f156 100644 (file)
@@ -31,9 +31,6 @@
 
 #include "wm8904.h"
 
-static struct snd_soc_codec *wm8904_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8904;
-
 enum wm8904_type {
        WM8904,
        WM8912,
@@ -52,10 +49,11 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8904_priv {
-       struct snd_soc_codec codec;
+
        u16 reg_cache[WM8904_MAX_REGISTER + 1];
 
        enum wm8904_type devtype;
+       void *control_data;
 
        struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
 
@@ -689,7 +687,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
 
@@ -760,7 +758,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
 
@@ -2218,8 +2216,8 @@ static struct snd_soc_dai_ops wm8904_dai_ops = {
        .digital_mute = wm8904_digital_mute,
 };
 
-struct snd_soc_dai wm8904_dai = {
-       .name = "WM8904",
+static struct snd_soc_dai_driver wm8904_dai = {
+       .name = "wm8904-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -2237,24 +2235,17 @@ struct snd_soc_dai wm8904_dai = {
        .ops = &wm8904_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8904_dai);
 
 #ifdef CONFIG_PM
-static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8904_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8904_resume(struct platform_device *pdev)
+static int wm8904_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -2264,9 +2255,9 @@ static int wm8904_resume(struct platform_device *pdev)
 #define wm8904_resume NULL
 #endif
 
-static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        struct snd_kcontrol_new control =
                SOC_ENUM_EXT("EQ Mode",
@@ -2315,20 +2306,20 @@ static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
        wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
        wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
 
-       ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+       ret = snd_soc_add_controls(codec, &control, 1);
        if (ret != 0)
-               dev_err(wm8904->codec.dev,
+               dev_err(codec->dev,
                        "Failed to add ReTune Mobile control: %d\n", ret);
 }
 
-static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_pdata(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int ret, i;
 
        if (!pdata) {
-               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+               snd_soc_add_controls(codec, wm8904_eq_controls,
                                     ARRAY_SIZE(wm8904_eq_controls));
                return;
        }
@@ -2344,7 +2335,7 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                wm8904->drc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8904->drc_texts) {
-                       dev_err(wm8904->codec.dev,
+                       dev_err(codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -2356,9 +2347,9 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                wm8904->drc_enum.max = pdata->num_drc_cfgs;
                wm8904->drc_enum.texts = wm8904->drc_texts;
 
-               ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+               ret = snd_soc_add_controls(codec, &control, 1);
                if (ret != 0)
-                       dev_err(wm8904->codec.dev,
+                       dev_err(codec->dev,
                                "Failed to add DRC mode control: %d\n", ret);
 
                wm8904_set_drc(codec);
@@ -2368,89 +2359,19 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                pdata->num_retune_mobile_cfgs);
 
        if (pdata->num_retune_mobile_cfgs)
-               wm8904_handle_retune_mobile_pdata(wm8904);
+               wm8904_handle_retune_mobile_pdata(codec);
        else
-               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+               snd_soc_add_controls(codec, wm8904_eq_controls,
                                     ARRAY_SIZE(wm8904_eq_controls));
 }
 
-static int wm8904_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8904_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
 
-       socdev->card->codec = wm8904_codec;
-       codec = wm8904_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       wm8904_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
-       wm8904_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8904_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8904 = {
-       .probe =        wm8904_probe,
-       .remove =       wm8904_remove,
-       .suspend =      wm8904_suspend,
-       .resume =       wm8904_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
-
-static int wm8904_register(struct wm8904_priv *wm8904,
-                          enum snd_soc_control_type control)
+static int wm8904_probe(struct snd_soc_codec *codec)
 {
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
-       int ret;
-       struct snd_soc_codec *codec = &wm8904->codec;
-       int i;
-
-       if (wm8904_codec) {
-               dev_err(codec->dev, "Another WM8904 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
+       int ret, i;
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8904);
-       codec->name = "WM8904";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8904_set_bias_level;
-       codec->dai = &wm8904_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8904_MAX_REGISTER;
-       codec->reg_cache = &wm8904->reg_cache;
-       codec->volatile_register = wm8904_volatile_register;
        codec->cache_sync = 1;
        codec->idle_bias_off = 1;
 
@@ -2463,16 +2384,13 @@ static int wm8904_register(struct wm8904_priv *wm8904,
        default:
                dev_err(codec->dev, "Unknown device type %d\n",
                        wm8904->devtype);
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
-       memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
@@ -2482,7 +2400,7 @@ static int wm8904_register(struct wm8904_priv *wm8904,
                                 wm8904->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
@@ -2517,8 +2435,6 @@ static int wm8904_register(struct wm8904_priv *wm8904,
                goto err_enable;
        }
 
-       wm8904_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
        wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
@@ -2563,72 +2479,68 @@ static int wm8904_register(struct wm8904_priv *wm8904,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 
-       wm8904_codec = codec;
+       wm8904_handle_pdata(codec);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8904_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       wm8904_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-err:
-       kfree(wm8904);
        return ret;
 }
 
-static void wm8904_unregister(struct wm8904_priv *wm8904)
+static int wm8904_remove(struct snd_soc_codec *codec)
 {
-       wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-       snd_soc_unregister_dai(&wm8904_dai);
-       snd_soc_unregister_codec(&wm8904->codec);
-       kfree(wm8904);
-       wm8904_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
+       .probe =        wm8904_probe,
+       .remove =       wm8904_remove,
+       .suspend =      wm8904_suspend,
+       .resume =       wm8904_resume,
+       .set_bias_level = wm8904_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8904_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8904_reg,
+       .volatile_register = wm8904_volatile_register,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8904_priv *wm8904;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
        if (wm8904 == NULL)
                return -ENOMEM;
 
-       codec = &wm8904->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        wm8904->devtype = id->driver_data;
-
        i2c_set_clientdata(i2c, wm8904);
-       codec->control_data = i2c;
+       wm8904->control_data = i2c;
        wm8904->pdata = i2c->dev.platform_data;
 
-       codec->dev = &i2c->dev;
-
-       return wm8904_register(wm8904, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8904, &wm8904_dai, 1);
+       if (ret < 0)
+               kfree(wm8904);
+       return ret;
 }
 
 static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 {
-       struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
-       wm8904_unregister(wm8904);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -2641,7 +2553,7 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
 
 static struct i2c_driver wm8904_i2c_driver = {
        .driver = {
-               .name = "WM8904",
+               .name = "wm8904-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8904_i2c_probe,
@@ -2652,15 +2564,15 @@ static struct i2c_driver wm8904_i2c_driver = {
 
 static int __init wm8904_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8904_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8904_modinit);
 
index abe5059b3004e3739878d5787754b6554233f12c..9e8c84188ba761bb0eb606029e7c80f8d34e8219 100644 (file)
@@ -21,9 +21,6 @@
 #define WM8904_FLL_LRCLK         3
 #define WM8904_FLL_FREE_RUNNING  4
 
-extern struct snd_soc_dai wm8904_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8904;
-
 /*
  * Register values.
  */
index f0c11138e61002cf2c6a0f419c64de177f0e9a62..2cb16f895c4607c9d323ea3cbb9d8e31c4741cb1 100644 (file)
@@ -44,7 +44,8 @@
 struct wm8940_priv {
        unsigned int sysclk;
        u16 reg_cache[WM8940_CACHEREGNUM];
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static u16 wm8940_reg_defaults[] = {
@@ -365,8 +366,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
        u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
        u16 companding =  snd_soc_read(codec,
@@ -636,8 +636,8 @@ static struct snd_soc_dai_ops wm8940_dai_ops = {
        .set_pll = wm8940_set_dai_pll,
 };
 
-struct snd_soc_dai wm8940_dai = {
-       .name = "WM8940",
+static struct snd_soc_dai_driver wm8940_dai = {
+       .name = "wm8940-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -655,20 +655,14 @@ struct snd_soc_dai wm8940_dai = {
        .ops = &wm8940_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8940_dai);
 
-static int wm8940_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int wm8940_resume(struct platform_device *pdev)
+static int wm8940_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        int ret;
        u8 data[3];
@@ -697,108 +691,26 @@ error_ret:
        return ret;
 }
 
-static struct snd_soc_codec *wm8940_codec;
-
-static int wm8940_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-
-       int ret = 0;
-
-       if (wm8940_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8940_codec;
-       codec = wm8940_codec;
-
-       mutex_init(&codec->mutex);
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       ret = snd_soc_add_controls(codec, wm8940_snd_controls,
-                            ARRAY_SIZE(wm8940_snd_controls));
-       if (ret)
-               goto error_free_pcms;
-       ret = wm8940_add_widgets(codec);
-       if (ret)
-               goto error_free_pcms;
-
-       return ret;
-
-error_free_pcms:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-pcm_err:
-       return ret;
-}
-
-static int wm8940_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8940 = {
-       .probe = wm8940_probe,
-       .remove = wm8940_remove,
-       .suspend = wm8940_suspend,
-       .resume = wm8940_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
-
-static int wm8940_register(struct wm8940_priv *wm8940,
-                          enum snd_soc_control_type control)
+static int wm8940_probe(struct snd_soc_codec *codec)
 {
-       struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
-       struct snd_soc_codec *codec = &wm8940->codec;
+       struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+       struct wm8940_setup_data *pdata = codec->dev->platform_data;
        int ret;
        u16 reg;
-       if (wm8940_codec) {
-               dev_err(codec->dev, "Another WM8940 is registered\n");
-               return -EINVAL;
-       }
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8940);
-       codec->name = "WM8940";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8940_set_bias_level;
-       codec->dai = &wm8940_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
-       codec->reg_cache = &wm8940->reg_cache;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       codec->control_data = wm8940->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       memcpy(codec->reg_cache, wm8940_reg_defaults,
-              sizeof(wm8940_reg_defaults));
-
        ret = wm8940_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
                return ret;
        }
 
-       wm8940_dai.dev = codec->dev;
-
        wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
@@ -814,64 +726,60 @@ static int wm8940_register(struct wm8940_priv *wm8940,
                        return ret;
        }
 
-
-       wm8940_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+       ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+                            ARRAY_SIZE(wm8940_snd_controls));
+       if (ret)
                return ret;
-       }
-
-       ret = snd_soc_register_dai(&wm8940_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
+       ret = wm8940_add_widgets(codec);
+       if (ret)
                return ret;
-       }
 
-       return 0;
+       return ret;
+;
 }
 
-static void wm8940_unregister(struct wm8940_priv *wm8940)
+static int wm8940_remove(struct snd_soc_codec *codec)
 {
-       wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8940_dai);
-       snd_soc_unregister_codec(&wm8940->codec);
-       kfree(wm8940);
-       wm8940_codec = NULL;
+       wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static int wm8940_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
+       .probe =        wm8940_probe,
+       .remove =       wm8940_remove,
+       .suspend =      wm8940_suspend,
+       .resume =       wm8940_resume,
+       .set_bias_level = wm8940_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8940_reg_defaults,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       int ret;
        struct wm8940_priv *wm8940;
-       struct snd_soc_codec *codec;
+       int ret;
 
-       wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+       wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
        if (wm8940 == NULL)
                return -ENOMEM;
 
-       codec = &wm8940->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
        i2c_set_clientdata(i2c, wm8940);
-       codec->control_data = i2c;
-       codec->dev = &i2c->dev;
+       wm8940->control_data = i2c;
 
-       ret = wm8940_register(wm8940, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8940, &wm8940_dai, 1);
        if (ret < 0)
                kfree(wm8940);
-
        return ret;
 }
 
-static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+static __devexit int wm8940_i2c_remove(struct i2c_client *client)
 {
-       struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
-
-       wm8940_unregister(wm8940);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -883,29 +791,34 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
 
 static struct i2c_driver wm8940_i2c_driver = {
        .driver = {
-               .name = "WM8940 I2C Codec",
+               .name = "wm8940-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8940_i2c_probe,
-       .remove = __devexit_p(wm8940_i2c_remove),
+       .probe =    wm8940_i2c_probe,
+       .remove =   __devexit_p(wm8940_i2c_remove),
        .id_table = wm8940_i2c_id,
 };
+#endif
 
 static int __init wm8940_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8940_i2c_driver);
-       if (ret)
-               printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
                       ret);
+       }
+#endif
        return ret;
 }
 module_init(wm8940_modinit);
 
 static void __exit wm8940_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8940_i2c_driver);
+#endif
 }
 module_exit(wm8940_exit);
 
index 8410eed3ef847958a5b54816be246f978d69535f..907fe192e9e02d04669783b0647ff1dcaff6cbab 100644 (file)
@@ -15,8 +15,6 @@ struct wm8940_setup_data {
 #define WM8940_VROI_30K 1
        unsigned int vroi:1;
 };
-extern struct snd_soc_dai wm8940_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8940;
 
 /* WM8940 register space */
 #define WM8940_SOFTRESET       0x00
index 5f025593d84d3f4b8bc47aedda98055cd900f8ca..f89ad6c9a80b9162e7040ea6fe76b434c9f743f1 100644 (file)
@@ -30,9 +30,6 @@
 
 #include "wm8955.h"
 
-static struct snd_soc_codec *wm8955_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8955;
-
 #define WM8955_NUM_SUPPLIES 4
 static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
        "DCVDD",
@@ -43,7 +40,8 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8955_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+
        u16 reg_cache[WM8955_MAX_REGISTER + 1];
 
        unsigned int mclk_rate;
@@ -52,8 +50,6 @@ struct wm8955_priv {
        int fs;
 
        struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
-
-       struct wm8955_pdata *pdata;
 };
 
 static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
@@ -870,8 +866,8 @@ static struct snd_soc_dai_ops wm8955_dai_ops = {
        .digital_mute = wm8955_digital_mute,
 };
 
-struct snd_soc_dai wm8955_dai = {
-       .name = "WM8955",
+static struct snd_soc_dai_driver wm8955_dai = {
+       .name = "wm8955-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -881,24 +877,17 @@ struct snd_soc_dai wm8955_dai = {
        },
        .ops = &wm8955_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8955_dai);
 
 #ifdef CONFIG_PM
-static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8955_resume(struct platform_device *pdev)
+static int wm8955_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -908,86 +897,16 @@ static int wm8955_resume(struct platform_device *pdev)
 #define wm8955_resume NULL
 #endif
 
-static int wm8955_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8955_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8955_codec;
-       codec = wm8955_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       wm8955_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8955_remove(struct platform_device *pdev)
+static int wm8955_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8955 = {
-       .probe =        wm8955_probe,
-       .remove =       wm8955_remove,
-       .suspend =      wm8955_suspend,
-       .resume =       wm8955_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
-
-static int wm8955_register(struct wm8955_priv *wm8955,
-                          enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8955->codec;
-       int i;
-
-       if (wm8955_codec) {
-               dev_err(codec->dev, "Another WM8955 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8955);
-       codec->name = "WM8955";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8955_set_bias_level;
-       codec->dai = &wm8955_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8955_MAX_REGISTER;
-       codec->reg_cache = &wm8955->reg_cache;
-
-       memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
+       struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+       struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+       int ret, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
@@ -997,7 +916,7 @@ static int wm8955_register(struct wm8955_priv *wm8955,
                                 wm8955->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
@@ -1013,8 +932,6 @@ static int wm8955_register(struct wm8955_priv *wm8955,
                goto err_enable;
        }
 
-       wm8955_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
        wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
@@ -1028,12 +945,12 @@ static int wm8955_register(struct wm8955_priv *wm8955,
        wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
 
        /* Set platform data values */
-       if (wm8955->pdata) {
-               if (wm8955->pdata->out2_speaker)
+       if (pdata) {
+               if (pdata->out2_speaker)
                        wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
                                |= WM8955_ROUT2INV;
 
-               if (wm8955->pdata->monoin_diff)
+               if (pdata->monoin_diff)
                        wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
                                |= WM8955_DMEN;
        }
@@ -1043,70 +960,60 @@ static int wm8955_register(struct wm8955_priv *wm8955,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
 
-       wm8955_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8955_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
+       wm8955_add_widgets(codec);
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err:
-       kfree(wm8955);
        return ret;
 }
 
-static void wm8955_unregister(struct wm8955_priv *wm8955)
+static int wm8955_remove(struct snd_soc_codec *codec)
 {
-       wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
+       struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+
+       wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-       snd_soc_unregister_dai(&wm8955_dai);
-       snd_soc_unregister_codec(&wm8955->codec);
-       kfree(wm8955);
-       wm8955_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
+       .probe =        wm8955_probe,
+       .remove =       wm8955_remove,
+       .suspend =      wm8955_suspend,
+       .resume =       wm8955_resume,
+       .set_bias_level = wm8955_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8955_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8955_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8955_priv *wm8955;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
        if (wm8955 == NULL)
                return -ENOMEM;
 
-       codec = &wm8955->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8955);
-       codec->control_data = i2c;
-       wm8955->pdata = i2c->dev.platform_data;
-
-       codec->dev = &i2c->dev;
 
-       return wm8955_register(wm8955, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8955, &wm8955_dai, 1);
+       if (ret < 0)
+               kfree(wm8955);
+       return ret;
 }
 
 static __devexit int wm8955_i2c_remove(struct i2c_client *client)
 {
-       struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
-       wm8955_unregister(wm8955);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1118,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
 
 static struct i2c_driver wm8955_i2c_driver = {
        .driver = {
-               .name = "wm8955",
+               .name = "wm8955-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8955_i2c_probe,
@@ -1129,7 +1036,7 @@ static struct i2c_driver wm8955_i2c_driver = {
 
 static int __init wm8955_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8955_i2c_driver);
        if (ret != 0) {
@@ -1137,7 +1044,7 @@ static int __init wm8955_modinit(void)
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8955_modinit);
 
index ae349c8531f61d3f6d492baea5c56d03cf357f5b..d13fd5c5fa630409d0400b48012c34cd91b8da0a 100644 (file)
@@ -15,9 +15,6 @@
 
 #define WM8955_CLK_MCLK 1
 
-extern struct snd_soc_dai wm8955_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8955;
-
 /*
  * Register values.
  */
index 3c6ee61f6c952220d05a648711eac86230b7cdfa..8d5efb333c33f260b271af07e9352b14679f0502 100644 (file)
@@ -29,8 +29,6 @@
 
 #define AUDIO_NAME "wm8960"
 
-struct snd_soc_codec_device soc_codec_dev_wm8960;
-
 /* R25 - Power 1 */
 #define WM8960_VMID_MASK 0x180
 #define WM8960_VREF      0x40
@@ -75,7 +73,10 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
 
 struct wm8960_priv {
        u16 reg_cache[WM8960_CACHEREGNUM];
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       int (*set_bias_level)(struct snd_soc_codec *,
+                             enum snd_soc_bias_level level);
        struct snd_soc_dapm_widget *lout1;
        struct snd_soc_dapm_widget *rout1;
        struct snd_soc_dapm_widget *out3;
@@ -507,8 +508,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
        int i;
@@ -849,6 +849,14 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       return wm8960->set_bias_level(codec, level);
+}
+
 #define WM8960_RATES SNDRV_PCM_RATE_8000_48000
 
 #define WM8960_FORMATS \
@@ -863,8 +871,8 @@ static struct snd_soc_dai_ops wm8960_dai_ops = {
        .set_pll = wm8960_set_dai_pll,
 };
 
-struct snd_soc_dai wm8960_dai = {
-       .name = "WM8960",
+static struct snd_soc_dai_driver wm8960_dai = {
+       .name = "wm8960-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -880,21 +888,18 @@ struct snd_soc_dai wm8960_dai = {
        .ops = &wm8960_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8960_dai);
 
-static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8960_resume(struct platform_device *pdev)
+static int wm8960_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -906,78 +911,19 @@ static int wm8960_resume(struct platform_device *pdev)
                codec->hw_write(codec->control_data, data, 2);
        }
 
-       codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static struct snd_soc_codec *wm8960_codec;
-
-static int wm8960_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8960_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8960_codec;
-       codec = wm8960_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8960_snd_controls,
-                            ARRAY_SIZE(wm8960_snd_controls));
-       wm8960_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8960_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8960 = {
-       .probe =        wm8960_probe,
-       .remove =       wm8960_remove,
-       .suspend =      wm8960_suspend,
-       .resume =       wm8960_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
-
-static int wm8960_register(struct wm8960_priv *wm8960,
-                          enum snd_soc_control_type control)
+static int wm8960_probe(struct snd_soc_codec *codec)
 {
-       struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
-       struct snd_soc_codec *codec = &wm8960->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       struct wm8960_data *pdata = dev_get_platdata(codec->dev);
        int ret;
        u16 reg;
 
-       if (wm8960_codec) {
-               dev_err(codec->dev, "Another WM8960 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       codec->set_bias_level = wm8960_set_bias_level_out3;
+       wm8960->set_bias_level = wm8960_set_bias_level_out3;
+       codec->control_data = wm8960->control_data;
 
        if (!pdata) {
                dev_warn(codec->dev, "No platform data supplied\n");
@@ -988,39 +934,22 @@ static int wm8960_register(struct wm8960_priv *wm8960,
                }
 
                if (pdata->capless)
-                       codec->set_bias_level = wm8960_set_bias_level_capless;
+                       wm8960->set_bias_level = wm8960_set_bias_level_capless;
        }
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8960);
-       codec->name = "WM8960";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->dai = &wm8960_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8960_CACHEREGNUM;
-       codec->reg_cache = &wm8960->reg_cache;
-
-       memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8960_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8960_dai.dev = codec->dev;
-
-       codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
        reg = snd_soc_read(codec, WM8960_LINVOL);
@@ -1044,62 +973,58 @@ static int wm8960_register(struct wm8960_priv *wm8960,
        reg = snd_soc_read(codec, WM8960_ROUT2);
        snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
 
-       wm8960_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8960_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8960_snd_controls,
+                                    ARRAY_SIZE(wm8960_snd_controls));
+       wm8960_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8960);
-       return ret;
 }
 
-static void wm8960_unregister(struct wm8960_priv *wm8960)
+/* power down chip */
+static int wm8960_remove(struct snd_soc_codec *codec)
 {
-       wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8960_dai);
-       snd_soc_unregister_codec(&wm8960->codec);
-       kfree(wm8960);
-       wm8960_codec = NULL;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
+       .probe =        wm8960_probe,
+       .remove =       wm8960_remove,
+       .suspend =      wm8960_suspend,
+       .resume =       wm8960_resume,
+       .set_bias_level = wm8960_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8960_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8960_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8960_priv *wm8960;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
        if (wm8960 == NULL)
                return -ENOMEM;
 
-       codec = &wm8960->codec;
-
        i2c_set_clientdata(i2c, wm8960);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8960->control_data = i2c;
 
-       return wm8960_register(wm8960, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8960, &wm8960_dai, 1);
+       if (ret < 0)
+               kfree(wm8960);
+       return ret;
 }
 
 static __devexit int wm8960_i2c_remove(struct i2c_client *client)
 {
-       struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
-       wm8960_unregister(wm8960);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1111,35 +1036,37 @@ MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
 
 static struct i2c_driver wm8960_i2c_driver = {
        .driver = {
-               .name = "wm8960",
+               .name = "wm8960-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8960_i2c_probe,
        .remove =   __devexit_p(wm8960_i2c_remove),
        .id_table = wm8960_i2c_id,
 };
+#endif
 
 static int __init wm8960_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8960_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm8960_modinit);
 
 static void __exit wm8960_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8960_i2c_driver);
+#endif
 }
 module_exit(wm8960_exit);
 
-
 MODULE_DESCRIPTION("ASoC WM8960 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
index a5ef65481b86e036bdad252b7aba50a6f14ec2e5..2d8163d7004b86a59c4f34522bd2f1d3f74a8e24 100644 (file)
 #define WM8960_OPCLK_DIV_5_5           (4 << 0)
 #define WM8960_OPCLK_DIV_6             (5 << 0)
 
-extern struct snd_soc_dai wm8960_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8960;
-
 #endif
index 2549d3a297ab957c3bacc608089beef0c688bff2..4f326f6041042742255731ba078574b37a48a6f3 100644 (file)
@@ -288,7 +288,7 @@ static u16 wm8961_reg_defaults[] = {
 };
 
 struct wm8961_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        int sysclk;
        u16 reg_cache[WM8961_MAX_REGISTER];
 };
@@ -940,8 +940,8 @@ static struct snd_soc_dai_ops wm8961_dai_ops = {
        .set_clkdiv = wm8961_set_clkdiv,
 };
 
-struct snd_soc_dai wm8961_dai = {
-       .name = "WM8961",
+static struct snd_soc_dai_driver wm8961_dai = {
+       .name = "wm8961-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -956,140 +956,22 @@ struct snd_soc_dai wm8961_dai = {
                .formats = WM8961_FORMATS,},
        .ops = &wm8961_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8961_dai);
 
-
-static struct snd_soc_codec *wm8961_codec;
-
-static int wm8961_probe(struct platform_device *pdev)
+static int wm8961_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       if (wm8961_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8961_codec;
-       codec = wm8961_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8961_snd_controls,
-                               ARRAY_SIZE(wm8961_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
-                                 ARRAY_SIZE(wm8961_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8961_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int wm8961_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int wm8961_resume(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       u16 *reg_cache = codec->reg_cache;
-       int i;
-
-       for (i = 0; i < codec->reg_cache_size; i++) {
-               if (reg_cache[i] == wm8961_reg_defaults[i])
-                       continue;
-
-               if (i == WM8961_SOFTWARE_RESET)
-                       continue;
-
-               snd_soc_write(codec, i, reg_cache[i]);
-       }
-
-       wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-#else
-#define wm8961_suspend NULL
-#define wm8961_resume NULL
-#endif
-
-struct snd_soc_codec_device soc_codec_dev_wm8961 = {
-       .probe =        wm8961_probe,
-       .remove =       wm8961_remove,
-       .suspend =      wm8961_suspend,
-       .resume =       wm8961_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961);
-
-static int wm8961_register(struct wm8961_priv *wm8961)
-{
-       struct snd_soc_codec *codec = &wm8961->codec;
-       int ret;
        u16 reg;
 
-       if (wm8961_codec) {
-               dev_err(codec->dev, "Another WM8961 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8961);
-       codec->name = "WM8961";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8961_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
-       codec->reg_cache = &wm8961->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8961_set_bias_level;
-       codec->volatile_register = wm8961_volatile_register;
-
-       memcpy(codec->reg_cache, wm8961_reg_defaults,
-              sizeof(wm8961_reg_defaults));
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
        if (reg != 0x1801) {
                dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        /* This isn't volatile - readback doesn't correspond to write */
@@ -1102,7 +984,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
        ret = wm8961_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
        /* Enable class W */
@@ -1140,64 +1022,89 @@ static int wm8961_register(struct wm8961_priv *wm8961)
 
        wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8961_dai.dev = codec->dev;
+       snd_soc_add_controls(codec, wm8961_snd_controls,
+                               ARRAY_SIZE(wm8961_snd_controls));
+       snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+                                 ARRAY_SIZE(wm8961_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-       wm8961_codec = codec;
+       return 0;
+}
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+static int wm8961_remove(struct snd_soc_codec *codec)
+{
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       ret = snd_soc_register_dai(&wm8961_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+#ifdef CONFIG_PM
+static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8961);
-       return ret;
 }
 
-static void wm8961_unregister(struct wm8961_priv *wm8961)
+static int wm8961_resume(struct snd_soc_codec *codec)
 {
-       wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8961_dai);
-       snd_soc_unregister_codec(&wm8961->codec);
-       kfree(wm8961);
-       wm8961_codec = NULL;
+       u16 *reg_cache = codec->reg_cache;
+       int i;
+
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (reg_cache[i] == wm8961_reg_defaults[i])
+                       continue;
+
+               if (i == WM8961_SOFTWARE_RESET)
+                       continue;
+
+               snd_soc_write(codec, i, reg_cache[i]);
+       }
+
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
 }
+#else
+#define wm8961_suspend NULL
+#define wm8961_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
+       .probe =        wm8961_probe,
+       .remove =       wm8961_remove,
+       .suspend =      wm8961_suspend,
+       .resume =       wm8961_resume,
+       .set_bias_level = wm8961_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8961_reg_defaults,
+       .volatile_register = wm8961_volatile_register,
+};
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8961_priv *wm8961;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
        if (wm8961 == NULL)
                return -ENOMEM;
 
-       codec = &wm8961->codec;
-
        i2c_set_clientdata(i2c, wm8961);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
 
-       return wm8961_register(wm8961);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8961, &wm8961_dai, 1);
+       if (ret < 0)
+               kfree(wm8961);
+       return ret;
 }
 
 static __devexit int wm8961_i2c_remove(struct i2c_client *client)
 {
-       struct wm8961_priv *wm8961 = i2c_get_clientdata(client);
-       wm8961_unregister(wm8961);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1209,35 +1116,37 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
 
 static struct i2c_driver wm8961_i2c_driver = {
        .driver = {
-               .name = "wm8961",
+               .name = "wm8961-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8961_i2c_probe,
        .remove =   __devexit_p(wm8961_i2c_remove),
        .id_table = wm8961_i2c_id,
 };
+#endif
 
 static int __init wm8961_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8961_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm8961_modinit);
 
 static void __exit wm8961_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8961_i2c_driver);
+#endif
 }
 module_exit(wm8961_exit);
 
-
 MODULE_DESCRIPTION("ASoC WM8961 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index 5513bfd720d68c05167ffa6e6179c45eed322477..1d736e5701c85b7a2bdcb80f6efdcbf24a66822c 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_codec_device soc_codec_dev_wm8961;
-extern struct snd_soc_dai wm8961_dai;
-
 #define WM8961_BCLK  1
 #define WM8961_LRCLK 2
 
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
new file mode 100644 (file)
index 0000000..894d0cd
--- /dev/null
@@ -0,0 +1,3977 @@
+/*
+ * wm8962.c  --  WM8962 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8962.h>
+
+#include "wm8962.h"
+
+#define WM8962_NUM_SUPPLIES 8
+static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "CPVDD",
+       "MICVDD",
+       "PLLVDD",
+       "SPKVDD1",
+       "SPKVDD2",
+};
+
+/* codec private data */
+struct wm8962_priv {
+       struct snd_soc_codec *codec;
+
+       u16 reg_cache[WM8962_MAX_REGISTER + 1];
+
+       int sysclk;
+       int sysclk_rate;
+
+       int bclk;  /* Desired BCLK */
+       int lrclk;
+
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       struct delayed_work mic_work;
+       struct snd_soc_jack *jack;
+
+       struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       struct input_dev *beep;
+       struct work_struct beep_work;
+       int beep_rate;
+#endif
+
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8962_REGULATOR_EVENT(n) \
+static int wm8962_regulator_event_##n(struct notifier_block *nb, \
+                                   unsigned long event, void *data)    \
+{ \
+       struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8962->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8962_REGULATOR_EVENT(0)
+WM8962_REGULATOR_EVENT(1)
+WM8962_REGULATOR_EVENT(2)
+WM8962_REGULATOR_EVENT(3)
+WM8962_REGULATOR_EVENT(4)
+WM8962_REGULATOR_EVENT(5)
+WM8962_REGULATOR_EVENT(6)
+WM8962_REGULATOR_EVENT(7)
+
+static const u16 wm8962_reg[WM8962_MAX_REGISTER + 1] = {
+       [0] = 0x009F,     /* R0     - Left Input volume */
+       [1] = 0x049F,     /* R1     - Right Input volume */
+       [2] = 0x0000,     /* R2     - HPOUTL volume */
+       [3] = 0x0000,     /* R3     - HPOUTR volume */
+       [4] = 0x0020,     /* R4     - Clocking1 */
+       [5] = 0x0018,     /* R5     - ADC & DAC Control 1 */
+       [6] = 0x2008,     /* R6     - ADC & DAC Control 2 */
+       [7] = 0x000A,     /* R7     - Audio Interface 0 */
+       [8] = 0x01E4,     /* R8     - Clocking2 */
+       [9] = 0x0300,     /* R9     - Audio Interface 1 */
+       [10] = 0x00C0,    /* R10    - Left DAC volume */
+       [11] = 0x00C0,    /* R11    - Right DAC volume */
+
+       [14] = 0x0040,     /* R14    - Audio Interface 2 */
+       [15] = 0x6243,     /* R15    - Software Reset */
+
+       [17] = 0x007B,     /* R17    - ALC1 */
+       [18] = 0x0000,     /* R18    - ALC2 */
+       [19] = 0x1C32,     /* R19    - ALC3 */
+       [20] = 0x3200,     /* R20    - Noise Gate */
+       [21] = 0x00C0,     /* R21    - Left ADC volume */
+       [22] = 0x00C0,     /* R22    - Right ADC volume */
+       [23] = 0x0160,     /* R23    - Additional control(1) */
+       [24] = 0x0000,     /* R24    - Additional control(2) */
+       [25] = 0x0000,     /* R25    - Pwr Mgmt (1) */
+       [26] = 0x0000,     /* R26    - Pwr Mgmt (2) */
+       [27] = 0x0010,     /* R27    - Additional Control (3) */
+       [28] = 0x0000,     /* R28    - Anti-pop */
+
+       [30] = 0x005E,     /* R30    - Clocking 3 */
+       [31] = 0x0000,     /* R31    - Input mixer control (1) */
+       [32] = 0x0145,     /* R32    - Left input mixer volume */
+       [33] = 0x0145,     /* R33    - Right input mixer volume */
+       [34] = 0x0009,     /* R34    - Input mixer control (2) */
+       [35] = 0x0003,     /* R35    - Input bias control */
+       [37] = 0x0008,     /* R37    - Left input PGA control */
+       [38] = 0x0008,     /* R38    - Right input PGA control */
+
+       [40] = 0x0000,     /* R40    - SPKOUTL volume */
+       [41] = 0x0000,     /* R41    - SPKOUTR volume */
+
+       [47] = 0x0000,     /* R47    - Thermal Shutdown Status */
+       [48] = 0x8027,     /* R48    - Additional Control (4) */
+       [49] = 0x0010,     /* R49    - Class D Control 1 */
+
+       [51] = 0x0003,     /* R51    - Class D Control 2 */
+
+       [56] = 0x0506,     /* R56    - Clocking 4 */
+       [57] = 0x0000,     /* R57    - DAC DSP Mixing (1) */
+       [58] = 0x0000,     /* R58    - DAC DSP Mixing (2) */
+
+       [60] = 0x0300,     /* R60    - DC Servo 0 */
+       [61] = 0x0300,     /* R61    - DC Servo 1 */
+
+       [64] = 0x0810,     /* R64    - DC Servo 4 */
+
+       [66] = 0x0000,     /* R66    - DC Servo 6 */
+
+       [68] = 0x001B,     /* R68    - Analogue PGA Bias */
+       [69] = 0x0000,     /* R69    - Analogue HP 0 */
+
+       [71] = 0x01FB,     /* R71    - Analogue HP 2 */
+       [72] = 0x0000,     /* R72    - Charge Pump 1 */
+
+       [82] = 0x0004,     /* R82    - Charge Pump B */
+
+       [87] = 0x0000,     /* R87    - Write Sequencer Control 1 */
+
+       [90] = 0x0000,     /* R90    - Write Sequencer Control 2 */
+
+       [93] = 0x0000,     /* R93    - Write Sequencer Control 3 */
+       [94] = 0x0000,     /* R94    - Control Interface */
+
+       [99] = 0x0000,     /* R99    - Mixer Enables */
+       [100] = 0x0000,     /* R100   - Headphone Mixer (1) */
+       [101] = 0x0000,     /* R101   - Headphone Mixer (2) */
+       [102] = 0x013F,     /* R102   - Headphone Mixer (3) */
+       [103] = 0x013F,     /* R103   - Headphone Mixer (4) */
+
+       [105] = 0x0000,     /* R105   - Speaker Mixer (1) */
+       [106] = 0x0000,     /* R106   - Speaker Mixer (2) */
+       [107] = 0x013F,     /* R107   - Speaker Mixer (3) */
+       [108] = 0x013F,     /* R108   - Speaker Mixer (4) */
+       [109] = 0x0003,     /* R109   - Speaker Mixer (5) */
+       [110] = 0x0002,     /* R110   - Beep Generator (1) */
+
+       [115] = 0x0006,     /* R115   - Oscillator Trim (3) */
+       [116] = 0x0026,     /* R116   - Oscillator Trim (4) */
+
+       [119] = 0x0000,     /* R119   - Oscillator Trim (7) */
+
+       [124] = 0x0011,     /* R124   - Analogue Clocking1 */
+       [125] = 0x004B,     /* R125   - Analogue Clocking2 */
+       [126] = 0x000D,     /* R126   - Analogue Clocking3 */
+       [127] = 0x0000,     /* R127   - PLL Software Reset */
+
+       [129] = 0x0000,     /* R129   - PLL2 */
+
+       [131] = 0x0000,     /* R131   - PLL 4 */
+
+       [136] = 0x0067,     /* R136   - PLL 9 */
+       [137] = 0x001C,     /* R137   - PLL 10 */
+       [138] = 0x0071,     /* R138   - PLL 11 */
+       [139] = 0x00C7,     /* R139   - PLL 12 */
+       [140] = 0x0067,     /* R140   - PLL 13 */
+       [141] = 0x0048,     /* R141   - PLL 14 */
+       [142] = 0x0022,     /* R142   - PLL 15 */
+       [143] = 0x0097,     /* R143   - PLL 16 */
+
+       [155] = 0x000C,     /* R155   - FLL Control (1) */
+       [156] = 0x0039,     /* R156   - FLL Control (2) */
+       [157] = 0x0180,     /* R157   - FLL Control (3) */
+
+       [159] = 0x0032,     /* R159   - FLL Control (5) */
+       [160] = 0x0018,     /* R160   - FLL Control (6) */
+       [161] = 0x007D,     /* R161   - FLL Control (7) */
+       [162] = 0x0008,     /* R162   - FLL Control (8) */
+
+       [252] = 0x0005,     /* R252   - General test 1 */
+
+       [256] = 0x0000,     /* R256   - DF1 */
+       [257] = 0x0000,     /* R257   - DF2 */
+       [258] = 0x0000,     /* R258   - DF3 */
+       [259] = 0x0000,     /* R259   - DF4 */
+       [260] = 0x0000,     /* R260   - DF5 */
+       [261] = 0x0000,     /* R261   - DF6 */
+       [262] = 0x0000,     /* R262   - DF7 */
+
+       [264] = 0x0000,     /* R264   - LHPF1 */
+       [265] = 0x0000,     /* R265   - LHPF2 */
+
+       [268] = 0x0000,     /* R268   - THREED1 */
+       [269] = 0x0000,     /* R269   - THREED2 */
+       [270] = 0x0000,     /* R270   - THREED3 */
+       [271] = 0x0000,     /* R271   - THREED4 */
+
+       [276] = 0x000C,     /* R276   - DRC 1 */
+       [277] = 0x0925,     /* R277   - DRC 2 */
+       [278] = 0x0000,     /* R278   - DRC 3 */
+       [279] = 0x0000,     /* R279   - DRC 4 */
+       [280] = 0x0000,     /* R280   - DRC 5 */
+
+       [285] = 0x0000,     /* R285   - Tloopback */
+
+       [335] = 0x0004,     /* R335   - EQ1 */
+       [336] = 0x6318,     /* R336   - EQ2 */
+       [337] = 0x6300,     /* R337   - EQ3 */
+       [338] = 0x0FCA,     /* R338   - EQ4 */
+       [339] = 0x0400,     /* R339   - EQ5 */
+       [340] = 0x00D8,     /* R340   - EQ6 */
+       [341] = 0x1EB5,     /* R341   - EQ7 */
+       [342] = 0xF145,     /* R342   - EQ8 */
+       [343] = 0x0B75,     /* R343   - EQ9 */
+       [344] = 0x01C5,     /* R344   - EQ10 */
+       [345] = 0x1C58,     /* R345   - EQ11 */
+       [346] = 0xF373,     /* R346   - EQ12 */
+       [347] = 0x0A54,     /* R347   - EQ13 */
+       [348] = 0x0558,     /* R348   - EQ14 */
+       [349] = 0x168E,     /* R349   - EQ15 */
+       [350] = 0xF829,     /* R350   - EQ16 */
+       [351] = 0x07AD,     /* R351   - EQ17 */
+       [352] = 0x1103,     /* R352   - EQ18 */
+       [353] = 0x0564,     /* R353   - EQ19 */
+       [354] = 0x0559,     /* R354   - EQ20 */
+       [355] = 0x4000,     /* R355   - EQ21 */
+       [356] = 0x6318,     /* R356   - EQ22 */
+       [357] = 0x6300,     /* R357   - EQ23 */
+       [358] = 0x0FCA,     /* R358   - EQ24 */
+       [359] = 0x0400,     /* R359   - EQ25 */
+       [360] = 0x00D8,     /* R360   - EQ26 */
+       [361] = 0x1EB5,     /* R361   - EQ27 */
+       [362] = 0xF145,     /* R362   - EQ28 */
+       [363] = 0x0B75,     /* R363   - EQ29 */
+       [364] = 0x01C5,     /* R364   - EQ30 */
+       [365] = 0x1C58,     /* R365   - EQ31 */
+       [366] = 0xF373,     /* R366   - EQ32 */
+       [367] = 0x0A54,     /* R367   - EQ33 */
+       [368] = 0x0558,     /* R368   - EQ34 */
+       [369] = 0x168E,     /* R369   - EQ35 */
+       [370] = 0xF829,     /* R370   - EQ36 */
+       [371] = 0x07AD,     /* R371   - EQ37 */
+       [372] = 0x1103,     /* R372   - EQ38 */
+       [373] = 0x0564,     /* R373   - EQ39 */
+       [374] = 0x0559,     /* R374   - EQ40 */
+       [375] = 0x4000,     /* R375   - EQ41 */
+
+       [513] = 0x0000,     /* R513   - GPIO 2 */
+       [514] = 0x0000,     /* R514   - GPIO 3 */
+
+       [516] = 0x8100,     /* R516   - GPIO 5 */
+       [517] = 0x8100,     /* R517   - GPIO 6 */
+
+       [560] = 0x0000,     /* R560   - Interrupt Status 1 */
+       [561] = 0x0000,     /* R561   - Interrupt Status 2 */
+
+       [568] = 0x0030,     /* R568   - Interrupt Status 1 Mask */
+       [569] = 0xFFED,     /* R569   - Interrupt Status 2 Mask */
+
+       [576] = 0x0000,     /* R576   - Interrupt Control */
+
+       [584] = 0x002D,     /* R584   - IRQ Debounce */
+
+       [586] = 0x0000,     /* R586   -  MICINT Source Pol */
+
+       [768] = 0x1C00,     /* R768   - DSP2 Power Management */
+
+       [1037] = 0x0000,     /* R1037  - DSP2_ExecControl */
+
+       [8192] = 0x0000,     /* R8192  - DSP2 Instruction RAM 0 */
+
+       [9216] = 0x0030,     /* R9216  - DSP2 Address RAM 2 */
+       [9217] = 0x0000,     /* R9217  - DSP2 Address RAM 1 */
+       [9218] = 0x0000,     /* R9218  - DSP2 Address RAM 0 */
+
+       [12288] = 0x0000,     /* R12288 - DSP2 Data1 RAM 1 */
+       [12289] = 0x0000,     /* R12289 - DSP2 Data1 RAM 0 */
+
+       [13312] = 0x0000,     /* R13312 - DSP2 Data2 RAM 1 */
+       [13313] = 0x0000,     /* R13313 - DSP2 Data2 RAM 0 */
+
+       [14336] = 0x0000,     /* R14336 - DSP2 Data3 RAM 1 */
+       [14337] = 0x0000,     /* R14337 - DSP2 Data3 RAM 0 */
+
+       [15360] = 0x000A,     /* R15360 - DSP2 Coeff RAM 0 */
+
+       [16384] = 0x0000,     /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+       [16385] = 0x0000,     /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+       [16386] = 0x0000,     /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+       [16387] = 0x0000,     /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+       [16388] = 0x0000,     /* R16388 - SOUNDSTAGE_ENABLES_1 */
+       [16389] = 0x0000,     /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+       [16896] = 0x0002,     /* R16896 - HDBASS_AI_1 */
+       [16897] = 0xBD12,     /* R16897 - HDBASS_AI_0 */
+       [16898] = 0x007C,     /* R16898 - HDBASS_AR_1 */
+       [16899] = 0x586C,     /* R16899 - HDBASS_AR_0 */
+       [16900] = 0x0053,     /* R16900 - HDBASS_B_1 */
+       [16901] = 0x8121,     /* R16901 - HDBASS_B_0 */
+       [16902] = 0x003F,     /* R16902 - HDBASS_K_1 */
+       [16903] = 0x8BD8,     /* R16903 - HDBASS_K_0 */
+       [16904] = 0x0032,     /* R16904 - HDBASS_N1_1 */
+       [16905] = 0xF52D,     /* R16905 - HDBASS_N1_0 */
+       [16906] = 0x0065,     /* R16906 - HDBASS_N2_1 */
+       [16907] = 0xAC8C,     /* R16907 - HDBASS_N2_0 */
+       [16908] = 0x006B,     /* R16908 - HDBASS_N3_1 */
+       [16909] = 0xE087,     /* R16909 - HDBASS_N3_0 */
+       [16910] = 0x0072,     /* R16910 - HDBASS_N4_1 */
+       [16911] = 0x1483,     /* R16911 - HDBASS_N4_0 */
+       [16912] = 0x0072,     /* R16912 - HDBASS_N5_1 */
+       [16913] = 0x1483,     /* R16913 - HDBASS_N5_0 */
+       [16914] = 0x0043,     /* R16914 - HDBASS_X1_1 */
+       [16915] = 0x3525,     /* R16915 - HDBASS_X1_0 */
+       [16916] = 0x0006,     /* R16916 - HDBASS_X2_1 */
+       [16917] = 0x6A4A,     /* R16917 - HDBASS_X2_0 */
+       [16918] = 0x0043,     /* R16918 - HDBASS_X3_1 */
+       [16919] = 0x6079,     /* R16919 - HDBASS_X3_0 */
+       [16920] = 0x0008,     /* R16920 - HDBASS_ATK_1 */
+       [16921] = 0x0000,     /* R16921 - HDBASS_ATK_0 */
+       [16922] = 0x0001,     /* R16922 - HDBASS_DCY_1 */
+       [16923] = 0x0000,     /* R16923 - HDBASS_DCY_0 */
+       [16924] = 0x0059,     /* R16924 - HDBASS_PG_1 */
+       [16925] = 0x999A,     /* R16925 - HDBASS_PG_0 */
+
+       [17048] = 0x0083,     /* R17408 - HPF_C_1 */
+       [17049] = 0x98AD,     /* R17409 - HPF_C_0 */
+
+       [17920] = 0x007F,     /* R17920 - ADCL_RETUNE_C1_1 */
+       [17921] = 0xFFFF,     /* R17921 - ADCL_RETUNE_C1_0 */
+       [17922] = 0x0000,     /* R17922 - ADCL_RETUNE_C2_1 */
+       [17923] = 0x0000,     /* R17923 - ADCL_RETUNE_C2_0 */
+       [17924] = 0x0000,     /* R17924 - ADCL_RETUNE_C3_1 */
+       [17925] = 0x0000,     /* R17925 - ADCL_RETUNE_C3_0 */
+       [17926] = 0x0000,     /* R17926 - ADCL_RETUNE_C4_1 */
+       [17927] = 0x0000,     /* R17927 - ADCL_RETUNE_C4_0 */
+       [17928] = 0x0000,     /* R17928 - ADCL_RETUNE_C5_1 */
+       [17929] = 0x0000,     /* R17929 - ADCL_RETUNE_C5_0 */
+       [17930] = 0x0000,     /* R17930 - ADCL_RETUNE_C6_1 */
+       [17931] = 0x0000,     /* R17931 - ADCL_RETUNE_C6_0 */
+       [17932] = 0x0000,     /* R17932 - ADCL_RETUNE_C7_1 */
+       [17933] = 0x0000,     /* R17933 - ADCL_RETUNE_C7_0 */
+       [17934] = 0x0000,     /* R17934 - ADCL_RETUNE_C8_1 */
+       [17935] = 0x0000,     /* R17935 - ADCL_RETUNE_C8_0 */
+       [17936] = 0x0000,     /* R17936 - ADCL_RETUNE_C9_1 */
+       [17937] = 0x0000,     /* R17937 - ADCL_RETUNE_C9_0 */
+       [17938] = 0x0000,     /* R17938 - ADCL_RETUNE_C10_1 */
+       [17939] = 0x0000,     /* R17939 - ADCL_RETUNE_C10_0 */
+       [17940] = 0x0000,     /* R17940 - ADCL_RETUNE_C11_1 */
+       [17941] = 0x0000,     /* R17941 - ADCL_RETUNE_C11_0 */
+       [17942] = 0x0000,     /* R17942 - ADCL_RETUNE_C12_1 */
+       [17943] = 0x0000,     /* R17943 - ADCL_RETUNE_C12_0 */
+       [17944] = 0x0000,     /* R17944 - ADCL_RETUNE_C13_1 */
+       [17945] = 0x0000,     /* R17945 - ADCL_RETUNE_C13_0 */
+       [17946] = 0x0000,     /* R17946 - ADCL_RETUNE_C14_1 */
+       [17947] = 0x0000,     /* R17947 - ADCL_RETUNE_C14_0 */
+       [17948] = 0x0000,     /* R17948 - ADCL_RETUNE_C15_1 */
+       [17949] = 0x0000,     /* R17949 - ADCL_RETUNE_C15_0 */
+       [17950] = 0x0000,     /* R17950 - ADCL_RETUNE_C16_1 */
+       [17951] = 0x0000,     /* R17951 - ADCL_RETUNE_C16_0 */
+       [17952] = 0x0000,     /* R17952 - ADCL_RETUNE_C17_1 */
+       [17953] = 0x0000,     /* R17953 - ADCL_RETUNE_C17_0 */
+       [17954] = 0x0000,     /* R17954 - ADCL_RETUNE_C18_1 */
+       [17955] = 0x0000,     /* R17955 - ADCL_RETUNE_C18_0 */
+       [17956] = 0x0000,     /* R17956 - ADCL_RETUNE_C19_1 */
+       [17957] = 0x0000,     /* R17957 - ADCL_RETUNE_C19_0 */
+       [17958] = 0x0000,     /* R17958 - ADCL_RETUNE_C20_1 */
+       [17959] = 0x0000,     /* R17959 - ADCL_RETUNE_C20_0 */
+       [17960] = 0x0000,     /* R17960 - ADCL_RETUNE_C21_1 */
+       [17961] = 0x0000,     /* R17961 - ADCL_RETUNE_C21_0 */
+       [17962] = 0x0000,     /* R17962 - ADCL_RETUNE_C22_1 */
+       [17963] = 0x0000,     /* R17963 - ADCL_RETUNE_C22_0 */
+       [17964] = 0x0000,     /* R17964 - ADCL_RETUNE_C23_1 */
+       [17965] = 0x0000,     /* R17965 - ADCL_RETUNE_C23_0 */
+       [17966] = 0x0000,     /* R17966 - ADCL_RETUNE_C24_1 */
+       [17967] = 0x0000,     /* R17967 - ADCL_RETUNE_C24_0 */
+       [17968] = 0x0000,     /* R17968 - ADCL_RETUNE_C25_1 */
+       [17969] = 0x0000,     /* R17969 - ADCL_RETUNE_C25_0 */
+       [17970] = 0x0000,     /* R17970 - ADCL_RETUNE_C26_1 */
+       [17971] = 0x0000,     /* R17971 - ADCL_RETUNE_C26_0 */
+       [17972] = 0x0000,     /* R17972 - ADCL_RETUNE_C27_1 */
+       [17973] = 0x0000,     /* R17973 - ADCL_RETUNE_C27_0 */
+       [17974] = 0x0000,     /* R17974 - ADCL_RETUNE_C28_1 */
+       [17975] = 0x0000,     /* R17975 - ADCL_RETUNE_C28_0 */
+       [17976] = 0x0000,     /* R17976 - ADCL_RETUNE_C29_1 */
+       [17977] = 0x0000,     /* R17977 - ADCL_RETUNE_C29_0 */
+       [17978] = 0x0000,     /* R17978 - ADCL_RETUNE_C30_1 */
+       [17979] = 0x0000,     /* R17979 - ADCL_RETUNE_C30_0 */
+       [17980] = 0x0000,     /* R17980 - ADCL_RETUNE_C31_1 */
+       [17981] = 0x0000,     /* R17981 - ADCL_RETUNE_C31_0 */
+       [17982] = 0x0000,     /* R17982 - ADCL_RETUNE_C32_1 */
+       [17983] = 0x0000,     /* R17983 - ADCL_RETUNE_C32_0 */
+
+       [18432] = 0x0020,     /* R18432 - RETUNEADC_PG2_1 */
+       [18433] = 0x0000,     /* R18433 - RETUNEADC_PG2_0 */
+       [18434] = 0x0040,     /* R18434 - RETUNEADC_PG_1 */
+       [18435] = 0x0000,     /* R18435 - RETUNEADC_PG_0 */
+
+       [18944] = 0x007F,     /* R18944 - ADCR_RETUNE_C1_1 */
+       [18945] = 0xFFFF,     /* R18945 - ADCR_RETUNE_C1_0 */
+       [18946] = 0x0000,     /* R18946 - ADCR_RETUNE_C2_1 */
+       [18947] = 0x0000,     /* R18947 - ADCR_RETUNE_C2_0 */
+       [18948] = 0x0000,     /* R18948 - ADCR_RETUNE_C3_1 */
+       [18949] = 0x0000,     /* R18949 - ADCR_RETUNE_C3_0 */
+       [18950] = 0x0000,     /* R18950 - ADCR_RETUNE_C4_1 */
+       [18951] = 0x0000,     /* R18951 - ADCR_RETUNE_C4_0 */
+       [18952] = 0x0000,     /* R18952 - ADCR_RETUNE_C5_1 */
+       [18953] = 0x0000,     /* R18953 - ADCR_RETUNE_C5_0 */
+       [18954] = 0x0000,     /* R18954 - ADCR_RETUNE_C6_1 */
+       [18955] = 0x0000,     /* R18955 - ADCR_RETUNE_C6_0 */
+       [18956] = 0x0000,     /* R18956 - ADCR_RETUNE_C7_1 */
+       [18957] = 0x0000,     /* R18957 - ADCR_RETUNE_C7_0 */
+       [18958] = 0x0000,     /* R18958 - ADCR_RETUNE_C8_1 */
+       [18959] = 0x0000,     /* R18959 - ADCR_RETUNE_C8_0 */
+       [18960] = 0x0000,     /* R18960 - ADCR_RETUNE_C9_1 */
+       [18961] = 0x0000,     /* R18961 - ADCR_RETUNE_C9_0 */
+       [18962] = 0x0000,     /* R18962 - ADCR_RETUNE_C10_1 */
+       [18963] = 0x0000,     /* R18963 - ADCR_RETUNE_C10_0 */
+       [18964] = 0x0000,     /* R18964 - ADCR_RETUNE_C11_1 */
+       [18965] = 0x0000,     /* R18965 - ADCR_RETUNE_C11_0 */
+       [18966] = 0x0000,     /* R18966 - ADCR_RETUNE_C12_1 */
+       [18967] = 0x0000,     /* R18967 - ADCR_RETUNE_C12_0 */
+       [18968] = 0x0000,     /* R18968 - ADCR_RETUNE_C13_1 */
+       [18969] = 0x0000,     /* R18969 - ADCR_RETUNE_C13_0 */
+       [18970] = 0x0000,     /* R18970 - ADCR_RETUNE_C14_1 */
+       [18971] = 0x0000,     /* R18971 - ADCR_RETUNE_C14_0 */
+       [18972] = 0x0000,     /* R18972 - ADCR_RETUNE_C15_1 */
+       [18973] = 0x0000,     /* R18973 - ADCR_RETUNE_C15_0 */
+       [18974] = 0x0000,     /* R18974 - ADCR_RETUNE_C16_1 */
+       [18975] = 0x0000,     /* R18975 - ADCR_RETUNE_C16_0 */
+       [18976] = 0x0000,     /* R18976 - ADCR_RETUNE_C17_1 */
+       [18977] = 0x0000,     /* R18977 - ADCR_RETUNE_C17_0 */
+       [18978] = 0x0000,     /* R18978 - ADCR_RETUNE_C18_1 */
+       [18979] = 0x0000,     /* R18979 - ADCR_RETUNE_C18_0 */
+       [18980] = 0x0000,     /* R18980 - ADCR_RETUNE_C19_1 */
+       [18981] = 0x0000,     /* R18981 - ADCR_RETUNE_C19_0 */
+       [18982] = 0x0000,     /* R18982 - ADCR_RETUNE_C20_1 */
+       [18983] = 0x0000,     /* R18983 - ADCR_RETUNE_C20_0 */
+       [18984] = 0x0000,     /* R18984 - ADCR_RETUNE_C21_1 */
+       [18985] = 0x0000,     /* R18985 - ADCR_RETUNE_C21_0 */
+       [18986] = 0x0000,     /* R18986 - ADCR_RETUNE_C22_1 */
+       [18987] = 0x0000,     /* R18987 - ADCR_RETUNE_C22_0 */
+       [18988] = 0x0000,     /* R18988 - ADCR_RETUNE_C23_1 */
+       [18989] = 0x0000,     /* R18989 - ADCR_RETUNE_C23_0 */
+       [18990] = 0x0000,     /* R18990 - ADCR_RETUNE_C24_1 */
+       [18991] = 0x0000,     /* R18991 - ADCR_RETUNE_C24_0 */
+       [18992] = 0x0000,     /* R18992 - ADCR_RETUNE_C25_1 */
+       [18993] = 0x0000,     /* R18993 - ADCR_RETUNE_C25_0 */
+       [18994] = 0x0000,     /* R18994 - ADCR_RETUNE_C26_1 */
+       [18995] = 0x0000,     /* R18995 - ADCR_RETUNE_C26_0 */
+       [18996] = 0x0000,     /* R18996 - ADCR_RETUNE_C27_1 */
+       [18997] = 0x0000,     /* R18997 - ADCR_RETUNE_C27_0 */
+       [18998] = 0x0000,     /* R18998 - ADCR_RETUNE_C28_1 */
+       [18999] = 0x0000,     /* R18999 - ADCR_RETUNE_C28_0 */
+       [19000] = 0x0000,     /* R19000 - ADCR_RETUNE_C29_1 */
+       [19001] = 0x0000,     /* R19001 - ADCR_RETUNE_C29_0 */
+       [19002] = 0x0000,     /* R19002 - ADCR_RETUNE_C30_1 */
+       [19003] = 0x0000,     /* R19003 - ADCR_RETUNE_C30_0 */
+       [19004] = 0x0000,     /* R19004 - ADCR_RETUNE_C31_1 */
+       [19005] = 0x0000,     /* R19005 - ADCR_RETUNE_C31_0 */
+       [19006] = 0x0000,     /* R19006 - ADCR_RETUNE_C32_1 */
+       [19007] = 0x0000,     /* R19007 - ADCR_RETUNE_C32_0 */
+
+       [19456] = 0x007F,     /* R19456 - DACL_RETUNE_C1_1 */
+       [19457] = 0xFFFF,     /* R19457 - DACL_RETUNE_C1_0 */
+       [19458] = 0x0000,     /* R19458 - DACL_RETUNE_C2_1 */
+       [19459] = 0x0000,     /* R19459 - DACL_RETUNE_C2_0 */
+       [19460] = 0x0000,     /* R19460 - DACL_RETUNE_C3_1 */
+       [19461] = 0x0000,     /* R19461 - DACL_RETUNE_C3_0 */
+       [19462] = 0x0000,     /* R19462 - DACL_RETUNE_C4_1 */
+       [19463] = 0x0000,     /* R19463 - DACL_RETUNE_C4_0 */
+       [19464] = 0x0000,     /* R19464 - DACL_RETUNE_C5_1 */
+       [19465] = 0x0000,     /* R19465 - DACL_RETUNE_C5_0 */
+       [19466] = 0x0000,     /* R19466 - DACL_RETUNE_C6_1 */
+       [19467] = 0x0000,     /* R19467 - DACL_RETUNE_C6_0 */
+       [19468] = 0x0000,     /* R19468 - DACL_RETUNE_C7_1 */
+       [19469] = 0x0000,     /* R19469 - DACL_RETUNE_C7_0 */
+       [19470] = 0x0000,     /* R19470 - DACL_RETUNE_C8_1 */
+       [19471] = 0x0000,     /* R19471 - DACL_RETUNE_C8_0 */
+       [19472] = 0x0000,     /* R19472 - DACL_RETUNE_C9_1 */
+       [19473] = 0x0000,     /* R19473 - DACL_RETUNE_C9_0 */
+       [19474] = 0x0000,     /* R19474 - DACL_RETUNE_C10_1 */
+       [19475] = 0x0000,     /* R19475 - DACL_RETUNE_C10_0 */
+       [19476] = 0x0000,     /* R19476 - DACL_RETUNE_C11_1 */
+       [19477] = 0x0000,     /* R19477 - DACL_RETUNE_C11_0 */
+       [19478] = 0x0000,     /* R19478 - DACL_RETUNE_C12_1 */
+       [19479] = 0x0000,     /* R19479 - DACL_RETUNE_C12_0 */
+       [19480] = 0x0000,     /* R19480 - DACL_RETUNE_C13_1 */
+       [19481] = 0x0000,     /* R19481 - DACL_RETUNE_C13_0 */
+       [19482] = 0x0000,     /* R19482 - DACL_RETUNE_C14_1 */
+       [19483] = 0x0000,     /* R19483 - DACL_RETUNE_C14_0 */
+       [19484] = 0x0000,     /* R19484 - DACL_RETUNE_C15_1 */
+       [19485] = 0x0000,     /* R19485 - DACL_RETUNE_C15_0 */
+       [19486] = 0x0000,     /* R19486 - DACL_RETUNE_C16_1 */
+       [19487] = 0x0000,     /* R19487 - DACL_RETUNE_C16_0 */
+       [19488] = 0x0000,     /* R19488 - DACL_RETUNE_C17_1 */
+       [19489] = 0x0000,     /* R19489 - DACL_RETUNE_C17_0 */
+       [19490] = 0x0000,     /* R19490 - DACL_RETUNE_C18_1 */
+       [19491] = 0x0000,     /* R19491 - DACL_RETUNE_C18_0 */
+       [19492] = 0x0000,     /* R19492 - DACL_RETUNE_C19_1 */
+       [19493] = 0x0000,     /* R19493 - DACL_RETUNE_C19_0 */
+       [19494] = 0x0000,     /* R19494 - DACL_RETUNE_C20_1 */
+       [19495] = 0x0000,     /* R19495 - DACL_RETUNE_C20_0 */
+       [19496] = 0x0000,     /* R19496 - DACL_RETUNE_C21_1 */
+       [19497] = 0x0000,     /* R19497 - DACL_RETUNE_C21_0 */
+       [19498] = 0x0000,     /* R19498 - DACL_RETUNE_C22_1 */
+       [19499] = 0x0000,     /* R19499 - DACL_RETUNE_C22_0 */
+       [19500] = 0x0000,     /* R19500 - DACL_RETUNE_C23_1 */
+       [19501] = 0x0000,     /* R19501 - DACL_RETUNE_C23_0 */
+       [19502] = 0x0000,     /* R19502 - DACL_RETUNE_C24_1 */
+       [19503] = 0x0000,     /* R19503 - DACL_RETUNE_C24_0 */
+       [19504] = 0x0000,     /* R19504 - DACL_RETUNE_C25_1 */
+       [19505] = 0x0000,     /* R19505 - DACL_RETUNE_C25_0 */
+       [19506] = 0x0000,     /* R19506 - DACL_RETUNE_C26_1 */
+       [19507] = 0x0000,     /* R19507 - DACL_RETUNE_C26_0 */
+       [19508] = 0x0000,     /* R19508 - DACL_RETUNE_C27_1 */
+       [19509] = 0x0000,     /* R19509 - DACL_RETUNE_C27_0 */
+       [19510] = 0x0000,     /* R19510 - DACL_RETUNE_C28_1 */
+       [19511] = 0x0000,     /* R19511 - DACL_RETUNE_C28_0 */
+       [19512] = 0x0000,     /* R19512 - DACL_RETUNE_C29_1 */
+       [19513] = 0x0000,     /* R19513 - DACL_RETUNE_C29_0 */
+       [19514] = 0x0000,     /* R19514 - DACL_RETUNE_C30_1 */
+       [19515] = 0x0000,     /* R19515 - DACL_RETUNE_C30_0 */
+       [19516] = 0x0000,     /* R19516 - DACL_RETUNE_C31_1 */
+       [19517] = 0x0000,     /* R19517 - DACL_RETUNE_C31_0 */
+       [19518] = 0x0000,     /* R19518 - DACL_RETUNE_C32_1 */
+       [19519] = 0x0000,     /* R19519 - DACL_RETUNE_C32_0 */
+
+       [19968] = 0x0020,     /* R19968 - RETUNEDAC_PG2_1 */
+       [19969] = 0x0000,     /* R19969 - RETUNEDAC_PG2_0 */
+       [19970] = 0x0040,     /* R19970 - RETUNEDAC_PG_1 */
+       [19971] = 0x0000,     /* R19971 - RETUNEDAC_PG_0 */
+
+       [20480] = 0x007F,     /* R20480 - DACR_RETUNE_C1_1 */
+       [20481] = 0xFFFF,     /* R20481 - DACR_RETUNE_C1_0 */
+       [20482] = 0x0000,     /* R20482 - DACR_RETUNE_C2_1 */
+       [20483] = 0x0000,     /* R20483 - DACR_RETUNE_C2_0 */
+       [20484] = 0x0000,     /* R20484 - DACR_RETUNE_C3_1 */
+       [20485] = 0x0000,     /* R20485 - DACR_RETUNE_C3_0 */
+       [20486] = 0x0000,     /* R20486 - DACR_RETUNE_C4_1 */
+       [20487] = 0x0000,     /* R20487 - DACR_RETUNE_C4_0 */
+       [20488] = 0x0000,     /* R20488 - DACR_RETUNE_C5_1 */
+       [20489] = 0x0000,     /* R20489 - DACR_RETUNE_C5_0 */
+       [20490] = 0x0000,     /* R20490 - DACR_RETUNE_C6_1 */
+       [20491] = 0x0000,     /* R20491 - DACR_RETUNE_C6_0 */
+       [20492] = 0x0000,     /* R20492 - DACR_RETUNE_C7_1 */
+       [20493] = 0x0000,     /* R20493 - DACR_RETUNE_C7_0 */
+       [20494] = 0x0000,     /* R20494 - DACR_RETUNE_C8_1 */
+       [20495] = 0x0000,     /* R20495 - DACR_RETUNE_C8_0 */
+       [20496] = 0x0000,     /* R20496 - DACR_RETUNE_C9_1 */
+       [20497] = 0x0000,     /* R20497 - DACR_RETUNE_C9_0 */
+       [20498] = 0x0000,     /* R20498 - DACR_RETUNE_C10_1 */
+       [20499] = 0x0000,     /* R20499 - DACR_RETUNE_C10_0 */
+       [20500] = 0x0000,     /* R20500 - DACR_RETUNE_C11_1 */
+       [20501] = 0x0000,     /* R20501 - DACR_RETUNE_C11_0 */
+       [20502] = 0x0000,     /* R20502 - DACR_RETUNE_C12_1 */
+       [20503] = 0x0000,     /* R20503 - DACR_RETUNE_C12_0 */
+       [20504] = 0x0000,     /* R20504 - DACR_RETUNE_C13_1 */
+       [20505] = 0x0000,     /* R20505 - DACR_RETUNE_C13_0 */
+       [20506] = 0x0000,     /* R20506 - DACR_RETUNE_C14_1 */
+       [20507] = 0x0000,     /* R20507 - DACR_RETUNE_C14_0 */
+       [20508] = 0x0000,     /* R20508 - DACR_RETUNE_C15_1 */
+       [20509] = 0x0000,     /* R20509 - DACR_RETUNE_C15_0 */
+       [20510] = 0x0000,     /* R20510 - DACR_RETUNE_C16_1 */
+       [20511] = 0x0000,     /* R20511 - DACR_RETUNE_C16_0 */
+       [20512] = 0x0000,     /* R20512 - DACR_RETUNE_C17_1 */
+       [20513] = 0x0000,     /* R20513 - DACR_RETUNE_C17_0 */
+       [20514] = 0x0000,     /* R20514 - DACR_RETUNE_C18_1 */
+       [20515] = 0x0000,     /* R20515 - DACR_RETUNE_C18_0 */
+       [20516] = 0x0000,     /* R20516 - DACR_RETUNE_C19_1 */
+       [20517] = 0x0000,     /* R20517 - DACR_RETUNE_C19_0 */
+       [20518] = 0x0000,     /* R20518 - DACR_RETUNE_C20_1 */
+       [20519] = 0x0000,     /* R20519 - DACR_RETUNE_C20_0 */
+       [20520] = 0x0000,     /* R20520 - DACR_RETUNE_C21_1 */
+       [20521] = 0x0000,     /* R20521 - DACR_RETUNE_C21_0 */
+       [20522] = 0x0000,     /* R20522 - DACR_RETUNE_C22_1 */
+       [20523] = 0x0000,     /* R20523 - DACR_RETUNE_C22_0 */
+       [20524] = 0x0000,     /* R20524 - DACR_RETUNE_C23_1 */
+       [20525] = 0x0000,     /* R20525 - DACR_RETUNE_C23_0 */
+       [20526] = 0x0000,     /* R20526 - DACR_RETUNE_C24_1 */
+       [20527] = 0x0000,     /* R20527 - DACR_RETUNE_C24_0 */
+       [20528] = 0x0000,     /* R20528 - DACR_RETUNE_C25_1 */
+       [20529] = 0x0000,     /* R20529 - DACR_RETUNE_C25_0 */
+       [20530] = 0x0000,     /* R20530 - DACR_RETUNE_C26_1 */
+       [20531] = 0x0000,     /* R20531 - DACR_RETUNE_C26_0 */
+       [20532] = 0x0000,     /* R20532 - DACR_RETUNE_C27_1 */
+       [20533] = 0x0000,     /* R20533 - DACR_RETUNE_C27_0 */
+       [20534] = 0x0000,     /* R20534 - DACR_RETUNE_C28_1 */
+       [20535] = 0x0000,     /* R20535 - DACR_RETUNE_C28_0 */
+       [20536] = 0x0000,     /* R20536 - DACR_RETUNE_C29_1 */
+       [20537] = 0x0000,     /* R20537 - DACR_RETUNE_C29_0 */
+       [20538] = 0x0000,     /* R20538 - DACR_RETUNE_C30_1 */
+       [20539] = 0x0000,     /* R20539 - DACR_RETUNE_C30_0 */
+       [20540] = 0x0000,     /* R20540 - DACR_RETUNE_C31_1 */
+       [20541] = 0x0000,     /* R20541 - DACR_RETUNE_C31_0 */
+       [20542] = 0x0000,     /* R20542 - DACR_RETUNE_C32_1 */
+       [20543] = 0x0000,     /* R20543 - DACR_RETUNE_C32_0 */
+
+       [20992] = 0x008C,     /* R20992 - VSS_XHD2_1 */
+       [20993] = 0x0200,     /* R20993 - VSS_XHD2_0 */
+       [20994] = 0x0035,     /* R20994 - VSS_XHD3_1 */
+       [20995] = 0x0700,     /* R20995 - VSS_XHD3_0 */
+       [20996] = 0x003A,     /* R20996 - VSS_XHN1_1 */
+       [20997] = 0x4100,     /* R20997 - VSS_XHN1_0 */
+       [20998] = 0x008B,     /* R20998 - VSS_XHN2_1 */
+       [20999] = 0x7D00,     /* R20999 - VSS_XHN2_0 */
+       [21000] = 0x003A,     /* R21000 - VSS_XHN3_1 */
+       [21001] = 0x4100,     /* R21001 - VSS_XHN3_0 */
+       [21002] = 0x008C,     /* R21002 - VSS_XLA_1 */
+       [21003] = 0xFEE8,     /* R21003 - VSS_XLA_0 */
+       [21004] = 0x0078,     /* R21004 - VSS_XLB_1 */
+       [21005] = 0x0000,     /* R21005 - VSS_XLB_0 */
+       [21006] = 0x003F,     /* R21006 - VSS_XLG_1 */
+       [21007] = 0xB260,     /* R21007 - VSS_XLG_0 */
+       [21008] = 0x002D,     /* R21008 - VSS_PG2_1 */
+       [21009] = 0x1818,     /* R21009 - VSS_PG2_0 */
+       [21010] = 0x0020,     /* R21010 - VSS_PG_1 */
+       [21011] = 0x0000,     /* R21011 - VSS_PG_0 */
+       [21012] = 0x00F1,     /* R21012 - VSS_XTD1_1 */
+       [21013] = 0x8340,     /* R21013 - VSS_XTD1_0 */
+       [21014] = 0x00FB,     /* R21014 - VSS_XTD2_1 */
+       [21015] = 0x8300,     /* R21015 - VSS_XTD2_0 */
+       [21016] = 0x00EE,     /* R21016 - VSS_XTD3_1 */
+       [21017] = 0xAEC0,     /* R21017 - VSS_XTD3_0 */
+       [21018] = 0x00FB,     /* R21018 - VSS_XTD4_1 */
+       [21019] = 0xAC40,     /* R21019 - VSS_XTD4_0 */
+       [21020] = 0x00F1,     /* R21020 - VSS_XTD5_1 */
+       [21021] = 0x7F80,     /* R21021 - VSS_XTD5_0 */
+       [21022] = 0x00F4,     /* R21022 - VSS_XTD6_1 */
+       [21023] = 0x3B40,     /* R21023 - VSS_XTD6_0 */
+       [21024] = 0x00F5,     /* R21024 - VSS_XTD7_1 */
+       [21025] = 0xFB00,     /* R21025 - VSS_XTD7_0 */
+       [21026] = 0x00EA,     /* R21026 - VSS_XTD8_1 */
+       [21027] = 0x10C0,     /* R21027 - VSS_XTD8_0 */
+       [21028] = 0x00FC,     /* R21028 - VSS_XTD9_1 */
+       [21029] = 0xC580,     /* R21029 - VSS_XTD9_0 */
+       [21030] = 0x00E2,     /* R21030 - VSS_XTD10_1 */
+       [21031] = 0x75C0,     /* R21031 - VSS_XTD10_0 */
+       [21032] = 0x0004,     /* R21032 - VSS_XTD11_1 */
+       [21033] = 0xB480,     /* R21033 - VSS_XTD11_0 */
+       [21034] = 0x00D4,     /* R21034 - VSS_XTD12_1 */
+       [21035] = 0xF980,     /* R21035 - VSS_XTD12_0 */
+       [21036] = 0x0004,     /* R21036 - VSS_XTD13_1 */
+       [21037] = 0x9140,     /* R21037 - VSS_XTD13_0 */
+       [21038] = 0x00D8,     /* R21038 - VSS_XTD14_1 */
+       [21039] = 0xA480,     /* R21039 - VSS_XTD14_0 */
+       [21040] = 0x0002,     /* R21040 - VSS_XTD15_1 */
+       [21041] = 0x3DC0,     /* R21041 - VSS_XTD15_0 */
+       [21042] = 0x00CF,     /* R21042 - VSS_XTD16_1 */
+       [21043] = 0x7A80,     /* R21043 - VSS_XTD16_0 */
+       [21044] = 0x00DC,     /* R21044 - VSS_XTD17_1 */
+       [21045] = 0x0600,     /* R21045 - VSS_XTD17_0 */
+       [21046] = 0x00F2,     /* R21046 - VSS_XTD18_1 */
+       [21047] = 0xDAC0,     /* R21047 - VSS_XTD18_0 */
+       [21048] = 0x00BA,     /* R21048 - VSS_XTD19_1 */
+       [21049] = 0xF340,     /* R21049 - VSS_XTD19_0 */
+       [21050] = 0x000A,     /* R21050 - VSS_XTD20_1 */
+       [21051] = 0x7940,     /* R21051 - VSS_XTD20_0 */
+       [21052] = 0x001C,     /* R21052 - VSS_XTD21_1 */
+       [21053] = 0x0680,     /* R21053 - VSS_XTD21_0 */
+       [21054] = 0x00FD,     /* R21054 - VSS_XTD22_1 */
+       [21055] = 0x2D00,     /* R21055 - VSS_XTD22_0 */
+       [21056] = 0x001C,     /* R21056 - VSS_XTD23_1 */
+       [21057] = 0xE840,     /* R21057 - VSS_XTD23_0 */
+       [21058] = 0x000D,     /* R21058 - VSS_XTD24_1 */
+       [21059] = 0xDC40,     /* R21059 - VSS_XTD24_0 */
+       [21060] = 0x00FC,     /* R21060 - VSS_XTD25_1 */
+       [21061] = 0x9D00,     /* R21061 - VSS_XTD25_0 */
+       [21062] = 0x0009,     /* R21062 - VSS_XTD26_1 */
+       [21063] = 0x5580,     /* R21063 - VSS_XTD26_0 */
+       [21064] = 0x00FE,     /* R21064 - VSS_XTD27_1 */
+       [21065] = 0x7E80,     /* R21065 - VSS_XTD27_0 */
+       [21066] = 0x000E,     /* R21066 - VSS_XTD28_1 */
+       [21067] = 0xAB40,     /* R21067 - VSS_XTD28_0 */
+       [21068] = 0x00F9,     /* R21068 - VSS_XTD29_1 */
+       [21069] = 0x9880,     /* R21069 - VSS_XTD29_0 */
+       [21070] = 0x0009,     /* R21070 - VSS_XTD30_1 */
+       [21071] = 0x87C0,     /* R21071 - VSS_XTD30_0 */
+       [21072] = 0x00FD,     /* R21072 - VSS_XTD31_1 */
+       [21073] = 0x2C40,     /* R21073 - VSS_XTD31_0 */
+       [21074] = 0x0009,     /* R21074 - VSS_XTD32_1 */
+       [21075] = 0x4800,     /* R21075 - VSS_XTD32_0 */
+       [21076] = 0x0003,     /* R21076 - VSS_XTS1_1 */
+       [21077] = 0x5F40,     /* R21077 - VSS_XTS1_0 */
+       [21078] = 0x0000,     /* R21078 - VSS_XTS2_1 */
+       [21079] = 0x8700,     /* R21079 - VSS_XTS2_0 */
+       [21080] = 0x00FA,     /* R21080 - VSS_XTS3_1 */
+       [21081] = 0xE4C0,     /* R21081 - VSS_XTS3_0 */
+       [21082] = 0x0000,     /* R21082 - VSS_XTS4_1 */
+       [21083] = 0x0B40,     /* R21083 - VSS_XTS4_0 */
+       [21084] = 0x0004,     /* R21084 - VSS_XTS5_1 */
+       [21085] = 0xE180,     /* R21085 - VSS_XTS5_0 */
+       [21086] = 0x0001,     /* R21086 - VSS_XTS6_1 */
+       [21087] = 0x1F40,     /* R21087 - VSS_XTS6_0 */
+       [21088] = 0x00F8,     /* R21088 - VSS_XTS7_1 */
+       [21089] = 0xB000,     /* R21089 - VSS_XTS7_0 */
+       [21090] = 0x00FB,     /* R21090 - VSS_XTS8_1 */
+       [21091] = 0xCBC0,     /* R21091 - VSS_XTS8_0 */
+       [21092] = 0x0004,     /* R21092 - VSS_XTS9_1 */
+       [21093] = 0xF380,     /* R21093 - VSS_XTS9_0 */
+       [21094] = 0x0007,     /* R21094 - VSS_XTS10_1 */
+       [21095] = 0xDF40,     /* R21095 - VSS_XTS10_0 */
+       [21096] = 0x00FF,     /* R21096 - VSS_XTS11_1 */
+       [21097] = 0x0700,     /* R21097 - VSS_XTS11_0 */
+       [21098] = 0x00EF,     /* R21098 - VSS_XTS12_1 */
+       [21099] = 0xD700,     /* R21099 - VSS_XTS12_0 */
+       [21100] = 0x00FB,     /* R21100 - VSS_XTS13_1 */
+       [21101] = 0xAF40,     /* R21101 - VSS_XTS13_0 */
+       [21102] = 0x0010,     /* R21102 - VSS_XTS14_1 */
+       [21103] = 0x8A80,     /* R21103 - VSS_XTS14_0 */
+       [21104] = 0x0011,     /* R21104 - VSS_XTS15_1 */
+       [21105] = 0x07C0,     /* R21105 - VSS_XTS15_0 */
+       [21106] = 0x00E0,     /* R21106 - VSS_XTS16_1 */
+       [21107] = 0x0800,     /* R21107 - VSS_XTS16_0 */
+       [21108] = 0x00D2,     /* R21108 - VSS_XTS17_1 */
+       [21109] = 0x7600,     /* R21109 - VSS_XTS17_0 */
+       [21110] = 0x0020,     /* R21110 - VSS_XTS18_1 */
+       [21111] = 0xCF40,     /* R21111 - VSS_XTS18_0 */
+       [21112] = 0x0030,     /* R21112 - VSS_XTS19_1 */
+       [21113] = 0x2340,     /* R21113 - VSS_XTS19_0 */
+       [21114] = 0x00FD,     /* R21114 - VSS_XTS20_1 */
+       [21115] = 0x69C0,     /* R21115 - VSS_XTS20_0 */
+       [21116] = 0x0028,     /* R21116 - VSS_XTS21_1 */
+       [21117] = 0x3500,     /* R21117 - VSS_XTS21_0 */
+       [21118] = 0x0006,     /* R21118 - VSS_XTS22_1 */
+       [21119] = 0x3300,     /* R21119 - VSS_XTS22_0 */
+       [21120] = 0x00D9,     /* R21120 - VSS_XTS23_1 */
+       [21121] = 0xF6C0,     /* R21121 - VSS_XTS23_0 */
+       [21122] = 0x00F3,     /* R21122 - VSS_XTS24_1 */
+       [21123] = 0x3340,     /* R21123 - VSS_XTS24_0 */
+       [21124] = 0x000F,     /* R21124 - VSS_XTS25_1 */
+       [21125] = 0x4200,     /* R21125 - VSS_XTS25_0 */
+       [21126] = 0x0004,     /* R21126 - VSS_XTS26_1 */
+       [21127] = 0x0C80,     /* R21127 - VSS_XTS26_0 */
+       [21128] = 0x00FB,     /* R21128 - VSS_XTS27_1 */
+       [21129] = 0x3F80,     /* R21129 - VSS_XTS27_0 */
+       [21130] = 0x00F7,     /* R21130 - VSS_XTS28_1 */
+       [21131] = 0x57C0,     /* R21131 - VSS_XTS28_0 */
+       [21132] = 0x0003,     /* R21132 - VSS_XTS29_1 */
+       [21133] = 0x5400,     /* R21133 - VSS_XTS29_0 */
+       [21134] = 0x0000,     /* R21134 - VSS_XTS30_1 */
+       [21135] = 0xC6C0,     /* R21135 - VSS_XTS30_0 */
+       [21136] = 0x0003,     /* R21136 - VSS_XTS31_1 */
+       [21137] = 0x12C0,     /* R21137 - VSS_XTS31_0 */
+       [21138] = 0x00FD,     /* R21138 - VSS_XTS32_1 */
+       [21139] = 0x8580,     /* R21139 - VSS_XTS32_0 */
+};
+
+static const struct wm8962_reg_access {
+       u16 read;
+       u16 write;
+       u16 vol;
+} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
+       [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0     - Left Input volume */
+       [1] = { 0xFEFF, 0x01FF, 0xFFFF }, /* R1     - Right Input volume */
+       [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2     - HPOUTL volume */
+       [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3     - HPOUTR volume */
+       [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4     - Clocking1 */
+       [5] = { 0x007F, 0x007F, 0x0000 }, /* R5     - ADC & DAC Control 1 */
+       [6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6     - ADC & DAC Control 2 */
+       [7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7     - Audio Interface 0 */
+       [8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8     - Clocking2 */
+       [9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9     - Audio Interface 1 */
+       [10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10    - Left DAC volume */
+       [11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11    - Right DAC volume */
+       [14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14    - Audio Interface 2 */
+       [15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15    - Software Reset */
+       [17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17    - ALC1 */
+       [18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18    - ALC2 */
+       [19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19    - ALC3 */
+       [20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20    - Noise Gate */
+       [21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21    - Left ADC volume */
+       [22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22    - Right ADC volume */
+       [23] = { 0x0161, 0x0161, 0x0000 }, /* R23    - Additional control(1) */
+       [24] = { 0x0008, 0x0008, 0x0000 }, /* R24    - Additional control(2) */
+       [25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25    - Pwr Mgmt (1) */
+       [26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26    - Pwr Mgmt (2) */
+       [27] = { 0x0017, 0x0017, 0x0000 }, /* R27    - Additional Control (3) */
+       [28] = { 0x001C, 0x001C, 0x0000 }, /* R28    - Anti-pop */
+
+       [30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30    - Clocking 3 */
+       [31] = { 0x000F, 0x000F, 0x0000 }, /* R31    - Input mixer control (1) */
+       [32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32    - Left input mixer volume */
+       [33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33    - Right input mixer volume */
+       [34] = { 0x003F, 0x003F, 0x0000 }, /* R34    - Input mixer control (2) */
+       [35] = { 0x003F, 0x003F, 0x0000 }, /* R35    - Input bias control */
+       [37] = { 0x001F, 0x001F, 0x0000 }, /* R37    - Left input PGA control */
+       [38] = { 0x001F, 0x001F, 0x0000 }, /* R38    - Right input PGA control */
+       [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40    - SPKOUTL volume */
+       [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41    - SPKOUTR volume */
+
+       [47] = { 0x000F, 0x0000, 0x0000 }, /* R47    - Thermal Shutdown Status */
+       [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48    - Additional Control (4) */
+       [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49    - Class D Control 1 */
+       [51] = { 0x0047, 0x0047, 0x0000 }, /* R51    - Class D Control 2 */
+       [56] = { 0x001E, 0x001E, 0x0000 }, /* R56    - Clocking 4 */
+       [57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57    - DAC DSP Mixing (1) */
+       [58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58    - DAC DSP Mixing (2) */
+       [60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60    - DC Servo 0 */
+       [61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61    - DC Servo 1 */
+       [64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64    - DC Servo 4 */
+       [66] = { 0x0780, 0x0000, 0xFFFF }, /* R66    - DC Servo 6 */
+       [68] = { 0x0007, 0x0007, 0x0000 }, /* R68    - Analogue PGA Bias */
+       [69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69    - Analogue HP 0 */
+       [71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71    - Analogue HP 2 */
+       [72] = { 0x0001, 0x0001, 0x0000 }, /* R72    - Charge Pump 1 */
+       [82] = { 0x0001, 0x0001, 0x0000 }, /* R82    - Charge Pump B */
+       [87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87    - Write Sequencer Control 1 */
+       [90] = { 0x007F, 0x01FF, 0x0000 }, /* R90    - Write Sequencer Control 2 */
+       [93] = { 0x03F9, 0x0000, 0x0000 }, /* R93    - Write Sequencer Control 3 */
+       [94] = { 0x0070, 0x0070, 0x0000 }, /* R94    - Control Interface */
+       [99] = { 0x000F, 0x000F, 0x0000 }, /* R99    - Mixer Enables */
+       [100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100   - Headphone Mixer (1) */
+       [101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101   - Headphone Mixer (2) */
+       [102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102   - Headphone Mixer (3) */
+       [103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103   - Headphone Mixer (4) */
+       [105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105   - Speaker Mixer (1) */
+       [106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106   - Speaker Mixer (2) */
+       [107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107   - Speaker Mixer (3) */
+       [108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108   - Speaker Mixer (4) */
+       [109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109   - Speaker Mixer (5) */
+       [110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110   - Beep Generator (1) */
+       [115] = { 0x001F, 0x001F, 0x0000 }, /* R115   - Oscillator Trim (3) */
+       [116] = { 0x001F, 0x001F, 0x0000 }, /* R116   - Oscillator Trim (4) */
+       [119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119   - Oscillator Trim (7) */
+       [124] = { 0x0079, 0x0079, 0x0000 }, /* R124   - Analogue Clocking1 */
+       [125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125   - Analogue Clocking2 */
+       [126] = { 0x000D, 0x000D, 0x0000 }, /* R126   - Analogue Clocking3 */
+       [127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127   - PLL Software Reset */
+       [129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129   - PLL2 */
+       [131] = { 0x0003, 0x0003, 0x0000 }, /* R131   - PLL 4 */
+       [136] = { 0x005F, 0x005F, 0x0000 }, /* R136   - PLL 9 */
+       [137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137   - PLL 10 */
+       [138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138   - PLL 11 */
+       [139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139   - PLL 12 */
+       [140] = { 0x005F, 0x005F, 0x0000 }, /* R140   - PLL 13 */
+       [141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141   - PLL 14 */
+       [142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142   - PLL 15 */
+       [143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143   - PLL 16 */
+       [155] = { 0x0067, 0x0067, 0x0000 }, /* R155   - FLL Control (1) */
+       [156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156   - FLL Control (2) */
+       [157] = { 0x0007, 0x0007, 0x0000 }, /* R157   - FLL Control (3) */
+       [159] = { 0x007F, 0x007F, 0x0000 }, /* R159   - FLL Control (5) */
+       [160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160   - FLL Control (6) */
+       [161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161   - FLL Control (7) */
+       [162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162   - FLL Control (8) */
+       [252] = { 0x0005, 0x0005, 0x0000 }, /* R252   - General test 1 */
+       [256] = { 0x000F, 0x000F, 0x0000 }, /* R256   - DF1 */
+       [257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257   - DF2 */
+       [258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258   - DF3 */
+       [259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259   - DF4 */
+       [260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260   - DF5 */
+       [261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261   - DF6 */
+       [262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262   - DF7 */
+       [264] = { 0x0003, 0x0003, 0x0000 }, /* R264   - LHPF1 */
+       [265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265   - LHPF2 */
+       [268] = { 0x0077, 0x0077, 0x0000 }, /* R268   - THREED1 */
+       [269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269   - THREED2 */
+       [270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270   - THREED3 */
+       [271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271   - THREED4 */
+       [276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276   - DRC 1 */
+       [277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277   - DRC 2 */
+       [278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278   - DRC 3 */
+       [279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279   - DRC 4 */
+       [280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280   - DRC 5 */
+       [285] = { 0x0003, 0x0003, 0x0000 }, /* R285   - Tloopback */
+       [335] = { 0x0007, 0x0007, 0x0000 }, /* R335   - EQ1 */
+       [336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336   - EQ2 */
+       [337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337   - EQ3 */
+       [338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338   - EQ4 */
+       [339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339   - EQ5 */
+       [340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340   - EQ6 */
+       [341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341   - EQ7 */
+       [342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342   - EQ8 */
+       [343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343   - EQ9 */
+       [344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344   - EQ10 */
+       [345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345   - EQ11 */
+       [346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346   - EQ12 */
+       [347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347   - EQ13 */
+       [348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348   - EQ14 */
+       [349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349   - EQ15 */
+       [350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350   - EQ16 */
+       [351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351   - EQ17 */
+       [352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352   - EQ18 */
+       [353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353   - EQ19 */
+       [354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354   - EQ20 */
+       [355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355   - EQ21 */
+       [356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356   - EQ22 */
+       [357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357   - EQ23 */
+       [358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358   - EQ24 */
+       [359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359   - EQ25 */
+       [360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360   - EQ26 */
+       [361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361   - EQ27 */
+       [362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362   - EQ28 */
+       [363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363   - EQ29 */
+       [364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364   - EQ30 */
+       [365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365   - EQ31 */
+       [366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366   - EQ32 */
+       [367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367   - EQ33 */
+       [368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368   - EQ34 */
+       [369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369   - EQ35 */
+       [370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370   - EQ36 */
+       [371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371   - EQ37 */
+       [372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372   - EQ38 */
+       [373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373   - EQ39 */
+       [374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374   - EQ40 */
+       [375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375   - EQ41 */
+       [513] = { 0x045F, 0x045F, 0x0000 }, /* R513   - GPIO 2 */
+       [514] = { 0x045F, 0x045F, 0x0000 }, /* R514   - GPIO 3 */
+       [516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516   - GPIO 5 */
+       [517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517   - GPIO 6 */
+       [560] = { 0x0030, 0x0030, 0xFFFF }, /* R560   - Interrupt Status 1 */
+       [561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561   - Interrupt Status 2 */
+       [568] = { 0x0030, 0x0030, 0x0000 }, /* R568   - Interrupt Status 1 Mask */
+       [569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569   - Interrupt Status 2 Mask */
+       [576] = { 0x0001, 0x0001, 0x0000 }, /* R576   - Interrupt Control */
+       [584] = { 0x002D, 0x002D, 0x0000 }, /* R584   - IRQ Debounce */
+       [586] = { 0xC000, 0xC000, 0x0000 }, /* R586   -  MICINT Source Pol */
+       [768] = { 0x0001, 0x0001, 0x0000 }, /* R768   - DSP2 Power Management */
+       [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037  - DSP2_ExecControl */
+       [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096  - Write Sequencer 0 */
+       [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097  - Write Sequencer 1 */
+       [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098  - Write Sequencer 2 */
+       [4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099  - Write Sequencer 3 */
+       [4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100  - Write Sequencer 4 */
+       [4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101  - Write Sequencer 5 */
+       [4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102  - Write Sequencer 6 */
+       [4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103  - Write Sequencer 7 */
+       [4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104  - Write Sequencer 8 */
+       [4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105  - Write Sequencer 9 */
+       [4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106  - Write Sequencer 10 */
+       [4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107  - Write Sequencer 11 */
+       [4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108  - Write Sequencer 12 */
+       [4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109  - Write Sequencer 13 */
+       [4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110  - Write Sequencer 14 */
+       [4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111  - Write Sequencer 15 */
+       [4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112  - Write Sequencer 16 */
+       [4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113  - Write Sequencer 17 */
+       [4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114  - Write Sequencer 18 */
+       [4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115  - Write Sequencer 19 */
+       [4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116  - Write Sequencer 20 */
+       [4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117  - Write Sequencer 21 */
+       [4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118  - Write Sequencer 22 */
+       [4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119  - Write Sequencer 23 */
+       [4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120  - Write Sequencer 24 */
+       [4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121  - Write Sequencer 25 */
+       [4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122  - Write Sequencer 26 */
+       [4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123  - Write Sequencer 27 */
+       [4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124  - Write Sequencer 28 */
+       [4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125  - Write Sequencer 29 */
+       [4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126  - Write Sequencer 30 */
+       [4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127  - Write Sequencer 31 */
+       [4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128  - Write Sequencer 32 */
+       [4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129  - Write Sequencer 33 */
+       [4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130  - Write Sequencer 34 */
+       [4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131  - Write Sequencer 35 */
+       [4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132  - Write Sequencer 36 */
+       [4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133  - Write Sequencer 37 */
+       [4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134  - Write Sequencer 38 */
+       [4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135  - Write Sequencer 39 */
+       [4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136  - Write Sequencer 40 */
+       [4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137  - Write Sequencer 41 */
+       [4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138  - Write Sequencer 42 */
+       [4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139  - Write Sequencer 43 */
+       [4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140  - Write Sequencer 44 */
+       [4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141  - Write Sequencer 45 */
+       [4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142  - Write Sequencer 46 */
+       [4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143  - Write Sequencer 47 */
+       [4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144  - Write Sequencer 48 */
+       [4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145  - Write Sequencer 49 */
+       [4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146  - Write Sequencer 50 */
+       [4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147  - Write Sequencer 51 */
+       [4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148  - Write Sequencer 52 */
+       [4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149  - Write Sequencer 53 */
+       [4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150  - Write Sequencer 54 */
+       [4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151  - Write Sequencer 55 */
+       [4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152  - Write Sequencer 56 */
+       [4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153  - Write Sequencer 57 */
+       [4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154  - Write Sequencer 58 */
+       [4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155  - Write Sequencer 59 */
+       [4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156  - Write Sequencer 60 */
+       [4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157  - Write Sequencer 61 */
+       [4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158  - Write Sequencer 62 */
+       [4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159  - Write Sequencer 63 */
+       [4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160  - Write Sequencer 64 */
+       [4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161  - Write Sequencer 65 */
+       [4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162  - Write Sequencer 66 */
+       [4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163  - Write Sequencer 67 */
+       [4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164  - Write Sequencer 68 */
+       [4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165  - Write Sequencer 69 */
+       [4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166  - Write Sequencer 70 */
+       [4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167  - Write Sequencer 71 */
+       [4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168  - Write Sequencer 72 */
+       [4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169  - Write Sequencer 73 */
+       [4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170  - Write Sequencer 74 */
+       [4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171  - Write Sequencer 75 */
+       [4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172  - Write Sequencer 76 */
+       [4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173  - Write Sequencer 77 */
+       [4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174  - Write Sequencer 78 */
+       [4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175  - Write Sequencer 79 */
+       [4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176  - Write Sequencer 80 */
+       [4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177  - Write Sequencer 81 */
+       [4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178  - Write Sequencer 82 */
+       [4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179  - Write Sequencer 83 */
+       [4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180  - Write Sequencer 84 */
+       [4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181  - Write Sequencer 85 */
+       [4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182  - Write Sequencer 86 */
+       [4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183  - Write Sequencer 87 */
+       [4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184  - Write Sequencer 88 */
+       [4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185  - Write Sequencer 89 */
+       [4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186  - Write Sequencer 90 */
+       [4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187  - Write Sequencer 91 */
+       [4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188  - Write Sequencer 92 */
+       [4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189  - Write Sequencer 93 */
+       [4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190  - Write Sequencer 94 */
+       [4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191  - Write Sequencer 95 */
+       [4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192  - Write Sequencer 96 */
+       [4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193  - Write Sequencer 97 */
+       [4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194  - Write Sequencer 98 */
+       [4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195  - Write Sequencer 99 */
+       [4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196  - Write Sequencer 100 */
+       [4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197  - Write Sequencer 101 */
+       [4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198  - Write Sequencer 102 */
+       [4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199  - Write Sequencer 103 */
+       [4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200  - Write Sequencer 104 */
+       [4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201  - Write Sequencer 105 */
+       [4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202  - Write Sequencer 106 */
+       [4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203  - Write Sequencer 107 */
+       [4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204  - Write Sequencer 108 */
+       [4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205  - Write Sequencer 109 */
+       [4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206  - Write Sequencer 110 */
+       [4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207  - Write Sequencer 111 */
+       [4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208  - Write Sequencer 112 */
+       [4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209  - Write Sequencer 113 */
+       [4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210  - Write Sequencer 114 */
+       [4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211  - Write Sequencer 115 */
+       [4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212  - Write Sequencer 116 */
+       [4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213  - Write Sequencer 117 */
+       [4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214  - Write Sequencer 118 */
+       [4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215  - Write Sequencer 119 */
+       [4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216  - Write Sequencer 120 */
+       [4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217  - Write Sequencer 121 */
+       [4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218  - Write Sequencer 122 */
+       [4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219  - Write Sequencer 123 */
+       [4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220  - Write Sequencer 124 */
+       [4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221  - Write Sequencer 125 */
+       [4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222  - Write Sequencer 126 */
+       [4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223  - Write Sequencer 127 */
+       [4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224  - Write Sequencer 128 */
+       [4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225  - Write Sequencer 129 */
+       [4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226  - Write Sequencer 130 */
+       [4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227  - Write Sequencer 131 */
+       [4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228  - Write Sequencer 132 */
+       [4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229  - Write Sequencer 133 */
+       [4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230  - Write Sequencer 134 */
+       [4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231  - Write Sequencer 135 */
+       [4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232  - Write Sequencer 136 */
+       [4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233  - Write Sequencer 137 */
+       [4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234  - Write Sequencer 138 */
+       [4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235  - Write Sequencer 139 */
+       [4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236  - Write Sequencer 140 */
+       [4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237  - Write Sequencer 141 */
+       [4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238  - Write Sequencer 142 */
+       [4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239  - Write Sequencer 143 */
+       [4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240  - Write Sequencer 144 */
+       [4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241  - Write Sequencer 145 */
+       [4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242  - Write Sequencer 146 */
+       [4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243  - Write Sequencer 147 */
+       [4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244  - Write Sequencer 148 */
+       [4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245  - Write Sequencer 149 */
+       [4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246  - Write Sequencer 150 */
+       [4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247  - Write Sequencer 151 */
+       [4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248  - Write Sequencer 152 */
+       [4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249  - Write Sequencer 153 */
+       [4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250  - Write Sequencer 154 */
+       [4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251  - Write Sequencer 155 */
+       [4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252  - Write Sequencer 156 */
+       [4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253  - Write Sequencer 157 */
+       [4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254  - Write Sequencer 158 */
+       [4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255  - Write Sequencer 159 */
+       [4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256  - Write Sequencer 160 */
+       [4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257  - Write Sequencer 161 */
+       [4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258  - Write Sequencer 162 */
+       [4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259  - Write Sequencer 163 */
+       [4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260  - Write Sequencer 164 */
+       [4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261  - Write Sequencer 165 */
+       [4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262  - Write Sequencer 166 */
+       [4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263  - Write Sequencer 167 */
+       [4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264  - Write Sequencer 168 */
+       [4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265  - Write Sequencer 169 */
+       [4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266  - Write Sequencer 170 */
+       [4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267  - Write Sequencer 171 */
+       [4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268  - Write Sequencer 172 */
+       [4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269  - Write Sequencer 173 */
+       [4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270  - Write Sequencer 174 */
+       [4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271  - Write Sequencer 175 */
+       [4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272  - Write Sequencer 176 */
+       [4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273  - Write Sequencer 177 */
+       [4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274  - Write Sequencer 178 */
+       [4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275  - Write Sequencer 179 */
+       [4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276  - Write Sequencer 180 */
+       [4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277  - Write Sequencer 181 */
+       [4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278  - Write Sequencer 182 */
+       [4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279  - Write Sequencer 183 */
+       [4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280  - Write Sequencer 184 */
+       [4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281  - Write Sequencer 185 */
+       [4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282  - Write Sequencer 186 */
+       [4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283  - Write Sequencer 187 */
+       [4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284  - Write Sequencer 188 */
+       [4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285  - Write Sequencer 189 */
+       [4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286  - Write Sequencer 190 */
+       [4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287  - Write Sequencer 191 */
+       [4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288  - Write Sequencer 192 */
+       [4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289  - Write Sequencer 193 */
+       [4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290  - Write Sequencer 194 */
+       [4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291  - Write Sequencer 195 */
+       [4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292  - Write Sequencer 196 */
+       [4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293  - Write Sequencer 197 */
+       [4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294  - Write Sequencer 198 */
+       [4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295  - Write Sequencer 199 */
+       [4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296  - Write Sequencer 200 */
+       [4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297  - Write Sequencer 201 */
+       [4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298  - Write Sequencer 202 */
+       [4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299  - Write Sequencer 203 */
+       [4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300  - Write Sequencer 204 */
+       [4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301  - Write Sequencer 205 */
+       [4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302  - Write Sequencer 206 */
+       [4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303  - Write Sequencer 207 */
+       [4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304  - Write Sequencer 208 */
+       [4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305  - Write Sequencer 209 */
+       [4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306  - Write Sequencer 210 */
+       [4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307  - Write Sequencer 211 */
+       [4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308  - Write Sequencer 212 */
+       [4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309  - Write Sequencer 213 */
+       [4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310  - Write Sequencer 214 */
+       [4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311  - Write Sequencer 215 */
+       [4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312  - Write Sequencer 216 */
+       [4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313  - Write Sequencer 217 */
+       [4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314  - Write Sequencer 218 */
+       [4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315  - Write Sequencer 219 */
+       [4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316  - Write Sequencer 220 */
+       [4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317  - Write Sequencer 221 */
+       [4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318  - Write Sequencer 222 */
+       [4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319  - Write Sequencer 223 */
+       [4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320  - Write Sequencer 224 */
+       [4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321  - Write Sequencer 225 */
+       [4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322  - Write Sequencer 226 */
+       [4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323  - Write Sequencer 227 */
+       [4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324  - Write Sequencer 228 */
+       [4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325  - Write Sequencer 229 */
+       [4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326  - Write Sequencer 230 */
+       [4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327  - Write Sequencer 231 */
+       [4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328  - Write Sequencer 232 */
+       [4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329  - Write Sequencer 233 */
+       [4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330  - Write Sequencer 234 */
+       [4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331  - Write Sequencer 235 */
+       [4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332  - Write Sequencer 236 */
+       [4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333  - Write Sequencer 237 */
+       [4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334  - Write Sequencer 238 */
+       [4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335  - Write Sequencer 239 */
+       [4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336  - Write Sequencer 240 */
+       [4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337  - Write Sequencer 241 */
+       [4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338  - Write Sequencer 242 */
+       [4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339  - Write Sequencer 243 */
+       [4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340  - Write Sequencer 244 */
+       [4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341  - Write Sequencer 245 */
+       [4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342  - Write Sequencer 246 */
+       [4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343  - Write Sequencer 247 */
+       [4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344  - Write Sequencer 248 */
+       [4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345  - Write Sequencer 249 */
+       [4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346  - Write Sequencer 250 */
+       [4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347  - Write Sequencer 251 */
+       [4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348  - Write Sequencer 252 */
+       [4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349  - Write Sequencer 253 */
+       [4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350  - Write Sequencer 254 */
+       [4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351  - Write Sequencer 255 */
+       [4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352  - Write Sequencer 256 */
+       [4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353  - Write Sequencer 257 */
+       [4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354  - Write Sequencer 258 */
+       [4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355  - Write Sequencer 259 */
+       [4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356  - Write Sequencer 260 */
+       [4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357  - Write Sequencer 261 */
+       [4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358  - Write Sequencer 262 */
+       [4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359  - Write Sequencer 263 */
+       [4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360  - Write Sequencer 264 */
+       [4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361  - Write Sequencer 265 */
+       [4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362  - Write Sequencer 266 */
+       [4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363  - Write Sequencer 267 */
+       [4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364  - Write Sequencer 268 */
+       [4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365  - Write Sequencer 269 */
+       [4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366  - Write Sequencer 270 */
+       [4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367  - Write Sequencer 271 */
+       [4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368  - Write Sequencer 272 */
+       [4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369  - Write Sequencer 273 */
+       [4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370  - Write Sequencer 274 */
+       [4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371  - Write Sequencer 275 */
+       [4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372  - Write Sequencer 276 */
+       [4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373  - Write Sequencer 277 */
+       [4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374  - Write Sequencer 278 */
+       [4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375  - Write Sequencer 279 */
+       [4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376  - Write Sequencer 280 */
+       [4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377  - Write Sequencer 281 */
+       [4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378  - Write Sequencer 282 */
+       [4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379  - Write Sequencer 283 */
+       [4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380  - Write Sequencer 284 */
+       [4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381  - Write Sequencer 285 */
+       [4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382  - Write Sequencer 286 */
+       [4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383  - Write Sequencer 287 */
+       [4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384  - Write Sequencer 288 */
+       [4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385  - Write Sequencer 289 */
+       [4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386  - Write Sequencer 290 */
+       [4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387  - Write Sequencer 291 */
+       [4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388  - Write Sequencer 292 */
+       [4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389  - Write Sequencer 293 */
+       [4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390  - Write Sequencer 294 */
+       [4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391  - Write Sequencer 295 */
+       [4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392  - Write Sequencer 296 */
+       [4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393  - Write Sequencer 297 */
+       [4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394  - Write Sequencer 298 */
+       [4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395  - Write Sequencer 299 */
+       [4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396  - Write Sequencer 300 */
+       [4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397  - Write Sequencer 301 */
+       [4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398  - Write Sequencer 302 */
+       [4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399  - Write Sequencer 303 */
+       [4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400  - Write Sequencer 304 */
+       [4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401  - Write Sequencer 305 */
+       [4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402  - Write Sequencer 306 */
+       [4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403  - Write Sequencer 307 */
+       [4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404  - Write Sequencer 308 */
+       [4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405  - Write Sequencer 309 */
+       [4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406  - Write Sequencer 310 */
+       [4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407  - Write Sequencer 311 */
+       [4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408  - Write Sequencer 312 */
+       [4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409  - Write Sequencer 313 */
+       [4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410  - Write Sequencer 314 */
+       [4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411  - Write Sequencer 315 */
+       [4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412  - Write Sequencer 316 */
+       [4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413  - Write Sequencer 317 */
+       [4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414  - Write Sequencer 318 */
+       [4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415  - Write Sequencer 319 */
+       [4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416  - Write Sequencer 320 */
+       [4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417  - Write Sequencer 321 */
+       [4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418  - Write Sequencer 322 */
+       [4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419  - Write Sequencer 323 */
+       [4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420  - Write Sequencer 324 */
+       [4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421  - Write Sequencer 325 */
+       [4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422  - Write Sequencer 326 */
+       [4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423  - Write Sequencer 327 */
+       [4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424  - Write Sequencer 328 */
+       [4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425  - Write Sequencer 329 */
+       [4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426  - Write Sequencer 330 */
+       [4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427  - Write Sequencer 331 */
+       [4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428  - Write Sequencer 332 */
+       [4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429  - Write Sequencer 333 */
+       [4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430  - Write Sequencer 334 */
+       [4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431  - Write Sequencer 335 */
+       [4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432  - Write Sequencer 336 */
+       [4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433  - Write Sequencer 337 */
+       [4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434  - Write Sequencer 338 */
+       [4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435  - Write Sequencer 339 */
+       [4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436  - Write Sequencer 340 */
+       [4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437  - Write Sequencer 341 */
+       [4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438  - Write Sequencer 342 */
+       [4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439  - Write Sequencer 343 */
+       [4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440  - Write Sequencer 344 */
+       [4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441  - Write Sequencer 345 */
+       [4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442  - Write Sequencer 346 */
+       [4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443  - Write Sequencer 347 */
+       [4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444  - Write Sequencer 348 */
+       [4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445  - Write Sequencer 349 */
+       [4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446  - Write Sequencer 350 */
+       [4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447  - Write Sequencer 351 */
+       [4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448  - Write Sequencer 352 */
+       [4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449  - Write Sequencer 353 */
+       [4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450  - Write Sequencer 354 */
+       [4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451  - Write Sequencer 355 */
+       [4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452  - Write Sequencer 356 */
+       [4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453  - Write Sequencer 357 */
+       [4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454  - Write Sequencer 358 */
+       [4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455  - Write Sequencer 359 */
+       [4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456  - Write Sequencer 360 */
+       [4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457  - Write Sequencer 361 */
+       [4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458  - Write Sequencer 362 */
+       [4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459  - Write Sequencer 363 */
+       [4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460  - Write Sequencer 364 */
+       [4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461  - Write Sequencer 365 */
+       [4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462  - Write Sequencer 366 */
+       [4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463  - Write Sequencer 367 */
+       [4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464  - Write Sequencer 368 */
+       [4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465  - Write Sequencer 369 */
+       [4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466  - Write Sequencer 370 */
+       [4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467  - Write Sequencer 371 */
+       [4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468  - Write Sequencer 372 */
+       [4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469  - Write Sequencer 373 */
+       [4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470  - Write Sequencer 374 */
+       [4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471  - Write Sequencer 375 */
+       [4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472  - Write Sequencer 376 */
+       [4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473  - Write Sequencer 377 */
+       [4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474  - Write Sequencer 378 */
+       [4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475  - Write Sequencer 379 */
+       [4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476  - Write Sequencer 380 */
+       [4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477  - Write Sequencer 381 */
+       [4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478  - Write Sequencer 382 */
+       [4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479  - Write Sequencer 383 */
+       [4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480  - Write Sequencer 384 */
+       [4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481  - Write Sequencer 385 */
+       [4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482  - Write Sequencer 386 */
+       [4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483  - Write Sequencer 387 */
+       [4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484  - Write Sequencer 388 */
+       [4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485  - Write Sequencer 389 */
+       [4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486  - Write Sequencer 390 */
+       [4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487  - Write Sequencer 391 */
+       [4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488  - Write Sequencer 392 */
+       [4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489  - Write Sequencer 393 */
+       [4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490  - Write Sequencer 394 */
+       [4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491  - Write Sequencer 395 */
+       [4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492  - Write Sequencer 396 */
+       [4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493  - Write Sequencer 397 */
+       [4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494  - Write Sequencer 398 */
+       [4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495  - Write Sequencer 399 */
+       [4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496  - Write Sequencer 400 */
+       [4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497  - Write Sequencer 401 */
+       [4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498  - Write Sequencer 402 */
+       [4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499  - Write Sequencer 403 */
+       [4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500  - Write Sequencer 404 */
+       [4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501  - Write Sequencer 405 */
+       [4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502  - Write Sequencer 406 */
+       [4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503  - Write Sequencer 407 */
+       [4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504  - Write Sequencer 408 */
+       [4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505  - Write Sequencer 409 */
+       [4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506  - Write Sequencer 410 */
+       [4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507  - Write Sequencer 411 */
+       [4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508  - Write Sequencer 412 */
+       [4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509  - Write Sequencer 413 */
+       [4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510  - Write Sequencer 414 */
+       [4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511  - Write Sequencer 415 */
+       [4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512  - Write Sequencer 416 */
+       [4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513  - Write Sequencer 417 */
+       [4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514  - Write Sequencer 418 */
+       [4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515  - Write Sequencer 419 */
+       [4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516  - Write Sequencer 420 */
+       [4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517  - Write Sequencer 421 */
+       [4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518  - Write Sequencer 422 */
+       [4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519  - Write Sequencer 423 */
+       [4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520  - Write Sequencer 424 */
+       [4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521  - Write Sequencer 425 */
+       [4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522  - Write Sequencer 426 */
+       [4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523  - Write Sequencer 427 */
+       [4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524  - Write Sequencer 428 */
+       [4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525  - Write Sequencer 429 */
+       [4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526  - Write Sequencer 430 */
+       [4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527  - Write Sequencer 431 */
+       [4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528  - Write Sequencer 432 */
+       [4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529  - Write Sequencer 433 */
+       [4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530  - Write Sequencer 434 */
+       [4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531  - Write Sequencer 435 */
+       [4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532  - Write Sequencer 436 */
+       [4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533  - Write Sequencer 437 */
+       [4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534  - Write Sequencer 438 */
+       [4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535  - Write Sequencer 439 */
+       [4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536  - Write Sequencer 440 */
+       [4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537  - Write Sequencer 441 */
+       [4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538  - Write Sequencer 442 */
+       [4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539  - Write Sequencer 443 */
+       [4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540  - Write Sequencer 444 */
+       [4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541  - Write Sequencer 445 */
+       [4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542  - Write Sequencer 446 */
+       [4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543  - Write Sequencer 447 */
+       [4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544  - Write Sequencer 448 */
+       [4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545  - Write Sequencer 449 */
+       [4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546  - Write Sequencer 450 */
+       [4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547  - Write Sequencer 451 */
+       [4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548  - Write Sequencer 452 */
+       [4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549  - Write Sequencer 453 */
+       [4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550  - Write Sequencer 454 */
+       [4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551  - Write Sequencer 455 */
+       [4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552  - Write Sequencer 456 */
+       [4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553  - Write Sequencer 457 */
+       [4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554  - Write Sequencer 458 */
+       [4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555  - Write Sequencer 459 */
+       [4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556  - Write Sequencer 460 */
+       [4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557  - Write Sequencer 461 */
+       [4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558  - Write Sequencer 462 */
+       [4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559  - Write Sequencer 463 */
+       [4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560  - Write Sequencer 464 */
+       [4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561  - Write Sequencer 465 */
+       [4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562  - Write Sequencer 466 */
+       [4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563  - Write Sequencer 467 */
+       [4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564  - Write Sequencer 468 */
+       [4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565  - Write Sequencer 469 */
+       [4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566  - Write Sequencer 470 */
+       [4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567  - Write Sequencer 471 */
+       [4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568  - Write Sequencer 472 */
+       [4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569  - Write Sequencer 473 */
+       [4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570  - Write Sequencer 474 */
+       [4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571  - Write Sequencer 475 */
+       [4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572  - Write Sequencer 476 */
+       [4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573  - Write Sequencer 477 */
+       [4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574  - Write Sequencer 478 */
+       [4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575  - Write Sequencer 479 */
+       [4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576  - Write Sequencer 480 */
+       [4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577  - Write Sequencer 481 */
+       [4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578  - Write Sequencer 482 */
+       [4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579  - Write Sequencer 483 */
+       [4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580  - Write Sequencer 484 */
+       [4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581  - Write Sequencer 485 */
+       [4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582  - Write Sequencer 486 */
+       [4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583  - Write Sequencer 487 */
+       [4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584  - Write Sequencer 488 */
+       [4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585  - Write Sequencer 489 */
+       [4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586  - Write Sequencer 490 */
+       [4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587  - Write Sequencer 491 */
+       [4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588  - Write Sequencer 492 */
+       [4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589  - Write Sequencer 493 */
+       [4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590  - Write Sequencer 494 */
+       [4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591  - Write Sequencer 495 */
+       [4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592  - Write Sequencer 496 */
+       [4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593  - Write Sequencer 497 */
+       [4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594  - Write Sequencer 498 */
+       [4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595  - Write Sequencer 499 */
+       [4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596  - Write Sequencer 500 */
+       [4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597  - Write Sequencer 501 */
+       [4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598  - Write Sequencer 502 */
+       [4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599  - Write Sequencer 503 */
+       [4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600  - Write Sequencer 504 */
+       [4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601  - Write Sequencer 505 */
+       [4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602  - Write Sequencer 506 */
+       [4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603  - Write Sequencer 507 */
+       [4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604  - Write Sequencer 508 */
+       [4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605  - Write Sequencer 509 */
+       [4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606  - Write Sequencer 510 */
+       [4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607  - Write Sequencer 511 */
+       [8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192  - DSP2 Instruction RAM 0 */
+       [9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216  - DSP2 Address RAM 2 */
+       [9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217  - DSP2 Address RAM 1 */
+       [9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218  - DSP2 Address RAM 0 */
+       [12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */
+       [12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */
+       [13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */
+       [13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */
+       [14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */
+       [14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */
+       [15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */
+       [16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+       [16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+       [16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+       [16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+       [16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+       [16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+       [16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */
+       [16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */
+       [16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */
+       [16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */
+       [16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */
+       [16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */
+       [16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */
+       [16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */
+       [16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */
+       [16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */
+       [16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */
+       [16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */
+       [16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */
+       [16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */
+       [16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */
+       [16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */
+       [16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */
+       [16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */
+       [16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */
+       [16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */
+       [16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */
+       [16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */
+       [16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */
+       [16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */
+       [16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */
+       [16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */
+       [16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */
+       [16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */
+       [16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */
+       [16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */
+       [17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */
+       [17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */
+       [17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */
+       [17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */
+       [17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */
+       [17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */
+       [17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */
+       [17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */
+       [17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */
+       [17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */
+       [17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */
+       [17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */
+       [17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */
+       [17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */
+       [17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */
+       [17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */
+       [17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */
+       [17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */
+       [17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */
+       [17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */
+       [17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */
+       [17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */
+       [17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */
+       [17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */
+       [17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */
+       [17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */
+       [17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */
+       [17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */
+       [17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */
+       [17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */
+       [17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */
+       [17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */
+       [17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */
+       [17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */
+       [17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */
+       [17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */
+       [17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */
+       [17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */
+       [17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */
+       [17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */
+       [17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */
+       [17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */
+       [17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */
+       [17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */
+       [17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */
+       [17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */
+       [17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */
+       [17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */
+       [17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */
+       [17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */
+       [17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */
+       [17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */
+       [17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */
+       [17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */
+       [17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */
+       [17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */
+       [17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */
+       [17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */
+       [17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */
+       [17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */
+       [17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */
+       [17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */
+       [17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */
+       [17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */
+       [17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */
+       [17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */
+       [18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */
+       [18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */
+       [18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */
+       [18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */
+       [18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */
+       [18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */
+       [18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */
+       [18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */
+       [18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */
+       [18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */
+       [18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */
+       [18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */
+       [18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */
+       [18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */
+       [18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */
+       [18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */
+       [18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */
+       [18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */
+       [18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */
+       [18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */
+       [18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */
+       [18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */
+       [18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */
+       [18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */
+       [18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */
+       [18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */
+       [18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */
+       [18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */
+       [18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */
+       [18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */
+       [18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */
+       [18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */
+       [18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */
+       [18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */
+       [18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */
+       [18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */
+       [18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */
+       [18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */
+       [18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */
+       [18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */
+       [18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */
+       [18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */
+       [18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */
+       [18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */
+       [18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */
+       [18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */
+       [18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */
+       [18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */
+       [18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */
+       [18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */
+       [18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */
+       [18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */
+       [18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */
+       [18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */
+       [18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */
+       [18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */
+       [18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */
+       [18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */
+       [18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */
+       [18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */
+       [19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */
+       [19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */
+       [19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */
+       [19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */
+       [19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */
+       [19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */
+       [19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */
+       [19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */
+       [19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */
+       [19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */
+       [19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */
+       [19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */
+       [19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */
+       [19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */
+       [19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */
+       [19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */
+       [19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */
+       [19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */
+       [19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */
+       [19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */
+       [19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */
+       [19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */
+       [19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */
+       [19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */
+       [19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */
+       [19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */
+       [19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */
+       [19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */
+       [19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */
+       [19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */
+       [19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */
+       [19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */
+       [19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */
+       [19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */
+       [19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */
+       [19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */
+       [19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */
+       [19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */
+       [19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */
+       [19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */
+       [19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */
+       [19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */
+       [19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */
+       [19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */
+       [19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */
+       [19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */
+       [19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */
+       [19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */
+       [19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */
+       [19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */
+       [19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */
+       [19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */
+       [19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */
+       [19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */
+       [19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */
+       [19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */
+       [19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */
+       [19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */
+       [19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */
+       [19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */
+       [19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */
+       [19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */
+       [19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */
+       [19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */
+       [19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */
+       [19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */
+       [19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */
+       [19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */
+       [19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */
+       [19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */
+       [19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */
+       [19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */
+       [19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */
+       [19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */
+       [19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */
+       [19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */
+       [20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */
+       [20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */
+       [20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */
+       [20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */
+       [20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */
+       [20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */
+       [20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */
+       [20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */
+       [20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */
+       [20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */
+       [20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */
+       [20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */
+       [20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */
+       [20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */
+       [20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */
+       [20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */
+       [20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */
+       [20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */
+       [20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */
+       [20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */
+       [20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */
+       [20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */
+       [20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */
+       [20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */
+       [20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */
+       [20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */
+       [20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */
+       [20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */
+       [20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */
+       [20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */
+       [20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */
+       [20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */
+       [20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */
+       [20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */
+       [20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */
+       [20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */
+       [20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */
+       [20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */
+       [20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */
+       [20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */
+       [20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */
+       [20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */
+       [20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */
+       [20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */
+       [20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */
+       [20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */
+       [20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */
+       [20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */
+       [20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */
+       [20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */
+       [20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */
+       [20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */
+       [20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */
+       [20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */
+       [20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */
+       [20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */
+       [20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */
+       [20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */
+       [20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */
+       [20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */
+       [20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */
+       [20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */
+       [20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */
+       [20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */
+       [20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */
+       [20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */
+       [20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */
+       [20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */
+       [20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */
+       [20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */
+       [20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */
+       [20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */
+       [21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */
+       [21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */
+       [21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */
+       [21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */
+       [21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */
+       [21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */
+       [21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */
+       [21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */
+       [21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */
+       [21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */
+       [21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */
+       [21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */
+       [21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */
+       [21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */
+       [21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */
+       [21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */
+       [21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */
+       [21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */
+       [21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */
+       [21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */
+       [21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */
+       [21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */
+       [21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */
+       [21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */
+       [21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */
+       [21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */
+       [21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */
+       [21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */
+       [21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */
+       [21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */
+       [21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */
+       [21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */
+       [21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */
+       [21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */
+       [21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */
+       [21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */
+       [21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */
+       [21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */
+       [21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */
+       [21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */
+       [21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */
+       [21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */
+       [21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */
+       [21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */
+       [21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */
+       [21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */
+       [21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */
+       [21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */
+       [21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */
+       [21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */
+       [21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */
+       [21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */
+       [21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */
+       [21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */
+       [21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */
+       [21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */
+       [21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */
+       [21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */
+       [21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */
+       [21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */
+       [21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */
+       [21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */
+       [21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */
+       [21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */
+       [21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */
+       [21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */
+       [21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */
+       [21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */
+       [21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */
+       [21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */
+       [21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */
+       [21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */
+       [21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */
+       [21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */
+       [21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */
+       [21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */
+       [21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */
+       [21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */
+       [21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */
+       [21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */
+       [21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */
+       [21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */
+       [21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */
+       [21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */
+       [21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */
+       [21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */
+       [21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */
+       [21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */
+       [21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */
+       [21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */
+       [21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */
+       [21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */
+       [21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */
+       [21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */
+       [21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */
+       [21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */
+       [21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */
+       [21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */
+       [21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */
+       [21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */
+       [21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */
+       [21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */
+       [21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */
+       [21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */
+       [21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */
+       [21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */
+       [21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */
+       [21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */
+       [21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */
+       [21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */
+       [21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */
+       [21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */
+       [21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */
+       [21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */
+       [21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */
+       [21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */
+       [21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */
+       [21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */
+       [21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */
+       [21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */
+       [21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */
+       [21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */
+       [21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */
+       [21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */
+       [21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */
+       [21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */
+       [21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */
+       [21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */
+       [21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */
+       [21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */
+       [21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */
+       [21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */
+       [21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */
+       [21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */
+       [21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */
+       [21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */
+       [21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */
+       [21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */
+       [21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */
+       [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
+};
+
+static int wm8962_volatile_register(unsigned int reg)
+{
+       if (wm8962_reg_access[reg].vol)
+               return 1;
+       else
+               return 0;
+}
+
+static int wm8962_readable_register(unsigned int reg)
+{
+       if (wm8962_reg_access[reg].read)
+               return 1;
+       else
+               return 0;
+}
+
+static int wm8962_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
+static const unsigned int mixinpga_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+       2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
+       3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
+       5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0),
+};
+static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
+static const unsigned int classd_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+       7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
+};
+
+/* The VU bits for the headphones are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int ret;
+
+       /* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret == 0)
+               return 0;
+
+       /* If the left PGA is enabled hit that VU bit... */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTL_PGA_ENA)
+               return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+                                    reg_cache[WM8962_HPOUTL_VOLUME]);
+
+       /* ...otherwise the right.  The VU is stereo. */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTR_PGA_ENA)
+               return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+                                    reg_cache[WM8962_HPOUTR_VOLUME]);
+
+       return 0;
+}
+
+/* The VU bits for the speakers are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int ret;
+
+       /* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret == 0)
+               return 0;
+
+       /* If the left PGA is enabled hit that VU bit... */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+               return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+                                    reg_cache[WM8962_SPKOUTL_VOLUME]);
+
+       /* ...otherwise the right.  The VU is stereo. */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+               return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+                                    reg_cache[WM8962_SPKOUTR_VOLUME]);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8962_snd_controls[] = {
+SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 6, 7, 0,
+              mixin_tlv),
+SOC_SINGLE_TLV("MIXINL PGA Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 3, 7, 0,
+              mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINL IN3L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 0, 7, 0,
+              mixin_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 6, 7, 0,
+              mixin_tlv),
+SOC_SINGLE_TLV("MIXINR PGA Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 3, 7, 0,
+              mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINR IN3R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 0, 7, 0,
+              mixin_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8962_LEFT_ADC_VOLUME,
+                WM8962_RIGHT_ADC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8962_LEFT_INPUT_VOLUME,
+                WM8962_RIGHT_INPUT_VOLUME, 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
+            WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
+            WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
+                WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
+                WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+
+SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
+          5, 1, 0),
+
+SOC_SINGLE_TLV("Beep Volume", WM8962_BEEP_GENERATOR_1, 4, 15, 0, beep_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8962_HPOUTL_VOLUME,
+                WM8962_HPOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Headphone Switch", WM8962_PWR_MGMT_2, 1, 0, 1, 1,
+              snd_soc_get_volsw, wm8962_put_hp_sw),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8962_HPOUTL_VOLUME, WM8962_HPOUTR_VOLUME,
+            7, 1, 0),
+SOC_DOUBLE_TLV("Headphone Aux Volume", WM8962_ANALOGUE_HP_2, 3, 6, 7, 0,
+              hp_tlv),
+
+SOC_DOUBLE_R("Headphone Mixer Switch", WM8962_HEADPHONE_MIXER_3,
+            WM8962_HEADPHONE_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("HPMIXL IN4L Volume", WM8962_HEADPHONE_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL IN4R Volume", WM8962_HEADPHONE_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINL Volume", WM8962_HEADPHONE_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINR Volume", WM8962_HEADPHONE_MIXER_3,
+              6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("HPMIXR IN4L Volume", WM8962_HEADPHONE_MIXER_4,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR IN4R Volume", WM8962_HEADPHONE_MIXER_4,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINL Volume", WM8962_HEADPHONE_MIXER_4,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
+              6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
+              classd_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
+SOC_SINGLE_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 1, 1,
+              snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_SINGLE("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3, 8, 1, 1),
+SOC_SINGLE_TLV("Speaker Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              6, 1, 0, inmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_stereo_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME,
+                WM8962_SPKOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 0, 1, 1,
+              snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, WM8962_SPKOUTR_VOLUME,
+            7, 1, 0),
+
+SOC_DOUBLE_R("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3,
+            WM8962_SPEAKER_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              6, 1, 0, inmix_tlv),
+
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4L Volume", WM8962_SPEAKER_MIXER_4,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4R Volume", WM8962_SPEAKER_MIXER_4,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_4,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_4,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              5, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              4, 1, 0, inmix_tlv),
+};
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int src;
+       int fll;
+
+       src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
+
+       switch (src) {
+       case 0:      /* MCLK */
+               fll = 0;
+               break;
+       case 0x200:  /* FLL */
+               fll = 1;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown SYSCLK source %x\n", src);
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (fll)
+                       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                           WM8962_FLL_ENA, WM8962_FLL_ENA);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               if (fll)
+                       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                           WM8962_FLL_ENA, 0);
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(5);
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int timeout;
+       int reg;
+       int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
+                       WM8962_DCS_STARTUP_DONE_HP1R);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA);
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
+
+               /* Start the DC servo */
+               snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP);
+
+               /* Wait for it to complete, should be well under 100ms */
+               timeout = 0;
+               do {
+                       msleep(1);
+                       reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+                       if (reg < 0) {
+                               dev_err(codec->dev,
+                                       "Failed to read DCS status: %d\n",
+                                       reg);
+                               continue;
+                       }
+                       dev_dbg(codec->dev, "DCS status: %x\n", reg);
+               } while (++timeout < 200 && (reg & expected) != expected);
+
+               if ((reg & expected) != expected)
+                       dev_err(codec->dev, "DC servo timed out\n");
+               else
+                       dev_dbg(codec->dev, "DC servo complete after %dms\n",
+                               timeout);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP,
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP);
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT, 0);
+
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP,
+                                   0);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA |
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP, 0);
+                                   
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       
+       }
+
+       return 0;
+}
+
+/* VU bits for the output PGAs only take effect while the PGA is powered */
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int reg;
+
+       switch (w->shift) {
+       case WM8962_HPOUTR_PGA_ENA_SHIFT:
+               reg = WM8962_HPOUTR_VOLUME;
+               break;
+       case WM8962_HPOUTL_PGA_ENA_SHIFT:
+               reg = WM8962_HPOUTL_VOLUME;
+               break;
+       case WM8962_SPKOUTR_PGA_ENA_SHIFT:
+               reg = WM8962_SPKOUTR_VOLUME;
+               break;
+       case WM8962_SPKOUTL_PGA_ENA_SHIFT:
+               reg = WM8962_SPKOUTL_VOLUME;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               return snd_soc_write(codec, reg, reg_cache[reg]);
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
+static const char *st_text[] = { "None", "Right", "Left" };
+
+static const struct soc_enum str_enum =
+       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+
+static const struct snd_kcontrol_new str_mux =
+       SOC_DAPM_ENUM("Right Sidetone", str_enum);
+
+static const struct soc_enum stl_enum =
+       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+
+static const struct snd_kcontrol_new stl_mux =
+       SOC_DAPM_ENUM("Left Sidetone", stl_enum);
+
+static const char *outmux_text[] = { "DAC", "Mixer" };
+
+static const struct soc_enum spkoutr_enum =
+       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutr_mux =
+       SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
+
+static const struct soc_enum spkoutl_enum =
+       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutl_mux =
+       SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
+
+static const struct soc_enum hpoutr_enum =
+       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutr_mux =
+       SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
+
+static const struct soc_enum hpoutl_enum =
+       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutl_mux =
+       SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+
+static const struct snd_kcontrol_new inpgal[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new inpgar[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_INPUT_MIXER_CONTROL_2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_INPUT_MIXER_CONTROL_2, 4, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_INPUT_MIXER_CONTROL_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_INPUT_MIXER_CONTROL_2, 1, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_INPUT("Beep"),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
+
+SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
+                   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
+                  inpgal, ARRAY_SIZE(inpgal)),
+SND_SOC_DAPM_MIXER("INPGAR", WM8962_RIGHT_INPUT_PGA_CONTROL, 4, 0,
+                  inpgar, ARRAY_SIZE(inpgar)),
+SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
+                  mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
+                  mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MUX("STL", SND_SOC_NOPM, 0, 0, &stl_mux),
+SND_SOC_DAPM_MUX("STR", SND_SOC_NOPM, 0, 0, &str_mux),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8962_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8962_PWR_MGMT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("HPMIXL", WM8962_MIXER_ENABLES, 3, 0,
+                  hpmixl, ARRAY_SIZE(hpmixl)),
+SND_SOC_DAPM_MIXER("HPMIXR", WM8962_MIXER_ENABLES, 2, 0,
+                  hpmixr, ARRAY_SIZE(hpmixr)),
+
+SND_SOC_DAPM_MUX_E("HPOUTL PGA", WM8962_PWR_MGMT_2, 6, 0, &hpoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("HPOUTR PGA", WM8962_PWR_MGMT_2, 5, 0, &hpoutr_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
+                  spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_stereo_widgets[] = {
+SND_SOC_DAPM_MIXER("SPKOUTL Mixer", WM8962_MIXER_ENABLES, 1, 0,
+                  spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MIXER("SPKOUTR Mixer", WM8962_MIXER_ENABLES, 0, 0,
+                  spkmixr, ARRAY_SIZE(spkmixr)),
+
+SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8962_intercon[] = {
+       { "INPGAL", "IN1L Switch", "IN1L" },
+       { "INPGAL", "IN2L Switch", "IN2L" },
+       { "INPGAL", "IN3L Switch", "IN3L" },
+       { "INPGAL", "IN4L Switch", "IN4L" },
+
+       { "INPGAR", "IN1R Switch", "IN1R" },
+       { "INPGAR", "IN2R Switch", "IN2R" },
+       { "INPGAR", "IN3R Switch", "IN3R" },
+       { "INPGAR", "IN4R Switch", "IN4R" },
+
+       { "MIXINL", "IN2L Switch", "IN2L" },
+       { "MIXINL", "IN3L Switch", "IN3L" },
+       { "MIXINL", "PGA Switch", "INPGAL" },
+
+       { "MIXINR", "IN2R Switch", "IN2R" },
+       { "MIXINR", "IN3R Switch", "IN3R" },
+       { "MIXINR", "PGA Switch", "INPGAR" },
+
+       { "MICBIAS", NULL, "SYSCLK" },
+
+       { "ADCL", NULL, "SYSCLK" },
+       { "ADCL", NULL, "TOCLK" },
+       { "ADCL", NULL, "MIXINL" },
+
+       { "ADCR", NULL, "SYSCLK" },
+       { "ADCR", NULL, "TOCLK" },
+       { "ADCR", NULL, "MIXINR" },
+
+       { "STL", "Left", "ADCL" },
+       { "STL", "Right", "ADCR" },
+
+       { "STR", "Left", "ADCL" },
+       { "STR", "Right", "ADCR" },
+
+       { "DACL", NULL, "SYSCLK" },
+       { "DACL", NULL, "TOCLK" },
+       { "DACL", NULL, "Beep" },
+       { "DACL", NULL, "STL" },
+
+       { "DACR", NULL, "SYSCLK" },
+       { "DACR", NULL, "TOCLK" },
+       { "DACR", NULL, "Beep" },
+       { "DACR", NULL, "STR" },
+
+       { "HPMIXL", "IN4L Switch", "IN4L" },
+       { "HPMIXL", "IN4R Switch", "IN4R" },
+       { "HPMIXL", "DACL Switch", "DACL" },
+       { "HPMIXL", "DACR Switch", "DACR" },
+       { "HPMIXL", "MIXINL Switch", "MIXINL" },
+       { "HPMIXL", "MIXINR Switch", "MIXINR" },
+
+       { "HPMIXR", "IN4L Switch", "IN4L" },
+       { "HPMIXR", "IN4R Switch", "IN4R" },
+       { "HPMIXR", "DACL Switch", "DACL" },
+       { "HPMIXR", "DACR Switch", "DACR" },
+       { "HPMIXR", "MIXINL Switch", "MIXINL" },
+       { "HPMIXR", "MIXINR Switch", "MIXINR" },
+
+       { "Left Bypass", NULL, "HPMIXL" },
+       { "Left Bypass", NULL, "Class G" },
+
+       { "Right Bypass", NULL, "HPMIXR" },
+       { "Right Bypass", NULL, "Class G" },
+
+       { "HPOUTL PGA", "Mixer", "Left Bypass" },
+       { "HPOUTL PGA", "DAC", "DACL" },
+
+       { "HPOUTR PGA", "Mixer", "Right Bypass" },
+       { "HPOUTR PGA", "DAC", "DACR" },
+
+       { "HPOUT", NULL, "HPOUTL PGA" },
+       { "HPOUT", NULL, "HPOUTR PGA" },
+       { "HPOUT", NULL, "Charge Pump" },
+       { "HPOUT", NULL, "SYSCLK" },
+       { "HPOUT", NULL, "TOCLK" },
+
+       { "HPOUTL", NULL, "HPOUT" },
+       { "HPOUTR", NULL, "HPOUT" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
+       { "Speaker Mixer", "IN4L Switch", "IN4L" },
+       { "Speaker Mixer", "IN4R Switch", "IN4R" },
+       { "Speaker Mixer", "DACL Switch", "DACL" },
+       { "Speaker Mixer", "DACR Switch", "DACR" },
+       { "Speaker Mixer", "MIXINL Switch", "MIXINL" },
+       { "Speaker Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "Speaker PGA", "Mixer", "Speaker Mixer" },
+       { "Speaker PGA", "DAC", "DACL" },
+
+       { "Speaker Output", NULL, "Speaker PGA" },
+       { "Speaker Output", NULL, "SYSCLK" },
+       { "Speaker Output", NULL, "TOCLK" },
+
+       { "SPKOUT", NULL, "Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
+       { "SPKOUTL Mixer", "IN4L Switch", "IN4L" },
+       { "SPKOUTL Mixer", "IN4R Switch", "IN4R" },
+       { "SPKOUTL Mixer", "DACL Switch", "DACL" },
+       { "SPKOUTL Mixer", "DACR Switch", "DACR" },
+       { "SPKOUTL Mixer", "MIXINL Switch", "MIXINL" },
+       { "SPKOUTL Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "SPKOUTR Mixer", "IN4L Switch", "IN4L" },
+       { "SPKOUTR Mixer", "IN4R Switch", "IN4R" },
+       { "SPKOUTR Mixer", "DACL Switch", "DACL" },
+       { "SPKOUTR Mixer", "DACR Switch", "DACR" },
+       { "SPKOUTR Mixer", "MIXINL Switch", "MIXINL" },
+       { "SPKOUTR Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "SPKOUTL PGA", "Mixer", "SPKOUTL Mixer" },
+       { "SPKOUTL PGA", "DAC", "DACL" },
+
+       { "SPKOUTR PGA", "Mixer", "SPKOUTR Mixer" },
+       { "SPKOUTR PGA", "DAC", "DACR" },
+
+       { "SPKOUTL Output", NULL, "SPKOUTL PGA" },
+       { "SPKOUTL Output", NULL, "SYSCLK" },
+       { "SPKOUTL Output", NULL, "TOCLK" },
+
+       { "SPKOUTR Output", NULL, "SPKOUTR PGA" },
+       { "SPKOUTR Output", NULL, "SYSCLK" },
+       { "SPKOUTR Output", NULL, "TOCLK" },
+
+       { "SPKOUTL", NULL, "SPKOUTL Output" },
+       { "SPKOUTR", NULL, "SPKOUTR Output" },
+};
+
+static int wm8962_add_widgets(struct snd_soc_codec *codec)
+{
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+
+       snd_soc_add_controls(codec, wm8962_snd_controls,
+                            ARRAY_SIZE(wm8962_snd_controls));
+       if (pdata && pdata->spk_mono)
+               snd_soc_add_controls(codec, wm8962_spk_mono_controls,
+                                    ARRAY_SIZE(wm8962_spk_mono_controls));
+       else
+               snd_soc_add_controls(codec, wm8962_spk_stereo_controls,
+                                    ARRAY_SIZE(wm8962_spk_stereo_controls));
+
+
+       snd_soc_dapm_new_controls(codec, wm8962_dapm_widgets,
+                                 ARRAY_SIZE(wm8962_dapm_widgets));
+       if (pdata && pdata->spk_mono)
+               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_mono_widgets,
+                                         ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
+       else
+               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_stereo_widgets,
+                                         ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
+
+       snd_soc_dapm_add_routes(codec, wm8962_intercon,
+                               ARRAY_SIZE(wm8962_intercon));
+       if (pdata && pdata->spk_mono)
+               snd_soc_dapm_add_routes(codec, wm8962_spk_mono_intercon,
+                                       ARRAY_SIZE(wm8962_spk_mono_intercon));
+       else
+               snd_soc_dapm_add_routes(codec, wm8962_spk_stereo_intercon,
+                                       ARRAY_SIZE(wm8962_spk_stereo_intercon));
+
+
+       snd_soc_dapm_disable_pin(codec, "Beep");
+
+       return 0;
+}
+
+static void wm8962_sync_cache(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       dev_dbg(codec->dev, "Syncing cache\n");
+
+       codec->cache_only = 0;
+
+       /* Sync back cached values if they're different from the
+        * hardware default.
+        */
+       for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+               if (i == WM8962_SOFTWARE_RESET)
+                       continue;
+               if (wm8962->reg_cache[i] == wm8962_reg[i])
+                       continue;
+
+               snd_soc_write(codec, i, wm8962->reg_cache[i]);
+       }
+
+       codec->cache_sync = 0;
+}
+
+/* -1 for reserved values */
+static const int bclk_divs[] = {
+       1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
+};
+
+static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int dspclk, i;
+       int clocking2 = 0;
+       int aif2 = 0;
+
+       if (!wm8962->bclk) {
+               dev_dbg(codec->dev, "No BCLK rate configured\n");
+               return;
+       }
+
+       dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+       if (dspclk < 0) {
+               dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+               return;
+       }
+
+       dspclk = (dspclk & WM8962_DSPCLK_DIV_MASK) >> WM8962_DSPCLK_DIV_SHIFT;
+       switch (dspclk) {
+       case 0:
+               dspclk = wm8962->sysclk_rate;
+               break;
+       case 1:
+               dspclk = wm8962->sysclk_rate / 2;
+               break;
+       case 2:
+               dspclk = wm8962->sysclk_rate / 4;
+               break;
+       default:
+               dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+               dspclk = wm8962->sysclk;
+       }
+
+       dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+
+       /* We're expecting an exact match */
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               if (bclk_divs[i] < 0)
+                       continue;
+
+               if (dspclk / bclk_divs[i] == wm8962->bclk) {
+                       dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
+                               bclk_divs[i], wm8962->bclk);
+                       clocking2 |= i;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(bclk_divs)) {
+               dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
+                       dspclk / wm8962->bclk);
+               return;
+       }
+
+       aif2 |= wm8962->bclk / wm8962->lrclk;
+       dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+               wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
+
+       snd_soc_update_bits(codec, WM8962_CLOCKING2,
+                           WM8962_BCLK_DIV_MASK, clocking2);
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+                           WM8962_AIF_RATE_MASK, aif2);
+}
+
+static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       if (level == codec->bias_level)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID 2*50k */
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK, 0x80);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                                   wm8962->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8962_sync_cache(codec);
+
+                       snd_soc_update_bits(codec, WM8962_ANTI_POP,
+                                           WM8962_STARTUP_BIAS_ENA |
+                                           WM8962_VMID_BUF_ENA,
+                                           WM8962_STARTUP_BIAS_ENA |
+                                           WM8962_VMID_BUF_ENA);
+
+                       /* Bias enable at 2*50k for ramp */
+                       snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                           WM8962_VMID_SEL_MASK |
+                                           WM8962_BIAS_ENA,
+                                           WM8962_BIAS_ENA | 0x180);
+
+                       msleep(5);
+
+                       snd_soc_update_bits(codec, WM8962_CLOCKING2,
+                                           WM8962_CLKREG_OVD,
+                                           WM8962_CLKREG_OVD);
+
+                       wm8962_configure_bclk(codec);
+               }
+
+               /* VMID 2*250k */
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK, 0x100);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+               snd_soc_update_bits(codec, WM8962_ANTI_POP,
+                                   WM8962_STARTUP_BIAS_ENA |
+                                   WM8962_VMID_BUF_ENA, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+                                      wm8962->supplies);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static const struct {
+       int rate;
+       int reg;
+} sr_vals[] = {
+       { 48000, 0 },
+       { 44100, 0 },
+       { 32000, 1 },
+       { 22050, 2 },
+       { 24000, 2 },
+       { 16000, 3 },
+       { 11025, 4 },
+       { 12000, 4 },
+       { 8000,  5 },
+       { 88200, 6 },
+       { 96000, 6 },
+};
+
+static const int sysclk_rates[] = {
+       64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+};
+
+static int wm8962_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int rate = params_rate(params);
+       int i;
+       int aif0 = 0;
+       int adctl3 = 0;
+       int clocking4 = 0;
+
+       wm8962->bclk = snd_soc_params_to_bclk(params);
+       wm8962->lrclk = params_rate(params);
+
+       for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
+               if (sr_vals[i].rate == rate) {
+                       adctl3 |= sr_vals[i].reg;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(sr_vals)) {
+               dev_err(codec->dev, "Unsupported rate %dHz\n", rate);
+               return -EINVAL;
+       }
+
+       if (rate % 8000 == 0)
+               adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
+
+       for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+               if (sysclk_rates[i] == wm8962->sysclk_rate / rate) {
+                       clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(sysclk_rates)) {
+               dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+                       wm8962->sysclk_rate / rate);
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif0 |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif0 |= 0x80;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif0 |= 0xc0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+                           WM8962_WL_MASK, aif0);
+       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+                           WM8962_SAMPLE_RATE_INT_MODE |
+                           WM8962_SAMPLE_RATE_MASK, adctl3);
+       snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+                           WM8962_SYSCLK_RATE_MASK, clocking4);
+
+       wm8962_configure_bclk(codec);
+
+       return 0;
+}
+
+static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int src;
+
+       switch (clk_id) {
+       case WM8962_SYSCLK_MCLK:
+               wm8962->sysclk = WM8962_SYSCLK_MCLK;
+               src = 0;
+               break;
+       case WM8962_SYSCLK_FLL:
+               wm8962->sysclk = WM8962_SYSCLK_FLL;
+               src = 1 << WM8962_SYSCLK_SRC_SHIFT;
+               WARN_ON(freq != wm8962->fll_fout);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+                           src);
+
+       wm8962->sysclk_rate = freq;
+
+       return 0;
+}
+
+static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int aif0 = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               aif0 |= WM8962_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_B:
+               aif0 |= 3;
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+               case SND_SOC_DAIFMT_IB_NF:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif0 |= 1;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif0 |= 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               aif0 |= WM8962_BCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               aif0 |= WM8962_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               aif0 |= WM8962_BCLK_INV | WM8962_LRCLK_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif0 |= WM8962_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+                           WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
+                           WM8962_LRCLK_INV, aif0);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_refclk_div;
+       u16 n;
+       u16 theta;
+       u16 lambda;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       unsigned int target;
+       unsigned int div;
+       unsigned int fratio, gcd_fll;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_refclk_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_refclk_div++;
+
+               if (div > 4) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 2;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("FLL Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       fratio = fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       fll_div->n = target / (fratio * Fref);
+
+       if (target % Fref == 0) {
+               fll_div->theta = 0;
+               fll_div->lambda = 0;
+       } else {
+               gcd_fll = gcd(target, fratio * Fref);
+
+               fll_div->theta = (target - (fll_div->n * fratio * Fref))
+                       / gcd_fll;
+               fll_div->lambda = (fratio * Fref) / gcd_fll;
+       }
+
+       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+                fll_div->n, fll_div->theta, fll_div->lambda);
+       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_refclk_div);
+
+       return 0;
+}
+
+static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct _fll_div fll_div;
+       int ret;
+       int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
+
+       /* Any change? */
+       if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
+           Fout == wm8962->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8962->fll_fref = 0;
+               wm8962->fll_fout = 0;
+
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                   WM8962_FLL_ENA, 0);
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       switch (fll_id) {
+       case WM8962_FLL_MCLK:
+       case WM8962_FLL_BCLK:
+       case WM8962_FLL_OSC:
+               fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+               break;
+       case WM8962_FLL_INT:
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                   WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+                                   WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+               return -EINVAL;
+       }
+
+       if (fll_div.theta || fll_div.lambda)
+               fll1 |= WM8962_FLL_FRAC;
+
+       /* Stop the FLL while we reconfigure */
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+                           WM8962_FLL_OUTDIV_MASK |
+                           WM8962_FLL_REFCLK_DIV_MASK,
+                           (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_refclk_div));
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+                           WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
+
+       snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
+       snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
+       snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                           WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
+                           WM8962_FLL_ENA, fll1);
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8962->fll_fref = Fref;
+       wm8962->fll_fout = Fout;
+       wm8962->fll_src = source;
+
+       return 0;
+}
+
+static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int val;
+
+       if (mute)
+               val = WM8962_DAC_MUTE;
+       else
+               val = 0;
+
+       return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+                                  WM8962_DAC_MUTE, val);
+}
+
+#define WM8962_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8962_dai_ops = {
+       .hw_params = wm8962_hw_params,
+       .set_sysclk = wm8962_set_dai_sysclk,
+       .set_fmt = wm8962_set_dai_fmt,
+       .set_pll = wm8962_set_fll,
+       .digital_mute = wm8962_mute,
+};
+
+static struct snd_soc_dai_driver wm8962_dai = {
+       .name = "wm8962",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8962_RATES,
+               .formats = WM8962_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8962_RATES,
+               .formats = WM8962_FORMATS,
+       },
+       .ops = &wm8962_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static void wm8962_mic_work(struct work_struct *work)
+{
+       struct wm8962_priv *wm8962 = container_of(work,
+                                                 struct wm8962_priv,
+                                                 mic_work.work);
+       struct snd_soc_codec *codec = wm8962->codec;
+       int status = 0;
+       int irq_pol = 0;
+       int reg;
+
+       reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+
+       if (reg & WM8962_MICDET_STS) {
+               status |= SND_JACK_MICROPHONE;
+               irq_pol |= WM8962_MICD_IRQ_POL;
+       }
+
+       if (reg & WM8962_MICSHORT_STS) {
+               status |= SND_JACK_BTN_0;
+               irq_pol |= WM8962_MICSCD_IRQ_POL;
+       }
+
+       snd_soc_jack_report(wm8962->jack, status,
+                           SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+       snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+                           WM8962_MICSCD_IRQ_POL |
+                           WM8962_MICD_IRQ_POL, irq_pol);
+}
+
+static irqreturn_t wm8962_irq(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int mask;
+       int active;
+
+       mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+
+       active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+       active &= ~mask;
+
+       if (active & WM8962_FIFOS_ERR_EINT)
+               dev_err(codec->dev, "FIFO error\n");
+
+       if (active & WM8962_TEMP_SHUT_EINT)
+               dev_crit(codec->dev, "Thermal shutdown\n");
+
+       if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+               dev_dbg(codec->dev, "Microphone event detected\n");
+
+               schedule_delayed_work(&wm8962->mic_work,
+                                     msecs_to_jiffies(250));
+       }
+
+       /* Acknowledge the interrupts */
+       snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @codec:  WM8962 codec
+ * @jack:   jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int irq_mask, enable;
+
+       wm8962->jack = jack;
+       if (jack) {
+               irq_mask = 0;
+               enable = WM8962_MICDET_ENA;
+       } else {
+               irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+               enable = 0;
+       }
+
+       snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+                           WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                           WM8962_MICDET_ENA, enable);
+
+       /* Send an initial empty report */
+       snd_soc_jack_report(wm8962->jack, 0,
+                           SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
+#ifdef CONFIG_PM
+static int wm8962_resume(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = codec->reg_cache;
+       int i;
+
+       /* Restore the registers */
+       for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+               switch (i) {
+               case WM8962_SOFTWARE_RESET:
+                       continue;
+               default:
+                       break;
+               }
+
+               if (reg_cache[i] != wm8962_reg[i])
+                       snd_soc_write(codec, i, reg_cache[i]);
+       }
+
+       return 0;
+}
+#else
+#define wm8962_resume NULL
+#endif
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+       500, 1000, 2000, 4000,
+};
+
+static void wm8962_beep_work(struct work_struct *work)
+{
+       struct wm8962_priv *wm8962 =
+               container_of(work, struct wm8962_priv, beep_work);
+       struct snd_soc_codec *codec = wm8962->codec;
+       int i;
+       int reg = 0;
+       int best = 0;
+
+       if (wm8962->beep_rate) {
+               for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+                       if (abs(wm8962->beep_rate - beep_rates[i]) <
+                           abs(wm8962->beep_rate - beep_rates[best]))
+                               best = i;
+               }
+
+               dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+                       beep_rates[best], wm8962->beep_rate);
+
+               reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
+
+               snd_soc_dapm_enable_pin(codec, "Beep");
+       } else {
+               dev_dbg(codec->dev, "Disabling beep\n");
+               snd_soc_dapm_disable_pin(codec, "Beep");
+       }
+
+       snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+                           WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
+
+       snd_soc_dapm_sync(codec);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
+                            unsigned int code, int hz)
+{
+       struct snd_soc_codec *codec = input_get_drvdata(dev);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+       switch (code) {
+       case SND_BELL:
+               if (hz)
+                       hz = 1000;
+       case SND_TONE:
+               break;
+       default:
+               return -1;
+       }
+
+       /* Kick the beep from a workqueue */
+       wm8962->beep_rate = hz;
+       schedule_work(&wm8962->beep_work);
+       return 0;
+}
+
+static ssize_t wm8962_beep_set(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+       long int time;
+
+       strict_strtol(buf, 10, &time);
+
+       input_event(wm8962->beep, EV_SND, SND_TONE, time);
+
+       return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       wm8962->beep = input_allocate_device();
+       if (!wm8962->beep) {
+               dev_err(codec->dev, "Failed to allocate beep device\n");
+               return;
+       }
+
+       INIT_WORK(&wm8962->beep_work, wm8962_beep_work);
+       wm8962->beep_rate = 0;
+
+       wm8962->beep->name = "WM8962 Beep Generator";
+       wm8962->beep->phys = dev_name(codec->dev);
+       wm8962->beep->id.bustype = BUS_I2C;
+
+       wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
+       wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+       wm8962->beep->event = wm8962_beep_event;
+       wm8962->beep->dev.parent = codec->dev;
+       input_set_drvdata(wm8962->beep, codec);
+
+       ret = input_register_device(wm8962->beep);
+       if (ret != 0) {
+               input_free_device(wm8962->beep);
+               wm8962->beep = NULL;
+               dev_err(codec->dev, "Failed to register beep device\n");
+       }
+
+       ret = device_create_file(codec->dev, &dev_attr_beep);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+                       ret);
+       }
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+       device_remove_file(codec->dev, &dev_attr_beep);
+       input_unregister_device(wm8962->beep);
+       cancel_work_sync(&wm8962->beep_work);
+       wm8962->beep = NULL;
+
+       snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+}
+#else
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+{
+       int mask = 0;
+       int val = 0;
+
+       /* Some of the GPIOs are behind MFP configuration and need to
+        * be put into GPIO mode. */
+       switch (gpio) {
+       case 2:
+               mask = WM8962_CLKOUT2_SEL_MASK;
+               val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+               break;
+       case 3:
+               mask = WM8962_CLKOUT3_SEL_MASK;
+               val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+               break;
+       default:
+               break;
+       }
+
+       if (mask)
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
+                                   mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
+{
+       return container_of(chip, struct wm8962_priv, gpio_chip);
+}
+
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+
+       /* The WM8962 GPIOs aren't linearly numbered.  For simplicity
+        * we export linear numbers and error out if the unsupported
+        * ones are requsted.
+        */
+       switch (offset + 1) {
+       case 2:
+       case 3:
+       case 5:
+       case 6:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8962_set_gpio_mode(codec, offset + 1);
+
+       return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+
+       snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+                           WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+       int val;
+
+       /* Force function 1 (logic output) */
+       val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+       return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+                                  WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+}
+
+static struct gpio_chip wm8962_template_chip = {
+       .label                  = "wm8962",
+       .owner                  = THIS_MODULE,
+       .request                = wm8962_gpio_request,
+       .direction_output       = wm8962_gpio_direction_out,
+       .set                    = wm8962_gpio_set,
+       .can_sleep              = 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       int ret;
+
+       wm8962->gpio_chip = wm8962_template_chip;
+       wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+       wm8962->gpio_chip.dev = codec->dev;
+
+       if (pdata && pdata->gpio_base)
+               wm8962->gpio_chip.base = pdata->gpio_base;
+       else
+               wm8962->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&wm8962->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = gpiochip_remove(&wm8962->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int wm8962_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+                                             dev);
+       int i, trigger, irq_pol;
+
+       wm8962->codec = codec;
+       INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+
+       codec->cache_sync = 1;
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+               wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8962->supplies),
+                                wm8962->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+       wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+       wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+       wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+       wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+       wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+       wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+       wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+               ret = regulator_register_notifier(wm8962->supplies[i].consumer,
+                                                 &wm8962->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                   wm8962->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = snd_soc_read(codec, WM8962_SOFTWARE_RESET);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register\n");
+               goto err_enable;
+       }
+       if (ret != wm8962_reg[WM8962_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Device is not a WM8962, ID %x != %x\n",
+                       ret, wm8962_reg[WM8962_SOFTWARE_RESET]);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8962_RIGHT_INPUT_VOLUME);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       
+       dev_info(codec->dev, "customer id %x revision %c\n",
+                (ret & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+                ((ret & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+                + 'A');
+
+       ret = wm8962_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err_enable;
+       }
+
+       /* SYSCLK defaults to on; make sure it is off so we can safely
+        * write to registers if the device is declocked.
+        */
+       snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+       if (pdata) {
+               /* Apply static configuration for GPIOs */
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+                       if (pdata->gpio_init[i]) {
+                               wm8962_set_gpio_mode(codec, i + 1);
+                               snd_soc_write(codec, 0x200 + i,
+                                             pdata->gpio_init[i] & 0xffff);
+                       }
+
+               /* Put the speakers into mono mode? */
+               if (pdata->spk_mono)
+                       wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
+                               |= WM8962_SPK_MONO;
+
+               /* Micbias setup, detection enable and detection
+                * threasholds. */
+               if (pdata->mic_cfg)
+                       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                                           WM8962_MICDET_ENA |
+                                           WM8962_MICDET_THR_MASK |
+                                           WM8962_MICSHORT_THR_MASK |
+                                           WM8962_MICBIAS_LVL,
+                                           pdata->mic_cfg);
+       }
+
+       /* Latch volume update bits */
+       wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+       wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+       wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+       wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;    
+       wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+       wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+       wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+       wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+       wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+       wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+
+       wm8962_add_widgets(codec);
+
+       wm8962_init_beep(codec);
+       wm8962_init_gpio(codec);
+
+       if (i2c->irq) {
+               if (pdata && pdata->irq_active_low) {
+                       trigger = IRQF_TRIGGER_LOW;
+                       irq_pol = WM8962_IRQ_POL;
+               } else {
+                       trigger = IRQF_TRIGGER_HIGH;
+                       irq_pol = 0;
+               }
+
+               snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
+                                   WM8962_IRQ_POL, irq_pol);
+
+               ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq,
+                                          trigger | IRQF_ONESHOT,
+                                          "wm8962", codec);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+                               i2c->irq, ret);
+                       /* Non-fatal */
+               } else {
+                       /* Enable error reporting IRQs by default */
+                       snd_soc_update_bits(codec,
+                                           WM8962_INTERRUPT_STATUS_2_MASK,
+                                           WM8962_TEMP_SHUT_EINT |
+                                           WM8962_FIFOS_ERR_EINT, 0);
+               }
+       }
+
+       return 0;
+
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
+       kfree(wm8962);
+       return ret;
+}
+
+static int wm8962_remove(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+                                             dev);
+       int i;
+
+       if (i2c->irq)
+               free_irq(i2c->irq, codec);
+
+       cancel_delayed_work_sync(&wm8962->mic_work);
+
+       wm8962_free_gpio(codec);
+       wm8962_free_beep(codec);
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+               regulator_unregister_notifier(wm8962->supplies[i].consumer,
+                                             &wm8962->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
+       .probe =        wm8962_probe,
+       .remove =       wm8962_remove,
+       .resume =       wm8962_resume,
+       .set_bias_level = wm8962_set_bias_level,
+       .reg_cache_size = WM8962_MAX_REGISTER + 1,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8962_reg,
+       .volatile_register = wm8962_volatile_register,
+       .readable_register = wm8962_readable_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8962_priv *wm8962;
+       int ret;
+
+       wm8962 = kzalloc(sizeof(struct wm8962_priv), GFP_KERNEL);
+       if (wm8962 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8962);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8962, &wm8962_dai, 1);
+       if (ret < 0)
+               kfree(wm8962);
+
+       return ret;
+}
+
+static __devexit int wm8962_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8962_i2c_id[] = {
+       { "wm8962", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
+
+static struct i2c_driver wm8962_i2c_driver = {
+       .driver = {
+               .name = "wm8962",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8962_i2c_probe,
+       .remove =   __devexit_p(wm8962_i2c_remove),
+       .id_table = wm8962_i2c_id,
+};
+#endif
+
+static int __init wm8962_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8962_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8962_modinit);
+
+static void __exit wm8962_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8962_i2c_driver);
+#endif
+}
+module_exit(wm8962_exit);
+
+MODULE_DESCRIPTION("ASoC WM8962 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
new file mode 100644 (file)
index 0000000..a1a5d52
--- /dev/null
@@ -0,0 +1,3780 @@
+/*
+ * wm8962.h  --  WM8962 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 _WM8962_H
+#define _WM8962_H
+
+#include <asm/types.h>
+#include <sound/soc.h>
+
+#define WM8962_SYSCLK_MCLK 1
+#define WM8962_SYSCLK_FLL  2
+#define WM8962_SYSCLK_PLL3 3
+
+#define WM8962_FLL  1
+
+#define WM8962_FLL_MCLK 1
+#define WM8962_FLL_BCLK 2
+#define WM8962_FLL_OSC  3
+#define WM8962_FLL_INT  4
+
+/*
+ * Register values.
+ */
+#define WM8962_LEFT_INPUT_VOLUME                0x00
+#define WM8962_RIGHT_INPUT_VOLUME               0x01
+#define WM8962_HPOUTL_VOLUME                    0x02
+#define WM8962_HPOUTR_VOLUME                    0x03
+#define WM8962_CLOCKING1                        0x04
+#define WM8962_ADC_DAC_CONTROL_1                0x05
+#define WM8962_ADC_DAC_CONTROL_2                0x06
+#define WM8962_AUDIO_INTERFACE_0                0x07
+#define WM8962_CLOCKING2                        0x08
+#define WM8962_AUDIO_INTERFACE_1                0x09
+#define WM8962_LEFT_DAC_VOLUME                  0x0A
+#define WM8962_RIGHT_DAC_VOLUME                 0x0B
+#define WM8962_AUDIO_INTERFACE_2                0x0E
+#define WM8962_SOFTWARE_RESET                   0x0F
+#define WM8962_ALC1                             0x11
+#define WM8962_ALC2                             0x12
+#define WM8962_ALC3                             0x13
+#define WM8962_NOISE_GATE                       0x14
+#define WM8962_LEFT_ADC_VOLUME                  0x15
+#define WM8962_RIGHT_ADC_VOLUME                 0x16
+#define WM8962_ADDITIONAL_CONTROL_1             0x17
+#define WM8962_ADDITIONAL_CONTROL_2             0x18
+#define WM8962_PWR_MGMT_1                       0x19
+#define WM8962_PWR_MGMT_2                       0x1A
+#define WM8962_ADDITIONAL_CONTROL_3             0x1B
+#define WM8962_ANTI_POP                         0x1C
+#define WM8962_CLOCKING_3                       0x1E
+#define WM8962_INPUT_MIXER_CONTROL_1            0x1F
+#define WM8962_LEFT_INPUT_MIXER_VOLUME          0x20
+#define WM8962_RIGHT_INPUT_MIXER_VOLUME         0x21
+#define WM8962_INPUT_MIXER_CONTROL_2            0x22
+#define WM8962_INPUT_BIAS_CONTROL               0x23
+#define WM8962_LEFT_INPUT_PGA_CONTROL           0x25
+#define WM8962_RIGHT_INPUT_PGA_CONTROL          0x26
+#define WM8962_SPKOUTL_VOLUME                   0x28
+#define WM8962_SPKOUTR_VOLUME                   0x29
+#define WM8962_THERMAL_SHUTDOWN_STATUS          0x2F
+#define WM8962_ADDITIONAL_CONTROL_4             0x30
+#define WM8962_CLASS_D_CONTROL_1                0x31
+#define WM8962_CLASS_D_CONTROL_2                0x33
+#define WM8962_CLOCKING_4                       0x38
+#define WM8962_DAC_DSP_MIXING_1                 0x39
+#define WM8962_DAC_DSP_MIXING_2                 0x3A
+#define WM8962_DC_SERVO_0                       0x3C
+#define WM8962_DC_SERVO_1                       0x3D
+#define WM8962_DC_SERVO_4                       0x40
+#define WM8962_DC_SERVO_6                       0x42
+#define WM8962_ANALOGUE_PGA_BIAS                0x44
+#define WM8962_ANALOGUE_HP_0                    0x45
+#define WM8962_ANALOGUE_HP_2                    0x47
+#define WM8962_CHARGE_PUMP_1                    0x48
+#define WM8962_CHARGE_PUMP_B                    0x52
+#define WM8962_WRITE_SEQUENCER_CONTROL_1        0x57
+#define WM8962_WRITE_SEQUENCER_CONTROL_2        0x5A
+#define WM8962_WRITE_SEQUENCER_CONTROL_3        0x5D
+#define WM8962_CONTROL_INTERFACE                0x5E
+#define WM8962_MIXER_ENABLES                    0x63
+#define WM8962_HEADPHONE_MIXER_1                0x64
+#define WM8962_HEADPHONE_MIXER_2                0x65
+#define WM8962_HEADPHONE_MIXER_3                0x66
+#define WM8962_HEADPHONE_MIXER_4                0x67
+#define WM8962_SPEAKER_MIXER_1                  0x69
+#define WM8962_SPEAKER_MIXER_2                  0x6A
+#define WM8962_SPEAKER_MIXER_3                  0x6B
+#define WM8962_SPEAKER_MIXER_4                  0x6C
+#define WM8962_SPEAKER_MIXER_5                  0x6D
+#define WM8962_BEEP_GENERATOR_1                 0x6E
+#define WM8962_OSCILLATOR_TRIM_3                0x73
+#define WM8962_OSCILLATOR_TRIM_4                0x74
+#define WM8962_OSCILLATOR_TRIM_7                0x77
+#define WM8962_ANALOGUE_CLOCKING1               0x7C
+#define WM8962_ANALOGUE_CLOCKING2               0x7D
+#define WM8962_ANALOGUE_CLOCKING3               0x7E
+#define WM8962_PLL_SOFTWARE_RESET               0x7F
+#define WM8962_PLL2                             0x81
+#define WM8962_PLL_4                            0x83
+#define WM8962_PLL_9                            0x88
+#define WM8962_PLL_10                           0x89
+#define WM8962_PLL_11                           0x8A
+#define WM8962_PLL_12                           0x8B
+#define WM8962_PLL_13                           0x8C
+#define WM8962_PLL_14                           0x8D
+#define WM8962_PLL_15                           0x8E
+#define WM8962_PLL_16                           0x8F
+#define WM8962_FLL_CONTROL_1                    0x9B
+#define WM8962_FLL_CONTROL_2                    0x9C
+#define WM8962_FLL_CONTROL_3                    0x9D
+#define WM8962_FLL_CONTROL_5                    0x9F
+#define WM8962_FLL_CONTROL_6                    0xA0
+#define WM8962_FLL_CONTROL_7                    0xA1
+#define WM8962_FLL_CONTROL_8                    0xA2
+#define WM8962_GENERAL_TEST_1                   0xFC
+#define WM8962_DF1                              0x100
+#define WM8962_DF2                              0x101
+#define WM8962_DF3                              0x102
+#define WM8962_DF4                              0x103
+#define WM8962_DF5                              0x104
+#define WM8962_DF6                              0x105
+#define WM8962_DF7                              0x106
+#define WM8962_LHPF1                            0x108
+#define WM8962_LHPF2                            0x109
+#define WM8962_THREED1                          0x10C
+#define WM8962_THREED2                          0x10D
+#define WM8962_THREED3                          0x10E
+#define WM8962_THREED4                          0x10F
+#define WM8962_DRC_1                            0x114
+#define WM8962_DRC_2                            0x115
+#define WM8962_DRC_3                            0x116
+#define WM8962_DRC_4                            0x117
+#define WM8962_DRC_5                            0x118
+#define WM8962_TLOOPBACK                        0x11D
+#define WM8962_EQ1                              0x14F
+#define WM8962_EQ2                              0x150
+#define WM8962_EQ3                              0x151
+#define WM8962_EQ4                              0x152
+#define WM8962_EQ5                              0x153
+#define WM8962_EQ6                              0x154
+#define WM8962_EQ7                              0x155
+#define WM8962_EQ8                              0x156
+#define WM8962_EQ9                              0x157
+#define WM8962_EQ10                             0x158
+#define WM8962_EQ11                             0x159
+#define WM8962_EQ12                             0x15A
+#define WM8962_EQ13                             0x15B
+#define WM8962_EQ14                             0x15C
+#define WM8962_EQ15                             0x15D
+#define WM8962_EQ16                             0x15E
+#define WM8962_EQ17                             0x15F
+#define WM8962_EQ18                             0x160
+#define WM8962_EQ19                             0x161
+#define WM8962_EQ20                             0x162
+#define WM8962_EQ21                             0x163
+#define WM8962_EQ22                             0x164
+#define WM8962_EQ23                             0x165
+#define WM8962_EQ24                             0x166
+#define WM8962_EQ25                             0x167
+#define WM8962_EQ26                             0x168
+#define WM8962_EQ27                             0x169
+#define WM8962_EQ28                             0x16A
+#define WM8962_EQ29                             0x16B
+#define WM8962_EQ30                             0x16C
+#define WM8962_EQ31                             0x16D
+#define WM8962_EQ32                             0x16E
+#define WM8962_EQ33                             0x16F
+#define WM8962_EQ34                             0x170
+#define WM8962_EQ35                             0x171
+#define WM8962_EQ36                             0x172
+#define WM8962_EQ37                             0x173
+#define WM8962_EQ38                             0x174
+#define WM8962_EQ39                             0x175
+#define WM8962_EQ40                             0x176
+#define WM8962_EQ41                             0x177
+#define WM8962_GPIO_BASE                       0x200
+#define WM8962_GPIO_2                           0x201
+#define WM8962_GPIO_3                           0x202
+#define WM8962_GPIO_5                           0x204
+#define WM8962_GPIO_6                           0x205
+#define WM8962_INTERRUPT_STATUS_1               0x230
+#define WM8962_INTERRUPT_STATUS_2               0x231
+#define WM8962_INTERRUPT_STATUS_1_MASK          0x238
+#define WM8962_INTERRUPT_STATUS_2_MASK          0x239
+#define WM8962_INTERRUPT_CONTROL                0x240
+#define WM8962_IRQ_DEBOUNCE                     0x248
+#define WM8962_MICINT_SOURCE_POL                0x24A
+#define WM8962_DSP2_POWER_MANAGEMENT            0x300
+#define WM8962_DSP2_EXECCONTROL                 0x40D
+#define WM8962_WRITE_SEQUENCER_0                0x1000
+#define WM8962_WRITE_SEQUENCER_1                0x1001
+#define WM8962_WRITE_SEQUENCER_2                0x1002
+#define WM8962_WRITE_SEQUENCER_3                0x1003
+#define WM8962_WRITE_SEQUENCER_4                0x1004
+#define WM8962_WRITE_SEQUENCER_5                0x1005
+#define WM8962_WRITE_SEQUENCER_6                0x1006
+#define WM8962_WRITE_SEQUENCER_7                0x1007
+#define WM8962_WRITE_SEQUENCER_8                0x1008
+#define WM8962_WRITE_SEQUENCER_9                0x1009
+#define WM8962_WRITE_SEQUENCER_10               0x100A
+#define WM8962_WRITE_SEQUENCER_11               0x100B
+#define WM8962_WRITE_SEQUENCER_12               0x100C
+#define WM8962_WRITE_SEQUENCER_13               0x100D
+#define WM8962_WRITE_SEQUENCER_14               0x100E
+#define WM8962_WRITE_SEQUENCER_15               0x100F
+#define WM8962_WRITE_SEQUENCER_16               0x1010
+#define WM8962_WRITE_SEQUENCER_17               0x1011
+#define WM8962_WRITE_SEQUENCER_18               0x1012
+#define WM8962_WRITE_SEQUENCER_19               0x1013
+#define WM8962_WRITE_SEQUENCER_20               0x1014
+#define WM8962_WRITE_SEQUENCER_21               0x1015
+#define WM8962_WRITE_SEQUENCER_22               0x1016
+#define WM8962_WRITE_SEQUENCER_23               0x1017
+#define WM8962_WRITE_SEQUENCER_24               0x1018
+#define WM8962_WRITE_SEQUENCER_25               0x1019
+#define WM8962_WRITE_SEQUENCER_26               0x101A
+#define WM8962_WRITE_SEQUENCER_27               0x101B
+#define WM8962_WRITE_SEQUENCER_28               0x101C
+#define WM8962_WRITE_SEQUENCER_29               0x101D
+#define WM8962_WRITE_SEQUENCER_30               0x101E
+#define WM8962_WRITE_SEQUENCER_31               0x101F
+#define WM8962_WRITE_SEQUENCER_32               0x1020
+#define WM8962_WRITE_SEQUENCER_33               0x1021
+#define WM8962_WRITE_SEQUENCER_34               0x1022
+#define WM8962_WRITE_SEQUENCER_35               0x1023
+#define WM8962_WRITE_SEQUENCER_36               0x1024
+#define WM8962_WRITE_SEQUENCER_37               0x1025
+#define WM8962_WRITE_SEQUENCER_38               0x1026
+#define WM8962_WRITE_SEQUENCER_39               0x1027
+#define WM8962_WRITE_SEQUENCER_40               0x1028
+#define WM8962_WRITE_SEQUENCER_41               0x1029
+#define WM8962_WRITE_SEQUENCER_42               0x102A
+#define WM8962_WRITE_SEQUENCER_43               0x102B
+#define WM8962_WRITE_SEQUENCER_44               0x102C
+#define WM8962_WRITE_SEQUENCER_45               0x102D
+#define WM8962_WRITE_SEQUENCER_46               0x102E
+#define WM8962_WRITE_SEQUENCER_47               0x102F
+#define WM8962_WRITE_SEQUENCER_48               0x1030
+#define WM8962_WRITE_SEQUENCER_49               0x1031
+#define WM8962_WRITE_SEQUENCER_50               0x1032
+#define WM8962_WRITE_SEQUENCER_51               0x1033
+#define WM8962_WRITE_SEQUENCER_52               0x1034
+#define WM8962_WRITE_SEQUENCER_53               0x1035
+#define WM8962_WRITE_SEQUENCER_54               0x1036
+#define WM8962_WRITE_SEQUENCER_55               0x1037
+#define WM8962_WRITE_SEQUENCER_56               0x1038
+#define WM8962_WRITE_SEQUENCER_57               0x1039
+#define WM8962_WRITE_SEQUENCER_58               0x103A
+#define WM8962_WRITE_SEQUENCER_59               0x103B
+#define WM8962_WRITE_SEQUENCER_60               0x103C
+#define WM8962_WRITE_SEQUENCER_61               0x103D
+#define WM8962_WRITE_SEQUENCER_62               0x103E
+#define WM8962_WRITE_SEQUENCER_63               0x103F
+#define WM8962_WRITE_SEQUENCER_64               0x1040
+#define WM8962_WRITE_SEQUENCER_65               0x1041
+#define WM8962_WRITE_SEQUENCER_66               0x1042
+#define WM8962_WRITE_SEQUENCER_67               0x1043
+#define WM8962_WRITE_SEQUENCER_68               0x1044
+#define WM8962_WRITE_SEQUENCER_69               0x1045
+#define WM8962_WRITE_SEQUENCER_70               0x1046
+#define WM8962_WRITE_SEQUENCER_71               0x1047
+#define WM8962_WRITE_SEQUENCER_72               0x1048
+#define WM8962_WRITE_SEQUENCER_73               0x1049
+#define WM8962_WRITE_SEQUENCER_74               0x104A
+#define WM8962_WRITE_SEQUENCER_75               0x104B
+#define WM8962_WRITE_SEQUENCER_76               0x104C
+#define WM8962_WRITE_SEQUENCER_77               0x104D
+#define WM8962_WRITE_SEQUENCER_78               0x104E
+#define WM8962_WRITE_SEQUENCER_79               0x104F
+#define WM8962_WRITE_SEQUENCER_80               0x1050
+#define WM8962_WRITE_SEQUENCER_81               0x1051
+#define WM8962_WRITE_SEQUENCER_82               0x1052
+#define WM8962_WRITE_SEQUENCER_83               0x1053
+#define WM8962_WRITE_SEQUENCER_84               0x1054
+#define WM8962_WRITE_SEQUENCER_85               0x1055
+#define WM8962_WRITE_SEQUENCER_86               0x1056
+#define WM8962_WRITE_SEQUENCER_87               0x1057
+#define WM8962_WRITE_SEQUENCER_88               0x1058
+#define WM8962_WRITE_SEQUENCER_89               0x1059
+#define WM8962_WRITE_SEQUENCER_90               0x105A
+#define WM8962_WRITE_SEQUENCER_91               0x105B
+#define WM8962_WRITE_SEQUENCER_92               0x105C
+#define WM8962_WRITE_SEQUENCER_93               0x105D
+#define WM8962_WRITE_SEQUENCER_94               0x105E
+#define WM8962_WRITE_SEQUENCER_95               0x105F
+#define WM8962_WRITE_SEQUENCER_96               0x1060
+#define WM8962_WRITE_SEQUENCER_97               0x1061
+#define WM8962_WRITE_SEQUENCER_98               0x1062
+#define WM8962_WRITE_SEQUENCER_99               0x1063
+#define WM8962_WRITE_SEQUENCER_100              0x1064
+#define WM8962_WRITE_SEQUENCER_101              0x1065
+#define WM8962_WRITE_SEQUENCER_102              0x1066
+#define WM8962_WRITE_SEQUENCER_103              0x1067
+#define WM8962_WRITE_SEQUENCER_104              0x1068
+#define WM8962_WRITE_SEQUENCER_105              0x1069
+#define WM8962_WRITE_SEQUENCER_106              0x106A
+#define WM8962_WRITE_SEQUENCER_107              0x106B
+#define WM8962_WRITE_SEQUENCER_108              0x106C
+#define WM8962_WRITE_SEQUENCER_109              0x106D
+#define WM8962_WRITE_SEQUENCER_110              0x106E
+#define WM8962_WRITE_SEQUENCER_111              0x106F
+#define WM8962_WRITE_SEQUENCER_112              0x1070
+#define WM8962_WRITE_SEQUENCER_113              0x1071
+#define WM8962_WRITE_SEQUENCER_114              0x1072
+#define WM8962_WRITE_SEQUENCER_115              0x1073
+#define WM8962_WRITE_SEQUENCER_116              0x1074
+#define WM8962_WRITE_SEQUENCER_117              0x1075
+#define WM8962_WRITE_SEQUENCER_118              0x1076
+#define WM8962_WRITE_SEQUENCER_119              0x1077
+#define WM8962_WRITE_SEQUENCER_120              0x1078
+#define WM8962_WRITE_SEQUENCER_121              0x1079
+#define WM8962_WRITE_SEQUENCER_122              0x107A
+#define WM8962_WRITE_SEQUENCER_123              0x107B
+#define WM8962_WRITE_SEQUENCER_124              0x107C
+#define WM8962_WRITE_SEQUENCER_125              0x107D
+#define WM8962_WRITE_SEQUENCER_126              0x107E
+#define WM8962_WRITE_SEQUENCER_127              0x107F
+#define WM8962_WRITE_SEQUENCER_128              0x1080
+#define WM8962_WRITE_SEQUENCER_129              0x1081
+#define WM8962_WRITE_SEQUENCER_130              0x1082
+#define WM8962_WRITE_SEQUENCER_131              0x1083
+#define WM8962_WRITE_SEQUENCER_132              0x1084
+#define WM8962_WRITE_SEQUENCER_133              0x1085
+#define WM8962_WRITE_SEQUENCER_134              0x1086
+#define WM8962_WRITE_SEQUENCER_135              0x1087
+#define WM8962_WRITE_SEQUENCER_136              0x1088
+#define WM8962_WRITE_SEQUENCER_137              0x1089
+#define WM8962_WRITE_SEQUENCER_138              0x108A
+#define WM8962_WRITE_SEQUENCER_139              0x108B
+#define WM8962_WRITE_SEQUENCER_140              0x108C
+#define WM8962_WRITE_SEQUENCER_141              0x108D
+#define WM8962_WRITE_SEQUENCER_142              0x108E
+#define WM8962_WRITE_SEQUENCER_143              0x108F
+#define WM8962_WRITE_SEQUENCER_144              0x1090
+#define WM8962_WRITE_SEQUENCER_145              0x1091
+#define WM8962_WRITE_SEQUENCER_146              0x1092
+#define WM8962_WRITE_SEQUENCER_147              0x1093
+#define WM8962_WRITE_SEQUENCER_148              0x1094
+#define WM8962_WRITE_SEQUENCER_149              0x1095
+#define WM8962_WRITE_SEQUENCER_150              0x1096
+#define WM8962_WRITE_SEQUENCER_151              0x1097
+#define WM8962_WRITE_SEQUENCER_152              0x1098
+#define WM8962_WRITE_SEQUENCER_153              0x1099
+#define WM8962_WRITE_SEQUENCER_154              0x109A
+#define WM8962_WRITE_SEQUENCER_155              0x109B
+#define WM8962_WRITE_SEQUENCER_156              0x109C
+#define WM8962_WRITE_SEQUENCER_157              0x109D
+#define WM8962_WRITE_SEQUENCER_158              0x109E
+#define WM8962_WRITE_SEQUENCER_159              0x109F
+#define WM8962_WRITE_SEQUENCER_160              0x10A0
+#define WM8962_WRITE_SEQUENCER_161              0x10A1
+#define WM8962_WRITE_SEQUENCER_162              0x10A2
+#define WM8962_WRITE_SEQUENCER_163              0x10A3
+#define WM8962_WRITE_SEQUENCER_164              0x10A4
+#define WM8962_WRITE_SEQUENCER_165              0x10A5
+#define WM8962_WRITE_SEQUENCER_166              0x10A6
+#define WM8962_WRITE_SEQUENCER_167              0x10A7
+#define WM8962_WRITE_SEQUENCER_168              0x10A8
+#define WM8962_WRITE_SEQUENCER_169              0x10A9
+#define WM8962_WRITE_SEQUENCER_170              0x10AA
+#define WM8962_WRITE_SEQUENCER_171              0x10AB
+#define WM8962_WRITE_SEQUENCER_172              0x10AC
+#define WM8962_WRITE_SEQUENCER_173              0x10AD
+#define WM8962_WRITE_SEQUENCER_174              0x10AE
+#define WM8962_WRITE_SEQUENCER_175              0x10AF
+#define WM8962_WRITE_SEQUENCER_176              0x10B0
+#define WM8962_WRITE_SEQUENCER_177              0x10B1
+#define WM8962_WRITE_SEQUENCER_178              0x10B2
+#define WM8962_WRITE_SEQUENCER_179              0x10B3
+#define WM8962_WRITE_SEQUENCER_180              0x10B4
+#define WM8962_WRITE_SEQUENCER_181              0x10B5
+#define WM8962_WRITE_SEQUENCER_182              0x10B6
+#define WM8962_WRITE_SEQUENCER_183              0x10B7
+#define WM8962_WRITE_SEQUENCER_184              0x10B8
+#define WM8962_WRITE_SEQUENCER_185              0x10B9
+#define WM8962_WRITE_SEQUENCER_186              0x10BA
+#define WM8962_WRITE_SEQUENCER_187              0x10BB
+#define WM8962_WRITE_SEQUENCER_188              0x10BC
+#define WM8962_WRITE_SEQUENCER_189              0x10BD
+#define WM8962_WRITE_SEQUENCER_190              0x10BE
+#define WM8962_WRITE_SEQUENCER_191              0x10BF
+#define WM8962_WRITE_SEQUENCER_192              0x10C0
+#define WM8962_WRITE_SEQUENCER_193              0x10C1
+#define WM8962_WRITE_SEQUENCER_194              0x10C2
+#define WM8962_WRITE_SEQUENCER_195              0x10C3
+#define WM8962_WRITE_SEQUENCER_196              0x10C4
+#define WM8962_WRITE_SEQUENCER_197              0x10C5
+#define WM8962_WRITE_SEQUENCER_198              0x10C6
+#define WM8962_WRITE_SEQUENCER_199              0x10C7
+#define WM8962_WRITE_SEQUENCER_200              0x10C8
+#define WM8962_WRITE_SEQUENCER_201              0x10C9
+#define WM8962_WRITE_SEQUENCER_202              0x10CA
+#define WM8962_WRITE_SEQUENCER_203              0x10CB
+#define WM8962_WRITE_SEQUENCER_204              0x10CC
+#define WM8962_WRITE_SEQUENCER_205              0x10CD
+#define WM8962_WRITE_SEQUENCER_206              0x10CE
+#define WM8962_WRITE_SEQUENCER_207              0x10CF
+#define WM8962_WRITE_SEQUENCER_208              0x10D0
+#define WM8962_WRITE_SEQUENCER_209              0x10D1
+#define WM8962_WRITE_SEQUENCER_210              0x10D2
+#define WM8962_WRITE_SEQUENCER_211              0x10D3
+#define WM8962_WRITE_SEQUENCER_212              0x10D4
+#define WM8962_WRITE_SEQUENCER_213              0x10D5
+#define WM8962_WRITE_SEQUENCER_214              0x10D6
+#define WM8962_WRITE_SEQUENCER_215              0x10D7
+#define WM8962_WRITE_SEQUENCER_216              0x10D8
+#define WM8962_WRITE_SEQUENCER_217              0x10D9
+#define WM8962_WRITE_SEQUENCER_218              0x10DA
+#define WM8962_WRITE_SEQUENCER_219              0x10DB
+#define WM8962_WRITE_SEQUENCER_220              0x10DC
+#define WM8962_WRITE_SEQUENCER_221              0x10DD
+#define WM8962_WRITE_SEQUENCER_222              0x10DE
+#define WM8962_WRITE_SEQUENCER_223              0x10DF
+#define WM8962_WRITE_SEQUENCER_224              0x10E0
+#define WM8962_WRITE_SEQUENCER_225              0x10E1
+#define WM8962_WRITE_SEQUENCER_226              0x10E2
+#define WM8962_WRITE_SEQUENCER_227              0x10E3
+#define WM8962_WRITE_SEQUENCER_228              0x10E4
+#define WM8962_WRITE_SEQUENCER_229              0x10E5
+#define WM8962_WRITE_SEQUENCER_230              0x10E6
+#define WM8962_WRITE_SEQUENCER_231              0x10E7
+#define WM8962_WRITE_SEQUENCER_232              0x10E8
+#define WM8962_WRITE_SEQUENCER_233              0x10E9
+#define WM8962_WRITE_SEQUENCER_234              0x10EA
+#define WM8962_WRITE_SEQUENCER_235              0x10EB
+#define WM8962_WRITE_SEQUENCER_236              0x10EC
+#define WM8962_WRITE_SEQUENCER_237              0x10ED
+#define WM8962_WRITE_SEQUENCER_238              0x10EE
+#define WM8962_WRITE_SEQUENCER_239              0x10EF
+#define WM8962_WRITE_SEQUENCER_240              0x10F0
+#define WM8962_WRITE_SEQUENCER_241              0x10F1
+#define WM8962_WRITE_SEQUENCER_242              0x10F2
+#define WM8962_WRITE_SEQUENCER_243              0x10F3
+#define WM8962_WRITE_SEQUENCER_244              0x10F4
+#define WM8962_WRITE_SEQUENCER_245              0x10F5
+#define WM8962_WRITE_SEQUENCER_246              0x10F6
+#define WM8962_WRITE_SEQUENCER_247              0x10F7
+#define WM8962_WRITE_SEQUENCER_248              0x10F8
+#define WM8962_WRITE_SEQUENCER_249              0x10F9
+#define WM8962_WRITE_SEQUENCER_250              0x10FA
+#define WM8962_WRITE_SEQUENCER_251              0x10FB
+#define WM8962_WRITE_SEQUENCER_252              0x10FC
+#define WM8962_WRITE_SEQUENCER_253              0x10FD
+#define WM8962_WRITE_SEQUENCER_254              0x10FE
+#define WM8962_WRITE_SEQUENCER_255              0x10FF
+#define WM8962_WRITE_SEQUENCER_256              0x1100
+#define WM8962_WRITE_SEQUENCER_257              0x1101
+#define WM8962_WRITE_SEQUENCER_258              0x1102
+#define WM8962_WRITE_SEQUENCER_259              0x1103
+#define WM8962_WRITE_SEQUENCER_260              0x1104
+#define WM8962_WRITE_SEQUENCER_261              0x1105
+#define WM8962_WRITE_SEQUENCER_262              0x1106
+#define WM8962_WRITE_SEQUENCER_263              0x1107
+#define WM8962_WRITE_SEQUENCER_264              0x1108
+#define WM8962_WRITE_SEQUENCER_265              0x1109
+#define WM8962_WRITE_SEQUENCER_266              0x110A
+#define WM8962_WRITE_SEQUENCER_267              0x110B
+#define WM8962_WRITE_SEQUENCER_268              0x110C
+#define WM8962_WRITE_SEQUENCER_269              0x110D
+#define WM8962_WRITE_SEQUENCER_270              0x110E
+#define WM8962_WRITE_SEQUENCER_271              0x110F
+#define WM8962_WRITE_SEQUENCER_272              0x1110
+#define WM8962_WRITE_SEQUENCER_273              0x1111
+#define WM8962_WRITE_SEQUENCER_274              0x1112
+#define WM8962_WRITE_SEQUENCER_275              0x1113
+#define WM8962_WRITE_SEQUENCER_276              0x1114
+#define WM8962_WRITE_SEQUENCER_277              0x1115
+#define WM8962_WRITE_SEQUENCER_278              0x1116
+#define WM8962_WRITE_SEQUENCER_279              0x1117
+#define WM8962_WRITE_SEQUENCER_280              0x1118
+#define WM8962_WRITE_SEQUENCER_281              0x1119
+#define WM8962_WRITE_SEQUENCER_282              0x111A
+#define WM8962_WRITE_SEQUENCER_283              0x111B
+#define WM8962_WRITE_SEQUENCER_284              0x111C
+#define WM8962_WRITE_SEQUENCER_285              0x111D
+#define WM8962_WRITE_SEQUENCER_286              0x111E
+#define WM8962_WRITE_SEQUENCER_287              0x111F
+#define WM8962_WRITE_SEQUENCER_288              0x1120
+#define WM8962_WRITE_SEQUENCER_289              0x1121
+#define WM8962_WRITE_SEQUENCER_290              0x1122
+#define WM8962_WRITE_SEQUENCER_291              0x1123
+#define WM8962_WRITE_SEQUENCER_292              0x1124
+#define WM8962_WRITE_SEQUENCER_293              0x1125
+#define WM8962_WRITE_SEQUENCER_294              0x1126
+#define WM8962_WRITE_SEQUENCER_295              0x1127
+#define WM8962_WRITE_SEQUENCER_296              0x1128
+#define WM8962_WRITE_SEQUENCER_297              0x1129
+#define WM8962_WRITE_SEQUENCER_298              0x112A
+#define WM8962_WRITE_SEQUENCER_299              0x112B
+#define WM8962_WRITE_SEQUENCER_300              0x112C
+#define WM8962_WRITE_SEQUENCER_301              0x112D
+#define WM8962_WRITE_SEQUENCER_302              0x112E
+#define WM8962_WRITE_SEQUENCER_303              0x112F
+#define WM8962_WRITE_SEQUENCER_304              0x1130
+#define WM8962_WRITE_SEQUENCER_305              0x1131
+#define WM8962_WRITE_SEQUENCER_306              0x1132
+#define WM8962_WRITE_SEQUENCER_307              0x1133
+#define WM8962_WRITE_SEQUENCER_308              0x1134
+#define WM8962_WRITE_SEQUENCER_309              0x1135
+#define WM8962_WRITE_SEQUENCER_310              0x1136
+#define WM8962_WRITE_SEQUENCER_311              0x1137
+#define WM8962_WRITE_SEQUENCER_312              0x1138
+#define WM8962_WRITE_SEQUENCER_313              0x1139
+#define WM8962_WRITE_SEQUENCER_314              0x113A
+#define WM8962_WRITE_SEQUENCER_315              0x113B
+#define WM8962_WRITE_SEQUENCER_316              0x113C
+#define WM8962_WRITE_SEQUENCER_317              0x113D
+#define WM8962_WRITE_SEQUENCER_318              0x113E
+#define WM8962_WRITE_SEQUENCER_319              0x113F
+#define WM8962_WRITE_SEQUENCER_320              0x1140
+#define WM8962_WRITE_SEQUENCER_321              0x1141
+#define WM8962_WRITE_SEQUENCER_322              0x1142
+#define WM8962_WRITE_SEQUENCER_323              0x1143
+#define WM8962_WRITE_SEQUENCER_324              0x1144
+#define WM8962_WRITE_SEQUENCER_325              0x1145
+#define WM8962_WRITE_SEQUENCER_326              0x1146
+#define WM8962_WRITE_SEQUENCER_327              0x1147
+#define WM8962_WRITE_SEQUENCER_328              0x1148
+#define WM8962_WRITE_SEQUENCER_329              0x1149
+#define WM8962_WRITE_SEQUENCER_330              0x114A
+#define WM8962_WRITE_SEQUENCER_331              0x114B
+#define WM8962_WRITE_SEQUENCER_332              0x114C
+#define WM8962_WRITE_SEQUENCER_333              0x114D
+#define WM8962_WRITE_SEQUENCER_334              0x114E
+#define WM8962_WRITE_SEQUENCER_335              0x114F
+#define WM8962_WRITE_SEQUENCER_336              0x1150
+#define WM8962_WRITE_SEQUENCER_337              0x1151
+#define WM8962_WRITE_SEQUENCER_338              0x1152
+#define WM8962_WRITE_SEQUENCER_339              0x1153
+#define WM8962_WRITE_SEQUENCER_340              0x1154
+#define WM8962_WRITE_SEQUENCER_341              0x1155
+#define WM8962_WRITE_SEQUENCER_342              0x1156
+#define WM8962_WRITE_SEQUENCER_343              0x1157
+#define WM8962_WRITE_SEQUENCER_344              0x1158
+#define WM8962_WRITE_SEQUENCER_345              0x1159
+#define WM8962_WRITE_SEQUENCER_346              0x115A
+#define WM8962_WRITE_SEQUENCER_347              0x115B
+#define WM8962_WRITE_SEQUENCER_348              0x115C
+#define WM8962_WRITE_SEQUENCER_349              0x115D
+#define WM8962_WRITE_SEQUENCER_350              0x115E
+#define WM8962_WRITE_SEQUENCER_351              0x115F
+#define WM8962_WRITE_SEQUENCER_352              0x1160
+#define WM8962_WRITE_SEQUENCER_353              0x1161
+#define WM8962_WRITE_SEQUENCER_354              0x1162
+#define WM8962_WRITE_SEQUENCER_355              0x1163
+#define WM8962_WRITE_SEQUENCER_356              0x1164
+#define WM8962_WRITE_SEQUENCER_357              0x1165
+#define WM8962_WRITE_SEQUENCER_358              0x1166
+#define WM8962_WRITE_SEQUENCER_359              0x1167
+#define WM8962_WRITE_SEQUENCER_360              0x1168
+#define WM8962_WRITE_SEQUENCER_361              0x1169
+#define WM8962_WRITE_SEQUENCER_362              0x116A
+#define WM8962_WRITE_SEQUENCER_363              0x116B
+#define WM8962_WRITE_SEQUENCER_364              0x116C
+#define WM8962_WRITE_SEQUENCER_365              0x116D
+#define WM8962_WRITE_SEQUENCER_366              0x116E
+#define WM8962_WRITE_SEQUENCER_367              0x116F
+#define WM8962_WRITE_SEQUENCER_368              0x1170
+#define WM8962_WRITE_SEQUENCER_369              0x1171
+#define WM8962_WRITE_SEQUENCER_370              0x1172
+#define WM8962_WRITE_SEQUENCER_371              0x1173
+#define WM8962_WRITE_SEQUENCER_372              0x1174
+#define WM8962_WRITE_SEQUENCER_373              0x1175
+#define WM8962_WRITE_SEQUENCER_374              0x1176
+#define WM8962_WRITE_SEQUENCER_375              0x1177
+#define WM8962_WRITE_SEQUENCER_376              0x1178
+#define WM8962_WRITE_SEQUENCER_377              0x1179
+#define WM8962_WRITE_SEQUENCER_378              0x117A
+#define WM8962_WRITE_SEQUENCER_379              0x117B
+#define WM8962_WRITE_SEQUENCER_380              0x117C
+#define WM8962_WRITE_SEQUENCER_381              0x117D
+#define WM8962_WRITE_SEQUENCER_382              0x117E
+#define WM8962_WRITE_SEQUENCER_383              0x117F
+#define WM8962_WRITE_SEQUENCER_384              0x1180
+#define WM8962_WRITE_SEQUENCER_385              0x1181
+#define WM8962_WRITE_SEQUENCER_386              0x1182
+#define WM8962_WRITE_SEQUENCER_387              0x1183
+#define WM8962_WRITE_SEQUENCER_388              0x1184
+#define WM8962_WRITE_SEQUENCER_389              0x1185
+#define WM8962_WRITE_SEQUENCER_390              0x1186
+#define WM8962_WRITE_SEQUENCER_391              0x1187
+#define WM8962_WRITE_SEQUENCER_392              0x1188
+#define WM8962_WRITE_SEQUENCER_393              0x1189
+#define WM8962_WRITE_SEQUENCER_394              0x118A
+#define WM8962_WRITE_SEQUENCER_395              0x118B
+#define WM8962_WRITE_SEQUENCER_396              0x118C
+#define WM8962_WRITE_SEQUENCER_397              0x118D
+#define WM8962_WRITE_SEQUENCER_398              0x118E
+#define WM8962_WRITE_SEQUENCER_399              0x118F
+#define WM8962_WRITE_SEQUENCER_400              0x1190
+#define WM8962_WRITE_SEQUENCER_401              0x1191
+#define WM8962_WRITE_SEQUENCER_402              0x1192
+#define WM8962_WRITE_SEQUENCER_403              0x1193
+#define WM8962_WRITE_SEQUENCER_404              0x1194
+#define WM8962_WRITE_SEQUENCER_405              0x1195
+#define WM8962_WRITE_SEQUENCER_406              0x1196
+#define WM8962_WRITE_SEQUENCER_407              0x1197
+#define WM8962_WRITE_SEQUENCER_408              0x1198
+#define WM8962_WRITE_SEQUENCER_409              0x1199
+#define WM8962_WRITE_SEQUENCER_410              0x119A
+#define WM8962_WRITE_SEQUENCER_411              0x119B
+#define WM8962_WRITE_SEQUENCER_412              0x119C
+#define WM8962_WRITE_SEQUENCER_413              0x119D
+#define WM8962_WRITE_SEQUENCER_414              0x119E
+#define WM8962_WRITE_SEQUENCER_415              0x119F
+#define WM8962_WRITE_SEQUENCER_416              0x11A0
+#define WM8962_WRITE_SEQUENCER_417              0x11A1
+#define WM8962_WRITE_SEQUENCER_418              0x11A2
+#define WM8962_WRITE_SEQUENCER_419              0x11A3
+#define WM8962_WRITE_SEQUENCER_420              0x11A4
+#define WM8962_WRITE_SEQUENCER_421              0x11A5
+#define WM8962_WRITE_SEQUENCER_422              0x11A6
+#define WM8962_WRITE_SEQUENCER_423              0x11A7
+#define WM8962_WRITE_SEQUENCER_424              0x11A8
+#define WM8962_WRITE_SEQUENCER_425              0x11A9
+#define WM8962_WRITE_SEQUENCER_426              0x11AA
+#define WM8962_WRITE_SEQUENCER_427              0x11AB
+#define WM8962_WRITE_SEQUENCER_428              0x11AC
+#define WM8962_WRITE_SEQUENCER_429              0x11AD
+#define WM8962_WRITE_SEQUENCER_430              0x11AE
+#define WM8962_WRITE_SEQUENCER_431              0x11AF
+#define WM8962_WRITE_SEQUENCER_432              0x11B0
+#define WM8962_WRITE_SEQUENCER_433              0x11B1
+#define WM8962_WRITE_SEQUENCER_434              0x11B2
+#define WM8962_WRITE_SEQUENCER_435              0x11B3
+#define WM8962_WRITE_SEQUENCER_436              0x11B4
+#define WM8962_WRITE_SEQUENCER_437              0x11B5
+#define WM8962_WRITE_SEQUENCER_438              0x11B6
+#define WM8962_WRITE_SEQUENCER_439              0x11B7
+#define WM8962_WRITE_SEQUENCER_440              0x11B8
+#define WM8962_WRITE_SEQUENCER_441              0x11B9
+#define WM8962_WRITE_SEQUENCER_442              0x11BA
+#define WM8962_WRITE_SEQUENCER_443              0x11BB
+#define WM8962_WRITE_SEQUENCER_444              0x11BC
+#define WM8962_WRITE_SEQUENCER_445              0x11BD
+#define WM8962_WRITE_SEQUENCER_446              0x11BE
+#define WM8962_WRITE_SEQUENCER_447              0x11BF
+#define WM8962_WRITE_SEQUENCER_448              0x11C0
+#define WM8962_WRITE_SEQUENCER_449              0x11C1
+#define WM8962_WRITE_SEQUENCER_450              0x11C2
+#define WM8962_WRITE_SEQUENCER_451              0x11C3
+#define WM8962_WRITE_SEQUENCER_452              0x11C4
+#define WM8962_WRITE_SEQUENCER_453              0x11C5
+#define WM8962_WRITE_SEQUENCER_454              0x11C6
+#define WM8962_WRITE_SEQUENCER_455              0x11C7
+#define WM8962_WRITE_SEQUENCER_456              0x11C8
+#define WM8962_WRITE_SEQUENCER_457              0x11C9
+#define WM8962_WRITE_SEQUENCER_458              0x11CA
+#define WM8962_WRITE_SEQUENCER_459              0x11CB
+#define WM8962_WRITE_SEQUENCER_460              0x11CC
+#define WM8962_WRITE_SEQUENCER_461              0x11CD
+#define WM8962_WRITE_SEQUENCER_462              0x11CE
+#define WM8962_WRITE_SEQUENCER_463              0x11CF
+#define WM8962_WRITE_SEQUENCER_464              0x11D0
+#define WM8962_WRITE_SEQUENCER_465              0x11D1
+#define WM8962_WRITE_SEQUENCER_466              0x11D2
+#define WM8962_WRITE_SEQUENCER_467              0x11D3
+#define WM8962_WRITE_SEQUENCER_468              0x11D4
+#define WM8962_WRITE_SEQUENCER_469              0x11D5
+#define WM8962_WRITE_SEQUENCER_470              0x11D6
+#define WM8962_WRITE_SEQUENCER_471              0x11D7
+#define WM8962_WRITE_SEQUENCER_472              0x11D8
+#define WM8962_WRITE_SEQUENCER_473              0x11D9
+#define WM8962_WRITE_SEQUENCER_474              0x11DA
+#define WM8962_WRITE_SEQUENCER_475              0x11DB
+#define WM8962_WRITE_SEQUENCER_476              0x11DC
+#define WM8962_WRITE_SEQUENCER_477              0x11DD
+#define WM8962_WRITE_SEQUENCER_478              0x11DE
+#define WM8962_WRITE_SEQUENCER_479              0x11DF
+#define WM8962_WRITE_SEQUENCER_480              0x11E0
+#define WM8962_WRITE_SEQUENCER_481              0x11E1
+#define WM8962_WRITE_SEQUENCER_482              0x11E2
+#define WM8962_WRITE_SEQUENCER_483              0x11E3
+#define WM8962_WRITE_SEQUENCER_484              0x11E4
+#define WM8962_WRITE_SEQUENCER_485              0x11E5
+#define WM8962_WRITE_SEQUENCER_486              0x11E6
+#define WM8962_WRITE_SEQUENCER_487              0x11E7
+#define WM8962_WRITE_SEQUENCER_488              0x11E8
+#define WM8962_WRITE_SEQUENCER_489              0x11E9
+#define WM8962_WRITE_SEQUENCER_490              0x11EA
+#define WM8962_WRITE_SEQUENCER_491              0x11EB
+#define WM8962_WRITE_SEQUENCER_492              0x11EC
+#define WM8962_WRITE_SEQUENCER_493              0x11ED
+#define WM8962_WRITE_SEQUENCER_494              0x11EE
+#define WM8962_WRITE_SEQUENCER_495              0x11EF
+#define WM8962_WRITE_SEQUENCER_496              0x11F0
+#define WM8962_WRITE_SEQUENCER_497              0x11F1
+#define WM8962_WRITE_SEQUENCER_498              0x11F2
+#define WM8962_WRITE_SEQUENCER_499              0x11F3
+#define WM8962_WRITE_SEQUENCER_500              0x11F4
+#define WM8962_WRITE_SEQUENCER_501              0x11F5
+#define WM8962_WRITE_SEQUENCER_502              0x11F6
+#define WM8962_WRITE_SEQUENCER_503              0x11F7
+#define WM8962_WRITE_SEQUENCER_504              0x11F8
+#define WM8962_WRITE_SEQUENCER_505              0x11F9
+#define WM8962_WRITE_SEQUENCER_506              0x11FA
+#define WM8962_WRITE_SEQUENCER_507              0x11FB
+#define WM8962_WRITE_SEQUENCER_508              0x11FC
+#define WM8962_WRITE_SEQUENCER_509              0x11FD
+#define WM8962_WRITE_SEQUENCER_510              0x11FE
+#define WM8962_WRITE_SEQUENCER_511              0x11FF
+#define WM8962_DSP2_INSTRUCTION_RAM_0           0x2000
+#define WM8962_DSP2_ADDRESS_RAM_2               0x2400
+#define WM8962_DSP2_ADDRESS_RAM_1               0x2401
+#define WM8962_DSP2_ADDRESS_RAM_0               0x2402
+#define WM8962_DSP2_DATA1_RAM_1                 0x3000
+#define WM8962_DSP2_DATA1_RAM_0                 0x3001
+#define WM8962_DSP2_DATA2_RAM_1                 0x3400
+#define WM8962_DSP2_DATA2_RAM_0                 0x3401
+#define WM8962_DSP2_DATA3_RAM_1                 0x3800
+#define WM8962_DSP2_DATA3_RAM_0                 0x3801
+#define WM8962_DSP2_COEFF_RAM_0                 0x3C00
+#define WM8962_RETUNEADC_SHARED_COEFF_1         0x4000
+#define WM8962_RETUNEADC_SHARED_COEFF_0         0x4001
+#define WM8962_RETUNEDAC_SHARED_COEFF_1         0x4002
+#define WM8962_RETUNEDAC_SHARED_COEFF_0         0x4003
+#define WM8962_SOUNDSTAGE_ENABLES_1             0x4004
+#define WM8962_SOUNDSTAGE_ENABLES_0             0x4005
+#define WM8962_HDBASS_AI_1                      0x4200
+#define WM8962_HDBASS_AI_0                      0x4201
+#define WM8962_HDBASS_AR_1                      0x4202
+#define WM8962_HDBASS_AR_0                      0x4203
+#define WM8962_HDBASS_B_1                       0x4204
+#define WM8962_HDBASS_B_0                       0x4205
+#define WM8962_HDBASS_K_1                       0x4206
+#define WM8962_HDBASS_K_0                       0x4207
+#define WM8962_HDBASS_N1_1                      0x4208
+#define WM8962_HDBASS_N1_0                      0x4209
+#define WM8962_HDBASS_N2_1                      0x420A
+#define WM8962_HDBASS_N2_0                      0x420B
+#define WM8962_HDBASS_N3_1                      0x420C
+#define WM8962_HDBASS_N3_0                      0x420D
+#define WM8962_HDBASS_N4_1                      0x420E
+#define WM8962_HDBASS_N4_0                      0x420F
+#define WM8962_HDBASS_N5_1                      0x4210
+#define WM8962_HDBASS_N5_0                      0x4211
+#define WM8962_HDBASS_X1_1                      0x4212
+#define WM8962_HDBASS_X1_0                      0x4213
+#define WM8962_HDBASS_X2_1                      0x4214
+#define WM8962_HDBASS_X2_0                      0x4215
+#define WM8962_HDBASS_X3_1                      0x4216
+#define WM8962_HDBASS_X3_0                      0x4217
+#define WM8962_HDBASS_ATK_1                     0x4218
+#define WM8962_HDBASS_ATK_0                     0x4219
+#define WM8962_HDBASS_DCY_1                     0x421A
+#define WM8962_HDBASS_DCY_0                     0x421B
+#define WM8962_HDBASS_PG_1                      0x421C
+#define WM8962_HDBASS_PG_0                      0x421D
+#define WM8962_HPF_C_1                          0x4400
+#define WM8962_HPF_C_0                          0x4401
+#define WM8962_ADCL_RETUNE_C1_1                 0x4600
+#define WM8962_ADCL_RETUNE_C1_0                 0x4601
+#define WM8962_ADCL_RETUNE_C2_1                 0x4602
+#define WM8962_ADCL_RETUNE_C2_0                 0x4603
+#define WM8962_ADCL_RETUNE_C3_1                 0x4604
+#define WM8962_ADCL_RETUNE_C3_0                 0x4605
+#define WM8962_ADCL_RETUNE_C4_1                 0x4606
+#define WM8962_ADCL_RETUNE_C4_0                 0x4607
+#define WM8962_ADCL_RETUNE_C5_1                 0x4608
+#define WM8962_ADCL_RETUNE_C5_0                 0x4609
+#define WM8962_ADCL_RETUNE_C6_1                 0x460A
+#define WM8962_ADCL_RETUNE_C6_0                 0x460B
+#define WM8962_ADCL_RETUNE_C7_1                 0x460C
+#define WM8962_ADCL_RETUNE_C7_0                 0x460D
+#define WM8962_ADCL_RETUNE_C8_1                 0x460E
+#define WM8962_ADCL_RETUNE_C8_0                 0x460F
+#define WM8962_ADCL_RETUNE_C9_1                 0x4610
+#define WM8962_ADCL_RETUNE_C9_0                 0x4611
+#define WM8962_ADCL_RETUNE_C10_1                0x4612
+#define WM8962_ADCL_RETUNE_C10_0                0x4613
+#define WM8962_ADCL_RETUNE_C11_1                0x4614
+#define WM8962_ADCL_RETUNE_C11_0                0x4615
+#define WM8962_ADCL_RETUNE_C12_1                0x4616
+#define WM8962_ADCL_RETUNE_C12_0                0x4617
+#define WM8962_ADCL_RETUNE_C13_1                0x4618
+#define WM8962_ADCL_RETUNE_C13_0                0x4619
+#define WM8962_ADCL_RETUNE_C14_1                0x461A
+#define WM8962_ADCL_RETUNE_C14_0                0x461B
+#define WM8962_ADCL_RETUNE_C15_1                0x461C
+#define WM8962_ADCL_RETUNE_C15_0                0x461D
+#define WM8962_ADCL_RETUNE_C16_1                0x461E
+#define WM8962_ADCL_RETUNE_C16_0                0x461F
+#define WM8962_ADCL_RETUNE_C17_1                0x4620
+#define WM8962_ADCL_RETUNE_C17_0                0x4621
+#define WM8962_ADCL_RETUNE_C18_1                0x4622
+#define WM8962_ADCL_RETUNE_C18_0                0x4623
+#define WM8962_ADCL_RETUNE_C19_1                0x4624
+#define WM8962_ADCL_RETUNE_C19_0                0x4625
+#define WM8962_ADCL_RETUNE_C20_1                0x4626
+#define WM8962_ADCL_RETUNE_C20_0                0x4627
+#define WM8962_ADCL_RETUNE_C21_1                0x4628
+#define WM8962_ADCL_RETUNE_C21_0                0x4629
+#define WM8962_ADCL_RETUNE_C22_1                0x462A
+#define WM8962_ADCL_RETUNE_C22_0                0x462B
+#define WM8962_ADCL_RETUNE_C23_1                0x462C
+#define WM8962_ADCL_RETUNE_C23_0                0x462D
+#define WM8962_ADCL_RETUNE_C24_1                0x462E
+#define WM8962_ADCL_RETUNE_C24_0                0x462F
+#define WM8962_ADCL_RETUNE_C25_1                0x4630
+#define WM8962_ADCL_RETUNE_C25_0                0x4631
+#define WM8962_ADCL_RETUNE_C26_1                0x4632
+#define WM8962_ADCL_RETUNE_C26_0                0x4633
+#define WM8962_ADCL_RETUNE_C27_1                0x4634
+#define WM8962_ADCL_RETUNE_C27_0                0x4635
+#define WM8962_ADCL_RETUNE_C28_1                0x4636
+#define WM8962_ADCL_RETUNE_C28_0                0x4637
+#define WM8962_ADCL_RETUNE_C29_1                0x4638
+#define WM8962_ADCL_RETUNE_C29_0                0x4639
+#define WM8962_ADCL_RETUNE_C30_1                0x463A
+#define WM8962_ADCL_RETUNE_C30_0                0x463B
+#define WM8962_ADCL_RETUNE_C31_1                0x463C
+#define WM8962_ADCL_RETUNE_C31_0                0x463D
+#define WM8962_ADCL_RETUNE_C32_1                0x463E
+#define WM8962_ADCL_RETUNE_C32_0                0x463F
+#define WM8962_RETUNEADC_PG2_1                  0x4800
+#define WM8962_RETUNEADC_PG2_0                  0x4801
+#define WM8962_RETUNEADC_PG_1                   0x4802
+#define WM8962_RETUNEADC_PG_0                   0x4803
+#define WM8962_ADCR_RETUNE_C1_1                 0x4A00
+#define WM8962_ADCR_RETUNE_C1_0                 0x4A01
+#define WM8962_ADCR_RETUNE_C2_1                 0x4A02
+#define WM8962_ADCR_RETUNE_C2_0                 0x4A03
+#define WM8962_ADCR_RETUNE_C3_1                 0x4A04
+#define WM8962_ADCR_RETUNE_C3_0                 0x4A05
+#define WM8962_ADCR_RETUNE_C4_1                 0x4A06
+#define WM8962_ADCR_RETUNE_C4_0                 0x4A07
+#define WM8962_ADCR_RETUNE_C5_1                 0x4A08
+#define WM8962_ADCR_RETUNE_C5_0                 0x4A09
+#define WM8962_ADCR_RETUNE_C6_1                 0x4A0A
+#define WM8962_ADCR_RETUNE_C6_0                 0x4A0B
+#define WM8962_ADCR_RETUNE_C7_1                 0x4A0C
+#define WM8962_ADCR_RETUNE_C7_0                 0x4A0D
+#define WM8962_ADCR_RETUNE_C8_1                 0x4A0E
+#define WM8962_ADCR_RETUNE_C8_0                 0x4A0F
+#define WM8962_ADCR_RETUNE_C9_1                 0x4A10
+#define WM8962_ADCR_RETUNE_C9_0                 0x4A11
+#define WM8962_ADCR_RETUNE_C10_1                0x4A12
+#define WM8962_ADCR_RETUNE_C10_0                0x4A13
+#define WM8962_ADCR_RETUNE_C11_1                0x4A14
+#define WM8962_ADCR_RETUNE_C11_0                0x4A15
+#define WM8962_ADCR_RETUNE_C12_1                0x4A16
+#define WM8962_ADCR_RETUNE_C12_0                0x4A17
+#define WM8962_ADCR_RETUNE_C13_1                0x4A18
+#define WM8962_ADCR_RETUNE_C13_0                0x4A19
+#define WM8962_ADCR_RETUNE_C14_1                0x4A1A
+#define WM8962_ADCR_RETUNE_C14_0                0x4A1B
+#define WM8962_ADCR_RETUNE_C15_1                0x4A1C
+#define WM8962_ADCR_RETUNE_C15_0                0x4A1D
+#define WM8962_ADCR_RETUNE_C16_1                0x4A1E
+#define WM8962_ADCR_RETUNE_C16_0                0x4A1F
+#define WM8962_ADCR_RETUNE_C17_1                0x4A20
+#define WM8962_ADCR_RETUNE_C17_0                0x4A21
+#define WM8962_ADCR_RETUNE_C18_1                0x4A22
+#define WM8962_ADCR_RETUNE_C18_0                0x4A23
+#define WM8962_ADCR_RETUNE_C19_1                0x4A24
+#define WM8962_ADCR_RETUNE_C19_0                0x4A25
+#define WM8962_ADCR_RETUNE_C20_1                0x4A26
+#define WM8962_ADCR_RETUNE_C20_0                0x4A27
+#define WM8962_ADCR_RETUNE_C21_1                0x4A28
+#define WM8962_ADCR_RETUNE_C21_0                0x4A29
+#define WM8962_ADCR_RETUNE_C22_1                0x4A2A
+#define WM8962_ADCR_RETUNE_C22_0                0x4A2B
+#define WM8962_ADCR_RETUNE_C23_1                0x4A2C
+#define WM8962_ADCR_RETUNE_C23_0                0x4A2D
+#define WM8962_ADCR_RETUNE_C24_1                0x4A2E
+#define WM8962_ADCR_RETUNE_C24_0                0x4A2F
+#define WM8962_ADCR_RETUNE_C25_1                0x4A30
+#define WM8962_ADCR_RETUNE_C25_0                0x4A31
+#define WM8962_ADCR_RETUNE_C26_1                0x4A32
+#define WM8962_ADCR_RETUNE_C26_0                0x4A33
+#define WM8962_ADCR_RETUNE_C27_1                0x4A34
+#define WM8962_ADCR_RETUNE_C27_0                0x4A35
+#define WM8962_ADCR_RETUNE_C28_1                0x4A36
+#define WM8962_ADCR_RETUNE_C28_0                0x4A37
+#define WM8962_ADCR_RETUNE_C29_1                0x4A38
+#define WM8962_ADCR_RETUNE_C29_0                0x4A39
+#define WM8962_ADCR_RETUNE_C30_1                0x4A3A
+#define WM8962_ADCR_RETUNE_C30_0                0x4A3B
+#define WM8962_ADCR_RETUNE_C31_1                0x4A3C
+#define WM8962_ADCR_RETUNE_C31_0                0x4A3D
+#define WM8962_ADCR_RETUNE_C32_1                0x4A3E
+#define WM8962_ADCR_RETUNE_C32_0                0x4A3F
+#define WM8962_DACL_RETUNE_C1_1                 0x4C00
+#define WM8962_DACL_RETUNE_C1_0                 0x4C01
+#define WM8962_DACL_RETUNE_C2_1                 0x4C02
+#define WM8962_DACL_RETUNE_C2_0                 0x4C03
+#define WM8962_DACL_RETUNE_C3_1                 0x4C04
+#define WM8962_DACL_RETUNE_C3_0                 0x4C05
+#define WM8962_DACL_RETUNE_C4_1                 0x4C06
+#define WM8962_DACL_RETUNE_C4_0                 0x4C07
+#define WM8962_DACL_RETUNE_C5_1                 0x4C08
+#define WM8962_DACL_RETUNE_C5_0                 0x4C09
+#define WM8962_DACL_RETUNE_C6_1                 0x4C0A
+#define WM8962_DACL_RETUNE_C6_0                 0x4C0B
+#define WM8962_DACL_RETUNE_C7_1                 0x4C0C
+#define WM8962_DACL_RETUNE_C7_0                 0x4C0D
+#define WM8962_DACL_RETUNE_C8_1                 0x4C0E
+#define WM8962_DACL_RETUNE_C8_0                 0x4C0F
+#define WM8962_DACL_RETUNE_C9_1                 0x4C10
+#define WM8962_DACL_RETUNE_C9_0                 0x4C11
+#define WM8962_DACL_RETUNE_C10_1                0x4C12
+#define WM8962_DACL_RETUNE_C10_0                0x4C13
+#define WM8962_DACL_RETUNE_C11_1                0x4C14
+#define WM8962_DACL_RETUNE_C11_0                0x4C15
+#define WM8962_DACL_RETUNE_C12_1                0x4C16
+#define WM8962_DACL_RETUNE_C12_0                0x4C17
+#define WM8962_DACL_RETUNE_C13_1                0x4C18
+#define WM8962_DACL_RETUNE_C13_0                0x4C19
+#define WM8962_DACL_RETUNE_C14_1                0x4C1A
+#define WM8962_DACL_RETUNE_C14_0                0x4C1B
+#define WM8962_DACL_RETUNE_C15_1                0x4C1C
+#define WM8962_DACL_RETUNE_C15_0                0x4C1D
+#define WM8962_DACL_RETUNE_C16_1                0x4C1E
+#define WM8962_DACL_RETUNE_C16_0                0x4C1F
+#define WM8962_DACL_RETUNE_C17_1                0x4C20
+#define WM8962_DACL_RETUNE_C17_0                0x4C21
+#define WM8962_DACL_RETUNE_C18_1                0x4C22
+#define WM8962_DACL_RETUNE_C18_0                0x4C23
+#define WM8962_DACL_RETUNE_C19_1                0x4C24
+#define WM8962_DACL_RETUNE_C19_0                0x4C25
+#define WM8962_DACL_RETUNE_C20_1                0x4C26
+#define WM8962_DACL_RETUNE_C20_0                0x4C27
+#define WM8962_DACL_RETUNE_C21_1                0x4C28
+#define WM8962_DACL_RETUNE_C21_0                0x4C29
+#define WM8962_DACL_RETUNE_C22_1                0x4C2A
+#define WM8962_DACL_RETUNE_C22_0                0x4C2B
+#define WM8962_DACL_RETUNE_C23_1                0x4C2C
+#define WM8962_DACL_RETUNE_C23_0                0x4C2D
+#define WM8962_DACL_RETUNE_C24_1                0x4C2E
+#define WM8962_DACL_RETUNE_C24_0                0x4C2F
+#define WM8962_DACL_RETUNE_C25_1                0x4C30
+#define WM8962_DACL_RETUNE_C25_0                0x4C31
+#define WM8962_DACL_RETUNE_C26_1                0x4C32
+#define WM8962_DACL_RETUNE_C26_0                0x4C33
+#define WM8962_DACL_RETUNE_C27_1                0x4C34
+#define WM8962_DACL_RETUNE_C27_0                0x4C35
+#define WM8962_DACL_RETUNE_C28_1                0x4C36
+#define WM8962_DACL_RETUNE_C28_0                0x4C37
+#define WM8962_DACL_RETUNE_C29_1                0x4C38
+#define WM8962_DACL_RETUNE_C29_0                0x4C39
+#define WM8962_DACL_RETUNE_C30_1                0x4C3A
+#define WM8962_DACL_RETUNE_C30_0                0x4C3B
+#define WM8962_DACL_RETUNE_C31_1                0x4C3C
+#define WM8962_DACL_RETUNE_C31_0                0x4C3D
+#define WM8962_DACL_RETUNE_C32_1                0x4C3E
+#define WM8962_DACL_RETUNE_C32_0                0x4C3F
+#define WM8962_RETUNEDAC_PG2_1                  0x4E00
+#define WM8962_RETUNEDAC_PG2_0                  0x4E01
+#define WM8962_RETUNEDAC_PG_1                   0x4E02
+#define WM8962_RETUNEDAC_PG_0                   0x4E03
+#define WM8962_DACR_RETUNE_C1_1                 0x5000
+#define WM8962_DACR_RETUNE_C1_0                 0x5001
+#define WM8962_DACR_RETUNE_C2_1                 0x5002
+#define WM8962_DACR_RETUNE_C2_0                 0x5003
+#define WM8962_DACR_RETUNE_C3_1                 0x5004
+#define WM8962_DACR_RETUNE_C3_0                 0x5005
+#define WM8962_DACR_RETUNE_C4_1                 0x5006
+#define WM8962_DACR_RETUNE_C4_0                 0x5007
+#define WM8962_DACR_RETUNE_C5_1                 0x5008
+#define WM8962_DACR_RETUNE_C5_0                 0x5009
+#define WM8962_DACR_RETUNE_C6_1                 0x500A
+#define WM8962_DACR_RETUNE_C6_0                 0x500B
+#define WM8962_DACR_RETUNE_C7_1                 0x500C
+#define WM8962_DACR_RETUNE_C7_0                 0x500D
+#define WM8962_DACR_RETUNE_C8_1                 0x500E
+#define WM8962_DACR_RETUNE_C8_0                 0x500F
+#define WM8962_DACR_RETUNE_C9_1                 0x5010
+#define WM8962_DACR_RETUNE_C9_0                 0x5011
+#define WM8962_DACR_RETUNE_C10_1                0x5012
+#define WM8962_DACR_RETUNE_C10_0                0x5013
+#define WM8962_DACR_RETUNE_C11_1                0x5014
+#define WM8962_DACR_RETUNE_C11_0                0x5015
+#define WM8962_DACR_RETUNE_C12_1                0x5016
+#define WM8962_DACR_RETUNE_C12_0                0x5017
+#define WM8962_DACR_RETUNE_C13_1                0x5018
+#define WM8962_DACR_RETUNE_C13_0                0x5019
+#define WM8962_DACR_RETUNE_C14_1                0x501A
+#define WM8962_DACR_RETUNE_C14_0                0x501B
+#define WM8962_DACR_RETUNE_C15_1                0x501C
+#define WM8962_DACR_RETUNE_C15_0                0x501D
+#define WM8962_DACR_RETUNE_C16_1                0x501E
+#define WM8962_DACR_RETUNE_C16_0                0x501F
+#define WM8962_DACR_RETUNE_C17_1                0x5020
+#define WM8962_DACR_RETUNE_C17_0                0x5021
+#define WM8962_DACR_RETUNE_C18_1                0x5022
+#define WM8962_DACR_RETUNE_C18_0                0x5023
+#define WM8962_DACR_RETUNE_C19_1                0x5024
+#define WM8962_DACR_RETUNE_C19_0                0x5025
+#define WM8962_DACR_RETUNE_C20_1                0x5026
+#define WM8962_DACR_RETUNE_C20_0                0x5027
+#define WM8962_DACR_RETUNE_C21_1                0x5028
+#define WM8962_DACR_RETUNE_C21_0                0x5029
+#define WM8962_DACR_RETUNE_C22_1                0x502A
+#define WM8962_DACR_RETUNE_C22_0                0x502B
+#define WM8962_DACR_RETUNE_C23_1                0x502C
+#define WM8962_DACR_RETUNE_C23_0                0x502D
+#define WM8962_DACR_RETUNE_C24_1                0x502E
+#define WM8962_DACR_RETUNE_C24_0                0x502F
+#define WM8962_DACR_RETUNE_C25_1                0x5030
+#define WM8962_DACR_RETUNE_C25_0                0x5031
+#define WM8962_DACR_RETUNE_C26_1                0x5032
+#define WM8962_DACR_RETUNE_C26_0                0x5033
+#define WM8962_DACR_RETUNE_C27_1                0x5034
+#define WM8962_DACR_RETUNE_C27_0                0x5035
+#define WM8962_DACR_RETUNE_C28_1                0x5036
+#define WM8962_DACR_RETUNE_C28_0                0x5037
+#define WM8962_DACR_RETUNE_C29_1                0x5038
+#define WM8962_DACR_RETUNE_C29_0                0x5039
+#define WM8962_DACR_RETUNE_C30_1                0x503A
+#define WM8962_DACR_RETUNE_C30_0                0x503B
+#define WM8962_DACR_RETUNE_C31_1                0x503C
+#define WM8962_DACR_RETUNE_C31_0                0x503D
+#define WM8962_DACR_RETUNE_C32_1                0x503E
+#define WM8962_DACR_RETUNE_C32_0                0x503F
+#define WM8962_VSS_XHD2_1                       0x5200
+#define WM8962_VSS_XHD2_0                       0x5201
+#define WM8962_VSS_XHD3_1                       0x5202
+#define WM8962_VSS_XHD3_0                       0x5203
+#define WM8962_VSS_XHN1_1                       0x5204
+#define WM8962_VSS_XHN1_0                       0x5205
+#define WM8962_VSS_XHN2_1                       0x5206
+#define WM8962_VSS_XHN2_0                       0x5207
+#define WM8962_VSS_XHN3_1                       0x5208
+#define WM8962_VSS_XHN3_0                       0x5209
+#define WM8962_VSS_XLA_1                        0x520A
+#define WM8962_VSS_XLA_0                        0x520B
+#define WM8962_VSS_XLB_1                        0x520C
+#define WM8962_VSS_XLB_0                        0x520D
+#define WM8962_VSS_XLG_1                        0x520E
+#define WM8962_VSS_XLG_0                        0x520F
+#define WM8962_VSS_PG2_1                        0x5210
+#define WM8962_VSS_PG2_0                        0x5211
+#define WM8962_VSS_PG_1                         0x5212
+#define WM8962_VSS_PG_0                         0x5213
+#define WM8962_VSS_XTD1_1                       0x5214
+#define WM8962_VSS_XTD1_0                       0x5215
+#define WM8962_VSS_XTD2_1                       0x5216
+#define WM8962_VSS_XTD2_0                       0x5217
+#define WM8962_VSS_XTD3_1                       0x5218
+#define WM8962_VSS_XTD3_0                       0x5219
+#define WM8962_VSS_XTD4_1                       0x521A
+#define WM8962_VSS_XTD4_0                       0x521B
+#define WM8962_VSS_XTD5_1                       0x521C
+#define WM8962_VSS_XTD5_0                       0x521D
+#define WM8962_VSS_XTD6_1                       0x521E
+#define WM8962_VSS_XTD6_0                       0x521F
+#define WM8962_VSS_XTD7_1                       0x5220
+#define WM8962_VSS_XTD7_0                       0x5221
+#define WM8962_VSS_XTD8_1                       0x5222
+#define WM8962_VSS_XTD8_0                       0x5223
+#define WM8962_VSS_XTD9_1                       0x5224
+#define WM8962_VSS_XTD9_0                       0x5225
+#define WM8962_VSS_XTD10_1                      0x5226
+#define WM8962_VSS_XTD10_0                      0x5227
+#define WM8962_VSS_XTD11_1                      0x5228
+#define WM8962_VSS_XTD11_0                      0x5229
+#define WM8962_VSS_XTD12_1                      0x522A
+#define WM8962_VSS_XTD12_0                      0x522B
+#define WM8962_VSS_XTD13_1                      0x522C
+#define WM8962_VSS_XTD13_0                      0x522D
+#define WM8962_VSS_XTD14_1                      0x522E
+#define WM8962_VSS_XTD14_0                      0x522F
+#define WM8962_VSS_XTD15_1                      0x5230
+#define WM8962_VSS_XTD15_0                      0x5231
+#define WM8962_VSS_XTD16_1                      0x5232
+#define WM8962_VSS_XTD16_0                      0x5233
+#define WM8962_VSS_XTD17_1                      0x5234
+#define WM8962_VSS_XTD17_0                      0x5235
+#define WM8962_VSS_XTD18_1                      0x5236
+#define WM8962_VSS_XTD18_0                      0x5237
+#define WM8962_VSS_XTD19_1                      0x5238
+#define WM8962_VSS_XTD19_0                      0x5239
+#define WM8962_VSS_XTD20_1                      0x523A
+#define WM8962_VSS_XTD20_0                      0x523B
+#define WM8962_VSS_XTD21_1                      0x523C
+#define WM8962_VSS_XTD21_0                      0x523D
+#define WM8962_VSS_XTD22_1                      0x523E
+#define WM8962_VSS_XTD22_0                      0x523F
+#define WM8962_VSS_XTD23_1                      0x5240
+#define WM8962_VSS_XTD23_0                      0x5241
+#define WM8962_VSS_XTD24_1                      0x5242
+#define WM8962_VSS_XTD24_0                      0x5243
+#define WM8962_VSS_XTD25_1                      0x5244
+#define WM8962_VSS_XTD25_0                      0x5245
+#define WM8962_VSS_XTD26_1                      0x5246
+#define WM8962_VSS_XTD26_0                      0x5247
+#define WM8962_VSS_XTD27_1                      0x5248
+#define WM8962_VSS_XTD27_0                      0x5249
+#define WM8962_VSS_XTD28_1                      0x524A
+#define WM8962_VSS_XTD28_0                      0x524B
+#define WM8962_VSS_XTD29_1                      0x524C
+#define WM8962_VSS_XTD29_0                      0x524D
+#define WM8962_VSS_XTD30_1                      0x524E
+#define WM8962_VSS_XTD30_0                      0x524F
+#define WM8962_VSS_XTD31_1                      0x5250
+#define WM8962_VSS_XTD31_0                      0x5251
+#define WM8962_VSS_XTD32_1                      0x5252
+#define WM8962_VSS_XTD32_0                      0x5253
+#define WM8962_VSS_XTS1_1                       0x5254
+#define WM8962_VSS_XTS1_0                       0x5255
+#define WM8962_VSS_XTS2_1                       0x5256
+#define WM8962_VSS_XTS2_0                       0x5257
+#define WM8962_VSS_XTS3_1                       0x5258
+#define WM8962_VSS_XTS3_0                       0x5259
+#define WM8962_VSS_XTS4_1                       0x525A
+#define WM8962_VSS_XTS4_0                       0x525B
+#define WM8962_VSS_XTS5_1                       0x525C
+#define WM8962_VSS_XTS5_0                       0x525D
+#define WM8962_VSS_XTS6_1                       0x525E
+#define WM8962_VSS_XTS6_0                       0x525F
+#define WM8962_VSS_XTS7_1                       0x5260
+#define WM8962_VSS_XTS7_0                       0x5261
+#define WM8962_VSS_XTS8_1                       0x5262
+#define WM8962_VSS_XTS8_0                       0x5263
+#define WM8962_VSS_XTS9_1                       0x5264
+#define WM8962_VSS_XTS9_0                       0x5265
+#define WM8962_VSS_XTS10_1                      0x5266
+#define WM8962_VSS_XTS10_0                      0x5267
+#define WM8962_VSS_XTS11_1                      0x5268
+#define WM8962_VSS_XTS11_0                      0x5269
+#define WM8962_VSS_XTS12_1                      0x526A
+#define WM8962_VSS_XTS12_0                      0x526B
+#define WM8962_VSS_XTS13_1                      0x526C
+#define WM8962_VSS_XTS13_0                      0x526D
+#define WM8962_VSS_XTS14_1                      0x526E
+#define WM8962_VSS_XTS14_0                      0x526F
+#define WM8962_VSS_XTS15_1                      0x5270
+#define WM8962_VSS_XTS15_0                      0x5271
+#define WM8962_VSS_XTS16_1                      0x5272
+#define WM8962_VSS_XTS16_0                      0x5273
+#define WM8962_VSS_XTS17_1                      0x5274
+#define WM8962_VSS_XTS17_0                      0x5275
+#define WM8962_VSS_XTS18_1                      0x5276
+#define WM8962_VSS_XTS18_0                      0x5277
+#define WM8962_VSS_XTS19_1                      0x5278
+#define WM8962_VSS_XTS19_0                      0x5279
+#define WM8962_VSS_XTS20_1                      0x527A
+#define WM8962_VSS_XTS20_0                      0x527B
+#define WM8962_VSS_XTS21_1                      0x527C
+#define WM8962_VSS_XTS21_0                      0x527D
+#define WM8962_VSS_XTS22_1                      0x527E
+#define WM8962_VSS_XTS22_0                      0x527F
+#define WM8962_VSS_XTS23_1                      0x5280
+#define WM8962_VSS_XTS23_0                      0x5281
+#define WM8962_VSS_XTS24_1                      0x5282
+#define WM8962_VSS_XTS24_0                      0x5283
+#define WM8962_VSS_XTS25_1                      0x5284
+#define WM8962_VSS_XTS25_0                      0x5285
+#define WM8962_VSS_XTS26_1                      0x5286
+#define WM8962_VSS_XTS26_0                      0x5287
+#define WM8962_VSS_XTS27_1                      0x5288
+#define WM8962_VSS_XTS27_0                      0x5289
+#define WM8962_VSS_XTS28_1                      0x528A
+#define WM8962_VSS_XTS28_0                      0x528B
+#define WM8962_VSS_XTS29_1                      0x528C
+#define WM8962_VSS_XTS29_0                      0x528D
+#define WM8962_VSS_XTS30_1                      0x528E
+#define WM8962_VSS_XTS30_0                      0x528F
+#define WM8962_VSS_XTS31_1                      0x5290
+#define WM8962_VSS_XTS31_0                      0x5291
+#define WM8962_VSS_XTS32_1                      0x5292
+#define WM8962_VSS_XTS32_0                      0x5293
+
+#define WM8962_REGISTER_COUNT                   1138
+#define WM8962_MAX_REGISTER                     0x5293
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAL_MUTE                      0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_MASK                 0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_SHIFT                     7  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_WIDTH                     1  /* INPGAL_MUTE */
+#define WM8962_INL_ZC                           0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_MASK                      0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_SHIFT                          6  /* INL_ZC */
+#define WM8962_INL_ZC_WIDTH                          1  /* INL_ZC */
+#define WM8962_INL_VOL_MASK                     0x003F  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_SHIFT                         0  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_WIDTH                         6  /* INL_VOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8962_CUST_ID_MASK                     0xF000  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_SHIFT                        12  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_WIDTH                         4  /* CUST_ID - [15:12] */
+#define WM8962_CHIP_REV_MASK                    0x0E00  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_SHIFT                        9  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_WIDTH                        3  /* CHIP_REV - [11:9] */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAR_MUTE                      0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_MASK                 0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_SHIFT                     7  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_WIDTH                     1  /* INPGAR_MUTE */
+#define WM8962_INR_ZC                           0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_MASK                      0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_SHIFT                          6  /* INR_ZC */
+#define WM8962_INR_ZC_WIDTH                          1  /* INR_ZC */
+#define WM8962_INR_VOL_MASK                     0x003F  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_SHIFT                         0  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_WIDTH                         6  /* INR_VOL - [5:0] */
+
+/*
+ * R2 (0x02) - HPOUTL volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTL_ZC                        0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_MASK                   0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_SHIFT                       7  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_WIDTH                       1  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_VOL_MASK                  0x007F  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_WIDTH                      7  /* HPOUTL_VOL - [6:0] */
+
+/*
+ * R3 (0x03) - HPOUTR volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTR_ZC                        0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_MASK                   0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_SHIFT                       7  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_WIDTH                       1  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_VOL_MASK                  0x007F  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_WIDTH                      7  /* HPOUTR_VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8962_DSPCLK_DIV_MASK                  0x0600  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_SHIFT                      9  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_WIDTH                      2  /* DSPCLK_DIV - [10:9] */
+#define WM8962_ADCSYS_CLK_DIV_MASK              0x01C0  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_SHIFT                  6  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_WIDTH                  3  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_DACSYS_CLK_DIV_MASK              0x0038  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_SHIFT                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_WIDTH                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_MCLKDIV_MASK                     0x0006  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_SHIFT                         1  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_WIDTH                         2  /* MCLKDIV - [2:1] */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8962_ADCR_DAT_INV                     0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_MASK                0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_SHIFT                    6  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_WIDTH                    1  /* ADCR_DAT_INV */
+#define WM8962_ADCL_DAT_INV                     0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_MASK                0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_SHIFT                    5  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_WIDTH                    1  /* ADCL_DAT_INV */
+#define WM8962_DAC_MUTE_RAMP                    0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_MASK               0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_SHIFT                   4  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_WIDTH                   1  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8962_DAC_DEEMP_MASK                   0x0006  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_SHIFT                       1  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_WIDTH                       2  /* DAC_DEEMP - [2:1] */
+#define WM8962_ADC_HPF_DIS                      0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_MASK                 0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_SHIFT                     0  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_WIDTH                     1  /* ADC_HPF_DIS */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8962_ADC_HPF_SR_MASK                  0x3000  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_SHIFT                     12  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_WIDTH                      2  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_MODE                     0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_MASK                0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_SHIFT                   10  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_WIDTH                    1  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_CUT_MASK                 0x0380  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_SHIFT                     7  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_WIDTH                     3  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_DACR_DAT_INV                     0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_MASK                0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_SHIFT                    6  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_WIDTH                    1  /* DACR_DAT_INV */
+#define WM8962_DACL_DAT_INV                     0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_MASK                0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_SHIFT                    5  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_WIDTH                    1  /* DACL_DAT_INV */
+#define WM8962_DAC_UNMUTE_RAMP                  0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_MASK             0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_SHIFT                 3  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_MUTERATE                     0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_MASK                0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_SHIFT                    2  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8962_DAC_HP                           0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_MASK                      0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_SHIFT                          0  /* DAC_HP */
+#define WM8962_DAC_HP_WIDTH                          1  /* DAC_HP */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8962_AIFDAC_TDM_MODE                  0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_MASK             0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_SHIFT                12  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_WIDTH                 1  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_SLOT                  0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_MASK             0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_SHIFT                11  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_WIDTH                 1  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_MODE                  0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_MASK             0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_SHIFT                10  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_WIDTH                 1  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_SLOT                  0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_MASK             0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_SHIFT                 9  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_WIDTH                 1  /* AIFADC_TDM_SLOT */
+#define WM8962_ADC_LRSWAP                       0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_MASK                  0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_SHIFT                      8  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_WIDTH                      1  /* ADC_LRSWAP */
+#define WM8962_BCLK_INV                         0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_MASK                    0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_SHIFT                        7  /* BCLK_INV */
+#define WM8962_BCLK_INV_WIDTH                        1  /* BCLK_INV */
+#define WM8962_MSTR                             0x0040  /* MSTR */
+#define WM8962_MSTR_MASK                        0x0040  /* MSTR */
+#define WM8962_MSTR_SHIFT                            6  /* MSTR */
+#define WM8962_MSTR_WIDTH                            1  /* MSTR */
+#define WM8962_DAC_LRSWAP                       0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_MASK                  0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_SHIFT                      5  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_WIDTH                      1  /* DAC_LRSWAP */
+#define WM8962_LRCLK_INV                        0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_MASK                   0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_SHIFT                       4  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_WIDTH                       1  /* LRCLK_INV */
+#define WM8962_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8962_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8962_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8962_FMT_MASK                         0x0003  /* FMT - [1:0] */
+#define WM8962_FMT_SHIFT                             0  /* FMT - [1:0] */
+#define WM8962_FMT_WIDTH                             2  /* FMT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8962_CLKREG_OVD                       0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_MASK                  0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_SHIFT                     11  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_WIDTH                      1  /* CLKREG_OVD */
+#define WM8962_SYSCLK_SRC_MASK                  0x0600  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_SHIFT                      9  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [10:9] */
+#define WM8962_CLASSD_CLK_DIV_MASK              0x01C0  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_SHIFT                  6  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_WIDTH                  3  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_SYSCLK_ENA                       0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_MASK                  0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_SHIFT                      5  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM8962_BCLK_DIV_MASK                    0x000F  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8962_AUTOMUTE_STS                     0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_MASK                0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_SHIFT                   11  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_WIDTH                    1  /* AUTOMUTE_STS */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_MASK        0x0300  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_SHIFT            8  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_WIDTH            2  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE                     0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_MASK                0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_SHIFT                    7  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_WIDTH                    1  /* DAC_AUTOMUTE */
+#define WM8962_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8962_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8962_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8962_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8962_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8962_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8962_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8962_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8962_AIF_RATE_MASK                    0x07FF  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_SHIFT                        0  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_WIDTH                       11  /* AIF_RATE - [10:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8962_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8962_ALC_INACTIVE_ENA                 0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_MASK            0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_SHIFT               10  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_WIDTH                1  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_LVL_MODE                     0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_MASK                0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_SHIFT                    9  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_WIDTH                    1  /* ALC_LVL_MODE */
+#define WM8962_ALCL_ENA                         0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_MASK                    0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_SHIFT                        8  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_WIDTH                        1  /* ALCL_ENA */
+#define WM8962_ALCR_ENA                         0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_MASK                    0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_SHIFT                        7  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_WIDTH                        1  /* ALCR_ENA */
+#define WM8962_ALC_MAXGAIN_MASK                 0x0070  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_SHIFT                     4  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_WIDTH                     3  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_LVL_MASK                     0x000F  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_SHIFT                         0  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_WIDTH                         4  /* ALC_LVL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8962_ALC_LOCK_STS                     0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_MASK                0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_SHIFT                   15  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_WIDTH                    1  /* ALC_LOCK_STS */
+#define WM8962_ALC_THRESH_STS                   0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_MASK              0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_SHIFT                 14  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_WIDTH                  1  /* ALC_THRESH_STS */
+#define WM8962_ALC_SAT_STS                      0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_MASK                 0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_SHIFT                    13  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_WIDTH                     1  /* ALC_SAT_STS */
+#define WM8962_ALC_PKOVR_STS                    0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_MASK               0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_SHIFT                  12  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_WIDTH                   1  /* ALC_PKOVR_STS */
+#define WM8962_ALC_NGATE_STS                    0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_MASK               0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_SHIFT                  11  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_WIDTH                   1  /* ALC_NGATE_STS */
+#define WM8962_ALC_ZC                           0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_MASK                      0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_SHIFT                          7  /* ALC_ZC */
+#define WM8962_ALC_ZC_WIDTH                          1  /* ALC_ZC */
+#define WM8962_ALC_MINGAIN_MASK                 0x0070  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_SHIFT                     4  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_WIDTH                     3  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_HLD_MASK                     0x000F  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_SHIFT                         0  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_WIDTH                         4  /* ALC_HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8962_ALC_NGATE_GAIN_MASK              0x1C00  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_SHIFT                 10  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_WIDTH                  3  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_MODE                         0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_MASK                    0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_SHIFT                        8  /* ALC_MODE */
+#define WM8962_ALC_MODE_WIDTH                        1  /* ALC_MODE */
+#define WM8962_ALC_DCY_MASK                     0x00F0  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_SHIFT                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_WIDTH                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_ATK_MASK                     0x000F  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_SHIFT                         0  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_WIDTH                         4  /* ALC_ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8962_ALC_NGATE_DCY_MASK               0xF000  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_SHIFT                  12  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_WIDTH                   4  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_ATK_MASK               0x0F00  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_SHIFT                   8  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_WIDTH                   4  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_THR_MASK               0x00F8  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_SHIFT                   3  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_WIDTH                   5  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_MODE_MASK              0x0006  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_SHIFT                  1  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_WIDTH                  2  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_ENA                    0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_MASK               0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_SHIFT                   0  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_WIDTH                   1  /* ALC_NGATE_ENA */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8962_THERR_ACT                        0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_MASK                   0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_SHIFT                       8  /* THERR_ACT */
+#define WM8962_THERR_ACT_WIDTH                       1  /* THERR_ACT */
+#define WM8962_ADC_BIAS                         0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_MASK                    0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_SHIFT                        6  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_WIDTH                        1  /* ADC_BIAS */
+#define WM8962_ADC_HP                           0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_MASK                      0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_SHIFT                          5  /* ADC_HP */
+#define WM8962_ADC_HP_WIDTH                          1  /* ADC_HP */
+#define WM8962_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8962_AIF_TRI                          0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_MASK                     0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_SHIFT                         3  /* AIF_TRI */
+#define WM8962_AIF_TRI_WIDTH                         1  /* AIF_TRI */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8962_DMIC_ENA                         0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_MASK                    0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_SHIFT                       10  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8962_OPCLK_ENA                        0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_MASK                   0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_SHIFT                       9  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8962_VMID_SEL_MASK                    0x0180  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_SHIFT                        7  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_WIDTH                        2  /* VMID_SEL - [8:7] */
+#define WM8962_BIAS_ENA                         0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_MASK                    0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_SHIFT                        6  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM8962_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8962_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8962_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8962_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8962_ADCL_ENA                         0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_MASK                    0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_SHIFT                        3  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8962_ADCR_ENA                         0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_MASK                    0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_SHIFT                        2  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+#define WM8962_MICBIAS_ENA                      0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_MASK                 0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_SHIFT                     1  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8962_DACL_ENA                         0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_MASK                    0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_SHIFT                        8  /* DACL_ENA */
+#define WM8962_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8962_DACR_ENA                         0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_MASK                    0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_SHIFT                        7  /* DACR_ENA */
+#define WM8962_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8962_HPOUTL_PGA_ENA                   0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_MASK              0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_SHIFT                  6  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_WIDTH                  1  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA                   0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_MASK              0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_SHIFT                  5  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_WIDTH                  1  /* HPOUTR_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA                  0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_MASK             0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_SHIFT                 4  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_WIDTH                 1  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA                  0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_MASK             0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_SHIFT                 3  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_WIDTH                 1  /* SPKOUTR_PGA_ENA */
+#define WM8962_HPOUTL_PGA_MUTE                  0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_MASK             0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_SHIFT                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_WIDTH                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE                  0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_MASK             0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_SHIFT                 0  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_WIDTH                 1  /* HPOUTR_PGA_MUTE */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8962_SAMPLE_RATE_INT_MODE             0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_MASK        0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_SHIFT            4  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_WIDTH            1  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8962_STARTUP_BIAS_ENA                 0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_MASK            0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_SHIFT                4  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8962_VMID_BUF_ENA                     0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_MASK                0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_SHIFT                    3  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8962_VMID_RAMP                        0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_MASK                   0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_SHIFT                       2  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8962_DBCLK_DIV_MASK                   0xE000  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_SHIFT                      13  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_WIDTH                       3  /* DBCLK_DIV - [15:13] */
+#define WM8962_OPCLK_DIV_MASK                   0x1C00  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_SHIFT                      10  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [12:10] */
+#define WM8962_TOCLK_DIV_MASK                   0x0380  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_SHIFT                       7  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [9:7] */
+#define WM8962_F256KCLK_DIV_MASK                0x007E  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_SHIFT                    1  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_WIDTH                    6  /* F256KCLK_DIV - [6:1] */
+
+/*
+ * R31 (0x1F) - Input mixer control (1)
+ */
+#define WM8962_MIXINL_MUTE                      0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_MASK                 0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_SHIFT                     3  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_WIDTH                     1  /* MIXINL_MUTE */
+#define WM8962_MIXINR_MUTE                      0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_MASK                 0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_SHIFT                     2  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_WIDTH                     1  /* MIXINR_MUTE */
+#define WM8962_MIXINL_ENA                       0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_MASK                  0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_SHIFT                      1  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_WIDTH                      1  /* MIXINL_ENA */
+#define WM8962_MIXINR_ENA                       0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_MASK                  0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_SHIFT                      0  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_WIDTH                      1  /* MIXINR_ENA */
+
+/*
+ * R32 (0x20) - Left input mixer volume
+ */
+#define WM8962_IN2L_MIXINL_VOL_MASK             0x01C0  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_SHIFT                 6  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_WIDTH                 3  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_INPGAL_MIXINL_VOL_MASK           0x0038  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_SHIFT               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_WIDTH               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_IN3L_MIXINL_VOL_MASK             0x0007  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_SHIFT                 0  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_WIDTH                 3  /* IN3L_MIXINL_VOL - [2:0] */
+
+/*
+ * R33 (0x21) - Right input mixer volume
+ */
+#define WM8962_IN2R_MIXINR_VOL_MASK             0x01C0  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_SHIFT                 6  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_WIDTH                 3  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_INPGAR_MIXINR_VOL_MASK           0x0038  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_SHIFT               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_WIDTH               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_IN3R_MIXINR_VOL_MASK             0x0007  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_SHIFT                 0  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_WIDTH                 3  /* IN3R_MIXINR_VOL - [2:0] */
+
+/*
+ * R34 (0x22) - Input mixer control (2)
+ */
+#define WM8962_IN2L_TO_MIXINL                   0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_MASK              0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_SHIFT                  5  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_WIDTH                  1  /* IN2L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL                   0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_MASK              0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_SHIFT                  4  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_WIDTH                  1  /* IN3L_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL                 0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_MASK            0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_SHIFT                3  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_WIDTH                1  /* INPGAL_TO_MIXINL */
+#define WM8962_IN2R_TO_MIXINR                   0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_MASK              0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_SHIFT                  2  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_WIDTH                  1  /* IN2R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR                   0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_MASK              0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_SHIFT                  1  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_WIDTH                  1  /* IN3R_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR                 0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_MASK            0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_SHIFT                0  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_WIDTH                1  /* INPGAR_TO_MIXINR */
+
+/*
+ * R35 (0x23) - Input bias control
+ */
+#define WM8962_MIXIN_BIAS_MASK                  0x0038  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_SHIFT                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_WIDTH                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_INPGA_BIAS_MASK                  0x0007  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_SHIFT                      0  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_WIDTH                      3  /* INPGA_BIAS - [2:0] */
+
+/*
+ * R37 (0x25) - Left input PGA control
+ */
+#define WM8962_INPGAL_ENA                       0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_MASK                  0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_SHIFT                      4  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_WIDTH                      1  /* INPGAL_ENA */
+#define WM8962_IN1L_TO_INPGAL                   0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_MASK              0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_SHIFT                  3  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_WIDTH                  1  /* IN1L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL                   0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_MASK              0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_SHIFT                  2  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_WIDTH                  1  /* IN2L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL                   0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_MASK              0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_SHIFT                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_WIDTH                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL                   0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_MASK              0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_SHIFT                  0  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_WIDTH                  1  /* IN4L_TO_INPGAL */
+
+/*
+ * R38 (0x26) - Right input PGA control
+ */
+#define WM8962_INPGAR_ENA                       0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_MASK                  0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_SHIFT                      4  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_WIDTH                      1  /* INPGAR_ENA */
+#define WM8962_IN1R_TO_INPGAR                   0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_MASK              0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_SHIFT                  3  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_WIDTH                  1  /* IN1R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR                   0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_MASK              0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_SHIFT                  2  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_WIDTH                  1  /* IN2R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR                   0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_MASK              0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_SHIFT                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_WIDTH                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR                   0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_MASK              0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_SHIFT                  0  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_WIDTH                  1  /* IN4R_TO_INPGAR */
+
+/*
+ * R40 (0x28) - SPKOUTL volume
+ */
+#define WM8962_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM8962_SPKOUTL_ZC                       0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_MASK                  0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_SHIFT                      7  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_WIDTH                      1  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_VOL_MASK                 0x007F  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_SHIFT                     0  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_WIDTH                     7  /* SPKOUTL_VOL - [6:0] */
+
+/*
+ * R41 (0x29) - SPKOUTR volume
+ */
+#define WM8962_SPKOUTR_ZC                       0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_MASK                  0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_SHIFT                      7  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_WIDTH                      1  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_VOL_MASK                 0x007F  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_SHIFT                     0  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_WIDTH                     7  /* SPKOUTR_VOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Thermal Shutdown Status
+ */
+#define WM8962_TEMP_ERR_HP                      0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_MASK                 0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_SHIFT                     3  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_WIDTH                     1  /* TEMP_ERR_HP */
+#define WM8962_TEMP_WARN_HP                     0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_MASK                0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_SHIFT                    2  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_WIDTH                    1  /* TEMP_WARN_HP */
+#define WM8962_TEMP_ERR_SPK                     0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_MASK                0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_SHIFT                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_WIDTH                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_WARN_SPK                    0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_MASK               0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_SHIFT                   0  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_WIDTH                   1  /* TEMP_WARN_SPK */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8962_MICDET_THR_MASK                  0x7000  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_SHIFT                     12  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_WIDTH                      3  /* MICDET_THR - [14:12] */
+#define WM8962_MICSHORT_THR_MASK                0x0C00  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_SHIFT                   10  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICDET_ENA                       0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_MASK                  0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_SHIFT                      9  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8962_MICDET_STS                       0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_MASK                  0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_SHIFT                      7  /* MICDET_STS */
+#define WM8962_MICDET_STS_WIDTH                      1  /* MICDET_STS */
+#define WM8962_MICSHORT_STS                     0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_MASK                0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_SHIFT                    6  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_WIDTH                    1  /* MICSHORT_STS */
+#define WM8962_TEMP_ENA_HP                      0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_MASK                 0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_SHIFT                     2  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_WIDTH                     1  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_SPK                     0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_MASK                0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_SHIFT                    1  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_WIDTH                    1  /* TEMP_ENA_SPK */
+#define WM8962_MICBIAS_LVL                      0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_MASK                 0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_SHIFT                     0  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_WIDTH                     1  /* MICBIAS_LVL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8962_SPKOUTR_ENA                      0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_MASK                 0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_SHIFT                     7  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_WIDTH                     1  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTL_ENA                      0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_MASK                 0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_SHIFT                     6  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_PGA_MUTE                 0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_MASK            0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_SHIFT                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_WIDTH                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE                 0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_MASK            0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_SHIFT                0  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_WIDTH                1  /* SPKOUTR_PGA_MUTE */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8962_SPK_MONO                         0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_MASK                    0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_SHIFT                        6  /* SPK_MONO */
+#define WM8962_SPK_MONO_WIDTH                        1  /* SPK_MONO */
+#define WM8962_CLASSD_VOL_MASK                  0x0007  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_SHIFT                      0  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_WIDTH                      3  /* CLASSD_VOL - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8962_SYSCLK_RATE_MASK                 0x001E  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_SHIFT                     1  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_WIDTH                     4  /* SYSCLK_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DAC DSP Mixing (1)
+ */
+#define WM8962_DAC_MONOMIX                      0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_MASK                 0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_SHIFT                     9  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_WIDTH                     1  /* DAC_MONOMIX */
+#define WM8962_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACR_MASK                 0x000C  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_SHIFT                     2  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DAC DSP Mixing (2)
+ */
+#define WM8962_ADCL_DAC_SVOL_MASK               0x00F0  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_SHIFT                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8962_INL_DCS_ENA                      0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_MASK                 0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_SHIFT                     7  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_WIDTH                     1  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_STARTUP                  0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_MASK             0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_SHIFT                 6  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_WIDTH                 1  /* INL_DCS_STARTUP */
+#define WM8962_INR_DCS_ENA                      0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_MASK                 0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_SHIFT                     3  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_WIDTH                     1  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_STARTUP                  0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_MASK             0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_SHIFT                 2  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_WIDTH                 1  /* INR_DCS_STARTUP */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8962_HP1L_DCS_ENA                     0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_MASK                0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_SHIFT                    7  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_WIDTH                    1  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_STARTUP                 0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_MASK            0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_SHIFT                6  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_WIDTH                1  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_SYNC                    0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_MASK               0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_SHIFT                   4  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_WIDTH                   1  /* HP1L_DCS_SYNC */
+#define WM8962_HP1R_DCS_ENA                     0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_MASK                0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_SHIFT                    3  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_WIDTH                    1  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_STARTUP                 0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_MASK            0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_SHIFT                2  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_WIDTH                1  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_SYNC                    0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_MASK               0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_SHIFT                   0  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_WIDTH                   1  /* HP1R_DCS_SYNC */
+
+/*
+ * R64 (0x40) - DC Servo 4
+ */
+#define WM8962_HP1_DCS_SYNC_STEPS_MASK          0x3F80  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_SHIFT              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_WIDTH              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+
+/*
+ * R66 (0x42) - DC Servo 6
+ */
+#define WM8962_DCS_STARTUP_DONE_INL             0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_MASK        0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_SHIFT           10  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_WIDTH            1  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INR             0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_MASK        0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_SHIFT            9  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_WIDTH            1  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_HP1L            0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_MASK       0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_SHIFT           8  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_WIDTH           1  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1R            0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_MASK       0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_SHIFT           7  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_WIDTH           1  /* DCS_STARTUP_DONE_HP1R */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8962_HP_PGAS_BIAS_MASK                0x0007  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_SHIFT                    0  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_WIDTH                    3  /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8962_HP1L_RMV_SHORT                   0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_MASK              0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_SHIFT                  7  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_WIDTH                  1  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_ENA_OUTP                    0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_MASK               0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_SHIFT                   6  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_WIDTH                   1  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_DLY                     0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_MASK                0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_SHIFT                    5  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_WIDTH                    1  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA                         0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_MASK                    0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_SHIFT                        4  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_WIDTH                        1  /* HP1L_ENA */
+#define WM8962_HP1R_RMV_SHORT                   0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_MASK              0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_SHIFT                  3  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_WIDTH                  1  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_ENA_OUTP                    0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_MASK               0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_SHIFT                   2  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_WIDTH                   1  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_DLY                     0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_MASK                0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_SHIFT                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_WIDTH                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA                         0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_MASK                    0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_SHIFT                        0  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_WIDTH                        1  /* HP1R_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8962_HP1L_VOL_MASK                    0x01C0  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_SHIFT                        6  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_WIDTH                        3  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1R_VOL_MASK                    0x0038  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_SHIFT                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_WIDTH                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP_BIAS_BOOST_MASK               0x0007  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_SHIFT                   0  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_WIDTH                   3  /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8962_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8962_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8962_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R87 (0x57) - Write Sequencer Control 1
+ */
+#define WM8962_WSEQ_AUTOSEQ_ENA                 0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_MASK            0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_SHIFT                7  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_WIDTH                1  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_ENA                         0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_MASK                    0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_SHIFT                        5  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+
+/*
+ * R90 (0x5A) - Write Sequencer Control 2
+ */
+#define WM8962_WSEQ_ABORT                       0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_MASK                  0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_SHIFT                      8  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8962_WSEQ_START                       0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_MASK                  0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_SHIFT                      7  /* WSEQ_START */
+#define WM8962_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8962_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer Control 3
+ */
+#define WM8962_WSEQ_CURRENT_INDEX_MASK          0x03F8  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_SHIFT              3  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R94 (0x5E) - Control Interface
+ */
+#define WM8962_SPI_CONTRD                       0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_MASK                  0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_SHIFT                      6  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_WIDTH                      1  /* SPI_CONTRD */
+#define WM8962_SPI_4WIRE                        0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_MASK                   0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_SHIFT                       5  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM8962_SPI_CFG                          0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_MASK                     0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_SHIFT                         4  /* SPI_CFG */
+#define WM8962_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+
+/*
+ * R99 (0x63) - Mixer Enables
+ */
+#define WM8962_HPMIXL_ENA                       0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_MASK                  0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_SHIFT                      3  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_WIDTH                      1  /* HPMIXL_ENA */
+#define WM8962_HPMIXR_ENA                       0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_MASK                  0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_SHIFT                      2  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_WIDTH                      1  /* HPMIXR_ENA */
+#define WM8962_SPKMIXL_ENA                      0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_MASK                 0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_SHIFT                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_WIDTH                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXR_ENA                      0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_MASK                 0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_SHIFT                     0  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_WIDTH                     1  /* SPKMIXR_ENA */
+
+/*
+ * R100 (0x64) - Headphone Mixer (1)
+ */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA             0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_MASK        0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_SHIFT            7  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_WIDTH            1  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_DACL_TO_HPMIXL                   0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_MASK              0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_SHIFT                  5  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_WIDTH                  1  /* DACL_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL                   0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_MASK              0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_SHIFT                  4  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_WIDTH                  1  /* DACR_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL                 0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_MASK            0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_SHIFT                3  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_WIDTH                1  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL                 0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_MASK            0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_SHIFT                2  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_WIDTH                1  /* MIXINR_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL                   0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_MASK              0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_SHIFT                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_WIDTH                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL                   0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_MASK              0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_SHIFT                  0  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_WIDTH                  1  /* IN4R_TO_HPMIXL */
+
+/*
+ * R101 (0x65) - Headphone Mixer (2)
+ */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA             0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_MASK        0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_SHIFT            7  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_WIDTH            1  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_DACL_TO_HPMIXR                   0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_MASK              0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_SHIFT                  5  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_WIDTH                  1  /* DACL_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR                   0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_MASK              0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_SHIFT                  4  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_WIDTH                  1  /* DACR_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR                 0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_MASK            0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_SHIFT                3  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_WIDTH                1  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR                 0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_MASK            0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_SHIFT                2  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_WIDTH                1  /* MIXINR_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR                   0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_MASK              0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_SHIFT                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_WIDTH                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR                   0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_MASK              0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_SHIFT                  0  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_WIDTH                  1  /* IN4R_TO_HPMIXR */
+
+/*
+ * R102 (0x66) - Headphone Mixer (3)
+ */
+#define WM8962_HPMIXL_MUTE                      0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_MASK                 0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_SHIFT                     8  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_WIDTH                     1  /* HPMIXL_MUTE */
+#define WM8962_MIXINL_HPMIXL_VOL                0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_MASK           0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_SHIFT               7  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_WIDTH               1  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL                0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_MASK           0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_SHIFT               6  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_WIDTH               1  /* MIXINR_HPMIXL_VOL */
+#define WM8962_IN4L_HPMIXL_VOL_MASK             0x0038  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_SHIFT                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_WIDTH                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXL_VOL_MASK             0x0007  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_SHIFT                 0  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_WIDTH                 3  /* IN4R_HPMIXL_VOL - [2:0] */
+
+/*
+ * R103 (0x67) - Headphone Mixer (4)
+ */
+#define WM8962_HPMIXR_MUTE                      0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_MASK                 0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_SHIFT                     8  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_WIDTH                     1  /* HPMIXR_MUTE */
+#define WM8962_MIXINL_HPMIXR_VOL                0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_MASK           0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_SHIFT               7  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_WIDTH               1  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL                0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_MASK           0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_SHIFT               6  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_WIDTH               1  /* MIXINR_HPMIXR_VOL */
+#define WM8962_IN4L_HPMIXR_VOL_MASK             0x0038  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_SHIFT                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_WIDTH                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXR_VOL_MASK             0x0007  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_SHIFT                 0  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_WIDTH                 3  /* IN4R_HPMIXR_VOL - [2:0] */
+
+/*
+ * R105 (0x69) - Speaker Mixer (1)
+ */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA           0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_MASK      0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_SHIFT          7  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_WIDTH          1  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_DACL_TO_SPKMIXL                  0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_MASK             0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_SHIFT                 5  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_WIDTH                 1  /* DACL_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL                  0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_MASK             0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_SHIFT                 4  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_WIDTH                 1  /* DACR_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL                0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_MASK           0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_SHIFT               3  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_WIDTH               1  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL                0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_MASK           0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_SHIFT               2  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_WIDTH               1  /* MIXINR_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL                  0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_MASK             0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_SHIFT                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_WIDTH                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL                  0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_MASK             0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_SHIFT                 0  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_WIDTH                 1  /* IN4R_TO_SPKMIXL */
+
+/*
+ * R106 (0x6A) - Speaker Mixer (2)
+ */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA           0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_MASK      0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_SHIFT          7  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_WIDTH          1  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_DACL_TO_SPKMIXR                  0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_MASK             0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_SHIFT                 5  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_WIDTH                 1  /* DACL_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR                  0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_MASK             0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_SHIFT                 4  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_WIDTH                 1  /* DACR_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR                0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_MASK           0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_SHIFT               3  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_WIDTH               1  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR                0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_MASK           0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_SHIFT               2  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_WIDTH               1  /* MIXINR_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR                  0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_MASK             0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_SHIFT                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_WIDTH                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR                  0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_MASK             0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_SHIFT                 0  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_WIDTH                 1  /* IN4R_TO_SPKMIXR */
+
+/*
+ * R107 (0x6B) - Speaker Mixer (3)
+ */
+#define WM8962_SPKMIXL_MUTE                     0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_MASK                0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_SHIFT                    8  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_WIDTH                    1  /* SPKMIXL_MUTE */
+#define WM8962_MIXINL_SPKMIXL_VOL               0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_MASK          0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_SHIFT              7  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_WIDTH              1  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL               0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_MASK          0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_SHIFT              6  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_WIDTH              1  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_IN4L_SPKMIXL_VOL_MASK            0x0038  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_SHIFT                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_WIDTH                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXL_VOL_MASK            0x0007  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_SHIFT                0  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_WIDTH                3  /* IN4R_SPKMIXL_VOL - [2:0] */
+
+/*
+ * R108 (0x6C) - Speaker Mixer (4)
+ */
+#define WM8962_SPKMIXR_MUTE                     0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_MASK                0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_SHIFT                    8  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_WIDTH                    1  /* SPKMIXR_MUTE */
+#define WM8962_MIXINL_SPKMIXR_VOL               0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_MASK          0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_SHIFT              7  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_WIDTH              1  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL               0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_MASK          0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_SHIFT              6  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_WIDTH              1  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_IN4L_SPKMIXR_VOL_MASK            0x0038  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_SHIFT                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_WIDTH                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXR_VOL_MASK            0x0007  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_SHIFT                0  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_WIDTH                3  /* IN4R_SPKMIXR_VOL - [2:0] */
+
+/*
+ * R109 (0x6D) - Speaker Mixer (5)
+ */
+#define WM8962_DACL_SPKMIXL_VOL                 0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_MASK            0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_SHIFT                7  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_WIDTH                1  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL                 0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_MASK            0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_SHIFT                6  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_WIDTH                1  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXR_VOL                 0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_MASK            0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_SHIFT                5  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_WIDTH                1  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL                 0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_MASK            0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_SHIFT                4  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_WIDTH                1  /* DACR_SPKMIXR_VOL */
+
+/*
+ * R110 (0x6E) - Beep Generator (1)
+ */
+#define WM8962_BEEP_GAIN_MASK                   0x00F0  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_SHIFT                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_WIDTH                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_RATE_MASK                   0x0006  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_SHIFT                       1  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_WIDTH                       2  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_ENA                         0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_MASK                    0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_SHIFT                        0  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_WIDTH                        1  /* BEEP_ENA */
+
+/*
+ * R115 (0x73) - Oscillator Trim (3)
+ */
+#define WM8962_OSC_TRIM_XTI_MASK                0x001F  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_SHIFT                    0  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_WIDTH                    5  /* OSC_TRIM_XTI - [4:0] */
+
+/*
+ * R116 (0x74) - Oscillator Trim (4)
+ */
+#define WM8962_OSC_TRIM_XTO_MASK                0x001F  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_SHIFT                    0  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_WIDTH                    5  /* OSC_TRIM_XTO - [4:0] */
+
+/*
+ * R119 (0x77) - Oscillator Trim (7)
+ */
+#define WM8962_XTO_CAP_SEL_MASK                 0x00F0  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_SHIFT                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_WIDTH                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTI_CAP_SEL_MASK                 0x000F  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_SHIFT                     0  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_WIDTH                     4  /* XTI_CAP_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - Analogue Clocking1
+ */
+#define WM8962_CLKOUT2_SEL_MASK                 0x0060  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_SHIFT                     5  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_WIDTH                     2  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT3_SEL_MASK                 0x0018  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_SHIFT                     3  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_WIDTH                     2  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT5_SEL                      0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_MASK                 0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_SHIFT                     0  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_WIDTH                     1  /* CLKOUT5_SEL */
+
+/*
+ * R125 (0x7D) - Analogue Clocking2
+ */
+#define WM8962_PLL2_OUTDIV                      0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_MASK                 0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_SHIFT                     7  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_WIDTH                     1  /* PLL2_OUTDIV */
+#define WM8962_PLL3_OUTDIV                      0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_MASK                 0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_SHIFT                     6  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_WIDTH                     1  /* PLL3_OUTDIV */
+#define WM8962_PLL_SYSCLK_DIV_MASK              0x0018  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_SHIFT                  3  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_WIDTH                  2  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_CLKOUT3_DIV                      0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_MASK                 0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_SHIFT                     2  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_WIDTH                     1  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT2_DIV                      0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_MASK                 0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_SHIFT                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_WIDTH                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT5_DIV                      0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_MASK                 0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_SHIFT                     0  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_WIDTH                     1  /* CLKOUT5_DIV */
+
+/*
+ * R126 (0x7E) - Analogue Clocking3
+ */
+#define WM8962_CLKOUT2_OE                       0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_MASK                  0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_SHIFT                      3  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_WIDTH                      1  /* CLKOUT2_OE */
+#define WM8962_CLKOUT3_OE                       0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_MASK                  0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_SHIFT                      2  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_WIDTH                      1  /* CLKOUT3_OE */
+#define WM8962_CLKOUT5_OE                       0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_MASK                  0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_SHIFT                      0  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_WIDTH                      1  /* CLKOUT5_OE */
+
+/*
+ * R127 (0x7F) - PLL Software Reset
+ */
+#define WM8962_SW_RESET_PLL_MASK                0xFFFF  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_SHIFT                    0  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_WIDTH                   16  /* SW_RESET_PLL - [15:0] */
+
+/*
+ * R129 (0x81) - PLL2
+ */
+#define WM8962_OSC_ENA                          0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_MASK                     0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_SHIFT                         7  /* OSC_ENA */
+#define WM8962_OSC_ENA_WIDTH                         1  /* OSC_ENA */
+#define WM8962_PLL2_ENA                         0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_MASK                    0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_SHIFT                        5  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_WIDTH                        1  /* PLL2_ENA */
+#define WM8962_PLL3_ENA                         0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_MASK                    0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_SHIFT                        4  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_WIDTH                        1  /* PLL3_ENA */
+
+/*
+ * R131 (0x83) - PLL 4
+ */
+#define WM8962_PLL_CLK_SRC                      0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_MASK                 0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_SHIFT                     1  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_WIDTH                     1  /* PLL_CLK_SRC */
+#define WM8962_FLL_TO_PLL3                      0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_MASK                 0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_SHIFT                     0  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_WIDTH                     1  /* FLL_TO_PLL3 */
+
+/*
+ * R136 (0x88) - PLL 9
+ */
+#define WM8962_PLL2_FRAC                        0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_MASK                   0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_SHIFT                       6  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_WIDTH                       1  /* PLL2_FRAC */
+#define WM8962_PLL2_N_MASK                      0x001F  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_SHIFT                          0  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_WIDTH                          5  /* PLL2_N - [4:0] */
+
+/*
+ * R137 (0x89) - PLL 10
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R138 (0x8A) - PLL 11
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R139 (0x8B) - PLL 12
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R140 (0x8C) - PLL 13
+ */
+#define WM8962_PLL3_FRAC                        0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_MASK                   0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_SHIFT                       6  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_WIDTH                       1  /* PLL3_FRAC */
+#define WM8962_PLL3_N_MASK                      0x001F  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_SHIFT                          0  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_WIDTH                          5  /* PLL3_N - [4:0] */
+
+/*
+ * R141 (0x8D) - PLL 14
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R142 (0x8E) - PLL 15
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R143 (0x8F) - PLL 16
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R155 (0x9B) - FLL Control (1)
+ */
+#define WM8962_FLL_REFCLK_SRC_MASK              0x0060  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_SHIFT                  5  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8962_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8962_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R156 (0x9C) - FLL Control (2)
+ */
+#define WM8962_FLL_OUTDIV_MASK                  0x01F8  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_SHIFT                      3  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_REFCLK_DIV_MASK              0x0003  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_SHIFT                  0  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [1:0] */
+
+/*
+ * R157 (0x9D) - FLL Control (3)
+ */
+#define WM8962_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R159 (0x9F) - FLL Control (5)
+ */
+#define WM8962_FLL_FRC_NCO_VAL_MASK             0x007E  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_SHIFT                 1  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R160 (0xA0) - FLL Control (6)
+ */
+#define WM8962_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R161 (0xA1) - FLL Control (7)
+ */
+#define WM8962_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R162 (0xA2) - FLL Control (8)
+ */
+#define WM8962_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8962_REG_SYNC                         0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_MASK                    0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_SHIFT                        2  /* REG_SYNC */
+#define WM8962_REG_SYNC_WIDTH                        1  /* REG_SYNC */
+#define WM8962_AUTO_INC                         0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_MASK                    0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_SHIFT                        0  /* AUTO_INC */
+#define WM8962_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R256 (0x100) - DF1
+ */
+#define WM8962_DRC_DF1_ENA                      0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_MASK                 0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_SHIFT                     3  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_WIDTH                     1  /* DRC_DF1_ENA */
+#define WM8962_DF1_SHARED_COEFF                 0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_MASK            0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SHIFT                2  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_WIDTH                1  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SEL             0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_MASK        0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_SHIFT            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_WIDTH            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_ENA                          0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_MASK                     0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_SHIFT                         0  /* DF1_ENA */
+#define WM8962_DF1_ENA_WIDTH                         1  /* DF1_ENA */
+
+/*
+ * R257 (0x101) - DF2
+ */
+#define WM8962_DF1_COEFF_L0_MASK                0xFFFF  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_SHIFT                    0  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_WIDTH                   16  /* DF1_COEFF_L0 - [15:0] */
+
+/*
+ * R258 (0x102) - DF3
+ */
+#define WM8962_DF1_COEFF_L1_MASK                0xFFFF  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_SHIFT                    0  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_WIDTH                   16  /* DF1_COEFF_L1 - [15:0] */
+
+/*
+ * R259 (0x103) - DF4
+ */
+#define WM8962_DF1_COEFF_L2_MASK                0xFFFF  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_SHIFT                    0  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_WIDTH                   16  /* DF1_COEFF_L2 - [15:0] */
+
+/*
+ * R260 (0x104) - DF5
+ */
+#define WM8962_DF1_COEFF_R0_MASK                0xFFFF  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_SHIFT                    0  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_WIDTH                   16  /* DF1_COEFF_R0 - [15:0] */
+
+/*
+ * R261 (0x105) - DF6
+ */
+#define WM8962_DF1_COEFF_R1_MASK                0xFFFF  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_SHIFT                    0  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_WIDTH                   16  /* DF1_COEFF_R1 - [15:0] */
+
+/*
+ * R262 (0x106) - DF7
+ */
+#define WM8962_DF1_COEFF_R2_MASK                0xFFFF  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_SHIFT                    0  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_WIDTH                   16  /* DF1_COEFF_R2 - [15:0] */
+
+/*
+ * R264 (0x108) - LHPF1
+ */
+#define WM8962_LHPF_MODE                        0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_MASK                   0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_SHIFT                       1  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_WIDTH                       1  /* LHPF_MODE */
+#define WM8962_LHPF_ENA                         0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_MASK                    0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_SHIFT                        0  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_WIDTH                        1  /* LHPF_ENA */
+
+/*
+ * R265 (0x109) - LHPF2
+ */
+#define WM8962_LHPF_COEFF_MASK                  0xFFFF  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_SHIFT                      0  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_WIDTH                     16  /* LHPF_COEFF - [15:0] */
+
+/*
+ * R268 (0x10C) - THREED1
+ */
+#define WM8962_ADC_MONOMIX                      0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_MASK                 0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_SHIFT                     6  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_WIDTH                     1  /* ADC_MONOMIX */
+#define WM8962_THREED_SIGN_L                    0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_MASK               0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_SHIFT                   5  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_WIDTH                   1  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_R                    0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_MASK               0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_SHIFT                   4  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_WIDTH                   1  /* THREED_SIGN_R */
+#define WM8962_THREED_LHPF_MODE                 0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_MASK            0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_SHIFT                2  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_WIDTH                1  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_ENA                  0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_MASK             0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_SHIFT                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_WIDTH                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_ENA                       0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_MASK                  0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_SHIFT                      0  /* THREED_ENA */
+#define WM8962_THREED_ENA_WIDTH                      1  /* THREED_ENA */
+
+/*
+ * R269 (0x10D) - THREED2
+ */
+#define WM8962_THREED_FGAINL_MASK               0xF800  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_SHIFT                  11  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_WIDTH                   5  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_CGAINL_MASK               0x07C0  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_SHIFT                   6  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_WIDTH                   5  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_DELAYL_MASK               0x003C  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_SHIFT                   2  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_WIDTH                   4  /* THREED_DELAYL - [5:2] */
+
+/*
+ * R270 (0x10E) - THREED3
+ */
+#define WM8962_THREED_LHPF_COEFF_MASK           0xFFFF  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_SHIFT               0  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_WIDTH              16  /* THREED_LHPF_COEFF - [15:0] */
+
+/*
+ * R271 (0x10F) - THREED4
+ */
+#define WM8962_THREED_FGAINR_MASK               0xF800  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_SHIFT                  11  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_WIDTH                   5  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_CGAINR_MASK               0x07C0  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_SHIFT                   6  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_WIDTH                   5  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_DELAYR_MASK               0x003C  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_SHIFT                   2  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_WIDTH                   4  /* THREED_DELAYR - [5:2] */
+
+/*
+ * R276 (0x114) - DRC 1
+ */
+#define WM8962_DRC_SIG_DET_RMS_MASK             0x7C00  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_SHIFT                10  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_WIDTH                 5  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_PK_MASK              0x0300  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_SHIFT                  8  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_WIDTH                  2  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_NG_ENA                       0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_MASK                  0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_SHIFT                      7  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_WIDTH                      1  /* DRC_NG_ENA */
+#define WM8962_DRC_SIG_DET_MODE                 0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_MASK            0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_SHIFT                6  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_WIDTH                1  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET                      0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_MASK                 0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_SHIFT                     5  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_WIDTH                     1  /* DRC_SIG_DET */
+#define WM8962_DRC_KNEE2_OP_ENA                 0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_MASK            0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_SHIFT                4  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_WIDTH                1  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_QR                           0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_MASK                      0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_SHIFT                          3  /* DRC_QR */
+#define WM8962_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8962_DRC_ANTICLIP                     0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_MASK                0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_SHIFT                    2  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8962_DRC_MODE                         0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_MASK                    0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_SHIFT                        1  /* DRC_MODE */
+#define WM8962_DRC_MODE_WIDTH                        1  /* DRC_MODE */
+#define WM8962_DRC_ENA                          0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_MASK                     0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_SHIFT                         0  /* DRC_ENA */
+#define WM8962_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+
+/*
+ * R277 (0x115) - DRC 2
+ */
+#define WM8962_DRC_ATK_MASK                     0x1E00  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_SHIFT                         9  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_WIDTH                         4  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_DCY_MASK                     0x01E0  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_SHIFT                         5  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_WIDTH                         4  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_MINGAIN_MASK                 0x001C  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_WIDTH                     3  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R278 (0x116) - DRC 3
+ */
+#define WM8962_DRC_NG_MINGAIN_MASK              0xF000  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_SHIFT                 12  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_WIDTH                  4  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_QR_THR_MASK                  0x0C00  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_SHIFT                     10  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_DCY_MASK                  0x0300  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_SHIFT                      8  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_NG_EXP_MASK                  0x00C0  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_SHIFT                      6  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_WIDTH                      2  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R279 (0x117) - DRC 4
+ */
+#define WM8962_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R280 (0x118) - DRC 5
+ */
+#define WM8962_DRC_KNEE2_IP_MASK                0x03E0  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_SHIFT                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_WIDTH                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_OP_MASK                0x001F  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_SHIFT                    0  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_WIDTH                    5  /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R285 (0x11D) - Tloopback
+ */
+#define WM8962_TLB_ENA                          0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_MASK                     0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_SHIFT                         1  /* TLB_ENA */
+#define WM8962_TLB_ENA_WIDTH                         1  /* TLB_ENA */
+#define WM8962_TLB_MODE                         0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_MASK                    0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_SHIFT                        0  /* TLB_MODE */
+#define WM8962_TLB_MODE_WIDTH                        1  /* TLB_MODE */
+
+/*
+ * R335 (0x14F) - EQ1
+ */
+#define WM8962_EQ_SHARED_COEFF                  0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_MASK             0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SHIFT                 2  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_WIDTH                 1  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SEL              0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_MASK         0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_SHIFT             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_WIDTH             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8962_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R336 (0x150) - EQ2
+ */
+#define WM8962_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+
+/*
+ * R337 (0x151) - EQ3
+ */
+#define WM8962_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R338 (0x152) - EQ4
+ */
+#define WM8962_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R339 (0x153) - EQ5
+ */
+#define WM8962_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R340 (0x154) - EQ6
+ */
+#define WM8962_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R341 (0x155) - EQ7
+ */
+#define WM8962_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R342 (0x156) - EQ8
+ */
+#define WM8962_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R343 (0x157) - EQ9
+ */
+#define WM8962_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R344 (0x158) - EQ10
+ */
+#define WM8962_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R345 (0x159) - EQ11
+ */
+#define WM8962_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R346 (0x15A) - EQ12
+ */
+#define WM8962_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R347 (0x15B) - EQ13
+ */
+#define WM8962_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R348 (0x15C) - EQ14
+ */
+#define WM8962_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R349 (0x15D) - EQ15
+ */
+#define WM8962_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R350 (0x15E) - EQ16
+ */
+#define WM8962_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R351 (0x15F) - EQ17
+ */
+#define WM8962_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R352 (0x160) - EQ18
+ */
+#define WM8962_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R353 (0x161) - EQ19
+ */
+#define WM8962_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R354 (0x162) - EQ20
+ */
+#define WM8962_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R355 (0x163) - EQ21
+ */
+#define WM8962_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R356 (0x164) - EQ22
+ */
+#define WM8962_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+
+/*
+ * R357 (0x165) - EQ23
+ */
+#define WM8962_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R358 (0x166) - EQ24
+ */
+#define WM8962_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R359 (0x167) - EQ25
+ */
+#define WM8962_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R360 (0x168) - EQ26
+ */
+#define WM8962_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R361 (0x169) - EQ27
+ */
+#define WM8962_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R362 (0x16A) - EQ28
+ */
+#define WM8962_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R363 (0x16B) - EQ29
+ */
+#define WM8962_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R364 (0x16C) - EQ30
+ */
+#define WM8962_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R365 (0x16D) - EQ31
+ */
+#define WM8962_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R366 (0x16E) - EQ32
+ */
+#define WM8962_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R367 (0x16F) - EQ33
+ */
+#define WM8962_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R368 (0x170) - EQ34
+ */
+#define WM8962_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R369 (0x171) - EQ35
+ */
+#define WM8962_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R370 (0x172) - EQ36
+ */
+#define WM8962_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R371 (0x173) - EQ37
+ */
+#define WM8962_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R372 (0x174) - EQ38
+ */
+#define WM8962_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R373 (0x175) - EQ39
+ */
+#define WM8962_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R374 (0x176) - EQ40
+ */
+#define WM8962_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R375 (0x177) - EQ41
+ */
+#define WM8962_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R513 (0x201) - GPIO 2
+ */
+#define WM8962_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8962_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8962_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8962_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8962_GP2_FN_MASK                      0x001F  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_SHIFT                          0  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_WIDTH                          5  /* GP2_FN - [4:0] */
+
+/*
+ * R514 (0x202) - GPIO 3
+ */
+#define WM8962_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8962_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8962_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8962_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8962_GP3_FN_MASK                      0x001F  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_SHIFT                          0  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_WIDTH                          5  /* GP3_FN - [4:0] */
+
+/*
+ * R516 (0x204) - GPIO 5
+ */
+#define WM8962_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8962_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8962_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8962_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8962_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8962_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8962_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8962_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8962_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8962_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8962_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8962_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8962_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8962_GP5_FN_MASK                      0x001F  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_SHIFT                          0  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_WIDTH                          5  /* GP5_FN - [4:0] */
+
+/*
+ * R517 (0x205) - GPIO 6
+ */
+#define WM8962_GP6_DIR                          0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_MASK                     0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_SHIFT                        15  /* GP6_DIR */
+#define WM8962_GP6_DIR_WIDTH                         1  /* GP6_DIR */
+#define WM8962_GP6_PU                           0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_MASK                      0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_SHIFT                         14  /* GP6_PU */
+#define WM8962_GP6_PU_WIDTH                          1  /* GP6_PU */
+#define WM8962_GP6_PD                           0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_MASK                      0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_SHIFT                         13  /* GP6_PD */
+#define WM8962_GP6_PD_WIDTH                          1  /* GP6_PD */
+#define WM8962_GP6_POL                          0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_MASK                     0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_SHIFT                        10  /* GP6_POL */
+#define WM8962_GP6_POL_WIDTH                         1  /* GP6_POL */
+#define WM8962_GP6_OP_CFG                       0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_MASK                  0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_SHIFT                      9  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_WIDTH                      1  /* GP6_OP_CFG */
+#define WM8962_GP6_DB                           0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_MASK                      0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_SHIFT                          8  /* GP6_DB */
+#define WM8962_GP6_DB_WIDTH                          1  /* GP6_DB */
+#define WM8962_GP6_LVL                          0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_MASK                     0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_SHIFT                         6  /* GP6_LVL */
+#define WM8962_GP6_LVL_WIDTH                         1  /* GP6_LVL */
+#define WM8962_GP6_FN_MASK                      0x001F  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_SHIFT                          0  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_WIDTH                          5  /* GP6_FN - [4:0] */
+
+/*
+ * R560 (0x230) - Interrupt Status 1
+ */
+#define WM8962_GP6_EINT                         0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_MASK                    0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_SHIFT                        5  /* GP6_EINT */
+#define WM8962_GP6_EINT_WIDTH                        1  /* GP6_EINT */
+#define WM8962_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8962_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+
+/*
+ * R561 (0x231) - Interrupt Status 2
+ */
+#define WM8962_MICSCD_EINT                      0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_MASK                 0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_SHIFT                    15  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_WIDTH                     1  /* MICSCD_EINT */
+#define WM8962_MICD_EINT                        0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_MASK                   0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_SHIFT                      14  /* MICD_EINT */
+#define WM8962_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+#define WM8962_FIFOS_ERR_EINT                   0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_MASK              0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_SHIFT                 13  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8962_ALC_LOCK_EINT                    0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_MASK               0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_SHIFT                  12  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_WIDTH                   1  /* ALC_LOCK_EINT */
+#define WM8962_ALC_THRESH_EINT                  0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_MASK             0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_SHIFT                11  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_WIDTH                 1  /* ALC_THRESH_EINT */
+#define WM8962_ALC_SAT_EINT                     0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_MASK                0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_SHIFT                   10  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_WIDTH                    1  /* ALC_SAT_EINT */
+#define WM8962_ALC_PKOVR_EINT                   0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_MASK              0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_SHIFT                  9  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_WIDTH                  1  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_NGATE_EINT                   0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_MASK              0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_SHIFT                  8  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_WIDTH                  1  /* ALC_NGATE_EINT */
+#define WM8962_WSEQ_DONE_EINT                   0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_MASK              0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_SHIFT                  7  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8962_DRC_ACTDET_EINT                  0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_MASK             0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_SHIFT                 6  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_WIDTH                 1  /* DRC_ACTDET_EINT */
+#define WM8962_FLL_LOCK_EINT                    0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_MASK               0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_SHIFT                   5  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT                   0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_MASK              0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_SHIFT                  3  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_WIDTH                  1  /* PLL3_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT                   0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_MASK              0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_SHIFT                  2  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_WIDTH                  1  /* PLL2_LOCK_EINT */
+#define WM8962_TEMP_SHUT_EINT                   0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_MASK              0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_SHIFT                  0  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_WIDTH                  1  /* TEMP_SHUT_EINT */
+
+/*
+ * R568 (0x238) - Interrupt Status 1 Mask
+ */
+#define WM8962_IM_GP6_EINT                      0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_MASK                 0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_SHIFT                     5  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_WIDTH                     1  /* IM_GP6_EINT */
+#define WM8962_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+
+/*
+ * R569 (0x239) - Interrupt Status 2 Mask
+ */
+#define WM8962_IM_MICSCD_EINT                   0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_MASK              0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_SHIFT                 15  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_WIDTH                  1  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICD_EINT                     0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_MASK                0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_SHIFT                   14  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT                0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_MASK           0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_SHIFT              13  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_ALC_LOCK_EINT                 0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_MASK            0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_SHIFT               12  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_WIDTH                1  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_THRESH_EINT               0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_MASK          0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_SHIFT             11  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_WIDTH              1  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_SAT_EINT                  0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_MASK             0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_SHIFT                10  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_WIDTH                 1  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT                0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_MASK           0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_SHIFT               9  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_WIDTH               1  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_NGATE_EINT                0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_MASK           0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_SHIFT               8  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_WIDTH               1  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT                0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_MASK           0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_SHIFT               7  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT               0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_MASK          0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_SHIFT              6  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_WIDTH              1  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_FLL_LOCK_EINT                 0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_MASK            0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_SHIFT                5  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT                0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_MASK           0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_SHIFT               3  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_WIDTH               1  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT                0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_MASK           0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_SHIFT               2  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_WIDTH               1  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT                0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_MASK           0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_SHIFT               0  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_WIDTH               1  /* IM_TEMP_SHUT_EINT */
+
+/*
+ * R576 (0x240) - Interrupt Control
+ */
+#define WM8962_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8962_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R584 (0x248) - IRQ Debounce
+ */
+#define WM8962_FLL_LOCK_DB                      0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_MASK                 0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_SHIFT                     5  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_WIDTH                     1  /* FLL_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB                     0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_MASK                0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_SHIFT                    3  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_WIDTH                    1  /* PLL3_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB                     0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_MASK                0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_SHIFT                    2  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_WIDTH                    1  /* PLL2_LOCK_DB */
+#define WM8962_TEMP_SHUT_DB                     0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_MASK                0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_SHIFT                    0  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_WIDTH                    1  /* TEMP_SHUT_DB */
+
+/*
+ * R586 (0x24A) -  MICINT Source Pol
+ */
+#define WM8962_MICSCD_IRQ_POL                   0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_MASK              0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_SHIFT                 15  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_WIDTH                  1  /* MICSCD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL                     0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_MASK                0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_SHIFT                   14  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_WIDTH                    1  /* MICD_IRQ_POL */
+
+/*
+ * R768 (0x300) - DSP2 Power Management
+ */
+#define WM8962_DSP2_ENA                         0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_MASK                    0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_SHIFT                        0  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_WIDTH                        1  /* DSP2_ENA */
+
+/*
+ * R1037 (0x40D) - DSP2_ExecControl
+ */
+#define WM8962_DSP2_STOPC                       0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_MASK                  0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_SHIFT                      5  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_WIDTH                      1  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPS                       0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_MASK                  0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_SHIFT                      4  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_WIDTH                      1  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPI                       0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_MASK                  0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_SHIFT                      3  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_WIDTH                      1  /* DSP2_STOPI */
+#define WM8962_DSP2_STOP                        0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_MASK                   0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_SHIFT                       2  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_WIDTH                       1  /* DSP2_STOP */
+#define WM8962_DSP2_RUNR                        0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_MASK                   0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_SHIFT                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_WIDTH                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUN                         0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_MASK                    0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_SHIFT                        0  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_WIDTH                        1  /* DSP2_RUN */
+
+/*
+ * R8192 (0x2000) - DSP2 Instruction RAM 0
+ */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_MASK  0x03FF  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_SHIFT      0  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_WIDTH     10  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+
+/*
+ * R9216 (0x2400) - DSP2 Address RAM 2
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_MASK 0x003F  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_WIDTH      6  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+
+/*
+ * R9217 (0x2401) - DSP2 Address RAM 1
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_MASK 0xFFFF  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+
+/*
+ * R9218 (0x2402) - DSP2 Address RAM 0
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_MASK  0xFFFF  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+
+/*
+ * R12288 (0x3000) - DSP2 Data1 RAM 1
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R12289 (0x3001) - DSP2 Data1 RAM 0
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R13312 (0x3400) - DSP2 Data2 RAM 1
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R13313 (0x3401) - DSP2 Data2 RAM 0
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R14336 (0x3800) - DSP2 Data3 RAM 1
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R14337 (0x3801) - DSP2 Data3 RAM 0
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R15360 (0x3C00) - DSP2 Coeff RAM 0
+ */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_MASK   0x07FF  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_SHIFT       0  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_WIDTH      11  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+
+/*
+ * R16384 (0x4000) - RETUNEADC_SHARED_COEFF_1
+ */
+#define WM8962_ADC_RETUNE_SCV                   0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_MASK              0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_SHIFT                  7  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_WIDTH                  1  /* ADC_RETUNE_SCV */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_MASK 0x007F  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_SHIFT      0  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_WIDTH      7  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+
+/*
+ * R16385 (0x4001) - RETUNEADC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16386 (0x4002) - RETUNEDAC_SHARED_COEFF_1
+ */
+#define WM8962_DAC_RETUNE_SCV                   0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_MASK              0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_SHIFT                  7  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_WIDTH                  1  /* DAC_RETUNE_SCV */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_MASK 0x007F  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_WIDTH      7  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+
+/*
+ * R16387 (0x4003) - RETUNEDAC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16388 (0x4004) - SOUNDSTAGE_ENABLES_1
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_MASK    0x00FF  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_SHIFT        0  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_WIDTH        8  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+
+/*
+ * R16389 (0x4005) - SOUNDSTAGE_ENABLES_0
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_MASK    0xFFC0  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_SHIFT        6  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_WIDTH       10  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_RTN_ADC_ENA                      0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_MASK                 0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_SHIFT                     5  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_WIDTH                     1  /* RTN_ADC_ENA */
+#define WM8962_RTN_DAC_ENA                      0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_MASK                 0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_SHIFT                     4  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_WIDTH                     1  /* RTN_DAC_ENA */
+#define WM8962_HDBASS_ENA                       0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_MASK                  0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_SHIFT                      3  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_WIDTH                      1  /* HDBASS_ENA */
+#define WM8962_HPF2_ENA                         0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_MASK                    0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_SHIFT                        2  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_WIDTH                        1  /* HPF2_ENA */
+#define WM8962_HPF1_ENA                         0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_MASK                    0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_SHIFT                        1  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_WIDTH                        1  /* HPF1_ENA */
+#define WM8962_VSS_ENA                          0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_MASK                     0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_SHIFT                         0  /* VSS_ENA */
+#define WM8962_VSS_ENA_WIDTH                         1  /* VSS_ENA */
+
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif
index a99620f335d2ab7fe7ace8dc37a5e1b6b637c61e..63f6dbf5d07021887084e57541591bf1fa570fb3 100644 (file)
 
 #include "wm8971.h"
 
-#define WM8971_VERSION "0.9"
-
 #define        WM8971_REG_COUNT                43
 
 static struct workqueue_struct *wm8971_workq = NULL;
 
 /* codec private data */
 struct wm8971_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
 };
 
@@ -492,8 +491,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +571,8 @@ static struct snd_soc_dai_ops wm8971_dai_ops = {
        .set_sysclk     = wm8971_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8971_dai = {
-       .name = "WM8971",
+static struct snd_soc_dai_driver wm8971_dai = {
+       .name = "wm8971-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -589,7 +587,6 @@ struct snd_soc_dai wm8971_dai = {
                .formats = WM8971_FORMATS,},
        .ops = &wm8971_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8971_dai);
 
 static void wm8971_work(struct work_struct *work)
 {
@@ -598,19 +595,14 @@ static void wm8971_work(struct work_struct *work)
        wm8971_set_bias_level(codec, codec->bias_level);
 }
 
-static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8971_resume(struct platform_device *pdev)
+static int wm8971_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -639,37 +631,24 @@ static int wm8971_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8971_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8971_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int reg, ret = 0;
-
-       codec->name = "WM8971";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8971_set_bias_level;
-       codec->dai = &wm8971_dai;
-       codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
-       codec->num_dai = 1;
-       codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+       u16 reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       wm8971_reset(codec);
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+       wm8971_workq = create_workqueue("wm8971");
+       if (wm8971_workq == NULL)
+               return -ENOMEM;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8971: failed to create pcms\n");
-               goto err;
-       }
+       wm8971_reset(codec);
 
        /* charge output caps - set vmid to 5k for quick power up */
        reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -704,40 +683,54 @@ static int wm8971_init(struct snd_soc_device *socdev,
        wm8971_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8971_socdev;
 
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+/* power down chip */
+static int wm8971_remove(struct snd_soc_codec *codec)
+{
+       wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       if (wm8971_workq)
+               destroy_workqueue(wm8971_workq);
+       return 0;
+}
 
-static int wm8971_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
+       .probe =        wm8971_probe,
+       .remove =       wm8971_remove,
+       .suspend =      wm8971_suspend,
+       .resume =       wm8971_resume,
+       .set_bias_level = wm8971_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8971_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8971_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8971_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8971_priv *wm8971;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
+       wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+       if (wm8971 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = i2c;
+       i2c_set_clientdata(i2c, wm8971);
 
-       ret = wm8971_init(socdev, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8971, &wm8971_dai, 1);
        if (ret < 0)
-               pr_err("failed to initialise WM8971\n");
-
+               kfree(wm8971);
        return ret;
 }
 
-static int wm8971_i2c_remove(struct i2c_client *client)
+static __devexit int wm8971_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -749,148 +742,34 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
 
 static struct i2c_driver wm8971_i2c_driver = {
        .driver = {
-               .name = "WM8971 I2C Codec",
+               .name = "wm8971-codec",
                .owner = THIS_MODULE,
        },
-       .probe    = wm8971_i2c_probe,
-       .remove   = wm8971_i2c_remove,
+       .probe =    wm8971_i2c_probe,
+       .remove =   __devexit_p(wm8971_i2c_remove),
        .id_table = wm8971_i2c_id,
 };
-
-static int wm8971_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8971_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&wm8971_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8971_i2c_driver);
-       return -ENODEV;
-}
-
 #endif
 
-static int wm8971_probe(struct platform_device *pdev)
+static int __init wm8971_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8971_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct wm8971_priv *wm8971;
        int ret = 0;
-
-       pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
-       if (wm8971 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, wm8971);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8971_socdev = socdev;
-
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
-       wm8971_workq = create_workqueue("wm8971");
-       if (wm8971_workq == NULL) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8971_add_i2c_device(pdev, setup);
-       }
-#endif
-       /* Add other interfaces here */
-
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8971_i2c_driver);
        if (ret != 0) {
-               destroy_workqueue(wm8971_workq);
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
+                      ret);
        }
-
-       return ret;
-}
-
-/* power down chip */
-static int wm8971_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       if (wm8971_workq)
-               destroy_workqueue(wm8971_workq);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
-       i2c_del_driver(&wm8971_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8971 = {
-       .probe =        wm8971_probe,
-       .remove =       wm8971_remove,
-       .suspend =      wm8971_suspend,
-       .resume =       wm8971_resume,
-};
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
-
-static int __init wm8971_modinit(void)
-{
-       return snd_soc_register_dai(&wm8971_dai);
+       return ret;
 }
 module_init(wm8971_modinit);
 
 static void __exit wm8971_exit(void)
 {
-       snd_soc_unregister_dai(&wm8971_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8971_i2c_driver);
+#endif
 }
 module_exit(wm8971_exit);
 
index ef4f08f9f344b0a5b7146a4015a3686afebbab87..f31c38fddfc45eaedb118ed02279aed81aaa2775 100644 (file)
 
 #define WM8971_SYSCLK  0
 
-struct wm8971_setup_data {
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8971_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8971;
-
 #endif
index 1468fe10cbbe54d57ce5d072b5406261487d2bc8..b4363f6d19b3b2b8437dcce636aa9545d023544e 100644 (file)
@@ -51,12 +51,10 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
 #define WM8974_POWER1_BUFIOEN 0x04
 
 struct wm8974_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8974_CACHEREGNUM];
 };
 
-static struct snd_soc_codec *wm8974_codec;
-
 #define wm8974_reset(c)        snd_soc_write(c, WM8974_RESET, 0)
 
 static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -566,8 +564,8 @@ static struct snd_soc_dai_ops wm8974_ops = {
        .set_pll = wm8974_set_dai_pll,
 };
 
-struct snd_soc_dai wm8974_dai = {
-       .name = "WM8974 HiFi",
+static struct snd_soc_dai_driver wm8974_dai = {
+       .name = "wm8974-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -583,21 +581,15 @@ struct snd_soc_dai wm8974_dai = {
        .ops = &wm8974_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8974_dai);
 
-static int wm8974_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8974_resume(struct platform_device *pdev)
+static int wm8974_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -613,156 +605,72 @@ static int wm8974_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8974_probe(struct platform_device *pdev)
+static int wm8974_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
-       if (wm8974_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8974_codec;
-       codec = wm8974_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8974_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm8974_snd_controls,
                             ARRAY_SIZE(wm8974_snd_controls));
        wm8974_add_widgets(codec);
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
 /* power down chip */
-static int wm8974_remove(struct platform_device *pdev)
+static int wm8974_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8974 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
        .probe =        wm8974_probe,
        .remove =       wm8974_remove,
        .suspend =      wm8974_suspend,
        .resume =       wm8974_resume,
+       .set_bias_level = wm8974_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8974_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8974_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
-
-static __devinit int wm8974_register(struct wm8974_priv *wm8974)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8974->codec;
-
-       if (wm8974_codec) {
-               dev_err(codec->dev, "Another WM8974 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8974);
-       codec->name = "WM8974";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8974_set_bias_level;
-       codec->dai = &wm8974_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8974_CACHEREGNUM;
-       codec->reg_cache = &wm8974->reg_cache;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
-
-       ret = wm8974_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
-       }
-
-       wm8974_dai.dev = codec->dev;
-
-       wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       wm8974_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8974_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8974);
-       return ret;
-}
-
-static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
-{
-       wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8974_dai);
-       snd_soc_unregister_codec(&wm8974->codec);
-       kfree(wm8974);
-       wm8974_codec = NULL;
-}
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8974_priv *wm8974;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
        if (wm8974 == NULL)
                return -ENOMEM;
 
-       codec = &wm8974->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8974);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
 
-       return wm8974_register(wm8974);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8974, &wm8974_dai, 1);
+       if (ret < 0)
+               kfree(wm8974);
+       return ret;
 }
 
 static __devexit int wm8974_i2c_remove(struct i2c_client *client)
 {
-       struct wm8974_priv *wm8974 = i2c_get_clientdata(client);
-       wm8974_unregister(wm8974);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -774,23 +682,34 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
 
 static struct i2c_driver wm8974_i2c_driver = {
        .driver = {
-               .name = "WM8974",
+               .name = "wm8974-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8974_i2c_probe,
        .remove =   __devexit_p(wm8974_i2c_remove),
        .id_table = wm8974_i2c_id,
 };
+#endif
 
 static int __init wm8974_modinit(void)
 {
-       return i2c_add_driver(&wm8974_i2c_driver);
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8974_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
 }
 module_init(wm8974_modinit);
 
 static void __exit wm8974_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8974_i2c_driver);
+#endif
 }
 module_exit(wm8974_exit);
 
index 896a7f0f3fc4b189e0537bb6f7765639e2957b65..3c94e7bb55a6b21e12170c736e95b75e8cf80b7a 100644 (file)
@@ -83,7 +83,4 @@
 #define WM8974_MCLKDIV_8       (6 << 5)
 #define WM8974_MCLKDIV_12      (7 << 5)
 
-extern struct snd_soc_dai wm8974_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8974;
-
 #endif
index 8a1ad778e7e345d42780fec7baccbb6e0f9b984e..13b979a71a7cfc6847a4f8cd72d21f10778c2dc4 100644 (file)
@@ -31,8 +31,6 @@
 
 #include "wm8978.h"
 
-static struct snd_soc_codec *wm8978_codec;
-
 /* wm8978 register cache. Note that register 0 is not included in the cache. */
 static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
        0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
@@ -54,7 +52,8 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
 
 /* codec private data */
 struct wm8978_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        unsigned int f_pllout;
        unsigned int f_mclk;
        unsigned int f_256fs;
@@ -374,8 +373,8 @@ struct wm8978_pll_div {
 
 #define FIXED_PLL_SIZE (1 << 24)
 
-static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
-                       unsigned int source)
+static void pll_factors(struct snd_soc_codec *codec,
+               struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
 {
        u64 k_part;
        unsigned int k, n_div, n_mod;
@@ -390,7 +389,7 @@ static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
        }
 
        if (n_div < 6 || n_div > 12)
-               dev_warn(wm8978_codec->dev,
+               dev_warn(codec->dev,
                         "WM8978 N value exceeds recommended range! N = %u\n",
                         n_div);
 
@@ -505,7 +504,7 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
        dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
                wm8978->f_mclk, wm8978->f_pllout);
 
-       pll_factors(&pll_div, f2, wm8978->f_mclk);
+       pll_factors(codec, &pll_div, f2, wm8978->f_mclk);
 
        dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
                __func__, pll_div.n, pll_div.k, pll_div.div2);
@@ -690,8 +689,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
        /* Word length mask = 0x60 */
        u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
@@ -875,9 +873,8 @@ static struct snd_soc_dai_ops wm8978_dai_ops = {
 };
 
 /* Also supports 12kHz */
-struct snd_soc_dai wm8978_dai = {
-       .name = "WM8978 HiFi",
-       .id = 1,
+static struct snd_soc_dai_driver wm8978_dai = {
+       .name = "wm8978-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -894,13 +891,9 @@ struct snd_soc_dai wm8978_dai = {
        },
        .ops = &wm8978_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8978_dai);
 
-static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
        /* Also switch PLL off */
        snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
@@ -908,10 +901,8 @@ static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8978_resume(struct platform_device *pdev)
+static int wm8978_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 *cache = codec->reg_cache;
@@ -933,54 +924,6 @@ static int wm8978_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8978_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8978_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8978_codec;
-       codec = wm8978_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8978_snd_controls,
-                            ARRAY_SIZE(wm8978_snd_controls));
-       wm8978_add_widgets(codec);
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8978_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8978 = {
-       .probe          = wm8978_probe,
-       .remove         = wm8978_remove,
-       .suspend        = wm8978_suspend,
-       .resume         = wm8978_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978);
-
 /*
  * These registers contain an "update" bit - bit 8. This means, for example,
  * that one can write new DAC digital volume for both channels, but only when
@@ -1000,44 +943,23 @@ static const int update_reg[] = {
        WM8978_ROUT2_SPK_CONTROL,
 };
 
-static __devinit int wm8978_register(struct wm8978_priv *wm8978)
+static int wm8978_probe(struct snd_soc_codec *codec)
 {
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8978->codec;
-
-       if (wm8978_codec) {
-               dev_err(codec->dev, "Another WM8978 is registered\n");
-               return -EINVAL;
-       }
+       struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, i;
 
        /*
         * Set default system clock to PLL, it is more precise, this is also the
         * default hardware setting
         */
        wm8978->sysclk = WM8978_PLL;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8978);
-       codec->name = "WM8978";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8978_set_bias_level;
-       codec->dai = &wm8978_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8978_CACHEREGNUM;
-       codec->reg_cache = &wm8978->reg_cache;
-
+       codec->control_data = wm8978->control_data;
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg));
-
        /*
         * Set the update bit in all registers, that have one. This way all
         * writes to those registers will also cause the update bit to be
@@ -1050,74 +972,61 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
        ret = snd_soc_write(codec, WM8978_RESET, 0);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8978_dai.dev = codec->dev;
-
        wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8978_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8978_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8978_snd_controls,
+                            ARRAY_SIZE(wm8978_snd_controls));
+       wm8978_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       return ret;
 }
 
-static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
+/* power down chip */
+static int wm8978_remove(struct snd_soc_codec *codec)
 {
-       wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8978_dai);
-       snd_soc_unregister_codec(&wm8978->codec);
-       wm8978_codec = NULL;
+       wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
+       .probe =        wm8978_probe,
+       .remove =       wm8978_remove,
+       .suspend =      wm8978_suspend,
+       .resume =       wm8978_resume,
+       .set_bias_level = wm8978_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8978_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8978_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
-       int ret;
        struct wm8978_priv *wm8978;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
        if (wm8978 == NULL)
                return -ENOMEM;
 
-       codec = &wm8978->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8978);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8978->control_data = i2c;
 
-       ret = wm8978_register(wm8978);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8978, &wm8978_dai, 1);
        if (ret < 0)
                kfree(wm8978);
-
        return ret;
 }
 
 static __devexit int wm8978_i2c_remove(struct i2c_client *client)
 {
-       struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
-       wm8978_unregister(wm8978);
-       kfree(wm8978);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1129,23 +1038,34 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
 
 static struct i2c_driver wm8978_i2c_driver = {
        .driver = {
-               .name = "WM8978",
+               .name = "wm8978",
                .owner = THIS_MODULE,
        },
        .probe =    wm8978_i2c_probe,
        .remove =   __devexit_p(wm8978_i2c_remove),
        .id_table = wm8978_i2c_id,
 };
+#endif
 
 static int __init wm8978_modinit(void)
 {
-       return i2c_add_driver(&wm8978_i2c_driver);
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8978_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
 }
 module_init(wm8978_modinit);
 
 static void __exit wm8978_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8978_i2c_driver);
+#endif
 }
 module_exit(wm8978_exit);
 
index 56ec83270917db070872ea5a9756e83b9bf16220..c75525b7f154c9fe25e88a91cb55e99d7e0b37c2 100644 (file)
@@ -80,7 +80,4 @@ enum wm8978_sysclk_src {
        WM8978_MCLK
 };
 
-extern struct snd_soc_dai wm8978_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8978;
-
 #endif /* __WM8978_H__ */
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
new file mode 100644 (file)
index 0000000..fd2e7cc
--- /dev/null
@@ -0,0 +1,1192 @@
+/*
+ * wm8985.c  --  WM8985 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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.
+ *
+ * TODO:
+ *  o Add OUT3/OUT4 mixer controls.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8985.h"
+
+#define WM8985_NUM_SUPPLIES 4
+static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD1",
+       "AVDD2"
+};
+
+static const u16 wm8985_reg_defs[] = {
+       0x0000,     /* R0  - Software Reset */
+       0x0000,     /* R1  - Power management 1 */
+       0x0000,     /* R2  - Power management 2 */
+       0x0000,     /* R3  - Power management 3 */
+       0x0050,     /* R4  - Audio Interface */
+       0x0000,     /* R5  - Companding control */
+       0x0140,     /* R6  - Clock Gen control */
+       0x0000,     /* R7  - Additional control */
+       0x0000,     /* R8  - GPIO Control */
+       0x0000,     /* R9  - Jack Detect Control 1 */
+       0x0000,     /* R10 - DAC Control */
+       0x00FF,     /* R11 - Left DAC digital Vol */
+       0x00FF,     /* R12 - Right DAC digital vol */
+       0x0000,     /* R13 - Jack Detect Control 2 */
+       0x0100,     /* R14 - ADC Control */
+       0x00FF,     /* R15 - Left ADC Digital Vol */
+       0x00FF,     /* R16 - Right ADC Digital Vol */
+       0x0000,     /* R17 */
+       0x012C,     /* R18 - EQ1 - low shelf */
+       0x002C,     /* R19 - EQ2 - peak 1 */
+       0x002C,     /* R20 - EQ3 - peak 2 */
+       0x002C,     /* R21 - EQ4 - peak 3 */
+       0x002C,     /* R22 - EQ5 - high shelf */
+       0x0000,     /* R23 */
+       0x0032,     /* R24 - DAC Limiter 1 */
+       0x0000,     /* R25 - DAC Limiter 2 */
+       0x0000,     /* R26 */
+       0x0000,     /* R27 - Notch Filter 1 */
+       0x0000,     /* R28 - Notch Filter 2 */
+       0x0000,     /* R29 - Notch Filter 3 */
+       0x0000,     /* R30 - Notch Filter 4 */
+       0x0000,     /* R31 */
+       0x0038,     /* R32 - ALC control 1 */
+       0x000B,     /* R33 - ALC control 2 */
+       0x0032,     /* R34 - ALC control 3 */
+       0x0000,     /* R35 - Noise Gate */
+       0x0008,     /* R36 - PLL N */
+       0x000C,     /* R37 - PLL K 1 */
+       0x0093,     /* R38 - PLL K 2 */
+       0x00E9,     /* R39 - PLL K 3 */
+       0x0000,     /* R40 */
+       0x0000,     /* R41 - 3D control */
+       0x0000,     /* R42 - OUT4 to ADC */
+       0x0000,     /* R43 - Beep control */
+       0x0033,     /* R44 - Input ctrl */
+       0x0010,     /* R45 - Left INP PGA gain ctrl */
+       0x0010,     /* R46 - Right INP PGA gain ctrl */
+       0x0100,     /* R47 - Left ADC BOOST ctrl */
+       0x0100,     /* R48 - Right ADC BOOST ctrl */
+       0x0002,     /* R49 - Output ctrl */
+       0x0001,     /* R50 - Left mixer ctrl */
+       0x0001,     /* R51 - Right mixer ctrl */
+       0x0039,     /* R52 - LOUT1 (HP) volume ctrl */
+       0x0039,     /* R53 - ROUT1 (HP) volume ctrl */
+       0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */
+       0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */
+       0x0001,     /* R56 - OUT3 mixer ctrl */
+       0x0001,     /* R57 - OUT4 (MONO) mix ctrl */
+       0x0001,     /* R58 */
+       0x0000,     /* R59 */
+       0x0004,     /* R60 - OUTPUT ctrl */
+       0x0000,     /* R61 - BIAS CTRL */
+       0x0180,     /* R62 */
+       0x0000      /* R63 */
+};
+
+/*
+ * latch bit 8 of these registers to ensure instant
+ * volume updates
+ */
+static const int volume_update_regs[] = {
+       WM8985_LEFT_DAC_DIGITAL_VOL,
+       WM8985_RIGHT_DAC_DIGITAL_VOL,
+       WM8985_LEFT_ADC_DIGITAL_VOL,
+       WM8985_RIGHT_ADC_DIGITAL_VOL,
+       WM8985_LOUT2_SPK_VOLUME_CTRL,
+       WM8985_ROUT2_SPK_VOLUME_CTRL,
+       WM8985_LOUT1_HP_VOLUME_CTRL,
+       WM8985_ROUT1_HP_VOLUME_CTRL,
+       WM8985_LEFT_INP_PGA_GAIN_CTRL,
+       WM8985_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8985_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+       unsigned int sysclk;
+       unsigned int bclk;
+};
+
+static const struct {
+       int div;
+       int ratio;
+} fs_ratios[] = {
+       { 10, 128 },
+       { 15, 192 },
+       { 20, 256 },
+       { 30, 384 },
+       { 40, 512 },
+       { 60, 768 },
+       { 80, 1024 },
+       { 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+       1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
+                                 alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
+                                 alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+                                 filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+       "80Hz", "105Hz", "135Hz", "175Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+                                 eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+       "230Hz", "300Hz", "385Hz", "500Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
+                                 eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+       "650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+                                 eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+       "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
+                                 eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+       "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+                                 eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+       "Off",
+       "6.67%",
+       "13.3%",
+       "20%",
+       "26.7%",
+       "33.3%",
+       "40%",
+       "46.6%",
+       "53.3%",
+       "60%",
+       "66.7%",
+       "73.3%",
+       "80%",
+       "86.7%",
+       "93.3%",
+       "100%"
+};
+static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
+                                 depth_3d_text);
+
+static const struct snd_kcontrol_new wm8985_snd_controls[] = {
+       SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
+               0, 1, 0),
+
+       SOC_ENUM("ALC Capture Function", alc_sel),
+       SOC_SINGLE_TLV("ALC Capture Max Volume", WM8985_ALC_CONTROL_1,
+               3, 7, 0, alc_max_tlv),
+       SOC_SINGLE_TLV("ALC Capture Min Volume", WM8985_ALC_CONTROL_1,
+               0, 7, 0, alc_min_tlv),
+       SOC_SINGLE_TLV("ALC Capture Target Volume", WM8985_ALC_CONTROL_2,
+               0, 15, 0, alc_tar_tlv),
+       SOC_SINGLE("ALC Capture Attack", WM8985_ALC_CONTROL_3, 0, 10, 0),
+       SOC_SINGLE("ALC Capture Hold", WM8985_ALC_CONTROL_2, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Decay", WM8985_ALC_CONTROL_3, 4, 10, 0),
+       SOC_ENUM("ALC Mode", alc_mode),
+       SOC_SINGLE("ALC Capture NG Switch", WM8985_NOISE_GATE,
+               3, 1, 0),
+       SOC_SINGLE("ALC Capture NG Threshold", WM8985_NOISE_GATE,
+               0, 7, 1),
+
+       SOC_DOUBLE_R_TLV("Capture Volume", WM8985_LEFT_ADC_DIGITAL_VOL,
+               WM8985_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+       SOC_DOUBLE_R("Capture PGA ZC Switch", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               WM8985_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               WM8985_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+       SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+               WM8985_LEFT_ADC_BOOST_CTRL, WM8985_RIGHT_ADC_BOOST_CTRL,
+               8, 1, 0, pga_boost_tlv),
+
+       SOC_DOUBLE("ADC Inversion Switch", WM8985_ADC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Playback Volume", WM8985_LEFT_DAC_DIGITAL_VOL,
+               WM8985_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+       SOC_SINGLE("DAC Playback Limiter Switch", WM8985_DAC_LIMITER_1, 8, 1, 0),
+       SOC_SINGLE("DAC Playback Limiter Decay", WM8985_DAC_LIMITER_1, 4, 10, 0),
+       SOC_SINGLE("DAC Playback Limiter Attack", WM8985_DAC_LIMITER_1, 0, 11, 0),
+       SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8985_DAC_LIMITER_2,
+               4, 7, 1, lim_thresh_tlv),
+       SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8985_DAC_LIMITER_2,
+               0, 12, 0, lim_boost_tlv),
+       SOC_DOUBLE("DAC Inversion Switch", WM8985_DAC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("DAC Auto Mute Switch", WM8985_DAC_CONTROL, 2, 1, 0),
+       SOC_SINGLE("DAC 128x Oversampling Switch", WM8985_DAC_CONTROL, 3, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Headphone Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Speaker Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_SINGLE("High Pass Filter Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+       SOC_ENUM("High Pass Filter Mode", filter_mode),
+       SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0),
+
+       SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+               WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0,
+               aux_tlv),
+
+       SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+               WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0,
+               bypass_tlv),
+
+       SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+       SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+       SOC_SINGLE_TLV("EQ1 Volume", WM8985_EQ1_LOW_SHELF,  0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ2 Bandwith", eq2_bw),
+       SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+       SOC_SINGLE_TLV("EQ2 Volume", WM8985_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ3 Bandwith", eq3_bw),
+       SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+       SOC_SINGLE_TLV("EQ3 Volume", WM8985_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ4 Bandwith", eq4_bw),
+       SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+       SOC_SINGLE_TLV("EQ4 Volume", WM8985_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+       SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+       SOC_ENUM("3D Depth", depth_3d),
+
+       SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+       SOC_DAPM_SINGLE("L2 Switch", WM8985_INPUT_CTRL, 2, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+       SOC_DAPM_SINGLE("R2 Switch", WM8985_INPUT_CTRL, 6, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+               4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+               0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+               4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+               0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3,
+               0, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3,
+               1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8985_POWER_MANAGEMENT_2,
+               0, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2,
+               1, 0),
+
+       SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+               2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+       SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+               3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2,
+               2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+       SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2,
+               3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+               4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+       SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+               5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+       SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               6, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL,
+               6, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Headphone Out", WM8985_POWER_MANAGEMENT_2,
+               7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Headphone Out", WM8985_POWER_MANAGEMENT_2,
+               8, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Speaker Out", WM8985_POWER_MANAGEMENT_3,
+               5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
+               6, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0),
+
+       SND_SOC_DAPM_INPUT("LIN"),
+       SND_SOC_DAPM_INPUT("LIP"),
+       SND_SOC_DAPM_INPUT("RIN"),
+       SND_SOC_DAPM_INPUT("RIP"),
+       SND_SOC_DAPM_INPUT("AUXL"),
+       SND_SOC_DAPM_INPUT("AUXR"),
+       SND_SOC_DAPM_INPUT("L2"),
+       SND_SOC_DAPM_INPUT("R2"),
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR")
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "Right Output Mixer", "PCM Switch", "Right DAC" },
+       { "Right Output Mixer", "Aux Switch", "AUXR" },
+       { "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+       { "Left Output Mixer", "PCM Switch", "Left DAC" },
+       { "Left Output Mixer", "Aux Switch", "AUXL" },
+       { "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+       { "Right Headphone Out", NULL, "Right Output Mixer" },
+       { "HPR", NULL, "Right Headphone Out" },
+
+       { "Left Headphone Out", NULL, "Left Output Mixer" },
+       { "HPL", NULL, "Left Headphone Out" },
+
+       { "Right Speaker Out", NULL, "Right Output Mixer" },
+       { "SPKR", NULL, "Right Speaker Out" },
+
+       { "Left Speaker Out", NULL, "Left Output Mixer" },
+       { "SPKL", NULL, "Left Speaker Out" },
+
+       { "Right ADC", NULL, "Right Boost Mixer" },
+
+       { "Right Boost Mixer", "AUXR Volume", "AUXR" },
+       { "Right Boost Mixer", NULL, "Right Capture PGA" },
+       { "Right Boost Mixer", "R2 Volume", "R2" },
+
+       { "Left ADC", NULL, "Left Boost Mixer" },
+
+       { "Left Boost Mixer", "AUXL Volume", "AUXL" },
+       { "Left Boost Mixer", NULL, "Left Capture PGA" },
+       { "Left Boost Mixer", "L2 Volume", "L2" },
+
+       { "Right Capture PGA", NULL, "Right Input Mixer" },
+       { "Left Capture PGA", NULL, "Left Input Mixer" },
+
+       { "Right Input Mixer", "R2 Switch", "R2" },
+       { "Right Input Mixer", "MicN Switch", "RIN" },
+       { "Right Input Mixer", "MicP Switch", "RIP" },
+
+       { "Left Input Mixer", "L2 Switch", "L2" },
+       { "Left Input Mixer", "MicN Switch", "LIN" },
+       { "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg;
+
+       reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+       if (reg & WM8985_EQ3DMODE)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int regpwr2, regpwr3;
+       unsigned int reg_eq;
+
+       if (ucontrol->value.integer.value[0] != 0
+                       && ucontrol->value.integer.value[0] != 1)
+               return -EINVAL;
+
+       reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+       switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
+       case 0:
+               if (!ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       case 1:
+               if (ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       }
+
+       regpwr2 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_2);
+       regpwr3 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_3);
+       /* disable the DACs and ADCs */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_2,
+                           WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_3,
+                           WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
+       snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+                           WM8985_M128ENB_MASK, WM8985_M128ENB);
+       /* set the desired eqmode */
+       snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
+                           WM8985_EQ3DMODE_MASK,
+                           ucontrol->value.integer.value[0]
+                           << WM8985_EQ3DMODE_SHIFT);
+       /* restore DAC/ADC configuration */
+       snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
+       snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, regpwr3);
+       return 0;
+}
+
+static int wm8985_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8985_dapm_widgets,
+                                 ARRAY_SIZE(wm8985_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map,
+                               ARRAY_SIZE(audio_map));
+       return 0;
+}
+
+static int wm8985_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
+}
+
+static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       return snd_soc_update_bits(codec, WM8985_DAC_CONTROL,
+                                  WM8985_SOFTMUTE_MASK,
+                                  !!mute << WM8985_SOFTMUTE_SHIFT);
+}
+
+static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       u16 format, master, bcp, lrp;
+
+       codec = dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = 0x0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               format = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_MS_MASK, master << WM8985_MS_SHIFT);
+
+       /* frame inversion is not valid for dsp modes */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_IB_IF:
+               case SND_SOC_DAIFMT_NB_IF:
+                       return -EINVAL;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       bcp = lrp = 0;
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bcp = lrp = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bcp = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrp = 1;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown polarity configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
+       return 0;
+}
+
+static int wm8985_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       int i;
+       struct snd_soc_codec *codec;
+       struct wm8985_priv *wm8985;
+       u16 blen, srate_idx;
+       unsigned int tmp;
+       int srate_best;
+
+       codec = dai->codec;
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       wm8985->bclk = snd_soc_params_to_bclk(params);
+       if ((int)wm8985->bclk < 0)
+               return wm8985->bclk;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               blen = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               blen = 0x1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               blen = 0x2;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               blen = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
+
+       /*
+        * match to the nearest possible sample rate and rely
+        * on the array index to configure the SR register
+        */
+       srate_idx = 0;
+       srate_best = abs(srates[0] - params_rate(params));
+       for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+               if (abs(srates[i] - params_rate(params)) >= srate_best)
+                       continue;
+               srate_idx = i;
+               srate_best = abs(srates[i] - params_rate(params));
+       }
+
+       dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+       snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+                           WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
+
+       dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
+       dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
+
+       for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+               if (wm8985->sysclk / params_rate(params)
+                               == fs_ratios[i].ratio)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(fs_ratios)) {
+               dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+                       wm8985->sysclk, params_rate(params));
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
+
+       /* select the appropriate bclk divider */
+       tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+               if (wm8985->bclk == tmp / bclk_divs[i])
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(bclk_divs)) {
+               dev_err(dai->dev, "No matching BCLK divider found\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "BCLK div = %d\n", i);
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
+       return 0;
+}
+
+struct pll_div {
+       u32 div2:1;
+       u32 n:4;
+       u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned long int K, Ndiv, Nmod;
+
+       pll_div->div2 = 0;
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div->div2 = 1;
+               Ndiv = target / source;
+       }
+
+       if (Ndiv < 6 || Ndiv > 12) {
+               printk(KERN_ERR "%s: WM8985 N value is not within"
+                      " the recommended range: %lu\n", __func__, Ndiv);
+               return -EINVAL;
+       }
+       pll_div->n = Ndiv;
+
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xffffffff;
+       if ((K % 10) >= 5)
+               K += 5;
+       K /= 10;
+       pll_div->k = K;
+
+       return 0;
+}
+
+static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
+                         int source, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       int ret;
+       struct snd_soc_codec *codec;
+       struct pll_div pll_div;
+
+       codec = dai->codec;
+       if (freq_in && freq_out) {
+               ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+               if (ret)
+                       return ret;
+       }
+
+       /* disable the PLL before reprogramming it */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                           WM8985_PLLEN_MASK, 0);
+       
+       if (!freq_in || !freq_out)
+               return 0;
+
+       /* set PLLN and PRESCALE */
+       snd_soc_write(codec, WM8985_PLL_N,
+                     (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+                     | pll_div.n);
+       /* set PLLK */
+       snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+       snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+       snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+       /* set the source of the clock to be the PLL */
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+       /* enable the PLL */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                           WM8985_PLLEN_MASK, WM8985_PLLEN);
+       return 0;
+}
+
+static int wm8985_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+       struct wm8985_priv *wm8985;
+
+       codec = dai->codec;
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case WM8985_CLKSRC_MCLK:
+               snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                                   WM8985_CLKSEL_MASK, 0);
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_PLLEN_MASK, 0);
+               break;
+       case WM8985_CLKSRC_PLL:
+               snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                                   WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       wm8985->sysclk = freq;
+       return 0;
+}
+
+static void wm8985_sync_cache(struct snd_soc_codec *codec)
+{
+       short i;
+       u16 *cache;
+
+       if (!codec->cache_sync)
+               return;
+       codec->cache_only = 0;
+       /* restore cache */
+       cache = codec->reg_cache;
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (i == WM8985_SOFTWARE_RESET
+                               || cache[i] == wm8985_reg_defs[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+       codec->cache_sync = 0;
+}
+
+static int wm8985_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct wm8985_priv *wm8985;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID at 75k */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK,
+                                   1 << WM8985_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+                                                   wm8985->supplies);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8985_sync_cache(codec);
+
+                       /* enable anti-pop features */
+                       snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+                                           WM8985_POBCTRL_MASK,
+                                           WM8985_POBCTRL);
+                       /* enable thermal shutdown */
+                       snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                           WM8985_TSDEN_MASK, WM8985_TSDEN);
+                       snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                           WM8985_TSOPCTRL_MASK,
+                                           WM8985_TSOPCTRL);
+                       /* enable BIASEN */
+                       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                           WM8985_BIASEN_MASK, WM8985_BIASEN);
+                       /* VMID at 75k */
+                       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                           WM8985_VMIDSEL_MASK,
+                                           1 << WM8985_VMIDSEL_SHIFT);
+                       msleep(500);
+                       /* disable anti-pop features */
+                       snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+                                           WM8985_POBCTRL_MASK, 0);
+               }
+               /* VMID at 300k */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK,
+                                   2 << WM8985_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* disable thermal shutdown */
+               snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                   WM8985_TSOPCTRL_MASK, 0);
+               snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                   WM8985_TSDEN_MASK, 0);
+               /* disable VMIDSEL and BIASEN */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
+                                   0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_1, 0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
+
+               codec->cache_sync = 1;
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
+                                      wm8985->supplies);
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8985_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8985_resume(struct snd_soc_codec *codec)
+{
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8985_suspend NULL
+#define wm8985_resume NULL
+#endif
+
+static int wm8985_remove(struct snd_soc_codec *codec)
+{
+       struct wm8985_priv *wm8985;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+       return 0;
+}
+
+static int wm8985_probe(struct snd_soc_codec *codec)
+{
+       size_t i;
+       struct wm8985_priv *wm8985;
+       int ret;
+       u16 *cache;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+               wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+                                wm8985->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+                                   wm8985->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_get;
+       }
+
+       ret = wm8985_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
+
+       cache = codec->reg_cache;
+       /* latch volume update bits */
+       for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
+               cache[volume_update_regs[i]] |= 0x100;
+       /* enable BIASCUT */
+       cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT;
+       codec->cache_sync = 1;
+
+       snd_soc_add_controls(codec, wm8985_snd_controls,
+                            ARRAY_SIZE(wm8985_snd_controls));
+       wm8985_add_widgets(codec);
+
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+err_reg_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+       return ret;
+}
+
+static struct snd_soc_dai_ops wm8985_dai_ops = {
+       .digital_mute = wm8985_dac_mute,
+       .hw_params = wm8985_hw_params,
+       .set_fmt = wm8985_set_fmt,
+       .set_sysclk = wm8985_set_sysclk,
+       .set_pll = wm8985_set_pll
+};
+
+#define WM8985_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8985_dai = {
+       .name = "wm8985-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8985_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8985_FORMATS,
+       },
+       .ops = &wm8985_dai_ops,
+       .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
+       .probe = wm8985_probe,
+       .remove = wm8985_remove,
+       .suspend = wm8985_suspend,
+       .resume = wm8985_resume,
+       .set_bias_level = wm8985_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8985_reg_defs),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8985_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8985_spi_probe(struct spi_device *spi)
+{
+       struct wm8985_priv *wm8985;
+       int ret;
+
+       wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+       if (!wm8985)
+               return -ENOMEM;
+
+       wm8985->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8985);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8985, &wm8985_dai, 1);
+       if (ret < 0)
+               kfree(wm8985);
+       return ret;
+}
+
+static int __devexit wm8985_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8985_spi_driver = {
+       .driver = {
+               .name = "wm8985",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8985_spi_probe,
+       .remove = __devexit_p(wm8985_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8985_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8985_priv *wm8985;
+       int ret;
+
+       wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+       if (!wm8985)
+               return -ENOMEM;
+
+       wm8985->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8985);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8985, &wm8985_dai, 1);
+       if (ret < 0)
+               kfree(wm8985);
+       return ret;
+}
+
+static __devexit int wm8985_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8985_i2c_id[] = {
+       { "wm8985", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
+
+static struct i2c_driver wm8985_i2c_driver = {
+       .driver = {
+               .name = "wm8985",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8985_i2c_probe,
+       .remove = __devexit_p(wm8985_i2c_remove),
+       .id_table = wm8985_i2c_id
+};
+#endif
+
+static int __init wm8985_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8985_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8985_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8985 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8985_modinit);
+
+static void __exit wm8985_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8985_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8985_spi_driver);
+#endif
+}
+module_exit(wm8985_exit);
+
+MODULE_DESCRIPTION("ASoC WM8985 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h
new file mode 100644 (file)
index 0000000..2e71ff5
--- /dev/null
@@ -0,0 +1,1045 @@
+/*
+ * wm8985.h  --  WM8985 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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 _WM8985_H
+#define _WM8985_H
+
+#define WM8985_SOFTWARE_RESET                   0x00
+#define WM8985_POWER_MANAGEMENT_1               0x01
+#define WM8985_POWER_MANAGEMENT_2               0x02
+#define WM8985_POWER_MANAGEMENT_3               0x03
+#define WM8985_AUDIO_INTERFACE                  0x04
+#define WM8985_COMPANDING_CONTROL               0x05
+#define WM8985_CLOCK_GEN_CONTROL                0x06
+#define WM8985_ADDITIONAL_CONTROL               0x07
+#define WM8985_GPIO_CONTROL                     0x08
+#define WM8985_JACK_DETECT_CONTROL_1            0x09
+#define WM8985_DAC_CONTROL                      0x0A
+#define WM8985_LEFT_DAC_DIGITAL_VOL             0x0B
+#define WM8985_RIGHT_DAC_DIGITAL_VOL            0x0C
+#define WM8985_JACK_DETECT_CONTROL_2            0x0D
+#define WM8985_ADC_CONTROL                      0x0E
+#define WM8985_LEFT_ADC_DIGITAL_VOL             0x0F
+#define WM8985_RIGHT_ADC_DIGITAL_VOL            0x10
+#define WM8985_EQ1_LOW_SHELF                    0x12
+#define WM8985_EQ2_PEAK_1                       0x13
+#define WM8985_EQ3_PEAK_2                       0x14
+#define WM8985_EQ4_PEAK_3                       0x15
+#define WM8985_EQ5_HIGH_SHELF                   0x16
+#define WM8985_DAC_LIMITER_1                    0x18
+#define WM8985_DAC_LIMITER_2                    0x19
+#define WM8985_NOTCH_FILTER_1                   0x1B
+#define WM8985_NOTCH_FILTER_2                   0x1C
+#define WM8985_NOTCH_FILTER_3                   0x1D
+#define WM8985_NOTCH_FILTER_4                   0x1E
+#define WM8985_ALC_CONTROL_1                    0x20
+#define WM8985_ALC_CONTROL_2                    0x21
+#define WM8985_ALC_CONTROL_3                    0x22
+#define WM8985_NOISE_GATE                       0x23
+#define WM8985_PLL_N                            0x24
+#define WM8985_PLL_K_1                          0x25
+#define WM8985_PLL_K_2                          0x26
+#define WM8985_PLL_K_3                          0x27
+#define WM8985_3D_CONTROL                       0x29
+#define WM8985_OUT4_TO_ADC                      0x2A
+#define WM8985_BEEP_CONTROL                     0x2B
+#define WM8985_INPUT_CTRL                       0x2C
+#define WM8985_LEFT_INP_PGA_GAIN_CTRL           0x2D
+#define WM8985_RIGHT_INP_PGA_GAIN_CTRL          0x2E
+#define WM8985_LEFT_ADC_BOOST_CTRL              0x2F
+#define WM8985_RIGHT_ADC_BOOST_CTRL             0x30
+#define WM8985_OUTPUT_CTRL0                     0x31
+#define WM8985_LEFT_MIXER_CTRL                  0x32
+#define WM8985_RIGHT_MIXER_CTRL                 0x33
+#define WM8985_LOUT1_HP_VOLUME_CTRL             0x34
+#define WM8985_ROUT1_HP_VOLUME_CTRL             0x35
+#define WM8985_LOUT2_SPK_VOLUME_CTRL            0x36
+#define WM8985_ROUT2_SPK_VOLUME_CTRL            0x37
+#define WM8985_OUT3_MIXER_CTRL                  0x38
+#define WM8985_OUT4_MONO_MIX_CTRL               0x39
+#define WM8985_OUTPUT_CTRL1                     0x3C
+#define WM8985_BIAS_CTRL                        0x3D
+
+#define WM8985_REGISTER_COUNT                   59
+#define WM8985_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8985_SOFTWARE_RESET_MASK              0x01FF  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_SHIFT                  0  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_WIDTH                  9  /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8985_OUT4MIXEN                        0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_MASK                   0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_SHIFT                       7  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_WIDTH                       1  /* OUT4MIXEN */
+#define WM8985_OUT3MIXEN                        0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_MASK                   0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_SHIFT                       6  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_WIDTH                       1  /* OUT3MIXEN */
+#define WM8985_PLLEN                            0x0020  /* PLLEN */
+#define WM8985_PLLEN_MASK                       0x0020  /* PLLEN */
+#define WM8985_PLLEN_SHIFT                           5  /* PLLEN */
+#define WM8985_PLLEN_WIDTH                           1  /* PLLEN */
+#define WM8985_MICBEN                           0x0010  /* MICBEN */
+#define WM8985_MICBEN_MASK                      0x0010  /* MICBEN */
+#define WM8985_MICBEN_SHIFT                          4  /* MICBEN */
+#define WM8985_MICBEN_WIDTH                          1  /* MICBEN */
+#define WM8985_BIASEN                           0x0008  /* BIASEN */
+#define WM8985_BIASEN_MASK                      0x0008  /* BIASEN */
+#define WM8985_BIASEN_SHIFT                          3  /* BIASEN */
+#define WM8985_BIASEN_WIDTH                          1  /* BIASEN */
+#define WM8985_BUFIOEN                          0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_MASK                     0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_SHIFT                         2  /* BUFIOEN */
+#define WM8985_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8985_VMIDSEL                          0x0003  /* VMIDSEL */
+#define WM8985_VMIDSEL_MASK                     0x0003  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_SHIFT                         0  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_WIDTH                         2  /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8985_ROUT1EN                          0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_MASK                     0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_SHIFT                         8  /* ROUT1EN */
+#define WM8985_ROUT1EN_WIDTH                         1  /* ROUT1EN */
+#define WM8985_LOUT1EN                          0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_MASK                     0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_SHIFT                         7  /* LOUT1EN */
+#define WM8985_LOUT1EN_WIDTH                         1  /* LOUT1EN */
+#define WM8985_SLEEP                            0x0040  /* SLEEP */
+#define WM8985_SLEEP_MASK                       0x0040  /* SLEEP */
+#define WM8985_SLEEP_SHIFT                           6  /* SLEEP */
+#define WM8985_SLEEP_WIDTH                           1  /* SLEEP */
+#define WM8985_BOOSTENR                         0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_MASK                    0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_SHIFT                        5  /* BOOSTENR */
+#define WM8985_BOOSTENR_WIDTH                        1  /* BOOSTENR */
+#define WM8985_BOOSTENL                         0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_MASK                    0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_SHIFT                        4  /* BOOSTENL */
+#define WM8985_BOOSTENL_WIDTH                        1  /* BOOSTENL */
+#define WM8985_INPGAENR                         0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_MASK                    0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_SHIFT                        3  /* INPGAENR */
+#define WM8985_INPGAENR_WIDTH                        1  /* INPGAENR */
+#define WM8985_INPPGAENL                        0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_MASK                   0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_SHIFT                       2  /* INPPGAENL */
+#define WM8985_INPPGAENL_WIDTH                       1  /* INPPGAENL */
+#define WM8985_ADCENR                           0x0002  /* ADCENR */
+#define WM8985_ADCENR_MASK                      0x0002  /* ADCENR */
+#define WM8985_ADCENR_SHIFT                          1  /* ADCENR */
+#define WM8985_ADCENR_WIDTH                          1  /* ADCENR */
+#define WM8985_ADCENL                           0x0001  /* ADCENL */
+#define WM8985_ADCENL_MASK                      0x0001  /* ADCENL */
+#define WM8985_ADCENL_SHIFT                          0  /* ADCENL */
+#define WM8985_ADCENL_WIDTH                          1  /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8985_OUT4EN                           0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_MASK                      0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_SHIFT                          8  /* OUT4EN */
+#define WM8985_OUT4EN_WIDTH                          1  /* OUT4EN */
+#define WM8985_OUT3EN                           0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_MASK                      0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_SHIFT                          7  /* OUT3EN */
+#define WM8985_OUT3EN_WIDTH                          1  /* OUT3EN */
+#define WM8985_ROUT2EN                          0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_MASK                     0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_SHIFT                         6  /* ROUT2EN */
+#define WM8985_ROUT2EN_WIDTH                         1  /* ROUT2EN */
+#define WM8985_LOUT2EN                          0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_MASK                     0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_SHIFT                         5  /* LOUT2EN */
+#define WM8985_LOUT2EN_WIDTH                         1  /* LOUT2EN */
+#define WM8985_RMIXEN                           0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_MASK                      0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_SHIFT                          3  /* RMIXEN */
+#define WM8985_RMIXEN_WIDTH                          1  /* RMIXEN */
+#define WM8985_LMIXEN                           0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_MASK                      0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_SHIFT                          2  /* LMIXEN */
+#define WM8985_LMIXEN_WIDTH                          1  /* LMIXEN */
+#define WM8985_DACENR                           0x0002  /* DACENR */
+#define WM8985_DACENR_MASK                      0x0002  /* DACENR */
+#define WM8985_DACENR_SHIFT                          1  /* DACENR */
+#define WM8985_DACENR_WIDTH                          1  /* DACENR */
+#define WM8985_DACENL                           0x0001  /* DACENL */
+#define WM8985_DACENL_MASK                      0x0001  /* DACENL */
+#define WM8985_DACENL_SHIFT                          0  /* DACENL */
+#define WM8985_DACENL_WIDTH                          1  /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8985_BCP                              0x0100  /* BCP */
+#define WM8985_BCP_MASK                         0x0100  /* BCP */
+#define WM8985_BCP_SHIFT                             8  /* BCP */
+#define WM8985_BCP_WIDTH                             1  /* BCP */
+#define WM8985_LRP                              0x0080  /* LRP */
+#define WM8985_LRP_MASK                         0x0080  /* LRP */
+#define WM8985_LRP_SHIFT                             7  /* LRP */
+#define WM8985_LRP_WIDTH                             1  /* LRP */
+#define WM8985_WL_MASK                          0x0060  /* WL - [6:5] */
+#define WM8985_WL_SHIFT                              5  /* WL - [6:5] */
+#define WM8985_WL_WIDTH                              2  /* WL - [6:5] */
+#define WM8985_FMT_MASK                         0x0018  /* FMT - [4:3] */
+#define WM8985_FMT_SHIFT                             3  /* FMT - [4:3] */
+#define WM8985_FMT_WIDTH                             2  /* FMT - [4:3] */
+#define WM8985_DLRSWAP                          0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_MASK                     0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_SHIFT                         2  /* DLRSWAP */
+#define WM8985_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8985_ALRSWAP                          0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_MASK                     0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_SHIFT                         1  /* ALRSWAP */
+#define WM8985_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8985_MONO                             0x0001  /* MONO */
+#define WM8985_MONO_MASK                        0x0001  /* MONO */
+#define WM8985_MONO_SHIFT                            0  /* MONO */
+#define WM8985_MONO_WIDTH                            1  /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8985_WL8                              0x0020  /* WL8 */
+#define WM8985_WL8_MASK                         0x0020  /* WL8 */
+#define WM8985_WL8_SHIFT                             5  /* WL8 */
+#define WM8985_WL8_WIDTH                             1  /* WL8 */
+#define WM8985_DAC_COMP_MASK                    0x0018  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_SHIFT                        3  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_WIDTH                        2  /* DAC_COMP - [4:3] */
+#define WM8985_ADC_COMP_MASK                    0x0006  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_SHIFT                        1  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_WIDTH                        2  /* ADC_COMP - [2:1] */
+#define WM8985_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8985_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8985_CLKSEL                           0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_MASK                      0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_SHIFT                          8  /* CLKSEL */
+#define WM8985_CLKSEL_WIDTH                          1  /* CLKSEL */
+#define WM8985_MCLKDIV_MASK                     0x00E0  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_SHIFT                         5  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_WIDTH                         3  /* MCLKDIV - [7:5] */
+#define WM8985_BCLKDIV_MASK                     0x001C  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_SHIFT                         2  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_WIDTH                         3  /* BCLKDIV - [4:2] */
+#define WM8985_MS                               0x0001  /* MS */
+#define WM8985_MS_MASK                          0x0001  /* MS */
+#define WM8985_MS_SHIFT                              0  /* MS */
+#define WM8985_MS_WIDTH                              1  /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8985_M128ENB                          0x0100  /* M128ENB */
+#define WM8985_M128ENB_MASK                     0x0100  /* M128ENB */
+#define WM8985_M128ENB_SHIFT                         8  /* M128ENB */
+#define WM8985_M128ENB_WIDTH                         1  /* M128ENB */
+#define WM8985_DCLKDIV_MASK                     0x00F0  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_SHIFT                         4  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_WIDTH                         4  /* DCLKDIV - [7:4] */
+#define WM8985_SR_MASK                          0x000E  /* SR - [3:1] */
+#define WM8985_SR_SHIFT                              1  /* SR - [3:1] */
+#define WM8985_SR_WIDTH                              3  /* SR - [3:1] */
+#define WM8985_SLOWCLKEN                        0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_MASK                   0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_SHIFT                       0  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_WIDTH                       1  /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8985_GPIO1GP                          0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_MASK                     0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_SHIFT                         8  /* GPIO1GP */
+#define WM8985_GPIO1GP_WIDTH                         1  /* GPIO1GP */
+#define WM8985_GPIO1GPU                         0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_MASK                    0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_SHIFT                        7  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_WIDTH                        1  /* GPIO1GPU */
+#define WM8985_GPIO1GPD                         0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_MASK                    0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_SHIFT                        6  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_WIDTH                        1  /* GPIO1GPD */
+#define WM8985_GPIO1POL                         0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_MASK                    0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_SHIFT                        3  /* GPIO1POL */
+#define WM8985_GPIO1POL_WIDTH                        1  /* GPIO1POL */
+#define WM8985_GPIO1SEL_MASK                    0x0007  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_SHIFT                        0  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_WIDTH                        3  /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8985_JD_EN                            0x0040  /* JD_EN */
+#define WM8985_JD_EN_MASK                       0x0040  /* JD_EN */
+#define WM8985_JD_EN_SHIFT                           6  /* JD_EN */
+#define WM8985_JD_EN_WIDTH                           1  /* JD_EN */
+#define WM8985_JD_SEL_MASK                      0x0030  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_SHIFT                          4  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_WIDTH                          2  /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8985_SOFTMUTE                         0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_MASK                    0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_SHIFT                        6  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_WIDTH                        1  /* SOFTMUTE */
+#define WM8985_DACOSR128                        0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_MASK                   0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_SHIFT                       3  /* DACOSR128 */
+#define WM8985_DACOSR128_WIDTH                       1  /* DACOSR128 */
+#define WM8985_AMUTE                            0x0004  /* AMUTE */
+#define WM8985_AMUTE_MASK                       0x0004  /* AMUTE */
+#define WM8985_AMUTE_SHIFT                           2  /* AMUTE */
+#define WM8985_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8985_DACPOLR                          0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_MASK                     0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_SHIFT                         1  /* DACPOLR */
+#define WM8985_DACPOLR_WIDTH                         1  /* DACPOLR */
+#define WM8985_DACPOLL                          0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_MASK                     0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_SHIFT                         0  /* DACPOLL */
+#define WM8985_DACPOLL_WIDTH                         1  /* DACPOLL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLL_MASK                     0x00FF  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_SHIFT                         0  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_WIDTH                         8  /* DACVOLL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLR_MASK                     0x00FF  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_SHIFT                         0  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_WIDTH                         8  /* DACVOLR - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8985_JD_EN1_MASK                      0x00F0  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_SHIFT                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_WIDTH                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN0_MASK                      0x000F  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_SHIFT                          0  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_WIDTH                          4  /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8985_HPFEN                            0x0100  /* HPFEN */
+#define WM8985_HPFEN_MASK                       0x0100  /* HPFEN */
+#define WM8985_HPFEN_SHIFT                           8  /* HPFEN */
+#define WM8985_HPFEN_WIDTH                           1  /* HPFEN */
+#define WM8985_HPFAPP                           0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_MASK                      0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_SHIFT                          7  /* HPFAPP */
+#define WM8985_HPFAPP_WIDTH                          1  /* HPFAPP */
+#define WM8985_HPFCUT_MASK                      0x0070  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_SHIFT                          4  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_WIDTH                          3  /* HPFCUT - [6:4] */
+#define WM8985_ADCOSR128                        0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_MASK                   0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_SHIFT                       3  /* ADCOSR128 */
+#define WM8985_ADCOSR128_WIDTH                       1  /* ADCOSR128 */
+#define WM8985_ADCRPOL                          0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_MASK                     0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_SHIFT                         1  /* ADCRPOL */
+#define WM8985_ADCRPOL_WIDTH                         1  /* ADCRPOL */
+#define WM8985_ADCLPOL                          0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_MASK                     0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_SHIFT                         0  /* ADCLPOL */
+#define WM8985_ADCLPOL_WIDTH                         1  /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLL_MASK                     0x00FF  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_SHIFT                         0  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_WIDTH                         8  /* ADCVOLL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLR_MASK                     0x00FF  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_SHIFT                         0  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_WIDTH                         8  /* ADCVOLR - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8985_EQ3DMODE                         0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_MASK                    0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_SHIFT                        8  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_WIDTH                        1  /* EQ3DMODE */
+#define WM8985_EQ1C_MASK                        0x0060  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_SHIFT                            5  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_WIDTH                            2  /* EQ1C - [6:5] */
+#define WM8985_EQ1G_MASK                        0x001F  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_SHIFT                            0  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_WIDTH                            5  /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8985_EQ2BW                            0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_MASK                       0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_SHIFT                           8  /* EQ2BW */
+#define WM8985_EQ2BW_WIDTH                           1  /* EQ2BW */
+#define WM8985_EQ2C_MASK                        0x0060  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_SHIFT                            5  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_WIDTH                            2  /* EQ2C - [6:5] */
+#define WM8985_EQ2G_MASK                        0x001F  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_SHIFT                            0  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_WIDTH                            5  /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8985_EQ3BW                            0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_MASK                       0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_SHIFT                           8  /* EQ3BW */
+#define WM8985_EQ3BW_WIDTH                           1  /* EQ3BW */
+#define WM8985_EQ3C_MASK                        0x0060  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_SHIFT                            5  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_WIDTH                            2  /* EQ3C - [6:5] */
+#define WM8985_EQ3G_MASK                        0x001F  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_SHIFT                            0  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_WIDTH                            5  /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8985_EQ4BW                            0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_MASK                       0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_SHIFT                           8  /* EQ4BW */
+#define WM8985_EQ4BW_WIDTH                           1  /* EQ4BW */
+#define WM8985_EQ4C_MASK                        0x0060  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_SHIFT                            5  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_WIDTH                            2  /* EQ4C - [6:5] */
+#define WM8985_EQ4G_MASK                        0x001F  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_SHIFT                            0  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_WIDTH                            5  /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8985_EQ5C_MASK                        0x0060  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_SHIFT                            5  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_WIDTH                            2  /* EQ5C - [6:5] */
+#define WM8985_EQ5G_MASK                        0x001F  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_SHIFT                            0  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_WIDTH                            5  /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8985_LIMEN                            0x0100  /* LIMEN */
+#define WM8985_LIMEN_MASK                       0x0100  /* LIMEN */
+#define WM8985_LIMEN_SHIFT                           8  /* LIMEN */
+#define WM8985_LIMEN_WIDTH                           1  /* LIMEN */
+#define WM8985_LIMDCY_MASK                      0x00F0  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_SHIFT                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_WIDTH                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMATK_MASK                      0x000F  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_SHIFT                          0  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_WIDTH                          4  /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8985_LIMLVL_MASK                      0x0070  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_SHIFT                          4  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_WIDTH                          3  /* LIMLVL - [6:4] */
+#define WM8985_LIMBOOST_MASK                    0x000F  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_SHIFT                        0  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_WIDTH                        4  /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFEN                             0x0080  /* NFEN */
+#define WM8985_NFEN_MASK                        0x0080  /* NFEN */
+#define WM8985_NFEN_SHIFT                            7  /* NFEN */
+#define WM8985_NFEN_WIDTH                            1  /* NFEN */
+#define WM8985_NFA0_13_7_MASK                   0x007F  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_SHIFT                       0  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_WIDTH                       7  /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA0_6_0_MASK                    0x007F  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_SHIFT                        0  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_WIDTH                        7  /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_13_7_MASK                   0x007F  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_SHIFT                       0  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_WIDTH                       7  /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_6_0_MASK                    0x007F  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_SHIFT                        0  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_WIDTH                        7  /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8985_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8985_ALCMAX_MASK                      0x0038  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_SHIFT                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_WIDTH                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMIN_MASK                      0x0007  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_SHIFT                          0  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_WIDTH                          3  /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8985_ALCHLD_MASK                      0x00F0  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_SHIFT                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_WIDTH                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCLVL_MASK                      0x000F  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_SHIFT                          0  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_WIDTH                          4  /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8985_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8985_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8985_ALCDCY_MASK                      0x00F0  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_SHIFT                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_WIDTH                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCATK_MASK                      0x000F  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_SHIFT                          0  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_WIDTH                          4  /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8985_NGEN                             0x0008  /* NGEN */
+#define WM8985_NGEN_MASK                        0x0008  /* NGEN */
+#define WM8985_NGEN_SHIFT                            3  /* NGEN */
+#define WM8985_NGEN_WIDTH                            1  /* NGEN */
+#define WM8985_NGTH_MASK                        0x0007  /* NGTH - [2:0] */
+#define WM8985_NGTH_SHIFT                            0  /* NGTH - [2:0] */
+#define WM8985_NGTH_WIDTH                            3  /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8985_PLL_PRESCALE                     0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_MASK                0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_SHIFT                    4  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_WIDTH                    1  /* PLL_PRESCALE */
+#define WM8985_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+#define WM8985_PLLN_SHIFT                            0  /* PLLN - [3:0] */
+#define WM8985_PLLN_WIDTH                            4  /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8985_PLLK_23_18_MASK                  0x003F  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_SHIFT                      0  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_WIDTH                      6  /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8985_PLLK_17_9_MASK                   0x01FF  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_SHIFT                       0  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_WIDTH                       9  /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8985_PLLK_8_0_MASK                    0x01FF  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_SHIFT                        0  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_WIDTH                        9  /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8985_DEPTH3D_MASK                     0x000F  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_SHIFT                         0  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_WIDTH                         4  /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8985_OUT4_2ADCVOL_MASK                0x01C0  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_SHIFT                    6  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_WIDTH                    3  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2LNR                        0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_MASK                   0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_SHIFT                       5  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_WIDTH                       1  /* OUT4_2LNR */
+#define WM8985_POBCTRL                          0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_MASK                     0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_SHIFT                         2  /* POBCTRL */
+#define WM8985_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8985_DELEN                            0x0002  /* DELEN */
+#define WM8985_DELEN_MASK                       0x0002  /* DELEN */
+#define WM8985_DELEN_SHIFT                           1  /* DELEN */
+#define WM8985_DELEN_WIDTH                           1  /* DELEN */
+#define WM8985_OUT1DEL                          0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_MASK                     0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_SHIFT                         0  /* OUT1DEL */
+#define WM8985_OUT1DEL_WIDTH                         1  /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8985_BYPL2RMIX                        0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_MASK                   0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_SHIFT                       8  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_WIDTH                       1  /* BYPL2RMIX */
+#define WM8985_BYPR2LMIX                        0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_MASK                   0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_SHIFT                       7  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_WIDTH                       1  /* BYPR2LMIX */
+#define WM8985_MUTERPGA2INV                     0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_MASK                0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_SHIFT                    5  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_WIDTH                    1  /* MUTERPGA2INV */
+#define WM8985_INVROUT2                         0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_MASK                    0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_SHIFT                        4  /* INVROUT2 */
+#define WM8985_INVROUT2_WIDTH                        1  /* INVROUT2 */
+#define WM8985_BEEPVOL_MASK                     0x000E  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_SHIFT                         1  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_WIDTH                         3  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPEN                           0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_MASK                      0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_SHIFT                          0  /* BEEPEN */
+#define WM8985_BEEPEN_WIDTH                          1  /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8985_MBVSEL                           0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_MASK                      0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_SHIFT                          8  /* MBVSEL */
+#define WM8985_MBVSEL_WIDTH                          1  /* MBVSEL */
+#define WM8985_R2_2INPPGA                       0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_MASK                  0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_SHIFT                      6  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_WIDTH                      1  /* R2_2INPPGA */
+#define WM8985_RIN2INPPGA                       0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_MASK                  0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_SHIFT                      5  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_WIDTH                      1  /* RIN2INPPGA */
+#define WM8985_RIP2INPPGA                       0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_MASK                  0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_SHIFT                      4  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_WIDTH                      1  /* RIP2INPPGA */
+#define WM8985_L2_2INPPGA                       0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_MASK                  0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_SHIFT                      2  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_WIDTH                      1  /* L2_2INPPGA */
+#define WM8985_LIN2INPPGA                       0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_MASK                  0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_SHIFT                      1  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_WIDTH                      1  /* LIN2INPPGA */
+#define WM8985_LIP2INPPGA                       0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_MASK                  0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_SHIFT                      0  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_WIDTH                      1  /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCL                        0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_MASK                   0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_SHIFT                       7  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_WIDTH                       1  /* INPPGAZCL */
+#define WM8985_INPPGAMUTEL                      0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_MASK                 0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_SHIFT                     6  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_WIDTH                     1  /* INPPGAMUTEL */
+#define WM8985_INPPGAVOLL_MASK                  0x003F  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_SHIFT                      0  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_WIDTH                      6  /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCR                        0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_MASK                   0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_SHIFT                       7  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_WIDTH                       1  /* INPPGAZCR */
+#define WM8985_INPPGAMUTER                      0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_MASK                 0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_SHIFT                     6  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_WIDTH                     1  /* INPPGAMUTER */
+#define WM8985_INPPGAVOLR_MASK                  0x003F  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_SHIFT                      0  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_WIDTH                      6  /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTL                        0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_MASK                   0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_SHIFT                       8  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_WIDTH                       1  /* PGABOOSTL */
+#define WM8985_L2_2BOOSTVOL_MASK                0x0070  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_SHIFT                    4  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_WIDTH                    3  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXL2BOOSTVOL_MASK               0x0007  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_SHIFT                   0  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_WIDTH                   3  /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTR                        0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_MASK                   0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_SHIFT                       8  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_WIDTH                       1  /* PGABOOSTR */
+#define WM8985_R2_2BOOSTVOL_MASK                0x0070  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_SHIFT                    4  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_WIDTH                    3  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXR2BOOSTVOL_MASK               0x0007  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_SHIFT                   0  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_WIDTH                   3  /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8985_DACL2RMIX                        0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_MASK                   0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_SHIFT                       6  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_WIDTH                       1  /* DACL2RMIX */
+#define WM8985_DACR2LMIX                        0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_MASK                   0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_SHIFT                       5  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_WIDTH                       1  /* DACR2LMIX */
+#define WM8985_OUT4BOOST                        0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_MASK                   0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_SHIFT                       4  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_WIDTH                       1  /* OUT4BOOST */
+#define WM8985_OUT3BOOST                        0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_MASK                   0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_SHIFT                       3  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_WIDTH                       1  /* OUT3BOOST */
+#define WM8985_TSOPCTRL                         0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_MASK                    0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_SHIFT                        2  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_WIDTH                        1  /* TSOPCTRL */
+#define WM8985_TSDEN                            0x0002  /* TSDEN */
+#define WM8985_TSDEN_MASK                       0x0002  /* TSDEN */
+#define WM8985_TSDEN_SHIFT                           1  /* TSDEN */
+#define WM8985_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8985_VROI                             0x0001  /* VROI */
+#define WM8985_VROI_MASK                        0x0001  /* VROI */
+#define WM8985_VROI_SHIFT                            0  /* VROI */
+#define WM8985_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8985_AUXLMIXVOL_MASK                  0x01C0  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_SHIFT                      6  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_WIDTH                      3  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXL2LMIX                        0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_MASK                   0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_SHIFT                       5  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_WIDTH                       1  /* AUXL2LMIX */
+#define WM8985_BYPLMIXVOL_MASK                  0x001C  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_SHIFT                      2  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_WIDTH                      3  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPL2LMIX                        0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_MASK                   0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_SHIFT                       1  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_WIDTH                       1  /* BYPL2LMIX */
+#define WM8985_DACL2LMIX                        0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_MASK                   0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_SHIFT                       0  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_WIDTH                       1  /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8985_AUXRMIXVOL_MASK                  0x01C0  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_SHIFT                      6  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_WIDTH                      3  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXR2RMIX                        0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_MASK                   0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_SHIFT                       5  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_WIDTH                       1  /* AUXR2RMIX */
+#define WM8985_BYPRMIXVOL_MASK                  0x001C  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_SHIFT                      2  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_WIDTH                      3  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPR2RMIX                        0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_MASK                   0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_SHIFT                       1  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_WIDTH                       1  /* BYPR2RMIX */
+#define WM8985_DACR2RMIX                        0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_MASK                   0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_SHIFT                       0  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_WIDTH                       1  /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_LOUT1ZC                          0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_MASK                     0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_SHIFT                         7  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_WIDTH                         1  /* LOUT1ZC */
+#define WM8985_LOUT1MUTE                        0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_MASK                   0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_SHIFT                       6  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_WIDTH                       1  /* LOUT1MUTE */
+#define WM8985_LOUT1VOL_MASK                    0x003F  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_WIDTH                        6  /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_ROUT1ZC                          0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_MASK                     0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_SHIFT                         7  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_WIDTH                         1  /* ROUT1ZC */
+#define WM8985_ROUT1MUTE                        0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_MASK                   0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_SHIFT                       6  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_WIDTH                       1  /* ROUT1MUTE */
+#define WM8985_ROUT1VOL_MASK                    0x003F  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_WIDTH                        6  /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_LOUT2ZC                          0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_MASK                     0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_SHIFT                         7  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_WIDTH                         1  /* LOUT2ZC */
+#define WM8985_LOUT2MUTE                        0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_MASK                   0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_SHIFT                       6  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_WIDTH                       1  /* LOUT2MUTE */
+#define WM8985_LOUT2VOL_MASK                    0x003F  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_WIDTH                        6  /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_ROUT2ZC                          0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_MASK                     0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_SHIFT                         7  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_WIDTH                         1  /* ROUT2ZC */
+#define WM8985_ROUT2MUTE                        0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_MASK                   0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_SHIFT                       6  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_WIDTH                       1  /* ROUT2MUTE */
+#define WM8985_ROUT2VOL_MASK                    0x003F  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_WIDTH                        6  /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8985_OUT3MUTE                         0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_MASK                    0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_SHIFT                        6  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8985_OUT4_2OUT3                       0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_MASK                  0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_SHIFT                      3  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_WIDTH                      1  /* OUT4_2OUT3 */
+#define WM8985_BYPL2OUT3                        0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_MASK                   0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_SHIFT                       2  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_WIDTH                       1  /* BYPL2OUT3 */
+#define WM8985_LMIX2OUT3                        0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_MASK                   0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_SHIFT                       1  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_WIDTH                       1  /* LMIX2OUT3 */
+#define WM8985_LDAC2OUT3                        0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_MASK                   0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_SHIFT                       0  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_WIDTH                       1  /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8985_OUT3_2OUT4                       0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_MASK                  0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_SHIFT                      7  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_WIDTH                      1  /* OUT3_2OUT4 */
+#define WM8985_OUT4MUTE                         0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_MASK                    0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_SHIFT                        6  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8985_OUT4ATTN                         0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_MASK                    0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_SHIFT                        5  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+#define WM8985_LMIX2OUT4                        0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_MASK                   0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_SHIFT                       4  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_WIDTH                       1  /* LMIX2OUT4 */
+#define WM8985_LDAC2OUT4                        0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_MASK                   0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_SHIFT                       3  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_WIDTH                       1  /* LDAC2OUT4 */
+#define WM8985_BYPR2OUT4                        0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_MASK                   0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_SHIFT                       2  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_WIDTH                       1  /* BYPR2OUT4 */
+#define WM8985_RMIX2OUT4                        0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_MASK                   0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_SHIFT                       1  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_WIDTH                       1  /* RMIX2OUT4 */
+#define WM8985_RDAC2OUT4                        0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_MASK                   0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_SHIFT                       0  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_WIDTH                       1  /* RDAC2OUT4 */
+
+/*
+ * R60 (0x3C) - OUTPUT ctrl
+ */
+#define WM8985_VIDBUFFTST_MASK                  0x01E0  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_SHIFT                      5  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_WIDTH                      4  /* VIDBUFFTST - [8:5] */
+#define WM8985_HPTOG                            0x0008  /* HPTOG */
+#define WM8985_HPTOG_MASK                       0x0008  /* HPTOG */
+#define WM8985_HPTOG_SHIFT                           3  /* HPTOG */
+#define WM8985_HPTOG_WIDTH                           1  /* HPTOG */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8985_BIASCUT                          0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_MASK                     0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_SHIFT                         8  /* BIASCUT */
+#define WM8985_BIASCUT_WIDTH                         1  /* BIASCUT */
+#define WM8985_HALFIPBIAS                       0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_MASK                  0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_SHIFT                      7  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_WIDTH                      1  /* HALFIPBIAS */
+#define WM8985_VBBIASTST_MASK                   0x0060  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_SHIFT                       5  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_WIDTH                       2  /* VBBIASTST - [6:5] */
+#define WM8985_BUFBIAS_MASK                     0x0018  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_SHIFT                         3  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_WIDTH                         2  /* BUFBIAS - [4:3] */
+#define WM8985_ADCBIAS_MASK                     0x0006  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_SHIFT                         1  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_WIDTH                         2  /* ADCBIAS - [2:1] */
+#define WM8985_HALFOPBIAS                       0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_MASK                  0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_SHIFT                      0  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_WIDTH                      1  /* HALFOPBIAS */
+
+enum clk_src {
+       WM8985_CLKSRC_MCLK,
+       WM8985_CLKSRC_PLL
+};
+
+#define WM8985_PLL 0
+
+#endif
index 19ad590ca0b390065850ce4ab8b0e4e2fd5d841a..d7f2597119703e983cccbaf4485109dd2f439130 100644 (file)
@@ -52,7 +52,7 @@ static const u16 wm8988_reg[] = {
 /* codec private data */
 struct wm8988_priv {
        unsigned int sysclk;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
        u16 reg_cache[WM8988_NUM_REG];
 };
@@ -608,8 +608,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
@@ -711,8 +710,8 @@ static struct snd_soc_dai_ops wm8988_ops = {
        .digital_mute = wm8988_mute,
 };
 
-struct snd_soc_dai wm8988_dai = {
-       .name = "WM8988",
+static struct snd_soc_dai_driver wm8988_dai = {
+       .name = "wm8988-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -730,21 +729,15 @@ struct snd_soc_dai wm8988_dai = {
        .ops = &wm8988_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8988_dai);
 
-static int wm8988_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8988_resume(struct platform_device *pdev)
+static int wm8988_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -763,99 +756,22 @@ static int wm8988_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8988_codec;
-
-static int wm8988_probe(struct platform_device *pdev)
+static int wm8988_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
-
-       if (wm8988_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8988_codec;
-       codec = wm8988_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8988_snd_controls,
-                               ARRAY_SIZE(wm8988_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
-                                 ARRAY_SIZE(wm8988_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8988_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8988 = {
-       .probe =        wm8988_probe,
-       .remove =       wm8988_remove,
-       .suspend =      wm8988_suspend,
-       .resume =       wm8988_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
-
-static int wm8988_register(struct wm8988_priv *wm8988,
-                          enum snd_soc_control_type control)
-{
-       struct snd_soc_codec *codec = &wm8988->codec;
-       int ret;
        u16 reg;
 
-       if (wm8988_codec) {
-               dev_err(codec->dev, "Another WM8988 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8988);
-       codec->name = "WM8988";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8988_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
-       codec->reg_cache = &wm8988->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8988_set_bias_level;
-
-       memcpy(codec->reg_cache, wm8988_reg,
-              sizeof(wm8988_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8988_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
        /* set the update bits (we always update left then right) */
@@ -870,139 +786,132 @@ static int wm8988_register(struct wm8988_priv *wm8988,
        reg = snd_soc_read(codec, WM8988_RINVOL);
        snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
 
-       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
-
-       wm8988_dai.dev = codec->dev;
-
-       wm8988_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       ret = snd_soc_register_dai(&wm8988_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8988_snd_controls,
+                               ARRAY_SIZE(wm8988_snd_controls));
+       snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+                                 ARRAY_SIZE(wm8988_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8988);
-       return ret;
 }
 
-static void wm8988_unregister(struct wm8988_priv *wm8988)
+static int wm8988_remove(struct snd_soc_codec *codec)
 {
-       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8988_dai);
-       snd_soc_unregister_codec(&wm8988->codec);
-       kfree(wm8988);
-       wm8988_codec = NULL;
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int wm8988_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+       .probe =        wm8988_probe,
+       .remove =       wm8988_remove,
+       .suspend =      wm8988_suspend,
+       .resume =       wm8988_resume,
+       .set_bias_level = wm8988_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8988_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8988_reg,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
 {
        struct wm8988_priv *wm8988;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
        if (wm8988 == NULL)
                return -ENOMEM;
 
-       codec = &wm8988->codec;
-
-       i2c_set_clientdata(i2c, wm8988);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8988->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8988);
 
-       return wm8988_register(wm8988, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8988, &wm8988_dai, 1);
+       if (ret < 0)
+               kfree(wm8988);
+       return ret;
 }
 
-static int wm8988_i2c_remove(struct i2c_client *client)
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
 {
-       struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
-       wm8988_unregister(wm8988);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8988_i2c_id[] = {
-       { "wm8988", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
-
-static struct i2c_driver wm8988_i2c_driver = {
+static struct spi_driver wm8988_spi_driver = {
        .driver = {
-               .name = "WM8988",
-               .owner = THIS_MODULE,
+               .name   = "wm8988-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe = wm8988_i2c_probe,
-       .remove = wm8988_i2c_remove,
-       .id_table = wm8988_i2c_id,
+       .probe          = wm8988_spi_probe,
+       .remove         = __devexit_p(wm8988_spi_remove),
 };
-#endif
+#endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8988_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8988_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8988_priv *wm8988;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
        if (wm8988 == NULL)
                return -ENOMEM;
 
-       codec = &wm8988->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8988);
+       i2c_set_clientdata(i2c, wm8988);
+       wm8988->control_type = SND_SOC_I2C;
 
-       return wm8988_register(wm8988, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8988, &wm8988_dai, 1);
+       if (ret < 0)
+               kfree(wm8988);
+       return ret;
 }
 
-static int __devexit wm8988_spi_remove(struct spi_device *spi)
+static __devexit int wm8988_i2c_remove(struct i2c_client *client)
 {
-       struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
-
-       wm8988_unregister(wm8988);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8988_spi_driver = {
+static const struct i2c_device_id wm8988_i2c_id[] = {
+       { "wm8988", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
        .driver = {
-               .name   = "wm8988",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8988-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8988_spi_probe,
-       .remove         = __devexit_p(wm8988_spi_remove),
+       .probe =    wm8988_i2c_probe,
+       .remove =   __devexit_p(wm8988_i2c_remove),
+       .id_table = wm8988_i2c_id,
 };
 #endif
 
 static int __init wm8988_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8988_i2c_driver);
-       if (ret != 0)
-               pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8988_spi_driver);
-       if (ret != 0)
-               pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",
+                      ret);
+       }
 #endif
        return ret;
 }
index 4552d37fdd415a3a68a91143f24d97f3bda929e8..5c04024e5f9f8c22b28bd09752237562c6092fba 100644 (file)
@@ -54,7 +54,4 @@
 
 #define WM8988_SYSCLK  0
 
-extern struct snd_soc_dai wm8988_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8988;
-
 #endif
index dd8d909788c1fe2b305d5b6af4f5eb4f58062cbd..264828e4e67c8be0d7e43a8ffd6d2f4d96498d74 100644 (file)
@@ -32,6 +32,7 @@
 
 /* codec private data */
 struct wm8990_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
        unsigned int pcmclk;
 };
@@ -1114,8 +1115,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1293,10 +1293,9 @@ static struct snd_soc_dai_ops wm8990_dai_ops = {
        .set_sysclk     = wm8990_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8990_dai = {
+static struct snd_soc_dai_driver wm8990_dai = {
 /* ADC/DAC on primary */
-       .name = "WM8990 ADC/DAC Primary",
-       .id = 1,
+       .name = "wm8990-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1311,21 +1310,15 @@ struct snd_soc_dai wm8990_dai = {
                .formats = WM8990_FORMATS,},
        .ops = &wm8990_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8990_dai);
 
-static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8990_resume(struct platform_device *pdev)
+static int wm8990_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1347,40 +1340,20 @@ static int wm8990_resume(struct platform_device *pdev)
  * initialise the WM8990 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8990_init(struct snd_soc_device *socdev)
+static int wm8990_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
+       int ret;
        u16 reg;
-       int ret = 0;
-
-       codec->name = "WM8990";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8990_set_bias_level;
-       codec->dai = &wm8990_dai;
-       codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
-       codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret < 0) {
                printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
-               goto pcm_err;
+               return ret;
        }
 
        wm8990_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8990: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* charge output caps */
-       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
@@ -1400,47 +1373,51 @@ static int wm8990_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(wm8990_snd_controls));
        wm8990_add_widgets(codec);
 
-       return ret;
+       return 0;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+/* power down chip */
+static int wm8990_remove(struct snd_soc_codec *codec)
+{
+       wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8990_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
+       .probe =        wm8990_probe,
+       .remove =       wm8990_remove,
+       .suspend =      wm8990_suspend,
+       .resume =       wm8990_resume,
+       .set_bias_level = wm8990_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8990_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8990_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM891 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x34
- *    high = 0x36
- */
-
-static int wm8990_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8990_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8990_priv *wm8990;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+       if (wm8990 == NULL)
+               return -ENOMEM;
 
-       ret = wm8990_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise WM8990\n");
+       i2c_set_clientdata(i2c, wm8990);
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8990, &wm8990_dai, 1);
+       if (ret < 0)
+               kfree(wm8990);
        return ret;
 }
 
-static int wm8990_i2c_remove(struct i2c_client *client)
+static __devexit int wm8990_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1452,134 +1429,34 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
        .driver = {
-               .name = "WM8990 I2C Codec",
+               .name = "wm8990-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8990_i2c_probe,
-       .remove =   wm8990_i2c_remove,
+       .remove =   __devexit_p(wm8990_i2c_remove),
        .id_table = wm8990_i2c_id,
 };
-
-static int wm8990_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8990_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&wm8990_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8990_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int wm8990_probe(struct platform_device *pdev)
+static int __init wm8990_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8990_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct wm8990_priv *wm8990;
-       int ret;
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
-       if (wm8990 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, wm8990);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8990_socdev = socdev;
-
-       ret = -ENODEV;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = wm8990_add_i2c_device(pdev, setup);
-       }
-#endif
-
+       ret = i2c_add_driver(&wm8990_i2c_driver);
        if (ret != 0) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
+                      ret);
        }
+#endif
        return ret;
 }
+module_init(wm8990_modinit);
 
-/* power down chip */
-static int wm8990_remove(struct platform_device *pdev)
+static void __exit wm8990_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8990_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8990 = {
-       .probe =        wm8990_probe,
-       .remove =       wm8990_remove,
-       .suspend =      wm8990_suspend,
-       .resume =       wm8990_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
-
-static int __init wm8990_modinit(void)
-{
-       return snd_soc_register_dai(&wm8990_dai);
-}
-module_init(wm8990_modinit);
-
-static void __exit wm8990_exit(void)
-{
-       snd_soc_unregister_dai(&wm8990_dai);
 }
 module_exit(wm8990_exit);
 
index 7114ddc88b4ba5fb6c2dff17712b7b05c36ac39c..77c98a4bfe9cdf34876e30866e73046d50748c85 100644 (file)
 #define WM8990_INMIXR_PWR_BIT                  2
 #define WM8990_AINRMUX_PWR_BIT                 3
 
-struct wm8990_setup_data {
-       unsigned i2c_bus;
-       unsigned short i2c_address;
-};
-
 #define WM8990_MCLK_DIV 0
 #define WM8990_DACCLK_DIV 1
 #define WM8990_ADCCLK_DIV 2
 #define WM8990_BCLK_DIV 3
 
-extern struct snd_soc_dai wm8990_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8990;
-
 #endif /* __WM8990REGISTERDEFS_H__ */
 /*------------------------------ END OF FILE ---------------------------------*/
index d8d300c6175fb2b48db37207885f9110b2a8768c..589e3fa24734c721cce8e8fac6b3f9f72a50373b 100644 (file)
@@ -229,7 +229,7 @@ struct wm8993_priv {
        u16 reg_cache[WM8993_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
        struct wm8993_platform_data pdata;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        int master;
        int sysclk_source;
        int tdm_slots;
@@ -367,10 +367,9 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
        return 0;
 }
 
-static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                          unsigned int Fref, unsigned int Fout)
 {
-       struct snd_soc_codec *codec = dai->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        u16 reg1, reg4, reg5;
        struct _fll_div fll_div;
@@ -456,6 +455,12 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
        return 0;
 }
 
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       return _wm8993_set_fll(dai->codec, fll_id, source, Fref, Fout);
+}
+
 static int configure_clock(struct snd_soc_codec *codec)
 {
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
@@ -1394,8 +1399,8 @@ static struct snd_soc_dai_ops wm8993_ops = {
                        SNDRV_PCM_FMTBIT_S24_LE |\
                        SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai wm8993_dai = {
-       .name = "WM8993",
+static struct snd_soc_dai_driver wm8993_dai = {
+       .name = "wm8993-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1413,32 +1418,81 @@ struct snd_soc_dai wm8993_dai = {
        .ops = &wm8993_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8993_dai);
-
-static struct snd_soc_codec *wm8993_codec;
 
-static int wm8993_probe(struct platform_device *pdev)
+static int wm8993_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm8993_priv *wm8993;
-       int ret = 0;
+       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+       int ret, i, val;
+
+       wm8993->hubs_data.hp_startup_mode = 1;
+       wm8993->hubs_data.dcs_codes = -2;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
+               wm8993->supplies[i].supply = wm8993_supply_names[i];
 
-       if (!wm8993_codec) {
-               dev_err(&pdev->dev, "I2C device not yet probed\n");
-               goto err;
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
+                                wm8993->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8993_codec;
-       codec = wm8993_codec;
-       wm8993 = snd_soc_codec_get_drvdata(codec);
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+                                   wm8993->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
 
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               goto err;
+       val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
+       if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Invalid ID register value %x\n", val);
+               ret = -EINVAL;
+               goto err_enable;
        }
 
+       ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
+       if (ret != 0)
+               goto err_enable;
+
+       codec->cache_only = 1;
+
+       /* By default we're using the output mixers */
+       wm8993->class_w_users = 2;
+
+       /* Latch volume update bits and default ZC on */
+       snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+                           WM8993_DAC_VU, WM8993_DAC_VU);
+       snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+                           WM8993_ADC_VU, WM8993_ADC_VU);
+
+       /* Manualy manage the HPOUT sequencing for independent stereo
+        * control. */
+       snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+                           WM8993_HPOUT1_AUTO_PU, 0);
+
+       /* Use automatic clock configuration */
+       snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+
+       wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
+                                     wm8993->pdata.lineout2_diff,
+                                     wm8993->pdata.lineout1fb,
+                                     wm8993->pdata.lineout2fb,
+                                     wm8993->pdata.jd_scthr,
+                                     wm8993->pdata.jd_thr,
+                                     wm8993->pdata.micbias1_lvl,
+                                     wm8993->pdata.micbias2_lvl);
+
+       ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       if (ret != 0)
+               goto err_enable;
+
        snd_soc_add_controls(codec, wm8993_snd_controls,
                             ARRAY_SIZE(wm8993_snd_controls));
        if (wm8993->pdata.num_retune_configs != 0) {
@@ -1457,36 +1511,36 @@ static int wm8993_probe(struct platform_device *pdev)
        wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
                                    wm8993->pdata.lineout2_diff);
 
-       return ret;
+       return 0;
 
-err:
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return ret;
 }
 
-static int wm8993_remove(struct platform_device *pdev)
+static int wm8993_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 
+       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8993_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int fll_fout = wm8993->fll_fout;
        int fll_fref  = wm8993->fll_fref;
        int ret;
 
        /* Stop the FLL in an orderly fashion */
-       ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
+       ret = _wm8993_set_fll(codec, 0, 0, 0, 0);
        if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               dev_err(codec->dev, "Failed to stop FLL\n");
                return ret;
        }
 
@@ -1498,10 +1552,8 @@ static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8993_resume(struct platform_device *pdev)
+static int wm8993_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
@@ -1515,7 +1567,7 @@ static int wm8993_resume(struct platform_device *pdev)
                wm8993->fll_fref = 0;
                wm8993->fll_fout = 0;
 
-               ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
+               ret = _wm8993_set_fll(codec, 0, wm8993->fll_src,
                                     fll_fref, fll_fout);
                if (ret != 0)
                        dev_err(codec->dev, "Failed to restart FLL\n");
@@ -1528,162 +1580,42 @@ static int wm8993_resume(struct platform_device *pdev)
 #define wm8993_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_wm8993 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
        .probe =        wm8993_probe,
        .remove =       wm8993_remove,
        .suspend =      wm8993_suspend,
        .resume =       wm8993_resume,
+       .set_bias_level = wm8993_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8993_reg_defaults,
+       .volatile_register = wm8993_volatile,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
 
-static int wm8993_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8993_priv *wm8993;
-       struct snd_soc_codec *codec;
-       unsigned int val;
        int ret;
-       int i;
-
-       if (wm8993_codec) {
-               dev_err(&i2c->dev, "A WM8993 is already registered\n");
-               return -EINVAL;
-       }
 
        wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
        if (wm8993 == NULL)
                return -ENOMEM;
 
-       codec = &wm8993->codec;
-       if (i2c->dev.platform_data)
-               memcpy(&wm8993->pdata, i2c->dev.platform_data,
-                      sizeof(wm8993->pdata));
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8993";
-       codec->volatile_register = wm8993_volatile;
-       codec->reg_cache = wm8993->reg_cache;
-       codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8993_set_bias_level;
-       codec->dai = &wm8993_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, wm8993);
-
-       wm8993->hubs_data.hp_startup_mode = 1;
-       wm8993->hubs_data.dcs_codes = -2;
-
-       memcpy(wm8993->reg_cache, wm8993_reg_defaults,
-              sizeof(wm8993->reg_cache));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
        i2c_set_clientdata(i2c, wm8993);
-       codec->control_data = i2c;
-       wm8993_codec = codec;
-
-       codec->dev = &i2c->dev;
-
-       for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
-               wm8993->supplies[i].supply = wm8993_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
-                                wm8993->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
-                                   wm8993->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
-       if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
-               dev_err(codec->dev, "Invalid ID register value %x\n", val);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
-       if (ret != 0)
-               goto err_enable;
-
-       codec->cache_only = 1;
-
-       /* By default we're using the output mixers */
-       wm8993->class_w_users = 2;
-
-       /* Latch volume update bits and default ZC on */
-       snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
-                           WM8993_DAC_VU, WM8993_DAC_VU);
-       snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
-                           WM8993_ADC_VU, WM8993_ADC_VU);
 
-       /* Manualy manage the HPOUT sequencing for independent stereo
-        * control. */
-       snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
-                           WM8993_HPOUT1_AUTO_PU, 0);
-
-       /* Use automatic clock configuration */
-       snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
-
-       wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
-                                     wm8993->pdata.lineout2_diff,
-                                     wm8993->pdata.lineout1fb,
-                                     wm8993->pdata.lineout2fb,
-                                     wm8993->pdata.jd_scthr,
-                                     wm8993->pdata.jd_thr,
-                                     wm8993->pdata.micbias1_lvl,
-                                     wm8993->pdata.micbias2_lvl);
-                            
-       ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       if (ret != 0)
-               goto err_enable;
-
-       wm8993_dai.dev = codec->dev;
-
-       ret = snd_soc_register_dai(&wm8993_dai);
-       if (ret != 0)
-               goto err_bias;
-
-       ret = snd_soc_register_codec(codec);
-
-       return 0;
-
-err_bias:
-       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err:
-       wm8993_codec = NULL;
-       kfree(wm8993);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8993, &wm8993_dai, 1);
+       if (ret < 0)
+               kfree(wm8993);
        return ret;
 }
 
-static int wm8993_i2c_remove(struct i2c_client *client)
+static __devexit int wm8993_i2c_remove(struct i2c_client *client)
 {
-       struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_codec(&wm8993->codec);
-       snd_soc_unregister_dai(&wm8993_dai);
-
-       wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-       kfree(wm8993);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1695,30 +1627,34 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
 
 static struct i2c_driver wm8993_i2c_driver = {
        .driver = {
-               .name = "WM8993",
+               .name = "wm8993-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8993_i2c_probe,
-       .remove = wm8993_i2c_remove,
+       .probe =    wm8993_i2c_probe,
+       .remove =   __devexit_p(wm8993_i2c_remove),
        .id_table = wm8993_i2c_id,
 };
-
+#endif
 
 static int __init wm8993_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8993_i2c_driver);
-       if (ret != 0)
-               pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
-
+       if (ret != 0) {
+               pr_err("WM8993: Unable to register I2C driver: %d\n",
+                      ret);
+       }
+#endif
        return ret;
 }
 module_init(wm8993_modinit);
 
 static void __exit wm8993_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8993_i2c_driver);
+#endif
 }
 module_exit(wm8993_exit);
 
index 30e71ca88dad1a790a59a6bad2730634f922b7ec..2184617b96117bfabac14cc7411eb24d2dadb317 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef WM8993_H
 #define WM8993_H
 
-extern struct snd_soc_dai wm8993_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8993;
-
 #define WM8993_SYSCLK_MCLK     1
 #define WM8993_SYSCLK_FLL      2
 
index 522249d5c2b463d9917e751bc0cac0fa9711c1da..0db59c3aa5d4dbb6cd2a821d29eaa75887290977 100644 (file)
@@ -36,9 +36,6 @@
 #include "wm8994.h"
 #include "wm_hubs.h"
 
-static struct snd_soc_codec *wm8994_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8994;
-
 struct fll_config {
        int src;
        int in;
@@ -71,7 +68,9 @@ struct wm8994_micdet {
 /* codec private data */
 struct wm8994_priv {
        struct wm_hubs_data hubs;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       struct snd_soc_codec *codec;
        u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
        int sysclk[2];
        int sysclk_rate[2];
@@ -99,1581 +98,1580 @@ struct wm8994_priv {
        struct wm8994_pdata *pdata;
 };
 
-static struct {
-       unsigned short  readable;   /* Mask of readable bits */
-       unsigned short  writable;   /* Mask of writable bits */
-       unsigned short  vol;        /* Mask of volatile bits */
+static const struct {
+       unsigned short readable;   /* Mask of readable bits */
+       unsigned short writable;   /* Mask of writable bits */
 } access_masks[] = {
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R0     - Software Reset */
-       { 0x3B37, 0x3B37, 0x0000 }, /* R1     - Power Management (1) */
-       { 0x6BF0, 0x6BF0, 0x0000 }, /* R2     - Power Management (2) */
-       { 0x3FF0, 0x3FF0, 0x0000 }, /* R3     - Power Management (3) */
-       { 0x3F3F, 0x3F3F, 0x0000 }, /* R4     - Power Management (4) */
-       { 0x3F0F, 0x3F0F, 0x0000 }, /* R5     - Power Management (5) */
-       { 0x003F, 0x003F, 0x0000 }, /* R6     - Power Management (6) */
-       { 0x0000, 0x0000, 0x0000 }, /* R7 */
-       { 0x0000, 0x0000, 0x0000 }, /* R8 */
-       { 0x0000, 0x0000, 0x0000 }, /* R9 */
-       { 0x0000, 0x0000, 0x0000 }, /* R10 */
-       { 0x0000, 0x0000, 0x0000 }, /* R11 */
-       { 0x0000, 0x0000, 0x0000 }, /* R12 */
-       { 0x0000, 0x0000, 0x0000 }, /* R13 */
-       { 0x0000, 0x0000, 0x0000 }, /* R14 */
-       { 0x0000, 0x0000, 0x0000 }, /* R15 */
-       { 0x0000, 0x0000, 0x0000 }, /* R16 */
-       { 0x0000, 0x0000, 0x0000 }, /* R17 */
-       { 0x0000, 0x0000, 0x0000 }, /* R18 */
-       { 0x0000, 0x0000, 0x0000 }, /* R19 */
-       { 0x0000, 0x0000, 0x0000 }, /* R20 */
-       { 0x01C0, 0x01C0, 0x0000 }, /* R21    - Input Mixer (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R22 */
-       { 0x0000, 0x0000, 0x0000 }, /* R23 */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R24    - Left Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R25    - Left Line Input 3&4 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R26    - Right Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R27    - Right Line Input 3&4 Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R28    - Left Output Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R29    - Right Output Volume */
-       { 0x0077, 0x0077, 0x0000 }, /* R30    - Line Outputs Volume */
-       { 0x0030, 0x0030, 0x0000 }, /* R31    - HPOUT2 Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R32    - Left OPGA Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R33    - Right OPGA Volume */
-       { 0x007F, 0x007F, 0x0000 }, /* R34    - SPKMIXL Attenuation */
-       { 0x017F, 0x017F, 0x0000 }, /* R35    - SPKMIXR Attenuation */
-       { 0x003F, 0x003F, 0x0000 }, /* R36    - SPKOUT Mixers */
-       { 0x003F, 0x003F, 0x0000 }, /* R37    - ClassD */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R38    - Speaker Volume Left */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R39    - Speaker Volume Right */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R40    - Input Mixer (2) */
-       { 0x01B7, 0x01B7, 0x0000 }, /* R41    - Input Mixer (3) */
-       { 0x01B7, 0x01B7, 0x0000 }, /* R42    - Input Mixer (4) */
-       { 0x01C7, 0x01C7, 0x0000 }, /* R43    - Input Mixer (5) */
-       { 0x01C7, 0x01C7, 0x0000 }, /* R44    - Input Mixer (6) */
-       { 0x01FF, 0x01FF, 0x0000 }, /* R45    - Output Mixer (1) */
-       { 0x01FF, 0x01FF, 0x0000 }, /* R46    - Output Mixer (2) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R47    - Output Mixer (3) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R48    - Output Mixer (4) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R49    - Output Mixer (5) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R50    - Output Mixer (6) */
-       { 0x0038, 0x0038, 0x0000 }, /* R51    - HPOUT2 Mixer */
-       { 0x0077, 0x0077, 0x0000 }, /* R52    - Line Mixer (1) */
-       { 0x0077, 0x0077, 0x0000 }, /* R53    - Line Mixer (2) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R54    - Speaker Mixer */
-       { 0x00C1, 0x00C1, 0x0000 }, /* R55    - Additional Control */
-       { 0x00F0, 0x00F0, 0x0000 }, /* R56    - AntiPOP (1) */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R57    - AntiPOP (2) */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R58    - MICBIAS */
-       { 0x000F, 0x000F, 0x0000 }, /* R59    - LDO 1 */
-       { 0x0007, 0x0007, 0x0000 }, /* R60    - LDO 2 */
-       { 0x0000, 0x0000, 0x0000 }, /* R61 */
-       { 0x0000, 0x0000, 0x0000 }, /* R62 */
-       { 0x0000, 0x0000, 0x0000 }, /* R63 */
-       { 0x0000, 0x0000, 0x0000 }, /* R64 */
-       { 0x0000, 0x0000, 0x0000 }, /* R65 */
-       { 0x0000, 0x0000, 0x0000 }, /* R66 */
-       { 0x0000, 0x0000, 0x0000 }, /* R67 */
-       { 0x0000, 0x0000, 0x0000 }, /* R68 */
-       { 0x0000, 0x0000, 0x0000 }, /* R69 */
-       { 0x0000, 0x0000, 0x0000 }, /* R70 */
-       { 0x0000, 0x0000, 0x0000 }, /* R71 */
-       { 0x0000, 0x0000, 0x0000 }, /* R72 */
-       { 0x0000, 0x0000, 0x0000 }, /* R73 */
-       { 0x0000, 0x0000, 0x0000 }, /* R74 */
-       { 0x0000, 0x0000, 0x0000 }, /* R75 */
-       { 0x8000, 0x8000, 0x0000 }, /* R76    - Charge Pump (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R77 */
-       { 0x0000, 0x0000, 0x0000 }, /* R78 */
-       { 0x0000, 0x0000, 0x0000 }, /* R79 */
-       { 0x0000, 0x0000, 0x0000 }, /* R80 */
-       { 0x0301, 0x0301, 0x0000 }, /* R81    - Class W (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R82 */
-       { 0x0000, 0x0000, 0x0000 }, /* R83 */
-       { 0x333F, 0x333F, 0x0000 }, /* R84    - DC Servo (1) */
-       { 0x0FEF, 0x0FEF, 0x0000 }, /* R85    - DC Servo (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R86 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R87    - DC Servo (4) */
-       { 0x0333, 0x0000, 0x0000 }, /* R88    - DC Servo Readback */
-       { 0x0000, 0x0000, 0x0000 }, /* R89 */
-       { 0x0000, 0x0000, 0x0000 }, /* R90 */
-       { 0x0000, 0x0000, 0x0000 }, /* R91 */
-       { 0x0000, 0x0000, 0x0000 }, /* R92 */
-       { 0x0000, 0x0000, 0x0000 }, /* R93 */
-       { 0x0000, 0x0000, 0x0000 }, /* R94 */
-       { 0x0000, 0x0000, 0x0000 }, /* R95 */
-       { 0x00EE, 0x00EE, 0x0000 }, /* R96    - Analogue HP (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R97 */
-       { 0x0000, 0x0000, 0x0000 }, /* R98 */
-       { 0x0000, 0x0000, 0x0000 }, /* R99 */
-       { 0x0000, 0x0000, 0x0000 }, /* R100 */
-       { 0x0000, 0x0000, 0x0000 }, /* R101 */
-       { 0x0000, 0x0000, 0x0000 }, /* R102 */
-       { 0x0000, 0x0000, 0x0000 }, /* R103 */
-       { 0x0000, 0x0000, 0x0000 }, /* R104 */
-       { 0x0000, 0x0000, 0x0000 }, /* R105 */
-       { 0x0000, 0x0000, 0x0000 }, /* R106 */
-       { 0x0000, 0x0000, 0x0000 }, /* R107 */
-       { 0x0000, 0x0000, 0x0000 }, /* R108 */
-       { 0x0000, 0x0000, 0x0000 }, /* R109 */
-       { 0x0000, 0x0000, 0x0000 }, /* R110 */
-       { 0x0000, 0x0000, 0x0000 }, /* R111 */
-       { 0x0000, 0x0000, 0x0000 }, /* R112 */
-       { 0x0000, 0x0000, 0x0000 }, /* R113 */
-       { 0x0000, 0x0000, 0x0000 }, /* R114 */
-       { 0x0000, 0x0000, 0x0000 }, /* R115 */
-       { 0x0000, 0x0000, 0x0000 }, /* R116 */
-       { 0x0000, 0x0000, 0x0000 }, /* R117 */
-       { 0x0000, 0x0000, 0x0000 }, /* R118 */
-       { 0x0000, 0x0000, 0x0000 }, /* R119 */
-       { 0x0000, 0x0000, 0x0000 }, /* R120 */
-       { 0x0000, 0x0000, 0x0000 }, /* R121 */
-       { 0x0000, 0x0000, 0x0000 }, /* R122 */
-       { 0x0000, 0x0000, 0x0000 }, /* R123 */
-       { 0x0000, 0x0000, 0x0000 }, /* R124 */
-       { 0x0000, 0x0000, 0x0000 }, /* R125 */
-       { 0x0000, 0x0000, 0x0000 }, /* R126 */
-       { 0x0000, 0x0000, 0x0000 }, /* R127 */
-       { 0x0000, 0x0000, 0x0000 }, /* R128 */
-       { 0x0000, 0x0000, 0x0000 }, /* R129 */
-       { 0x0000, 0x0000, 0x0000 }, /* R130 */
-       { 0x0000, 0x0000, 0x0000 }, /* R131 */
-       { 0x0000, 0x0000, 0x0000 }, /* R132 */
-       { 0x0000, 0x0000, 0x0000 }, /* R133 */
-       { 0x0000, 0x0000, 0x0000 }, /* R134 */
-       { 0x0000, 0x0000, 0x0000 }, /* R135 */
-       { 0x0000, 0x0000, 0x0000 }, /* R136 */
-       { 0x0000, 0x0000, 0x0000 }, /* R137 */
-       { 0x0000, 0x0000, 0x0000 }, /* R138 */
-       { 0x0000, 0x0000, 0x0000 }, /* R139 */
-       { 0x0000, 0x0000, 0x0000 }, /* R140 */
-       { 0x0000, 0x0000, 0x0000 }, /* R141 */
-       { 0x0000, 0x0000, 0x0000 }, /* R142 */
-       { 0x0000, 0x0000, 0x0000 }, /* R143 */
-       { 0x0000, 0x0000, 0x0000 }, /* R144 */
-       { 0x0000, 0x0000, 0x0000 }, /* R145 */
-       { 0x0000, 0x0000, 0x0000 }, /* R146 */
-       { 0x0000, 0x0000, 0x0000 }, /* R147 */
-       { 0x0000, 0x0000, 0x0000 }, /* R148 */
-       { 0x0000, 0x0000, 0x0000 }, /* R149 */
-       { 0x0000, 0x0000, 0x0000 }, /* R150 */
-       { 0x0000, 0x0000, 0x0000 }, /* R151 */
-       { 0x0000, 0x0000, 0x0000 }, /* R152 */
-       { 0x0000, 0x0000, 0x0000 }, /* R153 */
-       { 0x0000, 0x0000, 0x0000 }, /* R154 */
-       { 0x0000, 0x0000, 0x0000 }, /* R155 */
-       { 0x0000, 0x0000, 0x0000 }, /* R156 */
-       { 0x0000, 0x0000, 0x0000 }, /* R157 */
-       { 0x0000, 0x0000, 0x0000 }, /* R158 */
-       { 0x0000, 0x0000, 0x0000 }, /* R159 */
-       { 0x0000, 0x0000, 0x0000 }, /* R160 */
-       { 0x0000, 0x0000, 0x0000 }, /* R161 */
-       { 0x0000, 0x0000, 0x0000 }, /* R162 */
-       { 0x0000, 0x0000, 0x0000 }, /* R163 */
-       { 0x0000, 0x0000, 0x0000 }, /* R164 */
-       { 0x0000, 0x0000, 0x0000 }, /* R165 */
-       { 0x0000, 0x0000, 0x0000 }, /* R166 */
-       { 0x0000, 0x0000, 0x0000 }, /* R167 */
-       { 0x0000, 0x0000, 0x0000 }, /* R168 */
-       { 0x0000, 0x0000, 0x0000 }, /* R169 */
-       { 0x0000, 0x0000, 0x0000 }, /* R170 */
-       { 0x0000, 0x0000, 0x0000 }, /* R171 */
-       { 0x0000, 0x0000, 0x0000 }, /* R172 */
-       { 0x0000, 0x0000, 0x0000 }, /* R173 */
-       { 0x0000, 0x0000, 0x0000 }, /* R174 */
-       { 0x0000, 0x0000, 0x0000 }, /* R175 */
-       { 0x0000, 0x0000, 0x0000 }, /* R176 */
-       { 0x0000, 0x0000, 0x0000 }, /* R177 */
-       { 0x0000, 0x0000, 0x0000 }, /* R178 */
-       { 0x0000, 0x0000, 0x0000 }, /* R179 */
-       { 0x0000, 0x0000, 0x0000 }, /* R180 */
-       { 0x0000, 0x0000, 0x0000 }, /* R181 */
-       { 0x0000, 0x0000, 0x0000 }, /* R182 */
-       { 0x0000, 0x0000, 0x0000 }, /* R183 */
-       { 0x0000, 0x0000, 0x0000 }, /* R184 */
-       { 0x0000, 0x0000, 0x0000 }, /* R185 */
-       { 0x0000, 0x0000, 0x0000 }, /* R186 */
-       { 0x0000, 0x0000, 0x0000 }, /* R187 */
-       { 0x0000, 0x0000, 0x0000 }, /* R188 */
-       { 0x0000, 0x0000, 0x0000 }, /* R189 */
-       { 0x0000, 0x0000, 0x0000 }, /* R190 */
-       { 0x0000, 0x0000, 0x0000 }, /* R191 */
-       { 0x0000, 0x0000, 0x0000 }, /* R192 */
-       { 0x0000, 0x0000, 0x0000 }, /* R193 */
-       { 0x0000, 0x0000, 0x0000 }, /* R194 */
-       { 0x0000, 0x0000, 0x0000 }, /* R195 */
-       { 0x0000, 0x0000, 0x0000 }, /* R196 */
-       { 0x0000, 0x0000, 0x0000 }, /* R197 */
-       { 0x0000, 0x0000, 0x0000 }, /* R198 */
-       { 0x0000, 0x0000, 0x0000 }, /* R199 */
-       { 0x0000, 0x0000, 0x0000 }, /* R200 */
-       { 0x0000, 0x0000, 0x0000 }, /* R201 */
-       { 0x0000, 0x0000, 0x0000 }, /* R202 */
-       { 0x0000, 0x0000, 0x0000 }, /* R203 */
-       { 0x0000, 0x0000, 0x0000 }, /* R204 */
-       { 0x0000, 0x0000, 0x0000 }, /* R205 */
-       { 0x0000, 0x0000, 0x0000 }, /* R206 */
-       { 0x0000, 0x0000, 0x0000 }, /* R207 */
-       { 0x0000, 0x0000, 0x0000 }, /* R208 */
-       { 0x0000, 0x0000, 0x0000 }, /* R209 */
-       { 0x0000, 0x0000, 0x0000 }, /* R210 */
-       { 0x0000, 0x0000, 0x0000 }, /* R211 */
-       { 0x0000, 0x0000, 0x0000 }, /* R212 */
-       { 0x0000, 0x0000, 0x0000 }, /* R213 */
-       { 0x0000, 0x0000, 0x0000 }, /* R214 */
-       { 0x0000, 0x0000, 0x0000 }, /* R215 */
-       { 0x0000, 0x0000, 0x0000 }, /* R216 */
-       { 0x0000, 0x0000, 0x0000 }, /* R217 */
-       { 0x0000, 0x0000, 0x0000 }, /* R218 */
-       { 0x0000, 0x0000, 0x0000 }, /* R219 */
-       { 0x0000, 0x0000, 0x0000 }, /* R220 */
-       { 0x0000, 0x0000, 0x0000 }, /* R221 */
-       { 0x0000, 0x0000, 0x0000 }, /* R222 */
-       { 0x0000, 0x0000, 0x0000 }, /* R223 */
-       { 0x0000, 0x0000, 0x0000 }, /* R224 */
-       { 0x0000, 0x0000, 0x0000 }, /* R225 */
-       { 0x0000, 0x0000, 0x0000 }, /* R226 */
-       { 0x0000, 0x0000, 0x0000 }, /* R227 */
-       { 0x0000, 0x0000, 0x0000 }, /* R228 */
-       { 0x0000, 0x0000, 0x0000 }, /* R229 */
-       { 0x0000, 0x0000, 0x0000 }, /* R230 */
-       { 0x0000, 0x0000, 0x0000 }, /* R231 */
-       { 0x0000, 0x0000, 0x0000 }, /* R232 */
-       { 0x0000, 0x0000, 0x0000 }, /* R233 */
-       { 0x0000, 0x0000, 0x0000 }, /* R234 */
-       { 0x0000, 0x0000, 0x0000 }, /* R235 */
-       { 0x0000, 0x0000, 0x0000 }, /* R236 */
-       { 0x0000, 0x0000, 0x0000 }, /* R237 */
-       { 0x0000, 0x0000, 0x0000 }, /* R238 */
-       { 0x0000, 0x0000, 0x0000 }, /* R239 */
-       { 0x0000, 0x0000, 0x0000 }, /* R240 */
-       { 0x0000, 0x0000, 0x0000 }, /* R241 */
-       { 0x0000, 0x0000, 0x0000 }, /* R242 */
-       { 0x0000, 0x0000, 0x0000 }, /* R243 */
-       { 0x0000, 0x0000, 0x0000 }, /* R244 */
-       { 0x0000, 0x0000, 0x0000 }, /* R245 */
-       { 0x0000, 0x0000, 0x0000 }, /* R246 */
-       { 0x0000, 0x0000, 0x0000 }, /* R247 */
-       { 0x0000, 0x0000, 0x0000 }, /* R248 */
-       { 0x0000, 0x0000, 0x0000 }, /* R249 */
-       { 0x0000, 0x0000, 0x0000 }, /* R250 */
-       { 0x0000, 0x0000, 0x0000 }, /* R251 */
-       { 0x0000, 0x0000, 0x0000 }, /* R252 */
-       { 0x0000, 0x0000, 0x0000 }, /* R253 */
-       { 0x0000, 0x0000, 0x0000 }, /* R254 */
-       { 0x0000, 0x0000, 0x0000 }, /* R255 */
-       { 0x000F, 0x0000, 0x0000 }, /* R256   - Chip Revision */
-       { 0x0074, 0x0074, 0x0000 }, /* R257   - Control Interface */
-       { 0x0000, 0x0000, 0x0000 }, /* R258 */
-       { 0x0000, 0x0000, 0x0000 }, /* R259 */
-       { 0x0000, 0x0000, 0x0000 }, /* R260 */
-       { 0x0000, 0x0000, 0x0000 }, /* R261 */
-       { 0x0000, 0x0000, 0x0000 }, /* R262 */
-       { 0x0000, 0x0000, 0x0000 }, /* R263 */
-       { 0x0000, 0x0000, 0x0000 }, /* R264 */
-       { 0x0000, 0x0000, 0x0000 }, /* R265 */
-       { 0x0000, 0x0000, 0x0000 }, /* R266 */
-       { 0x0000, 0x0000, 0x0000 }, /* R267 */
-       { 0x0000, 0x0000, 0x0000 }, /* R268 */
-       { 0x0000, 0x0000, 0x0000 }, /* R269 */
-       { 0x0000, 0x0000, 0x0000 }, /* R270 */
-       { 0x0000, 0x0000, 0x0000 }, /* R271 */
-       { 0x807F, 0x837F, 0x0000 }, /* R272   - Write Sequencer Ctrl (1) */
-       { 0x017F, 0x0000, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R274 */
-       { 0x0000, 0x0000, 0x0000 }, /* R275 */
-       { 0x0000, 0x0000, 0x0000 }, /* R276 */
-       { 0x0000, 0x0000, 0x0000 }, /* R277 */
-       { 0x0000, 0x0000, 0x0000 }, /* R278 */
-       { 0x0000, 0x0000, 0x0000 }, /* R279 */
-       { 0x0000, 0x0000, 0x0000 }, /* R280 */
-       { 0x0000, 0x0000, 0x0000 }, /* R281 */
-       { 0x0000, 0x0000, 0x0000 }, /* R282 */
-       { 0x0000, 0x0000, 0x0000 }, /* R283 */
-       { 0x0000, 0x0000, 0x0000 }, /* R284 */
-       { 0x0000, 0x0000, 0x0000 }, /* R285 */
-       { 0x0000, 0x0000, 0x0000 }, /* R286 */
-       { 0x0000, 0x0000, 0x0000 }, /* R287 */
-       { 0x0000, 0x0000, 0x0000 }, /* R288 */
-       { 0x0000, 0x0000, 0x0000 }, /* R289 */
-       { 0x0000, 0x0000, 0x0000 }, /* R290 */
-       { 0x0000, 0x0000, 0x0000 }, /* R291 */
-       { 0x0000, 0x0000, 0x0000 }, /* R292 */
-       { 0x0000, 0x0000, 0x0000 }, /* R293 */
-       { 0x0000, 0x0000, 0x0000 }, /* R294 */
-       { 0x0000, 0x0000, 0x0000 }, /* R295 */
-       { 0x0000, 0x0000, 0x0000 }, /* R296 */
-       { 0x0000, 0x0000, 0x0000 }, /* R297 */
-       { 0x0000, 0x0000, 0x0000 }, /* R298 */
-       { 0x0000, 0x0000, 0x0000 }, /* R299 */
-       { 0x0000, 0x0000, 0x0000 }, /* R300 */
-       { 0x0000, 0x0000, 0x0000 }, /* R301 */
-       { 0x0000, 0x0000, 0x0000 }, /* R302 */
-       { 0x0000, 0x0000, 0x0000 }, /* R303 */
-       { 0x0000, 0x0000, 0x0000 }, /* R304 */
-       { 0x0000, 0x0000, 0x0000 }, /* R305 */
-       { 0x0000, 0x0000, 0x0000 }, /* R306 */
-       { 0x0000, 0x0000, 0x0000 }, /* R307 */
-       { 0x0000, 0x0000, 0x0000 }, /* R308 */
-       { 0x0000, 0x0000, 0x0000 }, /* R309 */
-       { 0x0000, 0x0000, 0x0000 }, /* R310 */
-       { 0x0000, 0x0000, 0x0000 }, /* R311 */
-       { 0x0000, 0x0000, 0x0000 }, /* R312 */
-       { 0x0000, 0x0000, 0x0000 }, /* R313 */
-       { 0x0000, 0x0000, 0x0000 }, /* R314 */
-       { 0x0000, 0x0000, 0x0000 }, /* R315 */
-       { 0x0000, 0x0000, 0x0000 }, /* R316 */
-       { 0x0000, 0x0000, 0x0000 }, /* R317 */
-       { 0x0000, 0x0000, 0x0000 }, /* R318 */
-       { 0x0000, 0x0000, 0x0000 }, /* R319 */
-       { 0x0000, 0x0000, 0x0000 }, /* R320 */
-       { 0x0000, 0x0000, 0x0000 }, /* R321 */
-       { 0x0000, 0x0000, 0x0000 }, /* R322 */
-       { 0x0000, 0x0000, 0x0000 }, /* R323 */
-       { 0x0000, 0x0000, 0x0000 }, /* R324 */
-       { 0x0000, 0x0000, 0x0000 }, /* R325 */
-       { 0x0000, 0x0000, 0x0000 }, /* R326 */
-       { 0x0000, 0x0000, 0x0000 }, /* R327 */
-       { 0x0000, 0x0000, 0x0000 }, /* R328 */
-       { 0x0000, 0x0000, 0x0000 }, /* R329 */
-       { 0x0000, 0x0000, 0x0000 }, /* R330 */
-       { 0x0000, 0x0000, 0x0000 }, /* R331 */
-       { 0x0000, 0x0000, 0x0000 }, /* R332 */
-       { 0x0000, 0x0000, 0x0000 }, /* R333 */
-       { 0x0000, 0x0000, 0x0000 }, /* R334 */
-       { 0x0000, 0x0000, 0x0000 }, /* R335 */
-       { 0x0000, 0x0000, 0x0000 }, /* R336 */
-       { 0x0000, 0x0000, 0x0000 }, /* R337 */
-       { 0x0000, 0x0000, 0x0000 }, /* R338 */
-       { 0x0000, 0x0000, 0x0000 }, /* R339 */
-       { 0x0000, 0x0000, 0x0000 }, /* R340 */
-       { 0x0000, 0x0000, 0x0000 }, /* R341 */
-       { 0x0000, 0x0000, 0x0000 }, /* R342 */
-       { 0x0000, 0x0000, 0x0000 }, /* R343 */
-       { 0x0000, 0x0000, 0x0000 }, /* R344 */
-       { 0x0000, 0x0000, 0x0000 }, /* R345 */
-       { 0x0000, 0x0000, 0x0000 }, /* R346 */
-       { 0x0000, 0x0000, 0x0000 }, /* R347 */
-       { 0x0000, 0x0000, 0x0000 }, /* R348 */
-       { 0x0000, 0x0000, 0x0000 }, /* R349 */
-       { 0x0000, 0x0000, 0x0000 }, /* R350 */
-       { 0x0000, 0x0000, 0x0000 }, /* R351 */
-       { 0x0000, 0x0000, 0x0000 }, /* R352 */
-       { 0x0000, 0x0000, 0x0000 }, /* R353 */
-       { 0x0000, 0x0000, 0x0000 }, /* R354 */
-       { 0x0000, 0x0000, 0x0000 }, /* R355 */
-       { 0x0000, 0x0000, 0x0000 }, /* R356 */
-       { 0x0000, 0x0000, 0x0000 }, /* R357 */
-       { 0x0000, 0x0000, 0x0000 }, /* R358 */
-       { 0x0000, 0x0000, 0x0000 }, /* R359 */
-       { 0x0000, 0x0000, 0x0000 }, /* R360 */
-       { 0x0000, 0x0000, 0x0000 }, /* R361 */
-       { 0x0000, 0x0000, 0x0000 }, /* R362 */
-       { 0x0000, 0x0000, 0x0000 }, /* R363 */
-       { 0x0000, 0x0000, 0x0000 }, /* R364 */
-       { 0x0000, 0x0000, 0x0000 }, /* R365 */
-       { 0x0000, 0x0000, 0x0000 }, /* R366 */
-       { 0x0000, 0x0000, 0x0000 }, /* R367 */
-       { 0x0000, 0x0000, 0x0000 }, /* R368 */
-       { 0x0000, 0x0000, 0x0000 }, /* R369 */
-       { 0x0000, 0x0000, 0x0000 }, /* R370 */
-       { 0x0000, 0x0000, 0x0000 }, /* R371 */
-       { 0x0000, 0x0000, 0x0000 }, /* R372 */
-       { 0x0000, 0x0000, 0x0000 }, /* R373 */
-       { 0x0000, 0x0000, 0x0000 }, /* R374 */
-       { 0x0000, 0x0000, 0x0000 }, /* R375 */
-       { 0x0000, 0x0000, 0x0000 }, /* R376 */
-       { 0x0000, 0x0000, 0x0000 }, /* R377 */
-       { 0x0000, 0x0000, 0x0000 }, /* R378 */
-       { 0x0000, 0x0000, 0x0000 }, /* R379 */
-       { 0x0000, 0x0000, 0x0000 }, /* R380 */
-       { 0x0000, 0x0000, 0x0000 }, /* R381 */
-       { 0x0000, 0x0000, 0x0000 }, /* R382 */
-       { 0x0000, 0x0000, 0x0000 }, /* R383 */
-       { 0x0000, 0x0000, 0x0000 }, /* R384 */
-       { 0x0000, 0x0000, 0x0000 }, /* R385 */
-       { 0x0000, 0x0000, 0x0000 }, /* R386 */
-       { 0x0000, 0x0000, 0x0000 }, /* R387 */
-       { 0x0000, 0x0000, 0x0000 }, /* R388 */
-       { 0x0000, 0x0000, 0x0000 }, /* R389 */
-       { 0x0000, 0x0000, 0x0000 }, /* R390 */
-       { 0x0000, 0x0000, 0x0000 }, /* R391 */
-       { 0x0000, 0x0000, 0x0000 }, /* R392 */
-       { 0x0000, 0x0000, 0x0000 }, /* R393 */
-       { 0x0000, 0x0000, 0x0000 }, /* R394 */
-       { 0x0000, 0x0000, 0x0000 }, /* R395 */
-       { 0x0000, 0x0000, 0x0000 }, /* R396 */
-       { 0x0000, 0x0000, 0x0000 }, /* R397 */
-       { 0x0000, 0x0000, 0x0000 }, /* R398 */
-       { 0x0000, 0x0000, 0x0000 }, /* R399 */
-       { 0x0000, 0x0000, 0x0000 }, /* R400 */
-       { 0x0000, 0x0000, 0x0000 }, /* R401 */
-       { 0x0000, 0x0000, 0x0000 }, /* R402 */
-       { 0x0000, 0x0000, 0x0000 }, /* R403 */
-       { 0x0000, 0x0000, 0x0000 }, /* R404 */
-       { 0x0000, 0x0000, 0x0000 }, /* R405 */
-       { 0x0000, 0x0000, 0x0000 }, /* R406 */
-       { 0x0000, 0x0000, 0x0000 }, /* R407 */
-       { 0x0000, 0x0000, 0x0000 }, /* R408 */
-       { 0x0000, 0x0000, 0x0000 }, /* R409 */
-       { 0x0000, 0x0000, 0x0000 }, /* R410 */
-       { 0x0000, 0x0000, 0x0000 }, /* R411 */
-       { 0x0000, 0x0000, 0x0000 }, /* R412 */
-       { 0x0000, 0x0000, 0x0000 }, /* R413 */
-       { 0x0000, 0x0000, 0x0000 }, /* R414 */
-       { 0x0000, 0x0000, 0x0000 }, /* R415 */
-       { 0x0000, 0x0000, 0x0000 }, /* R416 */
-       { 0x0000, 0x0000, 0x0000 }, /* R417 */
-       { 0x0000, 0x0000, 0x0000 }, /* R418 */
-       { 0x0000, 0x0000, 0x0000 }, /* R419 */
-       { 0x0000, 0x0000, 0x0000 }, /* R420 */
-       { 0x0000, 0x0000, 0x0000 }, /* R421 */
-       { 0x0000, 0x0000, 0x0000 }, /* R422 */
-       { 0x0000, 0x0000, 0x0000 }, /* R423 */
-       { 0x0000, 0x0000, 0x0000 }, /* R424 */
-       { 0x0000, 0x0000, 0x0000 }, /* R425 */
-       { 0x0000, 0x0000, 0x0000 }, /* R426 */
-       { 0x0000, 0x0000, 0x0000 }, /* R427 */
-       { 0x0000, 0x0000, 0x0000 }, /* R428 */
-       { 0x0000, 0x0000, 0x0000 }, /* R429 */
-       { 0x0000, 0x0000, 0x0000 }, /* R430 */
-       { 0x0000, 0x0000, 0x0000 }, /* R431 */
-       { 0x0000, 0x0000, 0x0000 }, /* R432 */
-       { 0x0000, 0x0000, 0x0000 }, /* R433 */
-       { 0x0000, 0x0000, 0x0000 }, /* R434 */
-       { 0x0000, 0x0000, 0x0000 }, /* R435 */
-       { 0x0000, 0x0000, 0x0000 }, /* R436 */
-       { 0x0000, 0x0000, 0x0000 }, /* R437 */
-       { 0x0000, 0x0000, 0x0000 }, /* R438 */
-       { 0x0000, 0x0000, 0x0000 }, /* R439 */
-       { 0x0000, 0x0000, 0x0000 }, /* R440 */
-       { 0x0000, 0x0000, 0x0000 }, /* R441 */
-       { 0x0000, 0x0000, 0x0000 }, /* R442 */
-       { 0x0000, 0x0000, 0x0000 }, /* R443 */
-       { 0x0000, 0x0000, 0x0000 }, /* R444 */
-       { 0x0000, 0x0000, 0x0000 }, /* R445 */
-       { 0x0000, 0x0000, 0x0000 }, /* R446 */
-       { 0x0000, 0x0000, 0x0000 }, /* R447 */
-       { 0x0000, 0x0000, 0x0000 }, /* R448 */
-       { 0x0000, 0x0000, 0x0000 }, /* R449 */
-       { 0x0000, 0x0000, 0x0000 }, /* R450 */
-       { 0x0000, 0x0000, 0x0000 }, /* R451 */
-       { 0x0000, 0x0000, 0x0000 }, /* R452 */
-       { 0x0000, 0x0000, 0x0000 }, /* R453 */
-       { 0x0000, 0x0000, 0x0000 }, /* R454 */
-       { 0x0000, 0x0000, 0x0000 }, /* R455 */
-       { 0x0000, 0x0000, 0x0000 }, /* R456 */
-       { 0x0000, 0x0000, 0x0000 }, /* R457 */
-       { 0x0000, 0x0000, 0x0000 }, /* R458 */
-       { 0x0000, 0x0000, 0x0000 }, /* R459 */
-       { 0x0000, 0x0000, 0x0000 }, /* R460 */
-       { 0x0000, 0x0000, 0x0000 }, /* R461 */
-       { 0x0000, 0x0000, 0x0000 }, /* R462 */
-       { 0x0000, 0x0000, 0x0000 }, /* R463 */
-       { 0x0000, 0x0000, 0x0000 }, /* R464 */
-       { 0x0000, 0x0000, 0x0000 }, /* R465 */
-       { 0x0000, 0x0000, 0x0000 }, /* R466 */
-       { 0x0000, 0x0000, 0x0000 }, /* R467 */
-       { 0x0000, 0x0000, 0x0000 }, /* R468 */
-       { 0x0000, 0x0000, 0x0000 }, /* R469 */
-       { 0x0000, 0x0000, 0x0000 }, /* R470 */
-       { 0x0000, 0x0000, 0x0000 }, /* R471 */
-       { 0x0000, 0x0000, 0x0000 }, /* R472 */
-       { 0x0000, 0x0000, 0x0000 }, /* R473 */
-       { 0x0000, 0x0000, 0x0000 }, /* R474 */
-       { 0x0000, 0x0000, 0x0000 }, /* R475 */
-       { 0x0000, 0x0000, 0x0000 }, /* R476 */
-       { 0x0000, 0x0000, 0x0000 }, /* R477 */
-       { 0x0000, 0x0000, 0x0000 }, /* R478 */
-       { 0x0000, 0x0000, 0x0000 }, /* R479 */
-       { 0x0000, 0x0000, 0x0000 }, /* R480 */
-       { 0x0000, 0x0000, 0x0000 }, /* R481 */
-       { 0x0000, 0x0000, 0x0000 }, /* R482 */
-       { 0x0000, 0x0000, 0x0000 }, /* R483 */
-       { 0x0000, 0x0000, 0x0000 }, /* R484 */
-       { 0x0000, 0x0000, 0x0000 }, /* R485 */
-       { 0x0000, 0x0000, 0x0000 }, /* R486 */
-       { 0x0000, 0x0000, 0x0000 }, /* R487 */
-       { 0x0000, 0x0000, 0x0000 }, /* R488 */
-       { 0x0000, 0x0000, 0x0000 }, /* R489 */
-       { 0x0000, 0x0000, 0x0000 }, /* R490 */
-       { 0x0000, 0x0000, 0x0000 }, /* R491 */
-       { 0x0000, 0x0000, 0x0000 }, /* R492 */
-       { 0x0000, 0x0000, 0x0000 }, /* R493 */
-       { 0x0000, 0x0000, 0x0000 }, /* R494 */
-       { 0x0000, 0x0000, 0x0000 }, /* R495 */
-       { 0x0000, 0x0000, 0x0000 }, /* R496 */
-       { 0x0000, 0x0000, 0x0000 }, /* R497 */
-       { 0x0000, 0x0000, 0x0000 }, /* R498 */
-       { 0x0000, 0x0000, 0x0000 }, /* R499 */
-       { 0x0000, 0x0000, 0x0000 }, /* R500 */
-       { 0x0000, 0x0000, 0x0000 }, /* R501 */
-       { 0x0000, 0x0000, 0x0000 }, /* R502 */
-       { 0x0000, 0x0000, 0x0000 }, /* R503 */
-       { 0x0000, 0x0000, 0x0000 }, /* R504 */
-       { 0x0000, 0x0000, 0x0000 }, /* R505 */
-       { 0x0000, 0x0000, 0x0000 }, /* R506 */
-       { 0x0000, 0x0000, 0x0000 }, /* R507 */
-       { 0x0000, 0x0000, 0x0000 }, /* R508 */
-       { 0x0000, 0x0000, 0x0000 }, /* R509 */
-       { 0x0000, 0x0000, 0x0000 }, /* R510 */
-       { 0x0000, 0x0000, 0x0000 }, /* R511 */
-       { 0x001F, 0x001F, 0x0000 }, /* R512   - AIF1 Clocking (1) */
-       { 0x003F, 0x003F, 0x0000 }, /* R513   - AIF1 Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R514 */
-       { 0x0000, 0x0000, 0x0000 }, /* R515 */
-       { 0x001F, 0x001F, 0x0000 }, /* R516   - AIF2 Clocking (1) */
-       { 0x003F, 0x003F, 0x0000 }, /* R517   - AIF2 Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R518 */
-       { 0x0000, 0x0000, 0x0000 }, /* R519 */
-       { 0x001F, 0x001F, 0x0000 }, /* R520   - Clocking (1) */
-       { 0x0777, 0x0777, 0x0000 }, /* R521   - Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R522 */
-       { 0x0000, 0x0000, 0x0000 }, /* R523 */
-       { 0x0000, 0x0000, 0x0000 }, /* R524 */
-       { 0x0000, 0x0000, 0x0000 }, /* R525 */
-       { 0x0000, 0x0000, 0x0000 }, /* R526 */
-       { 0x0000, 0x0000, 0x0000 }, /* R527 */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R528   - AIF1 Rate */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R529   - AIF2 Rate */
-       { 0x000F, 0x0000, 0x0000 }, /* R530   - Rate Status */
-       { 0x0000, 0x0000, 0x0000 }, /* R531 */
-       { 0x0000, 0x0000, 0x0000 }, /* R532 */
-       { 0x0000, 0x0000, 0x0000 }, /* R533 */
-       { 0x0000, 0x0000, 0x0000 }, /* R534 */
-       { 0x0000, 0x0000, 0x0000 }, /* R535 */
-       { 0x0000, 0x0000, 0x0000 }, /* R536 */
-       { 0x0000, 0x0000, 0x0000 }, /* R537 */
-       { 0x0000, 0x0000, 0x0000 }, /* R538 */
-       { 0x0000, 0x0000, 0x0000 }, /* R539 */
-       { 0x0000, 0x0000, 0x0000 }, /* R540 */
-       { 0x0000, 0x0000, 0x0000 }, /* R541 */
-       { 0x0000, 0x0000, 0x0000 }, /* R542 */
-       { 0x0000, 0x0000, 0x0000 }, /* R543 */
-       { 0x0007, 0x0007, 0x0000 }, /* R544   - FLL1 Control (1) */
-       { 0x3F77, 0x3F77, 0x0000 }, /* R545   - FLL1 Control (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R546   - FLL1 Control (3) */
-       { 0x7FEF, 0x7FEF, 0x0000 }, /* R547   - FLL1 Control (4) */
-       { 0x1FDB, 0x1FDB, 0x0000 }, /* R548   - FLL1 Control (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R549 */
-       { 0x0000, 0x0000, 0x0000 }, /* R550 */
-       { 0x0000, 0x0000, 0x0000 }, /* R551 */
-       { 0x0000, 0x0000, 0x0000 }, /* R552 */
-       { 0x0000, 0x0000, 0x0000 }, /* R553 */
-       { 0x0000, 0x0000, 0x0000 }, /* R554 */
-       { 0x0000, 0x0000, 0x0000 }, /* R555 */
-       { 0x0000, 0x0000, 0x0000 }, /* R556 */
-       { 0x0000, 0x0000, 0x0000 }, /* R557 */
-       { 0x0000, 0x0000, 0x0000 }, /* R558 */
-       { 0x0000, 0x0000, 0x0000 }, /* R559 */
-       { 0x0000, 0x0000, 0x0000 }, /* R560 */
-       { 0x0000, 0x0000, 0x0000 }, /* R561 */
-       { 0x0000, 0x0000, 0x0000 }, /* R562 */
-       { 0x0000, 0x0000, 0x0000 }, /* R563 */
-       { 0x0000, 0x0000, 0x0000 }, /* R564 */
-       { 0x0000, 0x0000, 0x0000 }, /* R565 */
-       { 0x0000, 0x0000, 0x0000 }, /* R566 */
-       { 0x0000, 0x0000, 0x0000 }, /* R567 */
-       { 0x0000, 0x0000, 0x0000 }, /* R568 */
-       { 0x0000, 0x0000, 0x0000 }, /* R569 */
-       { 0x0000, 0x0000, 0x0000 }, /* R570 */
-       { 0x0000, 0x0000, 0x0000 }, /* R571 */
-       { 0x0000, 0x0000, 0x0000 }, /* R572 */
-       { 0x0000, 0x0000, 0x0000 }, /* R573 */
-       { 0x0000, 0x0000, 0x0000 }, /* R574 */
-       { 0x0000, 0x0000, 0x0000 }, /* R575 */
-       { 0x0007, 0x0007, 0x0000 }, /* R576   - FLL2 Control (1) */
-       { 0x3F77, 0x3F77, 0x0000 }, /* R577   - FLL2 Control (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R578   - FLL2 Control (3) */
-       { 0x7FEF, 0x7FEF, 0x0000 }, /* R579   - FLL2 Control (4) */
-       { 0x1FDB, 0x1FDB, 0x0000 }, /* R580   - FLL2 Control (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R581 */
-       { 0x0000, 0x0000, 0x0000 }, /* R582 */
-       { 0x0000, 0x0000, 0x0000 }, /* R583 */
-       { 0x0000, 0x0000, 0x0000 }, /* R584 */
-       { 0x0000, 0x0000, 0x0000 }, /* R585 */
-       { 0x0000, 0x0000, 0x0000 }, /* R586 */
-       { 0x0000, 0x0000, 0x0000 }, /* R587 */
-       { 0x0000, 0x0000, 0x0000 }, /* R588 */
-       { 0x0000, 0x0000, 0x0000 }, /* R589 */
-       { 0x0000, 0x0000, 0x0000 }, /* R590 */
-       { 0x0000, 0x0000, 0x0000 }, /* R591 */
-       { 0x0000, 0x0000, 0x0000 }, /* R592 */
-       { 0x0000, 0x0000, 0x0000 }, /* R593 */
-       { 0x0000, 0x0000, 0x0000 }, /* R594 */
-       { 0x0000, 0x0000, 0x0000 }, /* R595 */
-       { 0x0000, 0x0000, 0x0000 }, /* R596 */
-       { 0x0000, 0x0000, 0x0000 }, /* R597 */
-       { 0x0000, 0x0000, 0x0000 }, /* R598 */
-       { 0x0000, 0x0000, 0x0000 }, /* R599 */
-       { 0x0000, 0x0000, 0x0000 }, /* R600 */
-       { 0x0000, 0x0000, 0x0000 }, /* R601 */
-       { 0x0000, 0x0000, 0x0000 }, /* R602 */
-       { 0x0000, 0x0000, 0x0000 }, /* R603 */
-       { 0x0000, 0x0000, 0x0000 }, /* R604 */
-       { 0x0000, 0x0000, 0x0000 }, /* R605 */
-       { 0x0000, 0x0000, 0x0000 }, /* R606 */
-       { 0x0000, 0x0000, 0x0000 }, /* R607 */
-       { 0x0000, 0x0000, 0x0000 }, /* R608 */
-       { 0x0000, 0x0000, 0x0000 }, /* R609 */
-       { 0x0000, 0x0000, 0x0000 }, /* R610 */
-       { 0x0000, 0x0000, 0x0000 }, /* R611 */
-       { 0x0000, 0x0000, 0x0000 }, /* R612 */
-       { 0x0000, 0x0000, 0x0000 }, /* R613 */
-       { 0x0000, 0x0000, 0x0000 }, /* R614 */
-       { 0x0000, 0x0000, 0x0000 }, /* R615 */
-       { 0x0000, 0x0000, 0x0000 }, /* R616 */
-       { 0x0000, 0x0000, 0x0000 }, /* R617 */
-       { 0x0000, 0x0000, 0x0000 }, /* R618 */
-       { 0x0000, 0x0000, 0x0000 }, /* R619 */
-       { 0x0000, 0x0000, 0x0000 }, /* R620 */
-       { 0x0000, 0x0000, 0x0000 }, /* R621 */
-       { 0x0000, 0x0000, 0x0000 }, /* R622 */
-       { 0x0000, 0x0000, 0x0000 }, /* R623 */
-       { 0x0000, 0x0000, 0x0000 }, /* R624 */
-       { 0x0000, 0x0000, 0x0000 }, /* R625 */
-       { 0x0000, 0x0000, 0x0000 }, /* R626 */
-       { 0x0000, 0x0000, 0x0000 }, /* R627 */
-       { 0x0000, 0x0000, 0x0000 }, /* R628 */
-       { 0x0000, 0x0000, 0x0000 }, /* R629 */
-       { 0x0000, 0x0000, 0x0000 }, /* R630 */
-       { 0x0000, 0x0000, 0x0000 }, /* R631 */
-       { 0x0000, 0x0000, 0x0000 }, /* R632 */
-       { 0x0000, 0x0000, 0x0000 }, /* R633 */
-       { 0x0000, 0x0000, 0x0000 }, /* R634 */
-       { 0x0000, 0x0000, 0x0000 }, /* R635 */
-       { 0x0000, 0x0000, 0x0000 }, /* R636 */
-       { 0x0000, 0x0000, 0x0000 }, /* R637 */
-       { 0x0000, 0x0000, 0x0000 }, /* R638 */
-       { 0x0000, 0x0000, 0x0000 }, /* R639 */
-       { 0x0000, 0x0000, 0x0000 }, /* R640 */
-       { 0x0000, 0x0000, 0x0000 }, /* R641 */
-       { 0x0000, 0x0000, 0x0000 }, /* R642 */
-       { 0x0000, 0x0000, 0x0000 }, /* R643 */
-       { 0x0000, 0x0000, 0x0000 }, /* R644 */
-       { 0x0000, 0x0000, 0x0000 }, /* R645 */
-       { 0x0000, 0x0000, 0x0000 }, /* R646 */
-       { 0x0000, 0x0000, 0x0000 }, /* R647 */
-       { 0x0000, 0x0000, 0x0000 }, /* R648 */
-       { 0x0000, 0x0000, 0x0000 }, /* R649 */
-       { 0x0000, 0x0000, 0x0000 }, /* R650 */
-       { 0x0000, 0x0000, 0x0000 }, /* R651 */
-       { 0x0000, 0x0000, 0x0000 }, /* R652 */
-       { 0x0000, 0x0000, 0x0000 }, /* R653 */
-       { 0x0000, 0x0000, 0x0000 }, /* R654 */
-       { 0x0000, 0x0000, 0x0000 }, /* R655 */
-       { 0x0000, 0x0000, 0x0000 }, /* R656 */
-       { 0x0000, 0x0000, 0x0000 }, /* R657 */
-       { 0x0000, 0x0000, 0x0000 }, /* R658 */
-       { 0x0000, 0x0000, 0x0000 }, /* R659 */
-       { 0x0000, 0x0000, 0x0000 }, /* R660 */
-       { 0x0000, 0x0000, 0x0000 }, /* R661 */
-       { 0x0000, 0x0000, 0x0000 }, /* R662 */
-       { 0x0000, 0x0000, 0x0000 }, /* R663 */
-       { 0x0000, 0x0000, 0x0000 }, /* R664 */
-       { 0x0000, 0x0000, 0x0000 }, /* R665 */
-       { 0x0000, 0x0000, 0x0000 }, /* R666 */
-       { 0x0000, 0x0000, 0x0000 }, /* R667 */
-       { 0x0000, 0x0000, 0x0000 }, /* R668 */
-       { 0x0000, 0x0000, 0x0000 }, /* R669 */
-       { 0x0000, 0x0000, 0x0000 }, /* R670 */
-       { 0x0000, 0x0000, 0x0000 }, /* R671 */
-       { 0x0000, 0x0000, 0x0000 }, /* R672 */
-       { 0x0000, 0x0000, 0x0000 }, /* R673 */
-       { 0x0000, 0x0000, 0x0000 }, /* R674 */
-       { 0x0000, 0x0000, 0x0000 }, /* R675 */
-       { 0x0000, 0x0000, 0x0000 }, /* R676 */
-       { 0x0000, 0x0000, 0x0000 }, /* R677 */
-       { 0x0000, 0x0000, 0x0000 }, /* R678 */
-       { 0x0000, 0x0000, 0x0000 }, /* R679 */
-       { 0x0000, 0x0000, 0x0000 }, /* R680 */
-       { 0x0000, 0x0000, 0x0000 }, /* R681 */
-       { 0x0000, 0x0000, 0x0000 }, /* R682 */
-       { 0x0000, 0x0000, 0x0000 }, /* R683 */
-       { 0x0000, 0x0000, 0x0000 }, /* R684 */
-       { 0x0000, 0x0000, 0x0000 }, /* R685 */
-       { 0x0000, 0x0000, 0x0000 }, /* R686 */
-       { 0x0000, 0x0000, 0x0000 }, /* R687 */
-       { 0x0000, 0x0000, 0x0000 }, /* R688 */
-       { 0x0000, 0x0000, 0x0000 }, /* R689 */
-       { 0x0000, 0x0000, 0x0000 }, /* R690 */
-       { 0x0000, 0x0000, 0x0000 }, /* R691 */
-       { 0x0000, 0x0000, 0x0000 }, /* R692 */
-       { 0x0000, 0x0000, 0x0000 }, /* R693 */
-       { 0x0000, 0x0000, 0x0000 }, /* R694 */
-       { 0x0000, 0x0000, 0x0000 }, /* R695 */
-       { 0x0000, 0x0000, 0x0000 }, /* R696 */
-       { 0x0000, 0x0000, 0x0000 }, /* R697 */
-       { 0x0000, 0x0000, 0x0000 }, /* R698 */
-       { 0x0000, 0x0000, 0x0000 }, /* R699 */
-       { 0x0000, 0x0000, 0x0000 }, /* R700 */
-       { 0x0000, 0x0000, 0x0000 }, /* R701 */
-       { 0x0000, 0x0000, 0x0000 }, /* R702 */
-       { 0x0000, 0x0000, 0x0000 }, /* R703 */
-       { 0x0000, 0x0000, 0x0000 }, /* R704 */
-       { 0x0000, 0x0000, 0x0000 }, /* R705 */
-       { 0x0000, 0x0000, 0x0000 }, /* R706 */
-       { 0x0000, 0x0000, 0x0000 }, /* R707 */
-       { 0x0000, 0x0000, 0x0000 }, /* R708 */
-       { 0x0000, 0x0000, 0x0000 }, /* R709 */
-       { 0x0000, 0x0000, 0x0000 }, /* R710 */
-       { 0x0000, 0x0000, 0x0000 }, /* R711 */
-       { 0x0000, 0x0000, 0x0000 }, /* R712 */
-       { 0x0000, 0x0000, 0x0000 }, /* R713 */
-       { 0x0000, 0x0000, 0x0000 }, /* R714 */
-       { 0x0000, 0x0000, 0x0000 }, /* R715 */
-       { 0x0000, 0x0000, 0x0000 }, /* R716 */
-       { 0x0000, 0x0000, 0x0000 }, /* R717 */
-       { 0x0000, 0x0000, 0x0000 }, /* R718 */
-       { 0x0000, 0x0000, 0x0000 }, /* R719 */
-       { 0x0000, 0x0000, 0x0000 }, /* R720 */
-       { 0x0000, 0x0000, 0x0000 }, /* R721 */
-       { 0x0000, 0x0000, 0x0000 }, /* R722 */
-       { 0x0000, 0x0000, 0x0000 }, /* R723 */
-       { 0x0000, 0x0000, 0x0000 }, /* R724 */
-       { 0x0000, 0x0000, 0x0000 }, /* R725 */
-       { 0x0000, 0x0000, 0x0000 }, /* R726 */
-       { 0x0000, 0x0000, 0x0000 }, /* R727 */
-       { 0x0000, 0x0000, 0x0000 }, /* R728 */
-       { 0x0000, 0x0000, 0x0000 }, /* R729 */
-       { 0x0000, 0x0000, 0x0000 }, /* R730 */
-       { 0x0000, 0x0000, 0x0000 }, /* R731 */
-       { 0x0000, 0x0000, 0x0000 }, /* R732 */
-       { 0x0000, 0x0000, 0x0000 }, /* R733 */
-       { 0x0000, 0x0000, 0x0000 }, /* R734 */
-       { 0x0000, 0x0000, 0x0000 }, /* R735 */
-       { 0x0000, 0x0000, 0x0000 }, /* R736 */
-       { 0x0000, 0x0000, 0x0000 }, /* R737 */
-       { 0x0000, 0x0000, 0x0000 }, /* R738 */
-       { 0x0000, 0x0000, 0x0000 }, /* R739 */
-       { 0x0000, 0x0000, 0x0000 }, /* R740 */
-       { 0x0000, 0x0000, 0x0000 }, /* R741 */
-       { 0x0000, 0x0000, 0x0000 }, /* R742 */
-       { 0x0000, 0x0000, 0x0000 }, /* R743 */
-       { 0x0000, 0x0000, 0x0000 }, /* R744 */
-       { 0x0000, 0x0000, 0x0000 }, /* R745 */
-       { 0x0000, 0x0000, 0x0000 }, /* R746 */
-       { 0x0000, 0x0000, 0x0000 }, /* R747 */
-       { 0x0000, 0x0000, 0x0000 }, /* R748 */
-       { 0x0000, 0x0000, 0x0000 }, /* R749 */
-       { 0x0000, 0x0000, 0x0000 }, /* R750 */
-       { 0x0000, 0x0000, 0x0000 }, /* R751 */
-       { 0x0000, 0x0000, 0x0000 }, /* R752 */
-       { 0x0000, 0x0000, 0x0000 }, /* R753 */
-       { 0x0000, 0x0000, 0x0000 }, /* R754 */
-       { 0x0000, 0x0000, 0x0000 }, /* R755 */
-       { 0x0000, 0x0000, 0x0000 }, /* R756 */
-       { 0x0000, 0x0000, 0x0000 }, /* R757 */
-       { 0x0000, 0x0000, 0x0000 }, /* R758 */
-       { 0x0000, 0x0000, 0x0000 }, /* R759 */
-       { 0x0000, 0x0000, 0x0000 }, /* R760 */
-       { 0x0000, 0x0000, 0x0000 }, /* R761 */
-       { 0x0000, 0x0000, 0x0000 }, /* R762 */
-       { 0x0000, 0x0000, 0x0000 }, /* R763 */
-       { 0x0000, 0x0000, 0x0000 }, /* R764 */
-       { 0x0000, 0x0000, 0x0000 }, /* R765 */
-       { 0x0000, 0x0000, 0x0000 }, /* R766 */
-       { 0x0000, 0x0000, 0x0000 }, /* R767 */
-       { 0xE1F8, 0xE1F8, 0x0000 }, /* R768   - AIF1 Control (1) */
-       { 0xCD1F, 0xCD1F, 0x0000 }, /* R769   - AIF1 Control (2) */
-       { 0xF000, 0xF000, 0x0000 }, /* R770   - AIF1 Master/Slave */
-       { 0x01F0, 0x01F0, 0x0000 }, /* R771   - AIF1 BCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R772   - AIF1ADC LRCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R773   - AIF1DAC LRCLK */
-       { 0x0003, 0x0003, 0x0000 }, /* R774   - AIF1DAC Data */
-       { 0x0003, 0x0003, 0x0000 }, /* R775   - AIF1ADC Data */
-       { 0x0000, 0x0000, 0x0000 }, /* R776 */
-       { 0x0000, 0x0000, 0x0000 }, /* R777 */
-       { 0x0000, 0x0000, 0x0000 }, /* R778 */
-       { 0x0000, 0x0000, 0x0000 }, /* R779 */
-       { 0x0000, 0x0000, 0x0000 }, /* R780 */
-       { 0x0000, 0x0000, 0x0000 }, /* R781 */
-       { 0x0000, 0x0000, 0x0000 }, /* R782 */
-       { 0x0000, 0x0000, 0x0000 }, /* R783 */
-       { 0xF1F8, 0xF1F8, 0x0000 }, /* R784   - AIF2 Control (1) */
-       { 0xFD1F, 0xFD1F, 0x0000 }, /* R785   - AIF2 Control (2) */
-       { 0xF000, 0xF000, 0x0000 }, /* R786   - AIF2 Master/Slave */
-       { 0x01F0, 0x01F0, 0x0000 }, /* R787   - AIF2 BCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R788   - AIF2ADC LRCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R789   - AIF2DAC LRCLK */
-       { 0x0003, 0x0003, 0x0000 }, /* R790   - AIF2DAC Data */
-       { 0x0003, 0x0003, 0x0000 }, /* R791   - AIF2ADC Data */
-       { 0x0000, 0x0000, 0x0000 }, /* R792 */
-       { 0x0000, 0x0000, 0x0000 }, /* R793 */
-       { 0x0000, 0x0000, 0x0000 }, /* R794 */
-       { 0x0000, 0x0000, 0x0000 }, /* R795 */
-       { 0x0000, 0x0000, 0x0000 }, /* R796 */
-       { 0x0000, 0x0000, 0x0000 }, /* R797 */
-       { 0x0000, 0x0000, 0x0000 }, /* R798 */
-       { 0x0000, 0x0000, 0x0000 }, /* R799 */
-       { 0x0000, 0x0000, 0x0000 }, /* R800 */
-       { 0x0000, 0x0000, 0x0000 }, /* R801 */
-       { 0x0000, 0x0000, 0x0000 }, /* R802 */
-       { 0x0000, 0x0000, 0x0000 }, /* R803 */
-       { 0x0000, 0x0000, 0x0000 }, /* R804 */
-       { 0x0000, 0x0000, 0x0000 }, /* R805 */
-       { 0x0000, 0x0000, 0x0000 }, /* R806 */
-       { 0x0000, 0x0000, 0x0000 }, /* R807 */
-       { 0x0000, 0x0000, 0x0000 }, /* R808 */
-       { 0x0000, 0x0000, 0x0000 }, /* R809 */
-       { 0x0000, 0x0000, 0x0000 }, /* R810 */
-       { 0x0000, 0x0000, 0x0000 }, /* R811 */
-       { 0x0000, 0x0000, 0x0000 }, /* R812 */
-       { 0x0000, 0x0000, 0x0000 }, /* R813 */
-       { 0x0000, 0x0000, 0x0000 }, /* R814 */
-       { 0x0000, 0x0000, 0x0000 }, /* R815 */
-       { 0x0000, 0x0000, 0x0000 }, /* R816 */
-       { 0x0000, 0x0000, 0x0000 }, /* R817 */
-       { 0x0000, 0x0000, 0x0000 }, /* R818 */
-       { 0x0000, 0x0000, 0x0000 }, /* R819 */
-       { 0x0000, 0x0000, 0x0000 }, /* R820 */
-       { 0x0000, 0x0000, 0x0000 }, /* R821 */
-       { 0x0000, 0x0000, 0x0000 }, /* R822 */
-       { 0x0000, 0x0000, 0x0000 }, /* R823 */
-       { 0x0000, 0x0000, 0x0000 }, /* R824 */
-       { 0x0000, 0x0000, 0x0000 }, /* R825 */
-       { 0x0000, 0x0000, 0x0000 }, /* R826 */
-       { 0x0000, 0x0000, 0x0000 }, /* R827 */
-       { 0x0000, 0x0000, 0x0000 }, /* R828 */
-       { 0x0000, 0x0000, 0x0000 }, /* R829 */
-       { 0x0000, 0x0000, 0x0000 }, /* R830 */
-       { 0x0000, 0x0000, 0x0000 }, /* R831 */
-       { 0x0000, 0x0000, 0x0000 }, /* R832 */
-       { 0x0000, 0x0000, 0x0000 }, /* R833 */
-       { 0x0000, 0x0000, 0x0000 }, /* R834 */
-       { 0x0000, 0x0000, 0x0000 }, /* R835 */
-       { 0x0000, 0x0000, 0x0000 }, /* R836 */
-       { 0x0000, 0x0000, 0x0000 }, /* R837 */
-       { 0x0000, 0x0000, 0x0000 }, /* R838 */
-       { 0x0000, 0x0000, 0x0000 }, /* R839 */
-       { 0x0000, 0x0000, 0x0000 }, /* R840 */
-       { 0x0000, 0x0000, 0x0000 }, /* R841 */
-       { 0x0000, 0x0000, 0x0000 }, /* R842 */
-       { 0x0000, 0x0000, 0x0000 }, /* R843 */
-       { 0x0000, 0x0000, 0x0000 }, /* R844 */
-       { 0x0000, 0x0000, 0x0000 }, /* R845 */
-       { 0x0000, 0x0000, 0x0000 }, /* R846 */
-       { 0x0000, 0x0000, 0x0000 }, /* R847 */
-       { 0x0000, 0x0000, 0x0000 }, /* R848 */
-       { 0x0000, 0x0000, 0x0000 }, /* R849 */
-       { 0x0000, 0x0000, 0x0000 }, /* R850 */
-       { 0x0000, 0x0000, 0x0000 }, /* R851 */
-       { 0x0000, 0x0000, 0x0000 }, /* R852 */
-       { 0x0000, 0x0000, 0x0000 }, /* R853 */
-       { 0x0000, 0x0000, 0x0000 }, /* R854 */
-       { 0x0000, 0x0000, 0x0000 }, /* R855 */
-       { 0x0000, 0x0000, 0x0000 }, /* R856 */
-       { 0x0000, 0x0000, 0x0000 }, /* R857 */
-       { 0x0000, 0x0000, 0x0000 }, /* R858 */
-       { 0x0000, 0x0000, 0x0000 }, /* R859 */
-       { 0x0000, 0x0000, 0x0000 }, /* R860 */
-       { 0x0000, 0x0000, 0x0000 }, /* R861 */
-       { 0x0000, 0x0000, 0x0000 }, /* R862 */
-       { 0x0000, 0x0000, 0x0000 }, /* R863 */
-       { 0x0000, 0x0000, 0x0000 }, /* R864 */
-       { 0x0000, 0x0000, 0x0000 }, /* R865 */
-       { 0x0000, 0x0000, 0x0000 }, /* R866 */
-       { 0x0000, 0x0000, 0x0000 }, /* R867 */
-       { 0x0000, 0x0000, 0x0000 }, /* R868 */
-       { 0x0000, 0x0000, 0x0000 }, /* R869 */
-       { 0x0000, 0x0000, 0x0000 }, /* R870 */
-       { 0x0000, 0x0000, 0x0000 }, /* R871 */
-       { 0x0000, 0x0000, 0x0000 }, /* R872 */
-       { 0x0000, 0x0000, 0x0000 }, /* R873 */
-       { 0x0000, 0x0000, 0x0000 }, /* R874 */
-       { 0x0000, 0x0000, 0x0000 }, /* R875 */
-       { 0x0000, 0x0000, 0x0000 }, /* R876 */
-       { 0x0000, 0x0000, 0x0000 }, /* R877 */
-       { 0x0000, 0x0000, 0x0000 }, /* R878 */
-       { 0x0000, 0x0000, 0x0000 }, /* R879 */
-       { 0x0000, 0x0000, 0x0000 }, /* R880 */
-       { 0x0000, 0x0000, 0x0000 }, /* R881 */
-       { 0x0000, 0x0000, 0x0000 }, /* R882 */
-       { 0x0000, 0x0000, 0x0000 }, /* R883 */
-       { 0x0000, 0x0000, 0x0000 }, /* R884 */
-       { 0x0000, 0x0000, 0x0000 }, /* R885 */
-       { 0x0000, 0x0000, 0x0000 }, /* R886 */
-       { 0x0000, 0x0000, 0x0000 }, /* R887 */
-       { 0x0000, 0x0000, 0x0000 }, /* R888 */
-       { 0x0000, 0x0000, 0x0000 }, /* R889 */
-       { 0x0000, 0x0000, 0x0000 }, /* R890 */
-       { 0x0000, 0x0000, 0x0000 }, /* R891 */
-       { 0x0000, 0x0000, 0x0000 }, /* R892 */
-       { 0x0000, 0x0000, 0x0000 }, /* R893 */
-       { 0x0000, 0x0000, 0x0000 }, /* R894 */
-       { 0x0000, 0x0000, 0x0000 }, /* R895 */
-       { 0x0000, 0x0000, 0x0000 }, /* R896 */
-       { 0x0000, 0x0000, 0x0000 }, /* R897 */
-       { 0x0000, 0x0000, 0x0000 }, /* R898 */
-       { 0x0000, 0x0000, 0x0000 }, /* R899 */
-       { 0x0000, 0x0000, 0x0000 }, /* R900 */
-       { 0x0000, 0x0000, 0x0000 }, /* R901 */
-       { 0x0000, 0x0000, 0x0000 }, /* R902 */
-       { 0x0000, 0x0000, 0x0000 }, /* R903 */
-       { 0x0000, 0x0000, 0x0000 }, /* R904 */
-       { 0x0000, 0x0000, 0x0000 }, /* R905 */
-       { 0x0000, 0x0000, 0x0000 }, /* R906 */
-       { 0x0000, 0x0000, 0x0000 }, /* R907 */
-       { 0x0000, 0x0000, 0x0000 }, /* R908 */
-       { 0x0000, 0x0000, 0x0000 }, /* R909 */
-       { 0x0000, 0x0000, 0x0000 }, /* R910 */
-       { 0x0000, 0x0000, 0x0000 }, /* R911 */
-       { 0x0000, 0x0000, 0x0000 }, /* R912 */
-       { 0x0000, 0x0000, 0x0000 }, /* R913 */
-       { 0x0000, 0x0000, 0x0000 }, /* R914 */
-       { 0x0000, 0x0000, 0x0000 }, /* R915 */
-       { 0x0000, 0x0000, 0x0000 }, /* R916 */
-       { 0x0000, 0x0000, 0x0000 }, /* R917 */
-       { 0x0000, 0x0000, 0x0000 }, /* R918 */
-       { 0x0000, 0x0000, 0x0000 }, /* R919 */
-       { 0x0000, 0x0000, 0x0000 }, /* R920 */
-       { 0x0000, 0x0000, 0x0000 }, /* R921 */
-       { 0x0000, 0x0000, 0x0000 }, /* R922 */
-       { 0x0000, 0x0000, 0x0000 }, /* R923 */
-       { 0x0000, 0x0000, 0x0000 }, /* R924 */
-       { 0x0000, 0x0000, 0x0000 }, /* R925 */
-       { 0x0000, 0x0000, 0x0000 }, /* R926 */
-       { 0x0000, 0x0000, 0x0000 }, /* R927 */
-       { 0x0000, 0x0000, 0x0000 }, /* R928 */
-       { 0x0000, 0x0000, 0x0000 }, /* R929 */
-       { 0x0000, 0x0000, 0x0000 }, /* R930 */
-       { 0x0000, 0x0000, 0x0000 }, /* R931 */
-       { 0x0000, 0x0000, 0x0000 }, /* R932 */
-       { 0x0000, 0x0000, 0x0000 }, /* R933 */
-       { 0x0000, 0x0000, 0x0000 }, /* R934 */
-       { 0x0000, 0x0000, 0x0000 }, /* R935 */
-       { 0x0000, 0x0000, 0x0000 }, /* R936 */
-       { 0x0000, 0x0000, 0x0000 }, /* R937 */
-       { 0x0000, 0x0000, 0x0000 }, /* R938 */
-       { 0x0000, 0x0000, 0x0000 }, /* R939 */
-       { 0x0000, 0x0000, 0x0000 }, /* R940 */
-       { 0x0000, 0x0000, 0x0000 }, /* R941 */
-       { 0x0000, 0x0000, 0x0000 }, /* R942 */
-       { 0x0000, 0x0000, 0x0000 }, /* R943 */
-       { 0x0000, 0x0000, 0x0000 }, /* R944 */
-       { 0x0000, 0x0000, 0x0000 }, /* R945 */
-       { 0x0000, 0x0000, 0x0000 }, /* R946 */
-       { 0x0000, 0x0000, 0x0000 }, /* R947 */
-       { 0x0000, 0x0000, 0x0000 }, /* R948 */
-       { 0x0000, 0x0000, 0x0000 }, /* R949 */
-       { 0x0000, 0x0000, 0x0000 }, /* R950 */
-       { 0x0000, 0x0000, 0x0000 }, /* R951 */
-       { 0x0000, 0x0000, 0x0000 }, /* R952 */
-       { 0x0000, 0x0000, 0x0000 }, /* R953 */
-       { 0x0000, 0x0000, 0x0000 }, /* R954 */
-       { 0x0000, 0x0000, 0x0000 }, /* R955 */
-       { 0x0000, 0x0000, 0x0000 }, /* R956 */
-       { 0x0000, 0x0000, 0x0000 }, /* R957 */
-       { 0x0000, 0x0000, 0x0000 }, /* R958 */
-       { 0x0000, 0x0000, 0x0000 }, /* R959 */
-       { 0x0000, 0x0000, 0x0000 }, /* R960 */
-       { 0x0000, 0x0000, 0x0000 }, /* R961 */
-       { 0x0000, 0x0000, 0x0000 }, /* R962 */
-       { 0x0000, 0x0000, 0x0000 }, /* R963 */
-       { 0x0000, 0x0000, 0x0000 }, /* R964 */
-       { 0x0000, 0x0000, 0x0000 }, /* R965 */
-       { 0x0000, 0x0000, 0x0000 }, /* R966 */
-       { 0x0000, 0x0000, 0x0000 }, /* R967 */
-       { 0x0000, 0x0000, 0x0000 }, /* R968 */
-       { 0x0000, 0x0000, 0x0000 }, /* R969 */
-       { 0x0000, 0x0000, 0x0000 }, /* R970 */
-       { 0x0000, 0x0000, 0x0000 }, /* R971 */
-       { 0x0000, 0x0000, 0x0000 }, /* R972 */
-       { 0x0000, 0x0000, 0x0000 }, /* R973 */
-       { 0x0000, 0x0000, 0x0000 }, /* R974 */
-       { 0x0000, 0x0000, 0x0000 }, /* R975 */
-       { 0x0000, 0x0000, 0x0000 }, /* R976 */
-       { 0x0000, 0x0000, 0x0000 }, /* R977 */
-       { 0x0000, 0x0000, 0x0000 }, /* R978 */
-       { 0x0000, 0x0000, 0x0000 }, /* R979 */
-       { 0x0000, 0x0000, 0x0000 }, /* R980 */
-       { 0x0000, 0x0000, 0x0000 }, /* R981 */
-       { 0x0000, 0x0000, 0x0000 }, /* R982 */
-       { 0x0000, 0x0000, 0x0000 }, /* R983 */
-       { 0x0000, 0x0000, 0x0000 }, /* R984 */
-       { 0x0000, 0x0000, 0x0000 }, /* R985 */
-       { 0x0000, 0x0000, 0x0000 }, /* R986 */
-       { 0x0000, 0x0000, 0x0000 }, /* R987 */
-       { 0x0000, 0x0000, 0x0000 }, /* R988 */
-       { 0x0000, 0x0000, 0x0000 }, /* R989 */
-       { 0x0000, 0x0000, 0x0000 }, /* R990 */
-       { 0x0000, 0x0000, 0x0000 }, /* R991 */
-       { 0x0000, 0x0000, 0x0000 }, /* R992 */
-       { 0x0000, 0x0000, 0x0000 }, /* R993 */
-       { 0x0000, 0x0000, 0x0000 }, /* R994 */
-       { 0x0000, 0x0000, 0x0000 }, /* R995 */
-       { 0x0000, 0x0000, 0x0000 }, /* R996 */
-       { 0x0000, 0x0000, 0x0000 }, /* R997 */
-       { 0x0000, 0x0000, 0x0000 }, /* R998 */
-       { 0x0000, 0x0000, 0x0000 }, /* R999 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1000 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1001 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1002 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1003 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1004 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1005 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1006 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1007 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1008 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1009 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1010 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1011 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1012 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1013 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1014 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1015 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1016 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1017 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1018 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1019 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1020 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1021 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1022 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1023 */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1024  - AIF1 ADC1 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1025  - AIF1 ADC1 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1026  - AIF1 DAC1 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1027  - AIF1 DAC1 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1028  - AIF1 ADC2 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1029  - AIF1 ADC2 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1030  - AIF1 DAC2 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1031  - AIF1 DAC2 Right Volume */
-       { 0x0000, 0x0000, 0x0000 }, /* R1032 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1033 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1034 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1035 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1036 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1037 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1038 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1039 */
-       { 0xF800, 0xF800, 0x0000 }, /* R1040  - AIF1 ADC1 Filters */
-       { 0x7800, 0x7800, 0x0000 }, /* R1041  - AIF1 ADC2 Filters */
-       { 0x0000, 0x0000, 0x0000 }, /* R1042 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1043 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1044 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1045 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1046 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1047 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1048 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1049 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1050 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1051 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1052 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1053 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1054 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1055 */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1056  - AIF1 DAC1 Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1057  - AIF1 DAC1 Filters (2) */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1058  - AIF1 DAC2 Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1059  - AIF1 DAC2 Filters (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1060 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1061 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1062 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1063 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1064 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1065 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1066 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1067 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1068 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1069 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1070 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1071 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1072 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1073 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1074 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1075 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1076 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1077 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1078 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1079 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1080 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1081 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1082 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1083 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1084 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1085 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1086 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1087 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088  - AIF1 DRC1 (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089  - AIF1 DRC1 (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090  - AIF1 DRC1 (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1091  - AIF1 DRC1 (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1092  - AIF1 DRC1 (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1093 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1094 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1095 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1096 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1097 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1098 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1099 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1100 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1101 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1102 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1103 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104  - AIF1 DRC2 (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105  - AIF1 DRC2 (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106  - AIF1 DRC2 (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1107  - AIF1 DRC2 (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1108  - AIF1 DRC2 (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1109 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1110 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1111 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1112 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1113 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1114 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1115 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1116 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1117 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1118 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1119 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1120 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1121 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1122 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1123 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1124 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1125 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1126 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1127 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1128 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1129 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1130 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1131 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1132 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1133 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1134 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1135 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1136 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1137 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1138 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1139 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1140 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1141 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1142 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1143 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1144 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1145 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1146 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1147 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1148 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1149 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1150 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1151 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1172 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1173 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1174 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1175 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1176 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1177 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1178 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1179 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1180 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1181 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1182 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1183 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1204 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1205 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1206 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1207 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1208 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1209 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1210 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1211 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1212 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1213 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1214 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1215 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1216 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1217 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1218 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1219 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1220 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1221 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1222 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1223 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1224 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1225 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1226 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1227 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1228 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1229 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1230 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1231 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1232 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1233 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1234 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1235 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1236 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1237 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1238 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1239 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1240 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1241 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1242 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1243 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1244 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1245 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1246 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1247 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1248 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1249 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1250 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1251 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1252 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1253 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1254 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1255 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1256 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1257 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1258 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1259 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1260 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1261 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1262 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1263 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1264 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1265 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1266 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1267 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1268 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1269 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1270 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1271 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1272 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1273 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1274 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1275 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1276 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1277 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1278 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1279 */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1280  - AIF2 ADC Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1281  - AIF2 ADC Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1282  - AIF2 DAC Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1283  - AIF2 DAC Right Volume */
-       { 0x0000, 0x0000, 0x0000 }, /* R1284 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1285 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1286 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1287 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1288 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1289 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1290 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1291 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1292 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1293 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1294 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1295 */
-       { 0xF800, 0xF800, 0x0000 }, /* R1296  - AIF2 ADC Filters */
-       { 0x0000, 0x0000, 0x0000 }, /* R1297 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1298 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1299 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1300 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1301 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1302 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1303 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1304 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1305 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1306 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1307 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1308 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1309 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1310 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1311 */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1312  - AIF2 DAC Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1313  - AIF2 DAC Filters (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1314 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1315 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1316 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1317 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1318 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1319 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1320 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1321 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1322 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1323 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1324 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1325 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1326 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1327 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1328 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1329 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1330 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1331 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1332 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1333 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1334 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1335 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1336 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1337 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1338 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1339 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1340 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1341 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1342 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1343 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344  - AIF2 DRC (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345  - AIF2 DRC (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346  - AIF2 DRC (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1347  - AIF2 DRC (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1348  - AIF2 DRC (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1349 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1350 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1351 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1352 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1353 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1354 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1355 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1356 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1357 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1358 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1359 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1360 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1361 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1362 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1363 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1364 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1365 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1366 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1367 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1368 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1369 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1370 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1371 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1372 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1373 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1374 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1375 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1376 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1377 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1378 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1379 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1380 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1381 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1382 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1383 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1384 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1385 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1386 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1387 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1388 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1389 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1390 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1391 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1392 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1393 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1394 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1395 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1396 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1397 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1398 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1399 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1400 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1401 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1402 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1403 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1404 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1405 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1406 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1407 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408  - AIF2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409  - AIF2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410  - AIF2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411  - AIF2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412  - AIF2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413  - AIF2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414  - AIF2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415  - AIF2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416  - AIF2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417  - AIF2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418  - AIF2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419  - AIF2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420  - AIF2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421  - AIF2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422  - AIF2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423  - AIF2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424  - AIF2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425  - AIF2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426  - AIF2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427  - AIF2 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1428 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1429 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1430 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1431 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1432 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1433 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1434 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1435 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1436 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1437 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1438 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1439 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1440 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1441 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1442 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1443 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1444 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1445 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1446 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1447 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1448 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1449 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1450 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1451 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1452 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1453 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1454 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1455 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1456 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1457 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1458 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1459 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1460 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1461 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1462 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1463 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1464 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1465 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1466 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1467 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1468 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1469 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1470 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1471 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1472 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1473 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1474 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1475 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1476 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1477 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1478 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1479 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1480 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1481 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1482 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1483 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1484 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1485 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1486 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1487 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1488 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1489 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1490 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1491 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1492 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1493 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1494 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1495 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1496 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1497 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1498 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1499 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1500 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1501 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1502 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1503 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1504 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1505 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1506 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1507 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1508 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1509 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1510 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1511 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1512 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1513 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1514 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1515 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1516 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1517 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1518 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1519 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1520 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1521 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1522 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1523 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1524 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1525 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1526 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1527 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1528 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1529 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1530 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1531 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1532 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1533 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1534 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1535 */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R1536  - DAC1 Mixer Volumes */
-       { 0x0037, 0x0037, 0x0000 }, /* R1537  - DAC1 Left Mixer Routing */
-       { 0x0037, 0x0037, 0x0000 }, /* R1538  - DAC1 Right Mixer Routing */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R1539  - DAC2 Mixer Volumes */
-       { 0x0037, 0x0037, 0x0000 }, /* R1540  - DAC2 Left Mixer Routing */
-       { 0x0037, 0x0037, 0x0000 }, /* R1541  - DAC2 Right Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
-       { 0x0000, 0x0000, 0x0000 }, /* R1546 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1547 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1548 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1549 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1550 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1551 */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1552  - DAC1 Left Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1553  - DAC1 Right Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1554  - DAC2 Left Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1555  - DAC2 Right Volume */
-       { 0x0003, 0x0003, 0x0000 }, /* R1556  - DAC Softmute */
-       { 0x0000, 0x0000, 0x0000 }, /* R1557 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1558 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1559 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1560 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1561 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1562 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1563 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1564 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1565 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1566 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1567 */
-       { 0x0003, 0x0003, 0x0000 }, /* R1568  - Oversampling */
-       { 0x03C3, 0x03C3, 0x0000 }, /* R1569  - Sidetone */
+       { 0xFFFF, 0xFFFF }, /* R0     - Software Reset */
+       { 0x3B37, 0x3B37 }, /* R1     - Power Management (1) */
+       { 0x6BF0, 0x6BF0 }, /* R2     - Power Management (2) */
+       { 0x3FF0, 0x3FF0 }, /* R3     - Power Management (3) */
+       { 0x3F3F, 0x3F3F }, /* R4     - Power Management (4) */
+       { 0x3F0F, 0x3F0F }, /* R5     - Power Management (5) */
+       { 0x003F, 0x003F }, /* R6     - Power Management (6) */
+       { 0x0000, 0x0000 }, /* R7 */
+       { 0x0000, 0x0000 }, /* R8 */
+       { 0x0000, 0x0000 }, /* R9 */
+       { 0x0000, 0x0000 }, /* R10 */
+       { 0x0000, 0x0000 }, /* R11 */
+       { 0x0000, 0x0000 }, /* R12 */
+       { 0x0000, 0x0000 }, /* R13 */
+       { 0x0000, 0x0000 }, /* R14 */
+       { 0x0000, 0x0000 }, /* R15 */
+       { 0x0000, 0x0000 }, /* R16 */
+       { 0x0000, 0x0000 }, /* R17 */
+       { 0x0000, 0x0000 }, /* R18 */
+       { 0x0000, 0x0000 }, /* R19 */
+       { 0x0000, 0x0000 }, /* R20 */
+       { 0x01C0, 0x01C0 }, /* R21    - Input Mixer (1) */
+       { 0x0000, 0x0000 }, /* R22 */
+       { 0x0000, 0x0000 }, /* R23 */
+       { 0x00DF, 0x01DF }, /* R24    - Left Line Input 1&2 Volume */
+       { 0x00DF, 0x01DF }, /* R25    - Left Line Input 3&4 Volume */
+       { 0x00DF, 0x01DF }, /* R26    - Right Line Input 1&2 Volume */
+       { 0x00DF, 0x01DF }, /* R27    - Right Line Input 3&4 Volume */
+       { 0x00FF, 0x01FF }, /* R28    - Left Output Volume */
+       { 0x00FF, 0x01FF }, /* R29    - Right Output Volume */
+       { 0x0077, 0x0077 }, /* R30    - Line Outputs Volume */
+       { 0x0030, 0x0030 }, /* R31    - HPOUT2 Volume */
+       { 0x00FF, 0x01FF }, /* R32    - Left OPGA Volume */
+       { 0x00FF, 0x01FF }, /* R33    - Right OPGA Volume */
+       { 0x007F, 0x007F }, /* R34    - SPKMIXL Attenuation */
+       { 0x017F, 0x017F }, /* R35    - SPKMIXR Attenuation */
+       { 0x003F, 0x003F }, /* R36    - SPKOUT Mixers */
+       { 0x003F, 0x003F }, /* R37    - ClassD */
+       { 0x00FF, 0x01FF }, /* R38    - Speaker Volume Left */
+       { 0x00FF, 0x01FF }, /* R39    - Speaker Volume Right */
+       { 0x00FF, 0x00FF }, /* R40    - Input Mixer (2) */
+       { 0x01B7, 0x01B7 }, /* R41    - Input Mixer (3) */
+       { 0x01B7, 0x01B7 }, /* R42    - Input Mixer (4) */
+       { 0x01C7, 0x01C7 }, /* R43    - Input Mixer (5) */
+       { 0x01C7, 0x01C7 }, /* R44    - Input Mixer (6) */
+       { 0x01FF, 0x01FF }, /* R45    - Output Mixer (1) */
+       { 0x01FF, 0x01FF }, /* R46    - Output Mixer (2) */
+       { 0x0FFF, 0x0FFF }, /* R47    - Output Mixer (3) */
+       { 0x0FFF, 0x0FFF }, /* R48    - Output Mixer (4) */
+       { 0x0FFF, 0x0FFF }, /* R49    - Output Mixer (5) */
+       { 0x0FFF, 0x0FFF }, /* R50    - Output Mixer (6) */
+       { 0x0038, 0x0038 }, /* R51    - HPOUT2 Mixer */
+       { 0x0077, 0x0077 }, /* R52    - Line Mixer (1) */
+       { 0x0077, 0x0077 }, /* R53    - Line Mixer (2) */
+       { 0x03FF, 0x03FF }, /* R54    - Speaker Mixer */
+       { 0x00C1, 0x00C1 }, /* R55    - Additional Control */
+       { 0x00F0, 0x00F0 }, /* R56    - AntiPOP (1) */
+       { 0x01EF, 0x01EF }, /* R57    - AntiPOP (2) */
+       { 0x00FF, 0x00FF }, /* R58    - MICBIAS */
+       { 0x000F, 0x000F }, /* R59    - LDO 1 */
+       { 0x0007, 0x0007 }, /* R60    - LDO 2 */
+       { 0x0000, 0x0000 }, /* R61 */
+       { 0x0000, 0x0000 }, /* R62 */
+       { 0x0000, 0x0000 }, /* R63 */
+       { 0x0000, 0x0000 }, /* R64 */
+       { 0x0000, 0x0000 }, /* R65 */
+       { 0x0000, 0x0000 }, /* R66 */
+       { 0x0000, 0x0000 }, /* R67 */
+       { 0x0000, 0x0000 }, /* R68 */
+       { 0x0000, 0x0000 }, /* R69 */
+       { 0x0000, 0x0000 }, /* R70 */
+       { 0x0000, 0x0000 }, /* R71 */
+       { 0x0000, 0x0000 }, /* R72 */
+       { 0x0000, 0x0000 }, /* R73 */
+       { 0x0000, 0x0000 }, /* R74 */
+       { 0x0000, 0x0000 }, /* R75 */
+       { 0x8000, 0x8000 }, /* R76    - Charge Pump (1) */
+       { 0x0000, 0x0000 }, /* R77 */
+       { 0x0000, 0x0000 }, /* R78 */
+       { 0x0000, 0x0000 }, /* R79 */
+       { 0x0000, 0x0000 }, /* R80 */
+       { 0x0301, 0x0301 }, /* R81    - Class W (1) */
+       { 0x0000, 0x0000 }, /* R82 */
+       { 0x0000, 0x0000 }, /* R83 */
+       { 0x333F, 0x333F }, /* R84    - DC Servo (1) */
+       { 0x0FEF, 0x0FEF }, /* R85    - DC Servo (2) */
+       { 0x0000, 0x0000 }, /* R86 */
+       { 0xFFFF, 0xFFFF }, /* R87    - DC Servo (4) */
+       { 0x0333, 0x0000 }, /* R88    - DC Servo Readback */
+       { 0x0000, 0x0000 }, /* R89 */
+       { 0x0000, 0x0000 }, /* R90 */
+       { 0x0000, 0x0000 }, /* R91 */
+       { 0x0000, 0x0000 }, /* R92 */
+       { 0x0000, 0x0000 }, /* R93 */
+       { 0x0000, 0x0000 }, /* R94 */
+       { 0x0000, 0x0000 }, /* R95 */
+       { 0x00EE, 0x00EE }, /* R96    - Analogue HP (1) */
+       { 0x0000, 0x0000 }, /* R97 */
+       { 0x0000, 0x0000 }, /* R98 */
+       { 0x0000, 0x0000 }, /* R99 */
+       { 0x0000, 0x0000 }, /* R100 */
+       { 0x0000, 0x0000 }, /* R101 */
+       { 0x0000, 0x0000 }, /* R102 */
+       { 0x0000, 0x0000 }, /* R103 */
+       { 0x0000, 0x0000 }, /* R104 */
+       { 0x0000, 0x0000 }, /* R105 */
+       { 0x0000, 0x0000 }, /* R106 */
+       { 0x0000, 0x0000 }, /* R107 */
+       { 0x0000, 0x0000 }, /* R108 */
+       { 0x0000, 0x0000 }, /* R109 */
+       { 0x0000, 0x0000 }, /* R110 */
+       { 0x0000, 0x0000 }, /* R111 */
+       { 0x0000, 0x0000 }, /* R112 */
+       { 0x0000, 0x0000 }, /* R113 */
+       { 0x0000, 0x0000 }, /* R114 */
+       { 0x0000, 0x0000 }, /* R115 */
+       { 0x0000, 0x0000 }, /* R116 */
+       { 0x0000, 0x0000 }, /* R117 */
+       { 0x0000, 0x0000 }, /* R118 */
+       { 0x0000, 0x0000 }, /* R119 */
+       { 0x0000, 0x0000 }, /* R120 */
+       { 0x0000, 0x0000 }, /* R121 */
+       { 0x0000, 0x0000 }, /* R122 */
+       { 0x0000, 0x0000 }, /* R123 */
+       { 0x0000, 0x0000 }, /* R124 */
+       { 0x0000, 0x0000 }, /* R125 */
+       { 0x0000, 0x0000 }, /* R126 */
+       { 0x0000, 0x0000 }, /* R127 */
+       { 0x0000, 0x0000 }, /* R128 */
+       { 0x0000, 0x0000 }, /* R129 */
+       { 0x0000, 0x0000 }, /* R130 */
+       { 0x0000, 0x0000 }, /* R131 */
+       { 0x0000, 0x0000 }, /* R132 */
+       { 0x0000, 0x0000 }, /* R133 */
+       { 0x0000, 0x0000 }, /* R134 */
+       { 0x0000, 0x0000 }, /* R135 */
+       { 0x0000, 0x0000 }, /* R136 */
+       { 0x0000, 0x0000 }, /* R137 */
+       { 0x0000, 0x0000 }, /* R138 */
+       { 0x0000, 0x0000 }, /* R139 */
+       { 0x0000, 0x0000 }, /* R140 */
+       { 0x0000, 0x0000 }, /* R141 */
+       { 0x0000, 0x0000 }, /* R142 */
+       { 0x0000, 0x0000 }, /* R143 */
+       { 0x0000, 0x0000 }, /* R144 */
+       { 0x0000, 0x0000 }, /* R145 */
+       { 0x0000, 0x0000 }, /* R146 */
+       { 0x0000, 0x0000 }, /* R147 */
+       { 0x0000, 0x0000 }, /* R148 */
+       { 0x0000, 0x0000 }, /* R149 */
+       { 0x0000, 0x0000 }, /* R150 */
+       { 0x0000, 0x0000 }, /* R151 */
+       { 0x0000, 0x0000 }, /* R152 */
+       { 0x0000, 0x0000 }, /* R153 */
+       { 0x0000, 0x0000 }, /* R154 */
+       { 0x0000, 0x0000 }, /* R155 */
+       { 0x0000, 0x0000 }, /* R156 */
+       { 0x0000, 0x0000 }, /* R157 */
+       { 0x0000, 0x0000 }, /* R158 */
+       { 0x0000, 0x0000 }, /* R159 */
+       { 0x0000, 0x0000 }, /* R160 */
+       { 0x0000, 0x0000 }, /* R161 */
+       { 0x0000, 0x0000 }, /* R162 */
+       { 0x0000, 0x0000 }, /* R163 */
+       { 0x0000, 0x0000 }, /* R164 */
+       { 0x0000, 0x0000 }, /* R165 */
+       { 0x0000, 0x0000 }, /* R166 */
+       { 0x0000, 0x0000 }, /* R167 */
+       { 0x0000, 0x0000 }, /* R168 */
+       { 0x0000, 0x0000 }, /* R169 */
+       { 0x0000, 0x0000 }, /* R170 */
+       { 0x0000, 0x0000 }, /* R171 */
+       { 0x0000, 0x0000 }, /* R172 */
+       { 0x0000, 0x0000 }, /* R173 */
+       { 0x0000, 0x0000 }, /* R174 */
+       { 0x0000, 0x0000 }, /* R175 */
+       { 0x0000, 0x0000 }, /* R176 */
+       { 0x0000, 0x0000 }, /* R177 */
+       { 0x0000, 0x0000 }, /* R178 */
+       { 0x0000, 0x0000 }, /* R179 */
+       { 0x0000, 0x0000 }, /* R180 */
+       { 0x0000, 0x0000 }, /* R181 */
+       { 0x0000, 0x0000 }, /* R182 */
+       { 0x0000, 0x0000 }, /* R183 */
+       { 0x0000, 0x0000 }, /* R184 */
+       { 0x0000, 0x0000 }, /* R185 */
+       { 0x0000, 0x0000 }, /* R186 */
+       { 0x0000, 0x0000 }, /* R187 */
+       { 0x0000, 0x0000 }, /* R188 */
+       { 0x0000, 0x0000 }, /* R189 */
+       { 0x0000, 0x0000 }, /* R190 */
+       { 0x0000, 0x0000 }, /* R191 */
+       { 0x0000, 0x0000 }, /* R192 */
+       { 0x0000, 0x0000 }, /* R193 */
+       { 0x0000, 0x0000 }, /* R194 */
+       { 0x0000, 0x0000 }, /* R195 */
+       { 0x0000, 0x0000 }, /* R196 */
+       { 0x0000, 0x0000 }, /* R197 */
+       { 0x0000, 0x0000 }, /* R198 */
+       { 0x0000, 0x0000 }, /* R199 */
+       { 0x0000, 0x0000 }, /* R200 */
+       { 0x0000, 0x0000 }, /* R201 */
+       { 0x0000, 0x0000 }, /* R202 */
+       { 0x0000, 0x0000 }, /* R203 */
+       { 0x0000, 0x0000 }, /* R204 */
+       { 0x0000, 0x0000 }, /* R205 */
+       { 0x0000, 0x0000 }, /* R206 */
+       { 0x0000, 0x0000 }, /* R207 */
+       { 0x0000, 0x0000 }, /* R208 */
+       { 0x0000, 0x0000 }, /* R209 */
+       { 0x0000, 0x0000 }, /* R210 */
+       { 0x0000, 0x0000 }, /* R211 */
+       { 0x0000, 0x0000 }, /* R212 */
+       { 0x0000, 0x0000 }, /* R213 */
+       { 0x0000, 0x0000 }, /* R214 */
+       { 0x0000, 0x0000 }, /* R215 */
+       { 0x0000, 0x0000 }, /* R216 */
+       { 0x0000, 0x0000 }, /* R217 */
+       { 0x0000, 0x0000 }, /* R218 */
+       { 0x0000, 0x0000 }, /* R219 */
+       { 0x0000, 0x0000 }, /* R220 */
+       { 0x0000, 0x0000 }, /* R221 */
+       { 0x0000, 0x0000 }, /* R222 */
+       { 0x0000, 0x0000 }, /* R223 */
+       { 0x0000, 0x0000 }, /* R224 */
+       { 0x0000, 0x0000 }, /* R225 */
+       { 0x0000, 0x0000 }, /* R226 */
+       { 0x0000, 0x0000 }, /* R227 */
+       { 0x0000, 0x0000 }, /* R228 */
+       { 0x0000, 0x0000 }, /* R229 */
+       { 0x0000, 0x0000 }, /* R230 */
+       { 0x0000, 0x0000 }, /* R231 */
+       { 0x0000, 0x0000 }, /* R232 */
+       { 0x0000, 0x0000 }, /* R233 */
+       { 0x0000, 0x0000 }, /* R234 */
+       { 0x0000, 0x0000 }, /* R235 */
+       { 0x0000, 0x0000 }, /* R236 */
+       { 0x0000, 0x0000 }, /* R237 */
+       { 0x0000, 0x0000 }, /* R238 */
+       { 0x0000, 0x0000 }, /* R239 */
+       { 0x0000, 0x0000 }, /* R240 */
+       { 0x0000, 0x0000 }, /* R241 */
+       { 0x0000, 0x0000 }, /* R242 */
+       { 0x0000, 0x0000 }, /* R243 */
+       { 0x0000, 0x0000 }, /* R244 */
+       { 0x0000, 0x0000 }, /* R245 */
+       { 0x0000, 0x0000 }, /* R246 */
+       { 0x0000, 0x0000 }, /* R247 */
+       { 0x0000, 0x0000 }, /* R248 */
+       { 0x0000, 0x0000 }, /* R249 */
+       { 0x0000, 0x0000 }, /* R250 */
+       { 0x0000, 0x0000 }, /* R251 */
+       { 0x0000, 0x0000 }, /* R252 */
+       { 0x0000, 0x0000 }, /* R253 */
+       { 0x0000, 0x0000 }, /* R254 */
+       { 0x0000, 0x0000 }, /* R255 */
+       { 0x000F, 0x0000 }, /* R256   - Chip Revision */
+       { 0x0074, 0x0074 }, /* R257   - Control Interface */
+       { 0x0000, 0x0000 }, /* R258 */
+       { 0x0000, 0x0000 }, /* R259 */
+       { 0x0000, 0x0000 }, /* R260 */
+       { 0x0000, 0x0000 }, /* R261 */
+       { 0x0000, 0x0000 }, /* R262 */
+       { 0x0000, 0x0000 }, /* R263 */
+       { 0x0000, 0x0000 }, /* R264 */
+       { 0x0000, 0x0000 }, /* R265 */
+       { 0x0000, 0x0000 }, /* R266 */
+       { 0x0000, 0x0000 }, /* R267 */
+       { 0x0000, 0x0000 }, /* R268 */
+       { 0x0000, 0x0000 }, /* R269 */
+       { 0x0000, 0x0000 }, /* R270 */
+       { 0x0000, 0x0000 }, /* R271 */
+       { 0x807F, 0x837F }, /* R272   - Write Sequencer Ctrl (1) */
+       { 0x017F, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
+       { 0x0000, 0x0000 }, /* R274 */
+       { 0x0000, 0x0000 }, /* R275 */
+       { 0x0000, 0x0000 }, /* R276 */
+       { 0x0000, 0x0000 }, /* R277 */
+       { 0x0000, 0x0000 }, /* R278 */
+       { 0x0000, 0x0000 }, /* R279 */
+       { 0x0000, 0x0000 }, /* R280 */
+       { 0x0000, 0x0000 }, /* R281 */
+       { 0x0000, 0x0000 }, /* R282 */
+       { 0x0000, 0x0000 }, /* R283 */
+       { 0x0000, 0x0000 }, /* R284 */
+       { 0x0000, 0x0000 }, /* R285 */
+       { 0x0000, 0x0000 }, /* R286 */
+       { 0x0000, 0x0000 }, /* R287 */
+       { 0x0000, 0x0000 }, /* R288 */
+       { 0x0000, 0x0000 }, /* R289 */
+       { 0x0000, 0x0000 }, /* R290 */
+       { 0x0000, 0x0000 }, /* R291 */
+       { 0x0000, 0x0000 }, /* R292 */
+       { 0x0000, 0x0000 }, /* R293 */
+       { 0x0000, 0x0000 }, /* R294 */
+       { 0x0000, 0x0000 }, /* R295 */
+       { 0x0000, 0x0000 }, /* R296 */
+       { 0x0000, 0x0000 }, /* R297 */
+       { 0x0000, 0x0000 }, /* R298 */
+       { 0x0000, 0x0000 }, /* R299 */
+       { 0x0000, 0x0000 }, /* R300 */
+       { 0x0000, 0x0000 }, /* R301 */
+       { 0x0000, 0x0000 }, /* R302 */
+       { 0x0000, 0x0000 }, /* R303 */
+       { 0x0000, 0x0000 }, /* R304 */
+       { 0x0000, 0x0000 }, /* R305 */
+       { 0x0000, 0x0000 }, /* R306 */
+       { 0x0000, 0x0000 }, /* R307 */
+       { 0x0000, 0x0000 }, /* R308 */
+       { 0x0000, 0x0000 }, /* R309 */
+       { 0x0000, 0x0000 }, /* R310 */
+       { 0x0000, 0x0000 }, /* R311 */
+       { 0x0000, 0x0000 }, /* R312 */
+       { 0x0000, 0x0000 }, /* R313 */
+       { 0x0000, 0x0000 }, /* R314 */
+       { 0x0000, 0x0000 }, /* R315 */
+       { 0x0000, 0x0000 }, /* R316 */
+       { 0x0000, 0x0000 }, /* R317 */
+       { 0x0000, 0x0000 }, /* R318 */
+       { 0x0000, 0x0000 }, /* R319 */
+       { 0x0000, 0x0000 }, /* R320 */
+       { 0x0000, 0x0000 }, /* R321 */
+       { 0x0000, 0x0000 }, /* R322 */
+       { 0x0000, 0x0000 }, /* R323 */
+       { 0x0000, 0x0000 }, /* R324 */
+       { 0x0000, 0x0000 }, /* R325 */
+       { 0x0000, 0x0000 }, /* R326 */
+       { 0x0000, 0x0000 }, /* R327 */
+       { 0x0000, 0x0000 }, /* R328 */
+       { 0x0000, 0x0000 }, /* R329 */
+       { 0x0000, 0x0000 }, /* R330 */
+       { 0x0000, 0x0000 }, /* R331 */
+       { 0x0000, 0x0000 }, /* R332 */
+       { 0x0000, 0x0000 }, /* R333 */
+       { 0x0000, 0x0000 }, /* R334 */
+       { 0x0000, 0x0000 }, /* R335 */
+       { 0x0000, 0x0000 }, /* R336 */
+       { 0x0000, 0x0000 }, /* R337 */
+       { 0x0000, 0x0000 }, /* R338 */
+       { 0x0000, 0x0000 }, /* R339 */
+       { 0x0000, 0x0000 }, /* R340 */
+       { 0x0000, 0x0000 }, /* R341 */
+       { 0x0000, 0x0000 }, /* R342 */
+       { 0x0000, 0x0000 }, /* R343 */
+       { 0x0000, 0x0000 }, /* R344 */
+       { 0x0000, 0x0000 }, /* R345 */
+       { 0x0000, 0x0000 }, /* R346 */
+       { 0x0000, 0x0000 }, /* R347 */
+       { 0x0000, 0x0000 }, /* R348 */
+       { 0x0000, 0x0000 }, /* R349 */
+       { 0x0000, 0x0000 }, /* R350 */
+       { 0x0000, 0x0000 }, /* R351 */
+       { 0x0000, 0x0000 }, /* R352 */
+       { 0x0000, 0x0000 }, /* R353 */
+       { 0x0000, 0x0000 }, /* R354 */
+       { 0x0000, 0x0000 }, /* R355 */
+       { 0x0000, 0x0000 }, /* R356 */
+       { 0x0000, 0x0000 }, /* R357 */
+       { 0x0000, 0x0000 }, /* R358 */
+       { 0x0000, 0x0000 }, /* R359 */
+       { 0x0000, 0x0000 }, /* R360 */
+       { 0x0000, 0x0000 }, /* R361 */
+       { 0x0000, 0x0000 }, /* R362 */
+       { 0x0000, 0x0000 }, /* R363 */
+       { 0x0000, 0x0000 }, /* R364 */
+       { 0x0000, 0x0000 }, /* R365 */
+       { 0x0000, 0x0000 }, /* R366 */
+       { 0x0000, 0x0000 }, /* R367 */
+       { 0x0000, 0x0000 }, /* R368 */
+       { 0x0000, 0x0000 }, /* R369 */
+       { 0x0000, 0x0000 }, /* R370 */
+       { 0x0000, 0x0000 }, /* R371 */
+       { 0x0000, 0x0000 }, /* R372 */
+       { 0x0000, 0x0000 }, /* R373 */
+       { 0x0000, 0x0000 }, /* R374 */
+       { 0x0000, 0x0000 }, /* R375 */
+       { 0x0000, 0x0000 }, /* R376 */
+       { 0x0000, 0x0000 }, /* R377 */
+       { 0x0000, 0x0000 }, /* R378 */
+       { 0x0000, 0x0000 }, /* R379 */
+       { 0x0000, 0x0000 }, /* R380 */
+       { 0x0000, 0x0000 }, /* R381 */
+       { 0x0000, 0x0000 }, /* R382 */
+       { 0x0000, 0x0000 }, /* R383 */
+       { 0x0000, 0x0000 }, /* R384 */
+       { 0x0000, 0x0000 }, /* R385 */
+       { 0x0000, 0x0000 }, /* R386 */
+       { 0x0000, 0x0000 }, /* R387 */
+       { 0x0000, 0x0000 }, /* R388 */
+       { 0x0000, 0x0000 }, /* R389 */
+       { 0x0000, 0x0000 }, /* R390 */
+       { 0x0000, 0x0000 }, /* R391 */
+       { 0x0000, 0x0000 }, /* R392 */
+       { 0x0000, 0x0000 }, /* R393 */
+       { 0x0000, 0x0000 }, /* R394 */
+       { 0x0000, 0x0000 }, /* R395 */
+       { 0x0000, 0x0000 }, /* R396 */
+       { 0x0000, 0x0000 }, /* R397 */
+       { 0x0000, 0x0000 }, /* R398 */
+       { 0x0000, 0x0000 }, /* R399 */
+       { 0x0000, 0x0000 }, /* R400 */
+       { 0x0000, 0x0000 }, /* R401 */
+       { 0x0000, 0x0000 }, /* R402 */
+       { 0x0000, 0x0000 }, /* R403 */
+       { 0x0000, 0x0000 }, /* R404 */
+       { 0x0000, 0x0000 }, /* R405 */
+       { 0x0000, 0x0000 }, /* R406 */
+       { 0x0000, 0x0000 }, /* R407 */
+       { 0x0000, 0x0000 }, /* R408 */
+       { 0x0000, 0x0000 }, /* R409 */
+       { 0x0000, 0x0000 }, /* R410 */
+       { 0x0000, 0x0000 }, /* R411 */
+       { 0x0000, 0x0000 }, /* R412 */
+       { 0x0000, 0x0000 }, /* R413 */
+       { 0x0000, 0x0000 }, /* R414 */
+       { 0x0000, 0x0000 }, /* R415 */
+       { 0x0000, 0x0000 }, /* R416 */
+       { 0x0000, 0x0000 }, /* R417 */
+       { 0x0000, 0x0000 }, /* R418 */
+       { 0x0000, 0x0000 }, /* R419 */
+       { 0x0000, 0x0000 }, /* R420 */
+       { 0x0000, 0x0000 }, /* R421 */
+       { 0x0000, 0x0000 }, /* R422 */
+       { 0x0000, 0x0000 }, /* R423 */
+       { 0x0000, 0x0000 }, /* R424 */
+       { 0x0000, 0x0000 }, /* R425 */
+       { 0x0000, 0x0000 }, /* R426 */
+       { 0x0000, 0x0000 }, /* R427 */
+       { 0x0000, 0x0000 }, /* R428 */
+       { 0x0000, 0x0000 }, /* R429 */
+       { 0x0000, 0x0000 }, /* R430 */
+       { 0x0000, 0x0000 }, /* R431 */
+       { 0x0000, 0x0000 }, /* R432 */
+       { 0x0000, 0x0000 }, /* R433 */
+       { 0x0000, 0x0000 }, /* R434 */
+       { 0x0000, 0x0000 }, /* R435 */
+       { 0x0000, 0x0000 }, /* R436 */
+       { 0x0000, 0x0000 }, /* R437 */
+       { 0x0000, 0x0000 }, /* R438 */
+       { 0x0000, 0x0000 }, /* R439 */
+       { 0x0000, 0x0000 }, /* R440 */
+       { 0x0000, 0x0000 }, /* R441 */
+       { 0x0000, 0x0000 }, /* R442 */
+       { 0x0000, 0x0000 }, /* R443 */
+       { 0x0000, 0x0000 }, /* R444 */
+       { 0x0000, 0x0000 }, /* R445 */
+       { 0x0000, 0x0000 }, /* R446 */
+       { 0x0000, 0x0000 }, /* R447 */
+       { 0x0000, 0x0000 }, /* R448 */
+       { 0x0000, 0x0000 }, /* R449 */
+       { 0x0000, 0x0000 }, /* R450 */
+       { 0x0000, 0x0000 }, /* R451 */
+       { 0x0000, 0x0000 }, /* R452 */
+       { 0x0000, 0x0000 }, /* R453 */
+       { 0x0000, 0x0000 }, /* R454 */
+       { 0x0000, 0x0000 }, /* R455 */
+       { 0x0000, 0x0000 }, /* R456 */
+       { 0x0000, 0x0000 }, /* R457 */
+       { 0x0000, 0x0000 }, /* R458 */
+       { 0x0000, 0x0000 }, /* R459 */
+       { 0x0000, 0x0000 }, /* R460 */
+       { 0x0000, 0x0000 }, /* R461 */
+       { 0x0000, 0x0000 }, /* R462 */
+       { 0x0000, 0x0000 }, /* R463 */
+       { 0x0000, 0x0000 }, /* R464 */
+       { 0x0000, 0x0000 }, /* R465 */
+       { 0x0000, 0x0000 }, /* R466 */
+       { 0x0000, 0x0000 }, /* R467 */
+       { 0x0000, 0x0000 }, /* R468 */
+       { 0x0000, 0x0000 }, /* R469 */
+       { 0x0000, 0x0000 }, /* R470 */
+       { 0x0000, 0x0000 }, /* R471 */
+       { 0x0000, 0x0000 }, /* R472 */
+       { 0x0000, 0x0000 }, /* R473 */
+       { 0x0000, 0x0000 }, /* R474 */
+       { 0x0000, 0x0000 }, /* R475 */
+       { 0x0000, 0x0000 }, /* R476 */
+       { 0x0000, 0x0000 }, /* R477 */
+       { 0x0000, 0x0000 }, /* R478 */
+       { 0x0000, 0x0000 }, /* R479 */
+       { 0x0000, 0x0000 }, /* R480 */
+       { 0x0000, 0x0000 }, /* R481 */
+       { 0x0000, 0x0000 }, /* R482 */
+       { 0x0000, 0x0000 }, /* R483 */
+       { 0x0000, 0x0000 }, /* R484 */
+       { 0x0000, 0x0000 }, /* R485 */
+       { 0x0000, 0x0000 }, /* R486 */
+       { 0x0000, 0x0000 }, /* R487 */
+       { 0x0000, 0x0000 }, /* R488 */
+       { 0x0000, 0x0000 }, /* R489 */
+       { 0x0000, 0x0000 }, /* R490 */
+       { 0x0000, 0x0000 }, /* R491 */
+       { 0x0000, 0x0000 }, /* R492 */
+       { 0x0000, 0x0000 }, /* R493 */
+       { 0x0000, 0x0000 }, /* R494 */
+       { 0x0000, 0x0000 }, /* R495 */
+       { 0x0000, 0x0000 }, /* R496 */
+       { 0x0000, 0x0000 }, /* R497 */
+       { 0x0000, 0x0000 }, /* R498 */
+       { 0x0000, 0x0000 }, /* R499 */
+       { 0x0000, 0x0000 }, /* R500 */
+       { 0x0000, 0x0000 }, /* R501 */
+       { 0x0000, 0x0000 }, /* R502 */
+       { 0x0000, 0x0000 }, /* R503 */
+       { 0x0000, 0x0000 }, /* R504 */
+       { 0x0000, 0x0000 }, /* R505 */
+       { 0x0000, 0x0000 }, /* R506 */
+       { 0x0000, 0x0000 }, /* R507 */
+       { 0x0000, 0x0000 }, /* R508 */
+       { 0x0000, 0x0000 }, /* R509 */
+       { 0x0000, 0x0000 }, /* R510 */
+       { 0x0000, 0x0000 }, /* R511 */
+       { 0x001F, 0x001F }, /* R512   - AIF1 Clocking (1) */
+       { 0x003F, 0x003F }, /* R513   - AIF1 Clocking (2) */
+       { 0x0000, 0x0000 }, /* R514 */
+       { 0x0000, 0x0000 }, /* R515 */
+       { 0x001F, 0x001F }, /* R516   - AIF2 Clocking (1) */
+       { 0x003F, 0x003F }, /* R517   - AIF2 Clocking (2) */
+       { 0x0000, 0x0000 }, /* R518 */
+       { 0x0000, 0x0000 }, /* R519 */
+       { 0x001F, 0x001F }, /* R520   - Clocking (1) */
+       { 0x0777, 0x0777 }, /* R521   - Clocking (2) */
+       { 0x0000, 0x0000 }, /* R522 */
+       { 0x0000, 0x0000 }, /* R523 */
+       { 0x0000, 0x0000 }, /* R524 */
+       { 0x0000, 0x0000 }, /* R525 */
+       { 0x0000, 0x0000 }, /* R526 */
+       { 0x0000, 0x0000 }, /* R527 */
+       { 0x00FF, 0x00FF }, /* R528   - AIF1 Rate */
+       { 0x00FF, 0x00FF }, /* R529   - AIF2 Rate */
+       { 0x000F, 0x0000 }, /* R530   - Rate Status */
+       { 0x0000, 0x0000 }, /* R531 */
+       { 0x0000, 0x0000 }, /* R532 */
+       { 0x0000, 0x0000 }, /* R533 */
+       { 0x0000, 0x0000 }, /* R534 */
+       { 0x0000, 0x0000 }, /* R535 */
+       { 0x0000, 0x0000 }, /* R536 */
+       { 0x0000, 0x0000 }, /* R537 */
+       { 0x0000, 0x0000 }, /* R538 */
+       { 0x0000, 0x0000 }, /* R539 */
+       { 0x0000, 0x0000 }, /* R540 */
+       { 0x0000, 0x0000 }, /* R541 */
+       { 0x0000, 0x0000 }, /* R542 */
+       { 0x0000, 0x0000 }, /* R543 */
+       { 0x0007, 0x0007 }, /* R544   - FLL1 Control (1) */
+       { 0x3F77, 0x3F77 }, /* R545   - FLL1 Control (2) */
+       { 0xFFFF, 0xFFFF }, /* R546   - FLL1 Control (3) */
+       { 0x7FEF, 0x7FEF }, /* R547   - FLL1 Control (4) */
+       { 0x1FDB, 0x1FDB }, /* R548   - FLL1 Control (5) */
+       { 0x0000, 0x0000 }, /* R549 */
+       { 0x0000, 0x0000 }, /* R550 */
+       { 0x0000, 0x0000 }, /* R551 */
+       { 0x0000, 0x0000 }, /* R552 */
+       { 0x0000, 0x0000 }, /* R553 */
+       { 0x0000, 0x0000 }, /* R554 */
+       { 0x0000, 0x0000 }, /* R555 */
+       { 0x0000, 0x0000 }, /* R556 */
+       { 0x0000, 0x0000 }, /* R557 */
+       { 0x0000, 0x0000 }, /* R558 */
+       { 0x0000, 0x0000 }, /* R559 */
+       { 0x0000, 0x0000 }, /* R560 */
+       { 0x0000, 0x0000 }, /* R561 */
+       { 0x0000, 0x0000 }, /* R562 */
+       { 0x0000, 0x0000 }, /* R563 */
+       { 0x0000, 0x0000 }, /* R564 */
+       { 0x0000, 0x0000 }, /* R565 */
+       { 0x0000, 0x0000 }, /* R566 */
+       { 0x0000, 0x0000 }, /* R567 */
+       { 0x0000, 0x0000 }, /* R568 */
+       { 0x0000, 0x0000 }, /* R569 */
+       { 0x0000, 0x0000 }, /* R570 */
+       { 0x0000, 0x0000 }, /* R571 */
+       { 0x0000, 0x0000 }, /* R572 */
+       { 0x0000, 0x0000 }, /* R573 */
+       { 0x0000, 0x0000 }, /* R574 */
+       { 0x0000, 0x0000 }, /* R575 */
+       { 0x0007, 0x0007 }, /* R576   - FLL2 Control (1) */
+       { 0x3F77, 0x3F77 }, /* R577   - FLL2 Control (2) */
+       { 0xFFFF, 0xFFFF }, /* R578   - FLL2 Control (3) */
+       { 0x7FEF, 0x7FEF }, /* R579   - FLL2 Control (4) */
+       { 0x1FDB, 0x1FDB }, /* R580   - FLL2 Control (5) */
+       { 0x0000, 0x0000 }, /* R581 */
+       { 0x0000, 0x0000 }, /* R582 */
+       { 0x0000, 0x0000 }, /* R583 */
+       { 0x0000, 0x0000 }, /* R584 */
+       { 0x0000, 0x0000 }, /* R585 */
+       { 0x0000, 0x0000 }, /* R586 */
+       { 0x0000, 0x0000 }, /* R587 */
+       { 0x0000, 0x0000 }, /* R588 */
+       { 0x0000, 0x0000 }, /* R589 */
+       { 0x0000, 0x0000 }, /* R590 */
+       { 0x0000, 0x0000 }, /* R591 */
+       { 0x0000, 0x0000 }, /* R592 */
+       { 0x0000, 0x0000 }, /* R593 */
+       { 0x0000, 0x0000 }, /* R594 */
+       { 0x0000, 0x0000 }, /* R595 */
+       { 0x0000, 0x0000 }, /* R596 */
+       { 0x0000, 0x0000 }, /* R597 */
+       { 0x0000, 0x0000 }, /* R598 */
+       { 0x0000, 0x0000 }, /* R599 */
+       { 0x0000, 0x0000 }, /* R600 */
+       { 0x0000, 0x0000 }, /* R601 */
+       { 0x0000, 0x0000 }, /* R602 */
+       { 0x0000, 0x0000 }, /* R603 */
+       { 0x0000, 0x0000 }, /* R604 */
+       { 0x0000, 0x0000 }, /* R605 */
+       { 0x0000, 0x0000 }, /* R606 */
+       { 0x0000, 0x0000 }, /* R607 */
+       { 0x0000, 0x0000 }, /* R608 */
+       { 0x0000, 0x0000 }, /* R609 */
+       { 0x0000, 0x0000 }, /* R610 */
+       { 0x0000, 0x0000 }, /* R611 */
+       { 0x0000, 0x0000 }, /* R612 */
+       { 0x0000, 0x0000 }, /* R613 */
+       { 0x0000, 0x0000 }, /* R614 */
+       { 0x0000, 0x0000 }, /* R615 */
+       { 0x0000, 0x0000 }, /* R616 */
+       { 0x0000, 0x0000 }, /* R617 */
+       { 0x0000, 0x0000 }, /* R618 */
+       { 0x0000, 0x0000 }, /* R619 */
+       { 0x0000, 0x0000 }, /* R620 */
+       { 0x0000, 0x0000 }, /* R621 */
+       { 0x0000, 0x0000 }, /* R622 */
+       { 0x0000, 0x0000 }, /* R623 */
+       { 0x0000, 0x0000 }, /* R624 */
+       { 0x0000, 0x0000 }, /* R625 */
+       { 0x0000, 0x0000 }, /* R626 */
+       { 0x0000, 0x0000 }, /* R627 */
+       { 0x0000, 0x0000 }, /* R628 */
+       { 0x0000, 0x0000 }, /* R629 */
+       { 0x0000, 0x0000 }, /* R630 */
+       { 0x0000, 0x0000 }, /* R631 */
+       { 0x0000, 0x0000 }, /* R632 */
+       { 0x0000, 0x0000 }, /* R633 */
+       { 0x0000, 0x0000 }, /* R634 */
+       { 0x0000, 0x0000 }, /* R635 */
+       { 0x0000, 0x0000 }, /* R636 */
+       { 0x0000, 0x0000 }, /* R637 */
+       { 0x0000, 0x0000 }, /* R638 */
+       { 0x0000, 0x0000 }, /* R639 */
+       { 0x0000, 0x0000 }, /* R640 */
+       { 0x0000, 0x0000 }, /* R641 */
+       { 0x0000, 0x0000 }, /* R642 */
+       { 0x0000, 0x0000 }, /* R643 */
+       { 0x0000, 0x0000 }, /* R644 */
+       { 0x0000, 0x0000 }, /* R645 */
+       { 0x0000, 0x0000 }, /* R646 */
+       { 0x0000, 0x0000 }, /* R647 */
+       { 0x0000, 0x0000 }, /* R648 */
+       { 0x0000, 0x0000 }, /* R649 */
+       { 0x0000, 0x0000 }, /* R650 */
+       { 0x0000, 0x0000 }, /* R651 */
+       { 0x0000, 0x0000 }, /* R652 */
+       { 0x0000, 0x0000 }, /* R653 */
+       { 0x0000, 0x0000 }, /* R654 */
+       { 0x0000, 0x0000 }, /* R655 */
+       { 0x0000, 0x0000 }, /* R656 */
+       { 0x0000, 0x0000 }, /* R657 */
+       { 0x0000, 0x0000 }, /* R658 */
+       { 0x0000, 0x0000 }, /* R659 */
+       { 0x0000, 0x0000 }, /* R660 */
+       { 0x0000, 0x0000 }, /* R661 */
+       { 0x0000, 0x0000 }, /* R662 */
+       { 0x0000, 0x0000 }, /* R663 */
+       { 0x0000, 0x0000 }, /* R664 */
+       { 0x0000, 0x0000 }, /* R665 */
+       { 0x0000, 0x0000 }, /* R666 */
+       { 0x0000, 0x0000 }, /* R667 */
+       { 0x0000, 0x0000 }, /* R668 */
+       { 0x0000, 0x0000 }, /* R669 */
+       { 0x0000, 0x0000 }, /* R670 */
+       { 0x0000, 0x0000 }, /* R671 */
+       { 0x0000, 0x0000 }, /* R672 */
+       { 0x0000, 0x0000 }, /* R673 */
+       { 0x0000, 0x0000 }, /* R674 */
+       { 0x0000, 0x0000 }, /* R675 */
+       { 0x0000, 0x0000 }, /* R676 */
+       { 0x0000, 0x0000 }, /* R677 */
+       { 0x0000, 0x0000 }, /* R678 */
+       { 0x0000, 0x0000 }, /* R679 */
+       { 0x0000, 0x0000 }, /* R680 */
+       { 0x0000, 0x0000 }, /* R681 */
+       { 0x0000, 0x0000 }, /* R682 */
+       { 0x0000, 0x0000 }, /* R683 */
+       { 0x0000, 0x0000 }, /* R684 */
+       { 0x0000, 0x0000 }, /* R685 */
+       { 0x0000, 0x0000 }, /* R686 */
+       { 0x0000, 0x0000 }, /* R687 */
+       { 0x0000, 0x0000 }, /* R688 */
+       { 0x0000, 0x0000 }, /* R689 */
+       { 0x0000, 0x0000 }, /* R690 */
+       { 0x0000, 0x0000 }, /* R691 */
+       { 0x0000, 0x0000 }, /* R692 */
+       { 0x0000, 0x0000 }, /* R693 */
+       { 0x0000, 0x0000 }, /* R694 */
+       { 0x0000, 0x0000 }, /* R695 */
+       { 0x0000, 0x0000 }, /* R696 */
+       { 0x0000, 0x0000 }, /* R697 */
+       { 0x0000, 0x0000 }, /* R698 */
+       { 0x0000, 0x0000 }, /* R699 */
+       { 0x0000, 0x0000 }, /* R700 */
+       { 0x0000, 0x0000 }, /* R701 */
+       { 0x0000, 0x0000 }, /* R702 */
+       { 0x0000, 0x0000 }, /* R703 */
+       { 0x0000, 0x0000 }, /* R704 */
+       { 0x0000, 0x0000 }, /* R705 */
+       { 0x0000, 0x0000 }, /* R706 */
+       { 0x0000, 0x0000 }, /* R707 */
+       { 0x0000, 0x0000 }, /* R708 */
+       { 0x0000, 0x0000 }, /* R709 */
+       { 0x0000, 0x0000 }, /* R710 */
+       { 0x0000, 0x0000 }, /* R711 */
+       { 0x0000, 0x0000 }, /* R712 */
+       { 0x0000, 0x0000 }, /* R713 */
+       { 0x0000, 0x0000 }, /* R714 */
+       { 0x0000, 0x0000 }, /* R715 */
+       { 0x0000, 0x0000 }, /* R716 */
+       { 0x0000, 0x0000 }, /* R717 */
+       { 0x0000, 0x0000 }, /* R718 */
+       { 0x0000, 0x0000 }, /* R719 */
+       { 0x0000, 0x0000 }, /* R720 */
+       { 0x0000, 0x0000 }, /* R721 */
+       { 0x0000, 0x0000 }, /* R722 */
+       { 0x0000, 0x0000 }, /* R723 */
+       { 0x0000, 0x0000 }, /* R724 */
+       { 0x0000, 0x0000 }, /* R725 */
+       { 0x0000, 0x0000 }, /* R726 */
+       { 0x0000, 0x0000 }, /* R727 */
+       { 0x0000, 0x0000 }, /* R728 */
+       { 0x0000, 0x0000 }, /* R729 */
+       { 0x0000, 0x0000 }, /* R730 */
+       { 0x0000, 0x0000 }, /* R731 */
+       { 0x0000, 0x0000 }, /* R732 */
+       { 0x0000, 0x0000 }, /* R733 */
+       { 0x0000, 0x0000 }, /* R734 */
+       { 0x0000, 0x0000 }, /* R735 */
+       { 0x0000, 0x0000 }, /* R736 */
+       { 0x0000, 0x0000 }, /* R737 */
+       { 0x0000, 0x0000 }, /* R738 */
+       { 0x0000, 0x0000 }, /* R739 */
+       { 0x0000, 0x0000 }, /* R740 */
+       { 0x0000, 0x0000 }, /* R741 */
+       { 0x0000, 0x0000 }, /* R742 */
+       { 0x0000, 0x0000 }, /* R743 */
+       { 0x0000, 0x0000 }, /* R744 */
+       { 0x0000, 0x0000 }, /* R745 */
+       { 0x0000, 0x0000 }, /* R746 */
+       { 0x0000, 0x0000 }, /* R747 */
+       { 0x0000, 0x0000 }, /* R748 */
+       { 0x0000, 0x0000 }, /* R749 */
+       { 0x0000, 0x0000 }, /* R750 */
+       { 0x0000, 0x0000 }, /* R751 */
+       { 0x0000, 0x0000 }, /* R752 */
+       { 0x0000, 0x0000 }, /* R753 */
+       { 0x0000, 0x0000 }, /* R754 */
+       { 0x0000, 0x0000 }, /* R755 */
+       { 0x0000, 0x0000 }, /* R756 */
+       { 0x0000, 0x0000 }, /* R757 */
+       { 0x0000, 0x0000 }, /* R758 */
+       { 0x0000, 0x0000 }, /* R759 */
+       { 0x0000, 0x0000 }, /* R760 */
+       { 0x0000, 0x0000 }, /* R761 */
+       { 0x0000, 0x0000 }, /* R762 */
+       { 0x0000, 0x0000 }, /* R763 */
+       { 0x0000, 0x0000 }, /* R764 */
+       { 0x0000, 0x0000 }, /* R765 */
+       { 0x0000, 0x0000 }, /* R766 */
+       { 0x0000, 0x0000 }, /* R767 */
+       { 0xE1F8, 0xE1F8 }, /* R768   - AIF1 Control (1) */
+       { 0xCD1F, 0xCD1F }, /* R769   - AIF1 Control (2) */
+       { 0xF000, 0xF000 }, /* R770   - AIF1 Master/Slave */
+       { 0x01F0, 0x01F0 }, /* R771   - AIF1 BCLK */
+       { 0x0FFF, 0x0FFF }, /* R772   - AIF1ADC LRCLK */
+       { 0x0FFF, 0x0FFF }, /* R773   - AIF1DAC LRCLK */
+       { 0x0003, 0x0003 }, /* R774   - AIF1DAC Data */
+       { 0x0003, 0x0003 }, /* R775   - AIF1ADC Data */
+       { 0x0000, 0x0000 }, /* R776 */
+       { 0x0000, 0x0000 }, /* R777 */
+       { 0x0000, 0x0000 }, /* R778 */
+       { 0x0000, 0x0000 }, /* R779 */
+       { 0x0000, 0x0000 }, /* R780 */
+       { 0x0000, 0x0000 }, /* R781 */
+       { 0x0000, 0x0000 }, /* R782 */
+       { 0x0000, 0x0000 }, /* R783 */
+       { 0xF1F8, 0xF1F8 }, /* R784   - AIF2 Control (1) */
+       { 0xFD1F, 0xFD1F }, /* R785   - AIF2 Control (2) */
+       { 0xF000, 0xF000 }, /* R786   - AIF2 Master/Slave */
+       { 0x01F0, 0x01F0 }, /* R787   - AIF2 BCLK */
+       { 0x0FFF, 0x0FFF }, /* R788   - AIF2ADC LRCLK */
+       { 0x0FFF, 0x0FFF }, /* R789   - AIF2DAC LRCLK */
+       { 0x0003, 0x0003 }, /* R790   - AIF2DAC Data */
+       { 0x0003, 0x0003 }, /* R791   - AIF2ADC Data */
+       { 0x0000, 0x0000 }, /* R792 */
+       { 0x0000, 0x0000 }, /* R793 */
+       { 0x0000, 0x0000 }, /* R794 */
+       { 0x0000, 0x0000 }, /* R795 */
+       { 0x0000, 0x0000 }, /* R796 */
+       { 0x0000, 0x0000 }, /* R797 */
+       { 0x0000, 0x0000 }, /* R798 */
+       { 0x0000, 0x0000 }, /* R799 */
+       { 0x0000, 0x0000 }, /* R800 */
+       { 0x0000, 0x0000 }, /* R801 */
+       { 0x0000, 0x0000 }, /* R802 */
+       { 0x0000, 0x0000 }, /* R803 */
+       { 0x0000, 0x0000 }, /* R804 */
+       { 0x0000, 0x0000 }, /* R805 */
+       { 0x0000, 0x0000 }, /* R806 */
+       { 0x0000, 0x0000 }, /* R807 */
+       { 0x0000, 0x0000 }, /* R808 */
+       { 0x0000, 0x0000 }, /* R809 */
+       { 0x0000, 0x0000 }, /* R810 */
+       { 0x0000, 0x0000 }, /* R811 */
+       { 0x0000, 0x0000 }, /* R812 */
+       { 0x0000, 0x0000 }, /* R813 */
+       { 0x0000, 0x0000 }, /* R814 */
+       { 0x0000, 0x0000 }, /* R815 */
+       { 0x0000, 0x0000 }, /* R816 */
+       { 0x0000, 0x0000 }, /* R817 */
+       { 0x0000, 0x0000 }, /* R818 */
+       { 0x0000, 0x0000 }, /* R819 */
+       { 0x0000, 0x0000 }, /* R820 */
+       { 0x0000, 0x0000 }, /* R821 */
+       { 0x0000, 0x0000 }, /* R822 */
+       { 0x0000, 0x0000 }, /* R823 */
+       { 0x0000, 0x0000 }, /* R824 */
+       { 0x0000, 0x0000 }, /* R825 */
+       { 0x0000, 0x0000 }, /* R826 */
+       { 0x0000, 0x0000 }, /* R827 */
+       { 0x0000, 0x0000 }, /* R828 */
+       { 0x0000, 0x0000 }, /* R829 */
+       { 0x0000, 0x0000 }, /* R830 */
+       { 0x0000, 0x0000 }, /* R831 */
+       { 0x0000, 0x0000 }, /* R832 */
+       { 0x0000, 0x0000 }, /* R833 */
+       { 0x0000, 0x0000 }, /* R834 */
+       { 0x0000, 0x0000 }, /* R835 */
+       { 0x0000, 0x0000 }, /* R836 */
+       { 0x0000, 0x0000 }, /* R837 */
+       { 0x0000, 0x0000 }, /* R838 */
+       { 0x0000, 0x0000 }, /* R839 */
+       { 0x0000, 0x0000 }, /* R840 */
+       { 0x0000, 0x0000 }, /* R841 */
+       { 0x0000, 0x0000 }, /* R842 */
+       { 0x0000, 0x0000 }, /* R843 */
+       { 0x0000, 0x0000 }, /* R844 */
+       { 0x0000, 0x0000 }, /* R845 */
+       { 0x0000, 0x0000 }, /* R846 */
+       { 0x0000, 0x0000 }, /* R847 */
+       { 0x0000, 0x0000 }, /* R848 */
+       { 0x0000, 0x0000 }, /* R849 */
+       { 0x0000, 0x0000 }, /* R850 */
+       { 0x0000, 0x0000 }, /* R851 */
+       { 0x0000, 0x0000 }, /* R852 */
+       { 0x0000, 0x0000 }, /* R853 */
+       { 0x0000, 0x0000 }, /* R854 */
+       { 0x0000, 0x0000 }, /* R855 */
+       { 0x0000, 0x0000 }, /* R856 */
+       { 0x0000, 0x0000 }, /* R857 */
+       { 0x0000, 0x0000 }, /* R858 */
+       { 0x0000, 0x0000 }, /* R859 */
+       { 0x0000, 0x0000 }, /* R860 */
+       { 0x0000, 0x0000 }, /* R861 */
+       { 0x0000, 0x0000 }, /* R862 */
+       { 0x0000, 0x0000 }, /* R863 */
+       { 0x0000, 0x0000 }, /* R864 */
+       { 0x0000, 0x0000 }, /* R865 */
+       { 0x0000, 0x0000 }, /* R866 */
+       { 0x0000, 0x0000 }, /* R867 */
+       { 0x0000, 0x0000 }, /* R868 */
+       { 0x0000, 0x0000 }, /* R869 */
+       { 0x0000, 0x0000 }, /* R870 */
+       { 0x0000, 0x0000 }, /* R871 */
+       { 0x0000, 0x0000 }, /* R872 */
+       { 0x0000, 0x0000 }, /* R873 */
+       { 0x0000, 0x0000 }, /* R874 */
+       { 0x0000, 0x0000 }, /* R875 */
+       { 0x0000, 0x0000 }, /* R876 */
+       { 0x0000, 0x0000 }, /* R877 */
+       { 0x0000, 0x0000 }, /* R878 */
+       { 0x0000, 0x0000 }, /* R879 */
+       { 0x0000, 0x0000 }, /* R880 */
+       { 0x0000, 0x0000 }, /* R881 */
+       { 0x0000, 0x0000 }, /* R882 */
+       { 0x0000, 0x0000 }, /* R883 */
+       { 0x0000, 0x0000 }, /* R884 */
+       { 0x0000, 0x0000 }, /* R885 */
+       { 0x0000, 0x0000 }, /* R886 */
+       { 0x0000, 0x0000 }, /* R887 */
+       { 0x0000, 0x0000 }, /* R888 */
+       { 0x0000, 0x0000 }, /* R889 */
+       { 0x0000, 0x0000 }, /* R890 */
+       { 0x0000, 0x0000 }, /* R891 */
+       { 0x0000, 0x0000 }, /* R892 */
+       { 0x0000, 0x0000 }, /* R893 */
+       { 0x0000, 0x0000 }, /* R894 */
+       { 0x0000, 0x0000 }, /* R895 */
+       { 0x0000, 0x0000 }, /* R896 */
+       { 0x0000, 0x0000 }, /* R897 */
+       { 0x0000, 0x0000 }, /* R898 */
+       { 0x0000, 0x0000 }, /* R899 */
+       { 0x0000, 0x0000 }, /* R900 */
+       { 0x0000, 0x0000 }, /* R901 */
+       { 0x0000, 0x0000 }, /* R902 */
+       { 0x0000, 0x0000 }, /* R903 */
+       { 0x0000, 0x0000 }, /* R904 */
+       { 0x0000, 0x0000 }, /* R905 */
+       { 0x0000, 0x0000 }, /* R906 */
+       { 0x0000, 0x0000 }, /* R907 */
+       { 0x0000, 0x0000 }, /* R908 */
+       { 0x0000, 0x0000 }, /* R909 */
+       { 0x0000, 0x0000 }, /* R910 */
+       { 0x0000, 0x0000 }, /* R911 */
+       { 0x0000, 0x0000 }, /* R912 */
+       { 0x0000, 0x0000 }, /* R913 */
+       { 0x0000, 0x0000 }, /* R914 */
+       { 0x0000, 0x0000 }, /* R915 */
+       { 0x0000, 0x0000 }, /* R916 */
+       { 0x0000, 0x0000 }, /* R917 */
+       { 0x0000, 0x0000 }, /* R918 */
+       { 0x0000, 0x0000 }, /* R919 */
+       { 0x0000, 0x0000 }, /* R920 */
+       { 0x0000, 0x0000 }, /* R921 */
+       { 0x0000, 0x0000 }, /* R922 */
+       { 0x0000, 0x0000 }, /* R923 */
+       { 0x0000, 0x0000 }, /* R924 */
+       { 0x0000, 0x0000 }, /* R925 */
+       { 0x0000, 0x0000 }, /* R926 */
+       { 0x0000, 0x0000 }, /* R927 */
+       { 0x0000, 0x0000 }, /* R928 */
+       { 0x0000, 0x0000 }, /* R929 */
+       { 0x0000, 0x0000 }, /* R930 */
+       { 0x0000, 0x0000 }, /* R931 */
+       { 0x0000, 0x0000 }, /* R932 */
+       { 0x0000, 0x0000 }, /* R933 */
+       { 0x0000, 0x0000 }, /* R934 */
+       { 0x0000, 0x0000 }, /* R935 */
+       { 0x0000, 0x0000 }, /* R936 */
+       { 0x0000, 0x0000 }, /* R937 */
+       { 0x0000, 0x0000 }, /* R938 */
+       { 0x0000, 0x0000 }, /* R939 */
+       { 0x0000, 0x0000 }, /* R940 */
+       { 0x0000, 0x0000 }, /* R941 */
+       { 0x0000, 0x0000 }, /* R942 */
+       { 0x0000, 0x0000 }, /* R943 */
+       { 0x0000, 0x0000 }, /* R944 */
+       { 0x0000, 0x0000 }, /* R945 */
+       { 0x0000, 0x0000 }, /* R946 */
+       { 0x0000, 0x0000 }, /* R947 */
+       { 0x0000, 0x0000 }, /* R948 */
+       { 0x0000, 0x0000 }, /* R949 */
+       { 0x0000, 0x0000 }, /* R950 */
+       { 0x0000, 0x0000 }, /* R951 */
+       { 0x0000, 0x0000 }, /* R952 */
+       { 0x0000, 0x0000 }, /* R953 */
+       { 0x0000, 0x0000 }, /* R954 */
+       { 0x0000, 0x0000 }, /* R955 */
+       { 0x0000, 0x0000 }, /* R956 */
+       { 0x0000, 0x0000 }, /* R957 */
+       { 0x0000, 0x0000 }, /* R958 */
+       { 0x0000, 0x0000 }, /* R959 */
+       { 0x0000, 0x0000 }, /* R960 */
+       { 0x0000, 0x0000 }, /* R961 */
+       { 0x0000, 0x0000 }, /* R962 */
+       { 0x0000, 0x0000 }, /* R963 */
+       { 0x0000, 0x0000 }, /* R964 */
+       { 0x0000, 0x0000 }, /* R965 */
+       { 0x0000, 0x0000 }, /* R966 */
+       { 0x0000, 0x0000 }, /* R967 */
+       { 0x0000, 0x0000 }, /* R968 */
+       { 0x0000, 0x0000 }, /* R969 */
+       { 0x0000, 0x0000 }, /* R970 */
+       { 0x0000, 0x0000 }, /* R971 */
+       { 0x0000, 0x0000 }, /* R972 */
+       { 0x0000, 0x0000 }, /* R973 */
+       { 0x0000, 0x0000 }, /* R974 */
+       { 0x0000, 0x0000 }, /* R975 */
+       { 0x0000, 0x0000 }, /* R976 */
+       { 0x0000, 0x0000 }, /* R977 */
+       { 0x0000, 0x0000 }, /* R978 */
+       { 0x0000, 0x0000 }, /* R979 */
+       { 0x0000, 0x0000 }, /* R980 */
+       { 0x0000, 0x0000 }, /* R981 */
+       { 0x0000, 0x0000 }, /* R982 */
+       { 0x0000, 0x0000 }, /* R983 */
+       { 0x0000, 0x0000 }, /* R984 */
+       { 0x0000, 0x0000 }, /* R985 */
+       { 0x0000, 0x0000 }, /* R986 */
+       { 0x0000, 0x0000 }, /* R987 */
+       { 0x0000, 0x0000 }, /* R988 */
+       { 0x0000, 0x0000 }, /* R989 */
+       { 0x0000, 0x0000 }, /* R990 */
+       { 0x0000, 0x0000 }, /* R991 */
+       { 0x0000, 0x0000 }, /* R992 */
+       { 0x0000, 0x0000 }, /* R993 */
+       { 0x0000, 0x0000 }, /* R994 */
+       { 0x0000, 0x0000 }, /* R995 */
+       { 0x0000, 0x0000 }, /* R996 */
+       { 0x0000, 0x0000 }, /* R997 */
+       { 0x0000, 0x0000 }, /* R998 */
+       { 0x0000, 0x0000 }, /* R999 */
+       { 0x0000, 0x0000 }, /* R1000 */
+       { 0x0000, 0x0000 }, /* R1001 */
+       { 0x0000, 0x0000 }, /* R1002 */
+       { 0x0000, 0x0000 }, /* R1003 */
+       { 0x0000, 0x0000 }, /* R1004 */
+       { 0x0000, 0x0000 }, /* R1005 */
+       { 0x0000, 0x0000 }, /* R1006 */
+       { 0x0000, 0x0000 }, /* R1007 */
+       { 0x0000, 0x0000 }, /* R1008 */
+       { 0x0000, 0x0000 }, /* R1009 */
+       { 0x0000, 0x0000 }, /* R1010 */
+       { 0x0000, 0x0000 }, /* R1011 */
+       { 0x0000, 0x0000 }, /* R1012 */
+       { 0x0000, 0x0000 }, /* R1013 */
+       { 0x0000, 0x0000 }, /* R1014 */
+       { 0x0000, 0x0000 }, /* R1015 */
+       { 0x0000, 0x0000 }, /* R1016 */
+       { 0x0000, 0x0000 }, /* R1017 */
+       { 0x0000, 0x0000 }, /* R1018 */
+       { 0x0000, 0x0000 }, /* R1019 */
+       { 0x0000, 0x0000 }, /* R1020 */
+       { 0x0000, 0x0000 }, /* R1021 */
+       { 0x0000, 0x0000 }, /* R1022 */
+       { 0x0000, 0x0000 }, /* R1023 */
+       { 0x00FF, 0x01FF }, /* R1024  - AIF1 ADC1 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1025  - AIF1 ADC1 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1026  - AIF1 DAC1 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1027  - AIF1 DAC1 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1028  - AIF1 ADC2 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1029  - AIF1 ADC2 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1030  - AIF1 DAC2 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1031  - AIF1 DAC2 Right Volume */
+       { 0x0000, 0x0000 }, /* R1032 */
+       { 0x0000, 0x0000 }, /* R1033 */
+       { 0x0000, 0x0000 }, /* R1034 */
+       { 0x0000, 0x0000 }, /* R1035 */
+       { 0x0000, 0x0000 }, /* R1036 */
+       { 0x0000, 0x0000 }, /* R1037 */
+       { 0x0000, 0x0000 }, /* R1038 */
+       { 0x0000, 0x0000 }, /* R1039 */
+       { 0xF800, 0xF800 }, /* R1040  - AIF1 ADC1 Filters */
+       { 0x7800, 0x7800 }, /* R1041  - AIF1 ADC2 Filters */
+       { 0x0000, 0x0000 }, /* R1042 */
+       { 0x0000, 0x0000 }, /* R1043 */
+       { 0x0000, 0x0000 }, /* R1044 */
+       { 0x0000, 0x0000 }, /* R1045 */
+       { 0x0000, 0x0000 }, /* R1046 */
+       { 0x0000, 0x0000 }, /* R1047 */
+       { 0x0000, 0x0000 }, /* R1048 */
+       { 0x0000, 0x0000 }, /* R1049 */
+       { 0x0000, 0x0000 }, /* R1050 */
+       { 0x0000, 0x0000 }, /* R1051 */
+       { 0x0000, 0x0000 }, /* R1052 */
+       { 0x0000, 0x0000 }, /* R1053 */
+       { 0x0000, 0x0000 }, /* R1054 */
+       { 0x0000, 0x0000 }, /* R1055 */
+       { 0x02B6, 0x02B6 }, /* R1056  - AIF1 DAC1 Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1057  - AIF1 DAC1 Filters (2) */
+       { 0x02B6, 0x02B6 }, /* R1058  - AIF1 DAC2 Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1059  - AIF1 DAC2 Filters (2) */
+       { 0x0000, 0x0000 }, /* R1060 */
+       { 0x0000, 0x0000 }, /* R1061 */
+       { 0x0000, 0x0000 }, /* R1062 */
+       { 0x0000, 0x0000 }, /* R1063 */
+       { 0x0000, 0x0000 }, /* R1064 */
+       { 0x0000, 0x0000 }, /* R1065 */
+       { 0x0000, 0x0000 }, /* R1066 */
+       { 0x0000, 0x0000 }, /* R1067 */
+       { 0x0000, 0x0000 }, /* R1068 */
+       { 0x0000, 0x0000 }, /* R1069 */
+       { 0x0000, 0x0000 }, /* R1070 */
+       { 0x0000, 0x0000 }, /* R1071 */
+       { 0x0000, 0x0000 }, /* R1072 */
+       { 0x0000, 0x0000 }, /* R1073 */
+       { 0x0000, 0x0000 }, /* R1074 */
+       { 0x0000, 0x0000 }, /* R1075 */
+       { 0x0000, 0x0000 }, /* R1076 */
+       { 0x0000, 0x0000 }, /* R1077 */
+       { 0x0000, 0x0000 }, /* R1078 */
+       { 0x0000, 0x0000 }, /* R1079 */
+       { 0x0000, 0x0000 }, /* R1080 */
+       { 0x0000, 0x0000 }, /* R1081 */
+       { 0x0000, 0x0000 }, /* R1082 */
+       { 0x0000, 0x0000 }, /* R1083 */
+       { 0x0000, 0x0000 }, /* R1084 */
+       { 0x0000, 0x0000 }, /* R1085 */
+       { 0x0000, 0x0000 }, /* R1086 */
+       { 0x0000, 0x0000 }, /* R1087 */
+       { 0xFFFF, 0xFFFF }, /* R1088  - AIF1 DRC1 (1) */
+       { 0x1FFF, 0x1FFF }, /* R1089  - AIF1 DRC1 (2) */
+       { 0xFFFF, 0xFFFF }, /* R1090  - AIF1 DRC1 (3) */
+       { 0x07FF, 0x07FF }, /* R1091  - AIF1 DRC1 (4) */
+       { 0x03FF, 0x03FF }, /* R1092  - AIF1 DRC1 (5) */
+       { 0x0000, 0x0000 }, /* R1093 */
+       { 0x0000, 0x0000 }, /* R1094 */
+       { 0x0000, 0x0000 }, /* R1095 */
+       { 0x0000, 0x0000 }, /* R1096 */
+       { 0x0000, 0x0000 }, /* R1097 */
+       { 0x0000, 0x0000 }, /* R1098 */
+       { 0x0000, 0x0000 }, /* R1099 */
+       { 0x0000, 0x0000 }, /* R1100 */
+       { 0x0000, 0x0000 }, /* R1101 */
+       { 0x0000, 0x0000 }, /* R1102 */
+       { 0x0000, 0x0000 }, /* R1103 */
+       { 0xFFFF, 0xFFFF }, /* R1104  - AIF1 DRC2 (1) */
+       { 0x1FFF, 0x1FFF }, /* R1105  - AIF1 DRC2 (2) */
+       { 0xFFFF, 0xFFFF }, /* R1106  - AIF1 DRC2 (3) */
+       { 0x07FF, 0x07FF }, /* R1107  - AIF1 DRC2 (4) */
+       { 0x03FF, 0x03FF }, /* R1108  - AIF1 DRC2 (5) */
+       { 0x0000, 0x0000 }, /* R1109 */
+       { 0x0000, 0x0000 }, /* R1110 */
+       { 0x0000, 0x0000 }, /* R1111 */
+       { 0x0000, 0x0000 }, /* R1112 */
+       { 0x0000, 0x0000 }, /* R1113 */
+       { 0x0000, 0x0000 }, /* R1114 */
+       { 0x0000, 0x0000 }, /* R1115 */
+       { 0x0000, 0x0000 }, /* R1116 */
+       { 0x0000, 0x0000 }, /* R1117 */
+       { 0x0000, 0x0000 }, /* R1118 */
+       { 0x0000, 0x0000 }, /* R1119 */
+       { 0x0000, 0x0000 }, /* R1120 */
+       { 0x0000, 0x0000 }, /* R1121 */
+       { 0x0000, 0x0000 }, /* R1122 */
+       { 0x0000, 0x0000 }, /* R1123 */
+       { 0x0000, 0x0000 }, /* R1124 */
+       { 0x0000, 0x0000 }, /* R1125 */
+       { 0x0000, 0x0000 }, /* R1126 */
+       { 0x0000, 0x0000 }, /* R1127 */
+       { 0x0000, 0x0000 }, /* R1128 */
+       { 0x0000, 0x0000 }, /* R1129 */
+       { 0x0000, 0x0000 }, /* R1130 */
+       { 0x0000, 0x0000 }, /* R1131 */
+       { 0x0000, 0x0000 }, /* R1132 */
+       { 0x0000, 0x0000 }, /* R1133 */
+       { 0x0000, 0x0000 }, /* R1134 */
+       { 0x0000, 0x0000 }, /* R1135 */
+       { 0x0000, 0x0000 }, /* R1136 */
+       { 0x0000, 0x0000 }, /* R1137 */
+       { 0x0000, 0x0000 }, /* R1138 */
+       { 0x0000, 0x0000 }, /* R1139 */
+       { 0x0000, 0x0000 }, /* R1140 */
+       { 0x0000, 0x0000 }, /* R1141 */
+       { 0x0000, 0x0000 }, /* R1142 */
+       { 0x0000, 0x0000 }, /* R1143 */
+       { 0x0000, 0x0000 }, /* R1144 */
+       { 0x0000, 0x0000 }, /* R1145 */
+       { 0x0000, 0x0000 }, /* R1146 */
+       { 0x0000, 0x0000 }, /* R1147 */
+       { 0x0000, 0x0000 }, /* R1148 */
+       { 0x0000, 0x0000 }, /* R1149 */
+       { 0x0000, 0x0000 }, /* R1150 */
+       { 0x0000, 0x0000 }, /* R1151 */
+       { 0xFFFF, 0xFFFF }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1172 */
+       { 0x0000, 0x0000 }, /* R1173 */
+       { 0x0000, 0x0000 }, /* R1174 */
+       { 0x0000, 0x0000 }, /* R1175 */
+       { 0x0000, 0x0000 }, /* R1176 */
+       { 0x0000, 0x0000 }, /* R1177 */
+       { 0x0000, 0x0000 }, /* R1178 */
+       { 0x0000, 0x0000 }, /* R1179 */
+       { 0x0000, 0x0000 }, /* R1180 */
+       { 0x0000, 0x0000 }, /* R1181 */
+       { 0x0000, 0x0000 }, /* R1182 */
+       { 0x0000, 0x0000 }, /* R1183 */
+       { 0xFFFF, 0xFFFF }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1204 */
+       { 0x0000, 0x0000 }, /* R1205 */
+       { 0x0000, 0x0000 }, /* R1206 */
+       { 0x0000, 0x0000 }, /* R1207 */
+       { 0x0000, 0x0000 }, /* R1208 */
+       { 0x0000, 0x0000 }, /* R1209 */
+       { 0x0000, 0x0000 }, /* R1210 */
+       { 0x0000, 0x0000 }, /* R1211 */
+       { 0x0000, 0x0000 }, /* R1212 */
+       { 0x0000, 0x0000 }, /* R1213 */
+       { 0x0000, 0x0000 }, /* R1214 */
+       { 0x0000, 0x0000 }, /* R1215 */
+       { 0x0000, 0x0000 }, /* R1216 */
+       { 0x0000, 0x0000 }, /* R1217 */
+       { 0x0000, 0x0000 }, /* R1218 */
+       { 0x0000, 0x0000 }, /* R1219 */
+       { 0x0000, 0x0000 }, /* R1220 */
+       { 0x0000, 0x0000 }, /* R1221 */
+       { 0x0000, 0x0000 }, /* R1222 */
+       { 0x0000, 0x0000 }, /* R1223 */
+       { 0x0000, 0x0000 }, /* R1224 */
+       { 0x0000, 0x0000 }, /* R1225 */
+       { 0x0000, 0x0000 }, /* R1226 */
+       { 0x0000, 0x0000 }, /* R1227 */
+       { 0x0000, 0x0000 }, /* R1228 */
+       { 0x0000, 0x0000 }, /* R1229 */
+       { 0x0000, 0x0000 }, /* R1230 */
+       { 0x0000, 0x0000 }, /* R1231 */
+       { 0x0000, 0x0000 }, /* R1232 */
+       { 0x0000, 0x0000 }, /* R1233 */
+       { 0x0000, 0x0000 }, /* R1234 */
+       { 0x0000, 0x0000 }, /* R1235 */
+       { 0x0000, 0x0000 }, /* R1236 */
+       { 0x0000, 0x0000 }, /* R1237 */
+       { 0x0000, 0x0000 }, /* R1238 */
+       { 0x0000, 0x0000 }, /* R1239 */
+       { 0x0000, 0x0000 }, /* R1240 */
+       { 0x0000, 0x0000 }, /* R1241 */
+       { 0x0000, 0x0000 }, /* R1242 */
+       { 0x0000, 0x0000 }, /* R1243 */
+       { 0x0000, 0x0000 }, /* R1244 */
+       { 0x0000, 0x0000 }, /* R1245 */
+       { 0x0000, 0x0000 }, /* R1246 */
+       { 0x0000, 0x0000 }, /* R1247 */
+       { 0x0000, 0x0000 }, /* R1248 */
+       { 0x0000, 0x0000 }, /* R1249 */
+       { 0x0000, 0x0000 }, /* R1250 */
+       { 0x0000, 0x0000 }, /* R1251 */
+       { 0x0000, 0x0000 }, /* R1252 */
+       { 0x0000, 0x0000 }, /* R1253 */
+       { 0x0000, 0x0000 }, /* R1254 */
+       { 0x0000, 0x0000 }, /* R1255 */
+       { 0x0000, 0x0000 }, /* R1256 */
+       { 0x0000, 0x0000 }, /* R1257 */
+       { 0x0000, 0x0000 }, /* R1258 */
+       { 0x0000, 0x0000 }, /* R1259 */
+       { 0x0000, 0x0000 }, /* R1260 */
+       { 0x0000, 0x0000 }, /* R1261 */
+       { 0x0000, 0x0000 }, /* R1262 */
+       { 0x0000, 0x0000 }, /* R1263 */
+       { 0x0000, 0x0000 }, /* R1264 */
+       { 0x0000, 0x0000 }, /* R1265 */
+       { 0x0000, 0x0000 }, /* R1266 */
+       { 0x0000, 0x0000 }, /* R1267 */
+       { 0x0000, 0x0000 }, /* R1268 */
+       { 0x0000, 0x0000 }, /* R1269 */
+       { 0x0000, 0x0000 }, /* R1270 */
+       { 0x0000, 0x0000 }, /* R1271 */
+       { 0x0000, 0x0000 }, /* R1272 */
+       { 0x0000, 0x0000 }, /* R1273 */
+       { 0x0000, 0x0000 }, /* R1274 */
+       { 0x0000, 0x0000 }, /* R1275 */
+       { 0x0000, 0x0000 }, /* R1276 */
+       { 0x0000, 0x0000 }, /* R1277 */
+       { 0x0000, 0x0000 }, /* R1278 */
+       { 0x0000, 0x0000 }, /* R1279 */
+       { 0x00FF, 0x01FF }, /* R1280  - AIF2 ADC Left Volume */
+       { 0x00FF, 0x01FF }, /* R1281  - AIF2 ADC Right Volume */
+       { 0x00FF, 0x01FF }, /* R1282  - AIF2 DAC Left Volume */
+       { 0x00FF, 0x01FF }, /* R1283  - AIF2 DAC Right Volume */
+       { 0x0000, 0x0000 }, /* R1284 */
+       { 0x0000, 0x0000 }, /* R1285 */
+       { 0x0000, 0x0000 }, /* R1286 */
+       { 0x0000, 0x0000 }, /* R1287 */
+       { 0x0000, 0x0000 }, /* R1288 */
+       { 0x0000, 0x0000 }, /* R1289 */
+       { 0x0000, 0x0000 }, /* R1290 */
+       { 0x0000, 0x0000 }, /* R1291 */
+       { 0x0000, 0x0000 }, /* R1292 */
+       { 0x0000, 0x0000 }, /* R1293 */
+       { 0x0000, 0x0000 }, /* R1294 */
+       { 0x0000, 0x0000 }, /* R1295 */
+       { 0xF800, 0xF800 }, /* R1296  - AIF2 ADC Filters */
+       { 0x0000, 0x0000 }, /* R1297 */
+       { 0x0000, 0x0000 }, /* R1298 */
+       { 0x0000, 0x0000 }, /* R1299 */
+       { 0x0000, 0x0000 }, /* R1300 */
+       { 0x0000, 0x0000 }, /* R1301 */
+       { 0x0000, 0x0000 }, /* R1302 */
+       { 0x0000, 0x0000 }, /* R1303 */
+       { 0x0000, 0x0000 }, /* R1304 */
+       { 0x0000, 0x0000 }, /* R1305 */
+       { 0x0000, 0x0000 }, /* R1306 */
+       { 0x0000, 0x0000 }, /* R1307 */
+       { 0x0000, 0x0000 }, /* R1308 */
+       { 0x0000, 0x0000 }, /* R1309 */
+       { 0x0000, 0x0000 }, /* R1310 */
+       { 0x0000, 0x0000 }, /* R1311 */
+       { 0x02B6, 0x02B6 }, /* R1312  - AIF2 DAC Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1313  - AIF2 DAC Filters (2) */
+       { 0x0000, 0x0000 }, /* R1314 */
+       { 0x0000, 0x0000 }, /* R1315 */
+       { 0x0000, 0x0000 }, /* R1316 */
+       { 0x0000, 0x0000 }, /* R1317 */
+       { 0x0000, 0x0000 }, /* R1318 */
+       { 0x0000, 0x0000 }, /* R1319 */
+       { 0x0000, 0x0000 }, /* R1320 */
+       { 0x0000, 0x0000 }, /* R1321 */
+       { 0x0000, 0x0000 }, /* R1322 */
+       { 0x0000, 0x0000 }, /* R1323 */
+       { 0x0000, 0x0000 }, /* R1324 */
+       { 0x0000, 0x0000 }, /* R1325 */
+       { 0x0000, 0x0000 }, /* R1326 */
+       { 0x0000, 0x0000 }, /* R1327 */
+       { 0x0000, 0x0000 }, /* R1328 */
+       { 0x0000, 0x0000 }, /* R1329 */
+       { 0x0000, 0x0000 }, /* R1330 */
+       { 0x0000, 0x0000 }, /* R1331 */
+       { 0x0000, 0x0000 }, /* R1332 */
+       { 0x0000, 0x0000 }, /* R1333 */
+       { 0x0000, 0x0000 }, /* R1334 */
+       { 0x0000, 0x0000 }, /* R1335 */
+       { 0x0000, 0x0000 }, /* R1336 */
+       { 0x0000, 0x0000 }, /* R1337 */
+       { 0x0000, 0x0000 }, /* R1338 */
+       { 0x0000, 0x0000 }, /* R1339 */
+       { 0x0000, 0x0000 }, /* R1340 */
+       { 0x0000, 0x0000 }, /* R1341 */
+       { 0x0000, 0x0000 }, /* R1342 */
+       { 0x0000, 0x0000 }, /* R1343 */
+       { 0xFFFF, 0xFFFF }, /* R1344  - AIF2 DRC (1) */
+       { 0x1FFF, 0x1FFF }, /* R1345  - AIF2 DRC (2) */
+       { 0xFFFF, 0xFFFF }, /* R1346  - AIF2 DRC (3) */
+       { 0x07FF, 0x07FF }, /* R1347  - AIF2 DRC (4) */
+       { 0x03FF, 0x03FF }, /* R1348  - AIF2 DRC (5) */
+       { 0x0000, 0x0000 }, /* R1349 */
+       { 0x0000, 0x0000 }, /* R1350 */
+       { 0x0000, 0x0000 }, /* R1351 */
+       { 0x0000, 0x0000 }, /* R1352 */
+       { 0x0000, 0x0000 }, /* R1353 */
+       { 0x0000, 0x0000 }, /* R1354 */
+       { 0x0000, 0x0000 }, /* R1355 */
+       { 0x0000, 0x0000 }, /* R1356 */
+       { 0x0000, 0x0000 }, /* R1357 */
+       { 0x0000, 0x0000 }, /* R1358 */
+       { 0x0000, 0x0000 }, /* R1359 */
+       { 0x0000, 0x0000 }, /* R1360 */
+       { 0x0000, 0x0000 }, /* R1361 */
+       { 0x0000, 0x0000 }, /* R1362 */
+       { 0x0000, 0x0000 }, /* R1363 */
+       { 0x0000, 0x0000 }, /* R1364 */
+       { 0x0000, 0x0000 }, /* R1365 */
+       { 0x0000, 0x0000 }, /* R1366 */
+       { 0x0000, 0x0000 }, /* R1367 */
+       { 0x0000, 0x0000 }, /* R1368 */
+       { 0x0000, 0x0000 }, /* R1369 */
+       { 0x0000, 0x0000 }, /* R1370 */
+       { 0x0000, 0x0000 }, /* R1371 */
+       { 0x0000, 0x0000 }, /* R1372 */
+       { 0x0000, 0x0000 }, /* R1373 */
+       { 0x0000, 0x0000 }, /* R1374 */
+       { 0x0000, 0x0000 }, /* R1375 */
+       { 0x0000, 0x0000 }, /* R1376 */
+       { 0x0000, 0x0000 }, /* R1377 */
+       { 0x0000, 0x0000 }, /* R1378 */
+       { 0x0000, 0x0000 }, /* R1379 */
+       { 0x0000, 0x0000 }, /* R1380 */
+       { 0x0000, 0x0000 }, /* R1381 */
+       { 0x0000, 0x0000 }, /* R1382 */
+       { 0x0000, 0x0000 }, /* R1383 */
+       { 0x0000, 0x0000 }, /* R1384 */
+       { 0x0000, 0x0000 }, /* R1385 */
+       { 0x0000, 0x0000 }, /* R1386 */
+       { 0x0000, 0x0000 }, /* R1387 */
+       { 0x0000, 0x0000 }, /* R1388 */
+       { 0x0000, 0x0000 }, /* R1389 */
+       { 0x0000, 0x0000 }, /* R1390 */
+       { 0x0000, 0x0000 }, /* R1391 */
+       { 0x0000, 0x0000 }, /* R1392 */
+       { 0x0000, 0x0000 }, /* R1393 */
+       { 0x0000, 0x0000 }, /* R1394 */
+       { 0x0000, 0x0000 }, /* R1395 */
+       { 0x0000, 0x0000 }, /* R1396 */
+       { 0x0000, 0x0000 }, /* R1397 */
+       { 0x0000, 0x0000 }, /* R1398 */
+       { 0x0000, 0x0000 }, /* R1399 */
+       { 0x0000, 0x0000 }, /* R1400 */
+       { 0x0000, 0x0000 }, /* R1401 */
+       { 0x0000, 0x0000 }, /* R1402 */
+       { 0x0000, 0x0000 }, /* R1403 */
+       { 0x0000, 0x0000 }, /* R1404 */
+       { 0x0000, 0x0000 }, /* R1405 */
+       { 0x0000, 0x0000 }, /* R1406 */
+       { 0x0000, 0x0000 }, /* R1407 */
+       { 0xFFFF, 0xFFFF }, /* R1408  - AIF2 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1409  - AIF2 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1410  - AIF2 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1411  - AIF2 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1412  - AIF2 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1413  - AIF2 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1414  - AIF2 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1415  - AIF2 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1416  - AIF2 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1417  - AIF2 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1418  - AIF2 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1419  - AIF2 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1420  - AIF2 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1421  - AIF2 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1422  - AIF2 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1423  - AIF2 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1424  - AIF2 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1425  - AIF2 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1426  - AIF2 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1427  - AIF2 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1428 */
+       { 0x0000, 0x0000 }, /* R1429 */
+       { 0x0000, 0x0000 }, /* R1430 */
+       { 0x0000, 0x0000 }, /* R1431 */
+       { 0x0000, 0x0000 }, /* R1432 */
+       { 0x0000, 0x0000 }, /* R1433 */
+       { 0x0000, 0x0000 }, /* R1434 */
+       { 0x0000, 0x0000 }, /* R1435 */
+       { 0x0000, 0x0000 }, /* R1436 */
+       { 0x0000, 0x0000 }, /* R1437 */
+       { 0x0000, 0x0000 }, /* R1438 */
+       { 0x0000, 0x0000 }, /* R1439 */
+       { 0x0000, 0x0000 }, /* R1440 */
+       { 0x0000, 0x0000 }, /* R1441 */
+       { 0x0000, 0x0000 }, /* R1442 */
+       { 0x0000, 0x0000 }, /* R1443 */
+       { 0x0000, 0x0000 }, /* R1444 */
+       { 0x0000, 0x0000 }, /* R1445 */
+       { 0x0000, 0x0000 }, /* R1446 */
+       { 0x0000, 0x0000 }, /* R1447 */
+       { 0x0000, 0x0000 }, /* R1448 */
+       { 0x0000, 0x0000 }, /* R1449 */
+       { 0x0000, 0x0000 }, /* R1450 */
+       { 0x0000, 0x0000 }, /* R1451 */
+       { 0x0000, 0x0000 }, /* R1452 */
+       { 0x0000, 0x0000 }, /* R1453 */
+       { 0x0000, 0x0000 }, /* R1454 */
+       { 0x0000, 0x0000 }, /* R1455 */
+       { 0x0000, 0x0000 }, /* R1456 */
+       { 0x0000, 0x0000 }, /* R1457 */
+       { 0x0000, 0x0000 }, /* R1458 */
+       { 0x0000, 0x0000 }, /* R1459 */
+       { 0x0000, 0x0000 }, /* R1460 */
+       { 0x0000, 0x0000 }, /* R1461 */
+       { 0x0000, 0x0000 }, /* R1462 */
+       { 0x0000, 0x0000 }, /* R1463 */
+       { 0x0000, 0x0000 }, /* R1464 */
+       { 0x0000, 0x0000 }, /* R1465 */
+       { 0x0000, 0x0000 }, /* R1466 */
+       { 0x0000, 0x0000 }, /* R1467 */
+       { 0x0000, 0x0000 }, /* R1468 */
+       { 0x0000, 0x0000 }, /* R1469 */
+       { 0x0000, 0x0000 }, /* R1470 */
+       { 0x0000, 0x0000 }, /* R1471 */
+       { 0x0000, 0x0000 }, /* R1472 */
+       { 0x0000, 0x0000 }, /* R1473 */
+       { 0x0000, 0x0000 }, /* R1474 */
+       { 0x0000, 0x0000 }, /* R1475 */
+       { 0x0000, 0x0000 }, /* R1476 */
+       { 0x0000, 0x0000 }, /* R1477 */
+       { 0x0000, 0x0000 }, /* R1478 */
+       { 0x0000, 0x0000 }, /* R1479 */
+       { 0x0000, 0x0000 }, /* R1480 */
+       { 0x0000, 0x0000 }, /* R1481 */
+       { 0x0000, 0x0000 }, /* R1482 */
+       { 0x0000, 0x0000 }, /* R1483 */
+       { 0x0000, 0x0000 }, /* R1484 */
+       { 0x0000, 0x0000 }, /* R1485 */
+       { 0x0000, 0x0000 }, /* R1486 */
+       { 0x0000, 0x0000 }, /* R1487 */
+       { 0x0000, 0x0000 }, /* R1488 */
+       { 0x0000, 0x0000 }, /* R1489 */
+       { 0x0000, 0x0000 }, /* R1490 */
+       { 0x0000, 0x0000 }, /* R1491 */
+       { 0x0000, 0x0000 }, /* R1492 */
+       { 0x0000, 0x0000 }, /* R1493 */
+       { 0x0000, 0x0000 }, /* R1494 */
+       { 0x0000, 0x0000 }, /* R1495 */
+       { 0x0000, 0x0000 }, /* R1496 */
+       { 0x0000, 0x0000 }, /* R1497 */
+       { 0x0000, 0x0000 }, /* R1498 */
+       { 0x0000, 0x0000 }, /* R1499 */
+       { 0x0000, 0x0000 }, /* R1500 */
+       { 0x0000, 0x0000 }, /* R1501 */
+       { 0x0000, 0x0000 }, /* R1502 */
+       { 0x0000, 0x0000 }, /* R1503 */
+       { 0x0000, 0x0000 }, /* R1504 */
+       { 0x0000, 0x0000 }, /* R1505 */
+       { 0x0000, 0x0000 }, /* R1506 */
+       { 0x0000, 0x0000 }, /* R1507 */
+       { 0x0000, 0x0000 }, /* R1508 */
+       { 0x0000, 0x0000 }, /* R1509 */
+       { 0x0000, 0x0000 }, /* R1510 */
+       { 0x0000, 0x0000 }, /* R1511 */
+       { 0x0000, 0x0000 }, /* R1512 */
+       { 0x0000, 0x0000 }, /* R1513 */
+       { 0x0000, 0x0000 }, /* R1514 */
+       { 0x0000, 0x0000 }, /* R1515 */
+       { 0x0000, 0x0000 }, /* R1516 */
+       { 0x0000, 0x0000 }, /* R1517 */
+       { 0x0000, 0x0000 }, /* R1518 */
+       { 0x0000, 0x0000 }, /* R1519 */
+       { 0x0000, 0x0000 }, /* R1520 */
+       { 0x0000, 0x0000 }, /* R1521 */
+       { 0x0000, 0x0000 }, /* R1522 */
+       { 0x0000, 0x0000 }, /* R1523 */
+       { 0x0000, 0x0000 }, /* R1524 */
+       { 0x0000, 0x0000 }, /* R1525 */
+       { 0x0000, 0x0000 }, /* R1526 */
+       { 0x0000, 0x0000 }, /* R1527 */
+       { 0x0000, 0x0000 }, /* R1528 */
+       { 0x0000, 0x0000 }, /* R1529 */
+       { 0x0000, 0x0000 }, /* R1530 */
+       { 0x0000, 0x0000 }, /* R1531 */
+       { 0x0000, 0x0000 }, /* R1532 */
+       { 0x0000, 0x0000 }, /* R1533 */
+       { 0x0000, 0x0000 }, /* R1534 */
+       { 0x0000, 0x0000 }, /* R1535 */
+       { 0x01EF, 0x01EF }, /* R1536  - DAC1 Mixer Volumes */
+       { 0x0037, 0x0037 }, /* R1537  - DAC1 Left Mixer Routing */
+       { 0x0037, 0x0037 }, /* R1538  - DAC1 Right Mixer Routing */
+       { 0x01EF, 0x01EF }, /* R1539  - DAC2 Mixer Volumes */
+       { 0x0037, 0x0037 }, /* R1540  - DAC2 Left Mixer Routing */
+       { 0x0037, 0x0037 }, /* R1541  - DAC2 Right Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
+       { 0x0000, 0x0000 }, /* R1546 */
+       { 0x0000, 0x0000 }, /* R1547 */
+       { 0x0000, 0x0000 }, /* R1548 */
+       { 0x0000, 0x0000 }, /* R1549 */
+       { 0x0000, 0x0000 }, /* R1550 */
+       { 0x0000, 0x0000 }, /* R1551 */
+       { 0x02FF, 0x03FF }, /* R1552  - DAC1 Left Volume */
+       { 0x02FF, 0x03FF }, /* R1553  - DAC1 Right Volume */
+       { 0x02FF, 0x03FF }, /* R1554  - DAC2 Left Volume */
+       { 0x02FF, 0x03FF }, /* R1555  - DAC2 Right Volume */
+       { 0x0003, 0x0003 }, /* R1556  - DAC Softmute */
+       { 0x0000, 0x0000 }, /* R1557 */
+       { 0x0000, 0x0000 }, /* R1558 */
+       { 0x0000, 0x0000 }, /* R1559 */
+       { 0x0000, 0x0000 }, /* R1560 */
+       { 0x0000, 0x0000 }, /* R1561 */
+       { 0x0000, 0x0000 }, /* R1562 */
+       { 0x0000, 0x0000 }, /* R1563 */
+       { 0x0000, 0x0000 }, /* R1564 */
+       { 0x0000, 0x0000 }, /* R1565 */
+       { 0x0000, 0x0000 }, /* R1566 */
+       { 0x0000, 0x0000 }, /* R1567 */
+       { 0x0003, 0x0003 }, /* R1568  - Oversampling */
+       { 0x03C3, 0x03C3 }, /* R1569  - Sidetone */
 };
 
 static int wm8994_readable(unsigned int reg)
@@ -1902,8 +1900,6 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
        return snd_soc_put_volsw(kcontrol, ucontrol);
 }
 
-
-
 static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1942,7 +1938,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_pdata *pdata = wm8994->pdata;
        int drc = wm8994_get_drc(kcontrol->id.name);
        int value = ucontrol->value.integer.value[0];
@@ -2045,7 +2041,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_pdata *pdata = wm8994->pdata;
        int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
        int value = ucontrol->value.integer.value[0];
@@ -2067,7 +2063,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
        int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
 
        ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -2075,6 +2071,22 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static const char *aifdac_src_text[] = {
+       "Left", "Right"
+};
+
+static const struct soc_enum aif1dacl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif1dacr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aifdac_src_text);
+
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
                 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -2086,6 +2098,11 @@ SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
                 WM8994_AIF2_ADC_RIGHT_VOLUME,
                 1, 119, 0, digital_tlv),
 
+SOC_ENUM("AIF1DACL Source", aif1dacl_src),
+SOC_ENUM("AIF1DACR Source", aif1dacr_src),
+SOC_ENUM("AIF2DACL Source", aif1dacl_src),
+SOC_ENUM("AIF2DACR Source", aif1dacr_src),
+
 SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
                 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
@@ -2881,10 +2898,9 @@ static int wm8994_get_fll_config(struct fll_div *fll,
        return 0;
 }
 
-static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                          unsigned int freq_in, unsigned int freq_out)
 {
-       struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int reg_offset, ret;
        struct fll_div fll;
@@ -2995,8 +3011,15 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
        return 0;
 }
 
+
 static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
 
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+                         unsigned int freq_in, unsigned int freq_out)
+{
+       return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
+}
+
 static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir)
 {
@@ -3313,20 +3336,24 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                bclk_reg = WM8994_AIF1_BCLK;
                rate_reg = WM8994_AIF1_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   wm8994->lrclk_shared[0])
+                   wm8994->lrclk_shared[0]) {
                        lrclk_reg = WM8994_AIF1DAC_LRCLK;
-               else
+               } else {
                        lrclk_reg = WM8994_AIF1ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+               }
                break;
        case 2:
                aif1_reg = WM8994_AIF2_CONTROL_1;
                bclk_reg = WM8994_AIF2_BCLK;
                rate_reg = WM8994_AIF2_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   wm8994->lrclk_shared[1])
+                   wm8994->lrclk_shared[1]) {
                        lrclk_reg = WM8994_AIF2DAC_LRCLK;
-               else
+               } else {
                        lrclk_reg = WM8994_AIF2ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+               }
                break;
        default:
                return -EINVAL;
@@ -3491,7 +3518,7 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 #define WM8994_RATES SNDRV_PCM_RATE_8000_96000
 
 #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
-                       SNDRV_PCM_FMTBIT_S24_LE)
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
@@ -3515,9 +3542,9 @@ static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
        .set_tristate   = wm8994_set_tristate,
 };
 
-struct snd_soc_dai wm8994_dai[] = {
+static struct snd_soc_dai_driver wm8994_dai[] = {
        {
-               .name = "WM8994 AIF1",
+               .name = "wm8994-aif1",
                .id = 1,
                .playback = {
                        .stream_name = "AIF1 Playback",
@@ -3536,7 +3563,7 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif1_dai_ops,
        },
        {
-               .name = "WM8994 AIF2",
+               .name = "wm8994-aif2",
                .id = 2,
                .playback = {
                        .stream_name = "AIF2 Playback",
@@ -3555,7 +3582,7 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif2_dai_ops,
        },
        {
-               .name = "WM8994 AIF3",
+               .name = "wm8994-aif3",
                .id = 3,
                .playback = {
                        .stream_name = "AIF3 Playback",
@@ -3574,20 +3601,17 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif3_dai_ops,
        }
 };
-EXPORT_SYMBOL_GPL(wm8994_dai);
 
 #ifdef CONFIG_PM
-static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
                       sizeof(struct fll_config));
-               ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0);
+               ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
                if (ret < 0)
                        dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
                                 i + 1, ret);
@@ -3598,10 +3622,8 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8994_resume(struct platform_device *pdev)
+static int wm8994_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        u16 *reg_cache = codec->reg_cache;
        int i, ret;
@@ -3630,7 +3652,7 @@ static int wm8994_resume(struct platform_device *pdev)
                if (!wm8994->fll_suspend[i].out)
                        continue;
 
-               ret = wm8994_set_fll(&codec->dai[0], i + 1,
+               ret = _wm8994_set_fll(codec, i + 1,
                                     wm8994->fll_suspend[i].src,
                                     wm8994->fll_suspend[i].in,
                                     wm8994->fll_suspend[i].out);
@@ -3648,7 +3670,7 @@ static int wm8994_resume(struct platform_device *pdev)
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        struct snd_kcontrol_new controls[] = {
                SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3706,16 +3728,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
        wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
        wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-       ret = snd_soc_add_controls(&wm8994->codec, controls,
+       ret = snd_soc_add_controls(wm8994->codec, controls,
                                   ARRAY_SIZE(controls));
        if (ret != 0)
-               dev_err(wm8994->codec.dev,
+               dev_err(wm8994->codec->dev,
                        "Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        int ret, i;
 
@@ -3747,7 +3769,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8994->drc_texts) {
-                       dev_err(wm8994->codec.dev,
+                       dev_err(wm8994->codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -3759,10 +3781,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_enum.max = pdata->num_drc_cfgs;
                wm8994->drc_enum.texts = wm8994->drc_texts;
 
-               ret = snd_soc_add_controls(&wm8994->codec, controls,
+               ret = snd_soc_add_controls(wm8994->codec, controls,
                                           ARRAY_SIZE(controls));
                if (ret != 0)
-                       dev_err(wm8994->codec.dev,
+                       dev_err(wm8994->codec->dev,
                                "Failed to add DRC mode controls: %d\n", ret);
 
                for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3775,62 +3797,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
-               snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls,
+               snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
                                     ARRAY_SIZE(wm8994_eq_controls));
 }
 
-static int wm8994_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8994_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8994_codec;
-       codec = wm8994_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               return ret;
-       }
-
-       wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
-       wm_hubs_add_analogue_controls(codec);
-       snd_soc_add_controls(codec, wm8994_snd_controls,
-                            ARRAY_SIZE(wm8994_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
-                                 ARRAY_SIZE(wm8994_dapm_widgets));
-       wm_hubs_add_analogue_routes(codec, 0, 0);
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
-static int wm8994_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8994 = {
-       .probe =        wm8994_probe,
-       .remove =       wm8994_remove,
-       .suspend =      wm8994_suspend,
-       .resume =       wm8994_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
-
 /**
  * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
  *
@@ -3842,7 +3812,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
  *
  * Enable microphone detection via IRQ on the WM8994.  If GPIOs are
  * being used to bring out signals to the processor then only platform
- * data configuration is needed for WM8903 and processor GPIOs should
+ * data configuration is needed for WM8994 and processor GPIOs should
  * be configured using snd_soc_jack_add_gpios() instead.
  *
  * Configuration of detection levels is available via the micbias1_lvl
@@ -3889,7 +3859,7 @@ EXPORT_SYMBOL_GPL(wm8994_mic_detect);
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = &priv->codec;
+       struct snd_soc_codec *codec = priv->codec;
        int reg;
        int report;
 
@@ -3921,46 +3891,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int wm8994_codec_probe(struct platform_device *pdev)
+static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct wm8994_priv *wm8994;
-       struct snd_soc_codec *codec;
-       int i;
+       int ret, i;
 
-       if (wm8994_codec) {
-               dev_err(&pdev->dev, "Another WM8994 is registered\n");
-               return -EINVAL;
-       }
+       codec->control_data = dev_get_drvdata(codec->dev->parent);
 
        wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
-       if (!wm8994) {
-               dev_err(&pdev->dev, "Failed to allocate private data\n");
+       if (wm8994 == NULL)
                return -ENOMEM;
-       }
-
-       codec = &wm8994->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        snd_soc_codec_set_drvdata(codec, wm8994);
-       codec->control_data = dev_get_drvdata(pdev->dev.parent);
-       codec->name = "WM8994";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8994_read;
-       codec->write = wm8994_write;
-       codec->readable_register = wm8994_readable;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8994_set_bias_level;
-       codec->dai = &wm8994_dai[0];
-       codec->num_dai = 3;
-       codec->reg_cache_size = WM8994_MAX_REGISTER;
-       codec->reg_cache = &wm8994->reg_cache;
-       codec->dev = &pdev->dev;
-
-       wm8994->pdata = pdev->dev.parent->platform_data;
+
+       wm8994->pdata = dev_get_platdata(codec->dev->parent);
+       wm8994->codec = codec;
 
        /* Fill the cache with physical values we inherited; don't reset */
        ret = wm8994_bulk_read(codec->control_data, 0,
@@ -3996,25 +3940,25 @@ static int wm8994_codec_probe(struct platform_device *pdev)
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
                                 wm8994_mic_irq, "Mic 1 detect", wm8994);
        if (ret != 0)
-               dev_warn(&pdev->dev,
+               dev_warn(codec->dev,
                         "Failed to request Mic1 detect IRQ: %d\n", ret);
 
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
                                 wm8994_mic_irq, "Mic 1 short", wm8994);
        if (ret != 0)
-               dev_warn(&pdev->dev,
+               dev_warn(codec->dev,
                         "Failed to request Mic1 short IRQ: %d\n", ret);
 
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
                                 wm8994_mic_irq, "Mic 2 detect", wm8994);
        if (ret != 0)
-               dev_warn(&pdev->dev,
+               dev_warn(codec->dev,
                         "Failed to request Mic2 detect IRQ: %d\n", ret);
 
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
                                 wm8994_mic_irq, "Mic 2 short", wm8994);
        if (ret != 0)
-               dev_warn(&pdev->dev,
+               dev_warn(codec->dev,
                         "Failed to request Mic2 short IRQ: %d\n", ret);
 
        /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
@@ -4045,13 +3989,8 @@ static int wm8994_codec_probe(struct platform_device *pdev)
                wm8994->lrclk_shared[1] = 0;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++)
-               wm8994_dai[i].dev = codec->dev;
-
        wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8994_codec = codec;
-
        /* Latch volume updates (right only; we always do left then right). */
        snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
                            WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
@@ -4088,24 +4027,18 @@ static int wm8994_codec_probe(struct platform_device *pdev)
 
        wm8994_update_class_w(codec);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_irq;
-       }
-
-       ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
+       wm8994_handle_pdata(wm8994);
 
-       platform_set_drvdata(pdev, wm8994);
+       wm_hubs_add_analogue_controls(codec);
+       snd_soc_add_controls(codec, wm8994_snd_controls,
+                            ARRAY_SIZE(wm8994_snd_controls));
+       snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
+                                 ARRAY_SIZE(wm8994_dapm_widgets));
+       wm_hubs_add_analogue_routes(codec, 0, 0);
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_irq:
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
@@ -4116,31 +4049,50 @@ err:
        return ret;
 }
 
-static int __devexit wm8994_codec_remove(struct platform_device *pdev)
+static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
-       struct wm8994_priv *wm8994 = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
-       snd_soc_unregister_codec(&wm8994->codec);
+
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
        kfree(wm8994);
-       wm8994_codec = NULL;
 
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
+       .probe =        wm8994_codec_probe,
+       .remove =       wm8994_codec_remove,
+       .suspend =      wm8994_suspend,
+       .resume =       wm8994_resume,
+       .read = wm8994_read,
+       .write = wm8994_write,
+       .set_bias_level = wm8994_set_bias_level,
+};
+
+static int __devinit wm8994_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
+                       wm8994_dai, ARRAY_SIZE(wm8994_dai));
+}
+
+static int __devexit wm8994_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
 static struct platform_driver wm8994_codec_driver = {
        .driver = {
                   .name = "wm8994-codec",
                   .owner = THIS_MODULE,
                   },
-       .probe = wm8994_codec_probe,
-       .remove = __devexit_p(wm8994_codec_remove),
+       .probe = wm8994_probe,
+       .remove = __devexit_p(wm8994_remove),
 };
 
 static __init int wm8994_init(void)
index 2e0ca67a8df7ad8f83c83c822190ae09d9395acf..d8dce260c430c31fa7544a63d5202a01aab10566 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_codec_device soc_codec_dev_wm8994;
-extern struct snd_soc_dai wm8994_dai[];
-
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
 #define WM8994_SYSCLK_MCLK2 2
index 76b37ff6c264915c3c4fdc470ebdfe2c3ec1cc0a..ecc7c37180c7ad2158f11b9de1579bde332cb44d 100644 (file)
@@ -156,7 +156,8 @@ static struct {
 };
 
 struct wm9081_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u16 reg_cache[WM9081_MAX_REGISTER + 1];
        int sysclk_source;
        int mclk_rate;
@@ -1212,8 +1213,8 @@ static struct snd_soc_dai_ops wm9081_dai_ops = {
 /* We report two channels because the CODEC processes a stereo signal, even
  * though it is only capable of handling a mono output.
  */
-struct snd_soc_dai wm9081_dai = {
-       .name = "WM9081",
+static struct snd_soc_dai_driver wm9081_dai = {
+       .name = "wm9081-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1223,34 +1224,42 @@ struct snd_soc_dai wm9081_dai = {
        },
        .ops = &wm9081_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm9081_dai);
 
-
-static struct snd_soc_codec *wm9081_codec;
-
-static int wm9081_probe(struct platform_device *pdev)
+static int wm9081_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm9081_priv *wm9081;
-       int ret = 0;
+       struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+       u16 reg;
 
-       if (wm9081_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = wm9081->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm9081_codec;
-       codec = wm9081_codec;
-       wm9081 = snd_soc_codec_get_drvdata(codec);
+       reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
+       if (reg != 0x9081) {
+               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+               ret = -EINVAL;
+               return ret;
+       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm9081_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Enable zero cross by default */
+       reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
+       snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+       reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+       snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+                    reg | WM9081_SPKPGAZC);
+
        snd_soc_add_controls(codec, wm9081_snd_controls,
                             ARRAY_SIZE(wm9081_snd_controls));
        if (!wm9081->retune) {
@@ -1265,40 +1274,28 @@ static int wm9081_probe(struct platform_device *pdev)
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
-static int wm9081_remove(struct platform_device *pdev)
+static int wm9081_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int wm9081_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm9081_resume(struct platform_device *pdev)
+static int wm9081_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 *reg_cache = codec->reg_cache;
        int i;
 
-       for (i = 0; i < codec->reg_cache_size; i++) {
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
                if (i == WM9081_SOFTWARE_RESET)
                        continue;
 
@@ -1314,133 +1311,43 @@ static int wm9081_resume(struct platform_device *pdev)
 #define wm9081_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
        .probe =        wm9081_probe,
        .remove =       wm9081_remove,
        .suspend =      wm9081_suspend,
        .resume =       wm9081_resume,
+       .set_bias_level = wm9081_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm9081_reg_defaults,
+       .volatile_register = wm9081_volatile_register,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
-
-static int wm9081_register(struct wm9081_priv *wm9081,
-                          enum snd_soc_control_type control)
-{
-       struct snd_soc_codec *codec = &wm9081->codec;
-       int ret;
-       u16 reg;
-
-       if (wm9081_codec) {
-               dev_err(codec->dev, "Another WM9081 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm9081);
-       codec->name = "WM9081";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm9081_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
-       codec->reg_cache = &wm9081->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm9081_set_bias_level;
-       codec->volatile_register = wm9081_volatile_register;
-
-       memcpy(codec->reg_cache, wm9081_reg_defaults,
-              sizeof(wm9081_reg_defaults));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
-       if (reg != 0x9081) {
-               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = wm9081_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
-       }
-
-       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* Enable zero cross by default */
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
-       snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
-       snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
-                    reg | WM9081_SPKPGAZC);
-
-       wm9081_dai.dev = codec->dev;
-
-       wm9081_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm9081_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm9081);
-       return ret;
-}
-
-static void wm9081_unregister(struct wm9081_priv *wm9081)
-{
-       wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm9081_dai);
-       snd_soc_unregister_codec(&wm9081->codec);
-       kfree(wm9081);
-       wm9081_codec = NULL;
-}
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm9081_priv *wm9081;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
        if (wm9081 == NULL)
                return -ENOMEM;
 
-       codec = &wm9081->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-       wm9081->retune = i2c->dev.platform_data;
-
        i2c_set_clientdata(i2c, wm9081);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm9081->control_data = i2c;
 
-       return wm9081_register(wm9081, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm9081, &wm9081_dai, 1);
+       if (ret < 0)
+               kfree(wm9081);
+       return ret;
 }
 
 static __devexit int wm9081_i2c_remove(struct i2c_client *client)
 {
-       struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
-       wm9081_unregister(wm9081);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1452,31 +1359,34 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
 
 static struct i2c_driver wm9081_i2c_driver = {
        .driver = {
-               .name = "wm9081",
+               .name = "wm9081-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm9081_i2c_probe,
        .remove =   __devexit_p(wm9081_i2c_remove),
        .id_table = wm9081_i2c_id,
 };
+#endif
 
 static int __init wm9081_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm9081_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm9081_modinit);
 
 static void __exit wm9081_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm9081_i2c_driver);
+#endif
 }
 module_exit(wm9081_exit);
 
index 42d3bc757021f554b1f94f44b02e01f4d4496142..871cccb066dcbeba2f6b83a265ffaed86135e19f 100644 (file)
@@ -15,9 +15,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_dai wm9081_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm9081;
-
 /*
  * SYSCLK sources
  */
index 1592250daec0ff0eda0896536d2a8d1234951b17..7a1825418ee49a47d0d4bcbbb8ce8b28d298b143 100644 (file)
@@ -34,8 +34,6 @@
 
 #include "wm9090.h"
 
-static struct snd_soc_codec *wm9090_codec;
-
 static const u16 wm9090_reg_defaults[] = {
        0x9093,     /* R0   - Software Reset */
        0x0006,     /* R1   - Power Management (1) */
@@ -142,15 +140,10 @@ static const u16 wm9090_reg_defaults[] = {
 
 /* This struct is used to save the context */
 struct wm9090_priv {
-       /* We're not really registering as a CODEC since ASoC core
-        * does not yet support multiple CODECs but having the CODEC
-        * structure means we can reuse some of the ASoC core
-        * features.
-        */
-       struct snd_soc_codec codec;
        struct mutex mutex;
        u16 reg_cache[WM9090_MAX_REGISTER + 1];
        struct wm9090_platform_data pdata;
+       void *control_data;
 };
 
 static int wm9090_volatile(unsigned int reg)
@@ -523,7 +516,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (codec->bias_level == SND_SOC_BIAS_OFF) {
                        /* Restore the register cache */
-                       for (i = 1; i < codec->reg_cache_size; i++) {
+                       for (i = 1; i < codec->driver->reg_cache_size; i++) {
                                if (reg_cache[i] == wm9090_reg_defaults[i])
                                        continue;
                                if (wm9090_volatile(i))
@@ -556,51 +549,67 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9090_probe(struct platform_device *pdev)
+static int wm9090_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (wm9090_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = wm9090->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm9090_codec;
-       codec = wm9090_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+       ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
+       if (ret < 0)
+               return ret;
+       if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret);
+               return -EINVAL;
        }
 
+       ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+       if (ret < 0)
+               return ret;
+
+       /* Configure some defaults; they will be written out when we
+        * bring the bias up.
+        */
+       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
+               | WM9090_IN1A_ZC;
+       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
+               | WM9090_IN1B_ZC;
+       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
+               | WM9090_IN2A_ZC;
+       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
+               | WM9090_IN2B_ZC;
+       wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
+               WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
+       wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+               WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
+       wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
+               WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
+
+       wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+
+       wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        wm9090_add_controls(codec);
 
        return 0;
-
-pcm_err:
-       return ret;
 }
 
 #ifdef CONFIG_PM
-static int wm9090_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm9090_resume(struct platform_device *pdev)
+static int wm9090_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -610,29 +619,29 @@ static int wm9090_resume(struct platform_device *pdev)
 #define wm9090_resume NULL
 #endif
 
-static int wm9090_remove(struct platform_device *pdev)
+static int wm9090_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9090 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
        .probe =        wm9090_probe,
        .remove =       wm9090_remove,
        .suspend =      wm9090_suspend,
        .resume =       wm9090_resume,
+       .set_bias_level = wm9090_set_bias_level,
+       .reg_cache_size = (WM9090_MAX_REGISTER + 1),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm9090_reg_defaults,
+       .volatile_register = wm9090_volatile,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090);
 
 static int wm9090_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm9090_priv *wm9090;
-       struct snd_soc_codec *codec;
        int ret;
 
        wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
@@ -640,102 +649,28 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev, "Can not allocate memory\n");
                return -ENOMEM;
        }
-       codec = &wm9090->codec;
 
        if (i2c->dev.platform_data)
                memcpy(&wm9090->pdata, i2c->dev.platform_data,
                       sizeof(wm9090->pdata));
 
-       wm9090_codec = codec;
-
        i2c_set_clientdata(i2c, wm9090);
+       wm9090->control_data = i2c;
+       mutex_init(&wm9090->mutex);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->control_data = i2c;
-       snd_soc_codec_set_drvdata(codec, wm9090);
-       codec->dev = &i2c->dev;
-       codec->name = "WM9090";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm9090_set_bias_level,
-       codec->reg_cache_size = WM9090_MAX_REGISTER + 1;
-       codec->reg_cache = &wm9090->reg_cache;
-       codec->volatile_register = wm9090_volatile;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       memcpy(&wm9090->reg_cache, wm9090_reg_defaults,
-              sizeof(wm9090->reg_cache));
-
-       ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
-       if (ret < 0)
-               goto err;
-       if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
-               dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm9090,  NULL, 0);
        if (ret < 0)
-               goto err;
-
-       /* Configure some defaults; they will be written out when we
-        * bring the bias up.
-        */
-       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
-               | WM9090_IN1A_ZC;
-       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
-               | WM9090_IN1B_ZC;
-       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
-               | WM9090_IN2A_ZC;
-       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
-               | WM9090_IN2B_ZC;
-       wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
-               WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
-       wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= 
-               WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
-       wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
-               WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
-
-       wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
-
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
-               goto err_bias;
-       }
-
-       return 0;
-
-err_bias:
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err:
-       kfree(wm9090);
-       i2c_set_clientdata(i2c, NULL);
-       wm9090_codec = NULL;
-
+               kfree(wm9090);
        return ret;
 }
 
 static int wm9090_i2c_remove(struct i2c_client *i2c)
 {
        struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
-       struct snd_soc_codec *codec = &wm9090->codec;
 
-       snd_soc_unregister_codec(codec);
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_codec(&i2c->dev);
        kfree(wm9090);
-       wm9090_codec = NULL;
 
        return 0;
 }
@@ -748,7 +683,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id);
 
 static struct i2c_driver wm9090_i2c_driver = {
        .driver = {
-               .name = "wm9090",
+               .name = "wm9090-codec",
                .owner = THIS_MODULE,
        },
        .probe = wm9090_i2c_probe,
index b08eab932a5b795ed037f7dac8843f88fa2eb172..29b9d9fc70b4cc20501d2529cfcbcc6c949dffdb 100644 (file)
@@ -23,8 +23,6 @@
 #ifndef __WM9090_H
 #define __WM9090_H
 
-extern struct snd_soc_codec_device soc_codec_dev_wm9090;
-
 /*
  * Register values.
  */
index 8793341849d1bafdc2e13f1c7564bd655cf440fe..a144acda751cb7578954abe12310a0759bd1dec4 100644 (file)
@@ -248,8 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        int reg;
        u16 vra;
 
@@ -273,9 +272,9 @@ static struct snd_soc_dai_ops wm9705_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
-struct snd_soc_dai wm9705_dai[] = {
+static struct snd_soc_dai_driver wm9705_dai[] = {
        {
-               .name = "AC97 HiFi",
+               .name = "wm9705-hifi",
                .ac97_control = 1,
                .playback = {
                        .stream_name = "HiFi Playback",
@@ -294,7 +293,7 @@ struct snd_soc_dai wm9705_dai[] = {
                .ops = &wm9705_dai_ops,
        },
        {
-               .name = "AC97 Aux",
+               .name = "wm9705-aux",
                .playback = {
                        .stream_name = "Aux Playback",
                        .channels_min = 1,
@@ -304,7 +303,6 @@ struct snd_soc_dai wm9705_dai[] = {
                },
        }
 };
-EXPORT_SYMBOL_GPL(wm9705_dai);
 
 static int wm9705_reset(struct snd_soc_codec *codec)
 {
@@ -318,20 +316,15 @@ static int wm9705_reset(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
 
        return 0;
 }
 
-static int wm9705_soc_resume(struct platform_device *pdev)
+static int wm9705_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i, ret;
        u16 *cache = codec->reg_cache;
 
@@ -352,49 +345,18 @@ static int wm9705_soc_resume(struct platform_device *pdev)
 #define wm9705_soc_resume NULL
 #endif
 
-static int wm9705_soc_probe(struct platform_device *pdev)
+static int wm9705_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "WM9705 SoC Audio Codec\n");
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9705_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "WM9705";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9705_dai;
-       codec->num_dai = ARRAY_SIZE(wm9705_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        ret = wm9705_reset(codec);
        if (ret)
                goto reset_err;
@@ -406,40 +368,62 @@ static int wm9705_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-codec_err:
-       kfree(codec->reg_cache);
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int wm9705_soc_remove(struct platform_device *pdev)
+static int wm9705_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
        .probe =        wm9705_soc_probe,
        .remove =       wm9705_soc_remove,
        .suspend =      wm9705_soc_suspend,
        .resume =       wm9705_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .reg_cache_size = ARRAY_SIZE(wm9705_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9705_reg,
+};
+
+static __devinit int wm9705_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
+}
+
+static int __devexit wm9705_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9705_codec_driver = {
+       .driver = {
+                       .name = "wm9705-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9705_probe,
+       .remove = __devexit_p(wm9705_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+static int __init wm9705_init(void)
+{
+       return platform_driver_register(&wm9705_codec_driver);
+}
+module_init(wm9705_init);
+
+static void __exit wm9705_exit(void)
+{
+       platform_driver_unregister(&wm9705_codec_driver);
+}
+module_exit(wm9705_exit);
 
 MODULE_DESCRIPTION("ASoC WM9705 driver");
 MODULE_AUTHOR("Ian Molton");
index d380f110f9e29c311f4ecbe83986fa6750ccb03b..23ea9ce473593b09e1ad753d271dc55f732c73df 100644 (file)
@@ -8,7 +8,4 @@
 #define WM9705_DAI_AC97_HIFI   0
 #define WM9705_DAI_AC97_AUX    1
 
-extern struct snd_soc_dai wm9705_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9705;
-
 #endif
index 28790a2ffe8dab5c5663059bebadf4a491b3fdc2..d2f224d62744011dba3e2536edd05a87c17aa3b0 100644 (file)
@@ -478,8 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        int reg;
        u16 vra;
 
@@ -499,8 +498,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 vra, xsle;
 
        vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -526,9 +524,9 @@ static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
        .prepare        = ac97_aux_prepare,
 };
 
-struct snd_soc_dai wm9712_dai[] = {
+static struct snd_soc_dai_driver wm9712_dai[] = {
 {
-       .name = "AC97 HiFi",
+       .name = "wm9712-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "HiFi Playback",
@@ -545,7 +543,7 @@ struct snd_soc_dai wm9712_dai[] = {
        .ops = &wm9712_dai_ops_hifi,
 },
 {
-       .name = "AC97 Aux",
+       .name = "wm9712-aux",
        .playback = {
                .stream_name = "Aux Playback",
                .channels_min = 1,
@@ -555,7 +553,6 @@ struct snd_soc_dai wm9712_dai[] = {
        .ops = &wm9712_dai_ops_aux,
 }
 };
-EXPORT_SYMBOL_GPL(wm9712_dai);
 
 static int wm9712_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
@@ -597,20 +594,15 @@ err:
        return -EIO;
 }
 
-static int wm9712_soc_suspend(struct platform_device *pdev,
+static int wm9712_soc_suspend(struct snd_soc_codec *codec,
        pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm9712_soc_resume(struct platform_device *pdev)
+static int wm9712_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i, ret;
        u16 *cache = codec->reg_cache;
 
@@ -635,51 +627,18 @@ static int wm9712_soc_resume(struct platform_device *pdev)
        return ret;
 }
 
-static int wm9712_soc_probe(struct platform_device *pdev)
+static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9712_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "WM9712";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9712_dai;
-       codec->num_dai = ARRAY_SIZE(wm9712_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       codec->set_bias_level = wm9712_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        ret = wm9712_reset(codec, 0);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
@@ -697,42 +656,63 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
-codec_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int wm9712_soc_remove(struct platform_device *pdev)
+static int wm9712_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
        .probe =        wm9712_soc_probe,
        .remove =       wm9712_soc_remove,
        .suspend =      wm9712_soc_suspend,
        .resume =       wm9712_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .set_bias_level = wm9712_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9712_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9712_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+static __devinit int wm9712_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
+}
+
+static int __devexit wm9712_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9712_codec_driver = {
+       .driver = {
+                       .name = "wm9712-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9712_probe,
+       .remove = __devexit_p(wm9712_remove),
+};
+
+static int __init wm9712_init(void)
+{
+       return platform_driver_register(&wm9712_codec_driver);
+}
+module_init(wm9712_init);
+
+static void __exit wm9712_exit(void)
+{
+       platform_driver_unregister(&wm9712_codec_driver);
+}
+module_exit(wm9712_exit);
 
 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
 MODULE_AUTHOR("Liam Girdwood");
index d29e8a18ca6d2abc6aa67d1c717f571978703a82..fb69c3aa4ed01d1f554c1f27b8267d5a0806be24 100644 (file)
@@ -8,7 +8,4 @@
 #define WM9712_DAI_AC97_HIFI   0
 #define WM9712_DAI_AC97_AUX            1
 
-extern struct snd_soc_dai wm9712_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9712;
-
 #endif
index 34e0c91092fa1f2cd7e03c0905a0b30fd404250c..7da13b07a53dfdbc5559e9eb21f140334145ed10 100644 (file)
@@ -1057,9 +1057,9 @@ static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
        .set_tristate   = wm9713_set_dai_tristate,
 };
 
-struct snd_soc_dai wm9713_dai[] = {
+static struct snd_soc_dai_driver wm9713_dai[] = {
 {
-       .name = "AC97 HiFi",
+       .name = "wm9713-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "HiFi Playback",
@@ -1076,7 +1076,7 @@ struct snd_soc_dai wm9713_dai[] = {
        .ops = &wm9713_dai_ops_hifi,
        },
        {
-       .name = "AC97 Aux",
+       .name = "wm9713-aux",
        .playback = {
                .stream_name = "Aux Playback",
                .channels_min = 1,
@@ -1086,7 +1086,7 @@ struct snd_soc_dai wm9713_dai[] = {
        .ops = &wm9713_dai_ops_aux,
        },
        {
-       .name = "WM9713 Voice",
+       .name = "wm9713-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1103,7 +1103,6 @@ struct snd_soc_dai wm9713_dai[] = {
        .symmetric_rates = 1,
        },
 };
-EXPORT_SYMBOL_GPL(wm9713_dai);
 
 int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
 {
@@ -1152,11 +1151,9 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9713_soc_suspend(struct platform_device *pdev,
+static int wm9713_soc_suspend(struct snd_soc_codec *codec,
        pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Disable everything except touchpanel - that will be handled
@@ -1171,10 +1168,8 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
        return 0;
 }
 
-static int wm9713_soc_resume(struct platform_device *pdev)
+static int wm9713_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
        u16 *cache = codec->reg_cache;
@@ -1204,53 +1199,20 @@ static int wm9713_soc_resume(struct platform_device *pdev)
        return ret;
 }
 
-static int wm9713_soc_probe(struct platform_device *pdev)
+static int wm9713_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm9713_priv *wm9713;
        int ret = 0, reg;
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
+       wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
+       if (wm9713 == NULL)
                return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9713_reg);
-       codec->reg_cache_step = 2;
-
-       snd_soc_codec_set_drvdata(codec, kzalloc(sizeof(struct wm9713_priv),
-                                                GFP_KERNEL));
-       if (snd_soc_codec_get_drvdata(codec) == NULL) {
-               ret = -ENOMEM;
-               goto priv_err;
-       }
-
-       codec->name = "WM9713";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9713_dai;
-       codec->num_dai = ARRAY_SIZE(wm9713_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       codec->set_bias_level = wm9713_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
+       snd_soc_codec_set_drvdata(codec, wm9713);
 
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        /* do a cold reset for the controller and then try
         * a warm reset followed by an optional cold reset for codec */
        wm9713_reset(codec, 0);
@@ -1273,46 +1235,67 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
 codec_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-
-priv_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
+       kfree(wm9713);
        return ret;
 }
 
-static int wm9713_soc_remove(struct platform_device *pdev)
+static int wm9713_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
+       struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
        snd_soc_free_ac97_codec(codec);
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec->reg_cache);
-       kfree(codec);
+       kfree(wm9713);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9713 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
        .probe =        wm9713_soc_probe,
        .remove =       wm9713_soc_remove,
        .suspend =      wm9713_soc_suspend,
        .resume =       wm9713_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .set_bias_level = wm9713_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9713_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9713_reg,
+};
+
+static __devinit int wm9713_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
+}
+
+static int __devexit wm9713_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9713_codec_driver = {
+       .driver = {
+                       .name = "wm9713-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9713_probe,
+       .remove = __devexit_p(wm9713_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713);
+
+static int __init wm9713_init(void)
+{
+       return platform_driver_register(&wm9713_codec_driver);
+}
+module_init(wm9713_init);
+
+static void __exit wm9713_exit(void)
+{
+       platform_driver_unregister(&wm9713_codec_driver);
+}
+module_exit(wm9713_exit);
 
 MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 63b8d81756e3a50daaeffd777da56539a6f2ad9f..793da863a03d94096aa130f5f88757ef5f23eb9c 100644 (file)
@@ -45,9 +45,6 @@
 #define WM9713_DAI_AC97_AUX            1
 #define WM9713_DAI_PCM_VOICE   2
 
-extern struct snd_soc_codec_device soc_codec_dev_wm9713;
-extern struct snd_soc_dai wm9713_dai[3];
-
 int wm9713_reset(struct snd_soc_codec *codec,  int try_warm);
 
 #endif
index 97f74d6a33e6b56cc87ec542b259bcf4c59c91cb..2b07b17a6b2d68f3173380bc16de4eb07b921689 100644 (file)
 #include <mach/mux.h>
 
 #include "../codecs/tlv320aic3x.h"
-#include "../codecs/cq93vc.h"
-#include "../codecs/spdif_transciever.h"
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
-#include "davinci-vcif.h"
 
 #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -41,8 +38,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
        unsigned sysclk;
 
@@ -87,7 +84,7 @@ static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        /* set cpu DAI configuration */
        return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
@@ -132,8 +129,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
 };
 
 /* Logic for a aic3x as connected on a davinci-evm */
-static int evm_aic3x_init(struct snd_soc_codec *codec)
+static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add davinci-evm specific widgets */
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
@@ -161,8 +160,10 @@ static int evm_aic3x_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link evm_dai = {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "davinci-mcasp.0",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.0-001a",
+       .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -171,40 +172,49 @@ static struct snd_soc_dai_link dm365_evm_dai = {
 #ifdef CONFIG_SND_DM365_AIC3X_CODEC
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "davinci-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
        .init = evm_aic3x_init,
+       .codec_name = "tlv320aic3x-codec.0-001a",
        .ops = &evm_ops,
 #elif defined(CONFIG_SND_DM365_VOICE_CODEC)
        .name = "Voice Codec - CQ93VC",
        .stream_name = "CQ93",
-       .cpu_dai = &davinci_vcif_dai,
-       .codec_dai = &cq93vc_dai,
+       .cpu_dai_name = "davinci-vcif",
+       .codec_dai_name = "cq93vc-hifi",
+       .codec_name = "cq93vc-codec",
 #endif
+       .platform_name = "davinci-pcm-audio",
 };
 
 static struct snd_soc_dai_link dm6467_evm_dai[] = {
        {
                .name = "TLV320AIC3X",
                .stream_name = "AIC3X",
-               .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
-               .codec_dai = &aic3x_dai,
+               .cpu_dai_name= "davinci-mcasp.0",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name ="davinci-pcm-audio",
+               .codec_name = "tlv320aic3x-codec.0-001a",
                .init = evm_aic3x_init,
                .ops = &evm_ops,
        },
        {
                .name = "McASP",
                .stream_name = "spdif",
-               .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
-               .codec_dai = &dit_stub_dai,
+               .cpu_dai_name= "davinci-mcasp.1",
+               .codec_dai_name = "dit-hifi",
+               .codec_name = "spdif_dit",
+               .platform_name = "davinci-pcm-audio",
                .ops = &evm_spdif_ops,
        },
 };
 static struct snd_soc_dai_link da8xx_evm_dai = {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name= "davinci-mcasp.0",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.0-001a",
+       .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -212,7 +222,6 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
 /* davinci dm6446, dm355 evm audio machine driver */
 static struct snd_soc_card snd_soc_card_evm = {
        .name = "DaVinci EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = &evm_dai,
        .num_links = 1,
 };
@@ -220,16 +229,13 @@ static struct snd_soc_card snd_soc_card_evm = {
 /* davinci dm365 evm audio machine driver */
 static struct snd_soc_card dm365_snd_soc_card_evm = {
        .name = "DaVinci DM365 EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
 };
 
-
 /* davinci dm6467 evm audio machine driver */
 static struct snd_soc_card dm6467_snd_soc_card_evm = {
        .name = "DaVinci DM6467 EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = dm6467_evm_dai,
        .num_links = ARRAY_SIZE(dm6467_evm_dai),
 };
@@ -237,82 +243,40 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = {
 static struct snd_soc_card da830_snd_soc_card = {
        .name = "DA830/OMAP-L137 EVM",
        .dai_link = &da8xx_evm_dai,
-       .platform = &davinci_soc_platform,
        .num_links = 1,
 };
 
 static struct snd_soc_card da850_snd_soc_card = {
        .name = "DA850/OMAP-L138 EVM",
        .dai_link = &da8xx_evm_dai,
-       .platform = &davinci_soc_platform,
        .num_links = 1,
 };
 
-static struct aic3x_setup_data aic3x_setup;
-
-/* evm audio subsystem */
-static struct snd_soc_device evm_snd_devdata = {
-       .card = &snd_soc_card_evm,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm365_evm_snd_devdata = {
-       .card = &dm365_snd_soc_card_evm,
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
-       .codec_dev = &soc_codec_dev_cq93vc,
-#endif
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm6467_evm_snd_devdata = {
-       .card = &dm6467_snd_soc_card_evm,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device da830_evm_snd_devdata = {
-       .card = &da830_snd_soc_card,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-static struct snd_soc_device da850_evm_snd_devdata = {
-       .card           = &da850_snd_soc_card,
-       .codec_dev      = &soc_codec_dev_aic3x,
-       .codec_data     = &aic3x_setup,
-};
-
 static struct platform_device *evm_snd_device;
 
 static int __init evm_init(void)
 {
-       struct snd_soc_device *evm_snd_dev_data;
+       struct snd_soc_card *evm_snd_dev_data;
        int index;
        int ret;
 
        if (machine_is_davinci_evm()) {
-               evm_snd_dev_data = &evm_snd_devdata;
+               evm_snd_dev_data = &snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_dm355_evm()) {
-               evm_snd_dev_data = &evm_snd_devdata;
+               evm_snd_dev_data = &snd_soc_card_evm;
                index = 1;
        } else if (machine_is_davinci_dm365_evm()) {
-               evm_snd_dev_data = &dm365_evm_snd_devdata;
+               evm_snd_dev_data = &dm365_snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_dm6467_evm()) {
-               evm_snd_dev_data = &dm6467_evm_snd_devdata;
+               evm_snd_dev_data = &dm6467_snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_da830_evm()) {
-               evm_snd_dev_data = &da830_evm_snd_devdata;
+               evm_snd_dev_data = &da830_snd_soc_card;
                index = 1;
        } else if (machine_is_davinci_da850_evm()) {
-               evm_snd_dev_data = &da850_evm_snd_devdata;
+               evm_snd_dev_data = &da850_snd_soc_card;
                index = 0;
        } else
                return -EINVAL;
@@ -322,7 +286,6 @@ static int __init evm_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
-       evm_snd_dev_data->dev = &evm_snd_device->dev;
        ret = platform_device_add(evm_snd_device);
        if (ret)
                platform_device_put(evm_snd_device);
index 9e8932abf158b7f8d22660081fd73183a73a4469..d46b545d41f432f037c58eb6c3b4b0f1b13cc2a2 100644 (file)
@@ -183,8 +183,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
                struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_platform *platform = socdev->card->platform;
+       struct snd_soc_platform *platform = rtd->platform;
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        u32 spcr;
        u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
@@ -205,8 +204,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
        if (playback) {
                /* Stop the DMA to avoid data loss */
                /* while the transmitter is out of reset to handle XSYNCERR */
-               if (platform->pcm_ops->trigger) {
-                       int ret = platform->pcm_ops->trigger(substream,
+               if (platform->driver->ops->trigger) {
+                       int ret = platform->driver->ops->trigger(substream,
                                SNDRV_PCM_TRIGGER_STOP);
                        if (ret < 0)
                                printk(KERN_DEBUG "Playback DMA stop failed\n");
@@ -227,8 +226,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
                toggle_clock(dev, playback);
 
                /* Restart the DMA */
-               if (platform->pcm_ops->trigger) {
-                       int ret = platform->pcm_ops->trigger(substream,
+               if (platform->driver->ops->trigger) {
+                       int ret = platform->driver->ops->trigger(substream,
                                SNDRV_PCM_TRIGGER_START);
                        if (ret < 0)
                                printk(KERN_DEBUG "Playback DMA start failed\n");
@@ -263,7 +262,7 @@ static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
 static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                   unsigned int fmt)
 {
-       struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int pcr;
        unsigned int srgr;
        /* Attention srgr is updated by hw_params! */
@@ -404,7 +403,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                int div_id, int div)
 {
-       struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (div_id != DAVINCI_MCBSP_CLKGDV)
                return -ENODEV;
@@ -417,7 +416,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_pcm_dma_params *dma_params =
                                        &dev->dma_params[substream->stream];
        struct snd_interval *i = NULL;
@@ -427,6 +426,9 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_format_t fmt;
        unsigned element_cnt = 1;
 
+       dai->capture_dma_data = dev->dma_params;
+       dai->playback_dma_data = dev->dma_params;
+
        /* general line settings */
        spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -569,24 +571,18 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
 static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        davinci_mcbsp_stop(dev, playback);
-       if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
-               /* codec is master */
-               davinci_mcbsp_start(dev, substream);
-       }
        return 0;
 }
 
 static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int ret = 0;
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
-               return 0;       /* return if codec is master */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -608,7 +604,7 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        davinci_mcbsp_stop(dev, playback);
 }
@@ -625,9 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 
 };
 
-struct snd_soc_dai davinci_i2s_dai = {
-       .name = "davinci-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver davinci_i2s_dai = {
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -641,7 +635,6 @@ struct snd_soc_dai davinci_i2s_dai = {
        .ops = &davinci_i2s_dai_ops,
 
 };
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
 
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
@@ -720,10 +713,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
        dev->dev = &pdev->dev;
 
-       davinci_i2s_dai.private_data = dev;
-       davinci_i2s_dai.capture.dma_data = dev->dma_params;
-       davinci_i2s_dai.playback.dma_data = dev->dma_params;
-       ret = snd_soc_register_dai(&davinci_i2s_dai);
+       dev_set_drvdata(&pdev->dev, dev);
+
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
        if (ret != 0)
                goto err_free_mem;
 
@@ -739,10 +731,10 @@ err_release_region:
 
 static int davinci_i2s_remove(struct platform_device *pdev)
 {
-       struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
+       struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *mem;
 
-       snd_soc_unregister_dai(&davinci_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
@@ -757,7 +749,7 @@ static struct platform_driver davinci_mcbsp_driver = {
        .probe          = davinci_i2s_probe,
        .remove         = davinci_i2s_remove,
        .driver         = {
-               .name   = "davinci-asp",
+               .name   = "davinci-i2s",
                .owner  = THIS_MODULE,
        },
 };
index 0b1e77b8c27992294ccf364c1038164485cc87ab..48dac3e2521a90a992aae255c4336eafc220ba9a 100644 (file)
@@ -17,6 +17,4 @@ enum davinci_mcbsp_div {
        DAVINCI_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-extern struct snd_soc_dai davinci_i2s_dai;
-
 #endif
index b24720894af64a183a68aec1925a77419b5d0ad5..86918ee12419e7fd3ff626bdb2ccd18a1bd09021 100644 (file)
@@ -422,7 +422,7 @@ static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
-       struct davinci_audio_dev *dev = cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *base = dev->base;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -709,12 +709,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params,
                                        struct snd_soc_dai *cpu_dai)
 {
-       struct davinci_audio_dev *dev = cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        struct davinci_pcm_dma_params *dma_params =
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
 
+       cpu_dai->capture_dma_data = dev->dma_params;
+       cpu_dai->playback_dma_data = dev->dma_params;
+
        davinci_hw_common_param(dev, substream->stream);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = dev->txnumevt;
@@ -761,8 +764,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
                                     int cmd, struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        int ret = 0;
 
        switch (cmd) {
@@ -804,10 +806,9 @@ static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 
 };
 
-struct snd_soc_dai davinci_mcasp_dai[] = {
+static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
-               .name           = "davinci-i2s",
-               .id             = 0,
+               .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
                        .channels_max   = 2,
@@ -828,8 +829,7 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
 
        },
        {
-               .name           = "davinci-dit",
-               .id             = 1,
+               "davinci-mcasp.1",
                .playback       = {
                        .channels_min   = 1,
                        .channels_max   = 384,
@@ -840,7 +840,6 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
        },
 
 };
-EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
@@ -899,6 +898,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
+               ret = -ENODEV;
                goto err_release_region;
        }
 
@@ -913,15 +913,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
+               ret = -ENODEV;
                goto err_release_region;
        }
 
        dma_data->channel = res->start;
-       davinci_mcasp_dai[pdata->op_mode].private_data = dev;
-       davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params;
-       davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params;
-       davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
-       ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
+       dev_set_drvdata(&pdev->dev, dev);
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
 
        if (ret != 0)
                goto err_release_region;
@@ -937,12 +935,10 @@ err_release_data:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct snd_platform_data *pdata = pdev->dev.platform_data;
-       struct davinci_audio_dev *dev;
+       struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *mem;
 
-       snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]);
-       dev = davinci_mcasp_dai[pdata->op_mode].private_data;
+       snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
index e755b5121ec728be29aed547b662c02994b2dc50..4681acc636061300efe053f56e214fc0eff1b98b 100644 (file)
@@ -22,8 +22,6 @@
 #include <mach/asp.h>
 #include "davinci-pcm.h"
 
-extern struct snd_soc_dai davinci_mcasp_dai[];
-
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_96000
 #define DAVINCI_MCASP_I2S_DAI  0
 #define DAVINCI_MCASP_DIT_DAI  1
index a7124116d2e01aea6832f158db798a8e16c93bfd..9d35b8c1a624338afcfa27a4282482515d2cb32a 100644 (file)
@@ -653,7 +653,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
        struct davinci_pcm_dma_params *pa;
        struct davinci_pcm_dma_params *params;
 
-       pa = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        if (!pa)
                return -ENODEV;
        params = &pa[substream->stream];
@@ -821,7 +821,7 @@ static int davinci_pcm_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK,
                        pcm_hardware_playback.buffer_bytes_max);
@@ -829,7 +829,7 @@ static int davinci_pcm_new(struct snd_card *card,
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE,
                        pcm_hardware_capture.buffer_bytes_max);
@@ -840,25 +840,44 @@ static int davinci_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform davinci_soc_platform = {
-       .name =         "davinci-audio",
-       .pcm_ops =      &davinci_pcm_ops,
+static struct snd_soc_platform_driver davinci_soc_platform = {
+       .ops =          &davinci_pcm_ops,
        .pcm_new =      davinci_pcm_new,
        .pcm_free =     davinci_pcm_free,
 };
-EXPORT_SYMBOL_GPL(davinci_soc_platform);
 
-static int __init davinci_soc_platform_init(void)
+static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&davinci_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
 }
-module_init(davinci_soc_platform_init);
 
-static void __exit davinci_soc_platform_exit(void)
+static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&davinci_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver davinci_pcm_driver = {
+       .driver = {
+                       .name = "davinci-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = davinci_soc_platform_probe,
+       .remove = __devexit_p(davinci_soc_platform_remove),
+};
+
+static int __init snd_davinci_pcm_init(void)
+{
+       return platform_driver_register(&davinci_pcm_driver);
+}
+module_init(snd_davinci_pcm_init);
+
+static void __exit snd_davinci_pcm_exit(void)
+{
+       platform_driver_unregister(&davinci_pcm_driver);
 }
-module_exit(davinci_soc_platform_exit);
+module_exit(snd_davinci_pcm_exit);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
index b799a02333d83b10a896d639ce1c73679ab06bec..c0d6c9be4b4d605b12bdf6145a8fde5319cd2bf6 100644 (file)
@@ -28,7 +28,4 @@ struct davinci_pcm_dma_params {
        unsigned int fifo_level;
 };
 
-
-extern struct snd_soc_platform davinci_soc_platform;
-
 #endif
index 40eccfe9e358c2f2bc05574d3cdeb87f6fa7bffc..009b6521a1bf9f3731e9d597f09ff3644126b967 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/plat-sffsdr/sffsdr-fpga.h>
 #endif
 
-#include <mach/mcbsp.h>
 #include <mach/edma.h>
 
 #include "../codecs/pcm3008.h"
@@ -48,7 +47,7 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fs;
        int ret = 0;
 
@@ -85,15 +84,16 @@ static struct snd_soc_ops sffsdr_ops = {
 static struct snd_soc_dai_link sffsdr_dai = {
        .name = "PCM3008", /* Codec name */
        .stream_name = "PCM3008 HiFi",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &pcm3008_dai,
+       .cpu_dai_name = "davinci-asp.0",
+       .codec_dai_name = "pcm3008-hifi",
+       .codec_name = "pcm3008-codec",
+       .platform_name = "davinci-pcm-audio",
        .ops = &sffsdr_ops,
 };
 
 /* davinci-sffsdr audio machine driver */
 static struct snd_soc_card snd_soc_sffsdr = {
        .name = "DaVinci SFFSDR",
-       .platform = &davinci_soc_platform,
        .dai_link = &sffsdr_dai,
        .num_links = 1,
 };
@@ -106,11 +106,12 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
        .pdda_pin = GPIO(38),
 };
 
-/* sffsdr audio subsystem */
-static struct snd_soc_device sffsdr_snd_devdata = {
-       .card = &snd_soc_sffsdr,
-       .codec_dev = &soc_codec_dev_pcm3008,
-       .codec_data = &sffsdr_pcm3008_setup,
+struct platform_device pcm3008_codec = {
+               .name = "pcm3008-codec",
+               .id = 0,
+               .dev = {
+                               .platform_data = &sffsdr_pcm3008_setup,
+               },
 };
 
 static struct resource sffsdr_snd_resources[] = {
@@ -135,14 +136,15 @@ static int __init sffsdr_init(void)
        if (!machine_is_sffsdr())
                return -EINVAL;
 
+       platform_device_register(&pcm3008_codec);
+
        sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
        if (!sffsdr_snd_device) {
                printk(KERN_ERR "platform device allocation failed\n");
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
-       sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
+       platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
        platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
                                 sizeof(sffsdr_snd_data));
 
@@ -150,7 +152,7 @@ static int __init sffsdr_init(void)
                                            sffsdr_snd_resources,
                                            ARRAY_SIZE(sffsdr_snd_resources));
        if (ret) {
-               printk(KERN_ERR "platform device add ressources failed\n");
+               printk(KERN_ERR "platform device add resources failed\n");
                goto error;
        }
 
@@ -168,6 +170,7 @@ error:
 static void __exit sffsdr_exit(void)
 {
        platform_device_unregister(sffsdr_snd_device);
+       platform_device_unregister(&pcm3008_codec);
 }
 
 module_init(sffsdr_init);
index 48678533da7af1641f56c6b3e2dcfca67d8dbedc..ea232f6a2c21912e408a69ea2d1f8df28e4552dd 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
-#include "davinci-vcif.h"
 
 #define MOD_REG_BIT(val, mask, set) do { \
        if (set) { \
@@ -55,7 +54,7 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct davinci_vcif_dev *davinci_vcif_dev =
-                                       rtd->dai->cpu_dai->private_data;
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        u32 w;
 
@@ -74,7 +73,7 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct davinci_vcif_dev *davinci_vcif_dev =
-                                       rtd->dai->cpu_dai->private_data;
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        u32 w;
 
@@ -92,12 +91,15 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
-       struct davinci_vcif_dev *davinci_vcif_dev = dai->private_data;
+       struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        struct davinci_pcm_dma_params *dma_params =
                        &davinci_vcif_dev->dma_params[substream->stream];
        u32 w;
 
+       dai->capture_dma_data = davinci_vcif_dev->dma_params;
+       dai->playback_dma_data = davinci_vcif_dev->dma_params;
+
        /* Restart the codec before setup */
        davinci_vcif_stop(substream);
        davinci_vcif_start(substream);
@@ -179,8 +181,7 @@ static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
        .hw_params      = davinci_vcif_hw_params,
 };
 
-struct snd_soc_dai davinci_vcif_dai = {
-       .name = "davinci-vcif",
+static struct snd_soc_dai_driver davinci_vcif_dai = {
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -194,7 +195,6 @@ struct snd_soc_dai davinci_vcif_dai = {
        .ops = &davinci_vcif_dai_ops,
 
 };
-EXPORT_SYMBOL_GPL(davinci_vcif_dai);
 
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
@@ -222,12 +222,9 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
                                        davinci_vc->davinci_vcif.dma_rx_addr;
 
-       davinci_vcif_dai.dev = &pdev->dev;
-       davinci_vcif_dai.capture.dma_data = davinci_vcif_dev->dma_params;
-       davinci_vcif_dai.playback.dma_data = davinci_vcif_dev->dma_params;
-       davinci_vcif_dai.private_data = davinci_vcif_dev;
+       dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
-       ret = snd_soc_register_dai(&davinci_vcif_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
        if (ret != 0) {
                dev_err(&pdev->dev, "could not register dai\n");
                goto fail;
@@ -243,7 +240,7 @@ fail:
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&davinci_vcif_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        return 0;
 }
@@ -252,7 +249,7 @@ static struct platform_driver davinci_vcif_driver = {
        .probe          = davinci_vcif_probe,
        .remove         = davinci_vcif_remove,
        .driver         = {
-               .name   = "davinci_vcif",
+               .name   = "davinci-vcif",
                .owner  = THIS_MODULE,
        },
 };
diff --git a/sound/soc/davinci/davinci-vcif.h b/sound/soc/davinci/davinci-vcif.h
deleted file mode 100644 (file)
index 571c994..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ALSA SoC Voice Codec Interface for TI DAVINCI processor
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _DAVINCI_VCIF_H
-#define _DAVINCI_VCIF_H
-
-extern struct snd_soc_dai davinci_vcif_dai;
-
-#endif
index f617f560f46b9e56d287ce8232ff70218a1e7ebd..57429041189c134abda26547ab723cef54590e6e 100644 (file)
@@ -3,11 +3,16 @@ config SND_EP93XX_SOC
        depends on ARCH_EP93XX && SND_SOC
        help
          Say Y or M if you want to add support for codecs attached to
-         the EP93xx I2S interface.
+         the EP93xx I2S or AC97 interfaces.
 
 config SND_EP93XX_SOC_I2S
        tristate
 
+config SND_EP93XX_SOC_AC97
+       tristate
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+
 config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
         depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
@@ -16,3 +21,12 @@ config SND_EP93XX_SOC_SNAPPERCL15
         help
           Say Y or M here if you want to add support for I2S audio on the
           Bluewater Systems Snapper CL15 module.
+
+config SND_EP93XX_SOC_SIMONE
+       tristate "SoC Audio support for Simplemachines Sim.One board"
+       depends on SND_EP93XX_SOC && MACH_SIM_ONE
+       select SND_EP93XX_SOC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         Say Y or M here if you want to add support for AC97 audio on the
+         Simplemachines Sim.One board.
index 272e60f57b9a5c33b8d9e1a493c32a339b49ec08..8e7977fb6b7d6c407bd94794ce7cbe04d2c96560 100644 (file)
@@ -1,11 +1,15 @@
 # EP93xx Platform Support
 snd-soc-ep93xx-objs                            := ep93xx-pcm.o
 snd-soc-ep93xx-i2s-objs                                := ep93xx-i2s.o
+snd-soc-ep93xx-ac97-objs                       := ep93xx-ac97.o
 
 obj-$(CONFIG_SND_EP93XX_SOC)                   += snd-soc-ep93xx.o
 obj-$(CONFIG_SND_EP93XX_SOC_I2S)               += snd-soc-ep93xx-i2s.o
+obj-$(CONFIG_SND_EP93XX_SOC_AC97)              += snd-soc-ep93xx-ac97.o
 
 # EP93XX Machine Support
 snd-soc-snappercl15-objs                       := snappercl15.o
+snd-soc-simone-objs                            := simone.o
 
 obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15)       += snd-soc-snappercl15.o
+obj-$(CONFIG_SND_EP93XX_SOC_SIMONE)            += snd-soc-simone.o
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
new file mode 100644 (file)
index 0000000..68a0bae
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * ASoC driver for Cirrus Logic EP93xx AC97 controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on s3c-ac97 ASoC driver by Jaswinder Singh.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "ep93xx-pcm.h"
+
+/*
+ * Per channel (1-4) registers.
+ */
+#define AC97CH(n)              (((n) - 1) * 0x20)
+
+#define AC97DR(n)              (AC97CH(n) + 0x0000)
+
+#define AC97RXCR(n)            (AC97CH(n) + 0x0004)
+#define AC97RXCR_REN           BIT(0)
+#define AC97RXCR_RX3           BIT(3)
+#define AC97RXCR_RX4           BIT(4)
+#define AC97RXCR_CM            BIT(15)
+
+#define AC97TXCR(n)            (AC97CH(n) + 0x0008)
+#define AC97TXCR_TEN           BIT(0)
+#define AC97TXCR_TX3           BIT(3)
+#define AC97TXCR_TX4           BIT(4)
+#define AC97TXCR_CM            BIT(15)
+
+#define AC97SR(n)              (AC97CH(n) + 0x000c)
+#define AC97SR_TXFE            BIT(1)
+#define AC97SR_TXUE            BIT(6)
+
+#define AC97RISR(n)            (AC97CH(n) + 0x0010)
+#define AC97ISR(n)             (AC97CH(n) + 0x0014)
+#define AC97IE(n)              (AC97CH(n) + 0x0018)
+
+/*
+ * Global AC97 controller registers.
+ */
+#define AC97S1DATA             0x0080
+#define AC97S2DATA             0x0084
+#define AC97S12DATA            0x0088
+
+#define AC97RGIS               0x008c
+#define AC97GIS                        0x0090
+#define AC97IM                 0x0094
+/*
+ * Common bits for RGIS, GIS and IM registers.
+ */
+#define AC97_SLOT2RXVALID      BIT(1)
+#define AC97_CODECREADY                BIT(5)
+#define AC97_SLOT2TXCOMPLETE   BIT(6)
+
+#define AC97EOI                        0x0098
+#define AC97EOI_WINT           BIT(0)
+#define AC97EOI_CODECREADY     BIT(1)
+
+#define AC97GCR                        0x009c
+#define AC97GCR_AC97IFE                BIT(0)
+
+#define AC97RESET              0x00a0
+#define AC97RESET_TIMEDRESET   BIT(0)
+
+#define AC97SYNC               0x00a4
+#define AC97SYNC_TIMEDSYNC     BIT(0)
+
+#define AC97_TIMEOUT           msecs_to_jiffies(5)
+
+/**
+ * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
+ * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
+ * @dev: pointer to the platform device dev structure
+ * @mem: physical memory resource for the registers
+ * @regs: mapped AC97 controller registers
+ * @irq: AC97 interrupt number
+ * @done: bus ops wait here for an interrupt
+ */
+struct ep93xx_ac97_info {
+       struct mutex            lock;
+       struct device           *dev;
+       struct resource         *mem;
+       void __iomem            *regs;
+       int                     irq;
+       struct completion       done;
+};
+
+/* currently ALSA only supports a single AC97 device */
+static struct ep93xx_ac97_info *ep93xx_ac97_info;
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+       .name           = "ac97-pcm-out",
+       .dma_port       = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+       .name           = "ac97-pcm-in",
+       .dma_port       = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
+                                           unsigned reg)
+{
+       return __raw_readl(info->regs + reg);
+}
+
+static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
+                                        unsigned reg, unsigned val)
+{
+       __raw_writel(val, info->regs + reg);
+}
+
+static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
+                                      unsigned short reg)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+       unsigned short val;
+
+       mutex_lock(&info->lock);
+
+       ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
+               dev_warn(info->dev, "timeout reading register %x\n", reg);
+               mutex_unlock(&info->lock);
+               return -ETIMEDOUT;
+       }
+       val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
+
+       mutex_unlock(&info->lock);
+       return val;
+}
+
+static void ep93xx_ac97_write(struct snd_ac97 *ac97,
+                             unsigned short reg,
+                             unsigned short val)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * Writes to the codec need to be done so that slot 2 is filled in
+        * before slot 1.
+        */
+       ep93xx_ac97_write_reg(info, AC97S2DATA, val);
+       ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "timeout writing register %x\n", reg);
+
+       mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * We are assuming that before this functions gets called, the codec
+        * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
+        * control the SYNC signal directly via AC97SYNC register. Using
+        * TIMEDSYNC the controller will keep the SYNC high > 1us.
+        */
+       ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "codec warm reset timeout\n");
+
+       mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * For doing cold reset, we disable the AC97 controller interface, clear
+        * WINT and CODECREADY bits, and finally enable the interface again.
+        */
+       ep93xx_ac97_write_reg(info, AC97GCR, 0);
+       ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
+       ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
+
+       /*
+        * Now, assert the reset and wait for the codec to become ready.
+        */
+       ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "codec cold reset timeout\n");
+
+       /*
+        * Give the codec some time to come fully out from the reset. This way
+        * we ensure that the subsequent reads/writes will work.
+        */
+       usleep_range(15000, 20000);
+
+       mutex_unlock(&info->lock);
+}
+
+static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
+{
+       struct ep93xx_ac97_info *info = dev_id;
+       unsigned status, mask;
+
+       /*
+        * Just mask out the interrupt and wake up the waiting thread.
+        * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
+        * the waiting thread.
+        */
+       status = ep93xx_ac97_read_reg(info, AC97GIS);
+       mask = ep93xx_ac97_read_reg(info, AC97IM);
+       mask &= ~status;
+       ep93xx_ac97_write_reg(info, AC97IM, mask);
+
+       complete(&info->done);
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = ep93xx_ac97_read,
+       .write          = ep93xx_ac97_write,
+       .reset          = ep93xx_ac97_cold_reset,
+       .warm_reset     = ep93xx_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
+                              int cmd, struct snd_soc_dai *dai)
+{
+       struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+       unsigned v = 0;
+
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /*
+                        * Enable compact mode, TX slots 3 & 4, and the TX FIFO
+                        * itself.
+                        */
+                       v |= AC97TXCR_CM;
+                       v |= AC97TXCR_TX3 | AC97TXCR_TX4;
+                       v |= AC97TXCR_TEN;
+                       ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
+               } else {
+                       /*
+                        * Enable compact mode, RX slots 3 & 4, and the RX FIFO
+                        * itself.
+                        */
+                       v |= AC97RXCR_CM;
+                       v |= AC97RXCR_RX3 | AC97RXCR_RX4;
+                       v |= AC97RXCR_REN;
+                       ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
+               }
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /*
+                        * As per Cirrus EP93xx errata described below:
+                        *
+                        * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
+                        *
+                        * we will wait for the TX FIFO to be empty before
+                        * clearing the TEN bit.
+                        */
+                       unsigned long timeout = jiffies + AC97_TIMEOUT;
+
+                       do {
+                               v = ep93xx_ac97_read_reg(info, AC97SR(1));
+                               if (time_after(jiffies, timeout)) {
+                                       dev_warn(info->dev, "TX timeout\n");
+                                       break;
+                               }
+                       } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
+
+                       /* disable the TX FIFO */
+                       ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
+               } else {
+                       /* disable the RX FIFO */
+                       ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
+               }
+               break;
+
+       default:
+               dev_warn(info->dev, "unknown command %d\n", cmd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct ep93xx_pcm_dma_params *dma_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = &ep93xx_ac97_pcm_out;
+       else
+               dma_data = &ep93xx_ac97_pcm_in;
+
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+       return 0;
+}
+
+static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
+       .startup        = ep93xx_ac97_startup,
+       .trigger        = ep93xx_ac97_trigger,
+};
+
+struct snd_soc_dai_driver ep93xx_ac97_dai = {
+       .name           = "ep93xx-ac97",
+       .id             = 0,
+       .ac97_control   = 1,
+       .playback       = {
+               .stream_name    = "AC97 Playback",
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_8000_48000,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture        = {
+               .stream_name    = "AC97 Capture",
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_8000_48000,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops                    = &ep93xx_ac97_dai_ops,
+};
+
+static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
+{
+       struct ep93xx_ac97_info *info;
+       int ret;
+
+       info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       mutex_init(&info->lock);
+       init_completion(&info->done);
+       info->dev = &pdev->dev;
+
+       info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!info->mem) {
+               ret = -ENXIO;
+               goto fail_free_info;
+       }
+
+       info->irq = platform_get_irq(pdev, 0);
+       if (!info->irq) {
+               ret = -ENXIO;
+               goto fail_free_info;
+       }
+
+       if (!request_mem_region(info->mem->start, resource_size(info->mem),
+                               pdev->name)) {
+               ret = -EBUSY;
+               goto fail_free_info;
+       }
+
+       info->regs = ioremap(info->mem->start, resource_size(info->mem));
+       if (!info->regs) {
+               ret = -ENOMEM;
+               goto fail_release_mem;
+       }
+
+       ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
+                         pdev->name, info);
+       if (ret)
+               goto fail_unmap_mem;
+
+       ep93xx_ac97_info = info;
+       platform_set_drvdata(pdev, info);
+
+       ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+       if (ret)
+               goto fail_free_irq;
+
+       return 0;
+
+fail_free_irq:
+       platform_set_drvdata(pdev, NULL);
+       free_irq(info->irq, info);
+fail_unmap_mem:
+       iounmap(info->regs);
+fail_release_mem:
+       release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
+       kfree(info);
+
+       return ret;
+}
+
+static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
+{
+       struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       /* disable the AC97 controller */
+       ep93xx_ac97_write_reg(info, AC97GCR, 0);
+
+       free_irq(info->irq, info);
+       iounmap(info->regs);
+       release_mem_region(info->mem->start, resource_size(info->mem));
+       platform_set_drvdata(pdev, NULL);
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver ep93xx_ac97_driver = {
+       .probe  = ep93xx_ac97_probe,
+       .remove = __devexit_p(ep93xx_ac97_remove),
+       .driver = {
+               .name = "ep93xx-ac97",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init ep93xx_ac97_init(void)
+{
+       return platform_driver_register(&ep93xx_ac97_driver);
+}
+module_init(ep93xx_ac97_init);
+
+static void __exit ep93xx_ac97_exit(void)
+{
+       platform_driver_unregister(&ep93xx_ac97_driver);
+}
+module_exit(ep93xx_ac97_exit);
+
+MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-ac97");
index 00b946632184a359cd5157ab8fceca38d1e40f43..4f48733596134c2e0fe68825b494ce798cbb6767 100644 (file)
@@ -31,7 +31,6 @@
 #include <mach/dma.h>
 
 #include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
 
 #define EP93XX_I2S_TXCLKCFG            0x00
 #define EP93XX_I2S_RXCLKCFG            0x04
@@ -145,8 +144,8 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        snd_soc_dai_set_dma_data(cpu_dai, substream,
                                 &info->dma_params[substream->stream]);
@@ -156,8 +155,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
 static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        ep93xx_i2s_disable(info, substream->stream);
 }
@@ -165,7 +163,7 @@ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
 static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                  unsigned int fmt)
 {
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int clk_cfg, lin_ctrl;
 
        clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
@@ -242,9 +240,7 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
        unsigned word_len, div, sdiv, lrdiv;
        int found = 0, err;
 
@@ -302,7 +298,7 @@ out:
 static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
                                 unsigned int freq, int dir)
 {
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
                return -EINVAL;
@@ -313,7 +309,7 @@ static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
 #ifdef CONFIG_PM
 static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
 {
-       struct ep93xx_i2s_info *info = dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return;
@@ -324,7 +320,7 @@ static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
 {
-       struct ep93xx_i2s_info *info = dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return;
@@ -349,9 +345,7 @@ static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
                            SNDRV_PCM_FMTBIT_S24_LE | \
                            SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai ep93xx_i2s_dai = {
-       .name           = "ep93xx-i2s",
-       .id             = 0,
+static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .symmetric_rates= 1,
        .suspend        = ep93xx_i2s_suspend,
        .resume         = ep93xx_i2s_resume,
@@ -369,7 +363,6 @@ struct snd_soc_dai ep93xx_i2s_dai = {
        },
        .ops            = &ep93xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
 
 static int ep93xx_i2s_probe(struct platform_device *pdev)
 {
@@ -383,8 +376,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       ep93xx_i2s_dai.dev = &pdev->dev;
-       ep93xx_i2s_dai.private_data = info;
+       dev_set_drvdata(&pdev->dev, info);
        info->dma_params = ep93xx_i2s_dma_params;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -424,7 +416,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                goto fail_put_sclk;
        }
 
-       err = snd_soc_register_dai(&ep93xx_i2s_dai);
+       err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
        if (err)
                goto fail_put_lrclk;
 
@@ -447,9 +439,9 @@ fail:
 
 static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
 {
-       struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+       struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&ep93xx_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        clk_put(info->lrclk);
        clk_put(info->sclk);
        clk_put(info->mclk);
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
deleted file mode 100644 (file)
index 3bd4ebf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * linux/sound/soc/ep93xx-i2s.h
- * EP93xx I2S driver
- *
- * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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 _EP93XX_SND_SOC_I2S_H
-#define _EP93XX_SND_SOC_I2S_H
-
-extern struct snd_soc_dai ep93xx_i2s_dai;
-
-#endif /* _EP93XX_SND_SOC_I2S_H */
index 4ba9384007916c454081a821cd1fcacab27d76f9..2f121ddbe4bb50d04ced8fb32db30bf54437b864 100644 (file)
@@ -95,7 +95,7 @@ static void ep93xx_pcm_buffer_finished(void *cookie,
 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
        struct ep93xx_pcm_dma_params *dma_params;
        struct ep93xx_runtime_data *rtd;    
        int ret;
@@ -276,14 +276,14 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -293,22 +293,41 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        return 0;
 }
 
-struct snd_soc_platform ep93xx_soc_platform = {
-       .name           = "ep93xx-audio",
-       .pcm_ops        = &ep93xx_pcm_ops,
+static struct snd_soc_platform_driver ep93xx_soc_platform = {
+       .ops            = &ep93xx_pcm_ops,
        .pcm_new        = &ep93xx_pcm_new,
        .pcm_free       = &ep93xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+}
+
+static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ep93xx_pcm_driver = {
+       .driver = {
+                       .name = "ep93xx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ep93xx_soc_platform_probe,
+       .remove = __devexit_p(ep93xx_soc_platform_remove),
+};
 
 static int __init ep93xx_soc_platform_init(void)
 {
-       return snd_soc_register_platform(&ep93xx_soc_platform);
+       return platform_driver_register(&ep93xx_pcm_driver);
 }
 
 static void __exit ep93xx_soc_platform_exit(void)
 {
-       snd_soc_unregister_platform(&ep93xx_soc_platform);
+       platform_driver_unregister(&ep93xx_pcm_driver);
 }
 
 module_init(ep93xx_soc_platform_init);
index 4ffdd3f62fe9fbc02a40a8078209e0befca3be0a..111e1121ecb83119576c6b9ad3cdf552a426be1e 100644 (file)
@@ -17,6 +17,4 @@ struct ep93xx_pcm_dma_params {
        int     dma_port;
 };
 
-extern struct snd_soc_platform ep93xx_soc_platform;
-
 #endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c
new file mode 100644 (file)
index 0000000..4b0d199
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * simone.c -- ASoC audio for Simplemachines Sim.One board
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on snappercl15 machine driver by Ryan Mallon.
+ *
+ * This program is free software; you can 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/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "ep93xx-pcm.h"
+
+static struct snd_soc_dai_link simone_dai = {
+       .name           = "AC97",
+       .stream_name    = "AC97 HiFi",
+       .cpu_dai_name   = "ep93xx-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name     = "ac97-codec",
+       .platform_name  = "ep93xx-pcm-audio",
+};
+
+static struct snd_soc_card snd_soc_simone = {
+       .name           = "Sim.One",
+       .dai_link       = &simone_dai,
+       .num_links      = 1,
+};
+
+static struct platform_device *simone_snd_ac97_device;
+static struct platform_device *simone_snd_device;
+
+static int __init simone_init(void)
+{
+       int ret;
+
+       if (!machine_is_sim_one())
+               return -ENODEV;
+
+       simone_snd_ac97_device = platform_device_alloc("ac97-codec", -1);
+       if (!simone_snd_ac97_device)
+               return -ENOMEM;
+
+       ret = platform_device_add(simone_snd_ac97_device);
+       if (ret)
+               goto fail;
+
+       simone_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!simone_snd_device) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       platform_set_drvdata(simone_snd_device, &snd_soc_simone);
+       ret = platform_device_add(simone_snd_device);
+       if (ret) {
+               platform_device_put(simone_snd_device);
+               goto fail;
+       }
+
+       return ret;
+
+fail:
+       platform_device_put(simone_snd_ac97_device);
+       return ret;
+}
+module_init(simone_init);
+
+static void __exit simone_exit(void)
+{
+       platform_device_unregister(simone_snd_device);
+       platform_device_unregister(simone_snd_ac97_device);
+}
+module_exit(simone_exit);
+
+MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
index 64955340ff75c9a66f830888cc847cd55c42818a..28ab5ff772acda6a82e7a17794aa988fd20aabfa 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "../codecs/tlv320aic23.h"
 #include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
 
 #define CODEC_CLOCK 5644800
 
@@ -30,8 +29,8 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
@@ -77,8 +76,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
@@ -89,24 +90,20 @@ static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link snappercl15_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "AIC23",
-       .cpu_dai        = &ep93xx_i2s_dai,
-       .codec_dai      = &tlv320aic23_dai,
+       .cpu_dai_name   = "ep93xx-i2s",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .codec_name     = "tlv320aic23-codec.0-001a",
+       .platform_name  =  "ep93xx-pcm-audio",
        .init           = snappercl15_tlv320aic23_init,
        .ops            = &snappercl15_ops,
 };
 
 static struct snd_soc_card snd_soc_snappercl15 = {
        .name           = "Snapper CL15",
-       .platform       = &ep93xx_soc_platform,
        .dai_link       = &snappercl15_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device snappercl15_snd_devdata = {
-       .card           = &snd_soc_snappercl15,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *snappercl15_snd_device;
 
 static int __init snappercl15_init(void)
@@ -126,8 +123,7 @@ static int __init snappercl15_init(void)
        if (!snappercl15_snd_device)
                return -ENOMEM;
        
-       platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
-       snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+       platform_set_drvdata(snappercl15_snd_device, &snd_soc_snappercl15);
        ret = platform_device_add(snappercl15_snd_device);
        if (ret)
                platform_device_put(snappercl15_snd_device);
index 8cb65ccad35fb8cfcf96caac60cd2b0e1adb468e..d754d34d68a68a83b95b080ee9bf0baebeaea0ce 100644 (file)
@@ -1,27 +1,36 @@
-config SND_SOC_OF_SIMPLE
-       tristate
-       
 config SND_MPC52xx_DMA
        tristate
 
-# ASoC platform support for the Freescale MPC8610 SOC.  This compiles drivers
-# for the SSI and the Elo DMA controller.  You will still need to select
-# a platform driver and a codec driver.
-config SND_SOC_MPC8610
+# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
+# an Elo DMA controller, such as the MPC8610 and P1022.  You will still need to
+# select a platform driver and a codec driver.
+config SND_SOC_POWERPC_SSI
        tristate
-       depends on MPC8610
+       depends on FSL_SOC
 
 config SND_SOC_MPC8610_HPCD
        tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
        # I2C is necessary for the CS4270 driver
        depends on MPC8610_HPCD && I2C
-       select SND_SOC_MPC8610
+       select SND_SOC_POWERPC_SSI
        select SND_SOC_CS4270
        select SND_SOC_CS4270_VD33_ERRATA
        default y if MPC8610_HPCD
        help
          Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
 
+config SND_SOC_P1022_DS
+       tristate "ALSA SoC support for the Freescale P1022 DS board"
+       # I2C is necessary for the WM8776 driver
+       depends on P1022_DS && I2C
+       select SND_SOC_POWERPC_SSI
+       select SND_SOC_WM8776
+       default y if P1022_DS
+       help
+         Say Y if you want to enable audio on the Freescale P1022 DS board.
+         This will also include the Wolfson Microelectronics WM8776 codec
+         driver.
+
 config SND_SOC_MPC5200_I2S
        tristate "Freescale MPC5200 PSC in I2S mode driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
index a83a73967ec666a14409bb8f64c3b540c8b0f401..b4a38c0ac58c35445e8efb91b66cf4f8c7a92cde 100644 (file)
@@ -1,14 +1,15 @@
-# Simple machine driver that extracts configuration from the OF device tree
-obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
-
 # MPC8610 HPCD Machine Support
 snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
 obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
 
-# MPC8610 Platform Support
+# P1022 DS Machine Support
+snd-soc-p1022-ds-objs := p1022_ds.o
+obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
+
+# Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
index 1a5b8e0d6a34d986fcfb62c5ac0c7cdc6ad9f2b7..53251e6b5bd509303dc17500e8f4d64feeea7021 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
 #include "mpc5200_dma.h"
 #include "mpc5200_psc_ac97.h"
 
 #define DRV_NAME "efika-audio-fabric"
 
-static struct snd_soc_device device;
 static struct snd_soc_card card;
 
 static struct snd_soc_dai_link efika_fabric_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 Analog",
-       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+       .codec_dai_name = "stac9766-hifi-analog",
+       .cpu_dai_name = "mpc5200-psc-ac97.0",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "stac9766-codec",
 },
 {
        .name = "AC97",
        .stream_name = "AC97 IEC958",
-       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+       .codec_dai_name = "stac9766-hifi-IEC958",
+       .cpu_dai_name = "mpc5200-psc-ac97.1",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "stac9766-codec",
 },
 };
 
@@ -58,13 +60,10 @@ static __init int efika_fabric_init(void)
        if (!of_machine_is_compatible("bplan,efika"))
                return -ENODEV;
 
-       card.platform = &mpc5200_audio_dma_platform;
        card.name = "Efika";
        card.dai_link = efika_fabric_dai;
        card.num_links = ARRAY_SIZE(efika_fabric_dai);
 
-       device.card = &card;
-       device.codec_dev = &soc_codec_dev_stac9766;
 
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
@@ -72,8 +71,7 @@ static __init int efika_fabric_init(void)
                return -ENODEV;
        }
 
-       platform_set_drvdata(pdev, &device);
-       device.dev = &pdev->dev;
+       platform_set_drvdata(pdev, &card);
 
        rc = platform_device_add(pdev);
        if (rc) {
index 410c7496a18dd295cec46770176ba960ca46686b..4cf98c03af223cda837a25a6f0c98c8eb0071025 100644 (file)
@@ -3,10 +3,11 @@
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, 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.
+ * Copyright 2007-2010 Freescale Semiconductor, 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.
  *
  * This driver implements ASoC support for the Elo DMA controller, which is
  * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
@@ -20,6 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
+#include <linux/of_platform.h>
+#include <linux/list.h>
+#include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -29,6 +33,7 @@
 #include <asm/io.h>
 
 #include "fsl_dma.h"
+#include "fsl_ssi.h"   /* For the offset of stx0 and srx0 */
 
 /*
  * The formats that the DMA controller supports, which is anything
 #define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
                          SNDRV_PCM_RATE_CONTINUOUS)
 
-/* DMA global data.  This structure is used by fsl_dma_open() to determine
- * which DMA channels to assign to a substream.  Unfortunately, ASoC V1 does
- * not allow the machine driver to provide this information to the PCM
- * driver in advance, and there's no way to differentiate between the two
- * DMA controllers.  So for now, this driver only supports one SSI device
- * using two DMA channels.  We cannot support multiple DMA devices.
- *
- * ssi_stx_phys: bus address of SSI STX register
- * ssi_srx_phys: bus address of SSI SRX register
- * dma_channel: pointer to the DMA channel's registers
- * irq: IRQ for this DMA channel
- * assigned: set to 1 if that DMA channel is assigned to a substream
- */
-static struct {
+struct dma_object {
+       struct snd_soc_platform_driver dai;
        dma_addr_t ssi_stx_phys;
        dma_addr_t ssi_srx_phys;
-       struct ccsr_dma_channel __iomem *dma_channel[2];
-       unsigned int irq[2];
-       unsigned int assigned[2];
-} dma_global_data;
+       unsigned int ssi_fifo_depth;
+       struct ccsr_dma_channel __iomem *channel;
+       unsigned int irq;
+       bool assigned;
+       char path[1];
+};
 
 /*
  * The number of DMA links to use.  Two is the bare minimum, but if you
@@ -88,8 +83,6 @@ static struct {
  * structure.
  *
  * @link[]: array of link descriptors
- * @controller_id: which DMA controller (0, 1, ...)
- * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
  * @dma_channel: pointer to the DMA channel's registers
  * @irq: IRQ for this DMA channel
  * @substream: pointer to the substream object, needed by the ISR
@@ -104,12 +97,11 @@ static struct {
  */
 struct fsl_dma_private {
        struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
-       unsigned int controller_id;
-       unsigned int channel_id;
        struct ccsr_dma_channel __iomem *dma_channel;
        unsigned int irq;
        struct snd_pcm_substream *substream;
        dma_addr_t ssi_sxx_phys;
+       unsigned int ssi_fifo_depth;
        dma_addr_t ld_buf_phys;
        unsigned int current_link;
        dma_addr_t dma_buf_phys;
@@ -185,13 +177,23 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
        struct fsl_dma_link_descriptor *link =
                &dma_private->link[dma_private->current_link];
 
-       /* Update our link descriptors to point to the next period */
-       if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               link->source_addr =
-                       cpu_to_be32(dma_private->dma_buf_next);
-       else
-               link->dest_addr =
-                       cpu_to_be32(dma_private->dma_buf_next);
+       /* Update our link descriptors to point to the next period. On a 36-bit
+        * system, we also need to update the ESAD bits.  We also set (keep) the
+        * snoop bits.  See the comments in fsl_dma_hw_params() about snooping.
+        */
+       if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               link->source_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+               link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                       upper_32_bits(dma_private->dma_buf_next));
+#endif
+       } else {
+               link->dest_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+               link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                       upper_32_bits(dma_private->dma_buf_next));
+#endif
+       }
 
        /* Update our variables for next time */
        dma_private->dma_buf_next += dma_private->period_size;
@@ -212,6 +214,9 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
 static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
 {
        struct fsl_dma_private *dma_private = dev_id;
+       struct snd_pcm_substream *substream = dma_private->substream;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
        struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
        irqreturn_t ret = IRQ_NONE;
        u32 sr, sr2 = 0;
@@ -222,11 +227,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
        sr = in_be32(&dma_channel->sr);
 
        if (sr & CCSR_DMA_SR_TE) {
-               dev_err(dma_private->substream->pcm->card->dev,
-                       "DMA transmit error (controller=%u channel=%u irq=%u\n",
-                       dma_private->controller_id,
-                       dma_private->channel_id, irq);
-               fsl_dma_abort_stream(dma_private->substream);
+               dev_err(dev, "dma transmit error\n");
+               fsl_dma_abort_stream(substream);
                sr2 |= CCSR_DMA_SR_TE;
                ret = IRQ_HANDLED;
        }
@@ -235,11 +237,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
                ret = IRQ_HANDLED;
 
        if (sr & CCSR_DMA_SR_PE) {
-               dev_err(dma_private->substream->pcm->card->dev,
-                       "DMA%u programming error (channel=%u irq=%u)\n",
-                       dma_private->controller_id,
-                       dma_private->channel_id, irq);
-               fsl_dma_abort_stream(dma_private->substream);
+               dev_err(dev, "dma programming error\n");
+               fsl_dma_abort_stream(substream);
                sr2 |= CCSR_DMA_SR_PE;
                ret = IRQ_HANDLED;
        }
@@ -253,8 +252,6 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
                ret = IRQ_HANDLED;
 
        if (sr & CCSR_DMA_SR_EOSI) {
-               struct snd_pcm_substream *substream = dma_private->substream;
-
                /* Tell ALSA we completed a period. */
                snd_pcm_period_elapsed(substream);
 
@@ -288,11 +285,19 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
  * This function is called when the codec driver calls snd_soc_new_pcms(),
  * once for each .dai_link in the machine driver's snd_soc_card
  * structure.
+ *
+ * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which
+ * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM
+ * is specified. Therefore, any DMA buffers we allocate will always be in low
+ * memory, but we support for 36-bit physical addresses anyway.
+ *
+ * Regardless of where the memory is actually allocated, since the device can
+ * technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
  */
 static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
-       static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
+       static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
        int ret;
 
        if (!card->dev->dma_mask)
@@ -301,25 +306,29 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = fsl_dma_dmamask;
 
-       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
-               fsl_dma_hardware.buffer_bytes_max,
-               &pcm->streams[0].substream->dma_buffer);
-       if (ret) {
-               dev_err(card->dev,
-                       "Can't allocate playback DMA buffer (size=%u)\n",
-                       fsl_dma_hardware.buffer_bytes_max);
-               return -ENOMEM;
+       /* Some codecs have separate DAIs for playback and capture, so we
+        * should allocate a DMA buffer only for the streams that are valid.
+        */
+
+       if (dai->driver->playback.channels_min) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+                       fsl_dma_hardware.buffer_bytes_max,
+                       &pcm->streams[0].substream->dma_buffer);
+               if (ret) {
+                       dev_err(card->dev, "can't alloc playback dma buffer\n");
+                       return ret;
+               }
        }
 
-       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
-               fsl_dma_hardware.buffer_bytes_max,
-               &pcm->streams[1].substream->dma_buffer);
-       if (ret) {
-               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
-               dev_err(card->dev,
-                       "Can't allocate capture DMA buffer (size=%u)\n",
-                       fsl_dma_hardware.buffer_bytes_max);
-               return -ENOMEM;
+       if (dai->driver->capture.channels_min) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+                       fsl_dma_hardware.buffer_bytes_max,
+                       &pcm->streams[1].substream->dma_buffer);
+               if (ret) {
+                       snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+                       dev_err(card->dev, "can't alloc capture dma buffer\n");
+                       return ret;
+               }
        }
 
        return 0;
@@ -390,6 +399,10 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
 static int fsl_dma_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct dma_object *dma =
+               container_of(rtd->platform->driver, struct dma_object, dai);
        struct fsl_dma_private *dma_private;
        struct ccsr_dma_channel __iomem *dma_channel;
        dma_addr_t ld_buf_phys;
@@ -407,52 +420,45 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
        ret = snd_pcm_hw_constraint_integer(runtime,
                SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+               dev_err(dev, "invalid buffer size\n");
                return ret;
        }
 
        channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
 
-       if (dma_global_data.assigned[channel]) {
-               dev_err(substream->pcm->card->dev,
-                       "DMA channel already assigned\n");
+       if (dma->assigned) {
+               dev_err(dev, "dma channel already assigned\n");
                return -EBUSY;
        }
 
-       dma_private = dma_alloc_coherent(substream->pcm->card->dev,
-               sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
+       dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private),
+                                        &ld_buf_phys, GFP_KERNEL);
        if (!dma_private) {
-               dev_err(substream->pcm->card->dev,
-                       "can't allocate DMA private data\n");
+               dev_err(dev, "can't allocate dma private data\n");
                return -ENOMEM;
        }
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
+               dma_private->ssi_sxx_phys = dma->ssi_stx_phys;
        else
-               dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
+               dma_private->ssi_sxx_phys = dma->ssi_srx_phys;
 
-       dma_private->dma_channel = dma_global_data.dma_channel[channel];
-       dma_private->irq = dma_global_data.irq[channel];
+       dma_private->ssi_fifo_depth = dma->ssi_fifo_depth;
+       dma_private->dma_channel = dma->channel;
+       dma_private->irq = dma->irq;
        dma_private->substream = substream;
        dma_private->ld_buf_phys = ld_buf_phys;
        dma_private->dma_buf_phys = substream->dma_buffer.addr;
 
-       /* We only support one DMA controller for now */
-       dma_private->controller_id = 0;
-       dma_private->channel_id = channel;
-
        ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
        if (ret) {
-               dev_err(substream->pcm->card->dev,
-                       "can't register ISR for IRQ %u (ret=%i)\n",
+               dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
                        dma_private->irq, ret);
-               dma_free_coherent(substream->pcm->card->dev,
-                       sizeof(struct fsl_dma_private),
+               dma_free_coherent(dev, sizeof(struct fsl_dma_private),
                        dma_private, dma_private->ld_buf_phys);
                return ret;
        }
 
-       dma_global_data.assigned[channel] = 1;
+       dma->assigned = 1;
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -546,13 +552,15 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
 
        /* Number of bits per sample */
-       unsigned int sample_size =
+       unsigned int sample_bits =
                snd_pcm_format_physical_width(params_format(hw_params));
 
        /* Number of bytes per frame */
-       unsigned int frame_size = 2 * (sample_size / 8);
+       unsigned int sample_bytes = sample_bits / 8;
 
        /* Bus address of SSI STX register */
        dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
@@ -592,7 +600,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
         * that offset here.  While we're at it, also tell the DMA controller
         * how much data to transfer per sample.
         */
-       switch (sample_size) {
+       switch (sample_bits) {
        case 8:
                mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
                ssi_sxx_phys += 3;
@@ -606,23 +614,42 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
                break;
        default:
                /* We should never get here */
-               dev_err(substream->pcm->card->dev,
-                       "unsupported sample size %u\n", sample_size);
+               dev_err(dev, "unsupported sample size %u\n", sample_bits);
                return -EINVAL;
        }
 
        /*
-        * BWC should always be a multiple of the frame size.  BWC determines
-        * how many bytes are sent/received before the DMA controller checks the
-        * SSI to see if it needs to stop.  For playback, the transmit FIFO can
-        * hold three frames, so we want to send two frames at a time. For
-        * capture, the receive FIFO is triggered when it contains one frame, so
-        * we want to receive one frame at a time.
+        * BWC determines how many bytes are sent/received before the DMA
+        * controller checks the SSI to see if it needs to stop. BWC should
+        * always be a multiple of the frame size, so that we always transmit
+        * whole frames.  Each frame occupies two slots in the FIFO.  The
+        * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two
+        * (MR[BWC] can only represent even powers of two).
+        *
+        * To simplify the process, we set BWC to the largest value that is
+        * less than or equal to the FIFO watermark.  For playback, this ensures
+        * that we transfer the maximum amount without overrunning the FIFO.
+        * For capture, this ensures that we transfer the maximum amount without
+        * underrunning the FIFO.
+        *
+        * f = SSI FIFO depth
+        * w = SSI watermark value (which equals f - 2)
+        * b = DMA bandwidth count (in bytes)
+        * s = sample size (in bytes, which equals frame_size * 2)
+        *
+        * For playback, we never transmit more than the transmit FIFO
+        * watermark, otherwise we might write more data than the FIFO can hold.
+        * The watermark is equal to the FIFO depth minus two.
+        *
+        * For capture, two equations must hold:
+        *      w > f - (b / s)
+        *      w >= b / s
+        *
+        * So, b > 2 * s, but b must also be <= s * w.  To simplify, we set
+        * b = s * w, which is equal to
+        *      (dma_private->ssi_fifo_depth - 2) * sample_bytes.
         */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mr |= CCSR_DMA_MR_BWC(2 * frame_size);
-       else
-               mr |= CCSR_DMA_MR_BWC(frame_size);
+       mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes);
 
        out_be32(&dma_channel->mr, mr);
 
@@ -631,12 +658,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
 
                link->count = cpu_to_be32(period_size);
 
-               /* Even though the DMA controller supports 36-bit addressing,
-                * for simplicity we allow only 32-bit addresses for the audio
-                * buffer itself.  This was enforced in fsl_dma_new() with the
-                * DMA mask.
-                *
-                * The snoop bit tells the DMA controller whether it should tell
+               /* The snoop bit tells the DMA controller whether it should tell
                 * the ECM to snoop during a read or write to an address. For
                 * audio, we use DMA to transfer data between memory and an I/O
                 * device (the SSI's STX0 or SRX0 register). Snooping is only
@@ -651,20 +673,24 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
                 * flush out the data for the previous period.  So if you
                 * increased period_bytes_min to a large enough size, you might
                 * get more performance by not snooping, and you'll still be
-                * okay.
+                * okay.  You'll need to update fsl_dma_update_pointers() also.
                 */
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        link->source_addr = cpu_to_be32(temp_addr);
-                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                               upper_32_bits(temp_addr));
 
                        link->dest_addr = cpu_to_be32(ssi_sxx_phys);
-                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+                               upper_32_bits(ssi_sxx_phys));
                } else {
                        link->source_addr = cpu_to_be32(ssi_sxx_phys);
-                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+                               upper_32_bits(ssi_sxx_phys));
 
                        link->dest_addr = cpu_to_be32(temp_addr);
-                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                               upper_32_bits(temp_addr));
                }
 
                temp_addr += period_size;
@@ -689,14 +715,29 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
        struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
        dma_addr_t position;
        snd_pcm_uframes_t frames;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       /* Obtain the current DMA pointer, but don't read the ESAD bits if we
+        * only have 32-bit DMA addresses.  This function is typically called
+        * in interrupt context, so we need to optimize it.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                position = in_be32(&dma_channel->sar);
-       else
+#ifdef CONFIG_PHYS_64BIT
+               position |= (u64)(in_be32(&dma_channel->satr) &
+                                 CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+       } else {
                position = in_be32(&dma_channel->dar);
+#ifdef CONFIG_PHYS_64BIT
+               position |= (u64)(in_be32(&dma_channel->datr) &
+                                 CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+       }
 
        /*
         * When capture is started, the SSI immediately starts to fill its FIFO.
@@ -710,8 +751,7 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
 
        if ((position < dma_private->dma_buf_phys) ||
            (position > dma_private->dma_buf_end)) {
-               dev_err(substream->pcm->card->dev,
-                       "dma pointer is out of range, halting stream\n");
+               dev_err(dev, "dma pointer is out of range, halting stream\n");
                return SNDRV_PCM_POS_XRUN;
        }
 
@@ -772,26 +812,28 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
-       int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct dma_object *dma =
+               container_of(rtd->platform->driver, struct dma_object, dai);
 
        if (dma_private) {
                if (dma_private->irq)
                        free_irq(dma_private->irq, dma_private);
 
                if (dma_private->ld_buf_phys) {
-                       dma_unmap_single(substream->pcm->card->dev,
-                               dma_private->ld_buf_phys,
-                               sizeof(dma_private->link), DMA_TO_DEVICE);
+                       dma_unmap_single(dev, dma_private->ld_buf_phys,
+                                        sizeof(dma_private->link),
+                                        DMA_TO_DEVICE);
                }
 
                /* Deallocate the fsl_dma_private structure */
-               dma_free_coherent(substream->pcm->card->dev,
-                       sizeof(struct fsl_dma_private),
-                       dma_private, dma_private->ld_buf_phys);
+               dma_free_coherent(dev, sizeof(struct fsl_dma_private),
+                                 dma_private, dma_private->ld_buf_phys);
                substream->runtime->private_data = NULL;
        }
 
-       dma_global_data.assigned[dir] = 0;
+       dma->assigned = 0;
 
        return 0;
 }
@@ -814,6 +856,37 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
+/**
+ * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ *
+ * Although this DMA driver attempts to operate independently of the other
+ * devices, it still needs to determine some information about the SSI device
+ * that it's working with.  Unfortunately, the device tree does not contain
+ * a pointer from the DMA channel node to the SSI node -- the pointer goes the
+ * other way.  So we need to scan the device tree for SSI nodes until we find
+ * the one that points to the given DMA channel node.  It's ugly, but at least
+ * it's contained in this one function.
+ */
+static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
+{
+       struct device_node *ssi_np, *np;
+
+       for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
+               /* Check each DMA phandle to see if it points to us.  We
+                * assume that device_node pointers are a valid comparison.
+                */
+               np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+               if (np == dma_channel_np)
+                       return ssi_np;
+
+               np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+               if (np == dma_channel_np)
+                       return ssi_np;
+       }
+
+       return NULL;
+}
+
 static struct snd_pcm_ops fsl_dma_ops = {
        .open           = fsl_dma_open,
        .close          = fsl_dma_close,
@@ -823,59 +896,114 @@ static struct snd_pcm_ops fsl_dma_ops = {
        .pointer        = fsl_dma_pointer,
 };
 
-struct snd_soc_platform fsl_soc_platform = {
-       .name           = "fsl-dma",
-       .pcm_ops        = &fsl_dma_ops,
-       .pcm_new        = fsl_dma_new,
-       .pcm_free       = fsl_dma_free_dma_buffers,
-};
-EXPORT_SYMBOL_GPL(fsl_soc_platform);
+static int __devinit fsl_soc_dma_probe(struct platform_device *pdev,
+                                      const struct of_device_id *match)
+ {
+       struct dma_object *dma;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np;
+       struct resource res;
+       const uint32_t *iprop;
+       int ret;
 
-/**
- * fsl_dma_configure: store the DMA parameters from the fabric driver.
- *
- * This function is called by the ASoC fabric driver to give us the DMA and
- * SSI channel information.
- *
- * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
- * data when a substream is created, so for now we need to store this data
- * into a global variable.  This means that we can only support one DMA
- * controller, and hence only one SSI.
- */
-int fsl_dma_configure(struct fsl_dma_info *dma_info)
+       /* Find the SSI node that points to us. */
+       ssi_np = find_ssi_node(np);
+       if (!ssi_np) {
+               dev_err(&pdev->dev, "cannot find parent SSI node\n");
+               return -ENODEV;
+       }
+
+       ret = of_address_to_resource(ssi_np, 0, &res);
+       if (ret) {
+               dev_err(&pdev->dev, "could not determine resources for %s\n",
+                       ssi_np->full_name);
+               of_node_put(ssi_np);
+               return ret;
+       }
+
+       dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+       if (!dma) {
+               dev_err(&pdev->dev, "could not allocate dma object\n");
+               of_node_put(ssi_np);
+               return -ENOMEM;
+       }
+
+       strcpy(dma->path, np->full_name);
+       dma->dai.ops = &fsl_dma_ops;
+       dma->dai.pcm_new = fsl_dma_new;
+       dma->dai.pcm_free = fsl_dma_free_dma_buffers;
+
+       /* Store the SSI-specific information that we need */
+       dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
+       dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
+
+       iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+       if (iprop)
+               dma->ssi_fifo_depth = *iprop;
+       else
+                /* Older 8610 DTs didn't have the fifo-depth property */
+               dma->ssi_fifo_depth = 8;
+
+       of_node_put(ssi_np);
+
+       ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
+       if (ret) {
+               dev_err(&pdev->dev, "could not register platform\n");
+               kfree(dma);
+               return ret;
+       }
+
+       dma->channel = of_iomap(np, 0);
+       dma->irq = irq_of_parse_and_map(np, 0);
+
+       dev_set_drvdata(&pdev->dev, dma);
+
+       return 0;
+}
+
+static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
 {
-       static int initialized;
+       struct dma_object *dma = dev_get_drvdata(&pdev->dev);
 
-       /* We only support one DMA controller for now */
-       if (initialized)
-               return 0;
+       snd_soc_unregister_platform(&pdev->dev);
+       iounmap(dma->channel);
+       irq_dispose_mapping(dma->irq);
+       kfree(dma);
 
-       dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
-       dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
-       dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
-       dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
-       dma_global_data.irq[0] = dma_info->dma_irq[0];
-       dma_global_data.irq[1] = dma_info->dma_irq[1];
-       dma_global_data.assigned[0] = 0;
-       dma_global_data.assigned[1] = 0;
-
-       initialized = 1;
-       return 1;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(fsl_dma_configure);
 
-static int __init fsl_soc_platform_init(void)
+static const struct of_device_id fsl_soc_dma_ids[] = {
+       { .compatible = "fsl,ssi-dma-channel", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_soc_dma_ids);
+
+static struct of_platform_driver fsl_soc_dma_driver = {
+       .driver = {
+               .name = "fsl-pcm-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_soc_dma_ids,
+       },
+       .probe = fsl_soc_dma_probe,
+       .remove = __devexit_p(fsl_soc_dma_remove),
+};
+
+static int __init fsl_soc_dma_init(void)
 {
-       return snd_soc_register_platform(&fsl_soc_platform);
+       pr_info("Freescale Elo DMA ASoC PCM Driver\n");
+
+       return of_register_platform_driver(&fsl_soc_dma_driver);
 }
-module_init(fsl_soc_platform_init);
 
-static void __exit fsl_soc_platform_exit(void)
+static void __exit fsl_soc_dma_exit(void)
 {
-       snd_soc_unregister_platform(&fsl_soc_platform);
+       of_unregister_platform_driver(&fsl_soc_dma_driver);
 }
-module_exit(fsl_soc_platform_exit);
+
+module_init(fsl_soc_dma_init);
+module_exit(fsl_soc_dma_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
+MODULE_LICENSE("GPL v2");
index 385d4a42603cf3b681ab12c6f050ccd3e11f7bb0..78fee97e80362eab8035b5eee0bc5df44ce8499b 100644 (file)
@@ -126,24 +126,4 @@ struct fsl_dma_link_descriptor {
        u8 res[4];      /* Reserved */
 } __attribute__ ((aligned(32), packed));
 
-/* DMA information needed to create a snd_soc_dai object
- *
- * ssi_stx_phys: bus address of SSI STX register to use
- * ssi_srx_phys: bus address of SSI SRX register to use
- * dma[0]: points to the DMA channel to use for playback
- * dma[1]: points to the DMA channel to use for capture
- * dma_irq[0]: IRQ of the DMA channel to use for playback
- * dma_irq[1]: IRQ of the DMA channel to use for capture
- */
-struct fsl_dma_info {
-       dma_addr_t ssi_stx_phys;
-       dma_addr_t ssi_srx_phys;
-       struct ccsr_dma_channel __iomem *dma_channel[2];
-       unsigned int dma_irq[2];
-};
-
-extern struct snd_soc_platform fsl_soc_platform;
-
-int fsl_dma_configure(struct fsl_dma_info *dma_info);
-
 #endif
index 762c1b8e8e4e078e48efede6dfc52b5a81eb4fc4..4cc167a7aeb82d411306f23634891aeb3ca6da79 100644 (file)
@@ -3,10 +3,11 @@
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, 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.
+ * Copyright 2007-2010 Freescale Semiconductor, 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/init.h>
@@ -15,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of_platform.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -22,8 +24,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <asm/immap_86xx.h>
-
 #include "fsl_ssi.h"
 
 /**
 /**
  * fsl_ssi_private: per-SSI private data
  *
- * @name: short name for this device ("SSI0", "SSI1", etc)
  * @ssi: pointer to the SSI's registers
  * @ssi_phys: physical address of the SSI registers
  * @irq: IRQ of this SSI
  * @first_stream: pointer to the stream that was opened first
  * @second_stream: pointer to second stream
- * @dev: struct device pointer
  * @playback: the number of playback streams opened
  * @capture: the number of capture streams opened
  * @asynchronous: 0=synchronous mode, 1=asynchronous mode
  * @cpu_dai: the CPU DAI for this device
  * @dev_attr: the sysfs device attribute structure
  * @stats: SSI statistics
+ * @name: name for this device
  */
 struct fsl_ssi_private {
-       char name[8];
        struct ccsr_ssi __iomem *ssi;
        dma_addr_t ssi_phys;
        unsigned int irq;
        struct snd_pcm_substream *first_stream;
        struct snd_pcm_substream *second_stream;
-       struct device *dev;
        unsigned int playback;
        unsigned int capture;
        int asynchronous;
-       struct snd_soc_dai cpu_dai;
+       unsigned int fifo_depth;
+       struct snd_soc_dai_driver cpu_dai_drv;
        struct device_attribute dev_attr;
+       struct platform_device *pdev;
 
        struct {
                unsigned int rfrc;
@@ -122,6 +121,8 @@ struct fsl_ssi_private {
                unsigned int tfe1;
                unsigned int tfe0;
        } stats;
+
+       char name[1];
 };
 
 /**
@@ -280,7 +281,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 
        /*
         * If this is the first stream opened, then request the IRQ
@@ -290,6 +291,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
                int ret;
 
+               /* The 'name' should not have any slashes in it. */
                ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
                                  ssi_private->name, ssi_private);
                if (ret < 0) {
@@ -336,11 +338,20 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 
                /*
                 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
-                * don't use FIFO 1.  Since the SSI only supports stereo, the
-                * watermark should never be an odd number.
+                * don't use FIFO 1.  We program the transmit water to signal a
+                * DMA transfer if there are only two (or fewer) elements left
+                * in the FIFO.  Two elements equals one frame (left channel,
+                * right channel).  This value, however, depends on the depth of
+                * the transmit buffer.
+                *
+                * We program the receive FIFO to notify us if at least two
+                * elements (one frame) have been written to the FIFO.  We could
+                * make this value larger (and maybe we should), but this way
+                * data will be written to memory as soon as it's available.
                 */
                out_be32(&ssi->sfcsr,
-                        CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
+                       CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+                       CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
 
                /*
                 * We keep the SSI disabled because if we enable it, then the
@@ -422,7 +433,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
 {
-       struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (substream == ssi_private->first_stream) {
                struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -458,7 +469,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
 
        switch (cmd) {
@@ -497,7 +508,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                ssi_private->playback--;
@@ -523,56 +534,15 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
-/**
- * fsl_ssi_set_sysclk: set the clock frequency and direction
- *
- * This function is called by the machine driver to tell us what the clock
- * frequency and direction are.
- *
- * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
- * and we don't care about the frequency.  Return an error if the direction
- * is not SND_SOC_CLOCK_IN.
- *
- * @clk_id: reserved, should be zero
- * @freq: the frequency of the given clock ID, currently ignored
- * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
- */
-static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
-                             int clk_id, unsigned int freq, int dir)
-{
-
-       return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_set_fmt: set the serial format.
- *
- * This function is called by the machine driver to tell us what serial
- * format to use.
- *
- * Currently, we only support I2S mode.  Return an error if the format is
- * not SND_SOC_DAIFMT_I2S.
- *
- * @format: one of SND_SOC_DAIFMT_xxx
- */
-static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
-{
-       return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_dai_template: template CPU DAI for the SSI
- */
 static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
        .hw_params      = fsl_ssi_hw_params,
        .shutdown       = fsl_ssi_shutdown,
        .trigger        = fsl_ssi_trigger,
-       .set_sysclk     = fsl_ssi_set_sysclk,
-       .set_fmt        = fsl_ssi_set_fmt,
 };
 
-static struct snd_soc_dai fsl_ssi_dai_template = {
+/* Template for the CPU dai driver structure */
+static struct snd_soc_dai_driver fsl_ssi_dai_template = {
        .playback = {
                /* The SSI does not support monaural audio. */
                .channels_min = 2,
@@ -640,95 +610,195 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev,
 }
 
 /**
- * fsl_ssi_create_dai: create a snd_soc_dai structure
- *
- * This function is called by the machine driver to create a snd_soc_dai
- * structure.  The function creates an ssi_private object, which contains
- * the snd_soc_dai.  It also creates the sysfs statistics device.
+ * Make every character in a string lower-case
  */
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+static void make_lowercase(char *s)
+{
+       char *p = s;
+       char c;
+
+       while ((c = *p)) {
+               if ((c >= 'A') && (c <= 'Z'))
+                       *p = c + ('a' - 'A');
+               p++;
+       }
+}
+
+static int __devinit fsl_ssi_probe(struct platform_device *pdev,
+                                  const struct of_device_id *match)
 {
-       struct snd_soc_dai *fsl_ssi_dai;
        struct fsl_ssi_private *ssi_private;
        int ret = 0;
-       struct device_attribute *dev_attr;
+       struct device_attribute *dev_attr = NULL;
+       struct device_node *np = pdev->dev.of_node;
+       const char *p, *sprop;
+       const uint32_t *iprop;
+       struct resource res;
+       char name[64];
+
+       /* SSIs that are not connected on the board should have a
+        *      status = "disabled"
+        * property in their device tree nodes.
+        */
+       if (!of_device_is_available(np))
+               return -ENODEV;
+
+       /* Check for a codec-handle property. */
+       if (!of_get_property(np, "codec-handle", NULL)) {
+               dev_err(&pdev->dev, "missing codec-handle property\n");
+               return -ENODEV;
+       }
 
-       ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
+       /* We only support the SSI in "I2S Slave" mode */
+       sprop = of_get_property(np, "fsl,mode", NULL);
+       if (!sprop || strcmp(sprop, "i2s-slave")) {
+               dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
+               return -ENODEV;
+       }
+
+       /* The DAI name is the last part of the full name of the node. */
+       p = strrchr(np->full_name, '/') + 1;
+       ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+                             GFP_KERNEL);
        if (!ssi_private) {
-               dev_err(ssi_info->dev, "could not allocate DAI object\n");
-               return NULL;
+               dev_err(&pdev->dev, "could not allocate DAI object\n");
+               return -ENOMEM;
        }
-       memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
-              sizeof(struct snd_soc_dai));
 
-       fsl_ssi_dai = &ssi_private->cpu_dai;
-       dev_attr = &ssi_private->dev_attr;
+       strcpy(ssi_private->name, p);
 
-       sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
-       ssi_private->ssi = ssi_info->ssi;
-       ssi_private->ssi_phys = ssi_info->ssi_phys;
-       ssi_private->irq = ssi_info->irq;
-       ssi_private->dev = ssi_info->dev;
-       ssi_private->asynchronous = ssi_info->asynchronous;
+       /* Initialize this copy of the CPU DAI driver structure */
+       memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+              sizeof(fsl_ssi_dai_template));
+       ssi_private->cpu_dai_drv.name = ssi_private->name;
 
-       dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
+       /* Get the addresses and IRQ */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               dev_err(&pdev->dev, "could not determine device resources\n");
+               kfree(ssi_private);
+               return ret;
+       }
+       ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
+       ssi_private->ssi_phys = res.start;
+       ssi_private->irq = irq_of_parse_and_map(np, 0);
+
+       /* Are the RX and the TX clocks locked? */
+       if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
+               ssi_private->asynchronous = 1;
+       else
+               ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
+       /* Determine the FIFO depth. */
+       iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+       if (iprop)
+               ssi_private->fifo_depth = *iprop;
+       else
+                /* Older 8610 DTs didn't have the fifo-depth property */
+               ssi_private->fifo_depth = 8;
 
        /* Initialize the the device_attribute structure */
-       dev_attr->attr.name = "ssi-stats";
+       dev_attr = &ssi_private->dev_attr;
+       dev_attr->attr.name = "statistics";
        dev_attr->attr.mode = S_IRUGO;
        dev_attr->show = fsl_sysfs_ssi_show;
 
-       ret = device_create_file(ssi_private->dev, dev_attr);
+       ret = device_create_file(&pdev->dev, dev_attr);
        if (ret) {
-               dev_err(ssi_info->dev, "could not create sysfs %s file\n",
+               dev_err(&pdev->dev, "could not create sysfs %s file\n",
                        ssi_private->dev_attr.attr.name);
-               kfree(fsl_ssi_dai);
-               return NULL;
+               goto error;
        }
 
-       fsl_ssi_dai->private_data = ssi_private;
-       fsl_ssi_dai->name = ssi_private->name;
-       fsl_ssi_dai->id = ssi_info->id;
-       fsl_ssi_dai->dev = ssi_info->dev;
-       fsl_ssi_dai->symmetric_rates = 1;
+       /* Register with ASoC */
+       dev_set_drvdata(&pdev->dev, ssi_private);
+
+       ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+               goto error;
+       }
 
-       ret = snd_soc_register_dai(fsl_ssi_dai);
-       if (ret != 0) {
-               dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret);
-               kfree(fsl_ssi_dai);
-               return NULL;
+       /* Trigger the machine driver's probe function.  The platform driver
+        * name of the machine driver is taken from the /model property of the
+        * device tree.  We also pass the address of the CPU DAI driver
+        * structure.
+        */
+       sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+       /* Sometimes the model name has a "fsl," prefix, so we strip that. */
+       p = strrchr(sprop, ',');
+       if (p)
+               sprop = p + 1;
+       snprintf(name, sizeof(name), "snd-soc-%s", sprop);
+       make_lowercase(name);
+
+       ssi_private->pdev =
+               platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
+       if (IS_ERR(ssi_private->pdev)) {
+               ret = PTR_ERR(ssi_private->pdev);
+               dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
+               goto error;
        }
 
-       return fsl_ssi_dai;
+       return 0;
+
+error:
+       snd_soc_unregister_dai(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, NULL);
+       if (dev_attr)
+               device_remove_file(&pdev->dev, dev_attr);
+       irq_dispose_mapping(ssi_private->irq);
+       iounmap(ssi_private->ssi);
+       kfree(ssi_private);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
 
-/**
- * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
- *
- * This function undoes the operations of fsl_ssi_create_dai()
- */
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
+static int fsl_ssi_remove(struct platform_device *pdev)
 {
-       struct fsl_ssi_private *ssi_private =
-       container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
-
-       device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
+       struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&ssi_private->cpu_dai);
+       platform_device_unregister(ssi_private->pdev);
+       snd_soc_unregister_dai(&pdev->dev);
+       device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
        kfree(ssi_private);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+
+static const struct of_device_id fsl_ssi_ids[] = {
+       { .compatible = "fsl,mpc8610-ssi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
+static struct of_platform_driver fsl_ssi_driver = {
+       .driver = {
+               .name = "fsl-ssi-dai",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_ssi_ids,
+       },
+       .probe = fsl_ssi_probe,
+       .remove = fsl_ssi_remove,
+};
 
 static int __init fsl_ssi_init(void)
 {
        printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
 
-       return 0;
+       return of_register_platform_driver(&fsl_ssi_driver);
 }
+
+static void __exit fsl_ssi_exit(void)
+{
+       of_unregister_platform_driver(&fsl_ssi_driver);
+}
+
 module_init(fsl_ssi_init);
+module_exit(fsl_ssi_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index eade01feaab69f0d69ea82c13466307d52158a14..217300029b5ba44463ccf4423c09093a602bac1d 100644 (file)
@@ -196,31 +196,5 @@ struct ccsr_ssi {
 #define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
 #define CCSR_SSI_SOR_SYNRST            0x00000001
 
-/* Instantiation data for an SSI interface
- *
- * This structure contains all the information that the the SSI driver needs
- * to instantiate an SSI interface with ALSA.  The machine driver should
- * create this structure, fill it in, call fsl_ssi_create_dai(), and then
- * delete the structure.
- *
- * id: which SSI this is (0, 1, etc. )
- * ssi: pointer to the SSI's registers
- * ssi_phys: physical address of the SSI registers
- * irq: IRQ of this SSI
- * dev: struct device, used to create the sysfs statistics file
- * asynchronous: 0=synchronous mode, 1=asynchronous mode
-*/
-struct fsl_ssi_info {
-       unsigned int id;
-       struct ccsr_ssi __iomem *ssi;
-       dma_addr_t ssi_phys;
-       unsigned int irq;
-       struct device *dev;
-       int asynchronous;
-};
-
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
-
 #endif
 
index 3dcd1469f2831939447b60f8410da6c6a0f2e11e..dce6b551cd7816be84c5dbd77db74be4c88e8315 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #include <sound/soc.h>
 
@@ -107,7 +109,7 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream)
 static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -212,7 +214,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
        int rc;
 
@@ -239,7 +241,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
 static int psc_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
 
        dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -264,7 +266,7 @@ static snd_pcm_uframes_t
 psc_dma_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
        dma_addr_t count;
 
@@ -302,11 +304,11 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
                           struct snd_pcm *pcm)
 {
        struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        size_t size = psc_dma_hardware.buffer_bytes_max;
        int rc = 0;
 
-       dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+       dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
                card, dai, pcm);
 
        if (!card->dev->dma_mask)
@@ -328,8 +330,8 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
                        goto capture_alloc_err;
        }
 
-       if (rtd->socdev->card->codec->ac97)
-               rtd->socdev->card->codec->ac97->private_data = psc_dma;
+       if (rtd->codec->ac97)
+               rtd->codec->ac97->private_data = psc_dma;
 
        return 0;
 
@@ -349,7 +351,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
        struct snd_pcm_substream *substream;
        int stream;
 
-       dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+       dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
 
        for (stream = 0; stream < 2; stream++) {
                substream = pcm->streams[stream].substream;
@@ -361,15 +363,14 @@ static void psc_dma_free(struct snd_pcm *pcm)
        }
 }
 
-struct snd_soc_platform mpc5200_audio_dma_platform = {
-       .name           = "mpc5200-psc-audio",
-       .pcm_ops        = &psc_dma_ops,
+static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+       .ops            = &psc_dma_ops,
        .pcm_new        = &psc_dma_new,
        .pcm_free       = &psc_dma_free,
 };
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
 
-int mpc5200_audio_dma_create(struct platform_device *op)
+static int mpc5200_hpcd_probe(struct of_device *op,
+               const struct of_device_id *match)
 {
        phys_addr_t fifo;
        struct psc_dma *psc_dma;
@@ -475,7 +476,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
        dev_set_drvdata(&op->dev, psc_dma);
 
        /* Tell the ASoC OF helpers about it */
-       return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+       return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
 out_irq:
        free_irq(psc_dma->irq, psc_dma);
        free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -486,15 +487,14 @@ out_unmap:
        iounmap(regs);
        return ret;
 }
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
 
-int mpc5200_audio_dma_destroy(struct platform_device *op)
+static int mpc5200_hpcd_remove(struct of_device *op)
 {
        struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
 
        dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
 
-       snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+       snd_soc_unregister_platform(&op->dev);
 
        bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
        bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
@@ -510,7 +510,35 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+static struct of_device_id mpc5200_hpcd_match[] = {
+       {
+               .compatible = "fsl,mpc5200-pcm",
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
+
+static struct of_platform_driver mpc5200_hpcd_of_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "mpc5200-pcm-audio",
+       .match_table    = mpc5200_hpcd_match,
+       .probe          = mpc5200_hpcd_probe,
+       .remove         = mpc5200_hpcd_remove,
+};
+
+static int __init mpc5200_hpcd_init(void)
+{
+       return of_register_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+static void __exit mpc5200_hpcd_exit(void)
+{
+       of_unregister_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+module_init(mpc5200_hpcd_init);
+module_exit(mpc5200_hpcd_exit);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
index ca99586f2ad993ecc286a0fe4e11a083aa9ee11e..a3c0cd5382fbbfdb74a52b93ceaef444e87f011f 100644 (file)
@@ -81,9 +81,4 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
        return &psc_dma->playback;
 }
 
-int mpc5200_audio_dma_create(struct platform_device *op);
-int mpc5200_audio_dma_destroy(struct platform_device *op);
-
-extern struct snd_soc_platform mpc5200_audio_dma_platform;
-
 #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
index a9560235daeee3d4260d6066f9951bc89aa5ab4f..40acc8e2b1cac1a36ba8a94d11dccd9d10129e55 100644 (file)
@@ -143,7 +143,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -166,7 +166,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
 
        dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
 
@@ -181,8 +181,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
 static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
                                                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        switch (cmd) {
@@ -207,10 +206,9 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int psc_ac97_probe(struct platform_device *pdev,
-                                       struct snd_soc_dai *cpu_dai)
+static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
 
        /* Go */
@@ -237,9 +235,8 @@ static struct snd_soc_dai_ops psc_ac97_digital_ops = {
        .hw_params      = psc_ac97_hw_digital_params,
 };
 
-struct snd_soc_dai psc_ac97_dai[] = {
+static struct snd_soc_dai_driver psc_ac97_dai[] = {
 {
-       .name   = "AC97",
        .ac97_control = 1,
        .probe  = psc_ac97_probe,
        .playback = {
@@ -257,7 +254,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
        .ops = &psc_ac97_analog_ops,
 },
 {
-       .name   = "SPDIF",
        .ac97_control = 1,
        .playback = {
                .channels_min   = 1,
@@ -268,7 +264,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
        },
        .ops = &psc_ac97_digital_ops,
 } };
-EXPORT_SYMBOL_GPL(psc_ac97_dai);
 
 
 
@@ -280,18 +275,11 @@ EXPORT_SYMBOL_GPL(psc_ac97_dai);
 static int __devinit psc_ac97_of_probe(struct platform_device *op,
                                      const struct of_device_id *match)
 {
-       int rc, i;
+       int rc;
        struct snd_ac97 ac97;
        struct mpc52xx_psc __iomem *regs;
 
-       rc = mpc5200_audio_dma_create(op);
-       if (rc != 0)
-               return rc;
-
-       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
-               psc_ac97_dai[i].dev = &op->dev;
-
-       rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+       rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
                return rc;
@@ -301,9 +289,6 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
        regs = psc_dma->psc_regs;
        ac97.private_data = psc_dma;
 
-       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
-               psc_ac97_dai[i].private_data = psc_dma;
-
        psc_dma->imr = 0;
        out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
 
@@ -319,7 +304,8 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
 
 static int __devexit psc_ac97_of_remove(struct platform_device *op)
 {
-       return mpc5200_audio_dma_destroy(op);
+       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+       return 0;
 }
 
 /* Match table for of_platform binding */
index 4bc18c35c369f41fb5f7b582ed94432a8e241fbd..e881e784b27041ffe1ead098aa581e43ac18b8cd 100644 (file)
@@ -7,8 +7,6 @@
 #ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
 #define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
 
-extern struct snd_soc_dai psc_ac97_dai[];
-
 #define MPC5200_AC97_NORMAL 0
 #define MPC5200_AC97_SPDIF 1
 
index 534f04cb15d7d1df602b4d8a3e65c962d93ad845..74ffed41340ff00c5d9ba97dc927059731b80673 100644 (file)
@@ -40,7 +40,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        u32 mode;
 
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -88,7 +88,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                              int clk_id, unsigned int freq, int dir)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
                                cpu_dai, dir);
        return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
@@ -107,7 +107,7 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
  */
 static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
                                cpu_dai, format);
        return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@ -129,8 +129,7 @@ static struct snd_soc_dai_ops psc_i2s_dai_ops = {
        .set_fmt        = psc_i2s_set_fmt,
 };
 
-struct snd_soc_dai psc_i2s_dai[] = {{
-       .name   = "I2S",
+static struct snd_soc_dai_driver psc_i2s_dai[] = {{
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -145,7 +144,6 @@ struct snd_soc_dai psc_i2s_dai[] = {{
        },
        .ops = &psc_i2s_dai_ops,
 } };
-EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -159,11 +157,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
        struct psc_dma *psc_dma;
        struct mpc52xx_psc __iomem *regs;
 
-       rc = mpc5200_audio_dma_create(op);
-       if (rc != 0)
-               return rc;
-
-       rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+       rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
                return 0;
@@ -207,7 +201,8 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
 
 static int __devexit psc_i2s_of_remove(struct platform_device *op)
 {
-       return mpc5200_audio_dma_destroy(op);
+       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+       return 0;
 }
 
 /* Match table for of_platform binding */
index 3b13b8d65262722d0bfbcc7e8e5d205a47485073..0d7dcf1e4863592c439a626b7fe449b56669f45d 100644 (file)
@@ -1,85 +1,97 @@
 /**
- * Freescale MPC8610HPCD ALSA SoC Fabric driver
+ * Freescale MPC8610HPCD ALSA SoC Machine driver
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, 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.
+ * Copyright 2007-2010 Freescale Semiconductor, 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/slab.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/slab.h>
 #include <sound/soc.h>
-#include <asm/immap_86xx.h>
+#include <asm/fsl_guts.h>
 
-#include "../codecs/cs4270.h"
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
 
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE  32
+
 /**
- * mpc8610_hpcd_data: fabric-specific ASoC device data
+ * mpc8610_hpcd_data: machine-specific ASoC device data
  *
  * This structure contains data for a single sound platform device on an
  * MPC8610 HPCD.  Some of the data is taken from the device tree.
  */
 struct mpc8610_hpcd_data {
-       struct snd_soc_device sound_devdata;
-       struct snd_soc_dai_link dai;
-       struct snd_soc_card machine;
+       struct snd_soc_dai_link dai[2];
+       struct snd_soc_card card;
        unsigned int dai_format;
        unsigned int codec_clk_direction;
        unsigned int cpu_clk_direction;
        unsigned int clk_frequency;
-       struct ccsr_guts __iomem *guts;
-       struct ccsr_ssi __iomem *ssi;
-       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
-       unsigned int ssi_irq;
-       unsigned int dma_id;            /* 0 = DMA1, 1 = DMA2, etc */
-       unsigned int dma_irq[2];
-       struct ccsr_dma_channel __iomem *dma[2];
+       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
+       unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
        unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+       char codec_dai_name[DAI_NAME_SIZE];
+       char codec_name[DAI_NAME_SIZE];
+       char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
 /**
  * mpc8610_hpcd_machine_probe: initialize the board
  *
- * This function is called when platform_device_add() is called.  It is used
- * to initialize the board-specific hardware.
+ * This function is used to initialize the board-specific hardware.
  *
  * Here we program the DMACR and PMUXCR registers.
  */
 static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
 {
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
+       struct ccsr_guts_86xx __iomem *guts;
 
-       /* Program the signal routing between the SSI and the DMA */
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
 
-       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], 0);
-       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], 0);
+       /* Program the signal routing between the SSI and the DMA */
+       guts_set_dmacr(guts, machine_data->dma_id[0],
+                      machine_data->dma_channel_id[0],
+                      CCSR_GUTS_DMACR_DEV_SSI);
+       guts_set_dmacr(guts, machine_data->dma_id[1],
+                      machine_data->dma_channel_id[1],
+                      CCSR_GUTS_DMACR_DEV_SSI);
+
+       guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
+                           machine_data->dma_channel_id[0], 0);
+       guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
+                           machine_data->dma_channel_id[1], 0);
 
        switch (machine_data->ssi_id) {
        case 0:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
                break;
        case 1:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
                break;
        }
 
+       iounmap(guts);
+
        return 0;
 }
 
@@ -93,38 +105,15 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
 static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct mpc8610_hpcd_data *machine_data =
-               rtd->socdev->dev->platform_data;
+               container_of(rtd->card, struct mpc8610_hpcd_data, card);
+       struct device *dev = rtd->card->dev;
        int ret = 0;
 
-       /* Tell the CPU driver what the serial protocol is. */
-       ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
-       if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set CPU driver audio format\n");
-               return ret;
-       }
-
        /* Tell the codec driver what the serial protocol is. */
-       ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format);
+       ret = snd_soc_dai_set_fmt(rtd->codec_dai, machine_data->dai_format);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set codec driver audio format\n");
-               return ret;
-       }
-
-       /*
-        * Tell the CPU driver what the clock frequency is, and whether it's a
-        * slave or master.
-        */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
-                                       machine_data->clk_frequency,
-                                       machine_data->cpu_clk_direction);
-       if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set CPU driver clock parameters\n");
+               dev_err(dev, "could not set codec driver audio format\n");
                return ret;
        }
 
@@ -132,12 +121,11 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
         * Tell the codec driver what the MCLK frequency is, and whether it's
         * a slave or master.
         */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-                                       machine_data->clk_frequency,
-                                       machine_data->codec_clk_direction);
+       ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
+                                    machine_data->clk_frequency,
+                                    machine_data->codec_clk_direction);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set codec driver clock params\n");
+               dev_err(dev, "could not set codec driver clock params\n");
                return ret;
        }
 
@@ -150,116 +138,255 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
  * This function is called to remove the sound device for one SSI.  We
  * de-program the DMACR and PMUXCR register.
  */
-int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
 {
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
+       struct ccsr_guts_86xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
 
        /* Restore the signal routing */
 
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], 0);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], 0);
+       guts_set_dmacr(guts, machine_data->dma_id[0],
+                      machine_data->dma_channel_id[0], 0);
+       guts_set_dmacr(guts, machine_data->dma_id[1],
+                      machine_data->dma_channel_id[1], 0);
 
        switch (machine_data->ssi_id) {
        case 0:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
                break;
        case 1:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
                break;
        }
 
+       iounmap(guts);
+
        return 0;
 }
 
 /**
- * mpc8610_hpcd_ops: ASoC fabric driver operations
+ * mpc8610_hpcd_ops: ASoC machine driver operations
  */
 static struct snd_soc_ops mpc8610_hpcd_ops = {
        .startup = mpc8610_hpcd_startup,
 };
 
 /**
- * mpc8610_hpcd_probe: OF probe function for the fabric driver
+ * get_node_by_phandle_name - get a node by its phandle name
  *
- * This function gets called when an SSI node is found in the device tree.
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string.  Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
  *
- * Although this is a fabric driver, the SSI node is the "master" node with
- * respect to audio hardware connections.  Therefore, we create a new ASoC
- * device for each new SSI node that has a codec attached.
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+                                              const char *name,
+                                              const char *compatible)
+{
+       const phandle *ph;
+       int len;
+
+       ph = of_get_property(np, name, &len);
+       if (!ph || (len != sizeof(phandle)))
+               return NULL;
+
+       np = of_find_node_by_phandle(*ph);
+       if (!np)
+               return NULL;
+
+       if (compatible && !of_device_is_compatible(np, compatible)) {
+               of_node_put(np);
+               return NULL;
+       }
+
+       return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node.  This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+       struct device_node *parent = of_get_parent(np);
+       const u32 *iprop;
+
+       if (!parent)
+               return -1;
+
+       iprop = of_get_property(parent, "cell-index", NULL);
+       of_node_put(parent);
+
+       if (!iprop)
+               return -1;
+
+       return *iprop;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
  *
- * FIXME: Currently, we only support one DMA controller, so if there are
- * multiple SSI nodes with codecs, only the first will be supported.
+ * This function determines the dev_name for an I2C node.  This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device'  It's ugly and hackish, but it works.
  *
- * FIXME: Even if we did support multiple DMA controllers, we have no
- * mechanism for assigning DMA controllers and channels to the individual
- * SSI devices.  We also probably aren't compatible with the generic Elo DMA
- * device driver.
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
  */
-static int mpc8610_hpcd_probe(struct platform_device *ofdev,
-       const struct of_device_id *match)
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 {
-       struct device_node *np = ofdev->dev.of_node;
-       struct device_node *codec_np = NULL;
-       struct device_node *guts_np = NULL;
-       struct device_node *dma_np = NULL;
-       struct device_node *dma_channel_np = NULL;
-       const phandle *codec_ph;
-       const char *sprop;
        const u32 *iprop;
+       int bus, addr;
+       char temp[DAI_NAME_SIZE];
+
+       of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+       iprop = of_get_property(np, "reg", NULL);
+       if (!iprop)
+               return -EINVAL;
+
+       addr = *iprop;
+
+       bus = get_parent_cell_index(np);
+       if (bus < 0)
+               return bus;
+
+       snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+       return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+                          const char *compatible,
+                          struct snd_soc_dai_link *dai,
+                          unsigned int *dma_channel_id,
+                          unsigned int *dma_id)
+{
        struct resource res;
+       struct device_node *dma_channel_np;
+       const u32 *iprop;
+       int ret;
+
+       dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+                                                 "fsl,ssi-dma-channel");
+       if (!dma_channel_np)
+               return -EINVAL;
+
+       /* Determine the dev_name for the device_node.  This code mimics the
+        * behavior of of_device_make_bus_id(). We need this because ASoC uses
+        * the dev_name() of the device to match the platform (DMA) device with
+        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+        * now).
+        *
+        * dai->platform name should already point to an allocated buffer.
+        */
+       ret = of_address_to_resource(dma_channel_np, 0, &res);
+       if (ret)
+               return ret;
+       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+                (unsigned long long) res.start, dma_channel_np->name);
+
+       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+
+       *dma_channel_id = *iprop;
+       *dma_id = get_parent_cell_index(dma_channel_np);
+       of_node_put(dma_channel_np);
+
+       return 0;
+}
+
+/**
+ * mpc8610_hpcd_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections.  Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int mpc8610_hpcd_probe(struct platform_device *pdev)
+{
+       struct device *dev = pdev->dev.parent;
+       /* ssi_pdev is the platform device for the SSI node that probed us */
+       struct platform_device *ssi_pdev =
+               container_of(dev, struct platform_device, dev);
+       struct device_node *np = ssi_pdev->dev.of_node;
+       struct device_node *codec_np = NULL;
        struct platform_device *sound_device = NULL;
        struct mpc8610_hpcd_data *machine_data;
-       struct fsl_ssi_info ssi_info;
-       struct fsl_dma_info dma_info;
        int ret = -ENODEV;
-       unsigned int playback_dma_channel;
-       unsigned int capture_dma_channel;
+       const char *sprop;
+       const u32 *iprop;
+
+       /* We are only interested in SSIs with a codec phandle in them,
+        * so let's make sure this SSI has one. The MPC8610 HPCD only
+        * knows about the CS4270 codec, so reject anything else.
+        */
+       codec_np = get_node_by_phandle_name(np, "codec-handle",
+                                           "cirrus,cs4270");
+       if (!codec_np) {
+               dev_err(dev, "invalid codec node\n");
+               return -EINVAL;
+       }
 
        machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
        if (!machine_data)
                return -ENOMEM;
 
-       memset(&ssi_info, 0, sizeof(ssi_info));
-       memset(&dma_info, 0, sizeof(dma_info));
+       machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+       machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-       ssi_info.dev = &ofdev->dev;
-
-       /*
-        * We are only interested in SSIs with a codec phandle in them, so let's
-        * make sure this SSI has one.
-        */
-       codec_ph = of_get_property(np, "codec-handle", NULL);
-       if (!codec_ph)
+       /* Determine the codec name, it will be used as the codec DAI name */
+       ret = codec_node_dev_name(codec_np, machine_data->codec_name,
+                                 DAI_NAME_SIZE);
+       if (ret) {
+               dev_err(&pdev->dev, "invalid codec node %s\n",
+                       codec_np->full_name);
+               ret = -EINVAL;
                goto error;
+       }
+       machine_data->dai[0].codec_name = machine_data->codec_name;
 
-       codec_np = of_find_node_by_phandle(*codec_ph);
-       if (!codec_np)
-               goto error;
+       /* The DAI name from the codec (snd_soc_dai_driver.name) */
+       machine_data->dai[0].codec_dai_name = "cs4270-hifi";
 
-       /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
-          anything else. */
-       if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
-               goto error;
+       /* We register two DAIs per SSI, one for playback and the other for
+        * capture.  Currently, we only support codecs that have one DAI for
+        * both playback and capture.
+        */
+       memcpy(&machine_data->dai[1], &machine_data->dai[0],
+              sizeof(struct snd_soc_dai_link));
 
        /* Get the device ID */
        iprop = of_get_property(np, "cell-index", NULL);
        if (!iprop) {
-               dev_err(&ofdev->dev, "cell-index property not found\n");
+               dev_err(&pdev->dev, "cell-index property not found\n");
                ret = -EINVAL;
                goto error;
        }
        machine_data->ssi_id = *iprop;
-       ssi_info.id = *iprop;
 
        /* Get the serial format and clock direction. */
        sprop = of_get_property(np, "fsl,mode", NULL);
        if (!sprop) {
-               dev_err(&ofdev->dev, "fsl,mode property not found\n");
+               dev_err(&pdev->dev, "fsl,mode property not found\n");
                ret = -EINVAL;
                goto error;
        }
@@ -269,15 +396,14 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
                machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
                machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
 
-               /*
-                * In i2s-slave mode, the codec has its own clock source, so we
+               /* In i2s-slave mode, the codec has its own clock source, so we
                 * need to get the frequency from the device tree and pass it to
                 * the codec driver.
                 */
                iprop = of_get_property(codec_np, "clock-frequency", NULL);
                if (!iprop || !*iprop) {
-                       dev_err(&ofdev->dev, "codec bus-frequency property "
-                               "is missing or invalid\n");
+                       dev_err(&pdev->dev, "codec bus-frequency "
+                               "property is missing or invalid\n");
                        ret = -EINVAL;
                        goto error;
                }
@@ -311,317 +437,153 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
                machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
                machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
        } else {
-               dev_err(&ofdev->dev,
-                       "unrecognized fsl,mode property \"%s\"\n", sprop);
+               dev_err(&pdev->dev,
+                       "unrecognized fsl,mode property '%s'\n", sprop);
                ret = -EINVAL;
                goto error;
        }
 
        if (!machine_data->clk_frequency) {
-               dev_err(&ofdev->dev, "unknown clock frequency\n");
+               dev_err(&pdev->dev, "unknown clock frequency\n");
                ret = -EINVAL;
                goto error;
        }
 
-       /* Read the SSI information from the device tree */
-       ret = of_address_to_resource(np, 0, &res);
+       /* Find the playback DMA channel to use. */
+       machine_data->dai[0].platform_name = machine_data->platform_name[0];
+       ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
+                             &machine_data->dma_channel_id[0],
+                             &machine_data->dma_id[0]);
        if (ret) {
-               dev_err(&ofdev->dev, "could not obtain SSI address\n");
-               goto error;
-       }
-       if (!res.start) {
-               dev_err(&ofdev->dev, "invalid SSI address\n");
-               goto error;
-       }
-       ssi_info.ssi_phys = res.start;
-
-       machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
-       if (!machine_data->ssi) {
-               dev_err(&ofdev->dev, "could not map SSI address %x\n",
-                       ssi_info.ssi_phys);
-               ret = -EINVAL;
-               goto error;
-       }
-       ssi_info.ssi = machine_data->ssi;
-
-
-       /* Get the IRQ of the SSI */
-       machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
-       if (!machine_data->ssi_irq) {
-               dev_err(&ofdev->dev, "could not get SSI IRQ\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       ssi_info.irq = machine_data->ssi_irq;
-
-       /* Do we want to use asynchronous mode? */
-       ssi_info.asynchronous =
-               of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
-       if (ssi_info.asynchronous)
-               dev_info(&ofdev->dev, "using asynchronous mode\n");
-
-       /* Map the global utilities registers. */
-       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
-       if (!guts_np) {
-               dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       machine_data->guts = of_iomap(guts_np, 0);
-       of_node_put(guts_np);
-       if (!machine_data->guts) {
-               dev_err(&ofdev->dev, "could not map GUTS\n");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       /* Find the DMA channels to use.  Both SSIs need to use the same DMA
-        * controller, so let's use DMA#1.
-        */
-       for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
-               iprop = of_get_property(dma_np, "cell-index", NULL);
-               if (iprop && (*iprop == 0)) {
-                       of_node_put(dma_np);
-                       break;
-               }
-       }
-       if (!dma_np) {
-               dev_err(&ofdev->dev, "could not find DMA node\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       machine_data->dma_id = *iprop;
-
-       /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
-        * channels 2 and 3.  This is just how the MPC8610 is wired
-        * internally.
-        */
-       playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
-       capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
-
-       /*
-        * Find the DMA channels to use.
-        */
-       while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
-               iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-               if (iprop && (*iprop == playback_dma_channel)) {
-                       /* dma_channel[0] and dma_irq[0] are for playback */
-                       dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
-                       dma_info.dma_irq[0] =
-                               irq_of_parse_and_map(dma_channel_np, 0);
-                       machine_data->dma_channel_id[0] = *iprop;
-                       continue;
-               }
-               if (iprop && (*iprop == capture_dma_channel)) {
-                       /* dma_channel[1] and dma_irq[1] are for capture */
-                       dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
-                       dma_info.dma_irq[1] =
-                               irq_of_parse_and_map(dma_channel_np, 0);
-                       machine_data->dma_channel_id[1] = *iprop;
-                       continue;
-               }
-       }
-       if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
-           !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
-               dev_err(&ofdev->dev, "could not find DMA channels\n");
-               ret = -EINVAL;
+               dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
                goto error;
        }
 
-       dma_info.ssi_stx_phys = ssi_info.ssi_phys +
-               offsetof(struct ccsr_ssi, stx0);
-       dma_info.ssi_srx_phys = ssi_info.ssi_phys +
-               offsetof(struct ccsr_ssi, srx0);
-
-       /* We have the DMA information, so tell the DMA driver what it is */
-       if (!fsl_dma_configure(&dma_info)) {
-               dev_err(&ofdev->dev, "could not instantiate DMA device\n");
-               ret = -EBUSY;
+       /* Find the capture DMA channel to use. */
+       machine_data->dai[1].platform_name = machine_data->platform_name[1];
+       ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
+                             &machine_data->dma_channel_id[1],
+                             &machine_data->dma_id[1]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
                goto error;
        }
 
-       /*
-        * Initialize our DAI data structure.  We should probably get this
-        * information from the device tree.
-        */
-       machine_data->dai.name = "CS4270";
-       machine_data->dai.stream_name = "CS4270";
-
-       machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
-       machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
-       machine_data->dai.ops = &mpc8610_hpcd_ops;
+       /* Initialize our DAI data structure.  */
+       machine_data->dai[0].stream_name = "playback";
+       machine_data->dai[1].stream_name = "capture";
+       machine_data->dai[0].name = machine_data->dai[0].stream_name;
+       machine_data->dai[1].name = machine_data->dai[1].stream_name;
 
-       machine_data->machine.probe = mpc8610_hpcd_machine_probe;
-       machine_data->machine.remove = mpc8610_hpcd_machine_remove;
-       machine_data->machine.name = "MPC8610 HPCD";
-       machine_data->machine.num_links = 1;
-       machine_data->machine.dai_link = &machine_data->dai;
+       machine_data->card.probe = mpc8610_hpcd_machine_probe;
+       machine_data->card.remove = mpc8610_hpcd_machine_remove;
+       machine_data->card.name = pdev->name; /* The platform driver name */
+       machine_data->card.num_links = 2;
+       machine_data->card.dai_link = machine_data->dai;
 
        /* Allocate a new audio platform device structure */
        sound_device = platform_device_alloc("soc-audio", -1);
        if (!sound_device) {
-               dev_err(&ofdev->dev, "platform device allocation failed\n");
+               dev_err(&pdev->dev, "platform device alloc failed\n");
                ret = -ENOMEM;
                goto error;
        }
 
-       machine_data->sound_devdata.card = &machine_data->machine;
-       machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
-       machine_data->machine.platform = &fsl_soc_platform;
-
-       sound_device->dev.platform_data = machine_data;
-
+       /* Associate the card data with the sound device */
+       platform_set_drvdata(sound_device, &machine_data->card);
 
-       /* Set the platform device and ASoC device to point to each other */
-       platform_set_drvdata(sound_device, &machine_data->sound_devdata);
-
-       machine_data->sound_devdata.dev = &sound_device->dev;
-
-
-       /* Tell ASoC to probe us.  This will call mpc8610_hpcd_machine.probe(),
-          if it exists. */
+       /* Register with ASoC */
        ret = platform_device_add(sound_device);
-
        if (ret) {
-               dev_err(&ofdev->dev, "platform device add failed\n");
+               dev_err(&pdev->dev, "platform device add failed\n");
                goto error;
        }
 
-       dev_set_drvdata(&ofdev->dev, sound_device);
+       of_node_put(codec_np);
 
        return 0;
 
 error:
        of_node_put(codec_np);
-       of_node_put(guts_np);
-       of_node_put(dma_np);
-       of_node_put(dma_channel_np);
 
        if (sound_device)
                platform_device_unregister(sound_device);
 
-       if (machine_data->dai.cpu_dai)
-               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
-       if (ssi_info.ssi)
-               iounmap(ssi_info.ssi);
-
-       if (ssi_info.irq)
-               irq_dispose_mapping(ssi_info.irq);
-
-       if (dma_info.dma_channel[0])
-               iounmap(dma_info.dma_channel[0]);
-
-       if (dma_info.dma_channel[1])
-               iounmap(dma_info.dma_channel[1]);
-
-       if (dma_info.dma_irq[0])
-               irq_dispose_mapping(dma_info.dma_irq[0]);
-
-       if (dma_info.dma_irq[1])
-               irq_dispose_mapping(dma_info.dma_irq[1]);
-
-       if (machine_data->guts)
-               iounmap(machine_data->guts);
-
        kfree(machine_data);
 
        return ret;
 }
 
 /**
- * mpc8610_hpcd_remove: remove the OF device
+ * mpc8610_hpcd_remove: remove the platform device
  *
- * This function is called when the OF device is removed.
+ * This function is called when the platform device is removed.
  */
-static int mpc8610_hpcd_remove(struct platform_device *ofdev)
+static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
 {
-       struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
+       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
 
        platform_device_unregister(sound_device);
 
-       if (machine_data->dai.cpu_dai)
-               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
-       if (machine_data->ssi)
-               iounmap(machine_data->ssi);
-
-       if (machine_data->dma[0])
-               iounmap(machine_data->dma[0]);
-
-       if (machine_data->dma[1])
-               iounmap(machine_data->dma[1]);
-
-       if (machine_data->dma_irq[0])
-               irq_dispose_mapping(machine_data->dma_irq[0]);
-
-       if (machine_data->dma_irq[1])
-               irq_dispose_mapping(machine_data->dma_irq[1]);
-
-       if (machine_data->guts)
-               iounmap(machine_data->guts);
-
        kfree(machine_data);
        sound_device->dev.platform_data = NULL;
 
-       dev_set_drvdata(&ofdev->dev, NULL);
+       dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id mpc8610_hpcd_match[] = {
-       {
-               .compatible = "fsl,mpc8610-ssi",
-       },
-       {}
-};
-MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
-
-static struct of_platform_driver mpc8610_hpcd_of_driver = {
+static struct platform_driver mpc8610_hpcd_driver = {
+       .probe = mpc8610_hpcd_probe,
+       .remove = __devexit_p(mpc8610_hpcd_remove),
        .driver = {
-               .name = "mpc8610_hpcd",
+               /* The name must match the 'model' property in the device tree,
+                * in lowercase letters.
+                */
+               .name = "snd-soc-mpc8610hpcd",
                .owner = THIS_MODULE,
-               .of_match_table = mpc8610_hpcd_match,
        },
-       .probe          = mpc8610_hpcd_probe,
-       .remove         = mpc8610_hpcd_remove,
 };
 
 /**
- * mpc8610_hpcd_init: fabric driver initialization.
+ * mpc8610_hpcd_init: machine driver initialization.
  *
  * This function is called when this module is loaded.
  */
 static int __init mpc8610_hpcd_init(void)
 {
-       int ret;
-
-       printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
+       struct device_node *guts_np;
+       struct resource res;
 
-       ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
+       pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
 
-       if (ret)
-               printk(KERN_ERR
-                       "mpc8610-hpcd: failed to register platform driver\n");
+       /* Get the physical address of the global utilities registers */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+       if (of_address_to_resource(guts_np, 0, &res)) {
+               pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
+               return -EINVAL;
+       }
+       guts_phys = res.start;
 
-       return ret;
+       return platform_driver_register(&mpc8610_hpcd_driver);
 }
 
 /**
- * mpc8610_hpcd_exit: fabric driver exit
+ * mpc8610_hpcd_exit: machine driver exit
  *
  * This function is called when this driver is unloaded.
  */
 static void __exit mpc8610_hpcd_exit(void)
 {
-       of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
+       platform_driver_unregister(&mpc8610_hpcd_driver);
 }
 
 module_init(mpc8610_hpcd_init);
 module_exit(mpc8610_hpcd_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
new file mode 100644 (file)
index 0000000..63b9eaa
--- /dev/null
@@ -0,0 +1,591 @@
+/**
+ * Freescale P1022DS ALSA SoC Machine driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_dma.h"
+#include "fsl_ssi.h"
+
+/* P1022-specific PMUXCR and DMUXCR bit definitions */
+
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK       0x0001c000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI  0x00010000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI                0x00018000
+
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK      0x00000c00
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI       0x00000000
+
+#define CCSR_GUTS_DMUXCR_PAD   1       /* DMA controller/channel set to pad */
+#define CCSR_GUTS_DMUXCR_SSI   2       /* DMA controller/channel set to SSI */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller.  Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
+ */
+static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
+       unsigned int co, unsigned int ch, unsigned int device)
+{
+       unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+       clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift);
+}
+
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE  32
+
+/**
+ * machine_data: machine-specific ASoC device data
+ *
+ * This structure contains data for a single sound platform device on an
+ * P1022 DS.  Some of the data is taken from the device tree.
+ */
+struct machine_data {
+       struct snd_soc_dai_link dai[2];
+       struct snd_soc_card card;
+       unsigned int dai_format;
+       unsigned int codec_clk_direction;
+       unsigned int cpu_clk_direction;
+       unsigned int clk_frequency;
+       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
+       unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
+       unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+       char codec_name[DAI_NAME_SIZE];
+       char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
+};
+
+/**
+ * p1022_ds_machine_probe: initialize the board
+ *
+ * This function is used to initialize the board-specific hardware.
+ *
+ * Here we program the DMACR and PMUXCR registers.
+ */
+static int p1022_ds_machine_probe(struct platform_device *sound_device)
+{
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+       struct ccsr_guts_85xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
+
+       /* Enable SSI Tx signal */
+       clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK,
+                       CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI);
+
+       /* Enable SSI Rx signal */
+       clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK,
+                       CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI);
+
+       /* Enable DMA Channel for SSI */
+       guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0],
+                       CCSR_GUTS_DMUXCR_SSI);
+
+       guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1],
+                       CCSR_GUTS_DMUXCR_SSI);
+
+       iounmap(guts);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_startup: program the board with various hardware parameters
+ *
+ * This function takes board-specific information, like clock frequencies
+ * and serial data formats, and passes that information to the codec and
+ * transport drivers.
+ */
+static int p1022_ds_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct machine_data *mdata =
+               container_of(rtd->card, struct machine_data, card);
+       struct device *dev = rtd->card->dev;
+       int ret = 0;
+
+       /* Tell the codec driver what the serial protocol is. */
+       ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format);
+       if (ret < 0) {
+               dev_err(dev, "could not set codec driver audio format\n");
+               return ret;
+       }
+
+       /*
+        * Tell the codec driver what the MCLK frequency is, and whether it's
+        * a slave or master.
+        */
+       ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, mdata->clk_frequency,
+                                    mdata->codec_clk_direction);
+       if (ret < 0) {
+               dev_err(dev, "could not set codec driver clock params\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * p1022_ds_machine_remove: Remove the sound device
+ *
+ * This function is called to remove the sound device for one SSI.  We
+ * de-program the DMACR and PMUXCR register.
+ */
+static int p1022_ds_machine_remove(struct platform_device *sound_device)
+{
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+       struct ccsr_guts_85xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
+
+       /* Restore the signal routing */
+       clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK);
+       clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK);
+       guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0);
+       guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0);
+
+       iounmap(guts);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_ops: ASoC machine driver operations
+ */
+static struct snd_soc_ops p1022_ds_ops = {
+       .startup = p1022_ds_startup,
+};
+
+/**
+ * get_node_by_phandle_name - get a node by its phandle name
+ *
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string.  Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
+ *
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+       const char *name, const char *compatible)
+{
+       np = of_parse_phandle(np, name, 0);
+       if (!np)
+               return NULL;
+
+       if (!of_device_is_compatible(np, compatible)) {
+               of_node_put(np);
+               return NULL;
+       }
+
+       return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node.  This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+       struct device_node *parent = of_get_parent(np);
+       const u32 *iprop;
+       int ret = -1;
+
+       if (!parent)
+               return -1;
+
+       iprop = of_get_property(parent, "cell-index", NULL);
+       if (iprop)
+               ret = *iprop;
+
+       of_node_put(parent);
+
+       return ret;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node.  This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device'  It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+       const u32 *iprop;
+       int bus, addr;
+       char temp[DAI_NAME_SIZE];
+
+       of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+       iprop = of_get_property(np, "reg", NULL);
+       if (!iprop)
+               return -EINVAL;
+
+       addr = *iprop;
+
+       bus = get_parent_cell_index(np);
+       if (bus < 0)
+               return bus;
+
+       snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+       return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+                          const char *compatible,
+                          struct snd_soc_dai_link *dai,
+                          unsigned int *dma_channel_id,
+                          unsigned int *dma_id)
+{
+       struct resource res;
+       struct device_node *dma_channel_np;
+       const u32 *iprop;
+       int ret;
+
+       dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+                                                 "fsl,ssi-dma-channel");
+       if (!dma_channel_np)
+               return -EINVAL;
+
+       /* Determine the dev_name for the device_node.  This code mimics the
+        * behavior of of_device_make_bus_id(). We need this because ASoC uses
+        * the dev_name() of the device to match the platform (DMA) device with
+        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+        * now).
+        *
+        * dai->platform name should already point to an allocated buffer.
+        */
+       ret = of_address_to_resource(dma_channel_np, 0, &res);
+       if (ret)
+               return ret;
+       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+                (unsigned long long) res.start, dma_channel_np->name);
+
+       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+
+       *dma_channel_id = *iprop;
+       *dma_id = get_parent_cell_index(dma_channel_np);
+       of_node_put(dma_channel_np);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections.  Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int p1022_ds_probe(struct platform_device *pdev)
+{
+       struct device *dev = pdev->dev.parent;
+       /* ssi_pdev is the platform device for the SSI node that probed us */
+       struct platform_device *ssi_pdev =
+               container_of(dev, struct platform_device, dev);
+       struct device_node *np = ssi_pdev->dev.of_node;
+       struct device_node *codec_np = NULL;
+       struct platform_device *sound_device = NULL;
+       struct machine_data *mdata;
+       int ret = -ENODEV;
+       const char *sprop;
+       const u32 *iprop;
+
+       /* Find the codec node for this SSI. */
+       codec_np = of_parse_phandle(np, "codec-handle", 0);
+       if (!codec_np) {
+               dev_err(dev, "could not find codec node\n");
+               return -EINVAL;
+       }
+
+       mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL);
+       if (!mdata) {
+               ret = -ENOMEM;
+               goto error_put;
+       }
+
+       mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+       mdata->dai[0].ops = &p1022_ds_ops;
+
+       /* Determine the codec name, it will be used as the codec DAI name */
+       ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
+       if (ret) {
+               dev_err(&pdev->dev, "invalid codec node %s\n",
+                       codec_np->full_name);
+               ret = -EINVAL;
+               goto error;
+       }
+       mdata->dai[0].codec_name = mdata->codec_name;
+
+       /* We register two DAIs per SSI, one for playback and the other for
+        * capture.  We support codecs that have separate DAIs for both playback
+        * and capture.
+        */
+       memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link));
+
+       /* The DAI names from the codec (snd_soc_dai_driver.name) */
+       mdata->dai[0].codec_dai_name = "wm8776-hifi-playback";
+       mdata->dai[1].codec_dai_name = "wm8776-hifi-capture";
+
+       /* Get the device ID */
+       iprop = of_get_property(np, "cell-index", NULL);
+       if (!iprop) {
+               dev_err(&pdev->dev, "cell-index property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       mdata->ssi_id = *iprop;
+
+       /* Get the serial format and clock direction. */
+       sprop = of_get_property(np, "fsl,mode", NULL);
+       if (!sprop) {
+               dev_err(&pdev->dev, "fsl,mode property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (strcasecmp(sprop, "i2s-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_I2S;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+
+               /* In i2s-slave mode, the codec has its own clock source, so we
+                * need to get the frequency from the device tree and pass it to
+                * the codec driver.
+                */
+               iprop = of_get_property(codec_np, "clock-frequency", NULL);
+               if (!iprop || !*iprop) {
+                       dev_err(&pdev->dev, "codec bus-frequency "
+                               "property is missing or invalid\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               mdata->clk_frequency = *iprop;
+       } else if (strcasecmp(sprop, "i2s-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_I2S;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "lj-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "lj-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "rj-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "rj-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "ac97-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_AC97;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "ac97-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_AC97;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else {
+               dev_err(&pdev->dev,
+                       "unrecognized fsl,mode property '%s'\n", sprop);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (!mdata->clk_frequency) {
+               dev_err(&pdev->dev, "unknown clock frequency\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Find the playback DMA channel to use. */
+       mdata->dai[0].platform_name = mdata->platform_name[0];
+       ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+                             &mdata->dma_channel_id[0],
+                             &mdata->dma_id[0]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
+               goto error;
+       }
+
+       /* Find the capture DMA channel to use. */
+       mdata->dai[1].platform_name = mdata->platform_name[1];
+       ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+                             &mdata->dma_channel_id[1],
+                             &mdata->dma_id[1]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
+               goto error;
+       }
+
+       /* Initialize our DAI data structure.  */
+       mdata->dai[0].stream_name = "playback";
+       mdata->dai[1].stream_name = "capture";
+       mdata->dai[0].name = mdata->dai[0].stream_name;
+       mdata->dai[1].name = mdata->dai[1].stream_name;
+
+       mdata->card.probe = p1022_ds_machine_probe;
+       mdata->card.remove = p1022_ds_machine_remove;
+       mdata->card.name = pdev->name; /* The platform driver name */
+       mdata->card.num_links = 2;
+       mdata->card.dai_link = mdata->dai;
+
+       /* Allocate a new audio platform device structure */
+       sound_device = platform_device_alloc("soc-audio", -1);
+       if (!sound_device) {
+               dev_err(&pdev->dev, "platform device alloc failed\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* Associate the card data with the sound device */
+       platform_set_drvdata(sound_device, &mdata->card);
+
+       /* Register with ASoC */
+       ret = platform_device_add(sound_device);
+       if (ret) {
+               dev_err(&pdev->dev, "platform device add failed\n");
+               goto error;
+       }
+
+       of_node_put(codec_np);
+
+       return 0;
+
+error:
+       if (sound_device)
+               platform_device_unregister(sound_device);
+
+       kfree(mdata);
+error_put:
+       of_node_put(codec_np);
+       return ret;
+}
+
+/**
+ * p1022_ds_remove: remove the platform device
+ *
+ * This function is called when the platform device is removed.
+ */
+static int __devexit p1022_ds_remove(struct platform_device *pdev)
+{
+       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+
+       platform_device_unregister(sound_device);
+
+       kfree(mdata);
+       sound_device->dev.platform_data = NULL;
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver p1022_ds_driver = {
+       .probe = p1022_ds_probe,
+       .remove = __devexit_p(p1022_ds_remove),
+       .driver = {
+               /* The name must match the 'model' property in the device tree,
+                * in lowercase letters, but only the part after that last
+                * comma.  This is because some model properties have a "fsl,"
+                * prefix.
+                */
+               .name = "snd-soc-p1022",
+               .owner = THIS_MODULE,
+       },
+};
+
+/**
+ * p1022_ds_init: machine driver initialization.
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init p1022_ds_init(void)
+{
+       struct device_node *guts_np;
+       struct resource res;
+
+       pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
+
+       /* Get the physical address of the global utilities registers */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (of_address_to_resource(guts_np, 0, &res)) {
+               pr_err("p1022-ds: missing/invalid global utilities node\n");
+               return -EINVAL;
+       }
+       guts_phys = res.start;
+       of_node_put(guts_np);
+
+       return platform_driver_register(&p1022_ds_driver);
+}
+
+/**
+ * p1022_ds_exit: machine driver exit
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit p1022_ds_exit(void)
+{
+       platform_driver_unregister(&p1022_ds_driver);
+}
+
+module_init(p1022_ds_init);
+module_exit(p1022_ds_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale P1022 DS ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
index 6644cba7cbf20e5a16e75ad459df1c2663afcc93..fe15bb26e48474e6f9aacb15961d62b59cea704d 100644 (file)
 
 #define DRV_NAME "pcm030-audio-fabric"
 
-static struct snd_soc_device device;
 static struct snd_soc_card card;
 
 static struct snd_soc_dai_link pcm030_fabric_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 Analog",
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+       .codec_dai_name = "wm9712-hifi",
+       .cpu_dai_name = "mpc5200-psc-ac97.0",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "wm9712-codec",
 },
 {
        .name = "AC97",
        .stream_name = "AC97 IEC958",
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+       .codec_dai_name = "wm9712-aux",
+       .cpu_dai_name = "mpc5200-psc-ac97.1",
+       .platform_name = "mpc5200-pcm-audio",
+       ..codec_name = "wm9712-codec",
 },
 };
 
@@ -58,22 +61,18 @@ static __init int pcm030_fabric_init(void)
        if (!of_machine_is_compatible("phytec,pcm030"))
                return -ENODEV;
 
-       card.platform = &mpc5200_audio_dma_platform;
+
        card.name = "pcm030";
        card.dai_link = pcm030_fabric_dai;
        card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
 
-       device.card = &card;
-       device.codec_dev = &soc_codec_dev_wm9712;
-
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
                pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
                return -ENODEV;
        }
 
-       platform_set_drvdata(pdev, &device);
-       device.dev = &pdev->dev;
+       platform_set_drvdata(pdev, &card);
 
        rc = platform_device_add(pdev);
        if (rc) {
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
deleted file mode 100644 (file)
index 3bc13fd..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * OF helpers for ALSA SoC Layer
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
-
-static DEFINE_MUTEX(of_snd_soc_mutex);
-static LIST_HEAD(of_snd_soc_device_list);
-static int of_snd_soc_next_index;
-
-struct of_snd_soc_device {
-       int id;
-       struct list_head list;
-       struct snd_soc_device device;
-       struct snd_soc_card card;
-       struct snd_soc_dai_link dai_link;
-       struct platform_device *pdev;
-       struct device_node *platform_node;
-       struct device_node *codec_node;
-};
-
-static struct snd_soc_ops of_snd_soc_ops = {
-};
-
-static struct of_snd_soc_device *
-of_snd_soc_get_device(struct device_node *codec_node)
-{
-       struct of_snd_soc_device *of_soc;
-
-       list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
-               if (of_soc->codec_node == codec_node)
-                       return of_soc;
-       }
-
-       of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
-       if (!of_soc)
-               return NULL;
-
-       /* Initialize the structure and add it to the global list */
-       of_soc->codec_node = codec_node;
-       of_soc->id = of_snd_soc_next_index++;
-       of_soc->card.dai_link = &of_soc->dai_link;
-       of_soc->card.num_links = 1;
-       of_soc->device.card = &of_soc->card;
-       of_soc->dai_link.ops = &of_snd_soc_ops;
-       list_add(&of_soc->list, &of_snd_soc_device_list);
-
-       return of_soc;
-}
-
-static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
-{
-       struct platform_device *pdev;
-       int rc;
-
-       /* Only register the device if both the codec and platform have
-        * been registered */
-       if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
-               return;
-
-       pr_info("platform<-->codec match achieved; registering machine\n");
-
-       pdev = platform_device_alloc("soc-audio", of_soc->id);
-       if (!pdev) {
-               pr_err("of_soc: platform_device_alloc() failed\n");
-               return;
-       }
-
-       pdev->dev.platform_data = of_soc;
-       platform_set_drvdata(pdev, &of_soc->device);
-       of_soc->device.dev = &pdev->dev;
-
-       /* The ASoC device is complete; register it */
-       rc = platform_device_add(pdev);
-       if (rc) {
-               pr_err("of_soc: platform_device_add() failed\n");
-               return;
-       }
-
-}
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-                             void *codec_data, struct snd_soc_dai *dai,
-                             struct device_node *node)
-{
-       struct of_snd_soc_device *of_soc;
-       int rc = 0;
-
-       pr_info("registering ASoC codec driver: %s\n", node->full_name);
-
-       mutex_lock(&of_snd_soc_mutex);
-       of_soc = of_snd_soc_get_device(node);
-       if (!of_soc) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       /* Store the codec data */
-       of_soc->device.codec_data = codec_data;
-       of_soc->device.codec_dev = codec_dev;
-       of_soc->dai_link.name = (char *)node->name;
-       of_soc->dai_link.stream_name = (char *)node->name;
-       of_soc->dai_link.codec_dai = dai;
-
-       /* Now try to register the SoC device */
-       of_snd_soc_register_device(of_soc);
-
- out:
-       mutex_unlock(&of_snd_soc_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-                                struct device_node *node,
-                                struct snd_soc_dai *cpu_dai)
-{
-       struct of_snd_soc_device *of_soc;
-       struct device_node *codec_node;
-       const phandle *handle;
-       int len, rc = 0;
-
-       pr_info("registering ASoC platform driver: %s\n", node->full_name);
-
-       handle = of_get_property(node, "codec-handle", &len);
-       if (!handle || len < sizeof(handle))
-               return -ENODEV;
-       codec_node = of_find_node_by_phandle(*handle);
-       if (!codec_node)
-               return -ENODEV;
-       pr_info("looking for codec: %s\n", codec_node->full_name);
-
-       mutex_lock(&of_snd_soc_mutex);
-       of_soc = of_snd_soc_get_device(codec_node);
-       if (!of_soc) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       of_soc->platform_node = node;
-       of_soc->dai_link.cpu_dai = cpu_dai;
-       of_soc->card.platform = platform;
-       of_soc->card.name = of_soc->dai_link.cpu_dai->name;
-
-       /* Now try to register the SoC device */
-       of_snd_soc_register_device(of_soc);
-
- out:
-       mutex_unlock(&of_snd_soc_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
index 687c76fc08397a39779bfe4eded6f4e67ea2abcb..642270a635ea544957c211cae3d0f69e030876ad 100644 (file)
@@ -8,12 +8,24 @@ menuconfig SND_IMX_SOC
          Say Y or M if you want to add support for codecs attached to
          the i.MX SSI interface.
 
+
 if SND_IMX_SOC
 
+config SND_MXC_SOC_SSI
+       tristate
+
+config SND_MXC_SOC_FIQ
+       tristate
+
+config SND_MXC_SOC_MX2
+       tristate
+
 config SND_MXC_SOC_WM1133_EV1
        tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
        depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
        select SND_SOC_WM8350
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Enable support for audio on the i.MX31ADS with the WM1133-EV1
          PMIC board with WM8835x fitted.
@@ -22,6 +34,8 @@ config SND_SOC_PHYCORE_AC97
        tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
        depends on MACH_PCM043 || MACH_PCA100
        select SND_SOC_WM9712
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Say Y if you want to add support for SoC audio on Phytec phyCORE
          and phyCARD boards in AC97 mode
@@ -32,6 +46,8 @@ config SND_SOC_EUKREA_TLV320
                || MACH_EUKREA_MBIMXSD25_BASEBOARD \
                || MACH_EUKREA_MBIMXSD35_BASEBOARD
        select SND_SOC_TLV320AIC23
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Enable I2S based access to the TLV320AIC23B codec attached
          to the SSI interface
index 7bc57baf2b0e9e68aaff7b27564fccc6dbd27113..b67fc02a4eccd781bda485a02e8de2eca26816b7 100644 (file)
@@ -1,11 +1,11 @@
 # i.MX Platform Support
-snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
-
-ifdef CONFIG_MACH_MX27
-snd-soc-imx-objs += imx-pcm-dma-mx2.o
-endif
+snd-soc-imx-objs := imx-ssi.o
+snd-soc-imx-fiq-objs := imx-pcm-fiq.o
+snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o
 
 obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o
+obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
index f15dfbdc47ee5cd838d873d0b8b1add1073eb6a4..b59675257ce55b61b6410f04008f12d6d705e37d 100644 (file)
@@ -79,22 +79,19 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = {
 static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .codec_dai      = &tlv320aic23_dai,
+       .codec_dai      = "tlv320aic23-hifi",
+       .platform_name  = "imx-pcm-audio.0",
+       .codec_name     = "tlv320aic23-codec.0-001a",
+       .cpu_dai = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
 };
 
 static struct snd_soc_card eukrea_tlv320 = {
        .name           = "cpuimx-audio",
-       .platform       = &imx_soc_platform,
        .dai_link       = &eukrea_tlv320_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device eukrea_tlv320_snd_devdata = {
-       .card           = &eukrea_tlv320,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *eukrea_tlv320_snd_device;
 
 static int __init eukrea_tlv320_init(void)
@@ -110,10 +107,7 @@ static int __init eukrea_tlv320_init(void)
        if (!eukrea_tlv320_snd_device)
                return -ENOMEM;
 
-       eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
-
-       platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
-       eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+       platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
        ret = platform_device_add(eukrea_tlv320_snd_device);
 
        if (ret) {
index 0a595da4811d343a389709e5656dceb550fbd2dd..fd493ee1428e2a977ac96ba7f7acc3a88d226025 100644 (file)
@@ -103,7 +103,7 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
        if (iprtd->dma < 0) {
@@ -213,7 +213,7 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int err;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        iprtd->substream = substream;
        iprtd->buf = (unsigned int *)substream->dma_buffer.area;
@@ -318,19 +318,42 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
-static struct snd_soc_platform imx_soc_platform_dma = {
-       .name           = "imx-audio",
-       .pcm_ops        = &imx_pcm_ops,
+static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
+       .ops            = &imx_pcm_ops,
        .pcm_new        = imx_pcm_new,
        .pcm_free       = imx_pcm_free,
 };
 
-struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
 {
-       ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
-       ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
+       return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
+}
+
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver imx_pcm_driver = {
+       .driver = {
+                       .name = "imx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
 
-       return &imx_soc_platform_dma;
+       .probe = imx_soc_platform_probe,
+       .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+       return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+       platform_driver_unregister(&imx_pcm_driver);
 }
+module_exit(snd_imx_pcm_exit);
 
index b2bf27282cd2d10189419236f5463c97c95354b7..413b78da248ff215db592d888e01f68fc40feffb 100644 (file)
@@ -236,6 +236,8 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
+static int ssi_irq = 0;
+
 static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
@@ -245,7 +247,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (ret)
                return ret;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                struct snd_pcm_substream *substream =
                        pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
                struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -253,7 +255,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
                imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                struct snd_pcm_substream *substream =
                        pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
                struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -267,24 +269,32 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        return 0;
 }
 
-static struct snd_soc_platform imx_soc_platform_fiq = {
-       .pcm_ops        = &imx_pcm_ops,
+static void imx_pcm_fiq_free(struct snd_pcm *pcm)
+{
+       mxc_set_irq_fiq(ssi_irq, 0);
+       release_fiq(&fh);
+       imx_pcm_free(pcm);
+}
+
+static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+       .ops            = &imx_pcm_ops,
        .pcm_new        = imx_pcm_fiq_new,
-       .pcm_free       = imx_pcm_free,
+       .pcm_free       = imx_pcm_fiq_free,
 };
 
-struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
 {
-       int ret = 0;
+       struct imx_ssi *ssi = platform_get_drvdata(pdev);
+       int ret;
 
        ret = claim_fiq(&fh);
        if (ret) {
                dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
-               return ERR_PTR(ret);
+               return ret;
        }
 
        mxc_set_irq_fiq(ssi->irq, 1);
+       ssi_irq = ssi->irq;
 
        imx_pcm_fiq = ssi->irq;
 
@@ -293,13 +303,43 @@ struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
        ssi->dma_params_tx.burstsize = 4;
        ssi->dma_params_rx.burstsize = 6;
 
-       return &imx_soc_platform_fiq;
+       ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
+       if (ret)
+               goto failed_register;
+
+       return 0;
+
+failed_register:
+       mxc_set_irq_fiq(ssi_irq, 0);
+       release_fiq(&fh);
+
+       return ret;
 }
 
-void imx_ssi_fiq_exit(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
 {
-       mxc_set_irq_fiq(ssi->irq, 0);
-       release_fiq(&fh);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
+static struct platform_driver imx_pcm_driver = {
+       .driver = {
+                       .name = "imx-fiq-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = imx_soc_platform_probe,
+       .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+       return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+       platform_driver_unregister(&imx_pcm_driver);
+}
+module_exit(snd_imx_pcm_exit);
index c81da05a4f11ee0ada1ad170dea17aea207eb969..d4bd345b0a8d4ba891222f5752fe6eca56aec7b4 100644 (file)
@@ -61,7 +61,7 @@
 static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 sccr;
 
        sccr = readl(ssi->base + SSI_STCCR);
@@ -86,7 +86,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
  */
 static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 strcr = 0, scr;
 
        scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
@@ -164,7 +164,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                  int clk_id, unsigned int freq, int dir)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 scr;
 
        scr = readl(ssi->base + SSI_SCR);
@@ -192,7 +192,7 @@ static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
                                  int div_id, int div)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 stccr, srccr;
 
        stccr = readl(ssi->base + SSI_STCCR);
@@ -241,7 +241,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params,
                             struct snd_soc_dai *cpu_dai)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        struct imx_pcm_dma_params *dma_data;
        u32 reg, sccr;
 
@@ -282,9 +282,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
        unsigned int sier_bits, sier;
        unsigned int scr;
 
@@ -353,22 +351,6 @@ static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
        .trigger        = imx_ssi_trigger,
 };
 
-static struct snd_soc_dai imx_ssi_dai = {
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &imx_ssi_pcm_dai_ops,
-};
-
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                struct vm_area_struct *vma)
 {
@@ -384,6 +366,7 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                        runtime->dma_bytes);
        return ret;
 }
+EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
 
 static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
@@ -415,14 +398,14 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                card->dev->dma_mask = &imx_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -432,6 +415,7 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(imx_pcm_new);
 
 void imx_pcm_free(struct snd_pcm *pcm)
 {
@@ -453,14 +437,40 @@ void imx_pcm_free(struct snd_pcm *pcm)
                buf->area = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(imx_pcm_free);
 
-struct snd_soc_platform imx_soc_platform = {
-       .name           = "imx-audio",
+static struct snd_soc_dai_driver imx_ssi_dai = {
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &imx_ssi_pcm_dai_ops,
 };
-EXPORT_SYMBOL_GPL(imx_soc_platform);
 
-static struct snd_soc_dai imx_ac97_dai = {
-       .name = "AC97",
+static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+       struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
+       uint32_t val;
+
+       snd_soc_dai_set_drvdata(dai, ssi);
+
+       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
+               SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+       writel(val, ssi->base + SSI_SFCSR);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver imx_ac97_dai = {
+       .probe = imx_ssi_dai_probe,
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
@@ -580,25 +590,18 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
 };
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
-struct snd_soc_dai imx_ssi_pcm_dai[2];
-EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
-
 static int imx_ssi_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct imx_ssi *ssi;
        struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
-       struct snd_soc_platform *platform;
        int ret = 0;
-       unsigned int val;
-       struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
-
-       if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
-               return -EINVAL;
+       struct snd_soc_dai_driver *dai;
 
        ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
        if (!ssi)
                return -ENOMEM;
+       dev_set_drvdata(&pdev->dev, ssi);
 
        if (pdata) {
                ssi->ac97_reset = pdata->ac97_reset;
@@ -643,9 +646,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
                }
                ac97_ssi = ssi;
                setup_channel_to_ac97(ssi);
-               memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
+               dai = &imx_ac97_dai;
        } else
-               memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
+               dai = &imx_ssi_dai;
 
        writel(0x0, ssi->base + SSI_SIER);
 
@@ -660,37 +663,36 @@ static int imx_ssi_probe(struct platform_device *pdev)
        if (res)
                ssi->dma_params_rx.dma = res->start;
 
-       dai->id = pdev->id;
-       dai->dev = &pdev->dev;
-       dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
-       dai->private_data = ssi;
-
        if ((cpu_is_mx27() || cpu_is_mx21()) &&
                        !(ssi->flags & IMX_SSI_USE_AC97) &&
                        (ssi->flags & IMX_SSI_DMA)) {
                ssi->flags |= IMX_SSI_DMA;
-               platform = imx_ssi_dma_mx2_init(pdev, ssi);
-       } else
-               platform = imx_ssi_fiq_init(pdev, ssi);
-
-       imx_soc_platform.pcm_ops = platform->pcm_ops;
-       imx_soc_platform.pcm_new = platform->pcm_new;
-       imx_soc_platform.pcm_free = platform->pcm_free;
+       }
 
-       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
-               SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
-       writel(val, ssi->base + SSI_SFCSR);
+       platform_set_drvdata(pdev, ssi);
 
-       ret = snd_soc_register_dai(dai);
+       ret = snd_soc_register_dai(&pdev->dev, dai);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                goto failed_register;
        }
 
-       platform_set_drvdata(pdev, ssi);
+       ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+       if (!ssi->soc_platform_pdev)
+               goto failed_pdev_alloc;
+       platform_set_drvdata(ssi->soc_platform_pdev, ssi);
+       ret = platform_device_add(ssi->soc_platform_pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add platform device\n");
+               goto failed_pdev_add;
+       }
 
        return 0;
 
+failed_pdev_add:
+       platform_device_put(ssi->soc_platform_pdev);
+failed_pdev_alloc:
+       snd_soc_unregister_dai(&pdev->dev);
 failed_register:
 failed_ac97:
        iounmap(ssi->base);
@@ -709,16 +711,15 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
-       struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
 
-       snd_soc_unregister_dai(dai);
+       platform_device_del(ssi->soc_platform_pdev);
+       platform_device_put(ssi->soc_platform_pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
 
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
 
-       if (!(ssi->flags & IMX_SSI_DMA))
-               imx_ssi_fiq_exit(pdev, ssi);
-
        iounmap(ssi->base);
        release_mem_region(res->start, resource_size(res));
        clk_disable(ssi->clk);
@@ -733,34 +734,19 @@ static struct platform_driver imx_ssi_driver = {
        .remove = __devexit_p(imx_ssi_remove),
 
        .driver = {
-               .name = DRV_NAME,
+               .name = "imx-ssi",
                .owner = THIS_MODULE,
        },
 };
 
 static int __init imx_ssi_init(void)
 {
-       int ret;
-
-       ret = snd_soc_register_platform(&imx_soc_platform);
-       if (ret) {
-               pr_err("failed to register soc platform: %d\n", ret);
-               return ret;
-       }
-
-       ret = platform_driver_register(&imx_ssi_driver);
-       if (ret) {
-               snd_soc_unregister_platform(&imx_soc_platform);
-               return ret;
-       }
-
-       return 0;
+       return platform_driver_register(&imx_ssi_driver);
 }
 
 static void __exit imx_ssi_exit(void)
 {
        platform_driver_unregister(&imx_ssi_driver);
-       snd_soc_unregister_platform(&imx_soc_platform);
 }
 
 module_init(imx_ssi_init);
index 55f26ebcd8c2531fc9267e12a6e590ac50199ad7..53b780d9b2b09375fdc7bf7f60a81af5045ab406 100644 (file)
 #define IMX_SSI_RX_DIV_PSR     4
 #define IMX_SSI_RX_DIV_PM      5
 
-extern struct snd_soc_dai imx_ssi_pcm_dai[2];
-extern struct snd_soc_platform imx_soc_platform;
-
 #define DRV_NAME "imx-ssi"
 
 struct imx_pcm_dma_params {
@@ -197,7 +194,7 @@ struct imx_pcm_dma_params {
 struct imx_ssi {
        struct platform_device *ac97_dev;
 
-       struct snd_soc_device imx_ac97;
+       struct snd_soc_dai *imx_ac97;
        struct clk *clk;
        void __iomem *base;
        int irq;
@@ -213,6 +210,8 @@ struct imx_ssi {
        struct imx_pcm_dma_params       dma_params_tx;
 
        int enabled;
+
+       struct platform_device *soc_platform_pdev;
 };
 
 struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
index a8307d55c70eaadc99e03aba65cef24d71668121..6a65dd7055199febc9a63393430461d086e2d4e8 100644 (file)
@@ -32,23 +32,20 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
        {
                .name           = "HiFi",
                .stream_name    = "HiFi",
-               .codec_dai      = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .codec_dai_name         = "wm9712-hifi",
+               .codec_name     = "wm9712-codec",
+               .cpu_dai_name   = "imx-ssi.0",
+               .platform_name  = "imx-fiq-pcm-audio.0",
                .ops            = &imx_phycore_hifi_ops,
        },
 };
 
 static struct snd_soc_card imx_phycore = {
        .name           = "PhyCORE-audio",
-       .platform       = &imx_soc_platform,
        .dai_link       = imx_phycore_dai_ac97,
        .num_links      = ARRAY_SIZE(imx_phycore_dai_ac97),
 };
 
-static struct snd_soc_device imx_phycore_snd_devdata = {
-       .card           = &imx_phycore,
-       .codec_dev      = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *imx_phycore_snd_device;
 
 static int __init imx_phycore_init(void)
@@ -63,10 +60,12 @@ static int __init imx_phycore_init(void)
        if (!imx_phycore_snd_device)
                return -ENOMEM;
 
-       imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0];
+       platform_set_drvdata(imx_phycore_snd_device, &imx_phycore);
+       ret = platform_device_add(imx_phycore_snd_device);
 
-       platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
-       imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
+       imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
+       if (!imx_phycore_snd_device)
+               return -ENOMEM;
        ret = platform_device_add(imx_phycore_snd_device);
 
        if (ret) {
index a6e7d94976399ee8c8f01fbd14268ef440e989c9..30fdb15065be314e6f0064b184605ff9f4ef8fb7 100644 (file)
@@ -82,8 +82,8 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int i, found = 0;
        snd_pcm_format_t format = params_format(params);
        unsigned int rate = params_rate(params);
@@ -210,9 +210,9 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
        { .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
 };
 
-static int wm1133_ev1_init(struct snd_soc_codec *codec)
+static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
                                  ARRAY_SIZE(wm1133_ev1_widgets));
@@ -221,13 +221,13 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
                                ARRAY_SIZE(wm1133_ev1_map));
 
        /* Headphone jack detection */
-       snd_soc_jack_new(card, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
+       snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
        snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
                              hp_jack_pins);
        wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
 
        /* Microphone jack detection */
-       snd_soc_jack_new(card, "Microphone",
+       snd_soc_jack_new(codec, "Microphone",
                         SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
        snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
                              mic_jack_pins);
@@ -243,8 +243,10 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link wm1133_ev1_dai = {
        .name = "WM1133-EV1",
        .stream_name = "Audio",
-       .cpu_dai = &imx_ssi_pcm_dai[0],
-       .codec_dai = &wm8350_dai,
+       .cpu_dai_name = "imx-ssi.0",
+       .codec_dai_name = "wm8350-hifi",
+       .platform_name = "imx-fiq-pcm-audio.0",
+       .codec_name = "wm8350-codec.0-0x1a",
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
        .symmetric_rates = 1,
@@ -252,16 +254,10 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
 
 static struct snd_soc_card wm1133_ev1 = {
        .name = "WM1133-EV1",
-       .platform = &imx_soc_platform,
        .dai_link = &wm1133_ev1_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device wm1133_ev1_snd_devdata = {
-       .card = &wm1133_ev1,
-       .codec_dev = &soc_codec_dev_wm8350,
-};
-
 static struct platform_device *wm1133_ev1_snd_device;
 
 static int __init wm1133_ev1_audio_init(void)
@@ -286,8 +282,7 @@ static int __init wm1133_ev1_audio_init(void)
        if (!wm1133_ev1_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1_snd_devdata);
-       wm1133_ev1_snd_devdata.dev = &wm1133_ev1_snd_device->dev;
+       platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
        ret = platform_device_add(wm1133_ev1_snd_device);
 
        if (ret)
index eb518f0c5e016274c0b00ab11a220e02b754641b..f3cffd18340192b3544e288480a22056b169f560 100644 (file)
@@ -106,15 +106,10 @@ static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
        writel(value, i2s->base + reg);
 }
 
-static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
-{
-       return dai->private_data;
-}
-
 static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf, ctrl;
 
        if (dai->active)
@@ -136,7 +131,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
 static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        if (!dai->active)
@@ -152,7 +147,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
        uint32_t ctrl;
        uint32_t mask;
@@ -186,7 +181,7 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
        uint32_t format = 0;
        uint32_t conf;
@@ -238,7 +233,7 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        enum jz4740_dma_width dma_width;
        struct jz4740_pcm_config *pcm_config;
        unsigned int sample_size;
@@ -288,7 +283,7 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
 static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        struct clk *parent;
        int ret = 0;
 
@@ -312,7 +307,7 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        if (dai->active) {
@@ -330,7 +325,7 @@ static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
 
 static int jz4740_i2s_resume(struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        clk_enable(i2s->clk_aic);
@@ -346,11 +341,38 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
        return 0;
 }
 
-static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_dma_config *dma_config;
+
+       /* Playback */
+       dma_config = &i2s->pcm_config_playback.dma_config;
+       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+       dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+       dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
+       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+       i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+
+       /* Capture */
+       dma_config = &i2s->pcm_config_capture.dma_config;
+       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+       dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
+       dma_config->flags = JZ4740_DMA_DST_AUTOINC;
+       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+       i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+}
+
+static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
+       clk_enable(i2s->clk_aic);
+
+       jz4740_i2c_init_pcm_config(i2s);
+
        conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
                (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
                JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
@@ -363,6 +385,14 @@ static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *da
        return 0;
 }
 
+static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable(i2s->clk_aic);
+       return 0;
+}
+
 static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
        .startup = jz4740_i2s_startup,
        .shutdown = jz4740_i2s_shutdown,
@@ -375,9 +405,9 @@ static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
                SNDRV_PCM_FMTBIT_S16_LE)
 
-struct snd_soc_dai jz4740_i2s_dai = {
-       .name = "jz4740-i2s",
-       .probe = jz4740_i2s_probe,
+static struct snd_soc_dai_driver jz4740_i2s_dai = {
+       .probe = jz4740_i2s_dai_probe,
+       .remove = jz4740_i2s_dai_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -395,30 +425,6 @@ struct snd_soc_dai jz4740_i2s_dai = {
        .suspend = jz4740_i2s_suspend,
        .resume = jz4740_i2s_resume,
 };
-EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
-
-static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
-{
-       struct jz4740_dma_config *dma_config;
-
-       /* Playback */
-       dma_config = &i2s->pcm_config_playback.dma_config;
-       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
-       dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-
-       /* Capture */
-       dma_config = &i2s->pcm_config_capture.dma_config;
-       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
-       dma_config->flags = JZ4740_DMA_DST_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-}
 
 static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
@@ -463,24 +469,17 @@ static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
                goto err_clk_put_aic;
        }
 
-       clk_enable(i2s->clk_aic);
-
-       jz4740_i2c_init_pcm_config(i2s);
-
-       jz4740_i2s_dai.private_data = i2s;
-       ret = snd_soc_register_dai(&jz4740_i2s_dai);
+       platform_set_drvdata(pdev, i2s);
+       ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to register DAI\n");
                goto err_clk_put_i2s;
        }
 
-       platform_set_drvdata(pdev, i2s);
-
        return 0;
 
 err_clk_put_i2s:
-       clk_disable(i2s->clk_aic);
        clk_put(i2s->clk_i2s);
 err_clk_put_aic:
        clk_put(i2s->clk_aic);
@@ -498,9 +497,8 @@ static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&jz4740_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
-       clk_disable(i2s->clk_aic);
        clk_put(i2s->clk_i2s);
        clk_put(i2s->clk_aic);
 
index da22ed88a5899ae334670e58ae88767f25287bda..5e49339d8b9340212e7e74f0defc3d2c5cc2ce76 100644 (file)
@@ -13,6 +13,4 @@
 
 #define JZ4740_I2S_BIT_CLK             0
 
-extern struct snd_soc_dai jz4740_i2s_dai;
-
 #endif
index ee68d850c8dd93715564679a8b766655952669c8..fb1483f7c9660b15daeddf0b978f7b969d2ee61a 100644 (file)
@@ -109,7 +109,7 @@ static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct jz4740_pcm_config *config;
 
-       config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        if (!config)
                return 0;
@@ -310,14 +310,14 @@ int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto err;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -328,22 +328,20 @@ err:
        return ret;
 }
 
-struct snd_soc_platform jz4740_soc_platform = {
-               .name           = "jz4740-pcm",
-               .pcm_ops        = &jz4740_pcm_ops,
+static struct snd_soc_platform_driver jz4740_soc_platform = {
+               .ops            = &jz4740_pcm_ops,
                .pcm_new        = jz4740_pcm_new,
                .pcm_free       = jz4740_pcm_free,
 };
-EXPORT_SYMBOL_GPL(jz4740_soc_platform);
 
 static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&jz4740_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
 }
 
 static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&jz4740_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
        return 0;
 }
 
@@ -351,7 +349,7 @@ static struct platform_driver jz4740_pcm_driver = {
        .probe = jz4740_pcm_probe,
        .remove = __devexit_p(jz4740_pcm_remove),
        .driver = {
-               .name = "jz4740-pcm",
+               .name = "jz4740-pcm-audio",
                .owner = THIS_MODULE,
        },
 };
index e3f221e2779c1c8164fc25e97abb17f2709e3e85..1220cbb4382c683966f868f918da55772d9a8288 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/dma-mapping.h>
 #include <asm/mach-jz4740/dma.h>
 
-/* platform data */
-extern struct snd_soc_platform jz4740_soc_platform;
 
 struct jz4740_pcm_config {
        struct jz4740_dma_config dma_config;
index f15f4918f15f4ef22904589cc3a5bb4992f19011..ef1a99e6a3bdf70994838f0f0d3a14a60680ab4e 100644 (file)
 #include <sound/soc-dapm.h>
 #include <linux/gpio.h>
 
-#include "../codecs/jz4740.h"
-#include "jz4740-pcm.h"
-#include "jz4740-i2s.h"
-
-
 #define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
 #define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
 
@@ -60,10 +55,11 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
                        SND_SOC_DAIFMT_NB_NF | \
                        SND_SOC_DAIFMT_CBM_CFM)
 
-static int qi_lb60_codec_init(struct snd_soc_codec *codec)
+static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
-       struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
 
        snd_soc_dapm_nc_pin(codec, "LIN");
        snd_soc_dapm_nc_pin(codec, "RIN");
@@ -84,8 +80,10 @@ static int qi_lb60_codec_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link qi_lb60_dai = {
        .name = "jz4740",
        .stream_name = "jz4740",
-       .cpu_dai = &jz4740_i2s_dai,
-       .codec_dai = &jz4740_codec_dai,
+       .cpu_dai_name = "jz4740-i2s",
+       .platform_name = "jz4740-pcm-audio",
+       .codec_dai_name = "jz4740-hifi",
+       .codec_name = "jz4740-codec",
        .init = qi_lb60_codec_init,
 };
 
@@ -93,12 +91,6 @@ static struct snd_soc_card qi_lb60 = {
        .name = "QI LB60",
        .dai_link = &qi_lb60_dai,
        .num_links = 1,
-       .platform = &jz4740_soc_platform,
-};
-
-static struct snd_soc_device qi_lb60_snd_devdata = {
-       .card = &qi_lb60,
-       .codec_dev = &soc_codec_dev_jz4740_codec,
 };
 
 static struct platform_device *qi_lb60_snd_device;
@@ -129,8 +121,7 @@ static int __init qi_lb60_init(void)
        gpio_direction_output(QI_LB60_SND_GPIO, 0);
        gpio_direction_output(QI_LB60_AMP_GPIO, 0);
 
-       platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
-       qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
+       platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 
        ret = platform_device_add(qi_lb60_snd_device);
        if (ret) {
index a30205be3e2b46b4ee5c315cbe7c227f9eacb8cc..0fd6a630db011eb961406aedb6352f2673fb0f1d 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-dma.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -18,7 +19,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/mbus.h>
 #include <sound/soc.h>
-#include "kirkwood-dma.h"
 #include "kirkwood.h"
 
 #define KIRKWOOD_RATES \
@@ -123,9 +123,10 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        int err;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_platform *platform = soc_runtime->platform;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
-       struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
        unsigned long addr;
 
        priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -151,7 +152,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        if (err < 0)
                return err;
 
-       if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+       if (prdata == NULL) {
                prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
                if (prdata == NULL)
                        return -ENOMEM;
@@ -165,7 +166,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
                        return -EBUSY;
                }
 
-               soc_runtime->dai->cpu_dai->private_data = prdata;
+               snd_soc_platform_set_drvdata(platform, prdata);
 
                /*
                 * Enable Error interrupts. We're only ack'ing them but
@@ -191,8 +192,9 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
 static int kirkwood_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
-       struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
+       struct snd_soc_platform *platform = soc_runtime->platform;
+       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
        struct kirkwood_dma_data *priv;
 
        priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -209,7 +211,7 @@ static int kirkwood_dma_close(struct snd_pcm_substream *substream)
                writel(0, priv->io + KIRKWOOD_ERR_MASK);
                free_irq(priv->irq, prdata);
                kfree(prdata);
-               soc_runtime->dai->cpu_dai->private_data = NULL;
+               snd_soc_platform_set_drvdata(platform, NULL);
        }
 
        return 0;
@@ -236,7 +238,7 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
        unsigned long size, count;
 
@@ -265,7 +267,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
                                                *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
        snd_pcm_uframes_t count;
 
@@ -320,14 +322,14 @@ static int kirkwood_dma_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -357,27 +359,46 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-struct snd_soc_platform kirkwood_soc_platform = {
-       .name           = "kirkwood-dma",
-       .pcm_ops        = &kirkwood_dma_ops,
+static struct snd_soc_platform_driver kirkwood_soc_platform = {
+       .ops            = &kirkwood_dma_ops,
        .pcm_new        = kirkwood_dma_new,
        .pcm_free       = kirkwood_dma_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
 
-static int __init kirkwood_soc_platform_init(void)
+static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&kirkwood_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
 }
-module_init(kirkwood_soc_platform_init);
 
-static void __exit kirkwood_soc_platform_exit(void)
+static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&kirkwood_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
-module_exit(kirkwood_soc_platform_exit);
 
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+static struct platform_driver kirkwood_pcm_driver = {
+       .driver = {
+                       .name = "kirkwood-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = kirkwood_soc_platform_probe,
+       .remove = __devexit_p(kirkwood_soc_platform_remove),
+};
+
+static int __init kirkwood_pcm_init(void)
+{
+       return platform_driver_register(&kirkwood_pcm_driver);
+}
+module_init(kirkwood_pcm_init);
+
+static void __exit kirkwood_pcm_exit(void)
+{
+       platform_driver_unregister(&kirkwood_pcm_driver);
+}
+module_exit(kirkwood_pcm_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
deleted file mode 100644 (file)
index ba4454c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-dma.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef _KIRKWOOD_DMA_H
-#define _KIRKWOOD_DMA_H
-
-extern struct snd_soc_platform kirkwood_soc_platform;
-
-#endif
index 981ffc2a13c8ad5adfdccdcd59cfc177bc1d9101..a33fc51f363be864ad2385e434dce97c409b5991 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-i2s.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -20,7 +21,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <plat/audio.h>
-#include "kirkwood-i2s.h"
 #include "kirkwood.h"
 
 #define DRV_NAME       "kirkwood-i2s"
         SNDRV_PCM_FMTBIT_S24_LE | \
         SNDRV_PCM_FMTBIT_S32_LE)
 
-
-struct snd_soc_dai kirkwood_i2s_dai;
-static struct kirkwood_dma_data *priv;
-
 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long mask;
        unsigned long value;
 
@@ -101,10 +98,20 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
        } while (value == 0);
 }
 
+static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_set_dma_data(dai, substream, priv);
+       return 0;
+}
+
 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned int i2s_reg, reg;
        unsigned long i2s_value, value;
 
@@ -171,6 +178,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
 
        /*
@@ -244,6 +252,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
 
        value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -323,9 +332,9 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int kirkwood_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
        unsigned int reg_data;
 
@@ -359,21 +368,20 @@ static int kirkwood_i2s_probe(struct platform_device *pdev,
 
 }
 
-static void kirkwood_i2s_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
+static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
 {
+       return 0;
 }
 
 static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+       .startup        = kirkwood_i2s_startup,
        .trigger        = kirkwood_i2s_trigger,
        .hw_params      = kirkwood_i2s_hw_params,
        .set_fmt        = kirkwood_i2s_set_fmt,
 };
 
 
-struct snd_soc_dai kirkwood_i2s_dai = {
-       .name = DRV_NAME,
-       .id = 0,
+static struct snd_soc_dai_driver kirkwood_i2s_dai = {
        .probe = kirkwood_i2s_probe,
        .remove = kirkwood_i2s_remove,
        .playback = {
@@ -388,13 +396,13 @@ struct snd_soc_dai kirkwood_i2s_dai = {
                .formats = KIRKWOOD_I2S_FORMATS,},
        .ops = &kirkwood_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
 
 static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        struct kirkwood_asoc_platform_data *data =
                pdev->dev.platform_data;
+       struct kirkwood_dma_data *priv;
        int err;
 
        priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
@@ -403,6 +411,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                err = -ENOMEM;
                goto error;
        }
+       dev_set_drvdata(&pdev->dev, priv);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -441,10 +450,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        priv->dram = data->dram;
        priv->burst = data->burst;
 
-       kirkwood_i2s_dai.capture.dma_data = priv;
-       kirkwood_i2s_dai.playback.dma_data = priv;
-
-       return snd_soc_register_dai(&kirkwood_i2s_dai);
+       return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
 
 err_ioremap:
        iounmap(priv->io);
@@ -458,12 +464,13 @@ error:
 
 static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
-       if (priv) {
-               iounmap(priv->io);
-               release_mem_region(priv->mem->start, SZ_16K);
-               kfree(priv);
-       }
-       snd_soc_unregister_dai(&kirkwood_i2s_dai);
+       struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+       iounmap(priv->io);
+       release_mem_region(priv->mem->start, SZ_16K);
+       kfree(priv);
+
        return 0;
 }
 
@@ -489,7 +496,7 @@ static void __exit kirkwood_i2s_exit(void)
 module_exit(kirkwood_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
deleted file mode 100644 (file)
index c5595c6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-i2s.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef _KIRKWOOD_I2S_H
-#define _KIRKWOOD_I2S_H
-
-extern struct snd_soc_dai kirkwood_i2s_dai;
-
-#endif
index 0353d06bc41ac38c94ea67ae10f6afe307485b4d..9d7c81e921f1150ddea58f3c045e7b41dbacb5aa 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-openrd.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
 #include <mach/kirkwood.h>
 #include <plat/audio.h>
 #include <asm/mach-types.h>
-#include "kirkwood-i2s.h"
-#include "kirkwood-dma.h"
 #include "../codecs/cs42l51.h"
 
 static int openrd_client_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
        unsigned int freq, fmt;
 
@@ -66,8 +65,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 {
        .name = "CS42L51",
        .stream_name = "CS42L51 HiFi",
-       .cpu_dai = &kirkwood_i2s_dai,
-       .codec_dai = &cs42l51_dai,
+       .cpu_dai_name = "kirkwood-i2s",
+       .platform_name = "kirkwood-pcm-audio",
+       .codec_dai_name = "cs42l51-hifi",
+       .codec_name = "cs42l51-codec.0-004a",
        .ops = &openrd_client_ops,
 },
 };
@@ -75,16 +76,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 
 static struct snd_soc_card openrd_client = {
        .name = "OpenRD Client",
-       .platform = &kirkwood_soc_platform,
        .dai_link = openrd_client_dai,
        .num_links = ARRAY_SIZE(openrd_client_dai),
 };
 
-static struct snd_soc_device openrd_client_snd_devdata = {
-       .card = &openrd_client,
-       .codec_dev = &soc_codec_device_cs42l51,
-};
-
 static struct platform_device *openrd_client_snd_device;
 
 static int __init openrd_client_init(void)
@@ -99,8 +94,7 @@ static int __init openrd_client_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(openrd_client_snd_device,
-                       &openrd_client_snd_devdata);
-       openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+                       &openrd_client);
 
        ret = platform_device_add(openrd_client_snd_device);
        if (ret) {
@@ -120,7 +114,7 @@ module_init(openrd_client_init);
 module_exit(openrd_client_exit);
 
 /* Module information */
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
index caa7c901bc2e131a24fbfe90e442242ab2e22185..293dc748797c51cf11a63b6b0afa548521ff2898 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <linux/device.h>
 #include <linux/clk.h>
 
 #include <mach/mfp.h>
@@ -297,8 +296,7 @@ static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
        .trigger        = nuc900_ac97_trigger,
 };
 
-struct snd_soc_dai nuc900_ac97_dai = {
-       .name                   = "nuc900-ac97",
+static struct snd_soc_dai_driver nuc900_ac97_dai = {
        .probe                  = nuc900_ac97_probe,
        .remove                 = nuc900_ac97_remove,
        .ac97_control           = 1,
@@ -316,7 +314,6 @@ struct snd_soc_dai nuc900_ac97_dai = {
        },
        .ops = &nuc900_ac97_dai_ops,
 }
-EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
 
 static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
 {
@@ -365,9 +362,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
 
        nuc900_ac97_data = nuc900_audio;
 
-       nuc900_audio->dev = nuc900_ac97_dai.dev =  &pdev->dev;
-
-       ret = snd_soc_register_dai(&nuc900_ac97_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
        if (ret)
                goto out3;
 
@@ -390,7 +385,7 @@ out0:
 static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dai(&nuc900_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        clk_put(nuc900_ac97_data->clk);
        iounmap(nuc900_ac97_data->mmio);
@@ -404,7 +399,7 @@ static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
 
 static struct platform_driver nuc900_ac97_driver = {
        .driver = {
-               .name   = "nuc900-audio",
+               .name   = "nuc900-ac97",
                .owner  = THIS_MODULE,
        },
        .probe          = nuc900_ac97_drvprobe,
index 72e6f518f7b21818a2177dd7739576cb04f2410b..161f5b667d7b5cf641896f462efe3740866f129a 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "nuc900-audio.h"
 
 static struct snd_soc_dai_link nuc900evb_ac97_dai = {
        .name           = "AC97",
        .stream_name    = "AC97 HiFi",
-       .cpu_dai        = &nuc900_ac97_dai,
-       .codec_dai      = &ac97_dai,
+       .cpu_dai_name   = "nuc900-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name     = "ac97-codec",
+       .platform_name  = "nuc900-pcm-audio",
 };
 
 static struct snd_soc_card nuc900evb_audio_machine = {
        .name           = "NUC900EVB_AC97",
        .dai_link       = &nuc900evb_ac97_dai,
        .num_links      = 1,
-       .platform       = &nuc900_soc_platform,
-};
-
-static struct snd_soc_device nuc900evb_ac97_devdata = {
-       .card           = &nuc900evb_audio_machine,
-       .codec_dev      = &soc_codec_dev_ac97,
 };
 
 static struct platform_device *nuc900evb_asoc_dev;
@@ -54,9 +49,8 @@ static int __init nuc900evb_audio_init(void)
                goto out;
 
        /* nuc900 board audio device */
-       platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+       platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine);
 
-       nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
        ret = platform_device_add(nuc900evb_asoc_dev);
 
        if (ret) {
index 3038f519729f5b9559cb47cceababfb919a93a56..aeed8ead2b2bcc42fcb5e06200a807f68cc6ce63 100644 (file)
@@ -110,8 +110,4 @@ struct nuc900_audio {
 
 };
 
-extern struct nuc900_audio *nuc900_ac97_data;
-extern struct snd_soc_dai nuc900_ac97_dai;
-extern struct snd_soc_platform nuc900_soc_platform;
-
 #endif /*end _NUC900_AUDIO_H */
index e81e803b3a63fd502e4dd857232f1ee9f34f6929..195d1ac94771808c0eda8075255efff787cdfd59 100644 (file)
@@ -328,26 +328,44 @@ static int nuc900_dma_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform nuc900_soc_platform = {
-       .name           = "nuc900-dma",
-       .pcm_ops        = &nuc900_dma_ops,
+static struct snd_soc_platform_driver nuc900_soc_platform = {
+       .ops            = &nuc900_dma_ops,
        .pcm_new        = nuc900_dma_new,
        .pcm_free       = nuc900_dma_free_dma_buffers,
 }
-EXPORT_SYMBOL_GPL(nuc900_soc_platform);
 
-static int __init nuc900_soc_platform_init(void)
+static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&nuc900_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
 }
 
-static void __exit nuc900_soc_platform_exit(void)
+static int __devexit nuc900_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&nuc900_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
-module_init(nuc900_soc_platform_init);
-module_exit(nuc900_soc_platform_exit);
+static struct platform_driver nuc900_pcm_driver = {
+       .driver = {
+                       .name = "nuc900-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = nuc900_soc_platform_probe,
+       .remove = __devexit_p(nuc900_soc_platform_remove),
+};
+
+static int __init nuc900_pcm_init(void)
+{
+       return platform_driver_register(&nuc900_pcm_driver);
+}
+module_init(nuc900_pcm_init);
+
+static void __exit nuc900_pcm_exit(void)
+{
+       platform_driver_unregister(&nuc900_pcm_driver);
+}
+module_exit(nuc900_pcm_exit);
 
 MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
 MODULE_DESCRIPTION("nuc900 Audio DMA module");
index 135901b2ea11b826c629ca93d572ea49ffccb7f8..979dd508305f812bc6ad893893ed6e811a8bdf3a 100644 (file)
@@ -40,8 +40,8 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -111,8 +111,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic In"},
 };
 
-static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add am3517-evm specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -134,8 +136,10 @@ static int am3517evm_aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link am3517evm_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name ="omap-mcbsp-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic23-codec",
        .init = am3517evm_aic23_init,
        .ops = &am3517evm_ops,
 };
@@ -143,27 +147,18 @@ static struct snd_soc_dai_link am3517evm_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_am3517evm = {
        .name = "am3517evm",
-       .platform = &omap_soc_platform,
        .dai_link = &am3517evm_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device am3517evm_snd_devdata = {
-       .card = &snd_soc_am3517evm,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *am3517evm_snd_device;
 
 static int __init am3517evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3517evm()) {
-               pr_err("Not OMAP3517 / AM3517 EVM!\n");
+       if (!machine_is_omap3517evm())
                return -ENODEV;
-       }
        pr_info("OMAP3517 / AM3517 EVM SoC init\n");
 
        am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -172,9 +167,7 @@ static int __init am3517evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
-       am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
-       *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+       platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
 
        ret = platform_device_add(am3517evm_snd_device);
        if (ret)
index b0f618e4484068e6c62e7b9515b6af5d6dfa021e..438146addbb88b0fdef55276d9513f772dc5b732 100644 (file)
@@ -99,7 +99,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
        int pin, changed = 0;
 
        /* Refuse any mode changes if we are not able to control the codec. */
-       if (!codec->control_data)
+       if (!codec->hw_write)
                return -EUNATCH;
 
        if (ucontrol->value.enumerated.item[0] >= control->max)
@@ -268,10 +268,32 @@ static void cx81801_timeout(unsigned long data)
                ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
 }
 
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
 /* Line discipline .open() */
 static int cx81801_open(struct tty_struct *tty)
 {
-       return v253_ops.open(tty);
+       int ret;
+
+       if (!cx20442_codec)
+               return -ENODEV;
+
+       /*
+        * Pass the codec structure pointer for use by other ldisc callbacks,
+        * both the card and the codec specific parts.
+        */
+       tty->disc_data = cx20442_codec;
+
+       ret = v253_ops.open(tty);
+
+       if (ret < 0)
+               tty->disc_data = NULL;
+
+       return ret;
 }
 
 /* Line discipline .close() */
@@ -281,11 +303,14 @@ static void cx81801_close(struct tty_struct *tty)
 
        del_timer_sync(&cx81801_timer);
 
-       v253_ops.close(tty);
-
        /* Prevent the hook switch from further changing the DAPM pins */
        INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
 
+       if (!codec)
+               return;
+
+       v253_ops.close(tty);
+
        /* Revert back to default audio input/output constellation */
        snd_soc_dapm_disable_pin(codec, "Mouthpiece");
        snd_soc_dapm_enable_pin(codec, "Earpiece");
@@ -310,7 +335,10 @@ static void cx81801_receive(struct tty_struct *tty,
        const unsigned char *c;
        int apply, ret;
 
-       if (!codec->control_data) {
+       if (!codec)
+               return;
+
+       if (!codec->hw_write) {
                /* First modem response, complete setup procedure */
 
                /* Initialize timer used for config pulse generation */
@@ -323,7 +351,7 @@ static void cx81801_receive(struct tty_struct *tty,
                                        ARRAY_SIZE(ams_delta_hook_switch_pins),
                                        ams_delta_hook_switch_pins);
                if (ret)
-                       dev_warn(codec->socdev->card->dev,
+                       dev_warn(codec->dev,
                                "Failed to link hook switch to DAPM pins, "
                                "will continue with hook switch unlinked.\n");
 
@@ -383,7 +411,7 @@ static int ams_delta_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
        /* Set cpu DAI configuration */
-       return snd_soc_dai_set_fmt(rtd->dai->cpu_dai,
+       return snd_soc_dai_set_fmt(rtd->cpu_dai,
                                   SND_SOC_DAIFMT_DSP_A |
                                   SND_SOC_DAIFMT_NB_NF |
                                   SND_SOC_DAIFMT_CBM_CFM);
@@ -398,7 +426,7 @@ static struct snd_soc_ops ams_delta_ops = {
 static int ams_delta_set_bias_level(struct snd_soc_card *card,
                                        enum snd_soc_bias_level level)
 {
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_codec *codec = card->rtd->codec;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -461,18 +489,22 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
  * Card initialization
  */
 
-static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
+static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = codec->dai;
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
        int ret;
        /* Codec is ready, now add/activate board specific controls */
 
+       /* Store a pointer to the codec structure for tty ldisc use */
+       cx20442_codec = codec;
+
        /* Set up digital mute if not provided by the codec */
-       if (!codec_dai->ops) {
-               codec_dai->ops = &ams_delta_dai_ops;
-       } else if (!codec_dai->ops->digital_mute) {
-               codec_dai->ops->digital_mute = ams_delta_digital_mute;
+       if (!codec_dai->driver->ops) {
+               codec_dai->driver->ops = &ams_delta_dai_ops;
+       } else if (!codec_dai->driver->ops->digital_mute) {
+               codec_dai->driver->ops->digital_mute = ams_delta_digital_mute;
        } else {
                ams_delta_ops.startup = ams_delta_startup;
                ams_delta_ops.shutdown = ams_delta_shutdown;
@@ -483,7 +515,7 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
 
        /* Add hook switch - can be used to control the codec from userspace
         * even if line discipline fails */
-       ret = snd_soc_jack_new(card, "hook_switch",
+       ret = snd_soc_jack_new(rtd->codec, "hook_switch",
                                SND_JACK_HEADSET, &ams_delta_hook_switch);
        if (ret)
                dev_warn(card->dev,
@@ -551,27 +583,22 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link ams_delta_dai_link = {
        .name = "CX20442",
        .stream_name = "CX20442",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &cx20442_dai,
+       .cpu_dai_name ="omap-mcbsp-dai.0",
+       .codec_dai_name = "cx20442-voice",
        .init = ams_delta_cx20442_init,
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "cx20442-codec",
        .ops = &ams_delta_ops,
 };
 
 /* Audio card driver */
 static struct snd_soc_card ams_delta_audio_card = {
        .name = "AMS_DELTA",
-       .platform = &omap_soc_platform,
        .dai_link = &ams_delta_dai_link,
        .num_links = 1,
        .set_bias_level = ams_delta_set_bias_level,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device ams_delta_snd_soc_device = {
-       .card = &ams_delta_audio_card,
-       .codec_dev = &cx20442_codec_dev,
-};
-
 /* Module init/exit */
 static struct platform_device *ams_delta_audio_platform_device;
 static struct platform_device *cx20442_platform_device;
@@ -589,9 +616,7 @@ static int __init ams_delta_module_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(ams_delta_audio_platform_device,
-                               &ams_delta_snd_soc_device);
-       ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev;
-       *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1;
+                               &ams_delta_audio_card);
 
        ret = platform_device_add(ams_delta_audio_platform_device);
        if (ret)
@@ -601,8 +626,8 @@ static int __init ams_delta_module_init(void)
         * Codec platform device could be registered from elsewhere (board?),
         * but I do it here as it makes sense only if used with the card.
         */
-       cx20442_platform_device = platform_device_register_simple("cx20442",
-                                                               -1, NULL, 0);
+       cx20442_platform_device =
+               platform_device_register_simple("cx20442-codec", -1, NULL, 0);
        return 0;
 err:
        platform_device_put(ams_delta_audio_platform_device);
@@ -612,19 +637,6 @@ module_init(ams_delta_module_init);
 
 static void __exit ams_delta_module_exit(void)
 {
-       struct snd_soc_codec *codec;
-       struct tty_struct *tty;
-
-       if (ams_delta_audio_card.codec) {
-               codec = ams_delta_audio_card.codec;
-
-               if (codec->control_data) {
-                       tty = codec->control_data;
-
-                       tty_hangup(tty);
-               }
-       }
-
        if (tty_unregister_ldisc(N_V253) != 0)
                dev_warn(&ams_delta_audio_platform_device->dev,
                        "failed to unregister V253 line discipline\n");
index 3583c429f9be38634e95f2c14af34f25cfba7643..fd3a40f309c8e4d3067ea93ecfebc6ad8f0f4a23 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int igep2_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -82,35 +81,28 @@ static struct snd_soc_ops igep2_ops = {
 static struct snd_soc_dai_link igep2_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &igep2_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_igep2 = {
        .name = "igep2",
-       .platform = &omap_soc_platform,
        .dai_link = &igep2_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device igep2_snd_devdata = {
-       .card = &snd_soc_card_igep2,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *igep2_snd_device;
 
 static int __init igep2_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_igep0020()) {
-               pr_debug("Not IGEP v2!\n");
+       if (!machine_is_igep0020())
                return -ENODEV;
-       }
        printk(KERN_INFO "IGEP v2 SoC init\n");
 
        igep2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -119,9 +111,7 @@ static int __init igep2_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
-       igep2_snd_devdata.dev = &igep2_snd_device->dev;
-       *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
 
        ret = platform_device_add(igep2_snd_device);
        if (ret)
index 90b8bf71c893be74903209f94b5f1aef17bc0171..928f03707451ecde15f046574ed8f1b4e841ee9a 100644 (file)
@@ -402,7 +402,7 @@ int omap_mcpdm_set_offset(int offset1, int offset2)
        return 0;
 }
 
-static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
+int __devinit omap_mcpdm_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int ret = 0;
@@ -449,7 +449,7 @@ exit:
        return ret;
 }
 
-static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+int __devexit omap_mcpdm_remove(struct platform_device *pdev)
 {
        struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
 
@@ -468,18 +468,3 @@ static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver omap_mcpdm_driver = {
-       .probe = omap_mcpdm_probe,
-       .remove = __devexit_p(omap_mcpdm_remove),
-       .driver = {
-               .name = "omap-mcpdm",
-       },
-};
-
-static struct platform_device *omap_mcpdm_device;
-
-static int __init omap_mcpdm_init(void)
-{
-       return platform_driver_register(&omap_mcpdm_driver);
-}
-arch_initcall(omap_mcpdm_init);
index 7bb326ef08866d7e032424c538d8069408d7d1a9..df3e16fb51f31ca2c6e1f25c9881ac272f7788c2 100644 (file)
@@ -149,3 +149,5 @@ extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
 extern int omap_mcpdm_request(void);
 extern void omap_mcpdm_free(void);
 extern int omap_mcpdm_set_offset(int offset1, int offset2);
+int __devinit omap_mcpdm_probe(struct platform_device *pdev);
+int __devexit omap_mcpdm_remove(struct platform_device *pdev);
index 08e09d72790f68beb75e40b1f55c1f3a4ff6d68f..a3b6d897ad84751b6ffced0757f27f51726d3385 100644 (file)
@@ -97,7 +97,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_pcm_hw_constraint_minmax(runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -115,8 +115,8 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -271,8 +271,9 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
                     n810_get_input, n810_set_input),
 };
 
-static int n810_aic33_init(struct snd_soc_codec *codec)
+static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Not connected */
@@ -307,8 +308,10 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link n810_dai = {
        .name = "TLV320AIC33",
        .stream_name = "AIC33",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic3x-codec.2-0018",
+       .codec_dai_name = "tlv320aic3x-hifi",
        .init = n810_aic33_init,
        .ops = &n810_ops,
 };
@@ -316,33 +319,12 @@ static struct snd_soc_dai_link n810_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_n810 = {
        .name = "N810",
-       .platform = &omap_soc_platform,
        .dai_link = &n810_dai,
        .num_links = 1,
 };
 
-/* Audio private data */
-static struct aic3x_setup_data n810_aic33_setup = {
-       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
-       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device n810_snd_devdata = {
-       .card = &snd_soc_n810,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &n810_aic33_setup,
-};
-
 static struct platform_device *n810_snd_device;
 
-/* temporary i2c device creation until this can be moved into the machine
- * support file.
-*/
-static struct i2c_board_info i2c_device[] = {
-       { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }
-};
-
 static int __init n810_soc_init(void)
 {
        int err;
@@ -351,15 +333,11 @@ static int __init n810_soc_init(void)
        if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
                return -ENODEV;
 
-       i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device));
-
        n810_snd_device = platform_device_alloc("soc-audio", -1);
        if (!n810_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
-       n810_snd_devdata.dev = &n810_snd_device->dev;
-       *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(n810_snd_device, &snd_soc_n810);
        err = platform_device_add(n810_snd_device);
        if (err)
                goto err1;
index 86f213905e2c0108e261de0f5d73b734cea27e57..d211c9fa5a914774534de29f51f40035320bfafb 100644 (file)
@@ -31,7 +31,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <plat/control.h>
 #include <plat/dma.h>
 #include <plat/mcbsp.h>
 #include "omap-mcbsp.h"
@@ -62,8 +61,6 @@ struct omap_mcbsp_data {
        int                             wlen;
 };
 
-#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
-
 static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
 
 /*
@@ -153,13 +150,13 @@ static const unsigned long omap34xx_mcbsp_port[][2] = {};
 static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_pcm_dma_data *dma_data;
        int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
        int words;
 
-       dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
        if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
@@ -203,11 +200,9 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
 }
 
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
+                                 struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        int bus_id = mcbsp_data->bus_id;
        int err = 0;
 
@@ -249,11 +244,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 }
 
 static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
-                                   struct snd_soc_dai *dai)
+                                   struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (!cpu_dai->active) {
                omap_mcbsp_free(mcbsp_data->bus_id);
@@ -262,11 +255,9 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
 }
 
 static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                                 struct snd_soc_dai *dai)
+                                 struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        switch (cmd) {
@@ -295,8 +286,8 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        u16 fifo_use;
        snd_pcm_sframes_t delay;
 
@@ -317,11 +308,9 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
 
 static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *dai)
+                                   struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        struct omap_pcm_dma_data *dma_data;
        int dma, bus_id = mcbsp_data->bus_id;
@@ -496,7 +485,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                      unsigned int fmt)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        unsigned int temp_fmt = fmt;
 
@@ -596,7 +585,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                     int div_id, int div)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
        if (div_id != OMAP_MCBSP_CLKGDV)
@@ -608,101 +597,22 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
-                                      int clk_id)
-{
-       int sel_bit;
-       u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
-
-       if (cpu_class_is_omap1()) {
-               /* OMAP1's can use only external source clock */
-               if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK))
-                       return -EINVAL;
-               else
-                       return 0;
-       }
-
-       if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
-               return -EINVAL;
-
-       if (cpu_is_omap343x())
-               reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
-
-       switch (mcbsp_data->bus_id) {
-       case 0:
-               reg = OMAP2_CONTROL_DEVCONF0;
-               sel_bit = 2;
-               break;
-       case 1:
-               reg = OMAP2_CONTROL_DEVCONF0;
-               sel_bit = 6;
-               break;
-       case 2:
-               reg = reg_devconf1;
-               sel_bit = 0;
-               break;
-       case 3:
-               reg = reg_devconf1;
-               sel_bit = 2;
-               break;
-       case 4:
-               reg = reg_devconf1;
-               sel_bit = 4;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
-               omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
-       else
-               omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
-
-       return 0;
-}
-
-static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data,
-                                      int clk_id)
-{
-       int sel_bit, set = 0;
-       u16 reg = OMAP2_CONTROL_DEVCONF0;
-
-       if (cpu_class_is_omap1())
-               return -EINVAL; /* TODO: Can this be implemented for OMAP1? */
-       if (mcbsp_data->bus_id != 0)
-               return -EINVAL;
-
-       switch (clk_id) {
-       case OMAP_MCBSP_CLKR_SRC_CLKX:
-               set = 1;
-       case OMAP_MCBSP_CLKR_SRC_CLKR:
-               sel_bit = 3;
-               break;
-       case OMAP_MCBSP_FSR_SRC_FSX:
-               set = 1;
-       case OMAP_MCBSP_FSR_SRC_FSR:
-               sel_bit = 4;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (set)
-               omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
-       else
-               omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
-
-       return 0;
-}
-
 static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                         int clk_id, unsigned int freq,
                                         int dir)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        int err = 0;
 
+       /* The McBSP signal muxing functions are only available on McBSP1 */
+       if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
+           clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
+           clk_id == OMAP_MCBSP_FSR_SRC_FSR ||
+           clk_id == OMAP_MCBSP_FSR_SRC_FSX)
+               if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0)
+                       return -EINVAL;
+
        mcbsp_data->in_freq = freq;
 
        switch (clk_id) {
@@ -710,8 +620,20 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                regs->srgr2     |= CLKSM;
                break;
        case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
+               if (cpu_class_is_omap1()) {
+                       err = -EINVAL;
+                       break;
+               }
+               err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+                                              MCBSP_CLKS_PRCM_SRC);
+               break;
        case OMAP_MCBSP_SYSCLK_CLKS_EXT:
-               err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
+               if (cpu_class_is_omap1()) {
+                       err = 0;
+                       break;
+               }
+               err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+                                              MCBSP_CLKS_PAD_SRC);
                break;
 
        case OMAP_MCBSP_SYSCLK_CLKX_EXT:
@@ -720,11 +642,18 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                regs->pcr0      |= SCLKME;
                break;
 
+
        case OMAP_MCBSP_CLKR_SRC_CLKR:
+               omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
+               break;
        case OMAP_MCBSP_CLKR_SRC_CLKX:
+               omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
+               break;
        case OMAP_MCBSP_FSR_SRC_FSR:
+               omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
+               break;
        case OMAP_MCBSP_FSR_SRC_FSX:
-               err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id);
+               omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
                break;
        default:
                err = -ENODEV;
@@ -733,7 +662,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+static struct snd_soc_dai_ops mcbsp_dai_ops = {
        .startup        = omap_mcbsp_dai_startup,
        .shutdown       = omap_mcbsp_dai_shutdown,
        .trigger        = omap_mcbsp_dai_trigger,
@@ -744,43 +673,32 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
        .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
 };
 
-#define OMAP_MCBSP_DAI_BUILDER(link_id)                                \
-{                                                              \
-       .name = "omap-mcbsp-dai-"#link_id,                      \
-       .id = (link_id),                                        \
-       .playback = {                                           \
-               .channels_min = 1,                              \
-               .channels_max = 16,                             \
-               .rates = OMAP_MCBSP_RATES,                      \
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |            \
-                          SNDRV_PCM_FMTBIT_S32_LE,             \
-       },                                                      \
-       .capture = {                                            \
-               .channels_min = 1,                              \
-               .channels_max = 16,                             \
-               .rates = OMAP_MCBSP_RATES,                      \
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |            \
-                          SNDRV_PCM_FMTBIT_S32_LE,             \
-       },                                                      \
-       .ops = &omap_mcbsp_dai_ops,                             \
-       .private_data = &mcbsp_data[(link_id)].bus_id,          \
+static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+{
+       mcbsp_data[dai->id].bus_id = dai->id;
+       snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+       return 0;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[] = {
-       OMAP_MCBSP_DAI_BUILDER(0),
-       OMAP_MCBSP_DAI_BUILDER(1),
-#if NUM_LINKS >= 3
-       OMAP_MCBSP_DAI_BUILDER(2),
-#endif
-#if NUM_LINKS == 5
-       OMAP_MCBSP_DAI_BUILDER(3),
-       OMAP_MCBSP_DAI_BUILDER(4),
-#endif
+static struct snd_soc_dai_driver omap_mcbsp_dai =
+{
+       .probe = mcbsp_dai_probe,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .ops = &mcbsp_dai_ops,
 };
 
-EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
-
-int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_info *uinfo)
 {
        struct soc_mixer_control *mc =
@@ -910,16 +828,36 @@ int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
 }
 EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
 
+static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+}
+
+static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_mcbsp_driver = {
+       .driver = {
+                       .name = "omap-mcbsp-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_mcbsp_probe,
+       .remove = __devexit_p(asoc_mcbsp_remove),
+};
+
 static int __init snd_omap_mcbsp_init(void)
 {
-       return snd_soc_register_dais(omap_mcbsp_dai,
-                                    ARRAY_SIZE(omap_mcbsp_dai));
+       return platform_driver_register(&asoc_mcbsp_driver);
 }
 module_init(snd_omap_mcbsp_init);
 
 static void __exit snd_omap_mcbsp_exit(void)
 {
-       snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
+       platform_driver_unregister(&asoc_mcbsp_driver);
 }
 module_exit(snd_omap_mcbsp_exit);
 
index 6c363e5f43876aa1f4d71906f7c09b2b40b8cd59..ffdcc5abb7b9619b99199ca4b7e079242ad16306 100644 (file)
@@ -55,8 +55,6 @@ enum omap_mcbsp_div {
 #define NUM_LINKS      5
 #endif
 
-extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
-
 int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
 
 #endif
index b7f4f7e015f3f4ef4c0dc91f46e1e4573ce39259..bed09c27e44cb9af6643f2e015d59405885b06bd 100644 (file)
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <plat/control.h>
 #include <plat/dma.h>
 #include <plat/mcbsp.h>
 #include "mcpdm.h"
-#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 
 struct omap_mcpdm_data {
@@ -89,11 +87,9 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
 static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int err = 0;
 
-       if (!cpu_dai->active)
+       if (!dai->active)
                err = omap_mcpdm_request();
 
        return err;
@@ -102,19 +98,14 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
 static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
-       if (!cpu_dai->active)
+       if (!dai->active)
                omap_mcpdm_free();
 }
 
 static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        int stream = substream->stream;
        int err = 0;
 
@@ -143,14 +134,12 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
        int stream = substream->stream;
        int channels, err, link_mask = 0;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream,
+       snd_soc_dai_set_dma_data(dai, substream,
                                 &omap_mcpdm_dai_dma_params[stream]);
 
        channels = params_channels(params);
@@ -189,9 +178,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
        int stream = substream->stream;
        int err;
@@ -215,9 +202,14 @@ static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
 #define OMAP_MCPDM_RATES       (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 #define OMAP_MCPDM_FORMATS     (SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai omap_mcpdm_dai = {
-       .name = "omap-mcpdm",
-       .id = -1,
+static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+{
+       snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+       return 0;
+}
+
+static struct snd_soc_dai_driver omap_mcpdm_dai = {
+       .probe = omap_mcpdm_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 4,
@@ -231,19 +223,47 @@ struct snd_soc_dai omap_mcpdm_dai = {
                .formats = OMAP_MCPDM_FORMATS,
        },
        .ops = &omap_mcpdm_dai_ops,
-       .private_data = &mcpdm_data,
 };
-EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
+
+static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = omap_mcpdm_probe(pdev);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+       if (ret < 0)
+               omap_mcpdm_remove(pdev);
+       return ret;
+}
+
+static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       omap_mcpdm_remove(pdev);
+       return 0;
+}
+
+static struct platform_driver asoc_mcpdm_driver = {
+       .driver = {
+                       .name = "omap-mcpdm-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_mcpdm_probe,
+       .remove = __devexit_p(asoc_mcpdm_remove),
+};
 
 static int __init snd_omap_mcpdm_init(void)
 {
-       return snd_soc_register_dai(&omap_mcpdm_dai);
+       return platform_driver_register(&asoc_mcpdm_driver);
 }
 module_init(snd_omap_mcpdm_init);
 
 static void __exit snd_omap_mcpdm_exit(void)
 {
-       snd_soc_unregister_dai(&omap_mcpdm_dai);
+       platform_driver_unregister(&asoc_mcpdm_driver);
 }
 module_exit(snd_omap_mcpdm_exit);
 
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
deleted file mode 100644 (file)
index 73b80d5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * omap-mcpdm.h
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Contact: Misael Lopez Cruz <x0052729@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_MCPDM_H__
-#define __OMAP_MCPDM_H__
-
-extern struct snd_soc_dai omap_mcpdm_dai;
-
-#endif /* End of __OMAP_MCPDM_H__ */
index 1e521904ea64efabd199c1d334adb2c5a247c799..8caeb8d305c3b0308f0592c7fa8d3461d6fce87f 100644 (file)
@@ -101,9 +101,10 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct omap_runtime_data *prtd = runtime->private_data;
        struct omap_pcm_dma_data *dma_data;
+
        int err = 0;
 
-       dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -374,14 +375,14 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -392,25 +393,45 @@ out:
        return ret;
 }
 
-struct snd_soc_platform omap_soc_platform = {
-       .name           = "omap-pcm-audio",
-       .pcm_ops        = &omap_pcm_ops,
+static struct snd_soc_platform_driver omap_soc_platform = {
+       .ops            = &omap_pcm_ops,
        .pcm_new        = omap_pcm_new,
        .pcm_free       = omap_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(omap_soc_platform);
 
-static int __init omap_soc_platform_init(void)
+static __devinit int omap_pcm_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev,
+                       &omap_soc_platform);
+}
+
+static int __devexit omap_pcm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver omap_pcm_driver = {
+       .driver = {
+                       .name = "omap-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = omap_pcm_probe,
+       .remove = __devexit_p(omap_pcm_remove),
+};
+
+static int __init snd_omap_pcm_init(void)
 {
-       return snd_soc_register_platform(&omap_soc_platform);
+       return platform_driver_register(&omap_pcm_driver);
 }
-module_init(omap_soc_platform_init);
+module_init(snd_omap_pcm_init);
 
-static void __exit omap_soc_platform_exit(void)
+static void __exit snd_omap_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&omap_soc_platform);
+       platform_driver_unregister(&omap_pcm_driver);
 }
-module_exit(omap_soc_platform_exit);
+module_exit(snd_omap_pcm_exit);
 
 MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
index b19975d269076bcf3b9bc46241846e29e5f26aae..fea0515331fb6721f1f91b95ee565f150d5f3e37 100644 (file)
@@ -35,6 +35,4 @@ struct omap_pcm_dma_data {
        int             packet_size;    /* packet size only in PACKET mode */
 };
 
-extern struct snd_soc_platform omap_soc_platform;
-
 #endif
index c7adea38274cb25f101d7dda9e6296eb4ff4e3f3..cf3fc8a675b5fc504169f35aaf418095d7da71d0 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap2evm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params,
-       struct snd_soc_dai *dai)
+       struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -85,35 +83,28 @@ static struct snd_soc_ops omap2evm_ops = {
 static struct snd_soc_dai_link omap2evm_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &omap2evm_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap2evm = {
        .name = "omap2evm",
-       .platform = &omap_soc_platform,
        .dai_link = &omap2evm_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap2evm_snd_devdata = {
-       .card = &snd_soc_omap2evm,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap2evm_snd_device;
 
 static int __init omap2evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap2evm()) {
-               pr_debug("Not omap2evm!\n");
+       if (!machine_is_omap2evm())
                return -ENODEV;
-       }
        printk(KERN_INFO "omap2evm SoC init\n");
 
        omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -122,9 +113,7 @@ static int __init omap2evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata);
-       omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev;
-       *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm);
 
        ret = platform_device_add(omap2evm_snd_device);
        if (ret)
index 240e0975dd6a716e47546a54deb83cecffb9b960..e56832b0c444083def074b75f3c788d9c89d07d3 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int fmt;
        int ret;
 
@@ -92,35 +91,29 @@ static struct snd_soc_ops omap3beagle_ops = {
 static struct snd_soc_dai_link omap3beagle_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .platform_name = "omap-pcm-audio",
+       .codec_dai_name = "twl4030-hifi",
+       .codec_name = "twl4030-codec",
        .ops = &omap3beagle_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap3beagle = {
        .name = "omap3beagle",
-       .platform = &omap_soc_platform,
+       .owner = THIS_MODULE,
        .dai_link = &omap3beagle_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap3beagle_snd_devdata = {
-       .card = &snd_soc_omap3beagle,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap3beagle_snd_device;
 
 static int __init omap3beagle_soc_init(void)
 {
        int ret;
 
-       if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
-               pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
+       if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
                return -ENODEV;
-       }
        pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
 
        omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
@@ -129,9 +122,7 @@ static int __init omap3beagle_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
-       omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
-       *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
 
        ret = platform_device_add(omap3beagle_snd_device);
        if (ret)
index dfcb344092e41c0506e4f243af3c70920a4cc5c0..810f1e36da2127e019570563d8d1d622939a3e48 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap3evm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -80,42 +79,28 @@ static struct snd_soc_ops omap3evm_ops = {
 static struct snd_soc_dai_link omap3evm_dai = {
        .name           = "TWL4030",
        .stream_name    = "TWL4030",
-       .cpu_dai        = &omap_mcbsp_dai[0],
-       .codec_dai      = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops            = &omap3evm_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap3evm = {
        .name = "omap3evm",
-       .platform = &omap_soc_platform,
        .dai_link = &omap3evm_dai,
        .num_links = 1,
 };
 
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 4,
-       .sysclk = 26000,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device omap3evm_snd_devdata = {
-       .card = &snd_soc_omap3evm,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *omap3evm_snd_device;
 
 static int __init omap3evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3evm()) {
-               pr_err("Not OMAP3 EVM!\n");
+       if (!machine_is_omap3evm())
                return -ENODEV;
-       }
        pr_info("OMAP3 EVM SoC init\n");
 
        omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -124,10 +109,7 @@ static int __init omap3evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
-       omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
-       *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
-
+       platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
        ret = platform_device_add(omap3evm_snd_device);
        if (ret)
                goto err1;
index 9eecac135bbbca973645d4391f8f3a6bcff36546..dbd9d96b5f9243c3e0cd0aafd3181e08cce84a3a 100644 (file)
 #include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 #define OMAP3_PANDORA_DAC_POWER_GPIO   118
 #define OMAP3_PANDORA_AMP_POWER_GPIO   14
@@ -47,8 +47,8 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                  SND_SOC_DAIFMT_CBS_CFS;
        int ret;
@@ -167,8 +167,9 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
        {"Mic Bias 2", NULL, "Mic (external)"},
 };
 
-static int omap3pandora_out_init(struct snd_soc_codec *codec)
+static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* All TWL4030 output pins are floating */
@@ -194,8 +195,9 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec)
        return snd_soc_dapm_sync(codec);
 }
 
-static int omap3pandora_in_init(struct snd_soc_codec *codec)
+static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Not comnnected */
@@ -224,15 +226,19 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
        {
                .name = "PCM1773",
                .stream_name = "HiFi Out",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .ops = &omap3pandora_ops,
                .init = omap3pandora_out_init,
        }, {
                .name = "TWL4030",
                .stream_name = "Line/Mic In",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.3",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .ops = &omap3pandora_ops,
                .init = omap3pandora_in_init,
        }
@@ -241,17 +247,10 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
 /* SoC card */
 static struct snd_soc_card snd_soc_card_omap3pandora = {
        .name = "omap3pandora",
-       .platform = &omap_soc_platform,
        .dai_link = omap3pandora_dai,
        .num_links = ARRAY_SIZE(omap3pandora_dai),
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap3pandora_snd_data = {
-       .card = &snd_soc_card_omap3pandora,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap3pandora_snd_device;
 
 static int __init omap3pandora_soc_init(void)
@@ -294,10 +293,7 @@ static int __init omap3pandora_soc_init(void)
                goto fail1;
        }
 
-       platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
-       omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
-       *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
-       *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
+       platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
 
        ret = platform_device_add(omap3pandora_snd_device);
        if (ret) {
index 498ca2e035197af484f0696bee925115fd959558..f0e6625564287df0b33643395af20c1849b8a596 100644 (file)
@@ -55,8 +55,8 @@ static int osk_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -113,8 +113,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Add osk5912 specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -136,8 +137,10 @@ static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link osk_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name = "omap-mcbsp-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic23-codec",
        .init = osk_tlv320aic23_init,
        .ops = &osk_ops,
 };
@@ -145,17 +148,10 @@ static struct snd_soc_dai_link osk_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_osk = {
        .name = "OSK5912",
-       .platform = &omap_soc_platform,
        .dai_link = &osk_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device osk_snd_devdata = {
-       .card = &snd_soc_card_osk,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *osk_snd_device;
 
 static int __init osk_soc_init(void)
@@ -171,9 +167,7 @@ static int __init osk_soc_init(void)
        if (!osk_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
-       osk_snd_devdata.dev = &osk_snd_device->dev;
-       *(unsigned int *)osk_dai.cpu_dai->private_data = 0;     /* McBSP1 */
+       platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
        err = platform_device_add(osk_snd_device);
        if (err)
                goto err1;
index c25f5276ad6f0135d1699548da4d3d6ad11b56f5..e95a607937de7a221998766dc0a2214e04b251f9 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int overo_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -82,25 +81,20 @@ static struct snd_soc_ops overo_ops = {
 static struct snd_soc_dai_link overo_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &overo_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_overo = {
        .name = "overo",
-       .platform = &omap_soc_platform,
        .dai_link = &overo_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device overo_snd_devdata = {
-       .card = &snd_soc_card_overo,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *overo_snd_device;
 
 static int __init overo_soc_init(void)
@@ -119,9 +113,7 @@ static int __init overo_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
-       overo_snd_devdata.dev = &overo_snd_device->dev;
-       *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
 
        ret = platform_device_add(overo_snd_device);
        if (ret)
index 88052d29617f9da25aac0eb687301d9e6cd207ce..04b5723bf89b5b4f289a6339e97f661fbd9dbccf 100644 (file)
@@ -31,6 +31,7 @@
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <plat/mcbsp.h>
 
 #include <asm/mach-types.h>
 
@@ -76,7 +77,7 @@ static int rx51_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_pcm_hw_constraint_minmax(runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -89,8 +90,8 @@ static int rx51_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -145,9 +146,9 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *k, int event)
 {
        if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
+               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
        else
-               gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
 
        return 0;
 }
@@ -240,9 +241,9 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
                     rx51_get_jack, rx51_set_jack),
 };
 
-static int rx51_aic34_init(struct snd_soc_codec *codec)
+static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Set up NC codec pins */
@@ -266,7 +267,7 @@ static int rx51_aic34_init(struct snd_soc_codec *codec)
        snd_soc_dapm_sync(codec);
 
        /* AV jack detection */
-       err = snd_soc_jack_new(card, "AV Jack",
+       err = snd_soc_jack_new(codec, "AV Jack",
                               SND_JACK_VIDEOOUT, &rx51_av_jack);
        if (err)
                return err;
@@ -282,32 +283,20 @@ static struct snd_soc_dai_link rx51_dai[] = {
        {
                .name = "TLV320AIC34",
                .stream_name = "AIC34",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &aic3x_dai,
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "tlv320aic3x-codec.2-0018",
                .init = rx51_aic34_init,
                .ops = &rx51_ops,
        },
 };
 
-/* Audio private data */
-static struct aic3x_setup_data rx51_aic34_setup = {
-       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
-       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
 /* Audio card */
 static struct snd_soc_card rx51_sound_card = {
        .name = "RX-51",
        .dai_link = rx51_dai,
        .num_links = ARRAY_SIZE(rx51_dai),
-       .platform = &omap_soc_platform,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device rx51_snd_devdata = {
-       .card = &rx51_sound_card,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &rx51_aic34_setup,
 };
 
 static struct platform_device *rx51_snd_device;
@@ -330,9 +319,7 @@ static int __init rx51_soc_init(void)
                goto err1;
        }
 
-       platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
-       rx51_snd_devdata.dev = &rx51_snd_device->dev;
-       *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
 
        err = platform_device_add(rx51_snd_device);
        if (err)
index 3c85c0f92823b82a87affec967b663966c279f4d..07fbcf7d2411ea6d0a80f5c390ba629f89a5e2ca 100644 (file)
 #include <mach/gpio.h>
 #include <plat/mcbsp.h>
 
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 /* TWL4030 PMBR1 Register */
 #define TWL4030_INTBR_PMBR1            0x0D
@@ -51,8 +53,8 @@ static int sdp3430_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -94,8 +96,8 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -186,8 +188,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Headset Stereophone", NULL, "HSOR"},
 };
 
-static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add SDP3430 specific widgets */
@@ -225,7 +228,7 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
                return ret;
 
        /* Headset jack detection */
-       ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+       ret = snd_soc_jack_new(codec, "Headset Jack",
                                SND_JACK_HEADSET, &hs_jack);
        if (ret)
                return ret;
@@ -241,14 +244,15 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
        return ret;
 }
 
-static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Enable voice interface */
-       reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+       reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
        reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
-       codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+       codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
 
        return 0;
 }
@@ -259,16 +263,20 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
        {
                .name = "TWL4030 I2S",
                .stream_name = "TWL4030 Audio",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = sdp3430_twl4030_init,
                .ops = &sdp3430_ops,
        },
        {
                .name = "TWL4030 PCM",
                .stream_name = "TWL4030 Voice",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+               .cpu_dai_name = "omap-mcbsp-dai.2",
+               .codec_dai_name = "twl4030-voice",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = sdp3430_twl4030_voice_init,
                .ops = &sdp3430_voice_ops,
        },
@@ -277,25 +285,10 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp3430 = {
        .name = "SDP3430",
-       .platform = &omap_soc_platform,
        .dai_link = sdp3430_dai,
        .num_links = ARRAY_SIZE(sdp3430_dai),
 };
 
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 3,
-       .sysclk = 26000,
-       .hs_extmute = 1,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device sdp3430_snd_devdata = {
-       .card = &snd_soc_sdp3430,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *sdp3430_snd_device;
 
 static int __init sdp3430_soc_init(void)
@@ -303,10 +296,8 @@ static int __init sdp3430_soc_init(void)
        int ret;
        u8 pin_mux;
 
-       if (!machine_is_omap_3430sdp()) {
-               pr_debug("Not SDP3430!\n");
+       if (!machine_is_omap_3430sdp())
                return -ENODEV;
-       }
        printk(KERN_INFO "SDP3430 SoC init\n");
 
        sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -315,10 +306,7 @@ static int __init sdp3430_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
-       sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
-       *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
-       *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+       platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
 
        /* Set TWL4030 GPIO6 as EXTMUTE signal */
        twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
index 4ebbde6b565f4fbfe6beafc0ab7fadf799171777..4b4463db6ba0330a0c29b401083e13cbc671bfd0 100644 (file)
@@ -31,7 +31,6 @@
 #include <plat/mux.h>
 
 #include "mcpdm.h"
-#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
@@ -41,7 +40,7 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int clk_id, freq;
        int ret;
 
@@ -60,6 +59,7 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
                printk(KERN_ERR "can't set codec system clock\n");
                return ret;
        }
+       return ret;
 }
 
 static struct snd_soc_ops sdp4430_ops = {
@@ -126,8 +126,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Earphone Spk", NULL, "EP"},
 };
 
-static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
+static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add SDP4430 specific controls */
@@ -164,8 +165,10 @@ static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link sdp4430_dai = {
        .name = "TWL6040",
        .stream_name = "TWL6040",
-       .cpu_dai = &omap_mcpdm_dai,
-       .codec_dai = &twl6040_dai,
+       .cpu_dai_name ="omap-mcpdm-dai",
+       .codec_dai_name = "twl6040-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl6040-codec",
        .init = sdp4430_twl6040_init,
        .ops = &sdp4430_ops,
 };
@@ -173,27 +176,18 @@ static struct snd_soc_dai_link sdp4430_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp4430 = {
        .name = "SDP4430",
-       .platform = &omap_soc_platform,
        .dai_link = &sdp4430_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device sdp4430_snd_devdata = {
-       .card = &snd_soc_sdp4430,
-       .codec_dev = &soc_codec_dev_twl6040,
-};
-
 static struct platform_device *sdp4430_snd_device;
 
 static int __init sdp4430_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap_4430sdp()) {
-               pr_debug("Not SDP4430!\n");
+       if (!machine_is_omap_4430sdp())
                return -ENODEV;
-       }
        printk(KERN_INFO "SDP4430 SoC init\n");
 
        sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -202,8 +196,7 @@ static int __init sdp4430_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sdp4430_snd_device, &sdp4430_snd_devdata);
-       sdp4430_snd_devdata.dev = &sdp4430_snd_device->dev;
+       platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
 
        ret = platform_device_add(sdp4430_snd_device);
        if (ret)
index 50a94ee76ecc2cf598e24068e7daa46e58e60d92..718031eeac34805bc16909fd29cb9a87da494a59 100644 (file)
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
+#include <mach/board-zoom.h>
 #include <plat/mcbsp.h>
 
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 #define ZOOM2_HEADSET_MUX_GPIO         (OMAP_MAX_GPIO_LINES + 15)
-#define ZOOM2_HEADSET_EXTMUTE_GPIO     153
 
 static int zoom2_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -85,8 +87,8 @@ static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -157,8 +159,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Aux In", NULL, "AUXR"},
 };
 
-static int zoom2_twl4030_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add Zoom2 specific widgets */
@@ -192,14 +195,15 @@ static int zoom2_twl4030_init(struct snd_soc_codec *codec)
        return ret;
 }
 
-static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Enable voice interface */
-       reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+       reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
        reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
-       codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+       codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
 
        return 0;
 }
@@ -209,16 +213,20 @@ static struct snd_soc_dai_link zoom2_dai[] = {
        {
                .name = "TWL4030 I2S",
                .stream_name = "TWL4030 Audio",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = zoom2_twl4030_init,
                .ops = &zoom2_ops,
        },
        {
                .name = "TWL4030 PCM",
                .stream_name = "TWL4030 Voice",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+               .cpu_dai_name = "omap-mcbsp-dai.2",
+               .codec_dai_name = "twl4030-voice",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = zoom2_twl4030_voice_init,
                .ops = &zoom2_voice_ops,
        },
@@ -227,42 +235,18 @@ static struct snd_soc_dai_link zoom2_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_zoom2 = {
        .name = "Zoom2",
-       .platform = &omap_soc_platform,
        .dai_link = zoom2_dai,
        .num_links = ARRAY_SIZE(zoom2_dai),
 };
 
-/* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
-{
-       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
-}
-
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 3,  /* 161 ms */
-       .sysclk = 26000,
-       .hs_extmute = 1,
-       .set_hs_extmute = zoom2_set_hs_extmute,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device zoom2_snd_devdata = {
-       .card = &snd_soc_zoom2,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *zoom2_snd_device;
 
 static int __init zoom2_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap_zoom2()) {
-               pr_debug("Not Zoom2!\n");
+       if (!machine_is_omap_zoom2())
                return -ENODEV;
-       }
        printk(KERN_INFO "Zoom2 SoC init\n");
 
        zoom2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -271,11 +255,7 @@ static int __init zoom2_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
-       zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
-       *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
-       *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
-
+       platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
        ret = platform_device_add(zoom2_snd_device);
        if (ret)
                goto err1;
index e30c8325f35e5fbccece8ff06f1fa8cc62951a3e..37f191bbfdd91edd64bb4abd7636600f4d694d0c 100644 (file)
@@ -117,6 +117,24 @@ config SND_PXA2XX_SOC_PALM27X
          Say Y if you want to add support for SoC audio on
          Palm T|X, T5, E2 or LifeDrive handheld computer.
 
+config SND_SOC_SAARB
+       tristate "SoC Audio support for Marvell Saarb"
+       depends on SND_PXA2XX_SOC && MACH_SAARB
+       select SND_PXA_SOC_SSP
+       select SND_SOC_88PM860X
+       help
+         Say Y if you want to add support for SoC audio on the
+         Marvell Saarb reference platform.
+
+config SND_SOC_TAVOREVB3
+       tristate "SoC Audio support for Marvell Tavor EVB3"
+       depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
+       select SND_PXA_SOC_SSP
+       select SND_SOC_88PM860X
+       help
+         Say Y if you want to add support for SoC audio on the
+         Marvell Saarb reference platform.
+
 config SND_SOC_ZYLONITE
        tristate "SoC Audio support for Marvell Zylonite"
        depends on SND_PXA2XX_SOC && MACH_ZYLONITE
index caa03d8f47896cf2aa1a8060812da54e79eac7c0..07660165ec8d70cff80726004f9cec56843b2e66 100644 (file)
@@ -19,6 +19,8 @@ snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
+snd-soc-saarb-objs := saarb.o
+snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
+obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
+obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
index fefe1a57f31adb329493bc482668a053afb65ea8..97e9423615c9c84d859a2b5b5b31695d73f4ab2f 100644 (file)
@@ -30,7 +30,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define CORGI_HP        0
@@ -99,7 +98,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec)
 static int corgi_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        corgi_ext_control(codec);
@@ -118,8 +117,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -150,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -272,8 +271,9 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
 /*
  * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
  */
-static int corgi_wm8731_init(struct snd_soc_codec *codec)
+static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -300,8 +300,10 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "pxa-is2-dai",
+       .codec_dai_name = "wm8731-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8731-codec-0.001a",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
@@ -309,17 +311,10 @@ static struct snd_soc_dai_link corgi_dai = {
 /* corgi audio machine driver */
 static struct snd_soc_card snd_soc_corgi = {
        .name = "Corgi",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &corgi_dai,
        .num_links = 1,
 };
 
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
-       .card = &snd_soc_corgi,
-       .codec_dev = &soc_codec_dev_wm8731,
-};
-
 static struct platform_device *corgi_snd_device;
 
 static int __init corgi_init(void)
@@ -334,8 +329,7 @@ static int __init corgi_init(void)
        if (!corgi_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
-       corgi_snd_devdata.dev = &corgi_snd_device->dev;
+       platform_set_drvdata(corgi_snd_device, &snd_soc_corgi);
        ret = platform_device_add(corgi_snd_device);
 
        if (ret)
index 7cd2f89d7b1021d9641a010a80901882b26ef495..c82cedb602fdaba519482639ea86dd670ccd9f12 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/mach-types.h>
 
 #include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 
@@ -90,8 +89,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Mic Amp", NULL, "Mic (Internal)"},
 };
 
-static int e740_ac97_init(struct snd_soc_codec *codec)
+static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_nc_pin(codec, "HPOUTL");
        snd_soc_dapm_nc_pin(codec, "HPOUTR");
        snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -116,30 +117,28 @@ static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9705-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
                .init = e740_ac97_init,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name = "wm9705-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
        },
 };
 
 static struct snd_soc_card e740 = {
        .name = "Toshiba e740",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e740_dai,
        .num_links = ARRAY_SIZE(e740_dai),
 };
 
-static struct snd_soc_device e740_snd_devdata = {
-       .card = &e740,
-       .codec_dev = &soc_codec_dev_wm9705,
-};
-
 static struct platform_device *e740_snd_device;
 
 static int __init e740_init(void)
@@ -178,8 +177,7 @@ static int __init e740_init(void)
                goto free_apwr_gpio;
        }
 
-       platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
-       e740_snd_devdata.dev = &e740_snd_device->dev;
+       platform_set_drvdata(e740_snd_device, &e740);
        ret = platform_device_add(e740_snd_device);
 
        if (!ret)
@@ -200,6 +198,9 @@ free_mic_amp_gpio:
 static void __exit e740_exit(void)
 {
        platform_device_unregister(e740_snd_device);
+       gpio_free(GPIO_E740_WM9705_nAVDD2);
+       gpio_free(GPIO_E740_AMP_ON);
+       gpio_free(GPIO_E740_MIC_ON);
 }
 
 module_init(e740_init);
index 8dceccc5e059fbb31a818f7fc76c892d4b3ba32e..4c143803a75e971de78e68d01d74f87df551b867 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/mach-types.h>
 
 #include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -72,8 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC1", NULL, "Mic (Internal)"},
 };
 
-static int e750_ac97_init(struct snd_soc_codec *codec)
+static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_nc_pin(codec, "LOUT");
        snd_soc_dapm_nc_pin(codec, "ROUT");
        snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -98,31 +99,29 @@ static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9705-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
                .init = e750_ac97_init,
                /* use ops to check startup state */
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9705-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
        },
 };
 
 static struct snd_soc_card e750 = {
        .name = "Toshiba e750",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e750_dai,
        .num_links = ARRAY_SIZE(e750_dai),
 };
 
-static struct snd_soc_device e750_snd_devdata = {
-       .card = &e750,
-       .codec_dev = &soc_codec_dev_wm9705,
-};
-
 static struct platform_device *e750_snd_device;
 
 static int __init e750_init(void)
@@ -154,8 +153,7 @@ static int __init e750_init(void)
                goto free_spk_amp_gpio;
        }
 
-       platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
-       e750_snd_devdata.dev = &e750_snd_device->dev;
+       platform_set_drvdata(e750_snd_device, &e750);
        ret = platform_device_add(e750_snd_device);
 
        if (!ret)
index bc019cdce42922c787f62dfd8bc30cd7a0582d25..d42e5fe832c5d5909176feaa5b3513e95e4b6f85 100644 (file)
@@ -23,7 +23,6 @@
 #include <mach/eseries-gpio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -73,8 +72,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2", NULL, "Mic (Internal2)"},
 };
 
-static int e800_ac97_init(struct snd_soc_codec *codec)
+static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
                                        ARRAY_SIZE(e800_dapm_widgets));
 
@@ -88,30 +89,28 @@ static struct snd_soc_dai_link e800_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9712-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
                .init = e800_ac97_init,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9712-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
 };
 
 static struct snd_soc_card e800 = {
        .name = "Toshiba e800",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e800_dai,
        .num_links = ARRAY_SIZE(e800_dai),
 };
 
-static struct snd_soc_device e800_snd_devdata = {
-       .card = &e800,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *e800_snd_device;
 
 static int __init e800_init(void)
@@ -141,8 +140,7 @@ static int __init e800_init(void)
        if (!e800_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
-       e800_snd_devdata.dev = &e800_snd_device->dev;
+       platform_set_drvdata(e800_snd_device, &e800);
        ret = platform_device_add(e800_snd_device);
 
        if (!ret)
index f4756e4025fd1dd0c06080d0e26a8c121dc52c2e..eadf9d351a04d996978881b46a9503b8723f03c7 100644 (file)
 #include <mach/audio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_dai_link em_x270_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9712-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9712-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
 };
 
 static struct snd_soc_card em_x270 = {
        .name = "EM-X270",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = em_x270_dai,
        .num_links = ARRAY_SIZE(em_x270_dai),
 };
 
-static struct snd_soc_device em_x270_snd_devdata = {
-       .card = &em_x270,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *em_x270_snd_device;
 
 static int __init em_x270_init(void)
@@ -76,8 +73,7 @@ static int __init em_x270_init(void)
        if (!em_x270_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata);
-       em_x270_snd_devdata.dev = &em_x270_snd_device->dev;
+       platform_set_drvdata(em_x270_snd_device, &em_x270);
        ret = platform_device_add(em_x270_snd_device);
 
        if (ret)
index 405587a011600ab2c1f81400240529201bdbc5c4..154fc6f234389e74d4354770b6057074377f6be2 100644 (file)
@@ -6,14 +6,13 @@
 
 #include "../codecs/wm8940.h"
 #include "pxa2xx-i2s.h"
-#include "pxa2xx-pcm.h"
 
 static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret;
 
@@ -64,23 +63,19 @@ static struct snd_soc_ops imote2_asoc_ops = {
 static struct snd_soc_dai_link imote2_dai = {
        .name = "WM8940",
        .stream_name = "WM8940",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8940_dai,
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "wm8940-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8940-codec.0-0034",
        .ops = &imote2_asoc_ops,
 };
 
 static struct snd_soc_card snd_soc_imote2 = {
        .name = "Imote2",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &imote2_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device imote2_snd_devdata = {
-       .card = &snd_soc_imote2,
-       .codec_dev = &soc_codec_dev_wm8940,
-};
-
 static struct platform_device *imote2_snd_device;
 
 static int __init imote2_asoc_init(void)
@@ -93,8 +88,7 @@ static int __init imote2_asoc_init(void)
        if (!imote2_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
-       imote2_snd_devdata.dev = &imote2_snd_device->dev;
+       platform_set_drvdata(imote2_snd_device, &snd_soc_imote2);
        ret = platform_device_add(imote2_snd_device);
        if (ret)
                platform_device_put(imote2_snd_device);
index 4c8d99a8d38667804ccb80b62a78268f8f55f439..b8207ced40729b0b375f28566b09de404313f28a 100644 (file)
@@ -32,7 +32,6 @@
 #include <mach/magician.h>
 #include <asm/mach-types.h>
 #include "../codecs/uda1380.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 #include "pxa-ssp.h"
 
@@ -71,7 +70,7 @@ static void magician_ext_control(struct snd_soc_codec *codec)
 static int magician_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        magician_ext_control(codec);
@@ -86,8 +85,8 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                                       struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int acps, acds, width, rate;
        unsigned int div4 = PXA_SSP_CLK_SCDB_4;
        int ret = 0;
@@ -227,8 +226,8 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        /* set codec DAI configuration */
@@ -393,8 +392,9 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
 /*
  * Logic for a uda1380 as connected on a HTC Magician
  */
-static int magician_uda1380_init(struct snd_soc_codec *codec)
+static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* NC codec pins */
@@ -427,16 +427,20 @@ static struct snd_soc_dai_link magician_dai[] = {
 {
        .name = "uda1380",
        .stream_name = "UDA1380 Playback",
-       .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
-       .codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
+       .cpu_dai_name = "pxa-ssp-dai.0",
+       .codec_dai_name = "uda1380-hifi-playback",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "uda1380-codec.0-0018",
        .init = magician_uda1380_init,
        .ops = &magician_playback_ops,
 },
 {
        .name = "uda1380",
        .stream_name = "UDA1380 Capture",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "uda1380-hifi-capture",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "uda1380-codec.0-0018",
        .ops = &magician_capture_ops,
 }
 };
@@ -446,13 +450,7 @@ static struct snd_soc_card snd_soc_card_magician = {
        .name = "Magician",
        .dai_link = magician_dai,
        .num_links = ARRAY_SIZE(magician_dai),
-       .platform = &pxa2xx_soc_platform,
-};
 
-/* magician audio subsystem */
-static struct snd_soc_device magician_snd_devdata = {
-       .card = &snd_soc_card_magician,
-       .codec_dev = &soc_codec_dev_uda1380,
 };
 
 static struct platform_device *magician_snd_device;
@@ -514,8 +512,7 @@ static int __init magician_init(void)
                goto err_pdev;
        }
 
-       platform_set_drvdata(magician_snd_device, &magician_snd_devdata);
-       magician_snd_devdata.dev = &magician_snd_device->dev;
+       platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
        ret = platform_device_add(magician_snd_device);
        if (ret) {
                platform_device_put(magician_snd_device);
index 19eda8bbfdafc8264de13284639ad610bcaf60cd..f284cc54bc80e8fcfe100c56ccfd009dcb03168c 100644 (file)
@@ -54,7 +54,6 @@
 #include <sound/initval.h>
 #include <sound/ac97_codec.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 #include "../codecs/wm9713.h"
 
@@ -128,8 +127,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Rear Speaker", NULL, "SPKR"},
 };
 
-static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Add mioa701 specific widgets */
@@ -139,12 +139,12 @@ static int mioa701_wm9713_init(struct snd_soc_codec *codec)
        snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
 
        /* Prepare GPIO8 for rear speaker amplifier */
-       reg = codec->read(codec, AC97_GPIO_CFG);
-       codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+       reg = codec->driver->read(codec, AC97_GPIO_CFG);
+       codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
 
        /* Prepare MIC input */
-       reg = codec->read(codec, AC97_3D_CONTROL);
-       codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+       reg = codec->driver->read(codec, AC97_3D_CONTROL);
+       codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
 
        snd_soc_dapm_enable_pin(codec, "Front Speaker");
        snd_soc_dapm_enable_pin(codec, "Rear Speaker");
@@ -162,32 +162,30 @@ static struct snd_soc_dai_link mioa701_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9713-hifi",
+               .codec_name = "wm9713-codec",
                .init = mioa701_wm9713_init,
+               .platform_name = "pxa-pcm-audio",
                .ops = &mioa701_ops,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9713-aux",
+               .codec_name = "wm9713-codec",
+               .platform_name = "pxa-pcm-audio",
                .ops = &mioa701_ops,
        },
 };
 
 static struct snd_soc_card mioa701 = {
        .name = "MioA701",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = mioa701_dai,
        .num_links = ARRAY_SIZE(mioa701_dai),
 };
 
-static struct snd_soc_device mioa701_snd_devdata = {
-       .card = &mioa701,
-       .codec_dev = &soc_codec_dev_wm9713,
-};
-
 static struct platform_device *mioa701_snd_device;
 
 static int mioa701_wm9713_probe(struct platform_device *pdev)
@@ -205,8 +203,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
        if (!mioa701_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
-       mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+       platform_set_drvdata(mioa701_snd_device, &mioa701);
 
        ret = platform_device_add(mioa701_snd_device);
        if (!ret)
index 1f96e3227be51920fbc011e2f9adaeba3e0fad31..13f6d485d57168affb88010669513af04c1881cb 100644 (file)
@@ -29,7 +29,6 @@
 #include <mach/palmasoc.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_jack hs_jack;
@@ -75,8 +74,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static struct snd_soc_card palm27x_asoc;
 
-static int palm27x_ac97_init(struct snd_soc_codec *codec)
+static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* add palm27x specific widgets */
@@ -112,7 +112,7 @@ static int palm27x_ac97_init(struct snd_soc_codec *codec)
                return err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+       err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
        if (err)
                return err;
@@ -132,30 +132,28 @@ static struct snd_soc_dai_link palm27x_dai[] = {
 {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_dai_name =  "wm9712-hifi",
+       .codec_name = "wm9712-codec",
+       .platform_name = "pxa-pcm-audio",
        .init = palm27x_ac97_init,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_dai_name = "wm9712-aux",
+       .codec_name = "wm9712-codec",
+       .platform_name = "pxa-pcm-audio",
 },
 };
 
 static struct snd_soc_card palm27x_asoc = {
        .name = "Palm/PXA27x",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = palm27x_dai,
        .num_links = ARRAY_SIZE(palm27x_dai),
 };
 
-static struct snd_soc_device palm27x_snd_devdata = {
-       .card = &palm27x_asoc,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *palm27x_snd_device;
 
 static int palm27x_asoc_probe(struct platform_device *pdev)
@@ -178,8 +176,7 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
        if (!palm27x_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
-       palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
+       platform_set_drvdata(palm27x_snd_device, &palm27x_asoc);
        ret = platform_device_add(palm27x_snd_device);
 
        if (ret != 0)
index c5f36e0eab58db4a188e36316f7239fab3272599..af84ee9c5e11edde0c8a253e3a5072e5f3ac0e36 100644 (file)
@@ -31,7 +31,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define POODLE_HP        1
@@ -76,7 +75,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
 static int poodle_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        poodle_ext_control(codec);
@@ -97,8 +96,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -129,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -237,8 +236,9 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
 /*
  * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
  */
-static int poodle_wm8731_init(struct snd_soc_codec *codec)
+static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -266,8 +266,10 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link poodle_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "wm8731-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8731-codec.0-001a",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
@@ -275,15 +277,9 @@ static struct snd_soc_dai_link poodle_dai = {
 /* poodle audio machine driver */
 static struct snd_soc_card snd_soc_poodle = {
        .name = "Poodle",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &poodle_dai,
        .num_links = 1,
-};
-
-/* poodle audio subsystem */
-static struct snd_soc_device poodle_snd_devdata = {
-       .card = &snd_soc_poodle,
-       .codec_dev = &soc_codec_dev_wm8731,
+       .owner = THIS_MODULE,
 };
 
 static struct platform_device *poodle_snd_device;
@@ -307,8 +303,7 @@ static int __init poodle_init(void)
        if (!poodle_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
-       poodle_snd_devdata.dev = &poodle_snd_device->dev;
+       platform_set_drvdata(poodle_snd_device, &snd_soc_poodle);
        ret = platform_device_add(poodle_snd_device);
 
        if (ret)
index a1fd23e0e3d00d5aa5fb93a53c2c106a74731cb0..b439eee462cb720ec622628fa78b955e846980ae 100644 (file)
@@ -35,7 +35,7 @@
 #include <mach/audio.h>
 #include <plat/ssp.h>
 
-#include "pxa2xx-pcm.h"
+#include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 
 /*
@@ -108,11 +108,9 @@ pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+                          struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int ret = 0;
 
@@ -128,11 +126,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 }
 
 static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
+                            struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
 
        if (!cpu_dai->active) {
@@ -148,7 +144,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
 
 static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
 
        if (!cpu_dai->active)
@@ -166,7 +162,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
 
 static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
 
@@ -230,7 +226,7 @@ static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
 static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        int clk_id, unsigned int freq, int dir)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -287,7 +283,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
        int div_id, int div)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -338,7 +334,7 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
        int source, unsigned int freq_in, unsigned int freq_out)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
 
@@ -407,7 +403,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 sscr0;
 
@@ -442,7 +438,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
        int tristate)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 sscr1;
 
@@ -464,11 +460,9 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
-       u32 sscr0;
-       u32 sscr1;
-       u32 sspsp;
+       u32 sscr0, sscr1, sspsp, scfr;
 
        /* check if we need to change anything at all */
        if (priv->dai_fmt == fmt)
@@ -483,16 +477,16 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
        /* reset port settings */
        sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
-               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+               ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
        sspsp = 0;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+               sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
-               sscr1 |= SSCR1_SCLKDIR;
+               sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
@@ -538,6 +532,17 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        pxa_ssp_write_reg(ssp, SSCR1, sscr1);
        pxa_ssp_write_reg(ssp, SSPSP, sspsp);
 
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
+               pxa_ssp_write_reg(ssp, SSCR1, scfr);
+
+               while (pxa_ssp_read_reg(ssp, SSSR) & SSSR_BSY)
+                       cpu_relax();
+               break;
+       }
+
        dump_registers(ssp);
 
        /* Since we are configuring the timings for the format by hand
@@ -555,11 +560,9 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
  */
 static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
+                               struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int chn = params_channels(params);
        u32 sscr0;
@@ -568,7 +571,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
        struct pxa2xx_pcm_dma_params *dma_data;
 
-       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
        /* generate correct DMA params */
        kfree(dma_data);
@@ -581,7 +584,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                        ((chn == 2) && (ttsa != 1)) || (width == 32),
                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
 
        /* we can only change the settings if the port is not in use */
        if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
@@ -589,10 +592,8 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 
        /* clear selected SSP bits */
        sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
-       pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 
        /* bit size */
-       sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
 #ifdef CONFIG_PXA3xx
@@ -668,12 +669,10 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 }
 
 static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
-                          struct snd_soc_dai *dai)
+                          struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret = 0;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -729,8 +728,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int pxa_ssp_probe(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
 {
        struct ssp_priv *priv;
        int ret;
@@ -746,7 +744,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
        }
 
        priv->dai_fmt = (unsigned int) -1;
-       dai->private_data = priv;
+       snd_soc_dai_set_drvdata(dai, priv);
 
        return 0;
 
@@ -755,11 +753,13 @@ err_priv:
        return ret;
 }
 
-static void pxa_ssp_remove(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
 {
-       struct ssp_priv *priv = dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(dai);
+
        pxa_ssp_free(priv->ssp);
+       kfree(priv);
+       return 0;
 }
 
 #define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -784,10 +784,7 @@ static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .set_tristate   = pxa_ssp_set_dai_tristate,
 };
 
-struct snd_soc_dai pxa_ssp_dai[] = {
-       {
-               .name = "pxa2xx-ssp1",
-               .id = 0,
+static struct snd_soc_dai_driver pxa_ssp_dai = {
                .probe = pxa_ssp_probe,
                .remove = pxa_ssp_remove,
                .suspend = pxa_ssp_suspend,
@@ -805,81 +802,38 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .formats = PXA_SSP_FORMATS,
                 },
                .ops = &pxa_ssp_dai_ops,
+};
+
+static __devinit int asoc_ssp_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+}
+
+static int __devexit asoc_ssp_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+       .driver = {
+                       .name = "pxa-ssp-dai",
+                       .owner = THIS_MODULE,
        },
-       {       .name = "pxa2xx-ssp2",
-               .id = 1,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
-       {
-               .name = "pxa2xx-ssp3",
-               .id = 2,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
-       {
-               .name = "pxa2xx-ssp4",
-               .id = 3,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
+
+       .probe = asoc_ssp_probe,
+       .remove = __devexit_p(asoc_ssp_remove),
 };
-EXPORT_SYMBOL_GPL(pxa_ssp_dai);
 
 static int __init pxa_ssp_init(void)
 {
-       return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+       return platform_driver_register(&asoc_ssp_driver);
 }
 module_init(pxa_ssp_init);
 
 static void __exit pxa_ssp_exit(void)
 {
-       snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+       platform_driver_unregister(&asoc_ssp_driver);
 }
 module_exit(pxa_ssp_exit);
 
index 91deadd55675a23aea5d7d89400747c6bd66cdf8..bc79da221c0df018942b80c613be5d8d11ef6bf9 100644 (file)
@@ -42,6 +42,4 @@
 
 #define PXA_SSP_PLL_OUT  0
 
-extern struct snd_soc_dai pxa_ssp_dai[4];
-
 #endif
index d314115e3dd726750afbb8706b72cc51fbb3104b..ac51c6d25c4291998bd7ffc6b4d51a0c0148923a 100644 (file)
@@ -24,7 +24,6 @@
 #include <mach/dma.h>
 #include <mach/audio.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -104,24 +103,21 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
 #define pxa2xx_ac97_resume     NULL
 #endif
 
-static int pxa2xx_ac97_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
 {
        return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
 }
 
-static void pxa2xx_ac97_remove(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int pxa2xx_ac97_remove(struct snd_soc_dai *dai)
 {
        pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
+       return 0;
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
+                                struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -136,10 +132,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
 
 static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *dai)
+                                    struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -154,11 +148,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
 
 static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *dai)
+                                    struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
        else
@@ -188,10 +179,9 @@ static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
  * There is only 1 physical AC97 interface for pxa2xx, but it
  * has extra fifo's that can be used for aux DACs and ADCs.
  */
-struct snd_soc_dai pxa_ac97_dai[] = {
+static struct snd_soc_dai_driver pxa_ac97_dai[] = {
 {
        .name = "pxa2xx-ac97",
-       .id = 0,
        .ac97_control = 1,
        .probe = pxa2xx_ac97_probe,
        .remove = pxa2xx_ac97_remove,
@@ -213,7 +203,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 {
        .name = "pxa2xx-ac97-aux",
-       .id = 1,
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Aux Playback",
@@ -231,7 +220,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 {
        .name = "pxa2xx-ac97-mic",
-       .id = 2,
        .ac97_control = 1,
        .capture = {
                .stream_name = "AC97 Mic Capture",
@@ -243,36 +231,26 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 };
 
-EXPORT_SYMBOL_GPL(pxa_ac97_dai);
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
-static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
+static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
-       int i;
-       pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
-
-       if (pdev->id >= 0) {
+       if (pdev->id != -1) {
                dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
                return -ENXIO;
        }
 
-       for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) {
-               pxa_ac97_dai[i].dev = &pdev->dev;
-               if (pdata && pdata->codec_pdata[0])
-                       pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0];
-       }
-
        /* Punt most of the init to the SoC probe; we may need the machine
         * driver to do interesting things with the clocking to get us up
         * and running.
         */
-       return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+       return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai,
+                       ARRAY_SIZE(pxa_ac97_dai));
 }
 
 static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
-
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai));
        return 0;
 }
 
index e390de8edcd48724558f63c4338a9e83b19d1762..eda891e6f31bab8ff1395a193bbc3949d2fecc8c 100644 (file)
@@ -14,8 +14,6 @@
 #define PXA2XX_DAI_AC97_AUX            1
 #define PXA2XX_DAI_AC97_MIC            2
 
-extern struct snd_soc_dai pxa_ac97_dai[3];
-
 /* platform data */
 extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
 
index c1a5275721e4f0eb2812842d31555c84b16f206c..11be5952a5066fa30163a3b51143b9dfb41b05e7 100644 (file)
@@ -27,7 +27,6 @@
 #include <mach/dma.h>
 #include <mach/audio.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 /*
@@ -80,6 +79,7 @@ struct pxa_i2s_port {
 };
 static struct pxa_i2s_port pxa_i2s;
 static struct clk *clk_i2s;
+static int clk_ena = 0;
 
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
        .name                   = "I2S PCM Stereo out",
@@ -101,7 +101,7 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        if (IS_ERR(clk_i2s))
                return PTR_ERR(clk_i2s);
@@ -162,13 +162,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
-       dai->private_data = dai;
+       clk_ena = 1;
        pxa_i2s_wait();
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -176,7 +174,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = &pxa2xx_i2s_pcm_stereo_in;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
 
        /* is port used by another stream */
        if (!(SACR0 & SACR0_ENB)) {
@@ -259,9 +257,9 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
        if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
-               if (dai->private_data != NULL) {
+               if (clk_ena) {
                        clk_disable(clk_i2s);
-                       dai->private_data = NULL;
+                       clk_ena = 0;
                }
        }
 }
@@ -300,6 +298,35 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 #define pxa2xx_i2s_resume      NULL
 #endif
 
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+       clk_i2s = clk_get(dai->dev, "I2SCLK");
+       if (IS_ERR(clk_i2s))
+               return PTR_ERR(clk_i2s);
+
+       /*
+        * PXA Developer's Manual:
+        * If SACR0[ENB] is toggled in the middle of a normal operation,
+        * the SACR0[RST] bit must also be set and cleared to reset all
+        * I2S controller registers.
+        */
+       SACR0 = SACR0_RST;
+       SACR0 = 0;
+       /* Make sure RPL and REC are disabled */
+       SACR1 = SACR1_DRPL | SACR1_DREC;
+       /* Along with FIFO servicing */
+       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+       return 0;
+}
+
+static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+       clk_put(clk_i2s);
+       clk_i2s = ERR_PTR(-ENOENT);
+       return 0;
+}
+
 #define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
@@ -313,9 +340,9 @@ static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
        .set_sysclk     = pxa2xx_i2s_set_dai_sysclk,
 };
 
-struct snd_soc_dai pxa_i2s_dai = {
-       .name = "pxa2xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+       .probe = pxa2xx_i2s_probe,
+       .remove = pxa2xx_i2s_remove,
        .suspend = pxa2xx_i2s_suspend,
        .resume = pxa2xx_i2s_resume,
        .playback = {
@@ -332,49 +359,20 @@ struct snd_soc_dai pxa_i2s_dai = {
        .symmetric_rates = 1,
 };
 
-EXPORT_SYMBOL_GPL(pxa_i2s_dai);
-
-static int pxa2xx_i2s_probe(struct platform_device *dev)
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-       int ret;
-
-       clk_i2s = clk_get(&dev->dev, "I2SCLK");
-       if (IS_ERR(clk_i2s))
-               return PTR_ERR(clk_i2s);
-
-       pxa_i2s_dai.dev = &dev->dev;
-       pxa_i2s_dai.private_data = NULL;
-       ret = snd_soc_register_dai(&pxa_i2s_dai);
-       if (ret != 0)
-               clk_put(clk_i2s);
-
-       /*
-        * PXA Developer's Manual:
-        * If SACR0[ENB] is toggled in the middle of a normal operation,
-        * the SACR0[RST] bit must also be set and cleared to reset all
-        * I2S controller registers.
-        */
-       SACR0 = SACR0_RST;
-       SACR0 = 0;
-       /* Make sure RPL and REC are disabled */
-       SACR1 = SACR1_DRPL | SACR1_DREC;
-       /* Along with FIFO servicing */
-       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
-
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
 }
 
-static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pxa_i2s_dai);
-       clk_put(clk_i2s);
-       clk_i2s = ERR_PTR(-ENOENT);
+       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver pxa2xx_i2s_driver = {
-       .probe = pxa2xx_i2s_probe,
-       .remove = __devexit_p(pxa2xx_i2s_remove),
+       .probe = pxa2xx_i2s_drv_probe,
+       .remove = __devexit_p(pxa2xx_i2s_drv_remove),
 
        .driver = {
                .name = "pxa2xx-i2s",
@@ -400,3 +398,4 @@ module_exit(pxa2xx_i2s_exit);
 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");
index e2def441153eee706ab6789a00385c6e13f49284..070f3c6059fed6e880f8cce055731506b43c71e8 100644 (file)
@@ -15,6 +15,4 @@
 /* I2S clock */
 #define PXA2XX_I2S_SYSCLK              0
 
-extern struct snd_soc_dai pxa_i2s_dai;
-
 #endif
index adc7e6f15f9367b5acbf16c02f633af3583a16da..02fb66416ddc894c7abdfd2fa52cddc3eb717225 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
 
-#include "pxa2xx-pcm.h"
 #include "../../arm/pxa2xx-pcm.h"
 
 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -28,7 +27,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct pxa2xx_pcm_dma_params *dma;
        int ret;
 
-       dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -95,14 +94,14 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -112,25 +111,44 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform pxa2xx_soc_platform = {
-       .name           = "pxa2xx-audio",
-       .pcm_ops        = &pxa2xx_pcm_ops,
+static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+       .ops    = &pxa2xx_pcm_ops,
        .pcm_new        = pxa2xx_soc_pcm_new,
        .pcm_free       = pxa2xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
 
-static int __init pxa2xx_soc_platform_init(void)
+static int __devinit pxa2xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pxa2xx_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
 }
-module_init(pxa2xx_soc_platform_init);
 
-static void __exit pxa2xx_soc_platform_exit(void)
+static int __devexit pxa2xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&pxa2xx_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver pxa_pcm_driver = {
+       .driver = {
+                       .name = "pxa-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = pxa2xx_soc_platform_probe,
+       .remove = __devexit_p(pxa2xx_soc_platform_remove),
+};
+
+static int __init snd_pxa_pcm_init(void)
+{
+       return platform_driver_register(&pxa_pcm_driver);
+}
+module_init(snd_pxa_pcm_init);
+
+static void __exit snd_pxa_pcm_exit(void)
+{
+       platform_driver_unregister(&pxa_pcm_driver);
 }
-module_exit(pxa2xx_soc_platform_exit);
+module_exit(snd_pxa_pcm_exit);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
deleted file mode 100644 (file)
index 60c3b20..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  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 _PXA2XX_PCM_H
-#define _PXA2XX_PCM_H
-
-/* platform data */
-extern struct snd_soc_platform pxa2xx_soc_platform;
-
-#endif
index 7e3f41696c41f53e6479a4678982f0bc7e28842d..2cda82bc5d2e4362e2a3941428ad1eaf9802934e 100644 (file)
@@ -26,9 +26,6 @@
 
 #include <asm/mach-types.h>
 
-#include "../codecs/cs4270.h"
-#include "../codecs/ak4104.h"
-#include "pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 
 #define GPIO_SPDIF_RESET       (38)
@@ -71,7 +68,7 @@ static void raumfeld_enable_audio(bool en)
 static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* set freq to 0 to enable all possible codec sample rates */
        return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -80,7 +77,7 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
 static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* set freq to 0 to enable all possible codec sample rates */
        snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -90,8 +87,8 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int fmt, clk = 0;
        int ret = 0;
 
@@ -167,32 +164,14 @@ static int raumfeld_line_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_dai_link raumfeld_line_dai = {
-       .name           = "CS4270",
-       .stream_name    = "CS4270",
-       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP1],
-       .codec_dai      = &cs4270_dai,
-       .ops            = &raumfeld_cs4270_ops,
-};
-
-static struct snd_soc_card snd_soc_line_raumfeld = {
-       .name           = "Raumfeld analog",
-       .platform       = &pxa2xx_soc_platform,
-       .dai_link       = &raumfeld_line_dai,
-       .suspend_post   = raumfeld_line_suspend,
-       .resume_pre     = raumfeld_line_resume,
-       .num_links      = 1,
-};
-
-
 /* AK4104 */
 
 static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fmt, ret = 0, clk = 0;
 
        switch (params_rate(params)) {
@@ -247,34 +226,35 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .hw_params = raumfeld_ak4104_hw_params,
 };
 
-static struct snd_soc_dai_link raumfeld_spdif_dai = {
+static struct snd_soc_dai_link raumfeld_dai[] = {
+{
        .name           = "ak4104",
        .stream_name    = "Playback",
-       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP2],
-       .codec_dai      = &ak4104_dai,
+       .cpu_dai_name = "pxa-ssp-dai.1",
+       .codec_dai_name = "ak4104-hifi",
+       .platform_name = "pxa-pcm-audio",
        .ops            = &raumfeld_ak4104_ops,
-};
-
-static struct snd_soc_card snd_soc_spdif_raumfeld = {
-       .name           = "Raumfeld S/PDIF",
-       .platform       = &pxa2xx_soc_platform,
-       .dai_link       = &raumfeld_spdif_dai,
-       .num_links      = 1
-};
-
-/* raumfeld_audio audio subsystem */
-static struct snd_soc_device raumfeld_line_devdata = {
-       .card = &snd_soc_line_raumfeld,
-       .codec_dev = &soc_codec_device_cs4270,
-};
+       .codec_name = "ak4104-codec.0",
+},
+{
+       .name           = "CS4270",
+       .stream_name    = "CS4270",
+       .cpu_dai_name = "pxa-ssp-dai.0",
+       .platform_name = "pxa-pcm-audio",
+       .codec_dai_name = "cs4270-hifi",
+       .codec_name = "cs4270-codec.0-0048",
+       .ops            = &raumfeld_cs4270_ops,
+},};
 
-static struct snd_soc_device raumfeld_spdif_devdata = {
-       .card = &snd_soc_spdif_raumfeld,
-       .codec_dev = &soc_codec_device_ak4104,
+static struct snd_soc_card snd_soc_raumfeld = {
+       .name           = "Raumfeld",
+       .dai_link       = raumfeld_dai,
+       .suspend_post   = raumfeld_line_suspend,
+       .resume_pre     = raumfeld_line_resume,
+       .num_links      = ARRAY_SIZE(raumfeld_dai),
 };
 
-static struct platform_device *raumfeld_audio_line_device;
-static struct platform_device *raumfeld_audio_spdif_device;
+static struct platform_device *raumfeld_audio_device;
 
 static int __init raumfeld_audio_init(void)
 {
@@ -292,38 +272,19 @@ static int __init raumfeld_audio_init(void)
 
        set_max9485_clk(MAX9485_MCLK_FREQ_122880);
 
-       /* LINE */
-       raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
-       if (!raumfeld_audio_line_device)
+       /* Register LINE and SPDIF */
+       raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
+       if (!raumfeld_audio_device)
                return -ENOMEM;
 
-       platform_set_drvdata(raumfeld_audio_line_device,
-                            &raumfeld_line_devdata);
-       raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
-       ret = platform_device_add(raumfeld_audio_line_device);
-       if (ret)
-               platform_device_put(raumfeld_audio_line_device);
+       platform_set_drvdata(raumfeld_audio_device,
+                            &snd_soc_raumfeld);
+       ret = platform_device_add(raumfeld_audio_device);
 
        /* no S/PDIF on Speakers */
        if (machine_is_raumfeld_speaker())
                return ret;
 
-       /* S/PDIF */
-       raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
-       if (!raumfeld_audio_spdif_device) {
-               platform_device_put(raumfeld_audio_line_device);
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(raumfeld_audio_spdif_device,
-                            &raumfeld_spdif_devdata);
-       raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
-       ret = platform_device_add(raumfeld_audio_spdif_device);
-       if (ret) {
-               platform_device_put(raumfeld_audio_line_device);
-               platform_device_put(raumfeld_audio_spdif_device);
-       }
-
        raumfeld_enable_audio(true);
 
        return ret;
@@ -333,10 +294,7 @@ static void __exit raumfeld_audio_exit(void)
 {
        raumfeld_enable_audio(false);
 
-       platform_device_unregister(raumfeld_audio_line_device);
-
-       if (machine_is_raumfeld_connector())
-               platform_device_unregister(raumfeld_audio_spdif_device);
+       platform_device_unregister(raumfeld_audio_device);
 
        i2c_unregister_device(max9486_client);
 
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
new file mode 100644 (file)
index 0000000..d63cb47
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * saarb.c -- SoC audio for saarb
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *saarb_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
+};
+
+/* saarb machine dapm widgets */
+static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* saarb machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headset Stereophone", NULL, "HS1"},
+       {"Headset Stereophone", NULL, "HS2"},
+
+       {"Ext Speaker", NULL, "LSP"},
+       {"Ext Speaker", NULL, "LSN"},
+
+       {"Lineout Out 1", NULL, "LINEOUT1"},
+       {"Lineout Out 2", NULL, "LINEOUT2"},
+
+       {"MIC1P", NULL, "Mic1 Bias"},
+       {"MIC1N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+       {"MIC2P", NULL, "Mic1 Bias"},
+       {"MIC2N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+       {"MIC3P", NULL, "Mic3 Bias"},
+       {"MIC3N", NULL, "Mic3 Bias"},
+       {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int width = snd_pcm_format_physical_width(params_format(params));
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+                                    PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+
+       return ret;
+}
+
+static struct snd_soc_ops saarb_i2s_ops = {
+       .hw_params      = saarb_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link saarb_dai[] = {
+       {
+               .name           = "88PM860x I2S",
+               .stream_name    = "I2S Audio",
+               .cpu_dai_name   = "pxa-ssp-dai.1",
+               .codec_dai_name = "88pm860x-i2s",
+               .platform_name  = "pxa-pcm-audio",
+               .codec_name     = "88pm860x-codec",
+               .init           = saarb_pm860x_init,
+               .ops            = &saarb_i2s_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_card_saarb = {
+       .name = "Saarb",
+       .dai_link = saarb_dai,
+       .num_links = ARRAY_SIZE(saarb_dai),
+};
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
+                                 ARRAY_SIZE(saarb_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       /* connected pins */
+       snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+       snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+       snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+       snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+       ret = snd_soc_dapm_sync(codec);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                       &hs_jack);
+       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                             hs_jack_pins);
+       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+                        &mic_jack);
+       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+                             mic_jack_pins);
+
+       /* headphone, microphone detection & headset short detection */
+       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+       return 0;
+}
+
+static int __init saarb_init(void)
+{
+       int ret;
+
+       if (!machine_is_saarb())
+               return -ENODEV;
+       saarb_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!saarb_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
+
+       ret = platform_device_add(saarb_snd_device);
+       if (ret)
+               platform_device_put(saarb_snd_device);
+
+       return ret;
+}
+
+static void __exit saarb_exit(void)
+{
+       platform_device_unregister(saarb_snd_device);
+}
+
+module_init(saarb_init);
+module_exit(saarb_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
+MODULE_LICENSE("GPL");
index d256f5f313b5a0e10ac5158dc422741f08ec6cd3..f470f360f4dda9a3193b5f5011a7b9688cfb3b32 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/mach-types.h>
 #include <mach/spitz.h>
 #include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define SPITZ_HP        0
@@ -107,7 +106,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec)
 static int spitz_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        spitz_ext_control(codec);
@@ -118,8 +117,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -274,8 +273,9 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
 /*
  * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
  */
-static int spitz_wm8750_init(struct snd_soc_codec *codec)
+static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* NC codec pins */
@@ -308,8 +308,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
        .stream_name = "WM8750",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8750_dai,
+       .cpu_dai_name = "pxa-is2",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8750-codec.0-001a",
        .init = spitz_wm8750_init,
        .ops = &spitz_ops,
 };
@@ -317,17 +319,10 @@ static struct snd_soc_dai_link spitz_dai = {
 /* spitz audio machine driver */
 static struct snd_soc_card snd_soc_spitz = {
        .name = "Spitz",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &spitz_dai,
        .num_links = 1,
 };
 
-/* spitz audio subsystem */
-static struct snd_soc_device spitz_snd_devdata = {
-       .card = &snd_soc_spitz,
-       .codec_dev = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *spitz_snd_device;
 
 static int __init spitz_init(void)
@@ -341,8 +336,7 @@ static int __init spitz_init(void)
        if (!spitz_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
-       spitz_snd_devdata.dev = &spitz_snd_device->dev;
+       platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
        ret = platform_device_add(spitz_snd_device);
 
        if (ret)
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
new file mode 100644 (file)
index 0000000..248c283
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * tavorevb3.c -- SoC audio for Tavor EVB3
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *evb3_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
+};
+
+/* tavorevb3 machine dapm widgets */
+static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* tavorevb3 machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headset Stereophone", NULL, "HS1"},
+       {"Headset Stereophone", NULL, "HS2"},
+
+       {"Ext Speaker", NULL, "LSP"},
+       {"Ext Speaker", NULL, "LSN"},
+
+       {"Lineout Out 1", NULL, "LINEOUT1"},
+       {"Lineout Out 2", NULL, "LINEOUT2"},
+
+       {"MIC1P", NULL, "Mic1 Bias"},
+       {"MIC1N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+       {"MIC2P", NULL, "Mic1 Bias"},
+       {"MIC2N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+       {"MIC3P", NULL, "Mic3 Bias"},
+       {"MIC3N", NULL, "Mic3 Bias"},
+       {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int width = snd_pcm_format_physical_width(params_format(params));
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+                                    PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+       return ret;
+}
+
+static struct snd_soc_ops evb3_i2s_ops = {
+       .hw_params      = evb3_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link evb3_dai[] = {
+       {
+               .name           = "88PM860x I2S",
+               .stream_name    = "I2S Audio",
+               .cpu_dai_name   = "pxa-ssp-dai.1",
+               .codec_dai_name = "88pm860x-i2s",
+               .platform_name  = "pxa-pcm-audio",
+               .codec_name     = "88pm860x-codec",
+               .init           = evb3_pm860x_init,
+               .ops            = &evb3_i2s_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_card_evb3 = {
+       .name = "Tavor EVB3",
+       .dai_link = evb3_dai,
+       .num_links = ARRAY_SIZE(evb3_dai),
+};
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
+                                 ARRAY_SIZE(evb3_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       /* connected pins */
+       snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+       snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+       snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+       snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+       ret = snd_soc_dapm_sync(codec);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                       &hs_jack);
+       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                             hs_jack_pins);
+       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+                        &mic_jack);
+       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+                             mic_jack_pins);
+
+       /* headphone, microphone detection & headset short detection */
+       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+       return 0;
+}
+
+static int __init tavorevb3_init(void)
+{
+       int ret;
+
+       if (!machine_is_tavorevb3())
+               return -ENODEV;
+       evb3_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!evb3_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
+
+       ret = platform_device_add(evb3_snd_device);
+       if (ret)
+               platform_device_put(evb3_snd_device);
+
+       return ret;
+}
+
+static void __exit tavorevb3_exit(void)
+{
+       platform_device_unregister(evb3_snd_device);
+}
+
+module_init(tavorevb3_init);
+module_exit(tavorevb3_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
+MODULE_LICENSE("GPL");
index dbbd3e9d1637f0b9d14d8790973d5d9035e9d3e1..a3bfb2e8b70fb6946739837126dc49fed237f658 100644 (file)
@@ -33,7 +33,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_card tosa;
@@ -80,7 +79,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->card->codec;
 
        /* check the jack status at stream startup */
        tosa_ext_control(codec);
@@ -184,8 +183,9 @@ static const struct snd_kcontrol_new tosa_controls[] = {
                tosa_set_spk),
 };
 
-static int tosa_ac97_init(struct snd_soc_codec *codec)
+static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "OUT3");
@@ -212,16 +212,20 @@ static struct snd_soc_dai_link tosa_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_dai_name = "wm9712-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm9712-codec",
        .init = tosa_ac97_init,
        .ops = &tosa_ops,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_dai_name = "wm9712-aux",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm9712-codec",
        .ops = &tosa_ops,
 },
 };
@@ -248,18 +252,12 @@ static int tosa_remove(struct platform_device *dev)
 
 static struct snd_soc_card tosa = {
        .name = "Tosa",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = tosa_dai,
        .num_links = ARRAY_SIZE(tosa_dai),
        .probe = tosa_probe,
        .remove = tosa_remove,
 };
 
-static struct snd_soc_device tosa_snd_devdata = {
-       .card = &tosa,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *tosa_snd_device;
 
 static int __init tosa_init(void)
@@ -275,8 +273,7 @@ static int __init tosa_init(void)
                goto err_alloc;
        }
 
-       platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
-       tosa_snd_devdata.dev = &tosa_snd_device->dev;
+       platform_set_drvdata(tosa_snd_device, &tosa);
        ret = platform_device_add(tosa_snd_device);
 
        if (!ret)
index 4e4d2fa8ddc5f056de46271aa0f97116350597b1..4cc841b441829bf6f04a2a00f683e4093619a372 100644 (file)
@@ -30,7 +30,6 @@
 #include <mach/z2.h>
 
 #include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 static struct snd_soc_card snd_soc_z2;
@@ -39,8 +38,8 @@ static int z2_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -138,8 +137,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 /*
  * Logic for a wm8750 as connected on a Z2 Device
  */
-static int z2_wm8750_init(struct snd_soc_codec *codec)
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* NC codec pins */
@@ -160,7 +160,7 @@ static int z2_wm8750_init(struct snd_soc_codec *codec)
                goto err;
 
        /* Jack detection API stuff */
-       ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET,
+       ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
                                &hs_jack);
        if (ret)
                goto err;
@@ -189,8 +189,10 @@ static struct snd_soc_ops z2_ops = {
 static struct snd_soc_dai_link z2_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
-       .cpu_dai        = &pxa_i2s_dai,
-       .codec_dai      = &wm8750_dai,
+       .cpu_dai_name   = "pxa2xx-i2s",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name     = "wm8750-codec.0-001a",
        .init           = z2_wm8750_init,
        .ops            = &z2_ops,
 };
@@ -198,17 +200,10 @@ static struct snd_soc_dai_link z2_dai = {
 /* z2 audio machine driver */
 static struct snd_soc_card snd_soc_z2 = {
        .name           = "Z2",
-       .platform       = &pxa2xx_soc_platform,
        .dai_link       = &z2_dai,
        .num_links      = 1,
 };
 
-/* z2 audio subsystem */
-static struct snd_soc_device z2_snd_devdata = {
-       .card           = &snd_soc_z2,
-       .codec_dev      = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *z2_snd_device;
 
 static int __init z2_init(void)
@@ -222,8 +217,7 @@ static int __init z2_init(void)
        if (!z2_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(z2_snd_device, &z2_snd_devdata);
-       z2_snd_devdata.dev = &z2_snd_device->dev;
+       platform_set_drvdata(z2_snd_device, &snd_soc_z2);
        ret = platform_device_add(z2_snd_device);
 
        if (ret)
index dd678ae24398bb7f336257a362b43e54eeb25a5f..d27e05af77594093e20b645ef203887683f8b8d5 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc-dapm.h>
 
 #include "../codecs/wm9713.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 #include "pxa-ssp.h"
 
@@ -71,10 +70,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "Multiactor", NULL, "SPKR" },
 };
 
-static int zylonite_wm9713_init(struct snd_soc_codec *codec)
+static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        if (clk_pout)
-               snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+               snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
                                    clk_get_rate(pout), 0);
 
        snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
@@ -94,8 +95,8 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int pll_out = 0;
        unsigned int wm9713_div = 0;
        int ret = 0;
@@ -163,21 +164,27 @@ static struct snd_soc_dai_link zylonite_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_name = "wm9713-hifi",
        .init = zylonite_wm9713_init,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_name = "wm9713-aux",
 },
 {
        .name = "WM9713 Voice",
        .stream_name = "WM9713 Voice",
-       .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3],
-       .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ssp-dai.2",
+       .codec_name = "wm9713-voice",
        .ops = &zylonite_voice_ops,
 },
 };
@@ -248,14 +255,9 @@ static struct snd_soc_card zylonite = {
        .remove = &zylonite_remove,
        .suspend_post = &zylonite_suspend_post,
        .resume_pre = &zylonite_resume_pre,
-       .platform = &pxa2xx_soc_platform,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
-};
-
-static struct snd_soc_device zylonite_snd_ac97_devdata = {
-       .card = &zylonite,
-       .codec_dev = &soc_codec_dev_wm9713,
+       .owner = THIS_MODULE,
 };
 
 static struct platform_device *zylonite_snd_ac97_device;
@@ -268,9 +270,7 @@ static int __init zylonite_init(void)
        if (!zylonite_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(zylonite_snd_ac97_device,
-                            &zylonite_snd_ac97_devdata);
-       zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev;
+       platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
 
        ret = platform_device_add(zylonite_snd_ac97_device);
        if (ret != 0)
index 213963ac3c28ba4aaa236c399f5211356f469625..8a6b53ccd203e0a8dfe14dd7579325284e736591 100644 (file)
@@ -36,6 +36,10 @@ config SND_S3C_SOC_AC97
        tristate
        select SND_SOC_AC97_BUS
 
+config SND_S5P_SOC_SPDIF
+       tristate
+       select SND_SOC_SPDIF
+
 config SND_S3C24XX_SOC_NEO1973_WM8753
        tristate "SoC I2S Audio support for NEO1973 - WM8753"
        depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -118,6 +122,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
        select SND_SOC_TLV320AIC3X
        select SND_S3C24XX_SOC_SIMTEC
 
+config SND_S3C24XX_SOC_RX1950_UDA1380
+       tristate "Audio support for the HP iPAQ RX1950"
+       depends on SND_S3C24XX_SOC && MACH_RX1950
+       select SND_S3C24XX_SOC_I2S
+       select SND_SOC_UDA1380
+       help
+         This driver provides audio support for HP iPAQ RX1950 PDA.
+
 config SND_SOC_SMDK_WM9713
        tristate "SoC AC97 Audio support for SMDK with WM9713"
        depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
@@ -131,3 +143,28 @@ config SND_S3C64XX_SOC_SMARTQ
        depends on SND_S3C24XX_SOC && MACH_SMARTQ
        select SND_S3C64XX_SOC_I2S
        select SND_SOC_WM8750
+
+config SND_S5PC110_SOC_AQUILA_WM8994
+       tristate "SoC I2S Audio support for AQUILA - WM8994"
+       depends on SND_S3C24XX_SOC && MACH_AQUILA
+       select SND_S3C64XX_SOC_I2S_V4
+       select SND_SOC_WM8994
+       help
+         Say Y if you want to add support for SoC audio on aquila
+         with the WM8994.
+
+config SND_S5PV210_SOC_GONI_WM8994
+       tristate "SoC I2S Audio support for GONI - WM8994"
+       depends on SND_S3C24XX_SOC && MACH_GONI
+       select SND_S3C64XX_SOC_I2S_V4
+       select SND_SOC_WM8994
+       help
+         Say Y if you want to add support for SoC audio on goni
+         with the WM8994.
+
+config SND_SOC_SMDK_SPDIF
+       tristate "SoC S/PDIF Audio support for SMDK"
+       depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+       select SND_S5P_SOC_SPDIF
+       help
+         Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
index 50172c385d90b89e7fc327a596efc235f95cca55..ee8f41d6df994e9eb7c3f5507a3a7d6c7023e293 100644 (file)
@@ -7,6 +7,7 @@ snd-soc-s3c-ac97-objs := s3c-ac97.o
 snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
 snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
 snd-soc-s3c-pcm-objs := s3c-pcm.o
+snd-soc-samsung-spdif-objs := spdif.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
 obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
 obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
 obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
+obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
 
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -27,9 +29,13 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
 snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
 snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
 snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
 snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-aquila-wm8994-objs := aquila_wm8994.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -40,6 +46,10 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
 obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
 obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
+obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
new file mode 100644 (file)
index 0000000..235d197
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * aquila_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card aquila;
+static struct platform_device *aquila_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       }, {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+       },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+       {
+               .gpio = S5PV210_GPH0(6),
+               .name = "DET_3.5",
+               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+               .debounce_time = 200,
+       },
+};
+
+static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Main Mic", NULL),
+       SND_SOC_DAPM_MIC("2nd Mic", NULL),
+       SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
+       {"Ext Spk", NULL, "SPKOUTLP"},
+       {"Ext Spk", NULL, "SPKOUTLN"},
+
+       {"Ext Rcv", NULL, "HPOUT2N"},
+       {"Ext Rcv", NULL, "HPOUT2P"},
+
+       {"Headset Stereophone", NULL, "HPOUT1L"},
+       {"Headset Stereophone", NULL, "HPOUT1R"},
+
+       {"IN1RN", NULL, "Headset Mic"},
+       {"IN1RP", NULL, "Headset Mic"},
+
+       {"IN1RN", NULL, "2nd Mic"},
+       {"IN1RP", NULL, "2nd Mic"},
+
+       {"IN1LN", NULL, "Main Mic"},
+       {"IN1LP", NULL, "Main Mic"},
+
+       {"IN2LN", NULL, "Radio In"},
+       {"IN2RN", NULL, "Radio In"},
+};
+
+static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       /* add aquila specific widgets */
+       snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
+                       ARRAY_SIZE(aquila_dapm_widgets));
+
+       /* set up aquila specific audio routes */
+       snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
+                       ARRAY_SIZE(aquila_dapm_routes));
+
+       /* set endpoints to not connected */
+       snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+       snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+       snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+       snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+
+       snd_soc_dapm_sync(codec);
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(&aquila, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+                       &jack);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int aquila_hifi_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       /* set the cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the cpu system clock */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops aquila_hifi_ops = {
+       .hw_params = aquila_hifi_hw_params,
+};
+
+static int aquila_voice_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+       .name = "aquila-voice-dai",
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops aquila_voice_ops = {
+       .hw_params = aquila_voice_hw_params,
+};
+
+static struct snd_soc_dai_link aquila_dai[] = {
+{
+       .name = "WM8994",
+       .stream_name = "WM8994 HiFi",
+       .cpu_dai_name = "s3c64xx-i2s-v4",
+       .codec_dai_name = "wm8994-hifi",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .init = aquila_wm8994_init,
+       .ops = &aquila_hifi_ops,
+}, {
+       .name = "WM8994 Voice",
+       .stream_name = "Voice",
+       .cpu_dai_name = "aquila-voice-dai",
+       .codec_dai_name = "wm8994-voice",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .ops = &aquila_voice_ops,
+},
+};
+
+static struct snd_soc_card aquila = {
+       .name = "aquila",
+       .dai_link = aquila_dai,
+       .num_links = ARRAY_SIZE(aquila_dai),
+};
+
+static int __init aquila_init(void)
+{
+       int ret;
+
+       if (!machine_is_aquila())
+               return -ENODEV;
+
+       aquila_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!aquila_snd_device)
+               return -ENOMEM;
+
+       /* register voice DAI here */
+       ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(aquila_snd_device, &aquila);
+       ret = platform_device_add(aquila_snd_device);
+
+       if (ret)
+               platform_device_put(aquila_snd_device);
+
+       return ret;
+}
+
+static void __exit aquila_exit(void)
+{
+       platform_device_unregister(aquila_snd_device);
+}
+
+module_init(aquila_init);
+module_exit(aquila_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
new file mode 100644 (file)
index 0000000..694f702
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       }, {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+       },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+       {
+               .gpio = S5PV210_GPH0(6),
+               .name = "DET_3.5",
+               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+               .debounce_time = 200,
+       },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Main Mic", NULL),
+       SND_SOC_DAPM_MIC("2nd Mic", NULL),
+       SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+       {"Ext Left Spk", NULL, "SPKOUTLP"},
+       {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+       {"Ext Right Spk", NULL, "SPKOUTRP"},
+       {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+       {"Ext Rcv", NULL, "HPOUT2N"},
+       {"Ext Rcv", NULL, "HPOUT2P"},
+
+       {"Headset Stereophone", NULL, "HPOUT1L"},
+       {"Headset Stereophone", NULL, "HPOUT1R"},
+
+       {"IN1RN", NULL, "Headset Mic"},
+       {"IN1RP", NULL, "Headset Mic"},
+
+       {"IN1RN", NULL, "2nd Mic"},
+       {"IN1RP", NULL, "2nd Mic"},
+
+       {"IN1LN", NULL, "Main Mic"},
+       {"IN1LP", NULL, "Main Mic"},
+
+       {"IN2LN", NULL, "Radio In"},
+       {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       /* add goni specific widgets */
+       snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
+                       ARRAY_SIZE(goni_dapm_widgets));
+
+       /* set up goni specific audio routes */
+       snd_soc_dapm_add_routes(codec, goni_dapm_routes,
+                       ARRAY_SIZE(goni_dapm_routes));
+
+       /* set endpoints to not connected */
+       snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+       snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+       snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+
+       snd_soc_dapm_sync(codec);
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(&goni, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+                       &jack);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       /* set the cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the cpu system clock */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+       .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+       .name = "goni-voice-dai",
+       .id = 0,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+       .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+       .name = "WM8994",
+       .stream_name = "WM8994 HiFi",
+       .cpu_dai_name = "s3c64xx-i2s-v4",
+       .codec_dai_name = "wm8994-hifi",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .init = goni_wm8994_init,
+       .ops = &goni_hifi_ops,
+}, {
+       .name = "WM8994 Voice",
+       .stream_name = "Voice",
+       .cpu_dai_name = "goni-voice-dai",
+       .codec_dai_name = "wm8994-voice",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+       .name = "goni",
+       .dai_link = goni_dai,
+       .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+       int ret;
+
+       if (!machine_is_goni())
+               return -ENODEV;
+
+       goni_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!goni_snd_device)
+               return -ENOMEM;
+
+       /* register voice DAI here */
+       ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(goni_snd_device, &goni);
+       ret = platform_device_add(goni_snd_device);
+
+       if (ret)
+               platform_device_put(goni_snd_device);
+
+       return ret;
+}
+
+static void __exit goni_exit(void)
+{
+       platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
index 8c108b121c10de97f4fbc2f786b54e40c23f9b8f..49605cd83947efc04f7cc6f7cbd4b4bc88614e0d 100644 (file)
@@ -49,8 +49,8 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
                          struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct s3c_i2sv2_rate_calc div;
        unsigned int clk = 0;
        int ret = 0;
@@ -108,8 +108,9 @@ static struct snd_soc_ops jive_ops = {
        .hw_params      = jive_hw_params,
 };
 
-static int jive_wm8750_init(struct snd_soc_codec *codec)
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* These endpoints are not being used. */
@@ -138,8 +139,10 @@ static int jive_wm8750_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link jive_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
-       .cpu_dai        = &s3c2412_i2s_dai,
-       .codec_dai      = &wm8750_dai,
+       .cpu_dai_name   = "s3c2412-i2s",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name  = "s3c24xx-pcm-audio",
+       .codec_name     = "wm8750-codec.0-0x1a",
        .init           = jive_wm8750_init,
        .ops            = &jive_ops,
 };
@@ -147,17 +150,10 @@ static struct snd_soc_dai_link jive_dai = {
 /* jive audio machine driver */
 static struct snd_soc_card snd_soc_machine_jive = {
        .name           = "Jive",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &jive_dai,
        .num_links      = 1,
 };
 
-/* jive audio subsystem */
-static struct snd_soc_device jive_snd_devdata = {
-       .card           = &snd_soc_machine_jive,
-       .codec_dev      = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *jive_snd_device;
 
 static int __init jive_init(void)
@@ -173,8 +169,7 @@ static int __init jive_init(void)
        if (!jive_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
-       jive_snd_devdata.dev = &jive_snd_device->dev;
+       platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
        ret = platform_device_add(jive_snd_device);
 
        if (ret)
index ffa954fe6931bea522fb02360b8f4877524884bb..abe64abe8c8423ad5f403532a9d40d8234d5b15b 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -33,23 +32,19 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "s3c-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name = "ac97-codec",
+       .platform_name = "s3c24xx-pcm-audio",
 },
 };
 
 static struct snd_soc_card ln2440sbc = {
        .name = "LN2440SBC",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = ln2440sbc_dai,
        .num_links = ARRAY_SIZE(ln2440sbc_dai),
 };
 
-static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
-       .card = &ln2440sbc,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *ln2440sbc_snd_ac97_device;
 
 static int __init ln2440sbc_init(void)
@@ -60,9 +55,7 @@ static int __init ln2440sbc_init(void)
        if (!ln2440sbc_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(ln2440sbc_snd_ac97_device,
-                               &ln2440sbc_snd_ac97_devdata);
-       ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+       platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
        ret = platform_device_add(ln2440sbc_snd_ac97_device);
 
        if (ret)
index 4719558289d402e20a410154ccbef239632c7ac9..e97bdf150a03042e34d231ddc507c5c33e79f95d 100644 (file)
@@ -41,8 +41,8 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int pll_out = 0, bclk = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -130,7 +130,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
 static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* disable the PLL */
        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
@@ -149,7 +149,7 @@ static int neo1973_gta02_voice_hw_params(
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pcmdiv = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -194,7 +194,7 @@ static int neo1973_gta02_voice_hw_params(
 static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* disable the PLL */
        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
@@ -262,7 +262,7 @@ static int lm4853_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k,
                        int event)
 {
-       gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value));
+       gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
 
        return 0;
 }
@@ -330,8 +330,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
  * This is an example machine initialisation for a wm8753 connected to a
  * neo1973 GTA02.
  */
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* set up NC codec pins */
@@ -378,9 +379,8 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
 /*
  * BT Codec DAI
  */
-static struct snd_soc_dai bt_dai = {
-       .name = "Bluetooth",
-       .id = 0,
+static struct snd_soc_dai_driver bt_dai = {
+       .name = "bluetooth-dai",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -397,32 +397,30 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
 { /* Hifi Playback - for similatious use with voice below */
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
-       .cpu_dai = &s3c24xx_i2s_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+       .cpu_dai_name = "s3c24xx-i2s",
+       .codec_dai_name = "wm8753-hifi",
        .init = neo1973_gta02_wm8753_init,
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8753-codec.0-0x1a",
        .ops = &neo1973_gta02_hifi_ops,
 },
 { /* Voice via BT */
        .name = "Bluetooth",
        .stream_name = "Voice",
-       .cpu_dai = &bt_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+       .cpu_dai_name = "bluetooth-dai",
+       .codec_dai_name = "wm8753-voice",
        .ops = &neo1973_gta02_voice_ops,
+       .codec_name = "wm8753-codec.0-0x1a",
+       .platform_name = "s3c24xx-pcm-audio",
 },
 };
 
 static struct snd_soc_card neo1973_gta02 = {
        .name = "neo1973-gta02",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = neo1973_gta02_dai,
        .num_links = ARRAY_SIZE(neo1973_gta02_dai),
 };
 
-static struct snd_soc_device neo1973_gta02_snd_devdata = {
-       .card = &neo1973_gta02,
-       .codec_dev = &soc_codec_dev_wm8753,
-};
-
 static struct platform_device *neo1973_gta02_snd_device;
 
 static int __init neo1973_gta02_init(void)
@@ -435,18 +433,18 @@ static int __init neo1973_gta02_init(void)
                return -ENODEV;
        }
 
-       /* register bluetooth DAI here */
-       ret = snd_soc_register_dai(&bt_dai);
-       if (ret)
-               return ret;
-
        neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
        if (!neo1973_gta02_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(neo1973_gta02_snd_device,
-                       &neo1973_gta02_snd_devdata);
-       neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
+       /* register bluetooth DAI here */
+       ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
+       if (ret) {
+               platform_device_put(neo1973_gta02_snd_device);
+               return ret;
+       }
+
+       platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
        ret = platform_device_add(neo1973_gta02_snd_device);
 
        if (ret) {
@@ -461,7 +459,7 @@ static int __init neo1973_gta02_init(void)
                goto err_unregister_device;
        }
 
-       ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
+       ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
        if (ret) {
                pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
                goto err_free_gpio_hp_in;
@@ -493,7 +491,7 @@ module_init(neo1973_gta02_init);
 
 static void __exit neo1973_gta02_exit(void)
 {
-       snd_soc_unregister_dai(&bt_dai);
+       snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
        platform_device_unregister(neo1973_gta02_snd_device);
        gpio_free(GTA02_GPIO_HP_IN);
        gpio_free(GTA02_GPIO_AMP_SHUT);
index 4ac620988e7c1d0894de39f7c39e6ba29e4dd0e2..f4f2ee731f0140123955c53c308ebf5071b39eea 100644 (file)
@@ -57,8 +57,8 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int pll_out = 0, bclk = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -147,7 +147,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
 static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -167,7 +167,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pcmdiv = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -213,7 +213,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -499,8 +499,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
  * neo1973 II. It is missing logic to detect hp/mic insertions and logic
  * to re-route the audio in such an event.
  */
-static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        pr_debug("Entered %s\n", __func__);
@@ -538,8 +539,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
  * BT Codec DAI
  */
 static struct snd_soc_dai bt_dai = {
-       .name = "Bluetooth",
-       .id = 0,
+       .name = "bluetooth-dai",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -556,32 +556,30 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Hifi Playback - for similatious use with voice below */
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
-       .cpu_dai = &s3c24xx_i2s_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+       .platform_name = "s3c24xx-pcm-audio",
+       .cpu_dai_name = "s3c24xx-i2s",
+       .codec_dai_name = "wm8753-hifi",
+       .codec_name = "wm8753-codec.0-0x1a",
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
 { /* Voice via BT */
        .name = "Bluetooth",
        .stream_name = "Voice",
-       .cpu_dai = &bt_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+       .platform_name = "s3c24xx-pcm-audio",
+       .cpu_dai_name = "bluetooth-dai",
+       .codec_dai_name = "wm8753-voice",
+       .codec_name = "wm8753-codec.0-0x1a",
        .ops = &neo1973_voice_ops,
 },
 };
 
 static struct snd_soc_card neo1973 = {
        .name = "neo1973",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = neo1973_dai,
        .num_links = ARRAY_SIZE(neo1973_dai),
 };
 
-static struct snd_soc_device neo1973_snd_devdata = {
-       .card = &neo1973,
-       .codec_dev = &soc_codec_dev_wm8753,
-};
-
 static int lm4857_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
@@ -673,8 +671,7 @@ static int __init neo1973_init(void)
        if (!neo1973_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
-       neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+       platform_set_drvdata(neo1973_snd_device, &neo1973);
        ret = platform_device_add(neo1973_snd_device);
 
        if (ret) {
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
new file mode 100644 (file)
index 0000000..ffd5cf2
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * rx1950.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *          Philipp Zabel <philipp.zabel@gmail.com>
+ *          Denis Grigoriev <dgreenday@gmail.com>
+ *          Vasily Khoruzhick <anarsoul@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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+static int rx1950_startup(struct snd_pcm_substream *substream);
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+       16000,
+       44100,
+       48000,
+       88200,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Speaker",
+               .mask   = SND_JACK_HEADPHONE,
+               .invert = 1,
+       },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+       [0] = {
+               .gpio                   = S3C2410_GPG(12),
+               .name                   = "hp-gpio",
+               .report                 = SND_JACK_HEADPHONE,
+               .invert                 = 1,
+               .debounce_time          = 200,
+       },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+       .startup        = rx1950_startup,
+       .hw_params      = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+       {
+               .name           = "uda1380",
+               .stream_name    = "UDA1380 Duplex",
+               .cpu_dai_name   = "s3c24xx-iis",
+               .codec_dai_name = "uda1380-hifi",
+               .init           = rx1950_uda1380_init,
+               .platform_name  = "s3c24xx-pcm-audio",
+               .codec_name     = "uda1380-codec.0-001a",
+               .ops            = &rx1950_ops,
+       },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+       .name = "rx1950",
+       .dai_link = rx1950_uda1380_dai,
+       .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* headphone connected to VOUTLHP, VOUTRHP */
+       {"Headphone Jack", NULL, "VOUTLHP"},
+       {"Headphone Jack", NULL, "VOUTRHP"},
+
+       /* ext speaker connected to VOUTL, VOUTR  */
+       {"Speaker", NULL, "VOUTL"},
+       {"Speaker", NULL, "VOUTR"},
+
+       /* mic is connected to VINM */
+       {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+static struct clk *xtal;
+
+static int rx1950_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.rate_min = hw_rates.list[0];
+       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+       return snd_pcm_hw_constraint_list(runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       &hw_rates);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(S3C2410_GPA(1), 1);
+       else
+               gpio_set_value(S3C2410_GPA(1), 0);
+
+       return 0;
+}
+
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int div;
+       int ret;
+       unsigned int rate = params_rate(params);
+       int clk_source, fs_mode;
+
+       switch (rate) {
+       case 16000:
+       case 48000:
+               clk_source = S3C24XX_CLKSRC_PCLK;
+               fs_mode = S3C2410_IISMOD_256FS;
+               div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+               if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+                       div++;
+               break;
+       case 44100:
+       case 88200:
+               clk_source = S3C24XX_CLKSRC_MPLL;
+               fs_mode = S3C2410_IISMOD_256FS;
+               div = clk_get_rate(xtal) / (256 * rate);
+               if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+                       div++;
+               break;
+       default:
+               printk(KERN_ERR "%s: rate %d is not supported\n",
+                       __func__, rate);
+               return -EINVAL;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* select clock source */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+                       SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               S3C2410_IISMOD_384FS);
+       if (ret < 0)
+               return ret;
+
+       /* set BCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+               S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(div, div));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int err;
+
+       /* Add rx1950 specific widgets */
+       err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+
+       if (err)
+               return err;
+
+       /* Set up rx1950 specific audio path audio_mapnects */
+       err = snd_soc_dapm_add_routes(codec, audio_map,
+                                     ARRAY_SIZE(audio_map));
+
+       if (err)
+               return err;
+
+       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       snd_soc_dapm_enable_pin(codec, "Speaker");
+
+       snd_soc_dapm_sync(codec);
+
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack);
+
+       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+               hp_jack_pins);
+
+       snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+
+       return 0;
+}
+
+static int __init rx1950_init(void)
+{
+       int ret;
+
+       if (!machine_is_rx1950())
+               return -ENODEV;
+
+       /* configure some gpios */
+       ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+       if (ret)
+               goto err_gpio;
+
+       ret = gpio_direction_output(S3C2410_GPA(1), 0);
+       if (ret)
+               goto err_gpio_conf;
+
+       s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!s3c24xx_snd_device) {
+               ret = -ENOMEM;
+               goto err_plat_alloc;
+       }
+
+       platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+       ret = platform_device_add(s3c24xx_snd_device);
+
+       if (ret) {
+               platform_device_put(s3c24xx_snd_device);
+               goto err_plat_add;
+       }
+
+       xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+       if (IS_ERR(xtal)) {
+               ret = PTR_ERR(xtal);
+               platform_device_unregister(s3c24xx_snd_device);
+               goto err_clk;
+       }
+
+       return 0;
+
+err_clk:
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+       gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+       return ret;
+}
+
+static void __exit rx1950_exit(void)
+{
+       platform_device_unregister(s3c24xx_snd_device);
+       snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+       clk_put(xtal);
+       gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
index 31f6d45b6384f2f0e0e4e5a351acc79a6f47520b..f891eb79b5754b19fd0dd443a09481cd2eb743b1 100644 (file)
@@ -89,7 +89,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to activate!");
+               pr_err("AC97: Unable to activate!");
 }
 
 static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -115,14 +115,15 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to read!");
+               pr_err("AC97: Unable to read!");
 
        stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
        addr = (stat >> 16) & 0x7f;
        data = (stat & 0xffff);
 
        if (addr != reg)
-               printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
+               pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
+                       reg, addr);
 
        mutex_unlock(&s3c_ac97.lock);
 
@@ -151,7 +152,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to write!");
+               pr_err("AC97: Unable to write!");
 
        ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
        ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
@@ -162,6 +163,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
 {
+       pr_debug("AC97: Cold reset\n");
        writel(S3C_AC97_GLBCTRL_COLDRESET,
                        s3c_ac97.regs + S3C_AC97_GLBCTRL);
        msleep(1);
@@ -178,6 +180,8 @@ static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
        if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
                return; /* Return if already active */
 
+       pr_debug("AC97: Warm reset\n");
+
        writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
        msleep(1);
 
@@ -222,7 +226,7 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct s3c_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -241,7 +245,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        u32 ac_glbctrl;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -277,7 +281,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                                      struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
@@ -293,7 +297,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
        u32 ac_glbctrl;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
        ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
@@ -328,10 +332,9 @@ static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
        .trigger        = s3c_ac97_mic_trigger,
 };
 
-struct snd_soc_dai s3c_ac97_dai[] = {
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
        [S3C_AC97_DAI_PCM] = {
                .name = "s3c-ac97",
-               .id = S3C_AC97_DAI_PCM,
                .ac97_control = 1,
                .playback = {
                        .stream_name = "AC97 Playback",
@@ -349,7 +352,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
        },
        [S3C_AC97_DAI_MIC] = {
                .name = "s3c-ac97-mic",
-               .id = S3C_AC97_DAI_MIC,
                .ac97_control = 1,
                .capture = {
                        .stream_name = "AC97 Mic Capture",
@@ -360,7 +362,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
                .ops = &s3c_ac97_mic_dai_ops,
        },
 };
-EXPORT_SYMBOL_GPL(s3c_ac97_dai);
 
 static __devinit int s3c_ac97_probe(struct platform_device *pdev)
 {
@@ -445,14 +446,12 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev)
        ret = request_irq(irq_res->start, s3c_ac97_irq,
                                        IRQF_DISABLED, "AC97", NULL);
        if (ret < 0) {
-               printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
+               dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
                goto err4;
        }
 
-       s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
-       s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
-
-       ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+                       ARRAY_SIZE(s3c_ac97_dai));
        if (ret)
                goto err5;
 
@@ -476,7 +475,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev)
 {
        struct resource *mem_res, *irq_res;
 
-       snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq_res)
@@ -518,3 +517,4 @@ module_exit(s3c_ac97_exit);
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-ac97");
index 278198379defa343fcaf905b99e03d897a8b3272..5dcedd07fdbbfdbfaab687e4fa4bea4dce6f9d04 100644 (file)
@@ -18,6 +18,4 @@
 #define S3C_AC97_DAI_PCM 0
 #define S3C_AC97_DAI_MIC 1
 
-extern struct snd_soc_dai s3c_ac97_dai[];
-
 #endif /* __S3C_AC97_H_ */
index f1b1bc4bacfb7134d588469cbcd0b5032747f0ae..243f79bf43bb127fabffa4474db175f4d297ea29 100644 (file)
@@ -146,7 +146,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        unsigned long totbytes = params_buffer_bytes(params);
        struct s3c_dma_params *dma =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        int ret = 0;
 
 
@@ -440,14 +440,14 @@ static int s3c_dma_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -457,26 +457,46 @@ static int s3c_dma_new(struct snd_card *card,
        return ret;
 }
 
-struct snd_soc_platform s3c24xx_soc_platform = {
-       .name           = "s3c24xx-audio",
-       .pcm_ops        = &s3c_dma_ops,
+static struct snd_soc_platform_driver s3c24xx_soc_platform = {
+       .ops            = &s3c_dma_ops,
        .pcm_new        = s3c_dma_new,
        .pcm_free       = s3c_dma_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
 
-static int __init s3c24xx_soc_platform_init(void)
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&s3c24xx_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
 }
-module_init(s3c24xx_soc_platform_init);
 
-static void __exit s3c24xx_soc_platform_exit(void)
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&s3c24xx_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s3c24xx_pcm_driver = {
+       .driver = {
+               .name = "s3c24xx-pcm-audio",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = s3c24xx_soc_platform_probe,
+       .remove = __devexit_p(s3c24xx_soc_platform_remove),
+};
+
+static int __init snd_s3c24xx_pcm_init(void)
+{
+       return platform_driver_register(&s3c24xx_pcm_driver);
+}
+module_init(snd_s3c24xx_pcm_init);
+
+static void __exit snd_s3c24xx_pcm_exit(void)
+{
+       platform_driver_unregister(&s3c24xx_pcm_driver);
 }
-module_exit(s3c24xx_soc_platform_exit);
+module_exit(snd_s3c24xx_pcm_exit);
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-pcm-audio");
index 69bb6bf6fc1c2a99a475313375a56969310b6f35..748c07d7c07578206cee11fff74be10be476814c 100644 (file)
@@ -25,7 +25,6 @@ struct s3c_dma_params {
 #define S3C24XX_DAI_I2S                        0
 
 /* platform data */
-extern struct snd_soc_platform s3c24xx_soc_platform;
 extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
 
 #endif
index 64376b2aac73ce8854daa3226368aee7e59ae223..b3866d5b19e95abb379df36b25692a4615af3dc4 100644 (file)
@@ -49,7 +49,7 @@
 
 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
 {
-       return cpu_dai->private_data;
+       return snd_soc_dai_get_drvdata(cpu_dai);
 }
 
 #define bit_set(v, b) (((v) & (b)) ? 1 : 0)
@@ -307,11 +307,9 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 
 static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *socdai)
+                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai = rtd->dai;
-       struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+       struct s3c_i2sv2_info *i2s = to_info(dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -322,7 +320,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = i2s->dma_capture;
 
-       snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
 
        /* Working copies of register */
        iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -396,12 +394,12 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+       struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
        int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
        unsigned long irqs;
        int ret = 0;
        struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        pr_debug("Entered %s\n", __func__);
 
@@ -640,36 +638,17 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 }
 EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
 
-int s3c_i2sv2_probe(struct platform_device *pdev,
-                   struct snd_soc_dai *dai,
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
                    struct s3c_i2sv2_info *i2s,
                    unsigned long base)
 {
-       struct device *dev = &pdev->dev;
+       struct device *dev = dai->dev;
        unsigned int iismod;
 
        i2s->dev = dev;
 
        /* record our i2s structure for later use in the callbacks */
-       dai->private_data = i2s;
-
-       if (!base) {
-               struct resource *res = platform_get_resource(pdev,
-                                                            IORESOURCE_MEM,
-                                                            0);
-               if (!res) {
-                       dev_err(dev, "Unable to get register resource\n");
-                       return -ENXIO;
-               }
-
-               if (!request_mem_region(res->start, resource_size(res),
-                                       "s3c64xx-i2s-v4")) {
-                       dev_err(dev, "Unable to request register region\n");
-                       return -EBUSY;
-               }
-
-               base = res->start;
-       }
+       snd_soc_dai_set_drvdata(dai, i2s);
 
        i2s->regs = ioremap(base, 0x100);
        if (i2s->regs == NULL) {
@@ -752,9 +731,10 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #define s3c2412_i2s_resume  NULL
 #endif
 
-int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+               struct snd_soc_dai_driver *drv)
 {
-       struct snd_soc_dai_ops *ops = dai->ops;
+       struct snd_soc_dai_ops *ops = drv->ops;
 
        ops->trigger = s3c2412_i2s_trigger;
        if (!ops->hw_params)
@@ -767,10 +747,10 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
        if (!ops->delay)
                ops->delay = s3c2412_i2s_delay;
 
-       dai->suspend = s3c2412_i2s_suspend;
-       dai->resume = s3c2412_i2s_resume;
+       drv->suspend = s3c2412_i2s_suspend;
+       drv->resume = s3c2412_i2s_resume;
 
-       return snd_soc_register_dai(dai);
+       return snd_soc_register_dai(dev, drv);
 }
 EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
 
index 766f43a13d8be29fe769b860fc71e2b120b93aa7..d45830151484a62610baa69a9c32e3580f2cfeef 100644 (file)
@@ -66,6 +66,8 @@ struct s3c_i2sv2_info {
        u32              suspend_iismod;
        u32              suspend_iiscon;
        u32              suspend_iispsr;
+
+       unsigned long   base;
 };
 
 extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
@@ -81,23 +83,24 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 
 /**
  * s3c_i2sv2_probe - probe for i2s device helper
- * @pdev: The platform device supplied to the original probe.
  * @dai: The ASoC DAI structure supplied to the original probe.
  * @i2s: Our local i2s structure to fill in.
  * @base: The base address for the registers.
  */
-extern int s3c_i2sv2_probe(struct platform_device *pdev,
-                          struct snd_soc_dai *dai,
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
                           struct s3c_i2sv2_info *i2s,
                           unsigned long base);
 
 /**
  * s3c_i2sv2_register_dai - register dai with soc core
- * @dai: The snd_soc_dai structure to register
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
  *
  * Fill in any missing fields and then register the given dai with the
  * soc core.
  */
-extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+               struct snd_soc_dai_driver *drv);
 
 #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
index 326f0a9e7e3076ebbce6af2500c86cb56fce5f60..2e020e1b4eab027640a0e92b4f0506305c0297f9 100644 (file)
@@ -64,11 +64,6 @@ static struct s3c_dma_params s3c_pcm_stereo_in[] = {
 
 static struct s3c_pcm_info s3c_pcm[2];
 
-static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return cpu_dai->private_data;
-}
-
 static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
 {
        void __iomem *regs = pcm->regs;
@@ -83,7 +78,7 @@ static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
                ctl |= S3C_PCM_CTL_TXDMA_EN;
                ctl |= S3C_PCM_CTL_TXFIFO_EN;
                ctl |= S3C_PCM_CTL_ENABLE;
-               ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+               ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
                clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
        } else {
                ctl &= ~S3C_PCM_CTL_TXDMA_EN;
@@ -107,11 +102,14 @@ static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
 
        ctl = readl(regs + S3C_PCM_CTL);
        clkctl = readl(regs + S3C_PCM_CLKCTL);
+       ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+                        << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
 
        if (on) {
                ctl |= S3C_PCM_CTL_RXDMA_EN;
                ctl |= S3C_PCM_CTL_RXFIFO_EN;
                ctl |= S3C_PCM_CTL_ENABLE;
+               ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
                clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
        } else {
                ctl &= ~S3C_PCM_CTL_RXDMA_EN;
@@ -132,7 +130,7 @@ static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        unsigned long flags;
 
        dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -176,8 +174,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *socdai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai = rtd->dai;
-       struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct s3c_dma_params *dma_data;
        void __iomem *regs = pcm->regs;
        struct clk *clk;
@@ -192,7 +189,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = pcm->dma_capture;
 
-       snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
 
        /* Strictly check for sample size */
        switch (params_format(params)) {
@@ -242,7 +239,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
 static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
                               unsigned int fmt)
 {
-       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *regs = pcm->regs;
        unsigned long flags;
        int ret = 0;
@@ -313,7 +310,7 @@ exit:
 static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                                int div_id, int div)
 {
-       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
 
        switch (div_id) {
        case S3C_PCM_SCLK_PER_FS:
@@ -330,7 +327,7 @@ static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
 static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
                                  int clk_id, unsigned int freq, int dir)
 {
-       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *regs = pcm->regs;
        u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
 
@@ -366,10 +363,7 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
 
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
-#define S3C_PCM_DECLARE(n)                     \
-{                                                              \
-       .name            = "samsung-pcm",                       \
-       .id              = (n),                         \
+#define S3C_PCM_DAI_DECLARE                    \
        .symmetric_rates = 1,                                   \
        .ops = &s3c_pcm_dai_ops,                                \
        .playback = {                                           \
@@ -383,19 +377,23 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
                .channels_max   = 2,                            \
                .rates          = S3C_PCM_RATES,                \
                .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
-       },                                                      \
-}
+       }
 
-struct snd_soc_dai s3c_pcm_dai[] = {
-       S3C_PCM_DECLARE(0),
-       S3C_PCM_DECLARE(1),
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+       [0] = {
+               .name   = "samsung-pcm.0",
+               S3C_PCM_DAI_DECLARE,
+       },
+       [1] = {
+               .name   = "samsung-pcm.1",
+               S3C_PCM_DAI_DECLARE,
+       },
 };
 EXPORT_SYMBOL_GPL(s3c_pcm_dai);
 
 static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
        struct s3c_pcm_info *pcm;
-       struct snd_soc_dai *dai;
        struct resource *mem_res, *dmatx_res, *dmarx_res;
        struct s3c_audio_pdata *pcm_pdata;
        int ret;
@@ -437,9 +435,6 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
 
        spin_lock_init(&pcm->lock);
 
-       dai = &s3c_pcm_dai[pdev->id];
-       dai->dev = &pdev->dev;
-
        /* Default is 128fs */
        pcm->sclk_per_fs = 128;
 
@@ -452,7 +447,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        clk_enable(pcm->cclk);
 
        /* record our pcm structure for later use in the callbacks */
-       dai->private_data = pcm;
+       dev_set_drvdata(&pdev->dev, pcm);
 
        if (!request_mem_region(mem_res->start,
                                resource_size(mem_res), "samsung-pcm")) {
@@ -476,7 +471,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        }
        clk_enable(pcm->pclk);
 
-       ret = snd_soc_register_dai(dai);
+       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to get pcm_clock\n");
                goto err5;
@@ -514,6 +509,8 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
        struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
        struct resource *mem_res;
 
+       snd_soc_unregister_dai(&pdev->dev);
+
        iounmap(pcm->regs);
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,3 +549,4 @@ module_exit(s3c_pcm_exit);
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("S3C PCM Controller Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
index 69ff9971692f8cfa4a5831f8b8f8b5e98e5da58d..f60baa19387d914551b1bb38daf75fb782e2faff 100644 (file)
@@ -22,7 +22,8 @@
 /* PCM_CTL Bit-Fields */
 #define S3C_PCM_CTL_TXDIPSTICK_MASK            (0x3f)
 #define S3C_PCM_CTL_TXDIPSTICK_SHIFT   (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MSK             (0x3f<<7)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK            (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT   (7)
 #define S3C_PCM_CTL_TXDMA_EN           (0x1<<6)
 #define S3C_PCM_CTL_RXDMA_EN           (0x1<<5)
 #define S3C_PCM_CTL_TXMSB_AFTER_FSYNC  (0x1<<4)
index 709adef9d0435554a78cfa082fd31d4475d145a3..4a861cfa52c5643852d2612028d3c1d71ffe7d5d 100644 (file)
@@ -65,26 +65,20 @@ static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
 
 static struct s3c_i2sv2_info s3c2412_i2s;
 
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return cpu_dai->private_data;
-}
-
-static int s3c2412_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
 {
        int ret;
 
        pr_debug("Entered %s\n", __func__);
 
-       ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+       ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
        if (ret)
                return ret;
 
        s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
        s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
 
-       s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
+       s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
        if (s3c2412_i2s.iis_cclk == NULL) {
                pr_err("failed to get i2sclk clock\n");
                iounmap(s3c2412_i2s.regs);
@@ -108,11 +102,20 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
        return 0;
 }
 
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+       clk_disable(s3c2412_i2s.iis_cclk);
+       clk_put(s3c2412_i2s.iis_cclk);
+       iounmap(s3c2412_i2s.regs);
+
+       return 0;
+}
+
 static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -152,10 +155,9 @@ static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
        .hw_params      = s3c2412_i2s_hw_params,
 };
 
-struct snd_soc_dai s3c2412_i2s_dai = {
-       .name           = "s3c2412-i2s",
-       .id             = 0,
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
        .probe          = s3c2412_i2s_probe,
+       .remove = s3c2412_i2s_remove,
        .playback = {
                .channels_min   = 2,
                .channels_max   = 2,
@@ -170,17 +172,36 @@ struct snd_soc_dai s3c2412_i2s_dai = {
        },
        .ops = &s3c2412_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+       .probe  = s3c2412_iis_dev_probe,
+       .remove = s3c2412_iis_dev_remove,
+       .driver = {
+               .name = "s3c2412-iis",
+               .owner = THIS_MODULE,
+       },
+};
 
 static int __init s3c2412_i2s_init(void)
 {
-       return  s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
+       return platform_driver_register(&s3c2412_iis_driver);
 }
 module_init(s3c2412_i2s_init);
 
 static void __exit s3c2412_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&s3c2412_i2s_dai);
+       platform_driver_unregister(&s3c2412_iis_driver);
 }
 module_exit(s3c2412_i2s_exit);
 
@@ -188,3 +209,4 @@ module_exit(s3c2412_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
index 0b5686b4d5c36fb4c307132b6c654017dd583657..01a0471ac65c88ac79622ec96f653f4fe24aa67a 100644 (file)
@@ -24,6 +24,4 @@
 #define S3C2412_CLKSRC_PCLK    S3C_I2SV2_CLKSRC_PCLK
 #define S3C2412_CLKSRC_I2SCLK  S3C_I2SV2_CLKSRC_AUDIOBUS
 
-extern struct snd_soc_dai s3c2412_i2s_dai;
-
 #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
index c3ac890a3986184f86ed00a1dc300fdb10d7d258..e060daaa458f80bf63ecacfb25731fbb93c497e3 100644 (file)
@@ -252,7 +252,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = &s3c24xx_i2s_pcm_stereo_in;
 
-       snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
 
        /* Working copies of register */
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -280,9 +280,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
        int ret = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(dai, substream);
 
        pr_debug("Entered %s\n", __func__);
 
@@ -387,8 +386,7 @@ u32 s3c24xx_i2s_get_clockrate(void)
 }
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 
-static int s3c24xx_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 {
        pr_debug("Entered %s\n", __func__);
 
@@ -396,7 +394,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
        if (s3c24xx_i2s.regs == NULL)
                return -ENXIO;
 
-       s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
+       s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
        if (s3c24xx_i2s.iis_clk == NULL) {
                pr_err("failed to get iis_clock\n");
                iounmap(s3c24xx_i2s.regs);
@@ -465,9 +463,7 @@ static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
        .set_sysclk     = s3c24xx_i2s_set_sysclk,
 };
 
-struct snd_soc_dai s3c24xx_i2s_dai = {
-       .name = "s3c24xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
        .probe = s3c24xx_i2s_probe,
        .suspend = s3c24xx_i2s_suspend,
        .resume = s3c24xx_i2s_resume,
@@ -483,17 +479,36 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
                .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &s3c24xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+       .probe  = s3c24xx_iis_dev_probe,
+       .remove = s3c24xx_iis_dev_remove,
+       .driver = {
+               .name = "s3c24xx-iis",
+               .owner = THIS_MODULE,
+       },
+};
 
 static int __init s3c24xx_i2s_init(void)
 {
-       return snd_soc_register_dai(&s3c24xx_i2s_dai);
+       return platform_driver_register(&s3c24xx_iis_driver);
 }
 module_init(s3c24xx_i2s_init);
 
 static void __exit s3c24xx_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+       platform_driver_unregister(&s3c24xx_iis_driver);
 }
 module_exit(s3c24xx_i2s_exit);
 
@@ -501,3 +516,4 @@ module_exit(s3c24xx_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
index 726d91cf4e1cfcbf624facdf7c0a697962bab190..f9ca04edacb7a4283a17bb2105b4d750478644ce 100644 (file)
@@ -32,6 +32,4 @@
 
 u32 s3c24xx_i2s_get_clockrate(void);
 
-extern struct snd_soc_dai s3c24xx_i2s_dai;
-
 #endif /*S3C24XXI2S_H_*/
index 4984754f3298dac412f9ee22dfbce4de5f5804f8..c4c1114420109944bdbf73cdeda17083a054e5e7 100644 (file)
@@ -139,8 +139,10 @@ static const struct snd_kcontrol_new amp_unmute_controls[] = {
                       speaker_unmute_get, speaker_unmute_put),
 };
 
-void simtec_audio_init(struct snd_soc_codec *codec)
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        if (pdata->amp_gpio > 0) {
                pr_debug("%s: adding amp routes\n", __func__);
 
@@ -170,8 +172,8 @@ static int simtec_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set the CODEC as the bus clock master, I2S */
@@ -319,12 +321,12 @@ EXPORT_SYMBOL_GPL(simtec_audio_pmops);
 #endif
 
 int __devinit simtec_audio_core_probe(struct platform_device *pdev,
-                                     struct snd_soc_device *socdev)
+                                     struct snd_soc_card *card)
 {
        struct platform_device *snd_dev;
        int ret;
 
-       socdev->card->dai_link->ops = &simtec_snd_ops;
+       card->dai_link->ops = &simtec_snd_ops;
 
        pdata = pdev->dev.platform_data;
        if (!pdata) {
@@ -353,8 +355,7 @@ int __devinit simtec_audio_core_probe(struct platform_device *pdev,
                goto err_gpio;
        }
 
-       platform_set_drvdata(snd_dev, socdev);
-       socdev->dev = &snd_dev->dev;
+       platform_set_drvdata(snd_dev, card);
 
        ret = platform_device_add(snd_dev);
        if (ret) {
index e18faee30cce0a388b2d06d2ba9a676200117d16..e63d5ff9c41fe4a42c64a6ea3b3960bf3046e14d 100644 (file)
@@ -7,10 +7,10 @@
  * published by the Free Software Foundation.
 */
 
-extern void simtec_audio_init(struct snd_soc_codec *codec);
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
 
 extern int simtec_audio_core_probe(struct platform_device *pdev,
-                                  struct snd_soc_device *socdev);
+                                  struct snd_soc_card *card);
 
 extern int simtec_audio_remove(struct platform_device *pdev);
 
index bdf8951af8e38fac1a7e88ff8be274ce4e7e1815..f88453735ae26e47c98f1c407c789df24227d638 100644 (file)
@@ -73,8 +73,10 @@ static const struct snd_soc_dapm_route base_map[] = {
  * Attach our controls and configure the necessary codec
  * mappings for our sound card instance.
 */
-static int simtec_hermes_init(struct snd_soc_codec *codec)
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, dapm_widgets,
                                  ARRAY_SIZE(dapm_widgets));
 
@@ -85,42 +87,33 @@ static int simtec_hermes_init(struct snd_soc_codec *codec)
        snd_soc_dapm_enable_pin(codec, "Line Out");
        snd_soc_dapm_enable_pin(codec, "Mic Jack");
 
-       simtec_audio_init(codec);
+       simtec_audio_init(rtd);
        snd_soc_dapm_sync(codec);
 
        return 0;
 }
 
-static struct aic3x_setup_data codec_setup = {
-};
-
 static struct snd_soc_dai_link simtec_dai_aic33 = {
        .name           = "tlv320aic33",
        .stream_name    = "TLV320AIC33",
-       .cpu_dai        = &s3c24xx_i2s_dai,
-       .codec_dai      = &aic3x_dai,
+       .codec_name     = "tlv320aic3x-codec.0-0x1a",
+       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name  = "s3c24xx-pcm-audio",
        .init           = simtec_hermes_init,
 };
 
 /* simtec audio machine driver */
 static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
        .name           = "Simtec-Hermes",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &simtec_dai_aic33,
        .num_links      = 1,
 };
 
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic33 = {
-       .card           = &snd_soc_machine_simtec_aic33,
-       .codec_dev      = &soc_codec_dev_aic3x,
-       .codec_data     = &codec_setup,
-};
-
 static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
 {
        dev_info(&pd->dev, "probing....\n");
-       return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33);
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
 }
 
 static struct platform_driver simtec_audio_hermes_platdrv = {
index 185c0acb5ce6b8f7fff39c3fd008477ad4c6d11e..c0967593510d1f294d63ae23581d1e4cb1bf54fb 100644 (file)
@@ -62,8 +62,10 @@ static const struct snd_soc_dapm_route base_map[] = {
  * Attach our controls and configure the necessary codec
  * mappings for our sound card instance.
 */
-static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, dapm_widgets,
                                  ARRAY_SIZE(dapm_widgets));
 
@@ -74,7 +76,7 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
        snd_soc_dapm_enable_pin(codec, "Line Out");
        snd_soc_dapm_enable_pin(codec, "Mic Jack");
 
-       simtec_audio_init(codec);
+       simtec_audio_init(rtd);
        snd_soc_dapm_sync(codec);
 
        return 0;
@@ -83,28 +85,23 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link simtec_dai_aic23 = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .cpu_dai        = &s3c24xx_i2s_dai,
-       .codec_dai      = &tlv320aic23_dai,
+       .codec_name     = "tlv320aic3x-codec.0-0x1a",
+       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name  = "s3c24xx-pcm-audio",
        .init           = simtec_tlv320aic23_init,
 };
 
 /* simtec audio machine driver */
 static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
        .name           = "Simtec",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &simtec_dai_aic23,
        .num_links      = 1,
 };
 
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic23 = {
-       .card           = &snd_soc_machine_simtec_aic23,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
 {
-       return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23);
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
 }
 
 static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
index 052d59659c296f2916261970ae9f4ff675b7a5cf..bd48ffbde8801701b2c5c18deb20b2e28457c697 100644 (file)
@@ -133,8 +133,8 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
        int clk_source, fs_mode;
@@ -227,14 +227,15 @@ static struct snd_soc_ops s3c24xx_uda134x_ops = {
 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .name = "UDA134X",
        .stream_name = "UDA134X",
-       .codec_dai = &uda134x_dai,
-       .cpu_dai = &s3c24xx_i2s_dai,
+       .codec_name = "uda134x-hifi",
+       .codec_dai_name = "uda134x-hifi",
+       .cpu_dai_name = "s3c24xx-i2s",
        .ops = &s3c24xx_uda134x_ops,
+       .platform_name  = "s3c24xx-pcm-audio",
 };
 
 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
        .name = "S3C24XX_UDA134X",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = &s3c24xx_uda134x_dai_link,
        .num_links = 1,
 };
@@ -256,6 +257,7 @@ static void setmode(int v)
        gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
 }
 
+/* FIXME - This must be codec platform data but in which board file ?? */
 static struct uda134x_platform_data s3c24xx_uda134x = {
        .l3 = {
                .setdat = setdat,
@@ -270,12 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = {
        },
 };
 
-static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
-       .card = &snd_soc_s3c24xx_uda134x,
-       .codec_dev = &soc_codec_dev_uda134x,
-       .codec_data = &s3c24xx_uda134x,
-};
-
 static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
 {
        if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
@@ -325,8 +321,7 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(s3c24xx_uda134x_snd_device,
-                            &s3c24xx_uda134x_snd_devdata);
-       s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+                            &snd_soc_s3c24xx_uda134x);
        ret = platform_device_add(s3c24xx_uda134x_snd_device);
        if (ret) {
                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
index 06db130030a13f8ce7326a6411f3b77e6209bc31..a9628472ebfe7ff4cff26991b1bcdf13d51d4742 100644 (file)
@@ -16,9 +16,7 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-h.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
 
 #include <mach/map.h>
 #include <mach/dma.h>
@@ -39,34 +37,23 @@ static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
 static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
 static struct s3c_i2sv2_info s3c64xx_i2sv4;
 
-struct snd_soc_dai s3c64xx_i2s_v4_dai;
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
 {
-       return cpu_dai->private_data;
-}
+       struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+       int ret = 0;
 
-static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
-{
-       /* configure GPIO for i2s port */
-       s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
-       s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
-       s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
-       s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+       snd_soc_dai_set_drvdata(dai, i2s);
 
-       return 0;
+       ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+
+       return ret;
 }
 
 static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -104,51 +91,79 @@ static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
        .hw_params      = s3c_i2sv4_hw_params,
 };
 
+static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
+       .symmetric_rates = 1,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,
+       },
+       .probe = s3c64xx_i2sv4_probe,
+       .ops = &s3c64xx_i2sv4_dai_ops,
+};
+
 static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
 {
+       struct s3c_audio_pdata *i2s_pdata;
        struct s3c_i2sv2_info *i2s;
-       struct snd_soc_dai *dai;
+       struct resource *res;
        int ret;
 
        i2s = &s3c64xx_i2sv4;
-       dai = &s3c64xx_i2s_v4_dai;
-
-       if (dai->dev) {
-               dev_dbg(dai->dev, "%s: \
-                       I2Sv4 instance already registered!\n", __func__);
-               return -EBUSY;
-       }
-
-       dai->dev = &pdev->dev;
-       dai->name = "s3c64xx-i2s-v4";
-       dai->id = 0;
-       dai->symmetric_rates = 1;
-       dai->playback.channels_min = 2;
-       dai->playback.channels_max = 2;
-       dai->playback.rates = S3C64XX_I2S_RATES;
-       dai->playback.formats = S3C64XX_I2S_FMTS;
-       dai->capture.channels_min = 2;
-       dai->capture.channels_max = 2;
-       dai->capture.rates = S3C64XX_I2S_RATES;
-       dai->capture.formats = S3C64XX_I2S_FMTS;
-       dai->probe = s3c64xx_i2sv4_probe;
-       dai->ops = &s3c64xx_i2sv4_dai_ops;
 
        i2s->feature |= S3C_FEATURE_CDCLKCON;
 
        i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
        i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
 
-       i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
-       i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
-       i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
-       i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+               return -ENXIO;
+       }
+       i2s->dma_playback->channel = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+               return -ENXIO;
+       }
+       i2s->dma_capture->channel = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+               return -ENXIO;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res),
+                               "s3c64xx-i2s-v4")) {
+               dev_err(&pdev->dev, "Unable to request SFR region\n");
+               return -EBUSY;
+       }
+       i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+       i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
 
        i2s->dma_capture->client = &s3c64xx_dma_client_in;
        i2s->dma_capture->dma_size = 4;
        i2s->dma_playback->client = &s3c64xx_dma_client_out;
        i2s->dma_playback->dma_size = 4;
 
+       i2s->base = res->start;
+
+       i2s_pdata = pdev->dev.platform_data;
+       if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               return -EINVAL;
+       }
+
        i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
        if (IS_ERR(i2s->iis_cclk)) {
                dev_err(&pdev->dev, "failed to get audio-bus\n");
@@ -158,19 +173,13 @@ static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
 
        clk_enable(i2s->iis_cclk);
 
-       ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
-       if (ret)
-               goto err_clk;
-
-       ret = s3c_i2sv2_register_dai(dai);
+       ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
        if (ret != 0)
                goto err_i2sv2;
 
        return 0;
 
 err_i2sv2:
-       /* Not implemented for I2Sv2 core yet */
-err_clk:
        clk_put(i2s->iis_cclk);
 err:
        return ret;
@@ -178,7 +187,18 @@ err:
 
 static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
 {
-       dev_err(&pdev->dev, "Device removal not yet supported\n");
+       struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+       struct resource *res;
+
+       snd_soc_unregister_dai(&pdev->dev);
+       clk_put(i2s->iis_cclk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               release_mem_region(res->start, resource_size(res));
+       else
+               dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
+               
        return 0;
 }
 
@@ -207,3 +227,4 @@ module_exit(s3c64xx_i2sv4_exit);
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis-v4");
index 1d85cb85a7d2f1cd1a6f58a52dd8e9717f147fe9..ae7acb6c4f1d5fe6cb6b6808eb8ab177f80b9de9 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <sound/soc.h>
 
-#include <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
 
 #include <mach/map.h>
 #include <mach/dma.h>
@@ -46,45 +46,107 @@ static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
 static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
 static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
 
-struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
 {
-       return cpu_dai->private_data;
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+       if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+               return i2s->iis_cclk;
+       else
+               return i2s->iis_pclk;
 }
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
 
-static int s3c64xx_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
 {
-       /* configure GPIO for i2s port */
-       switch (dai->id) {
-       case 0:
-               s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
-               s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
-               break;
-       case 1:
-               s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
-               s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+       struct s3c_i2sv2_info *i2s;
+       int ret;
+
+       if (dai->id >= MAX_I2SV3) {
+               dev_err(dai->dev, "id %d out of range\n", dai->id);
+               return -EINVAL;
+       }
+
+       i2s = &s3c64xx_i2s[dai->id];
+       snd_soc_dai_set_drvdata(dai, i2s);
+
+       i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
+       if (IS_ERR(i2s->iis_cclk)) {
+               dev_err(dai->dev, "failed to get audio-bus\n");
+               ret = PTR_ERR(i2s->iis_cclk);
+               goto err;
        }
 
+       clk_enable(i2s->iis_cclk);
+
+       ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+       if (ret)
+               goto err_clk;
+
        return 0;
+
+err_clk:
+       clk_disable(i2s->iis_cclk);
+       clk_put(i2s->iis_cclk);
+err:
+       kfree(i2s);
+       return ret;
 }
 
+static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable(i2s->iis_cclk);
+       clk_put(i2s->iis_cclk);
+       kfree(i2s);
+       return 0;
+}
 
 static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
 
+static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
+{
+       .name = "s3c64xx-i2s-0",
+       .probe = s3c64xx_i2s_probe,
+       .remove = s3c64xx_i2s_remove,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,},
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,},
+       .ops = &s3c64xx_i2s_dai_ops,
+       .symmetric_rates = 1,
+}, {
+       .name = "s3c64xx-i2s-1",
+       .probe = s3c64xx_i2s_probe,
+       .remove = s3c64xx_i2s_remove,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,},
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C64XX_I2S_RATES,
+               .formats = S3C64XX_I2S_FMTS,},
+       .ops = &s3c64xx_i2s_dai_ops,
+       .symmetric_rates = 1,
+},};
+
 static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
 {
+       struct s3c_audio_pdata *i2s_pdata;
        struct s3c_i2sv2_info *i2s;
-       struct snd_soc_dai *dai;
-       int ret;
+       struct resource *res;
+       int i, ret;
 
        if (pdev->id >= MAX_I2SV3) {
                dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
@@ -92,74 +154,63 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
        }
 
        i2s = &s3c64xx_i2s[pdev->id];
-       dai = &s3c64xx_i2s_dai[pdev->id];
-       dai->dev = &pdev->dev;
-       dai->name = "s3c64xx-i2s";
-       dai->id = pdev->id;
-       dai->symmetric_rates = 1;
-       dai->playback.channels_min = 2;
-       dai->playback.channels_max = 2;
-       dai->playback.rates = S3C64XX_I2S_RATES;
-       dai->playback.formats = S3C64XX_I2S_FMTS;
-       dai->capture.channels_min = 2;
-       dai->capture.channels_max = 2;
-       dai->capture.rates = S3C64XX_I2S_RATES;
-       dai->capture.formats = S3C64XX_I2S_FMTS;
-       dai->probe = s3c64xx_i2s_probe;
-       dai->ops = &s3c64xx_i2s_dai_ops;
-
-       i2s->feature |= S3C_FEATURE_CDCLKCON;
 
        i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
        i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
 
-       if (pdev->id == 0) {
-               i2s->dma_capture->channel = DMACH_I2S0_IN;
-               i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
-               i2s->dma_playback->channel = DMACH_I2S0_OUT;
-               i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
-       } else {
-               i2s->dma_capture->channel = DMACH_I2S1_IN;
-               i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
-               i2s->dma_playback->channel = DMACH_I2S1_OUT;
-               i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+               return -ENXIO;
+       }
+       i2s->dma_playback->channel = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+               return -ENXIO;
+       }
+       i2s->dma_capture->channel = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+               return -ENXIO;
        }
 
+       if (!request_mem_region(res->start, resource_size(res),
+                               "s3c64xx-i2s")) {
+               dev_err(&pdev->dev, "Unable to request SFR region\n");
+               return -EBUSY;
+       }
+       i2s->base = res->start;
+
+       i2s_pdata = pdev->dev.platform_data;
+       if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               return -EINVAL;
+       }
+       i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+       i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
+
        i2s->dma_capture->client = &s3c64xx_dma_client_in;
        i2s->dma_capture->dma_size = 4;
        i2s->dma_playback->client = &s3c64xx_dma_client_out;
        i2s->dma_playback->dma_size = 4;
 
-       i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
-       if (IS_ERR(i2s->iis_cclk)) {
-               dev_err(&pdev->dev, "failed to get audio-bus\n");
-               ret = PTR_ERR(i2s->iis_cclk);
-               goto err;
+       for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
+               ret = s3c_i2sv2_register_dai(&pdev->dev, i,
+                                               &s3c64xx_i2s_dai[i]);
+               if (ret != 0)
+                       return ret;
        }
 
-       clk_enable(i2s->iis_cclk);
-
-       ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
-       if (ret)
-               goto err_clk;
-
-       ret = s3c_i2sv2_register_dai(dai);
-       if (ret != 0)
-               goto err_i2sv2;
-
        return 0;
-
-err_i2sv2:
-       /* Not implemented for I2Sv2 core yet */
-err_clk:
-       clk_put(i2s->iis_cclk);
-err:
-       return ret;
 }
 
 static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
 {
-       dev_err(&pdev->dev, "Device removal not yet supported\n");
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
        return 0;
 }
 
@@ -188,3 +239,4 @@ module_exit(s3c64xx_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis");
index 7a40f43d1d5144a6afc6faa95176928cd56096fa..de4075d26f0cb48c48bc1e37161bc689c0de5607 100644 (file)
@@ -36,7 +36,6 @@ struct clk;
        (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
         SNDRV_PCM_FMTBIT_S24_LE)
 
-extern struct snd_soc_dai s3c64xx_i2s_dai[];
-extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
 
 #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
index b480348140b02db3bc001e84c851629e07b8e288..dd20ca7f46814e3458860931910d18a39bc4508f 100644 (file)
@@ -211,8 +211,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
        {
                .name           = "wm8987",
                .stream_name    = "SmartQ Hi-Fi",
-               .cpu_dai        = &s3c64xx_i2s_dai[0],
-               .codec_dai      = &wm8750_dai,
+               .cpu_dai_name   = "s3c64xx-i2s.0",
+               .codec_dai_name = "wm8750-hifi",
+               .platform_name  = "s3c24xx-pcm-audio",
+               .codec_name     = "wm8750-codec.0-0x1a",
                .init           = smartq_wm8987_init,
                .ops            = &smartq_hifi_ops,
        },
@@ -220,16 +222,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
 
 static struct snd_soc_card snd_soc_smartq = {
        .name = "SmartQ",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = smartq_dai,
        .num_links = ARRAY_SIZE(smartq_dai),
 };
 
-static struct snd_soc_device smartq_snd_devdata = {
-       .card = &snd_soc_smartq,
-       .codec_dev = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *smartq_snd_device;
 
 static int __init smartq_init(void)
@@ -245,8 +241,7 @@ static int __init smartq_init(void)
        if (!smartq_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
-       smartq_snd_devdata.dev = &smartq_snd_device->dev;
+       platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
 
        ret = platform_device_add(smartq_snd_device);
        if (ret) {
index 362258835e8d9aec20c71c53e8df9a9acf7b6036..4613288c2772a3f5474b54ff35818bf86468ca03 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -29,23 +28,19 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "s3c-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name = "ac97-codec",
+       .platform_name = "s3c24xx-pcm-audio",
 },
 };
 
 static struct snd_soc_card smdk2443 = {
        .name = "SMDK2443",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = smdk2443_dai,
        .num_links = ARRAY_SIZE(smdk2443_dai),
 };
 
-static struct snd_soc_device smdk2443_snd_ac97_devdata = {
-       .card = &smdk2443,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *smdk2443_snd_ac97_device;
 
 static int __init smdk2443_init(void)
@@ -56,9 +51,7 @@ static int __init smdk2443_init(void)
        if (!smdk2443_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk2443_snd_ac97_device,
-                               &smdk2443_snd_ac97_devdata);
-       smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+       platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
        ret = platform_device_add(smdk2443_snd_ac97_device);
 
        if (ret)
index 07e8e51d10d60e925e05062cd331a58a36ba64c4..052e499b68d161c614133bc596bc62b9afa31b2b 100644 (file)
 #include "s3c-dma.h"
 #include "s3c64xx-i2s.h"
 
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ *   SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
 /* SMDK64XX has a 12MHZ crystal attached to WM8580 */
 #define SMDK64XX_WM8580_FREQ 12000000
 
@@ -29,8 +35,8 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pll_out;
        int bfs, rfs, ret;
 
@@ -107,14 +113,13 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* Explicitly set WM8580-DAC to source from MCLK */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
-                                       WM8580_CLKSRC_MCLK);
+       ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+                                       SMDK64XX_WM8580_FREQ, pll_out);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
-                                       SMDK64XX_WM8580_FREQ, pll_out);
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+                                    pll_out, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
@@ -138,9 +143,9 @@ static struct snd_soc_ops smdk64xx_ops = {
 
 /* SMDK64xx Playback widgets */
 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
-       SND_SOC_DAPM_HP("Front-L/R", NULL),
-       SND_SOC_DAPM_HP("Center/Sub", NULL),
-       SND_SOC_DAPM_HP("Rear-L/R", NULL),
+       SND_SOC_DAPM_HP("Front", NULL),
+       SND_SOC_DAPM_HP("Center+Sub", NULL),
+       SND_SOC_DAPM_HP("Rear", NULL),
 };
 
 /* SMDK64xx Capture widgets */
@@ -162,20 +167,22 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
 /* SMDK-PAIFRX connections */
 static const struct snd_soc_dapm_route audio_map_rx[] = {
        /* Front Left/Right are fed VOUT1L/R */
-       {"Front-L/R", NULL, "VOUT1L"},
-       {"Front-L/R", NULL, "VOUT1R"},
+       {"Front", NULL, "VOUT1L"},
+       {"Front", NULL, "VOUT1R"},
 
        /* Center/Sub are fed VOUT2L/R */
-       {"Center/Sub", NULL, "VOUT2L"},
-       {"Center/Sub", NULL, "VOUT2R"},
+       {"Center+Sub", NULL, "VOUT2L"},
+       {"Center+Sub", NULL, "VOUT2R"},
 
        /* Rear Left/Right are fed VOUT3L/R */
-       {"Rear-L/R", NULL, "VOUT3L"},
-       {"Rear-L/R", NULL, "VOUT3R"},
+       {"Rear", NULL, "VOUT3L"},
+       {"Rear", NULL, "VOUT3R"},
 };
 
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add smdk64xx specific Capture widgets */
        snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
                                  ARRAY_SIZE(wm8580_dapm_widgets_cpt));
@@ -194,8 +201,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add smdk64xx specific Playback widgets */
        snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
                                  ARRAY_SIZE(wm8580_dapm_widgets_pbk));
@@ -213,33 +222,31 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
 { /* Primary Playback i/f */
        .name = "WM8580 PAIF RX",
        .stream_name = "Playback",
-       .cpu_dai = &s3c64xx_i2s_v4_dai,
-       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+       .cpu_dai_name = "s3c64xx-iis-v4",
+       .codec_dai_name = "wm8580-hifi-playback",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8580-codec.0-001b",
        .init = smdk64xx_wm8580_init_paifrx,
        .ops = &smdk64xx_ops,
 },
 { /* Primary Capture i/f */
        .name = "WM8580 PAIF TX",
        .stream_name = "Capture",
-       .cpu_dai = &s3c64xx_i2s_v4_dai,
-       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+       .cpu_dai_name = "s3c64xx-iis-v4",
+       .codec_dai_name = "wm8580-hifi-capture",
+       .platform_name = "s3c24xx-pcm-audio",
+       .codec_name = "wm8580-codec.0-001b",
        .init = smdk64xx_wm8580_init_paiftx,
        .ops = &smdk64xx_ops,
 },
 };
 
 static struct snd_soc_card smdk64xx = {
-       .name = "smdk64xx",
-       .platform = &s3c24xx_soc_platform,
+       .name = "SMDK64xx 5.1",
        .dai_link = smdk64xx_dai,
        .num_links = ARRAY_SIZE(smdk64xx_dai),
 };
 
-static struct snd_soc_device smdk64xx_snd_devdata = {
-       .card = &smdk64xx,
-       .codec_dev = &soc_codec_dev_wm8580,
-};
-
 static struct platform_device *smdk64xx_snd_device;
 
 static int __init smdk64xx_audio_init(void)
@@ -250,8 +257,7 @@ static int __init smdk64xx_audio_init(void)
        if (!smdk64xx_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
-       smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
        ret = platform_device_add(smdk64xx_snd_device);
 
        if (ret)
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
new file mode 100644 (file)
index 0000000..f31d22a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * smdk_spdif.c  --  S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+       struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+       int ret;
+
+       fout_epll = clk_get(NULL, "fout_epll");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       mout_epll = clk_get(NULL, "mout_epll");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out1;
+       }
+
+       sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+       if (IS_ERR(sclk_audio0)) {
+               printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out2;
+       }
+
+       sclk_spdif = clk_get(NULL, "sclk_spdif");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out3;
+       }
+
+       /* Set audio clock heirachy for S/PDIF */
+       clk_set_parent(mout_epll, fout_epll);
+       clk_set_parent(sclk_audio0, mout_epll);
+       clk_set_parent(sclk_spdif, sclk_audio0);
+
+       clk_put(sclk_spdif);
+out3:
+       clk_put(sclk_audio0);
+out2:
+       clk_put(mout_epll);
+out1:
+       clk_put(fout_epll);
+
+       return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's heirachy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+                               unsigned long audio_rate)
+{
+       struct clk *fout_epll, *sclk_spdif;
+
+       fout_epll = clk_get(NULL, "fout_epll");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+               return -ENOENT;
+       }
+
+       clk_set_rate(fout_epll, epll_rate);
+       clk_put(fout_epll);
+
+       sclk_spdif = clk_get(NULL, "sclk_spdif");
+       if (IS_ERR(sclk_spdif)) {
+               printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+               return -ENOENT;
+       }
+
+       clk_set_rate(sclk_spdif, audio_rate);
+       clk_put(sclk_spdif);
+
+       return 0;
+}
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned long pll_out, rclk_rate;
+       int ret, ratio;
+
+       switch (params_rate(params)) {
+       case 44100:
+               pll_out = 45158400;
+               break;
+       case 32000:
+       case 48000:
+       case 96000:
+               pll_out = 49152000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+        * modify S/PDIF ASoC machine driver.
+        */
+       ratio = 512;
+       rclk_rate = params_rate(params) * ratio;
+
+       /* Set audio source clock rates */
+       ret = set_audio_clock_rate(pll_out, rclk_rate);
+       if (ret < 0)
+               return ret;
+
+       /* Set S/PDIF uses internal source clock */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+                                       rclk_rate, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+       .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_card smdk;
+
+static struct snd_soc_dai_link smdk_dai = {
+       .name = "S/PDIF",
+       .stream_name = "S/PDIF PCM Playback",
+       .platform_name = "s3c24xx-pcm-audio",
+       .cpu_dai_name = "samsung-spdif",
+       .codec_dai_name = "dit-hifi",
+       .codec_name = "spdif-dit",
+       .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK-S/PDIF",
+       .dai_link = &smdk_dai,
+       .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+       int ret;
+
+       smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+       if (!smdk_snd_spdif_dit_device)
+               return -ENOMEM;
+
+       ret = platform_device_add(smdk_snd_spdif_dit_device);
+       if (ret)
+               goto err2;
+
+       smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_spdif_device) {
+               ret = -ENOMEM;
+               goto err2;
+       }
+
+       platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+       ret = platform_device_add(smdk_snd_spdif_device);
+       if (ret)
+               goto err1;
+
+       /* Set audio clock heirachy manually */
+       ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+       if (ret)
+               goto err1;
+
+       return 0;
+err1:
+       platform_device_put(smdk_snd_spdif_device);
+err2:
+       platform_device_put(smdk_snd_spdif_dit_device);
+       return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+       platform_device_unregister(smdk_snd_spdif_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
index 5527b9e88c98ee9f7772a002db499e6e0e274717..33ba8fdbcf07c2a0845caca16f39bba5d3bbc6bb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/device.h>
 #include <sound/soc.h>
 
-#include "../codecs/wm9713.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -46,46 +45,57 @@ static struct snd_soc_card smdk;
 static struct snd_soc_dai_link smdk_dai = {
        .name = "AC97",
        .stream_name = "AC97 PCM",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+       .platform_name = "s3c24xx-pcm-audio",
+       .cpu_dai_name = "s3c-ac97",
+       .codec_dai_name = "wm9713-hifi",
+       .codec_name = "wm9713-codec",
 };
 
 static struct snd_soc_card smdk = {
-       .name = "SMDK",
-       .platform = &s3c24xx_soc_platform,
+       .name = "SMDK WM9713",
        .dai_link = &smdk_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device smdk_snd_ac97_devdata = {
-       .card = &smdk,
-       .codec_dev = &soc_codec_dev_wm9713,
-};
-
+static struct platform_device *smdk_snd_wm9713_device;
 static struct platform_device *smdk_snd_ac97_device;
 
 static int __init smdk_init(void)
 {
        int ret;
 
-       smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk_snd_ac97_device)
+       smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+       if (!smdk_snd_wm9713_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk_snd_ac97_device,
-                            &smdk_snd_ac97_devdata);
-       smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
+       ret = platform_device_add(smdk_snd_wm9713_device);
+       if (ret)
+               goto err;
+
+       smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_ac97_device) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       platform_set_drvdata(smdk_snd_ac97_device, &smdk);
 
        ret = platform_device_add(smdk_snd_ac97_device);
-       if (ret)
+       if (ret) {
                platform_device_put(smdk_snd_ac97_device);
+               goto err;
+       }
 
+       return 0;
+err:
+       platform_device_put(smdk_snd_wm9713_device);
        return ret;
 }
 
 static void __exit smdk_exit(void)
 {
        platform_device_unregister(smdk_snd_ac97_device);
+       platform_device_unregister(smdk_snd_wm9713_device);
 }
 
 module_init(smdk_init);
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
new file mode 100644 (file)
index 0000000..ce554e9
--- /dev/null
@@ -0,0 +1,501 @@
+/* sound/soc/s3c24xx/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON                         0x00
+#define CON                            0x04
+#define BSTAS                          0x08
+#define CSTAS                          0x0C
+#define DATA_OUTBUF                    0x10
+#define DCNT                           0x14
+#define BSTAS_S                                0x18
+#define DCNT_S                         0x1C
+
+#define CLKCTL_MASK                    0x7
+#define CLKCTL_MCLK_EXT                        (0x1 << 2)
+#define CLKCTL_PWR_ON                  (0x1 << 0)
+
+#define CON_MASK                       0x3ffffff
+#define CON_FIFO_TH_SHIFT              19
+#define CON_FIFO_TH_MASK               (0x7 << 19)
+#define CON_USERDATA_23RDBIT           (0x1 << 12)
+
+#define CON_SW_RESET                   (0x1 << 5)
+
+#define CON_MCLKDIV_MASK               (0x3 << 3)
+#define CON_MCLKDIV_256FS              (0x0 << 3)
+#define CON_MCLKDIV_384FS              (0x1 << 3)
+#define CON_MCLKDIV_512FS              (0x2 << 3)
+
+#define CON_PCM_MASK                   (0x3 << 1)
+#define CON_PCM_16BIT                  (0x0 << 1)
+#define CON_PCM_20BIT                  (0x1 << 1)
+#define CON_PCM_24BIT                  (0x2 << 1)
+
+#define CON_PCM_DATA                   (0x1 << 0)
+
+#define CSTAS_MASK                     0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK           (0xF << 24)
+#define CSTAS_SAMP_FREQ_44             (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48             (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32             (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96             (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK            (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP                (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT             (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+       spinlock_t      lock;
+       struct device   *dev;
+       void __iomem    *regs;
+       unsigned long   clk_rate;
+       struct clk      *pclk;
+       struct clk      *sclk;
+       u32             saved_clkcon;
+       u32             saved_con;
+       u32             saved_cstas;
+       struct s3c_dma_params   *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+       .name           = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+       void __iomem *regs = spdif->regs;
+       u32 clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+       if (on)
+               writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+       else
+               writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+       u32 clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       clkcon = readl(spdif->regs + CLKCON);
+
+       if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+               clkcon &= ~CLKCTL_MCLK_EXT;
+       else
+               clkcon |= CLKCTL_MCLK_EXT;
+
+       writel(clkcon, spdif->regs + CLKCON);
+
+       spdif->clk_rate = freq;
+
+       return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       unsigned long flags;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 1);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 0);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+       512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       struct s3c_dma_params *dma_data;
+       u32 con, clkcon, cstas;
+       unsigned long flags;
+       int i, ratio;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = spdif->dma_playback;
+       else {
+               dev_err(spdif->dev, "Capture is not supported\n");
+               return -EINVAL;
+       }
+
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       con = readl(regs + CON) & CON_MASK;
+       cstas = readl(regs + CSTAS) & CSTAS_MASK;
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+       con &= ~CON_FIFO_TH_MASK;
+       con |= (0x7 << CON_FIFO_TH_SHIFT);
+       con |= CON_USERDATA_23RDBIT;
+       con |= CON_PCM_DATA;
+
+       con &= ~CON_PCM_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               con |= CON_PCM_16BIT;
+               break;
+       default:
+               dev_err(spdif->dev, "Unsupported data size.\n");
+               goto err;
+       }
+
+       ratio = spdif->clk_rate / params_rate(params);
+       for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+               if (ratio == spdif_sysclk_ratios[i])
+                       break;
+       if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+               dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+                               spdif->clk_rate, params_rate(params));
+               goto err;
+       }
+
+       con &= ~CON_MCLKDIV_MASK;
+       switch (ratio) {
+       case 256:
+               con |= CON_MCLKDIV_256FS;
+               break;
+       case 384:
+               con |= CON_MCLKDIV_384FS;
+               break;
+       case 512:
+               con |= CON_MCLKDIV_512FS;
+               break;
+       }
+
+       cstas &= ~CSTAS_SAMP_FREQ_MASK;
+       switch (params_rate(params)) {
+       case 44100:
+               cstas |= CSTAS_SAMP_FREQ_44;
+               break;
+       case 48000:
+               cstas |= CSTAS_SAMP_FREQ_48;
+               break;
+       case 32000:
+               cstas |= CSTAS_SAMP_FREQ_32;
+               break;
+       case 96000:
+               cstas |= CSTAS_SAMP_FREQ_96;
+               break;
+       default:
+               dev_err(spdif->dev, "Invalid sampling rate %d\n",
+                               params_rate(params));
+               goto err;
+       }
+
+       cstas &= ~CSTAS_CATEGORY_MASK;
+       cstas |= CSTAS_CATEGORY_CODE_CDP;
+       cstas |= CSTAS_NO_COPYRIGHT;
+
+       writel(con, regs + CON);
+       writel(cstas, regs + CSTAS);
+       writel(clkcon, regs + CLKCON);
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+err:
+       spin_unlock_irqrestore(&spdif->lock, flags);
+       return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       u32 con, clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       con = readl(regs + CON) & CON_MASK;
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+       writel(con | CON_SW_RESET, regs + CON);
+       cpu_relax();
+
+       writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+       u32 con = spdif->saved_con;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+       spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+       spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+       writel(con | CON_SW_RESET, spdif->regs + CON);
+       cpu_relax();
+
+       return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+       writel(spdif->saved_con, spdif->regs + CON);
+       writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+       return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+       .set_sysclk     = spdif_set_sysclk,
+       .trigger        = spdif_trigger,
+       .hw_params      = spdif_hw_params,
+       .shutdown       = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+       .name = "samsung-spdif",
+       .playback = {
+               .stream_name = "S/PDIF Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = (SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000),
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .ops = &spdif_dai_ops,
+       .suspend = spdif_suspend,
+       .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+       struct s3c_audio_pdata *spdif_pdata;
+       struct resource *mem_res, *dma_res;
+       struct samsung_spdif_info *spdif;
+       int ret;
+
+       spdif_pdata = pdev->dev.platform_data;
+
+       dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+       dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dma_res) {
+               dev_err(&pdev->dev, "Unable to get dma resource.\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Unable to get register resource.\n");
+               return -ENXIO;
+       }
+
+       if (spdif_pdata && spdif_pdata->cfg_gpio
+                       && spdif_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+               return -EINVAL;
+       }
+
+       spdif = &spdif_info;
+       spdif->dev = &pdev->dev;
+
+       spin_lock_init(&spdif->lock);
+
+       spdif->pclk = clk_get(&pdev->dev, "spdif");
+       if (IS_ERR(spdif->pclk)) {
+               dev_err(&pdev->dev, "failed to get peri-clock\n");
+               ret = -ENOENT;
+               goto err0;
+       }
+       clk_enable(spdif->pclk);
+
+       spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+       if (IS_ERR(spdif->sclk)) {
+               dev_err(&pdev->dev, "failed to get internal source clock\n");
+               ret = -ENOENT;
+               goto err1;
+       }
+       clk_enable(spdif->sclk);
+
+       /* Request S/PDIF Register's memory region */
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "samsung-spdif")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       spdif->regs = ioremap(mem_res->start, 0x100);
+       if (spdif->regs == NULL) {
+               dev_err(&pdev->dev, "Cannot ioremap registers\n");
+               ret = -ENXIO;
+               goto err3;
+       }
+
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "fail to register dai\n");
+               goto err4;
+       }
+
+       spdif_stereo_out.dma_size = 2;
+       spdif_stereo_out.client = &spdif_dma_client_out;
+       spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+       spdif_stereo_out.channel = dma_res->start;
+
+       spdif->dma_playback = &spdif_stereo_out;
+
+       return 0;
+
+err4:
+       iounmap(spdif->regs);
+err3:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+       clk_disable(spdif->sclk);
+       clk_put(spdif->sclk);
+err1:
+       clk_disable(spdif->pclk);
+       clk_put(spdif->pclk);
+err0:
+       return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+       struct samsung_spdif_info *spdif = &spdif_info;
+       struct resource *mem_res;
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       iounmap(spdif->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res)
+               release_mem_region(mem_res->start, resource_size(mem_res));
+
+       clk_disable(spdif->sclk);
+       clk_put(spdif->sclk);
+       clk_disable(spdif->pclk);
+       clk_put(spdif->pclk);
+
+       return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+       .probe  = spdif_probe,
+       .remove = spdif_remove,
+       .driver = {
+               .name   = "samsung-spdif",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init spdif_init(void)
+{
+       return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+       platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
new file mode 100644 (file)
index 0000000..3ed5559
--- /dev/null
@@ -0,0 +1,19 @@
+/* sound/soc/s3c24xx/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H      __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK         0
+#define SND_SOC_SPDIF_EXT_MCLK         1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
index 59e3fa7bcb05a7e912d709e7c1c2958097b1f7a0..8778faa174a6cb66da33e1e81430c6aae2c59973 100644 (file)
@@ -140,7 +140,7 @@ static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
 static void s6000_i2s_start(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        int channel;
 
        channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -152,7 +152,7 @@ static void s6000_i2s_start(struct snd_pcm_substream *substream)
 static void s6000_i2s_stop(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        int channel;
 
        channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -194,7 +194,7 @@ static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
 
 static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
 {
-       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int errors;
        unsigned int ret;
 
@@ -232,7 +232,7 @@ static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
 static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                   unsigned int fmt)
 {
-       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        u32 w;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -273,7 +273,7 @@ static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
 static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
 
        if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
                return -EINVAL;
@@ -287,7 +287,7 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params,
                               struct snd_soc_dai *dai)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
        int interf;
        u32 w = 0;
 
@@ -326,15 +326,17 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int s6000_i2s_dai_probe(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
-       struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
 
        if (!pdata)
                return -EINVAL;
 
+       dai->capture_dma_data = &dev->dma_params;
+       dai->playback_dma_data = &dev->dma_params;
+
        dev->wide = pdata->wide;
        dev->channel_in = pdata->channel_in;
        dev->channel_out = pdata->channel_out;
@@ -352,10 +354,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
 
                dev->channel_in = 0;
                dev->channel_out = 1;
-               dai->capture.channels_min = 2 * dev->lines_in;
-               dai->capture.channels_max = dai->capture.channels_min;
-               dai->playback.channels_min = 2 * dev->lines_out;
-               dai->playback.channels_max = dai->playback.channels_min;
+               dai->driver->capture.channels_min = 2 * dev->lines_in;
+               dai->driver->capture.channels_max = dai->driver->capture.channels_min;
+               dai->driver->playback.channels_min = 2 * dev->lines_out;
+               dai->driver->playback.channels_max = dai->driver->playback.channels_min;
 
                for (i = 0; i < dev->lines_out; i++)
                        s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
@@ -372,10 +374,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
                if (dev->lines_in > 1 || dev->lines_out > 1)
                        return -EINVAL;
 
-               dai->capture.channels_min = 2 * dev->lines_in;
-               dai->capture.channels_max = 8 * dev->lines_in;
-               dai->playback.channels_min = 2 * dev->lines_out;
-               dai->playback.channels_max = 8 * dev->lines_out;
+               dai->driver->capture.channels_min = 2 * dev->lines_in;
+               dai->driver->capture.channels_max = 8 * dev->lines_in;
+               dai->driver->playback.channels_min = 2 * dev->lines_out;
+               dai->driver->playback.channels_max = 8 * dev->lines_out;
 
                if (dev->lines_in)
                        cfg[dev->channel_in] = S6_I2S_IN;
@@ -413,9 +415,7 @@ static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
        .hw_params = s6000_i2s_hw_params,
 };
 
-struct snd_soc_dai s6000_i2s_dai = {
-       .name = "s6000-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver s6000_i2s_dai = {
        .probe = s6000_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
@@ -435,7 +435,6 @@ struct snd_soc_dai s6000_i2s_dai = {
        },
        .ops = &s6000_i2s_dai_ops,
 }
-EXPORT_SYMBOL_GPL(s6000_i2s_dai);
 
 static int __devinit s6000_i2s_probe(struct platform_device *pdev)
 {
@@ -513,11 +512,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_release_dma2;
        }
-
-       s6000_i2s_dai.dev = &pdev->dev;
-       s6000_i2s_dai.private_data = dev;
-       s6000_i2s_dai.capture.dma_data = &dev->dma_params;
-       s6000_i2s_dai.playback.dma_data = &dev->dma_params;
+       dev_set_drvdata(&pdev->dev, dev);
 
        dev->sifbase = sifmem->start;
        dev->scbbase = mmio;
@@ -548,7 +543,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
                         S6_I2S_INT_UNDERRUN |
                         S6_I2S_INT_OVERRUN);
 
-       ret = snd_soc_register_dai(&s6000_i2s_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
        if (ret)
                goto err_release_dev;
 
@@ -573,17 +568,16 @@ err_release_none:
 
 static void __devexit s6000_i2s_remove(struct platform_device *pdev)
 {
-       struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+       struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *region;
        void __iomem *mmio = dev->scbbase;
 
-       snd_soc_unregister_dai(&s6000_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        s6000_i2s_stop_channel(dev, 0);
        s6000_i2s_stop_channel(dev, 1);
 
        s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
-       s6000_i2s_dai.private_data = 0;
        kfree(dev);
 
        region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
index 2375fdfe6dba7dcf996e81dda673417d80b05d64..86aa1921c89e3b06b83b0e75ff78a40c5674a9ef 100644 (file)
@@ -12,8 +12,6 @@
 #ifndef _S6000_I2S_H
 #define _S6000_I2S_H
 
-extern struct snd_soc_dai s6000_i2s_dai;
-
 struct s6000_snd_platform_data {
        int lines_in;
        int lines_out;
index 9c7f7f00cebb45706aa6c8f7302b4a371d469ceb..271fd222bf1997f92cac08b6c8b27f8f604b5147 100644 (file)
@@ -65,7 +65,7 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        dma_addr_t dma_pos;
        dma_addr_t src, dst;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        period_size = snd_pcm_lib_period_bytes(substream);
        dma_offset = prtd->period * period_size;
@@ -103,23 +103,25 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
 {
        struct snd_pcm *pcm = data;
        struct snd_soc_pcm_runtime *runtime = pcm->private_data;
-       struct s6000_pcm_dma_params *params =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
        struct s6000_runtime_data *prtd;
        unsigned int has_xrun;
        int i, ret = IRQ_NONE;
-       u32 channel[2] = {
-               [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
-               [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
-       };
-
-       has_xrun = params->check_xrun(runtime->dai->cpu_dai);
 
-       for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+       for (i = 0; i < 2; ++i) {
                struct snd_pcm_substream *substream = pcm->streams[i].substream;
+               struct s6000_pcm_dma_params *params =
+                                       snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
+               u32 channel;
                unsigned int pending;
 
-               if (!channel[i])
+               if (substream == SNDRV_PCM_STREAM_PLAYBACK)
+                       channel = params->dma_out;
+               else
+                       channel = params->dma_in;
+
+               has_xrun = params->check_xrun(runtime->cpu_dai);
+
+               if (!channel)
                        continue;
 
                if (unlikely(has_xrun & (1 << i)) &&
@@ -130,8 +132,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                        ret = IRQ_HANDLED;
                }
 
-               pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
-                                            DMA_INDEX_CHNL(channel[i]));
+               pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
+                                            DMA_INDEX_CHNL(channel));
 
                if (pending & 1) {
                        ret = IRQ_HANDLED;
@@ -139,10 +141,10 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                                   snd_pcm_running(substream))) {
                                snd_pcm_period_elapsed(substream);
                                dev_dbg(pcm->dev, "period elapsed %x %x\n",
-                                      s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
-                                                  DMA_INDEX_CHNL(channel[i])),
-                                      s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
-                                                  DMA_INDEX_CHNL(channel[i])));
+                                      s6dmac_cur_src(DMA_MASK_DMAC(channel),
+                                                  DMA_INDEX_CHNL(channel)),
+                                      s6dmac_cur_dst(DMA_MASK_DMAC(channel),
+                                                  DMA_INDEX_CHNL(channel)));
                                prtd = substream->runtime->private_data;
                                spin_lock(&prtd->lock);
                                s6000_pcm_enqueue_dma(substream);
@@ -154,16 +156,16 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                        if (pending & (1 << 3))
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Underflow\n",
-                                      channel[i]);
+                                      channel);
                        if (pending & (1 << 4))
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Overflow\n",
-                                      channel[i]);
+                                      channel);
                        if (pending & 0x1e0)
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Master Error "
                                       "(mask %x)\n",
-                                      channel[i], pending >> 5);
+                                      channel, pending >> 5);
 
                }
        }
@@ -180,7 +182,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream)
        int srcinc;
        u32 dma;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock_irqsave(&prtd->lock, flags);
 
@@ -221,7 +223,7 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)
        unsigned long flags;
        u32 channel;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                channel = par->dma_out;
@@ -246,7 +248,7 @@ static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct s6000_pcm_dma_params *par;
        int ret;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        ret = par->trigger(substream, cmd, 0);
        if (ret < 0)
@@ -291,7 +293,7 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
        unsigned int offset;
        dma_addr_t count;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock_irqsave(&prtd->lock, flags);
 
@@ -321,7 +323,7 @@ static int s6000_pcm_open(struct snd_pcm_substream *substream)
        struct s6000_runtime_data *prtd;
        int ret;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
        snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
 
        ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -385,7 +387,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        if (par->same_rate) {
                spin_lock(&par->lock);
@@ -407,7 +409,7 @@ static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct s6000_pcm_dma_params *par =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock(&par->lock);
        par->in_use &= ~(1 << substream->stream);
@@ -433,7 +435,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_soc_pcm_runtime *runtime = pcm->private_data;
        struct s6000_pcm_dma_params *params =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream);
 
        free_irq(params->irq, pcm);
        snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -448,7 +450,8 @@ static int s6000_pcm_new(struct snd_card *card,
        struct s6000_pcm_dma_params *params;
        int res;
 
-       params = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
+                       pcm->streams[0].substream);
 
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &s6000_pcm_dmamask;
@@ -490,25 +493,44 @@ static int s6000_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform s6000_soc_platform = {
-       .name =         "s6000-audio",
-       .pcm_ops =      &s6000_pcm_ops,
+static struct snd_soc_platform_driver s6000_soc_platform = {
+       .ops =          &s6000_pcm_ops,
        .pcm_new =      s6000_pcm_new,
        .pcm_free =     s6000_pcm_free,
 };
-EXPORT_SYMBOL_GPL(s6000_soc_platform);
 
-static int __init s6000_pcm_init(void)
+static int __devinit s6000_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
+}
+
+static int __devexit s6000_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s6000_pcm_driver = {
+       .driver = {
+                       .name = "s6000-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = s6000_soc_platform_probe,
+       .remove = __devexit_p(s6000_soc_platform_remove),
+};
+
+static int __init snd_s6000_pcm_init(void)
 {
-       return snd_soc_register_platform(&s6000_soc_platform);
+       return platform_driver_register(&s6000_pcm_driver);
 }
-module_init(s6000_pcm_init);
+module_init(snd_s6000_pcm_init);
 
-static void __exit s6000_pcm_exit(void)
+static void __exit snd_s6000_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&s6000_soc_platform);
+       platform_driver_unregister(&s6000_pcm_driver);
 }
-module_exit(s6000_pcm_exit);
+module_exit(snd_s6000_pcm_exit);
 
 MODULE_AUTHOR("Daniel Gloeckner");
 MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
index 96f23f6f52bf6b6ece9493e1a6d66b95a54fe5c0..09d9b883e58b08b550927ea65a30f70764aad43d 100644 (file)
@@ -30,6 +30,4 @@ struct s6000_pcm_dma_params {
        int rate;
 };
 
-extern struct snd_soc_platform s6000_soc_platform;
-
 #endif
index c1b40ac22c052b22a986dac52435291529ad2bfd..96c05e1375386ebf6f11fd8d6ebcaa7dd118ac07 100644 (file)
@@ -32,8 +32,8 @@ static int s6105_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        /* set codec DAI configuration */
@@ -134,8 +134,10 @@ static const struct snd_kcontrol_new audio_out_mux = {
 };
 
 /* Logic for a aic3x as connected on the s6105 ip camera ref design */
-static int s6105_aic3x_init(struct snd_soc_codec *codec)
+static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add s6105 specific widgets */
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
@@ -165,7 +167,7 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
 
        snd_soc_dapm_sync(codec);
 
-       snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+       snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec));
 
        return 0;
 }
@@ -174,8 +176,10 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link s6105_dai = {
        .name = "TLV320AIC31",
        .stream_name = "AIC31",
-       .cpu_dai = &s6000_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "s6000-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name = "s6000-pcm-audio",
+       .codec_name = "tlv320aic3x-codec.0-001a",
        .init = s6105_aic3x_init,
        .ops = &s6105_ops,
 };
@@ -183,22 +187,10 @@ static struct snd_soc_dai_link s6105_dai = {
 /* s6105 audio machine driver */
 static struct snd_soc_card snd_soc_card_s6105 = {
        .name = "Stretch IP Camera",
-       .platform = &s6000_soc_platform,
        .dai_link = &s6105_dai,
        .num_links = 1,
 };
 
-/* s6105 audio private data */
-static struct aic3x_setup_data s6105_aic3x_setup = {
-};
-
-/* s6105 audio subsystem */
-static struct snd_soc_device s6105_snd_devdata = {
-       .card = &snd_soc_card_s6105,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &s6105_aic3x_setup,
-};
-
 static struct s6000_snd_platform_data __initdata s6105_snd_data = {
        .wide           = 0,
        .channel_in     = 0,
@@ -227,8 +219,7 @@ static int __init s6105_init(void)
        if (!s6105_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
-       s6105_snd_devdata.dev = &s6105_snd_device->dev;
+       platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
        platform_device_add_data(s6105_snd_device, &s6105_snd_data,
                                 sizeof(s6105_snd_data));
 
index 52d7e8ed9c1faa1e9e38015dfe0c04cb5a9a5fbf..7f0a496e07cee6d7e2ab52d64a02f4bfc4b146ba 100644 (file)
@@ -47,7 +47,7 @@ config SND_SH7760_AC97
          AC97 unit of the SH7760.
 
 config SND_FSI_AK4642
-       bool "FSI-AK4642 sound support"
+       tristate "FSI-AK4642 sound support"
        depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
        select SND_SOC_AK4642
        help
@@ -55,13 +55,20 @@ config SND_FSI_AK4642
          FSI - AK4642 unit
 
 config SND_FSI_DA7210
-       bool "FSI-DA7210 sound support"
+       tristate "FSI-DA7210 sound support"
        depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
        select SND_SOC_DA7210
        help
          This option enables generic sound support for the
          FSI - DA7210 unit
 
+config SND_FSI_HDMI
+       tristate "FSI-HDMI sound support"
+       depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
+       help
+         This option enables generic sound support for the
+         FSI - HDMI unit
+
 config SND_SIU_MIGOR
        tristate "SIU sound support on Migo-R"
        depends on SH_MIGOR
index 8a5a19293bda17b7d0ef11fc2a80f385aa23f273..94476d4c0fd58f01b9ae46691f9b6621b66cac95 100644 (file)
@@ -16,9 +16,11 @@ obj-$(CONFIG_SND_SOC_SH4_SIU)        += snd-soc-siu.o
 snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
 snd-soc-fsi-ak4642-objs                := fsi-ak4642.o
 snd-soc-fsi-da7210-objs                := fsi-da7210.o
+snd-soc-fsi-hdmi-objs          := fsi-hdmi.o
 snd-soc-migor-objs             := migor.o
 
 obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
 obj-$(CONFIG_SND_FSI_AK4642)   += snd-soc-fsi-ak4642.o
 obj-$(CONFIG_SND_FSI_DA7210)   += snd-soc-fsi-da7210.o
+obj-$(CONFIG_SND_FSI_HDMI)     += snd-soc-fsi-hdmi.o
 obj-$(CONFIG_SND_SIU_MIGOR)    += snd-soc-migor.o
index 0d8bdf07729c559daaf7bc861f379c7b3bbddf0d..c326d29992fe3c90184b7b97cef36ea42f54f3d9 100644 (file)
@@ -137,7 +137,7 @@ static void camelot_rxdma(void *data)
 static int camelot_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int ret, dmairq;
 
@@ -150,7 +150,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
                ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
                if (unlikely(ret)) {
                        pr_debug("audio unit %d irqs already taken!\n",
-                            rtd->dai->cpu_dai->id);
+                            rtd->cpu_dai->id);
                        return -EBUSY;
                }
                (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
@@ -159,7 +159,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
                ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
                if (unlikely(ret)) {
                        pr_debug("audio unit %d irqs already taken!\n",
-                            rtd->dai->cpu_dai->id);
+                            rtd->cpu_dai->id);
                        return -EBUSY;
                }
                (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
@@ -170,7 +170,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
 static int camelot_pcm_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int dmairq;
 
@@ -191,7 +191,7 @@ static int camelot_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *hw_params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int ret;
 
@@ -219,7 +219,7 @@ static int camelot_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
 
        pr_debug("PCM data: addr 0x%08ulx len %d\n",
                 (u32)runtime->dma_addr, runtime->dma_bytes);
@@ -266,7 +266,7 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
 static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
 
        switch (cmd) {
@@ -293,7 +293,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        unsigned long pos;
 
@@ -342,25 +342,44 @@ static int camelot_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform sh7760_soc_platform = {
-       .name           = "sh7760-pcm",
+static struct snd_soc_platform sh7760_soc_platform = {
        .pcm_ops        = &camelot_pcm_ops,
        .pcm_new        = camelot_pcm_new,
        .pcm_free       = camelot_pcm_free,
 };
-EXPORT_SYMBOL_GPL(sh7760_soc_platform);
 
-static int __init sh7760_soc_platform_init(void)
+static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&sh7760_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
 }
-module_init(sh7760_soc_platform_init);
 
-static void __exit sh7760_soc_platform_exit(void)
+static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&sh7760_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver sh7760_pcm_driver = {
+       .driver = {
+                       .name = "sh7760-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = sh7760_soc_platform_probe,
+       .remove = __devexit_p(sh7760_soc_platform_remove),
+};
+
+static int __init snd_sh7760_pcm_init(void)
+{
+       return platform_driver_register(&sh7760_pcm_driver);
+}
+module_init(snd_sh7760_pcm_init);
+
+static void __exit snd_sh7760_pcm_exit(void)
+{
+       platform_driver_unregister(&sh7760_pcm_driver);
 }
-module_exit(sh7760_soc_platform_exit);
+module_exit(snd_sh7760_pcm_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
index dad575a2262228fc1ffa6511bc036d74beade9dc..d96602de71de3fd351eb4c1a2b1ccbb0d21c819a 100644 (file)
 
 #include <linux/platform_device.h>
 #include <sound/sh_fsi.h>
-#include <../sound/soc/codecs/ak4642.h>
 
-static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
+static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_dai *dai = rtd->codec_dai;
        int ret;
 
-       ret = snd_soc_dai_set_fmt(&ak4642_dai, SND_SOC_DAIFMT_CBM_CFM);
+       ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_sysclk(&ak4642_dai, 0, 11289600, 0);
+       ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0);
 
        return ret;
 }
@@ -29,24 +29,25 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link fsi_dai_link = {
        .name           = "AK4642",
        .stream_name    = "AK4642",
-       .cpu_dai        = &fsi_soc_dai[FSI_PORT_A],
-       .codec_dai      = &ak4642_dai,
+       .cpu_dai_name   = "fsia-dai", /* fsi A */
+       .codec_dai_name = "ak4642-hifi",
+#ifdef CONFIG_MACH_AP4EVB
+       .platform_name  = "sh_fsi2",
+       .codec_name     = "ak4642-codec.0-0013",
+#else
+       .platform_name  = "sh_fsi.0",
+       .codec_name     = "ak4642-codec.0-0012",
+#endif
        .init           = fsi_ak4642_dai_init,
        .ops            = NULL,
 };
 
 static struct snd_soc_card fsi_soc_card  = {
-       .name           = "FSI",
-       .platform       = &fsi_soc_platform,
+       .name           = "FSI (AK4642)",
        .dai_link       = &fsi_dai_link,
        .num_links      = 1,
 };
 
-static struct snd_soc_device fsi_snd_devdata = {
-       .card           = &fsi_soc_card,
-       .codec_dev      = &soc_codec_dev_ak4642,
-};
-
 static struct platform_device *fsi_snd_device;
 
 static int __init fsi_ak4642_init(void)
@@ -57,9 +58,7 @@ static int __init fsi_ak4642_init(void)
        if (!fsi_snd_device)
                goto out;
 
-       platform_set_drvdata(fsi_snd_device,
-                            &fsi_snd_devdata);
-       fsi_snd_devdata.dev = &fsi_snd_device->dev;
+       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_snd_device);
 
        if (ret)
index 121bbb07bb03b7677280dcf7f8e9316c686de332..a6adb6e432507bd921cc7cc948c0380868a3bd4f 100644 (file)
 
 #include <linux/platform_device.h>
 #include <sound/sh_fsi.h>
-#include "../codecs/da7210.h"
 
-static int fsi_da7210_init(struct snd_soc_codec *codec)
+static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
 {
-       return snd_soc_dai_set_fmt(&da7210_dai,
+       struct snd_soc_dai *dai = rtd->codec_dai;
+
+       return snd_soc_dai_set_fmt(dai,
                                   SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                                   SND_SOC_DAIFMT_CBM_CFM);
 }
@@ -24,23 +25,19 @@ static int fsi_da7210_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link fsi_da7210_dai = {
        .name           = "DA7210",
        .stream_name    = "DA7210",
-       .cpu_dai        = &fsi_soc_dai[FSI_PORT_B],
-       .codec_dai      = &da7210_dai,
+       .cpu_dai_name   = "fsib-dai", /* FSI B */
+       .codec_dai_name = "da7210-hifi",
+       .platform_name  = "sh_fsi.0",
+       .codec_name     = "da7210-codec.0-001a",
        .init           = fsi_da7210_init,
 };
 
 static struct snd_soc_card fsi_soc_card = {
-       .name           = "FSI",
-       .platform       = &fsi_soc_platform,
+       .name           = "FSI (DA7210)",
        .dai_link       = &fsi_da7210_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device fsi_da7210_snd_devdata = {
-       .card           = &fsi_soc_card,
-       .codec_dev      = &soc_codec_dev_da7210,
-};
-
 static struct platform_device *fsi_da7210_snd_device;
 
 static int __init fsi_da7210_sound_init(void)
@@ -51,8 +48,7 @@ static int __init fsi_da7210_sound_init(void)
        if (!fsi_da7210_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
-       fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
+       platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_da7210_snd_device);
        if (ret)
                platform_device_put(fsi_da7210_snd_device);
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
new file mode 100644 (file)
index 0000000..a52dd8e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * FSI - HDMI sound support
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <sound/sh_fsi.h>
+
+static struct snd_soc_dai_link fsi_dai_link = {
+       .name           = "HDMI",
+       .stream_name    = "HDMI",
+       .cpu_dai_name   = "fsib-dai", /* fsi B */
+       .codec_dai_name = "sh_mobile_hdmi-hifi",
+       .platform_name  = "sh_fsi2",
+       .codec_name     = "sh-mobile-hdmi",
+};
+
+static struct snd_soc_card fsi_soc_card  = {
+       .name           = "FSI (SH MOBILE HDMI)",
+       .dai_link       = &fsi_dai_link,
+       .num_links      = 1,
+};
+
+static struct platform_device *fsi_snd_device;
+
+static int __init fsi_hdmi_init(void)
+{
+       int ret = -ENOMEM;
+
+       fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
+       if (!fsi_snd_device)
+               goto out;
+
+       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
+       ret = platform_device_add(fsi_snd_device);
+
+       if (ret)
+               platform_device_put(fsi_snd_device);
+
+out:
+       return ret;
+}
+
+static void __exit fsi_hdmi_exit(void)
+{
+       platform_device_unregister(fsi_snd_device);
+}
+
+module_init(fsi_hdmi_init);
+module_exit(fsi_hdmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 58c6bec642decf3093746f577fd387c0688ad459..507e709f2807c52995bed6c8dfaad09981ce471d 100644 (file)
 #define B_CLK          0x00000010
 #define A_CLK          0x00000001
 
-/* INT_ST */
-#define INT_B_IN       (1 << 12)
-#define INT_B_OUT      (1 << 8)
-#define INT_A_IN       (1 << 4)
-#define INT_A_OUT      (1 << 0)
+/* IO SHIFT / MACRO */
+#define BI_SHIFT       12
+#define BO_SHIFT       8
+#define AI_SHIFT       4
+#define AO_SHIFT       0
+#define AB_IO(param, shift)    (param << shift)
 
 /* SOFT_RST */
 #define PBSR           (1 << 12) /* Port B Software Reset */
 #define FSISR          (1 <<  0) /* Software Reset */
 
 /* FIFO_SZ */
-#define OUT_SZ_MASK    0x7
-#define BO_SZ_SHIFT    8
-#define AO_SZ_SHIFT    0
+#define FIFO_SZ_MASK   0x7
 
 #define FSI_RATES SNDRV_PCM_RATE_8000_96000
 
 #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
-/************************************************************************
+/*
+ * FSI driver use below type name for variable
+ *
+ * xxx_len     : data length
+ * xxx_width   : data width
+ * xxx_offset  : data offset
+ * xxx_num     : number of data
+ */
+
+/*
+ *             struct
+ */
 
+struct fsi_stream {
+       struct snd_pcm_substream *substream;
 
-               struct
+       int fifo_max_num;
+       int chan_num;
 
+       int buff_offset;
+       int buff_len;
+       int period_len;
+       int period_num;
+};
 
-************************************************************************/
 struct fsi_priv {
        void __iomem *base;
-       struct snd_pcm_substream *substream;
        struct fsi_master *master;
 
-       int fifo_max;
-       int chan;
-
-       int byte_offset;
-       int period_len;
-       int buffer_len;
-       int periods;
+       struct fsi_stream playback;
+       struct fsi_stream capture;
 
        u32 mst_ctrl;
 };
@@ -142,13 +153,10 @@ struct fsi_master {
        spinlock_t lock;
 };
 
-/************************************************************************
-
-
-               basic read write function
-
+/*
+ *             basic read write function
+ */
 
-************************************************************************/
 static void __fsi_reg_write(u32 reg, u32 data)
 {
        /* valid data area is 24bit */
@@ -251,13 +259,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
        spin_unlock_irqrestore(&master->lock, flags);
 }
 
-/************************************************************************
-
-
-               basic function
-
+/*
+ *             basic function
+ */
 
-************************************************************************/
 static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 {
        return fsi->master;
@@ -271,16 +276,19 @@ static int fsi_is_port_a(struct fsi_priv *fsi)
 static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *machine = rtd->dai;
 
-       return  machine->cpu_dai;
+       return  rtd->cpu_dai;
 }
 
 static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
 {
        struct snd_soc_dai *dai = fsi_get_dai(substream);
+       struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
 
-       return dai->private_data;
+       if (dai->id == 0)
+               return &master->fsia;
+       else
+               return &master->fsib;
 }
 
 static u32 fsi_get_info_flags(struct fsi_priv *fsi)
@@ -292,6 +300,22 @@ static u32 fsi_get_info_flags(struct fsi_priv *fsi)
                master->info->portb_flags;
 }
 
+static inline int fsi_stream_is_play(int stream)
+{
+       return stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static inline int fsi_is_play(struct snd_pcm_substream *substream)
+{
+       return fsi_stream_is_play(substream->stream);
+}
+
+static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
+                                               int is_play)
+{
+       return is_play ? &fsi->playback : &fsi->capture;
+}
+
 static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
 {
        u32 mode;
@@ -307,63 +331,144 @@ static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
        return (mode & flags) != mode;
 }
 
-static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play)
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
 {
        int is_porta = fsi_is_port_a(fsi);
-       u32 data;
+       u32 shift;
 
        if (is_porta)
-               data = is_play ? (1 << 0) : (1 << 4);
+               shift = is_play ? AO_SHIFT : AI_SHIFT;
        else
-               data = is_play ? (1 << 8) : (1 << 12);
+               shift = is_play ? BO_SHIFT : BI_SHIFT;
 
-       return data;
+       return shift;
 }
 
 static void fsi_stream_push(struct fsi_priv *fsi,
+                           int is_play,
                            struct snd_pcm_substream *substream,
                            u32 buffer_len,
                            u32 period_len)
 {
-       fsi->substream          = substream;
-       fsi->buffer_len         = buffer_len;
-       fsi->period_len         = period_len;
-       fsi->byte_offset        = 0;
-       fsi->periods            = 0;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       io->substream   = substream;
+       io->buff_len    = buffer_len;
+       io->buff_offset = 0;
+       io->period_len  = period_len;
+       io->period_num  = 0;
 }
 
-static void fsi_stream_pop(struct fsi_priv *fsi)
+static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
-       fsi->substream          = NULL;
-       fsi->buffer_len         = 0;
-       fsi->period_len         = 0;
-       fsi->byte_offset        = 0;
-       fsi->periods            = 0;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       io->substream   = NULL;
+       io->buff_len    = 0;
+       io->buff_offset = 0;
+       io->period_len  = 0;
+       io->period_num  = 0;
 }
 
-static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
+static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
        u32 reg = is_play ? DOFF_ST : DIFF_ST;
-       int residue;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       int data_num;
 
        status = fsi_reg_read(fsi, reg);
-       residue = 0x1ff & (status >> 8);
-       residue *= fsi->chan;
+       data_num = 0x1ff & (status >> 8);
+       data_num *= io->chan_num;
+
+       return data_num;
+}
+
+static int fsi_len2num(int len, int width)
+{
+       return len / width;
+}
+
+#define fsi_num2offset(a, b) fsi_num2len(a, b)
+static int fsi_num2len(int num, int width)
+{
+       return num * width;
+}
+
+static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
+{
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_substream *substream = io->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       return frames_to_bytes(runtime, 1) / io->chan_num;
+}
+
+/*
+ *             dma function
+ */
+
+static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
+{
+       int is_play = fsi_stream_is_play(stream);
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       return io->substream->runtime->dma_area + io->buff_offset;
+}
+
+static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
+{
+       u16 *start;
+       int i;
+
+       start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+       for (i = 0; i < num; i++)
+               fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8));
+}
+
+static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num)
+{
+       u16 *start;
+       int i;
 
-       return residue;
+       start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+
+
+       for (i = 0; i < num; i++)
+               *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
 }
 
-/************************************************************************
+static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num)
+{
+       u32 *start;
+       int i;
+
+       start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+
+       for (i = 0; i < num; i++)
+               fsi_reg_write(fsi, DODT, *(start + i));
+}
 
+static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num)
+{
+       u32 *start;
+       int i;
 
-               irq function
+       start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
 
+       for (i = 0; i < num; i++)
+               *(start + i) = fsi_reg_read(fsi, DIDT);
+}
+
+/*
+ *             irq function
+ */
 
-************************************************************************/
 static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
 {
-       u32 data = fsi_port_ab_io_bit(fsi, is_play);
+       u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
        fsi_master_mask_set(master, master->core->imsk,  data, data);
@@ -372,7 +477,7 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
 
 static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
 {
-       u32 data = fsi_port_ab_io_bit(fsi, is_play);
+       u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
        fsi_master_mask_set(master, master->core->imsk,  data, 0);
@@ -394,20 +499,18 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
        u32 data = 0;
        struct fsi_master *master = fsi_get_master(fsi);
 
-       data |= fsi_port_ab_io_bit(fsi, 0);
-       data |= fsi_port_ab_io_bit(fsi, 1);
+       data |= AB_IO(1, fsi_get_port_shift(fsi, 0));
+       data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
 
        /* clear interrupt factor */
        fsi_master_mask_set(master, master->core->int_st, data, 0);
 }
 
-/************************************************************************
-
-
-               SPDIF master clock function
-
-These functions are used later FSI2
-************************************************************************/
+/*
+ *             SPDIF master clock function
+ *
+ * These functions are used later FSI2
+ */
 static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -424,13 +527,10 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
                fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
 }
 
-/************************************************************************
-
-
-               ctrl function
-
+/*
+ *             ctrl function
+ */
 
-************************************************************************/
 static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
@@ -447,14 +547,15 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
                          struct snd_soc_dai *dai)
 {
        struct fsi_master *master = fsi_get_master(fsi);
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        u32 ctrl, shift, i;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
-       shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT;
-       shift &= OUT_SZ_MASK;
-       fsi->fifo_max = 256 << shift;
-       dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max);
+       shift >>= fsi_get_port_shift(fsi, is_play);
+       shift &= FIFO_SZ_MASK;
+       io->fifo_max_num = 256 << shift;
+       dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
 
        /*
         * The maximum number of sample data varies depending
@@ -475,9 +576,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
         * 7 channels:  32 ( 32 x 7 = 224)
         * 8 channels:  32 ( 32 x 8 = 256)
         */
-       for (i = 1; i < fsi->chan; i <<= 1)
-               fsi->fifo_max >>= 1;
-       dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max);
+       for (i = 1; i < io->chan_num; i <<= 1)
+               io->fifo_max_num >>= 1;
+       dev_dbg(dai->dev, "%d channel %d store\n",
+               io->chan_num, io->fifo_max_num);
 
        ctrl = is_play ? DOFF_CTL : DIFF_CTL;
 
@@ -500,84 +602,114 @@ static void fsi_soft_all_reset(struct fsi_master *master)
        mdelay(10);
 }
 
-/* playback interrupt */
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
 {
        struct snd_pcm_runtime *runtime;
        struct snd_pcm_substream *substream = NULL;
-       u32 status;
-       int send;
-       int fifo_free;
-       int width;
-       u8 *start;
-       int i, over_period;
+       int is_play = fsi_stream_is_play(stream);
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       u32 status_reg = is_play ? DOFF_ST : DIFF_ST;
+       int data_residue_num;
+       int data_num;
+       int data_num_max;
+       int ch_width;
+       int over_period;
+       void (*fn)(struct fsi_priv *fsi, int size);
 
        if (!fsi                        ||
-           !fsi->substream             ||
-           !fsi->substream->runtime)
+           !io->substream              ||
+           !io->substream->runtime)
                return -EINVAL;
 
        over_period     = 0;
-       substream       = fsi->substream;
+       substream       = io->substream;
        runtime         = substream->runtime;
 
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
         */
-       if (fsi->byte_offset >=
-           fsi->period_len * (fsi->periods + 1)) {
+       if (io->buff_offset >=
+           fsi_num2offset(io->period_num + 1, io->period_len)) {
 
                over_period = 1;
-               fsi->periods = (fsi->periods + 1) % runtime->periods;
+               io->period_num = (io->period_num + 1) % runtime->periods;
 
-               if (0 == fsi->periods)
-                       fsi->byte_offset = 0;
+               if (0 == io->period_num)
+                       io->buff_offset = 0;
        }
 
        /* get 1 channel data width */
-       width = frames_to_bytes(runtime, 1) / fsi->chan;
-
-       /* get send size for alsa */
-       send = (fsi->buffer_len - fsi->byte_offset) / width;
-
-       /*  get FIFO free size */
-       fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1);
-
-       /* size check */
-       if (fifo_free < send)
-               send = fifo_free;
+       ch_width = fsi_get_frame_width(fsi, is_play);
+
+       /* get residue data number of alsa */
+       data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
+                                      ch_width);
+
+       if (is_play) {
+               /*
+                * for play-back
+                *
+                * data_num_max : number of FSI fifo free space
+                * data_num     : number of ALSA residue data
+                */
+               data_num_max  = io->fifo_max_num * io->chan_num;
+               data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+
+               data_num = data_residue_num;
+
+               switch (ch_width) {
+               case 2:
+                       fn = fsi_dma_soft_push16;
+                       break;
+               case 4:
+                       fn = fsi_dma_soft_push32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               /*
+                * for capture
+                *
+                * data_num_max : number of ALSA free space
+                * data_num     : number of data in FSI fifo
+                */
+               data_num_max = data_residue_num;
+               data_num     = fsi_get_fifo_data_num(fsi, is_play);
+
+               switch (ch_width) {
+               case 2:
+                       fn = fsi_dma_soft_pop16;
+                       break;
+               case 4:
+                       fn = fsi_dma_soft_pop32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
 
-       start = runtime->dma_area;
-       start += fsi->byte_offset;
+       data_num = min(data_num, data_num_max);
 
-       switch (width) {
-       case 2:
-               for (i = 0; i < send; i++)
-                       fsi_reg_write(fsi, DODT,
-                                     ((u32)*((u16 *)start + i) << 8));
-               break;
-       case 4:
-               for (i = 0; i < send; i++)
-                       fsi_reg_write(fsi, DODT, *((u32 *)start + i));
-               break;
-       default:
-               return -EINVAL;
-       }
+       fn(fsi, data_num);
 
-       fsi->byte_offset += send * width;
+       /* update buff_offset */
+       io->buff_offset += fsi_num2offset(data_num, ch_width);
 
-       status = fsi_reg_read(fsi, DOFF_ST);
+       /* check fifo status */
        if (!startup) {
                struct snd_soc_dai *dai = fsi_get_dai(substream);
+               u32 status = fsi_reg_read(fsi, status_reg);
 
                if (status & ERR_OVER)
                        dev_err(dai->dev, "over run\n");
                if (status & ERR_UNDER)
                        dev_err(dai->dev, "under run\n");
        }
-       fsi_reg_write(fsi, DOFF_ST, 0);
+       fsi_reg_write(fsi, status_reg, 0);
 
-       fsi_irq_enable(fsi, 1);
+       /* re-enable irq */
+       fsi_irq_enable(fsi, is_play);
 
        if (over_period)
                snd_pcm_period_elapsed(substream);
@@ -587,85 +719,12 @@ static int fsi_data_push(struct fsi_priv *fsi, int startup)
 
 static int fsi_data_pop(struct fsi_priv *fsi, int startup)
 {
-       struct snd_pcm_runtime *runtime;
-       struct snd_pcm_substream *substream = NULL;
-       u32 status;
-       int free;
-       int fifo_fill;
-       int width;
-       u8 *start;
-       int i, over_period;
-
-       if (!fsi                        ||
-           !fsi->substream             ||
-           !fsi->substream->runtime)
-               return -EINVAL;
-
-       over_period     = 0;
-       substream       = fsi->substream;
-       runtime         = substream->runtime;
-
-       /* FSI FIFO has limit.
-        * So, this driver can not send periods data at a time
-        */
-       if (fsi->byte_offset >=
-           fsi->period_len * (fsi->periods + 1)) {
-
-               over_period = 1;
-               fsi->periods = (fsi->periods + 1) % runtime->periods;
-
-               if (0 == fsi->periods)
-                       fsi->byte_offset = 0;
-       }
-
-       /* get 1 channel data width */
-       width = frames_to_bytes(runtime, 1) / fsi->chan;
-
-       /* get free space for alsa */
-       free = (fsi->buffer_len - fsi->byte_offset) / width;
-
-       /* get recv size */
-       fifo_fill = fsi_get_fifo_residue(fsi, 0);
-
-       if (free < fifo_fill)
-               fifo_fill = free;
-
-       start = runtime->dma_area;
-       start += fsi->byte_offset;
-
-       switch (width) {
-       case 2:
-               for (i = 0; i < fifo_fill; i++)
-                       *((u16 *)start + i) =
-                               (u16)(fsi_reg_read(fsi, DIDT) >> 8);
-               break;
-       case 4:
-               for (i = 0; i < fifo_fill; i++)
-                       *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       fsi->byte_offset += fifo_fill * width;
-
-       status = fsi_reg_read(fsi, DIFF_ST);
-       if (!startup) {
-               struct snd_soc_dai *dai = fsi_get_dai(substream);
-
-               if (status & ERR_OVER)
-                       dev_err(dai->dev, "over run\n");
-               if (status & ERR_UNDER)
-                       dev_err(dai->dev, "under run\n");
-       }
-       fsi_reg_write(fsi, DIFF_ST, 0);
-
-       fsi_irq_enable(fsi, 0);
-
-       if (over_period)
-               snd_pcm_period_elapsed(substream);
+       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+}
 
-       return 0;
+static int fsi_data_push(struct fsi_priv *fsi, int startup)
+{
+       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
 static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -677,13 +736,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        fsi_master_mask_set(master, SOFT_RST, IR, 0);
        fsi_master_mask_set(master, SOFT_RST, IR, IR);
 
-       if (int_st & INT_A_OUT)
+       if (int_st & AB_IO(1, AO_SHIFT))
                fsi_data_push(&master->fsia, 0);
-       if (int_st & INT_B_OUT)
+       if (int_st & AB_IO(1, BO_SHIFT))
                fsi_data_push(&master->fsib, 0);
-       if (int_st & INT_A_IN)
+       if (int_st & AB_IO(1, AI_SHIFT))
                fsi_data_pop(&master->fsia, 0);
-       if (int_st & INT_B_IN)
+       if (int_st & AB_IO(1, BI_SHIFT))
                fsi_data_pop(&master->fsib, 0);
 
        fsi_irq_clear_all_status(master);
@@ -691,25 +750,24 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-/************************************************************************
-
-
-               dai ops
-
+/*
+ *             dai ops
+ */
 
-************************************************************************/
 static int fsi_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       u32 flags = fsi_get_info_flags(fsi);
        struct fsi_master *master = fsi_get_master(fsi);
+       struct fsi_stream *io;
+       u32 flags = fsi_get_info_flags(fsi);
        u32 fmt;
        u32 reg;
        u32 data;
-       int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int is_play = fsi_is_play(substream);
        int is_master;
-       int ret = 0;
+
+       io = fsi_get_stream(fsi, is_play);
 
        pm_runtime_get_sync(dai->dev);
 
@@ -741,29 +799,29 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        switch (fmt) {
        case SH_FSI_FMT_MONO:
                data = CR_MONO;
-               fsi->chan = 1;
+               io->chan_num = 1;
                break;
        case SH_FSI_FMT_MONO_DELAY:
                data = CR_MONO_D;
-               fsi->chan = 1;
+               io->chan_num = 1;
                break;
        case SH_FSI_FMT_PCM:
                data = CR_PCM;
-               fsi->chan = 2;
+               io->chan_num = 2;
                break;
        case SH_FSI_FMT_I2S:
                data = CR_I2S;
-               fsi->chan = 2;
+               io->chan_num = 2;
                break;
        case SH_FSI_FMT_TDM:
-               fsi->chan = is_play ?
+               io->chan_num = is_play ?
                        SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM | (fsi->chan - 1);
+               data = CR_TDM | (io->chan_num - 1);
                break;
        case SH_FSI_FMT_TDM_DELAY:
-               fsi->chan = is_play ?
+               io->chan_num = is_play ?
                        SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM_D | (fsi->chan - 1);
+               data = CR_TDM_D | (io->chan_num - 1);
                break;
        case SH_FSI_FMT_SPDIF:
                if (master->core->ver < 2) {
@@ -771,7 +829,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
                        return -EINVAL;
                }
                data = CR_SPDIF;
-               fsi->chan = 2;
+               io->chan_num = 2;
                fsi_spdif_clk_ctrl(fsi, 1);
                fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
                break;
@@ -788,14 +846,14 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        /* fifo init */
        fsi_fifo_init(fsi, is_play, dai);
 
-       return ret;
+       return 0;
 }
 
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int is_play = fsi_is_play(substream);
 
        fsi_irq_disable(fsi, is_play);
        fsi_clk_ctrl(fsi, 0);
@@ -808,19 +866,19 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int is_play = fsi_is_play(substream);
        int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               fsi_stream_push(fsi, substream,
+               fsi_stream_push(fsi, is_play, substream,
                                frames_to_bytes(runtime, runtime->buffer_size),
                                frames_to_bytes(runtime, runtime->period_size));
                ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                fsi_irq_disable(fsi, is_play);
-               fsi_stream_pop(fsi);
+               fsi_stream_pop(fsi, is_play);
                break;
        }
 
@@ -835,7 +893,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
        struct fsi_master *master = fsi_get_master(fsi);
        int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
        int fsi_ver = master->core->ver;
-       int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int is_play = fsi_is_play(substream);
        int ret;
 
        /* if slave mode, set_rate is not needed */
@@ -916,13 +974,10 @@ static struct snd_soc_dai_ops fsi_dai_ops = {
        .hw_params      = fsi_dai_hw_params,
 };
 
-/************************************************************************
-
-
-               pcm ops
-
+/*
+ *             pcm ops
+ */
 
-************************************************************************/
 static struct snd_pcm_hardware fsi_pcm_hardware = {
        .info =         SNDRV_PCM_INFO_INTERLEAVED      |
                        SNDRV_PCM_INFO_MMAP             |
@@ -971,9 +1026,10 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsi_priv *fsi = fsi_get_priv(substream);
+       struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
        long location;
 
-       location = (fsi->byte_offset - 1);
+       location = (io->buff_offset - 1);
        if (location < 0)
                location = 0;
 
@@ -988,13 +1044,10 @@ static struct snd_pcm_ops fsi_pcm_ops = {
        .pointer        = fsi_pointer,
 };
 
-/************************************************************************
-
-
-               snd_soc_platform
-
+/*
+ *             snd_soc_platform
+ */
 
-************************************************************************/
 #define PREALLOC_BUFFER                (32 * 1024)
 #define PREALLOC_BUFFER_MAX    (32 * 1024)
 
@@ -1018,17 +1071,13 @@ static int fsi_pcm_new(struct snd_card *card,
                PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-/************************************************************************
-
-
-               alsa struct
-
+/*
+ *             alsa struct
+ */
 
-************************************************************************/
-struct snd_soc_dai fsi_soc_dai[] = {
+static struct snd_soc_dai_driver fsi_soc_dai[] = {
        {
-               .name                   = "FSIA",
-               .id                     = 0,
+               .name                   = "fsia-dai",
                .playback = {
                        .rates          = FSI_RATES,
                        .formats        = FSI_FMTS,
@@ -1044,8 +1093,7 @@ struct snd_soc_dai fsi_soc_dai[] = {
                .ops = &fsi_dai_ops,
        },
        {
-               .name                   = "FSIB",
-               .id                     = 1,
+               .name                   = "fsib-dai",
                .playback = {
                        .rates          = FSI_RATES,
                        .formats        = FSI_FMTS,
@@ -1061,23 +1109,17 @@ struct snd_soc_dai fsi_soc_dai[] = {
                .ops = &fsi_dai_ops,
        },
 };
-EXPORT_SYMBOL_GPL(fsi_soc_dai);
 
-struct snd_soc_platform fsi_soc_platform = {
-       .name           = "fsi-pcm",
-       .pcm_ops        = &fsi_pcm_ops,
+static struct snd_soc_platform_driver fsi_soc_platform = {
+       .ops            = &fsi_pcm_ops,
        .pcm_new        = fsi_pcm_new,
        .pcm_free       = fsi_pcm_free,
 };
-EXPORT_SYMBOL_GPL(fsi_soc_platform);
-
-/************************************************************************
-
-
-               platform function
 
+/*
+ *             platform function
+ */
 
-************************************************************************/
 static int fsi_probe(struct platform_device *pdev)
 {
        struct fsi_master *master;
@@ -1132,11 +1174,7 @@ static int fsi_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
-
-       fsi_soc_dai[0].dev              = &pdev->dev;
-       fsi_soc_dai[0].private_data     = &master->fsia;
-       fsi_soc_dai[1].dev              = &pdev->dev;
-       fsi_soc_dai[1].private_data     = &master->fsib;
+       dev_set_drvdata(&pdev->dev, master);
 
        fsi_soft_all_reset(master);
 
@@ -1147,13 +1185,13 @@ static int fsi_probe(struct platform_device *pdev)
                goto exit_iounmap;
        }
 
-       ret = snd_soc_register_platform(&fsi_soc_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
        if (ret < 0) {
                dev_err(&pdev->dev, "cannot snd soc register\n");
                goto exit_free_irq;
        }
 
-       return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
+       return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
 
 exit_free_irq:
        free_irq(irq, master);
@@ -1171,10 +1209,10 @@ static int fsi_remove(struct platform_device *pdev)
 {
        struct fsi_master *master;
 
-       master = fsi_get_master(fsi_soc_dai[0].private_data);
+       master = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
-       snd_soc_unregister_platform(&fsi_soc_platform);
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+       snd_soc_unregister_platform(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
 
@@ -1183,11 +1221,6 @@ static int fsi_remove(struct platform_device *pdev)
        iounmap(master->base);
        kfree(master);
 
-       fsi_soc_dai[0].dev              = NULL;
-       fsi_soc_dai[0].private_data     = NULL;
-       fsi_soc_dai[1].dev              = NULL;
-       fsi_soc_dai[1].private_data     = NULL;
-
        return 0;
 }
 
@@ -1229,11 +1262,13 @@ static struct fsi_core fsi2_core = {
 static struct platform_device_id fsi_id_table[] = {
        { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
        { "sh_fsi2",    (kernel_ulong_t)&fsi2_core },
+       {},
 };
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
 
 static struct platform_driver fsi_driver = {
        .driver         = {
-               .name   = "sh_fsi",
+               .name   = "fsi-pcm-audio",
                .pm     = &fsi_pm_ops,
        },
        .probe          = fsi_probe,
@@ -1250,6 +1285,7 @@ static void __exit fsi_mobile_exit(void)
 {
        platform_driver_unregister(&fsi_driver);
 }
+
 module_init(fsi_mobile_init);
 module_exit(fsi_mobile_exit);
 
index 41db75af3c69d3b64f2420e07acfb2ca3473fa45..c87e3ff28a0a02957bbd37c2de21d96b661e569e 100644 (file)
@@ -239,8 +239,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params,
                         struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+       struct hac_priv *hac = &hac_cpu_data[dai->id];
        int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
 
        switch (params->msbits) {
@@ -271,10 +270,9 @@ static struct snd_soc_dai_ops hac_dai_ops = {
        .hw_params      = hac_hw_params,
 };
 
-struct snd_soc_dai sh4_hac_dai[] = {
+static struct snd_soc_dai_driver sh4_hac_dai[] = {
 {
-       .name                   = "HAC0",
-       .id                     = 0,
+       .name                   = "hac-dai.0",
        .ac97_control           = 1,
        .playback = {
                .rates          = AC97_RATES,
@@ -292,8 +290,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
-       .name                   = "HAC1",
-       .ac97_control           = 1,
+       .name                   = "hac-dai.1",
        .id                     = 1,
        .playback = {
                .rates          = AC97_RATES,
@@ -312,19 +309,40 @@ struct snd_soc_dai sh4_hac_dai[] = {
 },
 #endif
 };
-EXPORT_SYMBOL_GPL(sh4_hac_dai);
 
-static int __init sh4_hac_init(void)
+static int __devinit hac_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
+                       ARRAY_SIZE(sh4_hac_dai));
+}
+
+static int __devexit hac_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+       return 0;
+}
+
+static struct platform_driver hac_pcm_driver = {
+       .driver = {
+                       .name = "hac-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = hac_soc_platform_probe,
+       .remove = __devexit_p(hac_soc_platform_remove),
+};
+
+static int __init sh4_hac_pcm_init(void)
 {
-       return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+       return platform_driver_register(&hac_pcm_driver);
 }
-module_init(sh4_hac_init);
+module_init(sh4_hac_pcm_init);
 
-static void __exit sh4_hac_exit(void)
+static void __exit sh4_hac_pcm_exit(void)
 {
-       snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+       platform_driver_unregister(&hac_pcm_driver);
 }
-module_exit(sh4_hac_exit);
+module_exit(sh4_hac_pcm_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
index 87e2b7fcbf176d9f429506b285dcc2f6ac05d7bc..ac6c49ce6fdf5eb199ebad36b64c9fc159f10d40 100644 (file)
@@ -51,7 +51,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
        unsigned int rate = params_rate(params);
 
@@ -69,7 +69,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
@@ -82,7 +82,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        clk_set_rate(&siumckb_clk, codec_freq);
        dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
 
-       ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT,
+       ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, SIU_CLKB_EXT,
                                     codec_freq / 2, SND_SOC_CLOCK_IN);
 
        if (!ret)
@@ -94,7 +94,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
 static int migor_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        if (use_count) {
                use_count--;
@@ -137,8 +137,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "Mic Bias", NULL, "External Microphone" },
 };
 
-static int migor_dai_init(struct snd_soc_codec *codec)
+static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
                                  ARRAY_SIZE(migor_dapm_widgets));
 
@@ -151,8 +153,10 @@ static int migor_dai_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link migor_dai = {
        .name = "wm8978",
        .stream_name = "WM8978",
-       .cpu_dai = &siu_i2s_dai,
-       .codec_dai = &wm8978_dai,
+       .cpu_dai_name = "siu-i2s-dai",
+       .codec_dai_name = "wm8978-hifi",
+       .platform_name = "siu-pcm-audio",
+       .codec_name = "wm8978.0-001a",
        .ops = &migor_dai_ops,
        .init = migor_dai_init,
 };
@@ -160,17 +164,10 @@ static struct snd_soc_dai_link migor_dai = {
 /* migor audio machine driver */
 static struct snd_soc_card snd_soc_migor = {
        .name = "Migo-R",
-       .platform = &siu_platform,
        .dai_link = &migor_dai,
        .num_links = 1,
 };
 
-/* migor audio subsystem */
-static struct snd_soc_device migor_snd_devdata = {
-       .card = &snd_soc_migor,
-       .codec_dev = &soc_codec_dev_wm8978,
-};
-
 static struct platform_device *migor_snd_device;
 
 static int __init migor_init(void)
@@ -195,9 +192,7 @@ static int __init migor_init(void)
                goto epdevalloc;
        }
 
-       platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
-
-       migor_snd_devdata.dev = &migor_snd_device->dev;
+       platform_set_drvdata(migor_snd_device, &snd_soc_migor);
 
        ret = platform_device_add(migor_snd_device);
        if (ret)
index ce7f95b59de32aa3efe58bd46389ecb1d0b98c5e..b897f7b96d8990bbd0bee2c199bdf4531b9c6840 100644 (file)
 #include <sound/soc-dapm.h>
 #include <asm/io.h>
 
-#include "../codecs/ac97.h"
-
 #define IPSEL 0xFE400034
 
 /* platform specific structs can be declared here */
-extern struct snd_soc_dai sh4_hac_dai[2];
-extern struct snd_soc_platform sh7760_soc_platform;
+extern struct snd_soc_dai_driver sh4_hac_dai[2];
+extern struct snd_soc_platform_driver sh7760_soc_platform;
 
-static int machine_init(struct snd_soc_codec *codec)
+static int machine_init(struct snd_soc_pcm_runtime *rtd)
 {
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(rtd->codec);
        return 0;
 }
 
 static struct snd_soc_dai_link sh7760_ac97_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &sh4_hac_dai[0],     /* HAC0 */
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "hac-dai.0",    /* HAC0 */
+       .codec_dai_name = "ac97-hifi",
+       .platform_name = "sh7760-pcm-audio",
+       .codec_name = "ac97-codec",
        .init = machine_init,
        .ops = NULL,
 };
 
 static struct snd_soc_card sh7760_ac97_soc_machine  = {
        .name = "SH7760 AC97",
-       .platform = &sh7760_soc_platform,
        .dai_link = &sh7760_ac97_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device sh7760_ac97_snd_devdata = {
-       .card = &sh7760_ac97_soc_machine,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *sh7760_ac97_snd_device;
 
 static int __init sh7760_ac97_init(void)
@@ -67,8 +61,7 @@ static int __init sh7760_ac97_init(void)
                goto out;
 
        platform_set_drvdata(sh7760_ac97_snd_device,
-                            &sh7760_ac97_snd_devdata);
-       sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+                            &sh7760_ac97_soc_machine);
        ret = platform_device_add(sh7760_ac97_snd_device);
 
        if (ret)
index 492b1cae24ccb3dcd3b36681866aca923e78752b..9f4dcb921ff027563bab83e0eb720dd96b32b8cd 100644 (file)
@@ -98,7 +98,9 @@ enum {
        SIU_CLKB_EXT
 };
 
+struct device;
 struct siu_info {
+       struct device           *dev;
        int                     port_id;
        u32 __iomem             *pram;
        u32 __iomem             *xram;
@@ -181,8 +183,8 @@ static inline u32 siu_read32(u32 __iomem *addr)
 #define SIU_BRGBSEL    (0x108 / sizeof(u32))
 #define SIU_BRRB       (0x10c / sizeof(u32))
 
-extern struct snd_soc_platform siu_platform;
-extern struct snd_soc_dai siu_i2s_dai;
+extern struct snd_soc_platform_driver siu_platform;
+extern struct siu_info *siu_i2s_data;
 
 int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
 void siu_free_port(struct siu_port *port_info);
index eeed5edd722b2df38e4449f8b8e78d815c4fbcfd..af53b64d8af2ca8b6bda4894b6f091bfbefe5f65 100644 (file)
@@ -71,6 +71,8 @@ struct port_flag {
        struct format_flag      capture;
 };
 
+struct siu_info *siu_i2s_data;
+
 static struct port_flag siu_flags[SIU_PORT_NUM] = {
        [SIU_PORT_A] = {
                .playback = {
@@ -104,13 +106,13 @@ static struct port_flag siu_flags[SIU_PORT_NUM] = {
 
 static void siu_dai_start(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
 
        /* Turn on SIU clock */
-       pm_runtime_get_sync(siu_i2s_dai.dev);
+       pm_runtime_get_sync(info->dev);
 
        /* Issue software reset to siu */
        siu_write32(base + SIU_SRCTL, 0);
@@ -148,21 +150,21 @@ static void siu_dai_start(struct siu_port *port_info)
        siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
 }
 
-static void siu_dai_stop(void)
+static void siu_dai_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        /* SIU software reset */
        siu_write32(base + SIU_SRCTL, 0);
 
        /* Turn off SIU clock */
-       pm_runtime_put_sync(siu_i2s_dai.dev);
+       pm_runtime_put_sync(info->dev);
 }
 
 static void siu_dai_spbAselect(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
        u32 idx;
@@ -187,7 +189,7 @@ static void siu_dai_spbAselect(struct siu_port *port_info)
 
 static void siu_dai_spbBselect(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
        u32 idx;
@@ -207,7 +209,7 @@ static void siu_dai_spbBselect(struct siu_port *port_info)
 
 static void siu_dai_open(struct siu_stream *siu_stream)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 srctl, ifctl;
 
@@ -238,7 +240,7 @@ static void siu_dai_open(struct siu_stream *siu_stream)
  */
 static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 dpak;
 
@@ -258,7 +260,7 @@ static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
 
 static int siu_dai_spbstart(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
@@ -323,7 +325,7 @@ static int siu_dai_spbstart(struct siu_port *port_info)
 
 static void siu_dai_spbstop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        siu_write32(base + SIU_SBACTIV, 0);
@@ -402,7 +404,7 @@ static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
 {
        struct siu_port *port_info = snd_kcontrol_chip(kctrl);
        struct device *dev = port_info->pcm->card->dev;
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 new_vol;
        u32 cur_vol;
@@ -510,7 +512,7 @@ void siu_free_port(struct siu_port *port_info)
 static int siu_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct snd_pcm_runtime *rt = substream->runtime;
        struct siu_port *port_info = siu_port_info(substream);
        int ret;
@@ -532,7 +534,7 @@ static int siu_dai_startup(struct snd_pcm_substream *substream,
 static void siu_dai_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct siu_port *port_info = siu_port_info(substream);
 
        dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
@@ -548,7 +550,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
                /* during stmread or stmwrite ? */
                BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
                siu_dai_spbstop(port_info);
-               siu_dai_stop();
+               siu_dai_stop(port_info);
        }
 }
 
@@ -556,7 +558,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
 static int siu_dai_prepare(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct snd_pcm_runtime *rt = substream->runtime;
        struct siu_port *port_info = siu_port_info(substream);
        struct siu_stream *siu_stream;
@@ -605,7 +607,7 @@ fail:
 static int siu_dai_set_fmt(struct snd_soc_dai *dai,
                           unsigned int fmt)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        u32 __iomem *base = info->reg;
        u32 ifctl;
 
@@ -671,21 +673,37 @@ static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                return -EINVAL;
        }
 
-       siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
-       if (IS_ERR(siu_clk))
+       siu_clk = clk_get(dai->dev, siu_name);
+       if (IS_ERR(siu_clk)) {
+               dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
+                       PTR_ERR(siu_clk));
                return PTR_ERR(siu_clk);
+       }
+
+       parent_clk = clk_get(dai->dev, parent_name);
+       if (IS_ERR(parent_clk)) {
+               ret = PTR_ERR(parent_clk);
+               dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
+               goto epclkget;
+       }
 
-       parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
-       if (!IS_ERR(parent_clk)) {
-               ret = clk_set_parent(siu_clk, parent_clk);
-               if (!ret)
-                       clk_set_rate(siu_clk, freq);
-               clk_put(parent_clk);
+       ret = clk_set_parent(siu_clk, parent_clk);
+       if (ret < 0) {
+               dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
+               goto eclksetp;
        }
 
+       ret = clk_set_rate(siu_clk, freq);
+       if (ret < 0)
+               dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
+
+       /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
+eclksetp:
+       clk_put(parent_clk);
+epclkget:
        clk_put(siu_clk);
 
-       return 0;
+       return ret;
 }
 
 static struct snd_soc_dai_ops siu_dai_ops = {
@@ -696,9 +714,8 @@ static struct snd_soc_dai_ops siu_dai_ops = {
        .set_fmt        = siu_dai_set_fmt,
 };
 
-struct snd_soc_dai siu_i2s_dai = {
-       .name = "sh-siu",
-       .id = 0,
+static struct snd_soc_dai_driver siu_i2s_dai = {
+       .name   = "siu-i2s-dai",
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -713,7 +730,6 @@ struct snd_soc_dai siu_i2s_dai = {
         },
        .ops = &siu_dai_ops,
 };
-EXPORT_SYMBOL_GPL(siu_i2s_dai);
 
 static int __devinit siu_probe(struct platform_device *pdev)
 {
@@ -725,6 +741,8 @@ static int __devinit siu_probe(struct platform_device *pdev)
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
+       siu_i2s_data = info;
+       info->dev = &pdev->dev;
 
        ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
        if (ret)
@@ -767,14 +785,14 @@ static int __devinit siu_probe(struct platform_device *pdev)
        if (!info->reg)
                goto emapreg;
 
-       siu_i2s_dai.dev = &pdev->dev;
-       siu_i2s_dai.private_data = info;
+       dev_set_drvdata(&pdev->dev, info);
 
-       ret = snd_soc_register_dais(&siu_i2s_dai, 1);
+       /* register using ARRAY version so we can keep dai name */
+       ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
        if (ret < 0)
                goto edaiinit;
 
-       ret = snd_soc_register_platform(&siu_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
        if (ret < 0)
                goto esocregp;
 
@@ -783,7 +801,7 @@ static int __devinit siu_probe(struct platform_device *pdev)
        return ret;
 
 esocregp:
-       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+       snd_soc_unregister_dai(&pdev->dev);
 edaiinit:
        iounmap(info->reg);
 emapreg:
@@ -804,13 +822,13 @@ ereqfw:
 
 static int __devexit siu_remove(struct platform_device *pdev)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = dev_get_drvdata(&pdev->dev);
        struct resource *res;
 
        pm_runtime_disable(&pdev->dev);
 
-       snd_soc_unregister_platform(&siu_platform);
-       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_dai(&pdev->dev);
 
        iounmap(info->reg);
        iounmap(info->yram);
@@ -826,7 +844,8 @@ static int __devexit siu_remove(struct platform_device *pdev)
 
 static struct platform_driver siu_driver = {
        .driver         = {
-               .name   = "sh_siu",
+               .owner  = THIS_MODULE,
+               .name   = "siu-pcm-audio",
        },
        .probe          = siu_probe,
        .remove         = __devexit_p(siu_remove),
index 36170be15aa7453cfacf00505d18d162b369ca32..ed29c9e1ed4efe764ad7a06d448e58386201efcb 100644 (file)
@@ -48,7 +48,7 @@ struct siu_port *siu_ports[SIU_PORT_NUM];
 /* transfersize is number of u32 dma transfers per period */
 static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        u32 stfifo;
@@ -114,7 +114,7 @@ static void siu_dma_tx_complete(void *arg)
 static int siu_pcm_wr_set(struct siu_port *port_info,
                          dma_addr_t buff, u32 size)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        struct snd_pcm_substream *substream = siu_stream->substream;
@@ -127,6 +127,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
        sg_init_table(&sg, 1);
        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
                    size, offset_in_page(buff));
+       sg_dma_len(&sg) = size;
        sg_dma_address(&sg) = buff;
 
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@ -161,7 +162,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
 static int siu_pcm_rd_set(struct siu_port *port_info,
                          dma_addr_t buff, size_t size)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct snd_pcm_substream *substream = siu_stream->substream;
@@ -176,6 +177,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
        sg_init_table(&sg, 1);
        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
                    size, offset_in_page(buff));
+       sg_dma_len(&sg) = size;
        sg_dma_address(&sg) = buff;
 
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@ -270,7 +272,7 @@ static int siu_pcm_stmread_start(struct siu_port *port_info)
 
 static int siu_pcm_stmread_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct device *dev = siu_stream->substream->pcm->card->dev;
@@ -294,7 +296,7 @@ static int siu_pcm_stmread_stop(struct siu_port *port_info)
 static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
                             struct snd_pcm_hw_params *hw_params)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        int ret;
 
@@ -309,7 +311,7 @@ static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
 
 static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct siu_stream *siu_stream;
@@ -340,11 +342,12 @@ static bool filter(struct dma_chan *chan, void *slave)
 static int siu_pcm_open(struct snd_pcm_substream *ss)
 {
        /* Playback / Capture */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+       struct siu_platform *pdata = rtd->platform->dev->platform_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
        u32 port = info->port_id;
-       struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
        struct device *dev = ss->pcm->card->dev;
        dma_cap_mask_t mask;
        struct sh_dmae_slave *param;
@@ -381,7 +384,7 @@ static int siu_pcm_open(struct snd_pcm_substream *ss)
 
 static int siu_pcm_close(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
@@ -403,7 +406,7 @@ static int siu_pcm_close(struct snd_pcm_substream *ss)
 
 static int siu_pcm_prepare(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct snd_pcm_runtime  *rt = ss->runtime;
@@ -449,7 +452,7 @@ static int siu_pcm_prepare(struct snd_pcm_substream *ss)
 
 static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        int ret;
@@ -492,7 +495,7 @@ static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
 static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
 {
        struct device *dev = ss->pcm->card->dev;
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_port *port_info = siu_port_info(ss);
        struct snd_pcm_runtime *rt = ss->runtime;
@@ -528,7 +531,7 @@ static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                       struct snd_pcm *pcm)
 {
        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct platform_device *pdev = to_platform_device(card->dev);
        int ret;
        int i;
@@ -605,9 +608,8 @@ static struct snd_pcm_ops siu_pcm_ops = {
        .pointer        = siu_pcm_pointer_dma,
 };
 
-struct snd_soc_platform siu_platform = {
-       .name           = "siu-audio",
-       .pcm_ops        = &siu_pcm_ops,
+struct snd_soc_platform_driver siu_platform = {
+       .ops                    = &siu_pcm_ops,
        .pcm_new        = siu_pcm_new,
        .pcm_free       = siu_pcm_free,
 };
index b378096cadb1566e4e6dad55ae94cf7c0f6e9e25..40bbdf1591dca351631f8bdbbcc5f514e9c99139 100644 (file)
@@ -92,8 +92,7 @@ struct ssi_priv {
 static int ssi_startup(struct snd_pcm_substream *substream,
                       struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        if (ssi->inuse) {
                pr_debug("ssi: already in use!\n");
                return -EBUSY;
@@ -105,8 +104,7 @@ static int ssi_startup(struct snd_pcm_substream *substream,
 static void ssi_shutdown(struct snd_pcm_substream *substream,
                         struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
 
        ssi->inuse = 0;
 }
@@ -114,8 +112,7 @@ static void ssi_shutdown(struct snd_pcm_substream *substream,
 static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                       struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -135,8 +132,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params,
                         struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        unsigned long ssicr = SSIREG(SSICR);
        unsigned int bits, channels, swl, recv, i;
 
@@ -346,10 +342,9 @@ static struct snd_soc_dai_ops ssi_dai_ops = {
        .set_fmt        = ssi_set_fmt,
 };
 
-struct snd_soc_dai sh4_ssi_dai[] = {
+struct snd_soc_dai_driver sh4_ssi_dai[] = {
 {
-       .name                   = "SSI0",
-       .id                     = 0,
+       .name                   = "ssi-dai.0",
        .playback = {
                .rates          = SSI_RATES,
                .formats        = SSI_FMTS,
@@ -366,8 +361,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
-       .name                   = "SSI1",
-       .id                     = 1,
+       .name                   = "ssi-dai.1",
        .playback = {
                .rates          = SSI_RATES,
                .formats        = SSI_FMTS,
@@ -384,19 +378,40 @@ struct snd_soc_dai sh4_ssi_dai[] = {
 },
 #endif
 };
-EXPORT_SYMBOL_GPL(sh4_ssi_dai);
 
-static int __init sh4_ssi_init(void)
+static int __devinit sh4_soc_dai_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
+                       ARRAY_SIZE(sh4_ssi_dai));
+}
+
+static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+       return 0;
+}
+
+static struct platform_driver sh4_ssi_driver = {
+       .driver = {
+                       .name = "sh4-ssi-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = sh4_soc_dai_probe,
+       .remove = __devexit_p(sh4_soc_dai_remove),
+};
+
+static int __init snd_sh4_ssi_init(void)
 {
-       return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+       return platform_driver_register(&sh4_ssi_driver);
 }
-module_init(sh4_ssi_init);
+module_init(snd_sh4_ssi_init);
 
-static void __exit sh4_ssi_exit(void)
+static void __exit snd_sh4_ssi_exit(void)
 {
-       snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+       platform_driver_unregister(&sh4_ssi_driver);
 }
-module_exit(sh4_ssi_exit);
+module_exit(snd_sh4_ssi_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
index f6b0d2829ea96d438d1e84550272c6a7bda80b4c..d214f02cbb65a46314a121948525cb2b005734e1 100644 (file)
@@ -19,8 +19,15 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -31,13 +38,12 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[2];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg << 4) | ((value >> 8) & 0x000f);
        data[1] = value & 0x00ff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -89,8 +95,15 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -101,13 +114,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[2];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg << 1) | ((value >> 8) & 0x0001);
        data[1] = value & 0x00ff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -161,14 +173,13 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 *cache = codec->reg_cache;
        u8 data[2];
 
-       BUG_ON(codec->volatile_register);
-
        reg &= 0xff;
        data[0] = reg;
        data[1] = value & 0xff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -187,12 +198,49 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u8 *cache = codec->reg_cache;
+
        reg &= 0xff;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_8_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_8_8_spi_write NULL
+#endif
+
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
@@ -203,9 +251,9 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg)
-               && reg < codec->reg_cache_size)
-                       reg_cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+           reg < codec->driver->reg_cache_size)
+               reg_cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -225,10 +273,10 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
 {
        u16 *cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size ||
+       if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
-                       return -EINVAL;
+                       return -1;
 
                return codec->hw_read(codec, reg);
        } else {
@@ -236,6 +284,37 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
        }
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_16_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[3];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+       msg[2] = data[2];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_8_16_spi_write NULL
+#endif
+
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
@@ -344,8 +423,14 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
        u8 *cache = codec->reg_cache;
 
        reg &= 0xff;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -356,15 +441,14 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[3];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = value;
 
        reg &= 0xff;
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -452,10 +536,10 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 {
        u16 *cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size ||
+       if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
-                       return -EINVAL;
+                       return -1;
 
                return codec->hw_read(codec, reg);
        }
@@ -475,8 +559,9 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[2] = (value >> 8) & 0xff;
        data[3] = value & 0xff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -494,6 +579,38 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_16_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[4];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+       msg[2] = data[2];
+       msg[3] = data[3];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_16_16_spi_write NULL
+#endif
+
 static struct {
        int addr_bits;
        int data_bits;
@@ -516,11 +633,13 @@ static struct {
                .addr_bits = 8, .data_bits = 8,
                .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
                .i2c_read = snd_soc_8_8_read_i2c,
+               .spi_write = snd_soc_8_8_spi_write,
        },
        {
                .addr_bits = 8, .data_bits = 16,
                .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
                .i2c_read = snd_soc_8_16_read_i2c,
+               .spi_write = snd_soc_8_16_spi_write,
        },
        {
                .addr_bits = 16, .data_bits = 8,
@@ -532,6 +651,7 @@ static struct {
                .addr_bits = 16, .data_bits = 16,
                .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
                .i2c_read = snd_soc_16_16_read_i2c,
+               .spi_write = snd_soc_16_16_spi_write,
        },
 };
 
@@ -572,8 +692,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                return -EINVAL;
        }
 
-       codec->write = io_types[i].write;
-       codec->read = io_types[i].read;
+       codec->driver->write = io_types[i].write;
+       codec->driver->read = io_types[i].read;
 
        switch (control) {
        case SND_SOC_CUSTOM:
@@ -585,11 +705,19 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 #endif
                if (io_types[i].i2c_read)
                        codec->hw_read = io_types[i].i2c_read;
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct i2c_client,
+                                                  dev);
                break;
 
        case SND_SOC_SPI:
                if (io_types[i].spi_write)
                        codec->hw_write = io_types[i].spi_write;
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct spi_device,
+                                                  dev);
                break;
        }
 
index 4057d35343bbbbd434e6a2f99bf0398aeac2a75e..1c8f3f507f54e7d1fc469ff03a2fdbf787640e3a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
  *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
@@ -37,6 +39,8 @@
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
+#define NAME_SIZE      32
+
 static DEFINE_MUTEX(pcm_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
 
@@ -52,6 +56,7 @@ static LIST_HEAD(codec_list);
 
 static int snd_soc_register_card(struct snd_soc_card *card);
 static int snd_soc_unregister_card(struct snd_soc_card *card);
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -86,30 +91,30 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 {
        int ret, i, step = 1, count = 0;
 
-       if (!codec->reg_cache_size)
+       if (!codec->driver->reg_cache_size)
                return 0;
 
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
+       if (codec->driver->reg_cache_step)
+               step = codec->driver->reg_cache_step;
 
        count += sprintf(buf, "%s registers\n", codec->name);
-       for (i = 0; i < codec->reg_cache_size; i += step) {
-               if (codec->readable_register && !codec->readable_register(i))
+       for (i = 0; i < codec->driver->reg_cache_size; i += step) {
+               if (codec->driver->readable_register && !codec->driver->readable_register(i))
                        continue;
 
                count += sprintf(buf + count, "%2x: ", i);
                if (count >= PAGE_SIZE - 1)
                        break;
 
-               if (codec->display_register) {
-                       count += codec->display_register(codec, buf + count,
+               if (codec->driver->display_register) {
+                       count += codec->driver->display_register(codec, buf + count,
                                                         PAGE_SIZE - count, i);
                } else {
                        /* If the read fails it's almost certainly due to
                         * the register being volatile and the device being
                         * powered off.
                         */
-                       ret = codec->read(codec, i);
+                       ret = codec->driver->read(codec, i);
                        if (ret >= 0)
                                count += snprintf(buf + count,
                                                  PAGE_SIZE - count,
@@ -137,8 +142,10 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       return soc_codec_reg_show(devdata->card->codec, buf);
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+
+       return soc_codec_reg_show(rtd->codec, buf);
 }
 
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -146,20 +153,20 @@ static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
 static ssize_t pmdown_time_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *socdev = dev_get_drvdata(dev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
 
-       return sprintf(buf, "%ld\n", card->pmdown_time);
+       return sprintf(buf, "%ld\n", rtd->pmdown_time);
 }
 
 static ssize_t pmdown_time_set(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct snd_soc_device *socdev = dev_get_drvdata(dev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
 
-       strict_strtol(buf, 10, &card->pmdown_time);
+       strict_strtol(buf, 10, &rtd->pmdown_time);
 
        return count;
 }
@@ -203,19 +210,19 @@ static ssize_t codec_reg_write_file(struct file *file,
                return -EFAULT;
        buf[buf_size] = 0;
 
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
+       if (codec->driver->reg_cache_step)
+               step = codec->driver->reg_cache_step;
 
        while (*start == ' ')
                start++;
        reg = simple_strtoul(start, &start, 16);
-       if ((reg >= codec->reg_cache_size) || (reg % step))
+       if ((reg >= codec->driver->reg_cache_size) || (reg % step))
                return -EINVAL;
        while (*start == ' ')
                start++;
        if (strict_strtoul(start, 16, &value))
                return -EINVAL;
-       codec->write(codec, reg, value);
+       codec->driver->write(codec, reg, value);
        return buf_size;
 }
 
@@ -228,16 +235,7 @@ static const struct file_operations codec_reg_fops = {
 
 static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
 {
-       char codec_root[128];
-
-       if (codec->dev)
-               snprintf(codec_root, sizeof(codec_root),
-                       "%s.%s", codec->name, dev_name(codec->dev));
-       else
-               snprintf(codec_root, sizeof(codec_root),
-                       "%s", codec->name);
-
-       codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+       codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
                                                       debugfs_root);
        if (!codec->debugfs_codec_root) {
                printk(KERN_WARNING
@@ -273,6 +271,106 @@ static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
        debugfs_remove_recursive(codec->debugfs_codec_root);
 }
 
+static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_codec *codec;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(codec, &codec_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              codec->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations codec_list_fops = {
+       .read = codec_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_dai *dai;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(dai, &dai_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations dai_list_fops = {
+       .read = dai_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t platform_list_read_file(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_platform *platform;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(platform, &platform_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              platform->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations platform_list_fops = {
+       .read = platform_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
 #else
 
 static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@ -306,7 +404,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
        codec->ac97->dev.release = soc_ac97_device_release;
 
        dev_set_name(&codec->ac97->dev, "%d-%d:%s",
-                    codec->card->number, 0, codec->name);
+                    codec->card->snd_card->number, 0, codec->name);
        err = device_register(&codec->ac97->dev);
        if (err < 0) {
                snd_printk(KERN_ERR "Can't register ac97 bus\n");
@@ -320,24 +418,21 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
-           machine->symmetric_rates) {
-               dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
-                       machine->rate);
+       if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
+                       rtd->dai_link->symmetric_rates) {
+               dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
+                               rtd->rate);
 
                ret = snd_pcm_hw_constraint_minmax(substream->runtime,
                                                   SNDRV_PCM_HW_PARAM_RATE,
-                                                  machine->rate,
-                                                  machine->rate);
+                                                  rtd->rate,
+                                                  rtd->rate);
                if (ret < 0) {
-                       dev_err(card->dev,
+                       dev_err(&rtd->dev,
                                "Unable to apply rate symmetry constraint: %d\n", ret);
                        return ret;
                }
@@ -354,20 +449,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
 static int soc_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+       struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
        /* startup the audio subsystem */
-       if (cpu_dai->ops->startup) {
-               ret = cpu_dai->ops->startup(substream, cpu_dai);
+       if (cpu_dai->driver->ops->startup) {
+               ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open interface %s\n",
                                cpu_dai->name);
@@ -375,16 +469,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (platform->pcm_ops->open) {
-               ret = platform->pcm_ops->open(substream);
+       if (platform->driver->ops->open) {
+               ret = platform->driver->ops->open(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
                        goto platform_err;
                }
        }
 
-       if (codec_dai->ops->startup) {
-               ret = codec_dai->ops->startup(substream, codec_dai);
+       if (codec_dai->driver->ops->startup) {
+               ret = codec_dai->driver->ops->startup(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open codec %s\n",
                                codec_dai->name);
@@ -392,10 +486,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (machine->ops && machine->ops->startup) {
-               ret = machine->ops->startup(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+               ret = rtd->dai_link->ops->startup(substream);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+                       printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
                        goto machine_err;
                }
        }
@@ -403,50 +497,50 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        /* Check that the codec and cpu DAI's are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
-                       max(codec_dai->playback.rate_min,
-                           cpu_dai->playback.rate_min);
+                       max(codec_dai_drv->playback.rate_min,
+                           cpu_dai_drv->playback.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->playback.rate_max,
-                           cpu_dai->playback.rate_max);
+                       min(codec_dai_drv->playback.rate_max,
+                           cpu_dai_drv->playback.rate_max);
                runtime->hw.channels_min =
-                       max(codec_dai->playback.channels_min,
-                               cpu_dai->playback.channels_min);
+                       max(codec_dai_drv->playback.channels_min,
+                               cpu_dai_drv->playback.channels_min);
                runtime->hw.channels_max =
-                       min(codec_dai->playback.channels_max,
-                               cpu_dai->playback.channels_max);
+                       min(codec_dai_drv->playback.channels_max,
+                               cpu_dai_drv->playback.channels_max);
                runtime->hw.formats =
-                       codec_dai->playback.formats & cpu_dai->playback.formats;
+                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
                runtime->hw.rates =
-                       codec_dai->playback.rates & cpu_dai->playback.rates;
-               if (codec_dai->playback.rates
+                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
+               if (codec_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai->playback.rates;
-               if (cpu_dai->playback.rates
+                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
+               if (cpu_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai->playback.rates;
+                       runtime->hw.rates |= codec_dai_drv->playback.rates;
        } else {
                runtime->hw.rate_min =
-                       max(codec_dai->capture.rate_min,
-                           cpu_dai->capture.rate_min);
+                       max(codec_dai_drv->capture.rate_min,
+                           cpu_dai_drv->capture.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->capture.rate_max,
-                           cpu_dai->capture.rate_max);
+                       min(codec_dai_drv->capture.rate_max,
+                           cpu_dai_drv->capture.rate_max);
                runtime->hw.channels_min =
-                       max(codec_dai->capture.channels_min,
-                               cpu_dai->capture.channels_min);
+                       max(codec_dai_drv->capture.channels_min,
+                               cpu_dai_drv->capture.channels_min);
                runtime->hw.channels_max =
-                       min(codec_dai->capture.channels_max,
-                               cpu_dai->capture.channels_max);
+                       min(codec_dai_drv->capture.channels_max,
+                               cpu_dai_drv->capture.channels_max);
                runtime->hw.formats =
-                       codec_dai->capture.formats & cpu_dai->capture.formats;
+                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
                runtime->hw.rates =
-                       codec_dai->capture.rates & cpu_dai->capture.rates;
-               if (codec_dai->capture.rates
+                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
+               if (codec_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai->capture.rates;
-               if (cpu_dai->capture.rates
+                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
+               if (cpu_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai->capture.rates;
+                       runtime->hw.rates |= codec_dai_drv->capture.rates;
        }
 
        snd_pcm_limit_hw_rates(runtime);
@@ -462,7 +556,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
-                       codec_dai->name, cpu_dai->name);
+                               codec_dai->name, cpu_dai->name);
                goto config_err;
        }
 
@@ -473,7 +567,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                        goto config_err;
        }
 
-       pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
+       pr_debug("asoc: %s <-> %s info:\n",
+                       codec_dai->name, cpu_dai->name);
        pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
        pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
                 runtime->hw.channels_max);
@@ -481,33 +576,33 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                 runtime->hw.rate_max);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback.active++;
-               codec_dai->playback.active++;
+               cpu_dai->playback_active++;
+               codec_dai->playback_active++;
        } else {
-               cpu_dai->capture.active++;
-               codec_dai->capture.active++;
+               cpu_dai->capture_active++;
+               codec_dai->capture_active++;
        }
        cpu_dai->active++;
        codec_dai->active++;
-       card->codec->active++;
+       rtd->codec->active++;
        mutex_unlock(&pcm_mutex);
        return 0;
 
 config_err:
-       if (machine->ops && machine->ops->shutdown)
-               machine->ops->shutdown(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
 
 machine_err:
-       if (codec_dai->ops->shutdown)
-               codec_dai->ops->shutdown(substream, codec_dai);
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
 
 codec_dai_err:
-       if (platform->pcm_ops->close)
-               platform->pcm_ops->close(substream);
+       if (platform->driver->ops->close)
+               platform->driver->ops->close(substream);
 
 platform_err:
-       if (cpu_dai->ops->shutdown)
-               cpu_dai->ops->shutdown(substream, cpu_dai);
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -520,29 +615,25 @@ out:
  */
 static void close_delayed_work(struct work_struct *work)
 {
-       struct snd_soc_card *card = container_of(work, struct snd_soc_card,
-                                                delayed_work.work);
-       struct snd_soc_codec *codec = card->codec;
-       struct snd_soc_dai *codec_dai;
-       int i;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        mutex_lock(&pcm_mutex);
-       for (i = 0; i < codec->num_dai; i++) {
-               codec_dai = &codec->dai[i];
-
-               pr_debug("pop wq checking: %s status: %s waiting: %s\n",
-                        codec_dai->playback.stream_name,
-                        codec_dai->playback.active ? "active" : "inactive",
-                        codec_dai->pop_wait ? "yes" : "no");
-
-               /* are we waiting on this codec DAI stream */
-               if (codec_dai->pop_wait == 1) {
-                       codec_dai->pop_wait = 0;
-                       snd_soc_dapm_stream_event(codec,
-                               codec_dai->playback.stream_name,
-                               SND_SOC_DAPM_STREAM_STOP);
-               }
+
+       pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+                codec_dai->driver->playback.stream_name,
+                codec_dai->playback_active ? "active" : "inactive",
+                codec_dai->pop_wait ? "yes" : "no");
+
+       /* are we waiting on this codec DAI stream */
+       if (codec_dai->pop_wait == 1) {
+               codec_dai->pop_wait = 0;
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->playback.stream_name,
+                       SND_SOC_DAPM_STREAM_STOP);
        }
+
        mutex_unlock(&pcm_mutex);
 }
 
@@ -554,22 +645,19 @@ static void close_delayed_work(struct work_struct *work)
 static int soc_codec_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
 
        mutex_lock(&pcm_mutex);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback.active--;
-               codec_dai->playback.active--;
+               cpu_dai->playback_active--;
+               codec_dai->playback_active--;
        } else {
-               cpu_dai->capture.active--;
-               codec_dai->capture.active--;
+               cpu_dai->capture_active--;
+               codec_dai->capture_active--;
        }
 
        cpu_dai->active--;
@@ -582,27 +670,28 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                snd_soc_dai_digital_mute(codec_dai, 1);
 
-       if (cpu_dai->ops->shutdown)
-               cpu_dai->ops->shutdown(substream, cpu_dai);
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 
-       if (codec_dai->ops->shutdown)
-               codec_dai->ops->shutdown(substream, codec_dai);
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
 
-       if (machine->ops && machine->ops->shutdown)
-               machine->ops->shutdown(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
 
-       if (platform->pcm_ops->close)
-               platform->pcm_ops->close(substream);
+       if (platform->driver->ops->close)
+               platform->driver->ops->close(substream);
+       cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* start delayed pop wq here for playback streams */
                codec_dai->pop_wait = 1;
-               schedule_delayed_work(&card->delayed_work,
-                       msecs_to_jiffies(card->pmdown_time));
+               schedule_delayed_work(&rtd->delayed_work,
+                       msecs_to_jiffies(rtd->pmdown_time));
        } else {
                /* capture streams can be powered down now */
-               snd_soc_dapm_stream_event(codec,
-                       codec_dai->capture.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->capture.stream_name,
                        SND_SOC_DAPM_STREAM_STOP);
        }
 
@@ -618,43 +707,39 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
 static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
-       if (machine->ops && machine->ops->prepare) {
-               ret = machine->ops->prepare(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+               ret = rtd->dai_link->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine prepare error\n");
                        goto out;
                }
        }
 
-       if (platform->pcm_ops->prepare) {
-               ret = platform->pcm_ops->prepare(substream);
+       if (platform->driver->ops->prepare) {
+               ret = platform->driver->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform prepare error\n");
                        goto out;
                }
        }
 
-       if (codec_dai->ops->prepare) {
-               ret = codec_dai->ops->prepare(substream, codec_dai);
+       if (codec_dai->driver->ops->prepare) {
+               ret = codec_dai->driver->ops->prepare(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: codec DAI prepare error\n");
                        goto out;
                }
        }
 
-       if (cpu_dai->ops->prepare) {
-               ret = cpu_dai->ops->prepare(substream, cpu_dai);
+       if (cpu_dai->driver->ops->prepare) {
+               ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: cpu DAI prepare error\n");
                        goto out;
@@ -665,16 +750,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            codec_dai->pop_wait) {
                codec_dai->pop_wait = 0;
-               cancel_delayed_work(&card->delayed_work);
+               cancel_delayed_work(&rtd->delayed_work);
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_dapm_stream_event(codec,
-                                         codec_dai->playback.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->playback.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
        else
-               snd_soc_dapm_stream_event(codec,
-                                         codec_dai->capture.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->capture.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
 
        snd_soc_dai_digital_mute(codec_dai, 0);
@@ -693,26 +778,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
-       if (machine->ops && machine->ops->hw_params) {
-               ret = machine->ops->hw_params(substream, params);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+               ret = rtd->dai_link->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine hw_params failed\n");
                        goto out;
                }
        }
 
-       if (codec_dai->ops->hw_params) {
-               ret = codec_dai->ops->hw_params(substream, params, codec_dai);
+       if (codec_dai->driver->ops->hw_params) {
+               ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't set codec %s hw params\n",
                                codec_dai->name);
@@ -720,8 +802,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (cpu_dai->ops->hw_params) {
-               ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
+       if (cpu_dai->driver->ops->hw_params) {
+               ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: interface %s hw params failed\n",
                                cpu_dai->name);
@@ -729,8 +811,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (platform->pcm_ops->hw_params) {
-               ret = platform->pcm_ops->hw_params(substream, params);
+       if (platform->driver->ops->hw_params) {
+               ret = platform->driver->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform %s hw params failed\n",
                                platform->name);
@@ -738,23 +820,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       machine->rate = params_rate(params);
+       rtd->rate = params_rate(params);
 
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
 
 platform_err:
-       if (cpu_dai->ops->hw_free)
-               cpu_dai->ops->hw_free(substream, cpu_dai);
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
 interface_err:
-       if (codec_dai->ops->hw_free)
-               codec_dai->ops->hw_free(substream, codec_dai);
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
 
 codec_err:
-       if (machine->ops && machine->ops->hw_free)
-               machine->ops->hw_free(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
 
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -766,13 +848,10 @@ codec_err:
 static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -781,19 +860,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
                snd_soc_dai_digital_mute(codec_dai, 1);
 
        /* free any machine hw params */
-       if (machine->ops && machine->ops->hw_free)
-               machine->ops->hw_free(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
 
        /* free any DMA resources */
-       if (platform->pcm_ops->hw_free)
-               platform->pcm_ops->hw_free(substream);
+       if (platform->driver->ops->hw_free)
+               platform->driver->ops->hw_free(substream);
 
        /* now free hw params for the DAI's  */
-       if (codec_dai->ops->hw_free)
-               codec_dai->ops->hw_free(substream, codec_dai);
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
 
-       if (cpu_dai->ops->hw_free)
-               cpu_dai->ops->hw_free(substream, cpu_dai);
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
        mutex_unlock(&pcm_mutex);
        return 0;
@@ -802,28 +881,25 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card= socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       if (codec_dai->ops->trigger) {
-               ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
+       if (codec_dai->driver->ops->trigger) {
+               ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
                if (ret < 0)
                        return ret;
        }
 
-       if (platform->pcm_ops->trigger) {
-               ret = platform->pcm_ops->trigger(substream, cmd);
+       if (platform->driver->ops->trigger) {
+               ret = platform->driver->ops->trigger(substream, cmd);
                if (ret < 0)
                        return ret;
        }
 
-       if (cpu_dai->ops->trigger) {
-               ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
+       if (cpu_dai->driver->ops->trigger) {
+               ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
                if (ret < 0)
                        return ret;
        }
@@ -838,27 +914,24 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t offset = 0;
        snd_pcm_sframes_t delay = 0;
 
-       if (platform->pcm_ops->pointer)
-               offset = platform->pcm_ops->pointer(substream);
+       if (platform->driver->ops->pointer)
+               offset = platform->driver->ops->pointer(substream);
 
-       if (cpu_dai->ops->delay)
-               delay += cpu_dai->ops->delay(substream, cpu_dai);
+       if (cpu_dai->driver->ops->delay)
+               delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
 
-       if (codec_dai->ops->delay)
-               delay += codec_dai->ops->delay(substream, codec_dai);
+       if (codec_dai->driver->ops->delay)
+               delay += codec_dai->driver->ops->delay(substream, codec_dai);
 
-       if (platform->delay)
-               delay += platform->delay(substream, codec_dai);
+       if (platform->driver->delay)
+               delay += platform->driver->delay(substream, codec_dai);
 
        runtime->delay = delay;
 
@@ -881,104 +954,111 @@ static struct snd_pcm_ops soc_pcm_ops = {
 static int soc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
 
        /* If the initialization of this soc device failed, there is no codec
         * associated with it. Just bail out in this case.
         */
-       if (!codec)
+       if (list_empty(&card->codec_dev_list))
                return 0;
 
        /* Due to the resume being scheduled into a workqueue we could
        * suspend before that's finished - wait for it to complete.
         */
-       snd_power_lock(codec->card);
-       snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
-       snd_power_unlock(codec->card);
+       snd_power_lock(card->snd_card);
+       snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
+       snd_power_unlock(card->snd_card);
 
        /* we're going to block userspace touching us until resume completes */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
        /* mute any active DAC's */
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+               struct snd_soc_dai_driver *drv = dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (dai->ops->digital_mute && dai->playback.active)
-                       dai->ops->digital_mute(dai, 1);
+               if (drv->ops->digital_mute && dai->playback_active)
+                       drv->ops->digital_mute(dai, 1);
        }
 
        /* suspend all pcms */
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].ignore_suspend)
+       for (i = 0; i < card->num_rtd; i++) {
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               snd_pcm_suspend_all(card->dai_link[i].pcm);
+               snd_pcm_suspend_all(card->rtd[i].pcm);
        }
 
        if (card->suspend_pre)
                card->suspend_pre(pdev, PMSG_SUSPEND);
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai  *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               struct snd_soc_platform *platform = card->rtd[i].platform;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->suspend && !cpu_dai->ac97_control)
-                       cpu_dai->suspend(cpu_dai);
-               if (platform->suspend)
-                       platform->suspend(&card->dai_link[i]);
+               if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->suspend(cpu_dai);
+               if (platform->driver->suspend && !platform->suspended) {
+                       platform->driver->suspend(cpu_dai);
+                       platform->suspended = 1;
+               }
        }
 
        /* close any waiting streams and save state */
-       run_delayed_work(&card->delayed_work);
-       codec->suspend_bias_level = codec->bias_level;
+       for (i = 0; i < card->num_rtd; i++) {
+               run_delayed_work(&card->rtd[i].delayed_work);
+               card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
+       }
 
-       for (i = 0; i < codec->num_dai; i++) {
-               char *stream = codec->dai[i].playback.stream_name;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+               if (driver->playback.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
-               stream = codec->dai[i].capture.stream_name;
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+
+               if (driver->capture.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
        }
 
-       /* If there are paths active then the CODEC will be held with
-        * bias _ON and should not be suspended. */
-       if (codec_dev->suspend) {
-               switch (codec->bias_level) {
-               case SND_SOC_BIAS_STANDBY:
-               case SND_SOC_BIAS_OFF:
-                       codec_dev->suspend(pdev, PMSG_SUSPEND);
-                       break;
-               default:
-                       dev_dbg(socdev->dev, "CODEC is on over suspend\n");
-                       break;
+       /* suspend all CODECs */
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_codec *codec = card->rtd[i].codec;
+               /* If there are paths active then the CODEC will be held with
+                * bias _ON and should not be suspended. */
+               if (!codec->suspended && codec->driver->suspend) {
+                       switch (codec->bias_level) {
+                       case SND_SOC_BIAS_STANDBY:
+                       case SND_SOC_BIAS_OFF:
+                               codec->driver->suspend(codec, PMSG_SUSPEND);
+                               codec->suspended = 1;
+                               break;
+                       default:
+                               dev_dbg(codec->dev, "CODEC is on over suspend\n");
+                               break;
+                       }
                }
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->suspend && cpu_dai->ac97_control)
-                       cpu_dai->suspend(cpu_dai);
+               if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->suspend(cpu_dai);
        }
 
        if (card->suspend_post)
@@ -992,127 +1072,127 @@ static int soc_suspend(struct device *dev)
  */
 static void soc_resume_deferred(struct work_struct *work)
 {
-       struct snd_soc_card *card = container_of(work,
-                                                struct snd_soc_card,
-                                                deferred_resume_work);
-       struct snd_soc_device *socdev = card->socdev;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = card->codec;
-       struct platform_device *pdev = to_platform_device(socdev->dev);
+       struct snd_soc_card *card =
+                       container_of(work, struct snd_soc_card, deferred_resume_work);
+       struct platform_device *pdev = to_platform_device(card->dev);
        int i;
 
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
         * so userspace apps are blocked from touching us
         */
 
-       dev_dbg(socdev->dev, "starting resume work\n");
+       dev_dbg(card->dev, "starting resume work\n");
 
        /* Bring us up into D2 so that DAPM starts enabling things */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D2);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
 
        if (card->resume_pre)
                card->resume_pre(pdev);
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       /* resume AC97 DAIs */
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->resume && cpu_dai->ac97_control)
-                       cpu_dai->resume(cpu_dai);
-       }
-
-       /* If the CODEC was idle over suspend then it will have been
-        * left with bias OFF or STANDBY and suspended so we must now
-        * resume.  Otherwise the suspend was suppressed.
-        */
-       if (codec_dev->resume) {
-               switch (codec->bias_level) {
-               case SND_SOC_BIAS_STANDBY:
-               case SND_SOC_BIAS_OFF:
-                       codec_dev->resume(pdev);
-                       break;
-               default:
-                       dev_dbg(socdev->dev, "CODEC was on over suspend\n");
-                       break;
+               if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->resume(cpu_dai);
+       }
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_codec *codec = card->rtd[i].codec;
+               /* If the CODEC was idle over suspend then it will have been
+                * left with bias OFF or STANDBY and suspended so we must now
+                * resume.  Otherwise the suspend was suppressed.
+                */
+               if (codec->driver->resume && codec->suspended) {
+                       switch (codec->bias_level) {
+                       case SND_SOC_BIAS_STANDBY:
+                       case SND_SOC_BIAS_OFF:
+                               codec->driver->resume(codec);
+                               codec->suspended = 0;
+                               break;
+                       default:
+                               dev_dbg(codec->dev, "CODEC was on over suspend\n");
+                               break;
+                       }
                }
        }
 
-       for (i = 0; i < codec->num_dai; i++) {
-               char *stream = codec->dai[i].playback.stream_name;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+               if (driver->playback.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
-               stream = codec->dai[i].capture.stream_name;
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+
+               if (driver->capture.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
        }
 
        /* unmute any active DACs */
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+               struct snd_soc_dai_driver *drv = dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (dai->ops->digital_mute && dai->playback.active)
-                       dai->ops->digital_mute(dai, 0);
+               if (drv->ops->digital_mute && dai->playback_active)
+                       drv->ops->digital_mute(dai, 0);
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               struct snd_soc_platform *platform = card->rtd[i].platform;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->resume && !cpu_dai->ac97_control)
-                       cpu_dai->resume(cpu_dai);
-               if (platform->resume)
-                       platform->resume(&card->dai_link[i]);
+               if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->resume(cpu_dai);
+               if (platform->driver->resume && platform->suspended) {
+                       platform->driver->resume(cpu_dai);
+                       platform->suspended = 0;
+               }
        }
 
        if (card->resume_post)
                card->resume_post(pdev);
 
-       dev_dbg(socdev->dev, "resume work completed\n");
+       dev_dbg(card->dev, "resume work completed\n");
 
        /* userspace can access us now we are back as we were before */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
 }
 
 /* powers up audio subsystem after a suspend */
 static int soc_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
-
-       /* If the initialization of this soc device failed, there is no codec
-        * associated with it. Just bail out in this case.
-        */
-       if (!card->codec)
-               return 0;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       int i;
 
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
         * problem and may take a substantial amount of time to resume
         * due to I/O costs and anti-pop so handle them out of line.
         */
-       if (cpu_dai->ac97_control) {
-               dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
-               soc_resume_deferred(&card->deferred_resume_work);
-       } else {
-               dev_dbg(socdev->dev, "Scheduling resume work\n");
-               if (!schedule_work(&card->deferred_resume_work))
-                       dev_err(socdev->dev, "resume work item may be lost\n");
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               if (cpu_dai->driver->ac97_control) {
+                       dev_dbg(dev, "Resuming AC97 immediately\n");
+                       soc_resume_deferred(&card->deferred_resume_work);
+               } else {
+                       dev_dbg(dev, "Scheduling resume work\n");
+                       if (!schedule_work(&card->deferred_resume_work))
+                               dev_err(dev, "resume work item may be lost\n");
+               }
        }
 
        return 0;
@@ -1125,198 +1205,440 @@ static int soc_resume(struct device *dev)
 static struct snd_soc_dai_ops null_dai_ops = {
 };
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
-       struct platform_device *pdev = container_of(card->dev,
-                                                   struct platform_device,
-                                                   dev);
-       struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
-       struct snd_soc_dai *dai;
-       int i, found, ret, ac97;
+       struct snd_soc_dai *codec_dai, *cpu_dai;
 
-       if (card->instantiated)
-               return;
+       if (rtd->complete)
+               return 1;
+       dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-       found = 0;
-       list_for_each_entry(platform, &platform_list, list)
-               if (card->platform == platform) {
-                       found = 1;
-                       break;
+       /* do we already have the CPU DAI for this link ? */
+       if (rtd->cpu_dai) {
+               goto find_codec;
+       }
+       /* no, then find CPU DAI from registered DAIs*/
+       list_for_each_entry(cpu_dai, &dai_list, list) {
+               if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
+
+                       if (!try_module_get(cpu_dai->dev->driver->owner))
+                               return -ENODEV;
+
+                       rtd->cpu_dai = cpu_dai;
+                       goto find_codec;
                }
-       if (!found) {
-               dev_dbg(card->dev, "Platform %s not registered\n",
-                       card->platform->name);
-               return;
        }
+       dev_dbg(card->dev, "CPU DAI %s not registered\n",
+                       dai_link->cpu_dai_name);
 
-       ac97 = 0;
-       for (i = 0; i < card->num_links; i++) {
-               found = 0;
-               list_for_each_entry(dai, &dai_list, list)
-                       if (card->dai_link[i].cpu_dai == dai) {
-                               found = 1;
-                               break;
+find_codec:
+       /* do we already have the CODEC for this link ? */
+       if (rtd->codec) {
+               goto find_platform;
+       }
+
+       /* no, then find CODEC from registered CODECs*/
+       list_for_each_entry(codec, &codec_list, list) {
+               if (!strcmp(codec->name, dai_link->codec_name)) {
+                       rtd->codec = codec;
+
+                       if (!try_module_get(codec->dev->driver->owner))
+                               return -ENODEV;
+
+                       /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
+                       list_for_each_entry(codec_dai, &dai_list, list) {
+                               if (codec->dev == codec_dai->dev &&
+                                               !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
+                                       rtd->codec_dai = codec_dai;
+                                       goto find_platform;
+                               }
                        }
-               if (!found) {
-                       dev_dbg(card->dev, "DAI %s not registered\n",
-                               card->dai_link[i].cpu_dai->name);
-                       return;
+                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                                       dai_link->codec_dai_name);
+
+                       goto find_platform;
                }
+       }
+       dev_dbg(card->dev, "CODEC %s not registered\n",
+                       dai_link->codec_name);
 
-               if (card->dai_link[i].cpu_dai->ac97_control)
-                       ac97 = 1;
+find_platform:
+       /* do we already have the CODEC DAI for this link ? */
+       if (rtd->platform) {
+               goto out;
        }
+       /* no, then find CPU DAI from registered DAIs*/
+       list_for_each_entry(platform, &platform_list, list) {
+               if (!strcmp(platform->name, dai_link->platform_name)) {
 
-       for (i = 0; i < card->num_links; i++) {
-               if (!card->dai_link[i].codec_dai->ops)
-                       card->dai_link[i].codec_dai->ops = &null_dai_ops;
+                       if (!try_module_get(platform->dev->driver->owner))
+                               return -ENODEV;
+
+                       rtd->platform = platform;
+                       goto out;
+               }
        }
 
-       /* If we have AC97 in the system then don't wait for the
-        * codec.  This will need revisiting if we have to handle
-        * systems with mixed AC97 and non-AC97 parts.  Only check for
-        * DAIs currently; we can't do this per link since some AC97
-        * codecs have non-AC97 DAIs.
-        */
-       if (!ac97)
-               for (i = 0; i < card->num_links; i++) {
-                       found = 0;
-                       list_for_each_entry(dai, &dai_list, list)
-                               if (card->dai_link[i].codec_dai == dai) {
-                                       found = 1;
-                                       break;
-                               }
-                       if (!found) {
-                               dev_dbg(card->dev, "DAI %s not registered\n",
-                                       card->dai_link[i].codec_dai->name);
-                               return;
-                       }
+       dev_dbg(card->dev, "platform %s not registered\n",
+                       dai_link->platform_name);
+       return 0;
+
+out:
+       /* mark rtd as complete if we found all 4 of our client devices */
+       if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
+               rtd->complete = 1;
+               card->num_rtd++;
+       }
+       return 1;
+}
+
+static void soc_remove_dai_link(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       int err;
+
+       /* unregister the rtd device */
+       if (rtd->dev_registered) {
+               device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
+               device_unregister(&rtd->dev);
+               rtd->dev_registered = 0;
+       }
+
+       /* remove the CODEC DAI */
+       if (codec_dai && codec_dai->probed) {
+               if (codec_dai->driver->remove) {
+                       err = codec_dai->driver->remove(codec_dai);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
                }
+               codec_dai->probed = 0;
+               list_del(&codec_dai->card_list);
+       }
 
-       /* Note that we do not current check for codec components */
+       /* remove the platform */
+       if (platform && platform->probed) {
+               if (platform->driver->remove) {
+                       err = platform->driver->remove(platform);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+               }
+               platform->probed = 0;
+               list_del(&platform->card_list);
+               module_put(platform->dev->driver->owner);
+       }
 
-       dev_dbg(card->dev, "All components present, instantiating\n");
+       /* remove the CODEC */
+       if (codec && codec->probed) {
+               if (codec->driver->remove) {
+                       err = codec->driver->remove(codec);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", codec->name);
+               }
 
-       /* Found everything, bring it up */
-       card->pmdown_time = pmdown_time;
+               /* Make sure all DAPM widgets are freed */
+               snd_soc_dapm_free(codec);
 
-       if (card->probe) {
-               ret = card->probe(pdev);
-               if (ret < 0)
-                       return;
+               soc_cleanup_codec_debugfs(codec);
+               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
+               codec->probed = 0;
+               list_del(&codec->card_list);
+               module_put(codec->dev->driver->owner);
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-               if (cpu_dai->probe) {
-                       ret = cpu_dai->probe(pdev, cpu_dai);
-                       if (ret < 0)
-                               goto cpu_dai_err;
+       /* remove the cpu_dai */
+       if (cpu_dai && cpu_dai->probed) {
+               if (cpu_dai->driver->remove) {
+                       err = cpu_dai->driver->remove(cpu_dai);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
                }
+               cpu_dai->probed = 0;
+               list_del(&cpu_dai->card_list);
+               module_put(cpu_dai->dev->driver->owner);
        }
+}
 
-       if (codec_dev->probe) {
-               ret = codec_dev->probe(pdev);
-               if (ret < 0)
-                       goto cpu_dai_err;
+static void rtd_release(struct device *dev) {}
+
+static int soc_probe_dai_link(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       int ret;
+
+       dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
+
+       /* config components */
+       codec_dai->codec = codec;
+       codec->card = card;
+       cpu_dai->platform = platform;
+       rtd->card = card;
+       rtd->dev.parent = card->dev;
+       codec_dai->card = card;
+       cpu_dai->card = card;
+
+       /* set default power off timeout */
+       rtd->pmdown_time = pmdown_time;
+
+       /* probe the cpu_dai */
+       if (!cpu_dai->probed) {
+               if (cpu_dai->driver->probe) {
+                       ret = cpu_dai->driver->probe(cpu_dai);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
+                                               cpu_dai->name);
+                               return ret;
+                       }
+               }
+               cpu_dai->probed = 1;
+               /* mark cpu_dai as probed and add to card cpu_dai list */
+               list_add(&cpu_dai->card_list, &card->dai_dev_list);
        }
-       codec = card->codec;
 
-       if (platform->probe) {
-               ret = platform->probe(pdev);
-               if (ret < 0)
-                       goto platform_err;
+       /* probe the CODEC */
+       if (!codec->probed) {
+               if (codec->driver->probe) {
+                       ret = codec->driver->probe(codec);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to probe CODEC %s\n",
+                                               codec->name);
+                               return ret;
+                       }
+               }
+
+               soc_init_codec_debugfs(codec);
+
+               /* mark codec as probed and add to card codec list */
+               codec->probed = 1;
+               list_add(&codec->card_list, &card->codec_dev_list);
        }
 
-       /* DAPM stream work */
-       INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
-#ifdef CONFIG_PM
-       /* deferred resume work */
-       INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
-#endif
+       /* probe the platform */
+       if (!platform->probed) {
+               if (platform->driver->probe) {
+                       ret = platform->driver->probe(platform);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to probe platform %s\n",
+                                               platform->name);
+                               return ret;
+                       }
+               }
+               /* mark platform as probed and add to card platform list */
+               platform->probed = 1;
+               list_add(&platform->card_list, &card->platform_dev_list);
+       }
 
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].init) {
-                       ret = card->dai_link[i].init(codec);
+       /* probe the CODEC DAI */
+       if (!codec_dai->probed) {
+               if (codec_dai->driver->probe) {
+                       ret = codec_dai->driver->probe(codec_dai);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to init %s\n",
-                                       card->dai_link[i].stream_name);
-                               continue;
+                               printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
+                                               codec_dai->name);
+                               return ret;
                        }
                }
-               if (card->dai_link[i].codec_dai->ac97_control)
-                       ac97 = 1;
+
+               /* mark cpu_dai as probed and add to card cpu_dai list */
+               codec_dai->probed = 1;
+               list_add(&codec_dai->card_list, &card->dai_dev_list);
        }
 
-       snprintf(codec->card->shortname, sizeof(codec->card->shortname),
-                "%s",  card->name);
-       snprintf(codec->card->longname, sizeof(codec->card->longname),
-                "%s (%s)", card->name, codec->name);
+       /* DAPM dai link stream work */
+       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+
+       /* now that all clients have probed, initialise the DAI link */
+       if (dai_link->init) {
+               ret = dai_link->init(rtd);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
+                       return ret;
+               }
+       }
 
        /* Make sure all DAPM widgets are instantiated */
        snd_soc_dapm_new_widgets(codec);
+       snd_soc_dapm_sync(codec);
 
-       ret = snd_card_register(codec->card);
+       /* register the rtd device */
+       rtd->dev.release = rtd_release;
+       rtd->dev.init_name = dai_link->name;
+       ret = device_register(&rtd->dev);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
-                               codec->name);
-               goto card_err;
+               printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
+               return ret;
        }
 
-       mutex_lock(&codec->mutex);
+       rtd->dev_registered = 1;
+       ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+
+       /* add DAPM sysfs entries for this codec */
+       ret = snd_soc_dapm_sys_add(&rtd->dev);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n");
+
+       /* add codec sysfs entries */
+       ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
+       /* create the pcm */
+       ret = soc_new_pcm(rtd, num);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+               return ret;
+       }
+
+       /* add platform data for AC97 devices */
+       if (rtd->codec_dai->driver->ac97_control)
+               snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
+
+       return 0;
+}
+
 #ifdef CONFIG_SND_SOC_AC97_BUS
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+
        /* Only instantiate AC97 if not already done by the adaptor
         * for the generic AC97 subsystem.
         */
-       if (ac97 && strcmp(codec->name, "AC97") != 0) {
-               ret = soc_ac97_dev_register(codec);
+       if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+               /*
+                * It is possible that the AC97 device is already registered to
+                * the device subsystem. This happens when the device is created
+                * via snd_ac97_mixer(). Currently only SoC codec that does so
+                * is the generic AC97 glue but others migh emerge.
+                *
+                * In those cases we don't try to register the device again.
+                */
+               if (!rtd->codec->ac97_created)
+                       return 0;
+
+               ret = soc_ac97_dev_register(rtd->codec);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: AC97 device register failed\n");
-                       snd_card_free(codec->card);
-                       mutex_unlock(&codec->mutex);
-                       goto card_err;
+                       return ret;
                }
+
+               rtd->codec->ac97_registered = 1;
+       }
+       return 0;
+}
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+{
+       if (codec->ac97_registered) {
+               soc_ac97_dev_unregister(codec);
+               codec->ac97_registered = 0;
        }
+}
 #endif
 
-       ret = snd_soc_dapm_sys_add(card->socdev->dev);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+static void snd_soc_instantiate_card(struct snd_soc_card *card)
+{
+       struct platform_device *pdev = to_platform_device(card->dev);
+       int ret, i;
 
-       ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+       mutex_lock(&card->mutex);
 
-       ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+       if (card->instantiated) {
+               mutex_unlock(&card->mutex);
+               return;
+       }
 
-       soc_init_codec_debugfs(codec);
-       mutex_unlock(&codec->mutex);
+       /* bind DAIs */
+       for (i = 0; i < card->num_links; i++)
+               soc_bind_dai_link(card, i);
 
-       card->instantiated = 1;
+       /* bind completed ? */
+       if (card->num_rtd != card->num_links) {
+               mutex_unlock(&card->mutex);
+               return;
+       }
 
-       return;
+       /* card bind complete so register a sound card */
+       ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                       card->owner, 0, &card->snd_card);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: can't create sound card for card %s\n",
+                       card->name);
+               mutex_unlock(&card->mutex);
+               return;
+       }
+       card->snd_card->dev = card->dev;
 
-card_err:
-       if (platform->remove)
-               platform->remove(pdev);
+#ifdef CONFIG_PM
+       /* deferred resume work */
+       INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
+#endif
 
-platform_err:
-       if (codec_dev->remove)
-               codec_dev->remove(pdev);
+       /* initialise the sound card only once */
+       if (card->probe) {
+               ret = card->probe(pdev);
+               if (ret < 0)
+                       goto card_probe_error;
+       }
 
-cpu_dai_err:
-       for (i--; i >= 0; i--) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-               if (cpu_dai->remove)
-                       cpu_dai->remove(pdev, cpu_dai);
+       for (i = 0; i < card->num_links; i++) {
+               ret = soc_probe_dai_link(card, i);
+               if (ret < 0) {
+                       pr_err("asoc: failed to instantiate card %s: %d\n",
+                              card->name, ret);
+                       goto probe_dai_err;
+               }
        }
 
+       snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
+                "%s",  card->name);
+       snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+                "%s", card->name);
+
+       ret = snd_card_register(card->snd_card);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
+               goto probe_dai_err;
+       }
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+       /* register any AC97 codecs */
+       for (i = 0; i < card->num_rtd; i++) {
+                       ret = soc_register_ac97_dai_link(&card->rtd[i]);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+                               goto probe_dai_err;
+                       }
+               }
+#endif
+
+       card->instantiated = 1;
+       mutex_unlock(&card->mutex);
+       return;
+
+probe_dai_err:
+       for (i = 0; i < card->num_links; i++)
+               soc_remove_dai_link(card, i);
+
+card_probe_error:
        if (card->remove)
                card->remove(pdev);
+
+       snd_card_free(card->snd_card);
+
+       mutex_unlock(&card->mutex);
 }
 
 /*
@@ -1333,15 +1655,15 @@ static void snd_soc_instantiate_cards(void)
 /* probes a new socdev */
 static int soc_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int ret = 0;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-
-       /* Bodge while we push things out of socdev */
-       card->socdev = socdev;
 
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
+       INIT_LIST_HEAD(&card->dai_dev_list);
+       INIT_LIST_HEAD(&card->codec_dev_list);
+       INIT_LIST_HEAD(&card->platform_dev_list);
+
        ret = snd_soc_register_card(card);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to register card\n");
@@ -1354,50 +1676,49 @@ static int soc_probe(struct platform_device *pdev)
 /* removes a socdev */
 static int soc_remove(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 
-       if (card->instantiated) {
-               run_delayed_work(&card->delayed_work);
-
-               if (platform->remove)
-                       platform->remove(pdev);
+               if (card->instantiated) {
 
-               if (codec_dev->remove)
-                       codec_dev->remove(pdev);
-
-               for (i = 0; i < card->num_links; i++) {
-                       struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-                       if (cpu_dai->remove)
-                               cpu_dai->remove(pdev, cpu_dai);
+               /* make sure any delayed work runs */
+               for (i = 0; i < card->num_rtd; i++) {
+                       struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+                       run_delayed_work(&rtd->delayed_work);
                }
 
+               /* remove and free each DAI */
+               for (i = 0; i < card->num_rtd; i++)
+                       soc_remove_dai_link(card, i);
+
+               /* remove the card */
                if (card->remove)
                        card->remove(pdev);
-       }
 
+               kfree(card->rtd);
+               snd_card_free(card->snd_card);
+       }
        snd_soc_unregister_card(card);
-
        return 0;
 }
 
 static int soc_poweroff(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       int i;
 
        if (!card->instantiated)
                return 0;
 
        /* Flush out pmdown_time work - we actually do want to run it
         * now, we're shutting down so no imminent restart. */
-       run_delayed_work(&card->delayed_work);
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+               run_delayed_work(&rtd->delayed_work);
+       }
 
-       snd_soc_dapm_shutdown(socdev);
+       snd_soc_dapm_shutdown(card);
 
        return 0;
 }
@@ -1420,53 +1741,42 @@ static struct platform_driver soc_driver = {
 };
 
 /* create a new pcm */
-static int soc_new_pcm(struct snd_soc_device *socdev,
-       struct snd_soc_dai_link *dai_link, int num)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = card->codec;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *codec_dai = dai_link->codec_dai;
-       struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
-       struct snd_soc_pcm_runtime *rtd;
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
 
-       rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
-       if (rtd == NULL)
-               return -ENOMEM;
-
-       rtd->dai = dai_link;
-       rtd->socdev = socdev;
-       codec_dai->codec = card->codec;
-
        /* check client and interface hw capabilities */
        snprintf(new_name, sizeof(new_name), "%s %s-%d",
-                dai_link->stream_name, codec_dai->name, num);
+                       rtd->dai_link->stream_name, codec_dai->name, num);
 
-       if (codec_dai->playback.channels_min)
+       if (codec_dai->driver->playback.channels_min)
                playback = 1;
-       if (codec_dai->capture.channels_min)
+       if (codec_dai->driver->capture.channels_min)
                capture = 1;
 
-       ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
-               capture, &pcm);
+       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+       ret = snd_pcm_new(rtd->card->snd_card, new_name,
+                       num, playback, capture, &pcm);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
-                       codec->name);
-               kfree(rtd);
+               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
                return ret;
        }
 
-       dai_link->pcm = pcm;
+       rtd->pcm = pcm;
        pcm->private_data = rtd;
-       soc_pcm_ops.mmap = platform->pcm_ops->mmap;
-       soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
-       soc_pcm_ops.copy = platform->pcm_ops->copy;
-       soc_pcm_ops.silence = platform->pcm_ops->silence;
-       soc_pcm_ops.ack = platform->pcm_ops->ack;
-       soc_pcm_ops.page = platform->pcm_ops->page;
+       soc_pcm_ops.mmap = platform->driver->ops->mmap;
+       soc_pcm_ops.pointer = platform->driver->ops->pointer;
+       soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+       soc_pcm_ops.copy = platform->driver->ops->copy;
+       soc_pcm_ops.silence = platform->driver->ops->silence;
+       soc_pcm_ops.ack = platform->driver->ops->ack;
+       soc_pcm_ops.page = platform->driver->ops->page;
 
        if (playback)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -1474,14 +1784,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        if (capture)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-       ret = platform->pcm_new(codec->card, codec_dai, pcm);
+       ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
        if (ret < 0) {
                printk(KERN_ERR "asoc: platform pcm constructor failed\n");
-               kfree(rtd);
                return ret;
        }
 
-       pcm->private_free = platform->pcm_free;
+       pcm->private_free = platform->driver->pcm_free;
        printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
                cpu_dai->name);
        return ret;
@@ -1497,8 +1806,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
  */
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
 {
-       if (codec->volatile_register)
-               return codec->volatile_register(reg);
+       if (codec->driver->volatile_register)
+               return codec->driver->volatile_register(reg);
        else
                return 0;
 }
@@ -1533,7 +1842,13 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 
        codec->ac97->bus->ops = ops;
        codec->ac97->num = num;
-       codec->dev = &codec->ac97->dev;
+
+       /*
+        * Mark the AC97 device to be created by us. This way we ensure that the
+        * device will be registered with the device subsystem later on.
+        */
+       codec->ac97_created = 1;
+
        mutex_unlock(&codec->mutex);
        return 0;
 }
@@ -1548,9 +1863,13 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 {
        mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+       soc_unregister_ac97_dai_link(codec);
+#endif
        kfree(codec->ac97->bus);
        kfree(codec->ac97);
        codec->ac97 = NULL;
+       codec->ac97_created = 0;
        mutex_unlock(&codec->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@ -1633,95 +1952,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
 }
 EXPORT_SYMBOL_GPL(snd_soc_test_bits);
 
-/**
- * snd_soc_new_pcms - create new sound card and pcms
- * @socdev: the SoC audio device
- * @idx: ALSA card index
- * @xid: card identification
- *
- * Create a new sound card based upon the codec and interface pcms.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = card->codec;
-       int ret, i;
-
-       mutex_lock(&codec->mutex);
-
-       /* register a sound card */
-       ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
-                       codec->name);
-               mutex_unlock(&codec->mutex);
-               return ret;
-       }
-
-       codec->socdev = socdev;
-       codec->card->dev = socdev->dev;
-       codec->card->private_data = codec;
-       strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
-
-       /* create the pcms */
-       for (i = 0; i < card->num_links; i++) {
-               ret = soc_new_pcm(socdev, &card->dai_link[i], i);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't create pcm %s\n",
-                               card->dai_link[i].stream_name);
-                       mutex_unlock(&codec->mutex);
-                       return ret;
-               }
-               /* Check for codec->ac97 to handle the ac97.c fun */
-               if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
-                       snd_ac97_dev_add_pdata(codec->ac97,
-                               card->dai_link[i].cpu_dai->ac97_pdata);
-               }
-       }
-
-       mutex_unlock(&codec->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_free_pcms - free sound card and pcms
- * @socdev: the SoC audio device
- *
- * Frees sound card and pcms associated with the socdev.
- * Also unregister the codec if it is an AC97 device.
- */
-void snd_soc_free_pcms(struct snd_soc_device *socdev)
-{
-       struct snd_soc_codec *codec = socdev->card->codec;
-#ifdef CONFIG_SND_SOC_AC97_BUS
-       struct snd_soc_dai *codec_dai;
-       int i;
-#endif
-
-       mutex_lock(&codec->mutex);
-       soc_cleanup_codec_debugfs(codec);
-#ifdef CONFIG_SND_SOC_AC97_BUS
-       for (i = 0; i < codec->num_dai; i++) {
-               codec_dai = &codec->dai[i];
-               if (codec_dai->ac97_control && codec->ac97 &&
-                   strcmp(codec->name, "AC97") != 0) {
-                       soc_ac97_dev_unregister(codec);
-                       goto free_card;
-               }
-       }
-free_card:
-#endif
-
-       if (codec->card)
-               snd_card_free(codec->card);
-       device_remove_file(socdev->dev, &dev_attr_codec_reg);
-       mutex_unlock(&codec->mutex);
-}
-EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
-
 /**
  * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
  * @substream: the pcm substream
@@ -1783,15 +2013,15 @@ EXPORT_SYMBOL_GPL(snd_soc_cnew);
 int snd_soc_add_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls)
 {
-       struct snd_card *card = codec->card;
+       struct snd_card *card = codec->card->snd_card;
        int err, i;
 
        for (i = 0; i < num_controls; i++) {
                const struct snd_kcontrol_new *control = &controls[i];
                err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
                if (err < 0) {
-                       dev_err(codec->dev, "%s: Failed to add %s\n",
-                               codec->name, control->name);
+                       dev_err(codec->dev, "%s: Failed to add %s: %d\n",
+                               codec->name, control->name, err);
                        return err;
                }
        }
@@ -2338,7 +2568,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
        const char *name, int max)
 {
-       struct snd_card *card = codec->card;
+       struct snd_card *card = codec->card->snd_card;
        struct snd_kcontrol *kctl;
        struct soc_mixer_control *mc;
        int found = 0;
@@ -2470,8 +2700,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       if (dai->ops && dai->ops->set_sysclk)
-               return dai->ops->set_sysclk(dai, clk_id, freq, dir);
+       if (dai->driver && dai->driver->ops->set_sysclk)
+               return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
        else
                return -EINVAL;
 }
@@ -2490,8 +2720,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
-       if (dai->ops && dai->ops->set_clkdiv)
-               return dai->ops->set_clkdiv(dai, div_id, div);
+       if (dai->driver && dai->driver->ops->set_clkdiv)
+               return dai->driver->ops->set_clkdiv(dai, div_id, div);
        else
                return -EINVAL;
 }
@@ -2510,8 +2740,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
        unsigned int freq_in, unsigned int freq_out)
 {
-       if (dai->ops && dai->ops->set_pll)
-               return dai->ops->set_pll(dai, pll_id, source,
+       if (dai->driver && dai->driver->ops->set_pll)
+               return dai->driver->ops->set_pll(dai, pll_id, source,
                                         freq_in, freq_out);
        else
                return -EINVAL;
@@ -2527,8 +2757,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       if (dai->ops && dai->ops->set_fmt)
-               return dai->ops->set_fmt(dai, fmt);
+       if (dai->driver && dai->driver->ops->set_fmt)
+               return dai->driver->ops->set_fmt(dai, fmt);
        else
                return -EINVAL;
 }
@@ -2548,8 +2778,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       if (dai->ops && dai->ops->set_tdm_slot)
-               return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+       if (dai->driver && dai->driver->ops->set_tdm_slot)
+               return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
                                slots, slot_width);
        else
                return -EINVAL;
@@ -2572,8 +2802,8 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
        unsigned int tx_num, unsigned int *tx_slot,
        unsigned int rx_num, unsigned int *rx_slot)
 {
-       if (dai->ops && dai->ops->set_channel_map)
-               return dai->ops->set_channel_map(dai, tx_num, tx_slot,
+       if (dai->driver && dai->driver->ops->set_channel_map)
+               return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
                        rx_num, rx_slot);
        else
                return -EINVAL;
@@ -2589,8 +2819,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-       if (dai->ops && dai->ops->set_tristate)
-               return dai->ops->set_tristate(dai, tristate);
+       if (dai->driver && dai->driver->ops->set_tristate)
+               return dai->driver->ops->set_tristate(dai, tristate);
        else
                return -EINVAL;
 }
@@ -2605,8 +2835,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-       if (dai->ops && dai->ops->digital_mute)
-               return dai->ops->digital_mute(dai, mute);
+       if (dai->driver && dai->driver->ops->digital_mute)
+               return dai->driver->ops->digital_mute(dai, mute);
        else
                return -EINVAL;
 }
@@ -2623,11 +2853,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
  */
 static int snd_soc_register_card(struct snd_soc_card *card)
 {
+       int i;
+
        if (!card->name || !card->dev)
                return -EINVAL;
 
+       card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
+                       GFP_KERNEL);
+       if (card->rtd == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < card->num_links; i++)
+               card->rtd[i].dai_link = &card->dai_link[i];
+
        INIT_LIST_HEAD(&card->list);
        card->instantiated = 0;
+       mutex_init(&card->mutex);
 
        mutex_lock(&client_mutex);
        list_add(&card->list, &card_list);
@@ -2653,30 +2894,97 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
        mutex_lock(&client_mutex);
        list_del(&card->list);
        mutex_unlock(&client_mutex);
-
        dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
        return 0;
 }
 
+/*
+ * Simplify DAI link configuration by removing ".-1" from device names
+ * and sanitizing names.
+ */
+static inline char *fmt_single_name(struct device *dev, int *id)
+{
+       char *found, name[NAME_SIZE];
+       int id1, id2;
+
+       if (dev_name(dev) == NULL)
+               return NULL;
+
+       strncpy(name, dev_name(dev), NAME_SIZE);
+
+       /* are we a "%s.%d" name (platform and SPI components) */
+       found = strstr(name, dev->driver->name);
+       if (found) {
+               /* get ID */
+               if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
+
+                       /* discard ID from name if ID == -1 */
+                       if (*id == -1)
+                               found[strlen(dev->driver->name)] = '\0';
+               }
+
+       } else {
+               /* I2C component devices are named "bus-addr"  */
+               if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
+                       char tmp[NAME_SIZE];
+
+                       /* create unique ID number from I2C addr and bus */
+                       *id = ((id1 & 0xffff) << 16) + id2;
+
+                       /* sanitize component name for DAI link creation */
+                       snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
+                       strncpy(name, tmp, NAME_SIZE);
+               } else
+                       *id = 0;
+       }
+
+       return kstrdup(name, GFP_KERNEL);
+}
+
+/*
+ * Simplify DAI link naming for single devices with multiple DAIs by removing
+ * any ".-1" and using the DAI name (instead of device name).
+ */
+static inline char *fmt_multiple_name(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv)
+{
+       if (dai_drv->name == NULL) {
+               printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+                               dev_name(dev));
+               return NULL;
+       }
+
+       return kstrdup(dai_drv->name, GFP_KERNEL);
+}
+
 /**
  * snd_soc_register_dai - Register a DAI with the ASoC core
  *
  * @dai: DAI to register
  */
-int snd_soc_register_dai(struct snd_soc_dai *dai)
+int snd_soc_register_dai(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv)
 {
-       if (!dai->name)
-               return -EINVAL;
+       struct snd_soc_dai *dai;
+
+       dev_dbg(dev, "dai register %s\n", dev_name(dev));
 
-       /* The device should become mandatory over time */
-       if (!dai->dev)
-               printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+       dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+       if (dai == NULL)
+                       return -ENOMEM;
 
-       if (!dai->ops)
-               dai->ops = &null_dai_ops;
+       /* create DAI component name */
+       dai->name = fmt_single_name(dev, &dai->id);
+       if (dai->name == NULL) {
+               kfree(dai);
+               return -ENOMEM;
+       }
 
-       INIT_LIST_HEAD(&dai->list);
+       dai->dev = dev;
+       dai->driver = dai_drv;
+       if (!dai->driver->ops)
+               dai->driver->ops = &null_dai_ops;
 
        mutex_lock(&client_mutex);
        list_add(&dai->list, &dai_list);
@@ -2694,13 +3002,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai);
  *
  * @dai: DAI to unregister
  */
-void snd_soc_unregister_dai(struct snd_soc_dai *dai)
+void snd_soc_unregister_dai(struct device *dev)
 {
+       struct snd_soc_dai *dai;
+
+       list_for_each_entry(dai, &dai_list, list) {
+               if (dev == dai->dev)
+                       goto found;
+       }
+       return;
+
+found:
        mutex_lock(&client_mutex);
        list_del(&dai->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered DAI '%s'\n", dai->name);
+       kfree(dai->name);
+       kfree(dai);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 
@@ -2710,21 +3029,50 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  * @dai: Array of DAIs to register
  * @count: Number of DAIs
  */
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
+int snd_soc_register_dais(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv, size_t count)
 {
-       int i, ret;
+       struct snd_soc_dai *dai;
+       int i, ret = 0;
+
+       dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count);
 
        for (i = 0; i < count; i++) {
-               ret = snd_soc_register_dai(&dai[i]);
-               if (ret != 0)
+
+               dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+               if (dai == NULL)
+                       return -ENOMEM;
+
+               /* create DAI component name */
+               dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+               if (dai->name == NULL) {
+                       kfree(dai);
+                       ret = -EINVAL;
                        goto err;
+               }
+
+               dai->dev = dev;
+               dai->driver = &dai_drv[i];
+               if (dai->driver->id)
+                       dai->id = dai->driver->id;
+               else
+                       dai->id = i;
+               if (!dai->driver->ops)
+                       dai->driver->ops = &null_dai_ops;
+
+               mutex_lock(&client_mutex);
+               list_add(&dai->list, &dai_list);
+               mutex_unlock(&client_mutex);
+
+               pr_debug("Registered DAI '%s'\n", dai->name);
        }
 
+       snd_soc_instantiate_cards();
        return 0;
 
 err:
        for (i--; i >= 0; i--)
-               snd_soc_unregister_dai(&dai[i]);
+               snd_soc_unregister_dai(dev);
 
        return ret;
 }
@@ -2736,12 +3084,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  * @dai: Array of DAIs to unregister
  * @count: Number of DAIs
  */
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
+void snd_soc_unregister_dais(struct device *dev, size_t count)
 {
        int i;
 
        for (i = 0; i < count; i++)
-               snd_soc_unregister_dai(&dai[i]);
+               snd_soc_unregister_dai(dev);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 
@@ -2750,12 +3098,26 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
  *
  * @platform: platform to register
  */
-int snd_soc_register_platform(struct snd_soc_platform *platform)
+int snd_soc_register_platform(struct device *dev,
+               struct snd_soc_platform_driver *platform_drv)
 {
-       if (!platform->name)
-               return -EINVAL;
+       struct snd_soc_platform *platform;
+
+       dev_dbg(dev, "platform register %s\n", dev_name(dev));
 
-       INIT_LIST_HEAD(&platform->list);
+       platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
+       if (platform == NULL)
+                       return -ENOMEM;
+
+       /* create platform component name */
+       platform->name = fmt_single_name(dev, &platform->id);
+       if (platform->name == NULL) {
+               kfree(platform);
+               return -ENOMEM;
+       }
+
+       platform->dev = dev;
+       platform->driver = platform_drv;
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@ -2773,13 +3135,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
  *
  * @platform: platform to unregister
  */
-void snd_soc_unregister_platform(struct snd_soc_platform *platform)
+void snd_soc_unregister_platform(struct device *dev)
 {
+       struct snd_soc_platform *platform;
+
+       list_for_each_entry(platform, &platform_list, list) {
+               if (dev == platform->dev)
+                       goto found;
+       }
+       return;
+
+found:
        mutex_lock(&client_mutex);
        list_del(&platform->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered platform '%s'\n", platform->name);
+       kfree(platform->name);
+       kfree(platform);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
 
@@ -2821,22 +3194,61 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
  *
  * @codec: codec to register
  */
-int snd_soc_register_codec(struct snd_soc_codec *codec)
+int snd_soc_register_codec(struct device *dev,
+               struct snd_soc_codec_driver *codec_drv,
+               struct snd_soc_dai_driver *dai_drv, int num_dai)
 {
-       int i;
+       struct snd_soc_codec *codec;
+       int ret, i;
 
-       if (!codec->name)
-               return -EINVAL;
+       dev_dbg(dev, "codec register %s\n", dev_name(dev));
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       /* create CODEC component name */
+       codec->name = fmt_single_name(dev, &codec->id);
+       if (codec->name == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
 
-       /* The device should become mandatory over time */
-       if (!codec->dev)
-               printk(KERN_WARNING "No device for codec %s\n", codec->name);
+       /* allocate CODEC register cache */
+       if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
 
-       INIT_LIST_HEAD(&codec->list);
+               if (codec_drv->reg_cache_default)
+                       codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+                               codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
+               else
+                       codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
+                               codec_drv->reg_word_size, GFP_KERNEL);
 
-       for (i = 0; i < codec->num_dai; i++) {
-               fixup_codec_formats(&codec->dai[i].playback);
-               fixup_codec_formats(&codec->dai[i].capture);
+               if (codec->reg_cache == NULL) {
+                       kfree(codec->name);
+                       kfree(codec);
+                       return -ENOMEM;
+               }
+       }
+
+       codec->dev = dev;
+       codec->driver = codec_drv;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->num_dai = num_dai;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       for (i = 0; i < num_dai; i++) {
+               fixup_codec_formats(&dai_drv[i].playback);
+               fixup_codec_formats(&dai_drv[i].capture);
+       }
+
+       /* register any DAIs */
+       if (num_dai) {
+               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+               if (ret < 0)
+                       goto error;
        }
 
        mutex_lock(&client_mutex);
@@ -2845,8 +3257,17 @@ int snd_soc_register_codec(struct snd_soc_codec *codec)
        mutex_unlock(&client_mutex);
 
        pr_debug("Registered codec '%s'\n", codec->name);
-
        return 0;
+
+error:
+       for (i--; i >= 0; i--)
+               snd_soc_unregister_dai(dev);
+
+       if (codec->reg_cache)
+               kfree(codec->reg_cache);
+       kfree(codec->name);
+       kfree(codec);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_codec);
 
@@ -2855,13 +3276,32 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
  *
  * @codec: codec to unregister
  */
-void snd_soc_unregister_codec(struct snd_soc_codec *codec)
+void snd_soc_unregister_codec(struct device *dev)
 {
+       struct snd_soc_codec *codec;
+       int i;
+
+       list_for_each_entry(codec, &codec_list, list) {
+               if (dev == codec->dev)
+                       goto found;
+       }
+       return;
+
+found:
+       if (codec->num_dai)
+               for (i = 0; i < codec->num_dai; i++)
+                       snd_soc_unregister_dai(dev);
+
        mutex_lock(&client_mutex);
        list_del(&codec->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered codec '%s'\n", codec->name);
+
+       if (codec->reg_cache)
+               kfree(codec->reg_cache);
+       kfree(codec->name);
+       kfree(codec);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
@@ -2874,10 +3314,23 @@ static int __init snd_soc_init(void)
                       "ASoC: Failed to create debugfs directory\n");
                debugfs_root = NULL;
        }
+
+       if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+                                &codec_list_fops))
+               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+       if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+                                &dai_list_fops))
+               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+       if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+                                &platform_list_fops))
+               pr_warn("ASoC: Failed to create platform list debugfs file\n");
 #endif
 
        return platform_driver_register(&soc_driver);
 }
+module_init(snd_soc_init);
 
 static void __exit snd_soc_exit(void)
 {
@@ -2886,8 +3339,6 @@ static void __exit snd_soc_exit(void)
 #endif
        platform_driver_unregister(&soc_driver);
 }
-
-module_init(snd_soc_init);
 module_exit(snd_soc_exit);
 
 /* Module information */
index 72a53d0a41e934972120efe156902d4d42290533..7d85c6496afa432cbd9791be5f1a9510e7cb78c7 100644 (file)
@@ -112,43 +112,41 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
 
 /**
  * snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
+ * @card: audio device
  * @level: level to configure
  *
  * Configure the bias (power) levels for the SoC audio device.
  *
  * Returns 0 for success else error.
  */
-static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-                                      enum snd_soc_bias_level level)
+static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
+               struct snd_soc_codec *codec, enum snd_soc_bias_level level)
 {
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               dev_dbg(socdev->dev, "Setting full bias\n");
+               dev_dbg(codec->dev, "Setting full bias\n");
                break;
        case SND_SOC_BIAS_PREPARE:
-               dev_dbg(socdev->dev, "Setting bias prepare\n");
+               dev_dbg(codec->dev, "Setting bias prepare\n");
                break;
        case SND_SOC_BIAS_STANDBY:
-               dev_dbg(socdev->dev, "Setting standby bias\n");
+               dev_dbg(codec->dev, "Setting standby bias\n");
                break;
        case SND_SOC_BIAS_OFF:
-               dev_dbg(socdev->dev, "Setting bias off\n");
+               dev_dbg(codec->dev, "Setting bias off\n");
                break;
        default:
-               dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+               dev_err(codec->dev, "Setting invalid bias %d\n", level);
                return -EINVAL;
        }
 
-       if (card->set_bias_level)
+       if (card && card->set_bias_level)
                ret = card->set_bias_level(card, level);
        if (ret == 0) {
-               if (codec->set_bias_level)
-                       ret = codec->set_bias_level(codec, level);
+               if (codec->driver->set_bias_level)
+                       ret = codec->driver->set_bias_level(codec, level);
                else
                        codec->bias_level = level;
        }
@@ -370,7 +368,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
 
                        path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
                                path->long_name);
-                       ret = snd_ctl_add(codec->card, path->kcontrol);
+                       ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
                        if (ret < 0) {
                                printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
                                       path->long_name,
@@ -398,7 +396,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec,
        }
 
        kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
-       ret = snd_ctl_add(codec->card, kcontrol);
+       ret = snd_ctl_add(codec->card->snd_card, kcontrol);
        if (ret < 0)
                goto err;
 
@@ -437,9 +435,9 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
  */
 static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
 {
-       struct snd_soc_codec *codec = widget->codec;
+       int level = snd_power_get_state(widget->codec->card->snd_card);
 
-       switch (snd_power_get_state(codec->card)) {
+       switch (level) {
        case SNDRV_CTL_POWER_D3hot:
        case SNDRV_CTL_POWER_D3cold:
                if (widget->ignore_suspend)
@@ -893,7 +891,7 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
  */
 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 {
-       struct snd_soc_device *socdev = codec->socdev;
+       struct snd_soc_card *card = codec->card;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
@@ -966,7 +964,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        }
 
        if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
+               ret = snd_soc_dapm_set_bias_level(card, codec,
                                                  SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        pr_err("Failed to turn on bias: %d\n", ret);
@@ -975,8 +973,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        /* If we're changing to all on or all off then prepare */
        if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
            (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_PREPARE);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
                if (ret != 0)
                        pr_err("Failed to prepare bias: %d\n", ret);
        }
@@ -989,8 +986,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 
        /* If we just powered the last thing off drop to standby bias */
        if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_STANDBY);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        pr_err("Failed to apply standby bias: %d\n", ret);
        }
@@ -998,15 +994,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        /* If we're in standby and can support bias off then do that */
        if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
            codec->idle_bias_off) {
-               ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
                if (ret != 0)
                        pr_err("Failed to turn off bias: %d\n", ret);
        }
 
        /* If we just powered up then move to active bias */
        if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_ON);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
                if (ret != 0)
                        pr_err("Failed to apply active bias: %d\n", ret);
        }
@@ -1189,8 +1184,9 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       struct snd_soc_codec *codec = devdata->card->codec;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_codec *codec =rtd->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
        char *state = "not set";
@@ -1999,9 +1995,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
-       char *stream, int event)
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_widget *w;
 
        if (stream == NULL)
@@ -2169,25 +2166,19 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
 /**
  * snd_soc_dapm_free - free dapm resources
- * @socdev: SoC device
+ * @card: SoC device
  *
  * Free all dapm widgets and resources.
  */
-void snd_soc_dapm_free(struct snd_soc_device *socdev)
+void snd_soc_dapm_free(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_dapm_sys_remove(socdev->dev);
+       snd_soc_dapm_sys_remove(codec->dev);
        dapm_free_widgets(codec);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
-/*
- * snd_soc_dapm_shutdown - callback for system shutdown
- */
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(down_list);
        int powerdown = 0;
@@ -2204,12 +2195,23 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
         * standby.
         */
        if (powerdown) {
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
                dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
        }
+}
+
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+void snd_soc_dapm_shutdown(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &card->codec_dev_list, list)
+               soc_dapm_shutdown_codec(codec);
 
-       snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+       snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
 }
 
 /* Module information */
index 29159e1781d0edbc681a8120865323171a7a4906..8a0a9205b1e785bf92d6ddd773b0a70cc7cf568d 100644 (file)
  * Returns zero if successful, or a negative error code on failure.
  * On success jack will be initialised.
  */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack)
 {
-       jack->card = card;
+       jack->codec = codec;
        INIT_LIST_HEAD(&jack->pins);
        BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
 
-       return snd_jack_new(card->codec->card, id, type, &jack->jack);
+       return snd_jack_new(codec->card->snd_card, id, type, &jack->jack);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_new);
 
@@ -67,7 +67,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        if (!jack)
                return;
 
-       codec = jack->card->codec;
+       codec = jack->codec;
 
        mutex_lock(&codec->mutex);
 
@@ -188,9 +188,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
        int enable;
        int report;
 
-       if (gpio->debounce_time > 0)
-               mdelay(gpio->debounce_time);
-
        enable = gpio_get_value(gpio->gpio);
        if (gpio->invert)
                enable = !enable;
@@ -211,7 +208,8 @@ static irqreturn_t gpio_handler(int irq, void *data)
 {
        struct snd_soc_jack_gpio *gpio = data;
 
-       schedule_work(&gpio->work);
+       schedule_delayed_work(&gpio->work,
+                             msecs_to_jiffies(gpio->debounce_time));
 
        return IRQ_HANDLED;
 }
@@ -221,7 +219,7 @@ static void gpio_work(struct work_struct *work)
 {
        struct snd_soc_jack_gpio *gpio;
 
-       gpio = container_of(work, struct snd_soc_jack_gpio, work);
+       gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
        snd_soc_jack_gpio_detect(gpio);
 }
 
@@ -262,13 +260,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                if (ret)
                        goto err;
 
-               INIT_WORK(&gpios[i].work, gpio_work);
+               INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
                gpios[i].jack = jack;
 
                ret = request_irq(gpio_to_irq(gpios[i].gpio),
                                gpio_handler,
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               jack->card->dev->driver->name,
+                               jack->codec->dev->driver->name,
                                &gpios[i]);
                if (ret)
                        goto err;
@@ -312,6 +310,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
                gpio_unexport(gpios[i].gpio);
 #endif
                free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+               cancel_delayed_work_sync(&gpios[i].work);
                gpio_free(gpios[i].gpio);
                gpios[i].jack = NULL;
        }
index 0ec20b68e8cbbe6089c7c8b453fdf9d4d5a41507..743d07b82c062033f5287a85537b175ef72976d5 100644 (file)
 
 static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
 
-/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
-static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
 
-static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
 {
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
-
        return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
 }
 
@@ -50,8 +48,7 @@ static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
 static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
                                         unsigned short reg)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        u32 dat;
 
@@ -61,15 +58,15 @@ static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
        dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
        __raw_writel(dat, base + ACREGACC);
        __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
                __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-               dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+               printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
                dat = 0xffff;
                goto done;
        }
        dat = __raw_readl(base + ACREGACC);
        if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
-               dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+               printk(KERN_ERR "reg mismatch %x with %x\n",
                        dat, reg);
                dat = 0xffff;
                goto done;
@@ -84,16 +81,15 @@ done:
 static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short val)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
 
        __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
                     (val << ACREGACC_DAT_SHIFT),
                     base + ACREGACC);
        __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
-               dev_err(dev->soc_dev.dev,
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
+               printk(KERN_ERR
                        "ac97 write timeout (reg %#x)\n", reg);
        }
        __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
@@ -101,8 +97,7 @@ static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
 
@@ -141,31 +136,23 @@ static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int txx9aclc_ac97_probe(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-
-       dev->aclc_pdev = to_platform_device(dai->dev);
-       txx9aclc_soc_dev = dev;
+       txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
        return 0;
 }
 
-static void txx9aclc_ac97_remove(struct platform_device *pdev,
-                                struct snd_soc_dai *dai)
+static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
 {
-       struct platform_device *aclc_pdev = to_platform_device(dai->dev);
-       struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+       struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
 
        /* disable AC-link */
        __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
-       txx9aclc_soc_dev = NULL;
+       txx9aclc_drvdata = NULL;
+       return 0;
 }
 
-struct snd_soc_dai txx9aclc_ac97_dai = {
-       .name                   = "txx9aclc_ac97",
+static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
        .ac97_control           = 1,
        .probe                  = txx9aclc_ac97_probe,
        .remove                 = txx9aclc_ac97_remove,
@@ -182,7 +169,6 @@ struct snd_soc_dai txx9aclc_ac97_dai = {
                .channels_max   = 2,
        },
 };
-EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
 
 static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -219,13 +205,12 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       txx9aclc_ac97_dai.dev = &pdev->dev;
-       return snd_soc_register_dai(&txx9aclc_ac97_dai);
+       return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
 }
 
 static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
index 95b17f731aec3a298e2f8c38638201e8eeb63ac2..6770e7166be4b77ae3427cbd3aba16b3b4694489 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include "../codecs/ac97.h"
 #include "txx9aclc.h"
 
 static struct snd_soc_dai_link txx9aclc_generic_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &txx9aclc_ac97_dai,
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "txx9aclc-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .platform_name  = "txx9aclc-pcm-audio",
+       .codec_name     = "ac97-codec",
 };
 
 static struct snd_soc_card txx9aclc_generic_card = {
        .name           = "Generic TXx9 ACLC Audio",
-       .platform       = &txx9aclc_soc_platform,
        .dai_link       = &txx9aclc_generic_dai,
        .num_links      = 1,
 };
 
-static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
-       .soc_dev = {
-               .card           = &txx9aclc_generic_card,
-               .codec_dev      = &soc_codec_dev_ac97,
-       },
-};
+static struct platform_device *soc_pdev;
 
 static int __init txx9aclc_generic_probe(struct platform_device *pdev)
 {
-       struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
-       struct platform_device *soc_pdev;
        int ret;
 
        soc_pdev = platform_device_alloc("soc-audio", -1);
        if (!soc_pdev)
                return -ENOMEM;
-       platform_set_drvdata(soc_pdev, &dev->soc_dev);
-       dev->soc_dev.dev = &soc_pdev->dev;
+       platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
        ret = platform_device_add(soc_pdev);
        if (ret) {
                platform_device_put(soc_pdev);
                return ret;
        }
-       platform_set_drvdata(pdev, soc_pdev);
+
        return 0;
 }
 
 static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
 {
-       struct platform_device *soc_pdev = platform_get_drvdata(pdev);
-
        platform_device_unregister(soc_pdev);
        return 0;
 }
index 0e3452303ea6903d4045d325be31c059d6257b60..f4aa4e03c88884e0b1768314c6d2273b221fb976 100644 (file)
 #include <sound/soc.h>
 #include "txx9aclc.h"
 
+static struct txx9aclc_soc_device {
+       struct txx9aclc_dmadata dmadata[2];
+} txx9aclc_soc_device;
+
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+                            struct txx9aclc_dmadata *dmadata);
+
 static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
        /*
         * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
@@ -46,7 +56,6 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct snd_soc_device *socdev = rtd->socdev;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct txx9aclc_dmadata *dmadata = runtime->private_data;
        int ret;
@@ -55,13 +64,13 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       dev_dbg(socdev->dev,
+       dev_dbg(rtd->platform->dev,
                "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
                "runtime->min_align %ld\n",
                (unsigned long)runtime->dma_area,
                (unsigned long)runtime->dma_addr, runtime->dma_bytes,
                runtime->min_align);
-       dev_dbg(socdev->dev,
+       dev_dbg(rtd->platform->dev,
                "periods %d period_bytes %d stream %d\n",
                params_periods(params), params_period_bytes(params),
                substream->stream);
@@ -152,11 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
 
        spin_lock_irqsave(&dmadata->dma_lock, flags);
        if (dmadata->frag_count < 0) {
-               struct txx9aclc_soc_device *dev =
-                       container_of(dmadata, struct txx9aclc_soc_device,
-                                    dmadata[substream->stream]);
-               struct txx9aclc_plat_drvdata *drvdata =
-                       txx9aclc_get_plat_drvdata(dev);
+               struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
                void __iomem *base = drvdata->base;
 
                spin_unlock_irqrestore(&dmadata->dma_lock, flags);
@@ -202,10 +207,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
 static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct txx9aclc_soc_device *dev =
-               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        unsigned long flags;
        int ret = 0;
@@ -244,9 +246,7 @@ txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct txx9aclc_soc_device *dev =
-               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+       struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
        struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
        int ret;
 
@@ -291,8 +291,38 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
 static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                            struct snd_pcm *pcm)
 {
+       struct platform_device *pdev = to_platform_device(dai->platform->dev);
+       struct txx9aclc_soc_device *dev;
+       struct resource *r;
+       int i;
+       int ret;
+
+       /* at this point onwards the AC97 component has probed and this will be valid */
+       dev = snd_soc_dai_get_drvdata(dai);
+
+       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+       for (i = 0; i < 2; i++) {
+               r = platform_get_resource(pdev, IORESOURCE_DMA, i);
+               if (!r) {
+                       ret = -EBUSY;
+                       goto exit;
+               }
+               dev->dmadata[i].dma_res = r;
+               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+               if (ret)
+                       goto exit;
+       }
        return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                card->dev, 64 * 1024, 4 * 1024 * 1024);
+
+exit:
+       for (i = 0; i < 2; i++) {
+               if (dev->dmadata[i].dma_chan)
+                       dma_release_channel(dev->dmadata[i].dma_chan);
+               dev->dmadata[i].dma_chan = NULL;
+       }
+       return ret;
 }
 
 static bool filter(struct dma_chan *chan, void *param)
@@ -314,7 +344,7 @@ static bool filter(struct dma_chan *chan, void *param)
 static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
                             struct txx9aclc_dmadata *dmadata)
 {
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
        struct txx9dmac_slave *ds = &dmadata->dma_slave;
        dma_cap_mask_t mask;
 
@@ -334,7 +364,7 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
        dma_cap_set(DMA_SLAVE, mask);
        dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
        if (!dmadata->dma_chan) {
-               dev_err(dev->soc_dev.dev,
+               printk(KERN_ERR
                        "DMA channel for %s is not available\n",
                        dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                        "playback" : "capture");
@@ -345,45 +375,16 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
        return 0;
 }
 
-static int txx9aclc_pcm_probe(struct platform_device *pdev)
+static int txx9aclc_pcm_probe(struct snd_soc_platform *platform)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-       struct resource *r;
-       int i;
-       int ret;
-
-       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
-       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
-       for (i = 0; i < 2; i++) {
-               r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
-               if (!r) {
-                       ret = -EBUSY;
-                       goto exit;
-               }
-               dev->dmadata[i].dma_res = r;
-               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
-               if (ret)
-                       goto exit;
-       }
+       snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device);
        return 0;
-
-exit:
-       for (i = 0; i < 2; i++) {
-               if (dev->dmadata[i].dma_chan)
-                       dma_release_channel(dev->dmadata[i].dma_chan);
-               dev->dmadata[i].dma_chan = NULL;
-       }
-       return ret;
 }
 
-static int txx9aclc_pcm_remove(struct platform_device *pdev)
+static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        int i;
 
@@ -406,28 +407,46 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev)
        return 0;
 }
 
-struct snd_soc_platform txx9aclc_soc_platform = {
-       .name           = "txx9aclc-audio",
+static struct snd_soc_platform_driver txx9aclc_soc_platform = {
        .probe          = txx9aclc_pcm_probe,
        .remove         = txx9aclc_pcm_remove,
-       .pcm_ops        = &txx9aclc_pcm_ops,
+       .ops            = &txx9aclc_pcm_ops,
        .pcm_new        = txx9aclc_pcm_new,
        .pcm_free       = txx9aclc_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
 
-static int __init txx9aclc_soc_platform_init(void)
+static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&txx9aclc_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
 }
 
-static void __exit txx9aclc_soc_platform_exit(void)
+static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&txx9aclc_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
-module_init(txx9aclc_soc_platform_init);
-module_exit(txx9aclc_soc_platform_exit);
+static struct platform_driver txx9aclc_pcm_driver = {
+       .driver = {
+                       .name = "txx9aclc-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = txx9aclc_soc_platform_probe,
+       .remove = __devexit_p(txx9aclc_soc_platform_remove),
+};
+
+static int __init snd_txx9aclc_pcm_init(void)
+{
+       return platform_driver_register(&txx9aclc_pcm_driver);
+}
+module_init(snd_txx9aclc_pcm_init);
+
+static void __exit snd_txx9aclc_pcm_exit(void)
+{
+       platform_driver_unregister(&txx9aclc_pcm_driver);
+}
+module_exit(snd_txx9aclc_pcm_exit);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
index 6769aab41b331d60f77b412369cb68823aa3b8c6..9c2de84fec3bbae4bd529f977b4aeab648f38129 100644 (file)
@@ -65,19 +65,10 @@ struct txx9aclc_plat_drvdata {
        u64 physbase;
 };
 
-struct txx9aclc_soc_device {
-       struct snd_soc_device soc_dev;
-       struct platform_device *aclc_pdev;      /* for ioresources, drvdata */
-       struct txx9aclc_dmadata dmadata[2];
-};
-
 static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
-       struct txx9aclc_soc_device *sdev)
+       struct snd_soc_dai *dai)
 {
-       return platform_get_drvdata(sdev->aclc_pdev);
+       return dev_get_drvdata(dai->dev);
 }
 
-extern struct snd_soc_platform txx9aclc_soc_platform;
-extern struct snd_soc_dai txx9aclc_ac97_dai;
-
 #endif /* __TXX9ACLC_H */
index ff0b2a8fd25bbe20dd51191935582746f8ba6edf..5ae1eae9f6dbc2491c5b6bb378ca81cc896e22dc 100644 (file)
@@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu)
        strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
        hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
        hw->ops.ioctl = snd_emux_hwdep_ioctl;
+       /* The ioctl parameter types are compatible between 32- and
+        * 64-bit architectures, so use the same function. */
+       hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
        hw->exclusive = 1;
        hw->private_data = emu;
        if ((err = snd_card_register(emu->card)) < 0)
index 44d6d2ec964f364c07852f9bf88a7d9282a6d059..112984f4080f1d5cbd84aa157d0c60fae2be5cd9 100644 (file)
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
            * Native Instruments Guitar Rig Session I/O
            * Native Instruments Guitar Rig mobile
            * Native Instruments Traktor Kontrol X1
+           * Native Instruments Traktor Kontrol S4
 
           To compile this driver as a module, choose M here: the module
           will be called snd-usb-caiaq.
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT
           * Native Instruments Kore Controller
           * Native Instruments Kore Controller 2
           * Native Instruments Audio Kontrol 1
+          * Native Instruments Traktor Kontrol S4
 
 config SND_USB_US122L
        tristate "Tascam US-122L USB driver"
index 4328cad6c3a24cd7f5887eb6d825d52f0ad6091b..68b97477577b923f8017733d0a6656cbbfa486d3 100644 (file)
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
        memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
        dev->input_panic = 0;
        dev->output_panic = 0;
-       dev->first_packet = 1;
+       dev->first_packet = 4;
        dev->streaming = 1;
        dev->warned = 0;
 
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 }
 
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
-                                       struct snd_pcm_hw_params *hw_params)
+                                      struct snd_pcm_hw_params *hw_params)
 {
        debug("%s(%p)\n", __func__, sub);
        return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 #endif
 
 static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
-                                 48000, 64000, 88200, 96000, 176400, 192000 };
+                               48000, 64000, 88200, 96000, 176400, 192000 };
 
 static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 {
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        debug("%s(%p)\n", __func__, substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
-               dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
+               int out_pos;
+
+               switch (dev->spec.data_alignment) {
+               case 0:
+               case 2:
+                       out_pos = BYTES_PER_SAMPLE + 1;
+                       break;
+               case 3:
+               default:
+                       out_pos = 0;
+                       break;
+               }
+
+               dev->period_out_count[index] = out_pos;
+               dev->audio_out_buf_pos[index] = out_pos;
        } else {
-               int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2;
-               dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos;
-               dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos;
+               int in_pos;
+
+               switch (dev->spec.data_alignment) {
+               case 0:
+                       in_pos = BYTES_PER_SAMPLE + 2;
+                       break;
+               case 2:
+                       in_pos = BYTES_PER_SAMPLE;
+                       break;
+               case 3:
+               default:
+                       in_pos = 0;
+                       break;
+               }
+
+               dev->period_in_count[index] = in_pos;
+               dev->audio_in_buf_pos[index] = in_pos;
        }
 
        if (dev->streaming)
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        snd_pcm_limit_hw_rates(runtime);
 
        bytes_per_sample = BYTES_PER_SAMPLE;
-       if (dev->spec.data_alignment == 2)
+       if (dev->spec.data_alignment >= 2)
                bytes_per_sample++;
 
        bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
 {
        struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
 
+       debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
        }
 }
 
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+                             const struct urb *urb,
+                             const struct usb_iso_packet_descriptor *iso)
+{
+       unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+       int stream, i;
+
+       /* paranoia check */
+       if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
+               return;
+
+       for (i = 0; i < iso->actual_length;) {
+               for (stream = 0; stream < dev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = dev->sub_capture[stream];
+                       char *audio_buf = NULL;
+                       int c, n, sz = 0;
+
+                       if (sub && !dev->input_panic) {
+                               struct snd_pcm_runtime *rt = sub->runtime;
+                               audio_buf = rt->dma_area;
+                               sz = frames_to_bytes(rt, rt->buffer_size);
+                       }
+
+                       for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+                               /* 3 audio data bytes, followed by 1 check byte */
+                               if (audio_buf) {
+                                       for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+                                               audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+
+                                               if (dev->audio_in_buf_pos[stream] == sz)
+                                                       dev->audio_in_buf_pos[stream] = 0;
+                                       }
+
+                                       dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+                               }
+
+                               i += BYTES_PER_SAMPLE;
+
+                               if (usb_buf[i] != ((stream << 1) | c) &&
+                                   !dev->first_packet) {
+                                       if (!dev->input_panic)
+                                               printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+                                                       ((stream << 1) | c), usb_buf[i], c, stream, i);
+                                       dev->input_panic = 1;
+                               }
+
+                               i++;
+                       }
+               }
+       }
+
+       if (dev->first_packet > 0)
+               dev->first_packet--;
+}
+
 static void read_in_urb(struct snd_usb_caiaqdev *dev,
                        const struct urb *urb,
                        const struct usb_iso_packet_descriptor *iso)
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        case 2:
                read_in_urb_mode2(dev, urb, iso);
                break;
+       case 3:
+               read_in_urb_mode3(dev, urb, iso);
+               break;
        }
 
        if ((dev->input_panic || dev->output_panic) && !dev->warned) {
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        }
 }
 
-static void fill_out_urb(struct snd_usb_caiaqdev *dev,
-                        struct urb *urb,
-                        const struct usb_iso_packet_descriptor *iso)
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
 {
        unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
        struct snd_pcm_substream *sub;
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
                /* fill in the check bytes */
                if (dev->spec.data_alignment == 2 &&
                    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
-                       (dev->n_streams * CHANNELS_PER_STREAM))
-                   for (stream = 0; stream < dev->n_streams; stream++, i++)
-                       usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+                       (dev->n_streams * CHANNELS_PER_STREAM))
+                       for (stream = 0; stream < dev->n_streams; stream++, i++)
+                               usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+       }
+}
+
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
+{
+       unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+       int stream, i;
+
+       for (i = 0; i < iso->length;) {
+               for (stream = 0; stream < dev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = dev->sub_playback[stream];
+                       char *audio_buf = NULL;
+                       int c, n, sz = 0;
+
+                       if (sub) {
+                               struct snd_pcm_runtime *rt = sub->runtime;
+                               audio_buf = rt->dma_area;
+                               sz = frames_to_bytes(rt, rt->buffer_size);
+                       }
+
+                       for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+                               for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+                                       if (audio_buf) {
+                                               usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+
+                                               if (dev->audio_out_buf_pos[stream] == sz)
+                                                       dev->audio_out_buf_pos[stream] = 0;
+                                       } else {
+                                               usb_buf[i+n] = 0;
+                                       }
+                               }
+
+                               if (audio_buf)
+                                       dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+
+                               i += BYTES_PER_SAMPLE;
+
+                               /* fill in the check byte pattern */
+                               usb_buf[i++] = (stream << 1) | c;
+                       }
+               }
+       }
+}
+
+static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
+{
+       switch (dev->spec.data_alignment) {
+       case 0:
+       case 2:
+               fill_out_urb_mode_0(dev, urb, iso);
+               break;
+       case 3:
+               fill_out_urb_mode_3(dev, urb, iso);
+               break;
        }
 }
 
index 91c804cd278278c639f428ab59d963d6d6804105..00e5d0a469e1b065a6bee10b57d9fc1c41f2d716 100644 (file)
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol,
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                maxval = 127;
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               maxval = 31;
+               break;
        }
 
        if (is_intval) {
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
        struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
+       int v = ucontrol->value.integer.value[0];
        unsigned char cmd = EP1_CMD_WRITE_IO;
 
        if (dev->chip.usb_id ==
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol,
                cmd = EP1_CMD_DIMM_LEDS;
 
        if (pos & CNT_INTVAL) {
-               dev->control_state[pos & ~CNT_INTVAL]
-                       = ucontrol->value.integer.value[0];
-               snd_usb_caiaq_send_command(dev, cmd,
-                               dev->control_state, sizeof(dev->control_state));
+               int i = pos & ~CNT_INTVAL;
+
+               dev->control_state[i] = v;
+
+               if (dev->chip.usb_id ==
+                       USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
+                       int actual_len;
+
+                       dev->ep8_out_buf[0] = i;
+                       dev->ep8_out_buf[1] = v;
+
+                       usb_bulk_msg(dev->chip.dev,
+                                    usb_sndbulkpipe(dev->chip.dev, 8),
+                                    dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+                                    &actual_len, 200);
+               } else {
+                       snd_usb_caiaq_send_command(dev, cmd,
+                                       dev->control_state, sizeof(dev->control_state));
+               }
        } else {
-               if (ucontrol->value.integer.value[0])
+               if (v)
                        dev->control_state[pos / 8] |= 1 << (pos % 8);
                else
                        dev->control_state[pos / 8] &= ~(1 << (pos % 8));
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = {
        { "LED Deck B: SYNC",           8  | CNT_INTVAL },
 };
 
+static struct caiaq_controller kontrols4_controller[] = {
+       { "LED: Master: Quant",                 10  | CNT_INTVAL },
+       { "LED: Master: Headphone",             11  | CNT_INTVAL },
+       { "LED: Master: Master",                12  | CNT_INTVAL },
+       { "LED: Master: Snap",                  14  | CNT_INTVAL },
+       { "LED: Master: Warning",               15  | CNT_INTVAL },
+       { "LED: Master: Master button",         112 | CNT_INTVAL },
+       { "LED: Master: Snap button",           113 | CNT_INTVAL },
+       { "LED: Master: Rec",                   118 | CNT_INTVAL },
+       { "LED: Master: Size",                  119 | CNT_INTVAL },
+       { "LED: Master: Quant button",          120 | CNT_INTVAL },
+       { "LED: Master: Browser button",        121 | CNT_INTVAL },
+       { "LED: Master: Play button",           126 | CNT_INTVAL },
+       { "LED: Master: Undo button",           127 | CNT_INTVAL },
+
+       { "LED: Channel A: >",                  4   | CNT_INTVAL },
+       { "LED: Channel A: <",                  5   | CNT_INTVAL },
+       { "LED: Channel A: Meter 1",            97  | CNT_INTVAL },
+       { "LED: Channel A: Meter 2",            98  | CNT_INTVAL },
+       { "LED: Channel A: Meter 3",            99  | CNT_INTVAL },
+       { "LED: Channel A: Meter 4",            100 | CNT_INTVAL },
+       { "LED: Channel A: Meter 5",            101 | CNT_INTVAL },
+       { "LED: Channel A: Meter 6",            102 | CNT_INTVAL },
+       { "LED: Channel A: Meter clip",         103 | CNT_INTVAL },
+       { "LED: Channel A: Active",             114 | CNT_INTVAL },
+       { "LED: Channel A: Cue",                116 | CNT_INTVAL },
+       { "LED: Channel A: FX1",                149 | CNT_INTVAL },
+       { "LED: Channel A: FX2",                148 | CNT_INTVAL },
+
+       { "LED: Channel B: >",                  2   | CNT_INTVAL },
+       { "LED: Channel B: <",                  3   | CNT_INTVAL },
+       { "LED: Channel B: Meter 1",            89  | CNT_INTVAL },
+       { "LED: Channel B: Meter 2",            90  | CNT_INTVAL },
+       { "LED: Channel B: Meter 3",            91  | CNT_INTVAL },
+       { "LED: Channel B: Meter 4",            92  | CNT_INTVAL },
+       { "LED: Channel B: Meter 5",            93  | CNT_INTVAL },
+       { "LED: Channel B: Meter 6",            94  | CNT_INTVAL },
+       { "LED: Channel B: Meter clip",         95  | CNT_INTVAL },
+       { "LED: Channel B: Active",             122 | CNT_INTVAL },
+       { "LED: Channel B: Cue",                125 | CNT_INTVAL },
+       { "LED: Channel B: FX1",                147 | CNT_INTVAL },
+       { "LED: Channel B: FX2",                146 | CNT_INTVAL },
+
+       { "LED: Channel C: >",                  6   | CNT_INTVAL },
+       { "LED: Channel C: <",                  7   | CNT_INTVAL },
+       { "LED: Channel C: Meter 1",            105 | CNT_INTVAL },
+       { "LED: Channel C: Meter 2",            106 | CNT_INTVAL },
+       { "LED: Channel C: Meter 3",            107 | CNT_INTVAL },
+       { "LED: Channel C: Meter 4",            108 | CNT_INTVAL },
+       { "LED: Channel C: Meter 5",            109 | CNT_INTVAL },
+       { "LED: Channel C: Meter 6",            110 | CNT_INTVAL },
+       { "LED: Channel C: Meter clip",         111 | CNT_INTVAL },
+       { "LED: Channel C: Active",             115 | CNT_INTVAL },
+       { "LED: Channel C: Cue",                117 | CNT_INTVAL },
+       { "LED: Channel C: FX1",                151 | CNT_INTVAL },
+       { "LED: Channel C: FX2",                150 | CNT_INTVAL },
+
+       { "LED: Channel D: >",                  0   | CNT_INTVAL },
+       { "LED: Channel D: <",                  1   | CNT_INTVAL },
+       { "LED: Channel D: Meter 1",            81  | CNT_INTVAL },
+       { "LED: Channel D: Meter 2",            82  | CNT_INTVAL },
+       { "LED: Channel D: Meter 3",            83  | CNT_INTVAL },
+       { "LED: Channel D: Meter 4",            84  | CNT_INTVAL },
+       { "LED: Channel D: Meter 5",            85  | CNT_INTVAL },
+       { "LED: Channel D: Meter 6",            86  | CNT_INTVAL },
+       { "LED: Channel D: Meter clip",         87  | CNT_INTVAL },
+       { "LED: Channel D: Active",             123 | CNT_INTVAL },
+       { "LED: Channel D: Cue",                124 | CNT_INTVAL },
+       { "LED: Channel D: FX1",                145 | CNT_INTVAL },
+       { "LED: Channel D: FX2",                144 | CNT_INTVAL },
+
+       { "LED: Deck A: 1 (blue)",              22  | CNT_INTVAL },
+       { "LED: Deck A: 1 (green)",             23  | CNT_INTVAL },
+       { "LED: Deck A: 2 (blue)",              20  | CNT_INTVAL },
+       { "LED: Deck A: 2 (green)",             21  | CNT_INTVAL },
+       { "LED: Deck A: 3 (blue)",              18  | CNT_INTVAL },
+       { "LED: Deck A: 3 (green)",             19  | CNT_INTVAL },
+       { "LED: Deck A: 4 (blue)",              16  | CNT_INTVAL },
+       { "LED: Deck A: 4 (green)",             17  | CNT_INTVAL },
+       { "LED: Deck A: Load",                  44  | CNT_INTVAL },
+       { "LED: Deck A: Deck C button",         45  | CNT_INTVAL },
+       { "LED: Deck A: In",                    47  | CNT_INTVAL },
+       { "LED: Deck A: Out",                   46  | CNT_INTVAL },
+       { "LED: Deck A: Shift",                 24  | CNT_INTVAL },
+       { "LED: Deck A: Sync",                  27  | CNT_INTVAL },
+       { "LED: Deck A: Cue",                   26  | CNT_INTVAL },
+       { "LED: Deck A: Play",                  25  | CNT_INTVAL },
+       { "LED: Deck A: Tempo up",              33  | CNT_INTVAL },
+       { "LED: Deck A: Tempo down",            32  | CNT_INTVAL },
+       { "LED: Deck A: Master",                34  | CNT_INTVAL },
+       { "LED: Deck A: Keylock",               35  | CNT_INTVAL },
+       { "LED: Deck A: Deck A",                37  | CNT_INTVAL },
+       { "LED: Deck A: Deck C",                36  | CNT_INTVAL },
+       { "LED: Deck A: Samples",               38  | CNT_INTVAL },
+       { "LED: Deck A: On Air",                39  | CNT_INTVAL },
+       { "LED: Deck A: Sample 1",              31  | CNT_INTVAL },
+       { "LED: Deck A: Sample 2",              30  | CNT_INTVAL },
+       { "LED: Deck A: Sample 3",              29  | CNT_INTVAL },
+       { "LED: Deck A: Sample 4",              28  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - A",           55  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - B",           54  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - C",           53  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - D",           52  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - E",           51  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - F",           50  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - G",           49  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - dot",         48  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - A",           63  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - B",           62  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - C",           61  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - D",           60  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - E",           59  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - F",           58  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - G",           57  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - dot",         56  | CNT_INTVAL },
+
+       { "LED: Deck B: 1 (blue)",              78  | CNT_INTVAL },
+       { "LED: Deck B: 1 (green)",             79  | CNT_INTVAL },
+       { "LED: Deck B: 2 (blue)",              76  | CNT_INTVAL },
+       { "LED: Deck B: 2 (green)",             77  | CNT_INTVAL },
+       { "LED: Deck B: 3 (blue)",              74  | CNT_INTVAL },
+       { "LED: Deck B: 3 (green)",             75  | CNT_INTVAL },
+       { "LED: Deck B: 4 (blue)",              72  | CNT_INTVAL },
+       { "LED: Deck B: 4 (green)",             73  | CNT_INTVAL },
+       { "LED: Deck B: Load",                  180 | CNT_INTVAL },
+       { "LED: Deck B: Deck D button",         181 | CNT_INTVAL },
+       { "LED: Deck B: In",                    183 | CNT_INTVAL },
+       { "LED: Deck B: Out",                   182 | CNT_INTVAL },
+       { "LED: Deck B: Shift",                 64  | CNT_INTVAL },
+       { "LED: Deck B: Sync",                  67  | CNT_INTVAL },
+       { "LED: Deck B: Cue",                   66  | CNT_INTVAL },
+       { "LED: Deck B: Play",                  65  | CNT_INTVAL },
+       { "LED: Deck B: Tempo up",              185 | CNT_INTVAL },
+       { "LED: Deck B: Tempo down",            184 | CNT_INTVAL },
+       { "LED: Deck B: Master",                186 | CNT_INTVAL },
+       { "LED: Deck B: Keylock",               187 | CNT_INTVAL },
+       { "LED: Deck B: Deck B",                189 | CNT_INTVAL },
+       { "LED: Deck B: Deck D",                188 | CNT_INTVAL },
+       { "LED: Deck B: Samples",               190 | CNT_INTVAL },
+       { "LED: Deck B: On Air",                191 | CNT_INTVAL },
+       { "LED: Deck B: Sample 1",              71  | CNT_INTVAL },
+       { "LED: Deck B: Sample 2",              70  | CNT_INTVAL },
+       { "LED: Deck B: Sample 3",              69  | CNT_INTVAL },
+       { "LED: Deck B: Sample 4",              68  | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - A",           175 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - B",           174 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - C",           173 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - D",           172 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - E",           171 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - F",           170 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - G",           169 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - dot",         168 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - A",           167 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - B",           166 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - C",           165 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - D",           164 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - E",           163 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - F",           162 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - G",           161 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - dot",         160 | CNT_INTVAL },
+
+       { "LED: FX1: dry/wet",                  153 | CNT_INTVAL },
+       { "LED: FX1: 1",                        154 | CNT_INTVAL },
+       { "LED: FX1: 2",                        155 | CNT_INTVAL },
+       { "LED: FX1: 3",                        156 | CNT_INTVAL },
+       { "LED: FX1: Mode",                     157 | CNT_INTVAL },
+       { "LED: FX2: dry/wet",                  129 | CNT_INTVAL },
+       { "LED: FX2: 1",                        130 | CNT_INTVAL },
+       { "LED: FX2: 2",                        131 | CNT_INTVAL },
+       { "LED: FX2: 3",                        132 | CNT_INTVAL },
+       { "LED: FX2: Mode",                     133 | CNT_INTVAL },
+};
+
 static int __devinit add_controls(struct caiaq_controller *c, int num,
                                  struct snd_usb_caiaqdev *dev)
 {
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
                ret = add_controls(kontrolx1_controller,
                        ARRAY_SIZE(kontrolx1_controller), dev);
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               ret = add_controls(kontrols4_controller,
+                       ARRAY_SIZE(kontrols4_controller), dev);
+               break;
        }
 
        return ret;
index cdfb856bddd261c5717fe6845b5a210fa20a7f75..6480c3283c05a0082e21c31788ea54c0e7ccb7b4 100644 (file)
@@ -36,7 +36,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
+MODULE_DESCRIPTION("caiaq USB audio");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, Audio 8 DJ},"
                         "{Native Instruments, Session I/O},"
                         "{Native Instruments, GuitarRig mobile}"
-                        "{Native Instruments, Traktor Kontrol X1}");
+                        "{Native Instruments, Traktor Kontrol X1}"
+                        "{Native Instruments, Traktor Kontrol S4}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_TRAKTORKONTROLX1
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_TRAKTORKONTROLS4
+       },
        { /* terminator */ }
 };
 
index f1117ecc84fdf9d7b6133ae3fd96ed395f073109..e3d8a3efb35b5350de0f60789f4834bf19494f96 100644 (file)
@@ -16,6 +16,7 @@
 #define USB_PID_SESSIONIO              0x1915
 #define USB_PID_GUITARRIGMOBILE                0x0d8d
 #define USB_PID_TRAKTORKONTROLX1       0x2305
+#define USB_PID_TRAKTORKONTROLS4       0xbaff
 
 #define EP1_BUFSIZE 64
 #define EP4_BUFSIZE 512
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev {
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
 
        /* Controls */
-       unsigned char control_state[64];
+       unsigned char control_state[256];
+       unsigned char ep8_out_buf[2];
 
        /* Linux input */
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        struct input_dev *input_dev;
        char phys[64];                  /* physical device path */
-       unsigned short keycode[64];
+       unsigned short keycode[128];
        struct urb *ep4_in_urb;
        unsigned char ep4_in_buf[EP4_BUFSIZE];
 #endif
index dcb620796d9ef5c14ba7f52ab3686b1ae0c1969a..4432ef7a70a9ad184066d4d0b63ff594c442acdf 100644 (file)
@@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = {
        KEY_BRL_DOT5
 };
 
-#define KONTROLX1_INPUTS 40
+#define KONTROLX1_INPUTS       (40)
+#define KONTROLS4_BUTTONS      (12 * 8)
+#define KONTROLS4_AXIS         (46)
+
+#define KONTROLS4_BUTTON(X)    ((X) + BTN_MISC)
+#define KONTROLS4_ABS(X)       ((X) + ABS_HAT0X)
 
 #define DEG90          (range / 2)
 #define DEG180         (range)
@@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 #undef HIGH_PEAK
 #undef LOW_PEAK
 
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+                                             int axis, const unsigned char *buf,
+                                             int offset)
+{
+       input_report_abs(dev->input_dev, axis,
+                        (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
+}
 
 static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
                                        const unsigned char *buf,
@@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
-               input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]);
-               input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
+               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
-               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
-               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
-               input_sync(input_dev);
-               break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
-               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
+               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
-               input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8)  | buf[9]);
-               input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8)  | buf[5]);
-               input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
-               input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8)  | buf[3]);
-               input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
-               input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8)  | buf[1]);
-               input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
-               input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8)  | buf[7]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
+               snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
+               snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
+               snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
+               snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
+               snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
+               snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
                break;
        }
+
+       input_sync(input_dev);
 }
 
 static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
@@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
        input_sync(input_dev);
 }
 
+#define TKS4_MSGBLOCK_SIZE     16
+
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+                                       const unsigned char *buf,
+                                       unsigned int len)
+{
+       while (len) {
+               unsigned int i, block_id = (buf[0] << 8) | buf[1];
+
+               switch (block_id) {
+               case 0:
+                       /* buttons */
+                       for (i = 0; i < KONTROLS4_BUTTONS; i++)
+                               input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+                                                (buf[4 + (i / 8)] >> (i % 8)) & 1);
+                       break;
+
+               case 1:
+                       /* left wheel */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+                       /* right wheel */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+
+                       /* rotary encoders */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+
+                       break;
+               case 2:
+                       /* Volume Fader Channel D */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+                       /* Volume Fader Channel B */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+                       /* Volume Fader Channel A */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+                       /* Volume Fader Channel C */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+                       /* Loop Volume */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+                       /* Crossfader */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+
+                       break;
+
+               case 3:
+                       /* Tempo Fader R */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+                       /* Tempo Fader L */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+                       /* Mic Volume */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+                       /* Cue Mix */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+
+                       break;
+
+               case 4:
+                       /* Wheel distance sensor L */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+                       /* Wheel distance sensor R */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+                       /* Channel D EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+                       /* Channel D EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+                       /* Channel D EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+                       /* Channel D EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+                       /* FX2 - dry/wet */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+
+                       break;
+
+               case 5:
+                       /* FX2 - 1 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+                       /* FX2 - 2 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+                       /* FX2 - 3 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+                       /* Channel B EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+                       /* Channel B EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+                       /* Channel B EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+                       /* Channel B EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+
+                       break;
+
+               case 6:
+                       /* Channel A EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+                       /* Channel A EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+                       /* Channel A EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+                       /* Channel A EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+                       /* Channel C EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+                       /* Channel C EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+                       /* Channel C EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+
+                       break;
+
+               case 7:
+                       /* Channel C EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+                       /* FX1 - wet/dry */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+                       /* FX1 - 1 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+                       /* FX1 - 2 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+                       /* FX1 - 3 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+
+                       break;
+
+               default:
+                       debug("%s(): bogus block (id %d)\n",
+                               __func__, block_id);
+                       return;
+               }
+
+               len -= TKS4_MSGBLOCK_SIZE;
+               buf += TKS4_MSGBLOCK_SIZE;
+       }
+
+       input_sync(dev->input_dev);
+}
+
 static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
 {
        struct snd_usb_caiaqdev *dev = urb->context;
@@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
        if (urb->status || !dev || urb != dev->ep4_in_urb)
                return;
 
-       if (urb->actual_length < 24)
-               goto requeue;
-
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+               if (urb->actual_length < 24)
+                       goto requeue;
+
                if (buf[0] & 0x3)
                        snd_caiaq_input_read_io(dev, buf + 1, 7);
 
@@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
                        snd_caiaq_input_read_analog(dev, buf + 8, 16);
 
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+               break;
        }
 
 requeue:
@@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
                        return -EIO;
                break;
@@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev)
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                usb_kill_urb(dev->ep4_in_urb);
                break;
        }
@@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
 
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+               BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+               for (i = 0; i < KONTROLS4_BUTTONS; i++)
+                       dev->keycode[i] = KONTROLS4_BUTTON(i);
+               input->keycodemax = KONTROLS4_BUTTONS;
+
+               for (i = 0; i < KONTROLS4_AXIS; i++) {
+                       int axis = KONTROLS4_ABS(i);
+                       input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
+               }
+
+               /* 36 analog potentiometers and faders */
+               for (i = 0; i < 36; i++)
+                       input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10);
+
+               /* 2 encoder wheels */
+               input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1);
+               input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1);
+
+               /* 9 rotary encoders */
+               for (i = 0; i < 9; i++)
+                       input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
+
+               dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!dev->ep4_in_urb) {
+                       ret = -ENOMEM;
+                       goto exit_free_idev;
+               }
+
+               usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+                                 usb_rcvbulkpipe(usb_dev, 0x4),
+                                 dev->ep4_in_buf, EP4_BUFSIZE,
+                                 snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+
+               break;
+
        default:
                /* no input methods supported on this device */
                goto exit_free_idev;
index 4eabafa5b037db66b250db64cc0ce05aa783f595..800f7cb4f251cd77ae246c5dee2acaed9de587f4 100644 (file)
@@ -300,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 
        *rchip = NULL;
 
-       if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
-           snd_usb_get_speed(dev) != USB_SPEED_FULL &&
-           snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+       switch (snd_usb_get_speed(dev)) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               break;
+       default:
                snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
                return -ENXIO;
        }
@@ -378,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        if (len < sizeof(card->longname))
                usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
 
-       strlcat(card->longname,
-               snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
-               snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
-               ", high speed",
-               sizeof(card->longname));
+       switch (snd_usb_get_speed(dev)) {
+       case USB_SPEED_LOW:
+               strlcat(card->longname, ", low speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_FULL:
+               strlcat(card->longname, ", full speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_HIGH:
+               strlcat(card->longname, ", high speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_SUPER:
+               strlcat(card->longname, ", super speed", sizeof(card->longname));
+               break;
+       default:
+               break;
+       }
 
        snd_usb_audio_create_proc(chip);
 
index ef0a07e34844ae4d53ffd12e54b16a203da02a19..b0ef9f5018960db6a502170a05e73044864e0c0e 100644 (file)
@@ -405,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        break;
                case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
                case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-               case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */
-               case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
                        /* doesn't set the sample rate attribute, but supports it */
                        fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
                        break;
index d48d6f8f6ac9747343b6c3b7c6e5d3760464c7e4..f280c1903c25bdaa0b20e8456b6753c3dc5edcfb 100644 (file)
@@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
                                         struct usb_host_interface *alts)
 {
-       if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
-           get_endpoint(alts, 0)->bInterval >= 1 &&
-           get_endpoint(alts, 0)->bInterval <= 4)
-               return get_endpoint(alts, 0)->bInterval - 1;
-       else
-               return 0;
+       switch (snd_usb_get_speed(chip->dev)) {
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               if (get_endpoint(alts, 0)->bInterval >= 1 &&
+                   get_endpoint(alts, 0)->bInterval <= 4)
+                       return get_endpoint(alts, 0)->bInterval - 1;
+               break;
+       default:
+               break;
+       }
+       return 0;
 }
 
index b9c2bc65f51ae7bd24da9adfaf8b62c241c2846f..25bce7e5b1afd09cf1fdac8ad7d5f77e61c0eca9 100644 (file)
@@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = {
 };
 
 /*
- * "raw" protocol: used by the MOTU FastLane.
+ * "raw" protocol: just move raw MIDI bytes from/to the endpoint
  */
 
 static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,
@@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
 
        if (!ep->ports[0].active)
                return;
-       count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
+       switch (snd_usb_get_speed(ep->umidi->dev)) {
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               count = 1;
+               break;
+       default:
+               count = 2;
+       }
        count = snd_rawmidi_transmit(ep->ports[0].substream,
                                     urb->transfer_buffer,
                                     count);
@@ -2115,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card,
                umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
-       case QUIRK_MIDI_FASTLANE:
+       case QUIRK_MIDI_RAW_BYTES:
                umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
                /*
                 * Interface 1 contains isochronous endpoints, but with the same
@@ -2126,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card,
                 * interface 0, so we have to make sure that the USB core looks
                 * again at interface 0 by calling usb_set_interface() on it.
                 */
-               usb_set_interface(umidi->dev, 0, 0);
+               if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */
+                       usb_set_interface(umidi->dev, 0, 0);
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        case QUIRK_MIDI_EMAGIC:
index 3ed3901369ce1a9ca58473ecef450623cf95a7b2..f2d74d654b3c3302b6dbe353ae8be95484c16ccf 100644 (file)
@@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
  */
 static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
 {
-       struct snd_usb_audio *chip = cval->mixer->chip;
-
        /* for failsafe */
        cval->min = default_min;
        cval->max = cval->min + 1;
@@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
                    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
                        snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
-                                  cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id);
+                                  cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
                        return -EINVAL;
                }
                if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@@ -1642,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = cval->max;
-       if ((int)uinfo->value.enumerated.item >= cval->max)
+       if (uinfo->value.enumerated.item >= cval->max)
                uinfo->value.enumerated.item = cval->max - 1;
-       strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
+       strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item],
+               sizeof(uinfo->value.enumerated.name));
        return 0;
 }
 
index e7df1e5e3f2ecd36b60ba07944dfeac1d14ff85f..7dae05d8783e4274266bb5c867e534b342e18614 100644 (file)
@@ -60,6 +60,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
+       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
index 3b5135c930628fc092cad54e67ce2a7645c59c02..f49756c1b83709716d8a60a8341dccb7c5f10f4f 100644 (file)
@@ -466,7 +466,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
                return 0;
        }
        /* check whether the period time is >= the data packet interval */
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) {
+       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
                ptime = 125 * (1 << fp->datainterval);
                if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
                        hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max);
@@ -734,7 +734,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
        }
 
        param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
-       if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH)
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
                /* full speed devices have fixed data packet interval */
                ptmin = 1000;
        if (ptmin == 1000)
index f5e3f356b95ff4277e98ad5ad60518f2cac15aa7..3c650ab3c91de8e2edb87e3e0b03ce716b17d894 100644 (file)
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                        }
                        snd_iprintf(buffer, "\n");
                }
-               if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+               if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
                        snd_iprintf(buffer, "    Data packet interval: %d us\n",
                                    125 * (1 << fp->datainterval));
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
index 2e8003f98fca9bd141f655aa619abb4009ae9553..ad7079d1676cd1607b7cc161b4c2dfff6651a5eb 100644 (file)
@@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL),
 YAMAHA_DEVICE(0x1050, NULL),
 YAMAHA_DEVICE(0x1051, NULL),
 YAMAHA_DEVICE(0x1052, NULL),
+YAMAHA_INTERFACE(0x1053, 0, NULL),
+YAMAHA_INTERFACE(0x1054, 0, NULL),
+YAMAHA_DEVICE(0x1055, NULL),
+YAMAHA_DEVICE(0x1056, NULL),
+YAMAHA_DEVICE(0x1057, NULL),
+YAMAHA_DEVICE(0x1058, NULL),
+YAMAHA_DEVICE(0x1059, NULL),
+YAMAHA_DEVICE(0x105a, NULL),
+YAMAHA_DEVICE(0x105b, NULL),
+YAMAHA_DEVICE(0x105c, NULL),
+YAMAHA_DEVICE(0x105d, NULL),
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
+YAMAHA_DEVICE(0x2003, NULL),
 YAMAHA_DEVICE(0x5000, "CS1D"),
 YAMAHA_DEVICE(0x5001, "DSP1D"),
 YAMAHA_DEVICE(0x5002, "DME32"),
@@ -1135,12 +1147,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_STANDARD_INTERFACE
        }
 },
+{
+       /* has ID 0x0066 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0064),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* has ID 0x0067 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0065),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "PCR-1",
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
                .ifnum = 0,
                .type = QUIRK_MIDI_FIXED_ENDPOINT,
                .data = & (const struct snd_usb_midi_endpoint_info) {
@@ -1525,6 +1560,50 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* has ID 0x0110 when not in Advanced Driver mode */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "A-PRO", */
+               .ifnum = 1,
+               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = & (const struct snd_usb_midi_endpoint_info) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+       }
+},
+{
+       USB_DEVICE(0x0582, 0x0113),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "BOSS", */
+               /* .product_name = "ME-25", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
@@ -1830,7 +1909,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        USB_DEVICE(0x0763, 0x2080),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "M-Audio", */
-               /* .product_name = "Fast Track Ultra 8", */
+               /* .product_name = "Fast Track Ultra", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = & (const struct snd_usb_audio_quirk[]) {
@@ -1840,11 +1919,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x01,
+                                       .ep_attr = 0x09,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x81,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        /* interface 3 (MIDI) is standard compliant */
                        {
@@ -1867,11 +1986,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x01,
+                                       .ep_attr = 0x09,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                                       44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x81,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        /* interface 3 (MIDI) is standard compliant */
                        {
@@ -1919,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = & (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_MIDI_FASTLANE
+                               .type = QUIRK_MIDI_RAW_BYTES
                        },
                        {
                                .ifnum = 1,
@@ -2067,6 +2226,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_NOVATION
        }
 },
+{
+       USB_DEVICE(0x1235, 0x000e),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Novation", */
+               /* .product_name = "Launchpad", */
+               .ifnum = 0,
+               .type = QUIRK_MIDI_RAW_BYTES
+       }
+},
 {
        USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
index 9a9da09586a5581b8fe26eec00d3b5183e3a8469..cf8bf088394bd39431a0cd541720bc6990013c4f 100644 (file)
@@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
                [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
                [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
-               [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+               [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
                [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
                [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
index de607d4411acf5137edbeeb4e6af45ea0546b67b..8deeaad10f10caa4827288cc41230ce1cc6eb77e 100644 (file)
@@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
        else
                subs->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
                packs_per_ms = 8 >> subs->datainterval;
        else
                packs_per_ms = 1;
index 24d3319cc34d0985ace0270be5b7894a3b086c21..db3eb21627eeee5f7c9c062286e5669ed93aff1a 100644 (file)
@@ -70,7 +70,7 @@ enum quirk_type {
        QUIRK_MIDI_YAMAHA,
        QUIRK_MIDI_MIDIMAN,
        QUIRK_MIDI_NOVATION,
-       QUIRK_MIDI_FASTLANE,
+       QUIRK_MIDI_RAW_BYTES,
        QUIRK_MIDI_EMAGIC,
        QUIRK_MIDI_CME,
        QUIRK_MIDI_AKAI,
index 2a528e56afd50db1c7f7cb309e1734c826cef3c2..287ef73b123728dbe4a60c2cf999ac5eeaffea75 100644 (file)
@@ -36,9 +36,9 @@
          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
          2periods works but is useless cause of crackling).
+
  This is a first "proof of concept" implementation.
- Later, funcionalities should migrate to more apropriate places:
+ Later, functionalities should migrate to more apropriate places:
  Userland:
  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
  - alsa-lib could provide power of 2 period sized shaping combined with int/float
@@ -54,7 +54,7 @@
 #include <linux/gfp.h>
 #include "usbusx2yaudio.c"
 
-#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)
+#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
 
 #include <sound/hwdep.h>